Model
Use classes of Concert Technology for .NET users to build a model for the problem.
After you have written a description of the problem, you can use classes of Concert Technology for .NET users with CPLEX to build a model.
Step 2: Open the file
Open the file yourCPLEXhome \examples\src\tutorials\LPex1lesson.cs in your integrated development environment, such as Microsoft Visual
Studio.
Step 3: Create the model object
Go to the comment Step 3 in that file, and add this statement to create the Cplex model for your application.
Cplex cplex = new Cplex();
That statement creates an empty instance of the class Cplex . In the next steps, you will add methods that
make it possible for your application populate the model with data,
either by rows, by columns, or by nonzeros.
Step 4: Populate the model by rows
Now go to the comment Step 4 in that file, and add these lines to create a method to populate the empty model with data by rows.
internal static void PopulateByRow(IMPModeler model,
INumVar[][] var,
IRange[][] rng) {
double[] lb = {0.0, 0.0, 0.0};
double[] ub = {40.0,
System.Double.MaxValue,
System.Double.MaxValue};
INumVar[] x = model.NumVarArray(3, lb, ub);
var[0] = x;
double[] objvals = {1.0, 2.0, 3.0};
model.AddMaximize(model.ScalProd(x, objvals));
rng[0] = new IRange[2];
rng[0][0] = model.AddLe(model.Sum(model.Prod(-1.0, x[0]),
model.Prod( 1.0, x[1]),
model.Prod( 1.0, x[2])), 20.0);
rng[0][1] = model.AddLe(model.Sum(model.Prod( 1.0, x[0]),
model.Prod(-3.0, x[1]),
model.Prod( 1.0, x[2])), 30.0);
}
Those lines populate the model with data specific to
this particular example. However, you can see from its use of the
interface IMPModeler how to add ranged constraints to a model. IMPModeler is the Concert Technology interface typically
used to build math programming (MP) matrix models. You will see its
use again in Step 5 and Step 6.
Step 5: Populate the model by columns
Go to the comment Step 5 in the file, and add these lines to create a method to populate the empty model with data by columns.
internal static void PopulateByColumn(IMPModeler model,
INumVar[][] var,
IRange[][] rng) {
IObjective obj = model.AddMaximize();
rng[0] = new IRange[2];
rng[0][0] = model.AddRange(-System.Double.MaxValue, 20.0);
rng[0][1] = model.AddRange(-System.Double.MaxValue, 30.0);
IRange r0 = rng[0][0];
IRange r1 = rng[0][1];
var[0] = new INumVar[3];
var[0][0] = model.NumVar(model.Column(obj, 1.0).And(
model.Column(r0, -1.0).And(
model.Column(r1, 1.0))),
0.0, 40.0);
var[0][1] = model.NumVar(model.Column(obj, 2.0).And(
model.Column(r0, 1.0).And(
model.Column(r1, -3.0))),
0.0, System.Double.MaxValue);
var[0][2] = model.NumVar(model.Column(obj, 3.0).And(
model.Column(r0, 1.0).And(
model.Column(r1, 1.0))),
0.0, System.Double.MaxValue);
}
Again, those lines populate the model with data specific
to this problem. From them you can see how to use the interface IMPModeler to add columns to an empty model.
While for many examples population by rows may seem most
straightforward and natural, there are some models where population
by columns is a more natural or more efficient approach to implement.
For example, problems with network structure typically lend themselves
well to modeling by column. Readers familiar with matrix algebra may
view the method populateByColumn as the
transpose of populateByRow .
In this approach, range objects are created for modeling by column with only their lower and upper bound. No expressions over variables are given because building them at this point would be impossible since the variables have not been created yet. Similarly, the objective function is created only with its intended optimization sense, and without any expression.
Next the variables are created and installed in the existing
ranges and objective. These newly created variables are introduced
into the ranges and the objective by means of column objects, which
are implemented in the class IColumn. Objects
of this class are created with the methods Cplex.Column, and can be linked together with the method IColumn.And to form aggregate IColumn objects.
An IColumn object created
with the method ICplex.Column contains
information about how to use this column to introduce a new variable
into an existing modeling object. For example if obj is an IObjective object, cplex.Column(obj, 2.0) creates an IColumn object containing the information to install a new variable in
the expression of the IObjective object obj with a linear coefficient of 2.0 . Similarly, for an IRange constraint rng , the method call cplex.Column(rng,
-1.0) creates an IColumn object containing the information to install a new variable into
the expression of rng , as a linear term
with coefficient -1.0 .
In short, when you use a modeling-by-column approach,
new columns are created and installed as variables in all existing
modeling objects where they are needed. To do this with Concert Technology,
you create an IColumn object for every
modeling object in which you want to install a new variable, and link
them together with the method IColumn.And .
Step 6: Populate the model by nonzeros
Go to the comment Step 6 in the file, and add these lines to create a method to populate the empty model with data by nonzeros.
internal static void PopulateByNonzero(IMPModeler model,
INumVar[][] var,
IRange[][] rng) {
double[] lb = {0.0, 0.0, 0.0};
double[] ub = {40.0, System.Double.MaxValue, System.Double.MaxValue};
INumVar[] x = model.NumVarArray(3, lb, ub);
var[0] = x;
double[] objvals = {1.0, 2.0, 3.0};
model.Add(model.Maximize(model.ScalProd(x, objvals)));
rng[0] = new IRange[2];
rng[0][0] = model.AddRange(-System.Double.MaxValue, 20.0);
rng[0][1] = model.AddRange(-System.Double.MaxValue, 30.0);
rng[0][0].Expr = model.Sum(model.Prod(-1.0, x[0]),
model.Prod( 1.0, x[1]),
model.Prod( 1.0, x[2]));
rng[0][1].Expr = model.Sum(model.Prod( 1.0, x[0]),
model.Prod(-3.0, x[1]),
model.Prod( 1.0, x[2]));
}
In those lines, you can see how to populate an empty model with data indicating the nonzeros of the constraint matrix. Those lines first create objects for the objective and the ranges without expressions. They also create variables without columns; that is, variables with only their bounds. Then those lines create expressions over the objective, ranges, and variables and add the expressions to the model.
Step 7: Add an interface
Go to the comment Step 7 in the file, and add these lines to create a method that tells a user how to invoke this application.
internal static void Usage() {
System.Console.WriteLine(“usage: LPex1 <option>”);
System.Console.WriteLine(“options: -r build model row by row”);
System.Console.WriteLine(“options: -c build model column by column”);
System.Console.WriteLine(“options: -n build model nonzero by nonzero”);
}
Step 8: Add a command evaluator
Go to the comment Step 8 in the file, and add these lines to create a switch statement that evaluates the command that a user of your application might enter.
switch ( args[0].ToCharArray()[1] ) {
case ‘r’: PopulateByRow(cplex, var, rng);
break;
case ‘c’: PopulateByColumn(cplex, var, rng);
break;
case ‘n’: PopulateByNonzero(cplex, var, rng);
break;
default: Usage();
return;
}