Examples of Use
This section
In this section there are five examples to illustrate the use of the GMP
library. Each example consists of two paragraphs. The first paragraph
explains the basic problem and an algorithmic approach, while the second
paragraph provides the corresponding implementation in AIMMS using the
GMP procedures. Note that these algorithms could also have been
implemented using AIMMS’ regular SOLVE
statement, but at the cost of
one or more structure recognition steps during every iteration.
Indexed Mathematical Program Instances
Indexed mathematical program instances
AIMMS does not support indexed mathematical program declarations, which would result in a different mathematical program for every index value when generated. Using the GMP library, however, it is straightforward to generate indexed mathematical program instances
Declarations in AIMMS
Consider the following declarations
Set Cities {
Index : c, j;
}
Set SelectedCities {
SubsetOf : Cities;
Index : i;
}
together with a mathematical program declaration TransportModel
defining a standard transportation problem determining transports from
cities i
to j
. When SelectedCities
equals Cities
we
would solve the mathematical program for all possible combinations of
cities.
Procedure in AIMMS
Further assume that we have an element parameter
IndexedTransportModel(c)
into the set
AllGeneratedMathematicalPrograms
. The following procedure
illustrates how indexed mathematical program instances for every city
c
which restricts the transports from c
to all cities j
.
for ( c ) do
SelectedCities := {c};
IndexedTransportModel(c) := GMP::Instance::Generate( TransportModel,
"TransportModel-" + FormatString("%e", c) );
endfor;
Sensitivity Analysis
Parametric changes
Sensitivity analysis considers how the optimal solution, and the corresponding objective function value, change as a result of changes in input data. Using the GMP library, it is straightforward to write a procedure to determine these sensitivities for a discrete set of input values.
Procedure in AIMMS
The following procedure illustrates how parametric changes can be implemented using matrix manipulation functions. The resulting objective function values are stored in a separate identifier.
myGMP := GMP::Instance::Generate( MathProgramOfInterest );
for ( n ) do
GMP::Coefficient::Set( myGMP,
ResourceConstraint(SelectedResource),
ActivityVariable(SelectedActivity),
OriginalCoefficient + Delta(n) );
GMP::Instance::Solve( myGMP );
ObjectiveValue(n) := GMP::Solution::GetObjective(myGMP, 1);
endfor;
Finding a Feasible Solution for a Binary Program
Fixing one variable at a time
There have been instances in which the following simple but greedy heuristic was used successfully to solve a binary program. The algorithm considers linear programming solutions in sequence. During each iteration, the algorithm
selects the single variable that, of all the variables, is nearest but not equal to one of its bounds, and
fixes the value of this variable to that of the nearest bound.
As soon as such variables can no longer be found (and the last linear programming solution is optimal), a feasible integer solution to the binary program has been found.
Procedure in AIMMS
The following procedure illustrates how fixing one variable at a time can be implemented using matrix manipulation functions. The procedure terminates as soon as there is no solution, or all variables have been fixed.
relaxedGMP := GMP::Instance::Generate( RelaxedBinaryProgram );
GMP::Instance::Solve( relaxedGMP );
repeat
LargestLessThanOne := ArgMax( j | x(j) <= 1 - Tolerance, x(j) );
SmallestGreaterThanZero := ArgMin( j | x(j) >= Tolerance, x(j) );
break when ( RelaxedBinaryProgram.ProgramStatus = 'Infeasible' or
not ( LargestLessThanOne or SmallestGreaterThanZero ) );
if ( x(SmallestGreaterThanZero) < 1 - x(LargestLessThanOne) )
then GMP::Column::Freeze( relaxedGMP, x(SmallestGreaterThanZero), 0 );
else GMP::Column::Freeze( relaxedGMP, x(LargestLessThanOne), 1 );
endif;
GMP::Instance::Solve( relaxedGMP );
endrepeat;
Column Generation
Adding columns
Chapter 20 of the AIMMS book on Optimization Modeling describes a cutting stock problem. This problem is modeled as a linear program with an initial selection of cutting patterns. An auxiliary integer programming model is introduced to generate a new “best” pattern based on the current solution of the linear program and the corresponding shadow prices. Such a pattern is then added to the existing patterns in the linear program, and the next optimal solution is found. This process continues until no further improvement in the value of the objective function can be achieved.
Procedure in AIMMS
The following procedure illustrates how adding columns can be implemented using matrix manipulation functions. During each iteration of the overall process, two different mathematical programs are modified in turn.
cuttingStockGMP := GMP::Instance::Generate( CuttingStock );
GMP::Instance::Solve( cuttingStockGMP );
findPatternGMP := GMP::Instance::Generate( FindPattern );
GMP::Instance::Solve( findPatternGMP );
MaxPattern := 0;
while ( PatternContribution > 1 ) do
MaxPattern += 1;
AllPatterns += MaxPattern;
LastPattern := last(AllPatterns);
GMP::Column::Add( GMP: cuttingStockGMP, column: RollsUsed(LastPattern) );
for ( width ) do
GMP::Coefficient::Set( GMP : cuttingStockGMP,
row : MeetCutDemand(width),
column: RollsUsed(LastPattern),
value : CutsInPattern(width) );
endfor;
GMP::Instance::Solve( cuttingStockGMP );
for ( width ) do
GMP::Coefficient::Set( GMP : findPatternGMP,
row : PatternContribution,
column: CutsInPattern(width),
value : MeetCutDemand(width).ShadowPrice );
endfor;
GMP::Instance::Solve( findPatternGMP );
endwhile;
Here MaxPattern
is a parameter of type integer, AllPatterns
a
subset of Integers
, and LastPattern
an element parameter with
range AllPatterns
.
Sequential Linear Programming
Sequential linear programming
Linear constraints and a nonlinear objective function together form a special class of nonlinear programs. It is possible to solve a problem of this class by solving a sequence of linear programs. The main requirement is that the nonlinear objective function has first-order derivatives. The objective function can then be linearized around the solution of a previous linear program. By restricting the linearized function to an appropriate finite box, a new solution point is found. The sequence of linear programs terminates when the appropriate box has become sufficiently small. Upon termination, the optimal solution, as last found, is considered to be a local optimum of the underlying nonlinear program.
Procedure in AIMMS
The following procedure illustrates how sequential linear programming
can be implemented using matrix manipulation functions. The procedure
assumes the existence of finite upper and lower bounds on the variables,
and the presence of a function ComputeGradient
to compute the
required first partial derivatives with respect to the variables in the
objective function. To implement the function ComputeGradient
one
can, for instance, use the built-in GMP function
GMP::Solution::GetFirstOrderDerivative
(see also
Managing the Solution Repository).
linearizedGMP := GMP::Instance::Generate(LinearizedProgram);
GMP::Instance::Solve(linearizedGMP);
BoxWidth(j) := 0.1 * (x.upper(j) - x.lower(j));
x(j) := 0.5 * (x.upper(j) + x.lower(j));
while ( max( j, BoxWidth(j) ) > Tolerance ) do
ObjCoeff(j) := ComputeGradient(x)(j);
for (j) do
GMP::Column::SetLowerBound ( linearizedGMP, x(j),
max(x.lower(j), x(j) - 0.5*BoxWidth(j)) );
GMP::Column::SetUpperBound ( linearizedGMP, x(j),
min(x.upper(j), x(j) + 0.5*BoxWidth(j)) );
GMP::Coefficient::Set( linearizedGMP, ObjectiveRow,
x(j), ObjCoeff(j) );
endfor;
GMP::Instance::Solve(linearizedGMP);
BoxWidth(j) *= ShrinkFactor;
endwhile;