Celso Axelrud
Jan/30/2011
Introduction
This document presents a Linear Programming function developed in F# and executed in the interactive environment.
I am targeting small LP programs on very fast computers.
I selected the simplest and shortest code from all references. It means that has no linear algebra operation and not subroutine calls.
The F# code presented here is based on the subroutine Linpro.
Fortran version at:
http://www.sie.arizona.edu/faculty/addenda/yak/SIE270/for/linpro
Pascal version at:
http://www.sie.arizona.edu/faculty/addenda/yak/SIE270/pas/linpro.pas
There are other references to a subroutine Linpro but it is not the same code.
Fortran version at:
http://www.slac.stanford.edu/accel/ilc/codes/lcopt/source/linpro.f
Python version at:
http://adorio-research.org/wordpress/?p=194
Source Code and Results
(* Linpro - this function computes the solution of a linear programming problem by using the Simplex method. The Objective function is maximized. Parameters a,b, and c are presumed transmitted as global variables declared in the calling program Usage: Linpro n m1 m2 m3 Parmeters: a = matrix of coefficients (global) b = right hand side vector (global) c = coefficients of the objective function(global) Input: n = number of variables m1 = number of constraints of the Le type m2 = number of constraints of the Eq type m3 = number of constraints of the Ge type Output: x.[i] = i-th component of the optimal solution for i = 1, ... ,N x.[n+1] = optimal value of the objective function Kod = key showing the category of the Lp problem if Kod = 1 then an optimal exists if Kod = 2 then no feasible solution exists if Kod = 3 then the objective function is not bounded Remarks: matrix a needs to be re-assign before calling the function again Conditions: M1+M2+M3 must be less then or equal to 50 N must not be larger then 50 unless the subroutine is redimenstion Example: Maximize Z = f(x,y) = 3x + 2y subject to: 2x + y ≤ 18 2x + 3y ≤ 42 3x + y ≤ 24 x ≥ 0 , y ≥ 0 result: (x,y) = (3,12) Z=33 *) let a:float[,]= Array2D.zeroCreate 52 151 let b:float[]= Array.zeroCreate 50 let c:float[]= Array.zeroCreate 50 //Linpro let Linpro n m1 m2 m3 = let x:float array = Array.zeroCreate 50 let mutable i,i0,i1,i2=0,0,0,0 let mutable j,j0,j1,j2,L=0,0,0,0,0 let mutable L1,L2,L3,Kod=0,0,0,0 let mutable m4,m5,mm,n1,n5,nm,nn=0,0,0,0,0,0,0 let mutable key=0 let mutable ifirst=0 let mutable u=0.0 let mutable Key=0 let eps=1.0e-3 let kk:int array = Array.zeroCreate 150 //Load up the initial tableau with slack and artificial //variables, original and secondary objective functions L1<- n + 1 L2<- m1+m2+m3+1 n1<- n + 1 //set the size of the appended matrix mm<- m1+m2+m3+2 nn<- n+m1+m2+(2*m3)+1 //initialize both objectives to zero for i= L2 to mm do for j= 1 to nn do a.[i,j]<- 0.0 L3<- m1+m2+m3 // initialize all slack and artificial coefficients to zero for i= 1 to L3 do for j= L1 to nn do a.[i,j]<- 0.0 L<-n if m1 > 0 then // Fix slack coefficients for Le constraints for i= 1 to m1 do a.[i,L+i]<- 1.0 L<- L + m1 if m3 > 0 then // Fix slack coefficients for Ge constraints for i= 1 to m3 do i1<-m1+m2+i a.[i1,L+i]<- -1.0 L<- L + m3 m4<- m2 + m3 if (m4 > 0) then // Fix artificial coefficient for for Eq and Ge constraints for i= 1 to m4 do a.[m1+i,L+i]<- 1.0 m5<- mm - 1 // Place the objective function for j= 1 to n do a.[m5,j]<- c.[j] i2<- m1+m2+m3; if (m4 > 0) then i1<- m1 + 1 //construct the secondary objective function for j= 1 to n do for i= i1 to i2 do a.[mm,j]<- a.[mm,j] + a.[i,j] j1<- n+m1+1 j2<- n+m1+m3 if (m3 > 0) then for j= j1 to j2 do a.[mm,j]<- -1.0 for i= i1 to i2 do a.[mm,nn]<- a.[mm,nn] + b.[i] for i= 1 to i2 do a.[i,nn]<- b.[i] a.[m5,nn]<- 0.0 // Load up the initial basic solution if (m1 > 0) then for i= 1 to m1 do kk.[i]<- i + n if (m4 > 0) then i1<- m1 + 1 for i= i1 to i2 do kk.[i]<- n+m1+m3+i-i1+1 else //If no constraint of Eq and Gt type, then no secondary // objective function is needed mm<- mm - 1 ifirst<- 0 u<- 0.0 while (ifirst = 0) || (u > eps) do ifirst<- 1 n5<- nn - 1; // Check for the pivot element find the largest // coefficient of the objective u<-a.[mm,1] j0<- 1 for j= 1 to n5 do if (a.[mm,j] > u) then u<- a.[mm,j] j0<- j if (u > eps) then Key<- 0 i0<- 0 while (Key = 0) && (i0 <= i2) do i0<- i0 + 1 if (a.[i0,j0] >= eps) then Key<- 1 // Test if there is a positive a[i,j] in this column // if not then the objective function is bounded if (Key = 0) then Kod<- 3 //goto 10; else if (i0 < i2) then i1<- i0 + 1 u<- a.[i0,nn]/a.[i0,j0] for i= i1 to i2 do if (a.[i,j0] >= eps) then if ((a.[i,nn]/a.[i,j0]) < u) then i0<- i u<- a.[i,nn]/a.[i,j0] //Perform the elimination step u<- a.[i0,j0] for j= 1 to nn do a.[i0,j]<- a.[i0,j]/u for i= 1 to mm do if (i <> i0) then for j= 1 to nn do if (j <> j0) then a.[i,j]<- a.[i,j]-a.[i0,j]*a.[i,j0] for i= 1 to mm do if (i <> i0) then a.[i,j0]<- 0.0; //Register the newest basis vector and go back to //perform the next step of elimination kk.[i0]<- j0 else if (m4 > 0) then L<- n+m1+m3; // Check for feasible solution from the secondary //objective for i= 1 to i2 do if (kk.[i] > L) then Kod<- 2 //goto 10; if Kod<>2 then mm<- mm - 1 // Remove artificail variables and the secondary //objective function m4<- 0 nm<- nn-m2-m3 for i= 1 to mm do a.[i,nm]<- a.[i,nn] nn<- nm ifirst<- 0 //From here we go back to continue elimination if Kod<>2 || Kod<>3 then Kod<- 1 // Set up the optimal solution for i= 1 to n do x.[i]<- 0.0 for i= 1 to i2 do j<- kk.[i]; x.[j]<- a.[i,nn] x.[n+1]<- -a.[mm,nn] x,Kod (* //Example 1 let n=2 let m1=3 let m2,m3=0,0 c.[1..2]<-[|3.0;2.0|] b.[1..3]<-[|18.0;42.0;24.0|] a.[1..3,1..2]<-array2D [[2.0;1.0];[2.0;3.0];[3.0;1.0]] let r=Linpro n m1 m2 m3 printfn "LP category: %i" (snd r) printfn "LP Objective Function: %A" ((fst r).[3]) printfn "LP Varaibles: %A" ((fst r).[1..2]) (* > LP category: 0 LP Objective Function: 33.0 LP Varaibles: [|3.0; 12.0|] *) *) //Example 2 (* R = –2x + 5y, subject to: x <= 200 y <= 170 x >= 100 y >= 80 y + x >= 200 Solution: x=100,y=170 *) let n=2 let m1=2 let m2=0 let m3=3 c.[1..2]<-[|-2.0;5.0|] b.[1..3]<-[|200.0;170.0;100.0;80.0;200.0|] a.Initialize() a.[1..5,1..2]<-array2D [[1.0;0.0];[0.0;1.0];[1.0;0.0];[0.0;1.0];[1.0;1.0]] let r=Linpro n m1 m2 m3 printfn "LP category: %i" (snd r) printfn "LP Objective Function: %A" ((fst r).[3]) printfn "LP Varaibles: %A" ((fst r).[1..2])