Lindo Systems

! LINGO MODEL for interior point/barrier primal-dual method. (IntPtAlg.lg4)
   Original version by Kipp Martin. See article by
    Marsten, et. al.(1990) in INTERFACES, vol. 20, no. 4.;
 ! Keywords: Interior Point Method, Barrier Method;
SETS:
   ROW  : B, Y, DY;
   COL  : C, DX, X, DZ, Z;
   MATRIX( ROW, COL) : A;
ENDSETS

 ! Solve the optimization problem 
     Min CX
      s.t.
      AX = B,
       X >= 0,
 by solving approximately the system:
   1)  AX = B,     (Primal conditions)
   2)  A'Y - C = Z,(Dual conditions)
   3)  X >= 0,     (Non-negativity)
   4)  Z >= 0
   5)  ZX = 0.     (Complementarity)
 We start with a solution to the linear constraints, (1-4), and
 then use iterative approximation to satisfy (5);
  DATA:
   COL = A__ C__ D__ S_1 S_2 S_3;
   B = 60, 50, 120;       ! RHS;
   C = -20, -30, -47,  0,  0,  0; ! Objective coefficients, cost minimize form;
   A =   1,   0,   1,  1,  0,  0, ! Coefficient matrix for the;
         0,   1,   1,  0,  1,  0, ! Astro/Cosmo;
         1,   2,   3,  0,  0,  1; ! Problem in Schrage;

   X =   1    1    1  58  48 114; ! Initial feasible primal soln;
   Z =  40   60  103  30  30  30; ! Initial feasible reduced costs;
   Y =  30 30 30;      ! Initial dual prices;
   TOLZR  = .0000001;  ! Zero tolerance;
   TOLGAP = .00000005; ! Termination tolerance;
  ENDDATA

 SUBMODEL DIRECTION:
  !  Given a current point:
       X : feasible (nonnegative) primal point,
       Y : feasible dual prices,
       Z : feasible (nonnegative) reduced costs,
    Choose a direction: DX, DY and DZ that
     tries to better satisfy the complementary slackness constraint;

  ! The Primal equations: A*( X + DX) = B;
  @FOR( ROW( I):
   [P] @SUM( COL( J) : A( I, J)*( X( J) + DX( J))) = B( I);
       );

  ! The Dual equations: A*( Y + DY) -(Z + DZ) = -C;
  @FOR( COL( J):
   [D] @SUM( ROW( I): A( I, J) * ( Y( I) + DY( I))) -
    (Z( J) + DZ( J)) = -C( J)
      );

  ! The Complementary slackness equation:
    ( Z + DZ) * ( X + DX) =  0, or
    Z*X + Z*DX + DZ*X + DZ*DX = 0, 
    or the linear approximation
    Z*X + Z*DX + DZ*X ~ 0, ;
  ! and the linear approximation to it;
  @FOR( COL( J):
   [CM] ( Z( J) + DZ( J)) * X( J) + Z( J) * DX( J) = MU
       );

  ! Allow for movements in the negative direction;
  @FOR( ROW: @FREE( DY));
  @FOR( COL: @FREE( DX));
  @FOR( COL: @FREE( DZ));
 ENDSUBMODEL

 CALC:
   N = @SIZE( COL);
   ! Turn off all messages;
   @SET('TERSEO',3); ! Set to <= 2 for debugging;
   maxiter = 30; ! Seldom need more than this # iterations;
   more = 1;     ! Set to 0 when done;
   iter = 0;
   @WHILE( iter #LE# maxiter #AND# more:
    iter = iter + 1; 
    gap = @SUM( COL: X * Z); ! Duality gap;
    @WRITE(iter,') Current gap= ', gap,@NEWLINE(1));
! Marsten's rule for error target, MU;
    MU = gap / ( N * N);
    @SOLVE(  DIRECTION); ! Get the move direction;

   ! Calculate step size in the move direction so that
     X and Z remain > 0;
   !  Do not let any variable get too close to zero;
    ALPHAP = .995 * ( @MIN(COL( J) | DX( J) #LT# -TOLZR:
      -X(J) / DX(J)));
    ALPHAD = .995 * ( @MIN(COL( J) | DZ( J) #LT# -TOLZR:
      -Z(J) / DZ(J)));

   ! Move to the new point;
    @FOR( COL( J): X( J) = X( J) + ALPHAP * DX( J));
    @FOR( COL( J): Z( J) = Z( J) + ALPHAD * DZ( J));
    @FOR( ROW( I): Y( I) = Y( I) + ALPHAD * DY( I));

   ! Calculate primal and dual objectives;
    POBJ = -@SUM( COL: X * C);
    DOBJ = @SUM( ROW: Y * B);
    gap = DOBJ - POBJ ;

  ! Write out details of new point;
    @WRITE(' New Primal, Dual, Gap= ', @FORMAT(POBJ,'12.4f'),' ',@FORMAT(DOBJ,'12.4f'),' ',gap,@NEWLINE(1));
    @FOR( COL(j): @WRITE('        ',COL(j)));
    @WRITE(@NEWLINE(1),'X= ');
    @FOR( COL(j):
      @WRITE( @FORMAT(X(j),'10.3f'),' ');
        );
    @WRITE(@NEWLINE(1));
    @WRITE('Z= ');
    @FOR( COL(j):
      @WRITE( @FORMAT(Z(j),'10.3f'),' ');
        );
    @WRITE(@NEWLINE(1));
    @WRITE('Y= ');
    @FOR( ROW(i):
      @WRITE( @FORMAT(Y(i),'10.3f'),' ');
        );
    @WRITE(@NEWLINE(1));

    ! Exit if gap is small enough;
    @IFC( gap #LE# TOLGAP *( 1 + @ABS( @SUM( COL: C * X))): more = 0); 
    );
 ENDCALC