---------------------------------------------------------------------- -- Title : LineAK -- Version : 1.0 -- Author : David Wallace Croft, CompuServe [76600,102] -- Compiler : Ada -- Unit Type : package body -- Copyright : 1994 David Wallace Croft. All rights reserved. -- Description : Linear Programming & Game Theory ---------------------------------------------------------------------- with ConsAK ; use ConsAK ; with FloaAK ; use FloaAK ; with InteAK ; use InteAK ; with Text_IO; use Text_IO; package body LineAK is ---------------------------------------------------------------------- ---------------------------------------------------------------------- procedure Demo is ---------------------------------------------------------------------- begin Simplex_Revised_Demo; Pause; end Demo; procedure Simplex_Revised ( Degenerate : out boolean; X : out Vector_Type; Y : out Vector_Type; Z : out float; A : in Matrix_Type; B : in Vector_Type; C : in Vector_Type; Show : in boolean := false; Near_0 : in float := 1.0e-10 ) is ---------------------------------------------------------------------- -- Assumes A non-degenerate. -- -- Franklin, Joel. "Methods of Mathematical Economics: Linear and -- Non-linear Programming, Fixed-Point Theorem". Springer-Verlag: -- NY, 1980, pp93-. ---------------------------------------------------------------------- M : constant positive := A'last ( 1 ); N : constant positive := A'last ( 2 ); I : Matrix_Type ( 1..M, 1..M ); A1 : Matrix_Type ( 1..M, 1..( N + M ) ) := ( others => ( others => 0.0 ) ); C1 : Vector_Type ( 1..( N + M ) ); Tableau : Matrix_Type ( 0..M, 0..M ) := ( others => ( others => 0.0 ) ); U : Matrix_Type ( 1..M, 1..M ); Basis : Vector_Integer_Type ( 1..M ); Old_Basis : Vector_Integer_Type ( 1..M ); X_Temp : Vector_Type ( X'range ); Degenerate_Temp : boolean; begin Degenerate := false; if Show then Put_Line ( "Phase 1" ); end if; -- A1 := [ A, I ] A1 := Concatenate ( A, Identity ( I ) ); C1 := Concatenate ( Fill ( C ), Fill ( B, 1.0 ) ); -- T_i0 = B_i for I in 1..M loop Tableau ( I, 0 ) := B ( I ); end loop; -- U_ij = Delta_ij, initially the identity matrix. U := Identity ( U ); for I in 1..M loop for J in 1..M loop Tableau ( I, J ) := U ( I, J ); end loop; end loop; -- Z0 = Sum ( B_I ) for I in B'range loop Tableau ( 0, 0 ) := Tableau ( 0, 0 ) + B ( I ); end loop; -- Y_i = 1 for I in 1..M loop Tableau ( 0, I ) := 1.0; end loop; for index in Basis'range loop Basis ( index ) := N + index; end loop; loop if Show then Put_Line ( "Extended Tableau" ); Put_Line ( Tableau ); Put_Line ( "Basis" ); Put_Line ( Basis ); Pause; end if; Old_Basis := Basis; Simplex_Revised_2 ( Degenerate_Temp, Tableau, Basis, A1, C1, Show, Near_0 ); if Degenerate_Temp then Degenerate := true; return; end if; exit when Basis = Old_Basis; end loop; if Show then Put_Line ( "Phase 2" ); end if; -- recalculate Z(0) Tableau ( 0, 0 ) := 0.0; for index in Basis'range loop begin Tableau ( 0, 0 ) := Tableau ( 0, 0 ) + Tableau ( 0, index ) * C ( Basis ( index ) ); exception when constraint_error => if Show then Put_Line ( "Degenerate: B is a linear combination of fewer" & " than m columns of A" ); Put_Line ( "where m is the number of rows in A." ); Pause; end if; Degenerate := true; return; end; end loop; -- recalculate Y vector for J in 1..M loop Tableau ( 0, J ) := 0.0; for I in Basis'range loop Tableau ( 0, J ) := Tableau ( 0, J ) + Tableau ( I, J ) * C ( Basis ( I ) ); if abs ( Tableau ( 0, J ) ) < Near_0 then Tableau ( 0, J ) := 0.0; end if; end loop; end loop; loop Old_Basis := Basis; if Show then Put_Line ( "Extended Tableau" ); Put_Line ( Tableau ); Put_Line ( "Basis" ); Put_Line ( Basis ); Pause; end if; Simplex_Revised_2 ( Degenerate_Temp, Tableau, Basis, A, C, Show, Near_0 ); if Degenerate_Temp then Degenerate := true; return; end if; exit when Basis = Old_Basis; end loop; X_Temp := ( others => 0.0 ); for index in Basis'range loop begin X_Temp ( Basis ( index ) ) := Tableau ( index, 0 ); exception when constraint_error => if Show then Put_Line ( "Degenerate: no feasible solution exists." ); Pause; end if; Degenerate := true; return; end; end loop; X := X_Temp; for index in 1..M loop Y ( index ) := Tableau ( 0, index ); end loop; Z := Dot ( C, X_Temp ); end Simplex_Revised; procedure Simplex_Revised_2 ( Degenerate : out boolean; Tableau : in out Matrix_Type; Basis : in out Vector_Integer_Type; A : in Matrix_Type; C : in Vector_Type; Show : in boolean := false; Near_0 : in float := 1.0e-10 ) is ---------------------------------------------------------------------- -- p94 -- 0 1 2 ... M -- ------------------------- -- 0 | Z0 | Y1 Y2 ... YM | Extended Tableau Matrix format -- ------------------------- -- 1 | T10 | U11 U12 ... U1M | -- | | | -- 2 | T20 | U21 U22 ... U2M | -- | | | -- : | : | : : ... : | -- | | | -- M | TM0 | UM1 UM2 ... UMM | -- ------------------------- ---------------------------------------------------------------------- Case_2a : boolean; M : constant positive := Basis'last; R : natural := 0; S : natural := 0; T_S : Vector_Type ( 1..M ); Theta : Vector_Type ( 0..M ); Z : Vector_Type ( A'range ( 2 ) ); Non_Basic : boolean; Old_Row_R : Vector_Type ( Tableau'range ( 2 ) ); begin Degenerate := false; for J in A'range ( 2 ) loop -- Find a non-basic index j. Non_Basic := true; for index in Basis'range loop Non_Basic := Non_Basic and ( J /= Basis ( index ) ); exit when not Non_Basic; end loop; if Non_Basic then -- Check if the cost can be reduced. -- Z ( J ) := Y_t * A_J; Z ( J ) := 0.0; for I in 1..M loop Z ( J ) := Z ( J ) + Tableau ( 0, I ) * A ( I, J ); end loop; if Z ( J ) > C ( J ) then -- If so, move column J into the basis. S := J; exit; end if; end if; end loop; -- Otherwise, X is already optimal. if S = 0 then return; end if; if Show then Put_Line ( "Pivot column =" & positive'image ( S ) ); end if; -- Compute the pivot column of the simplex tableau. Case_2a := true; for I in 1..M loop T_S ( I ) := 0.0; for K in 1..M loop T_S ( I ) := T_S ( I ) + Tableau ( I, K ) * A ( K, S ); end loop; -- Check to see if costs can be driven to minus infinity. Case_2a := Case_2a and ( T_S ( I ) < 0.0 ); end loop; if Case_2a then if Show then Put_Line ( "Degenerate: cost can go to negative infinity." ); Pause; end if; Degenerate := true; return; end if; -- Choose the pivot row R. R := 0; for I in T_S'range loop if T_S ( I ) > 0.0 then if R = 0 then R := I; else if Tableau ( I, 0 ) / T_S ( I ) < Tableau ( R, 0 ) / T_S ( R ) then R := I; end if; end if; end if; end loop; -- Replace the Basis with S. if Show then Put_Line ( "Pivot row =" & positive'image ( R ) ); end if; Basis ( R ) := S; -- Setup the theta vector Theta ( 0 ) := ( Z ( S ) - C ( S ) ) / T_S ( R ); for I in 1..Tableau'last loop Theta ( I ) := T_S ( I ) / T_S ( R ); end loop; -- Compute new rows for Col in Tableau'range ( 2 ) loop Old_Row_R ( Col ) := Tableau ( R, Col ); end loop; for Row in Tableau'range ( 1 ) loop for Col in Tableau'range ( 2 ) loop if Row = R then Tableau ( R, Col ) := Old_Row_R ( Col ) / T_S ( R ); else Tableau ( Row, Col ) := Tableau ( Row, Col ) - Theta ( Row ) * Old_Row_R ( Col ); end if; if abs ( Tableau ( Row, Col ) ) < Near_0 then Tableau ( Row, Col ) := 0.0; end if; end loop; end loop; end Simplex_Revised_2; procedure Simplex_Revised_Demo is ---------------------------------------------------------------------- B_Last, C_Last : positive; Degenerate : boolean; begin Put_Line ( "Simplex_Revised_Demo (C) 1994 David Wallace Croft" ); New_Line; Put_Line ( "Given matrix A, requirement vector B, and cost vector C," ); Put_Line ( "find the solution vector X and shadow vector Y" ); Put_Line ( "for the primal A*X >= B, X >= 0, Transpose (C) * X = minimum" ); Put_Line ( "and the dual Transpose (Y) * A <= Transpose (C)," ); Put_Line ( "Transpose (Y) * B = maximum; also show the" ); Put_Line ( "cost Z = Transpose (C) * X = Transpose (Y) * B." ); Put_Line ( "This assumes the problem is non-degenerate." ); New_Line; B_Last := Ask_Pos ( "How many rows are in your vector B? ", 2, 1 ); C_Last := Ask_Pos ( "How many rows are in your vector C? ", 3, 1 ); declare A : Matrix_Type ( 1..B_Last, 1..C_Last ); B : Vector_Type ( 1..B_Last ); C : Vector_Type ( 1..C_Last ); X : Vector_Type ( 1..C_Last ); Y : Vector_Type ( 1..B_Last ); Z : float; begin Ask ( A, "Please enter the matrix A." ); Ask ( B, "Please enter the requirement vector B." ); Ask ( C, "Please enter the cost vector C." ); Simplex_Revised ( Degenerate, X, Y, Z, A, B, C, true ); if not Degenerate then Put_Line ( "Your solution vector X is" ); Put_Line ( X, 2, 4 ); Put_Line ( "Your shadow vector Y is" ); Put_Line ( Y, 2, 4 ); Put_Line ( "Your cost Z is" ); Put_Line ( Z, 2, 4 ); else Put_Line ( "The problem is degenerate; no solution is given using the" ); Put_Line ( "Revised Simplex Algorithm." ); end if; end; end Simplex_Revised_Demo; ---------------------------------------------------------------------- ---------------------------------------------------------------------- end LineAK;