ILOG CPLEX 11.0 Getting Started > Tutorials > Concert Technology Tutorial for .NET Users > Model

After you have written a description of the problem, you can use classes of ILOG Concert Technology for .NET users with ILOG 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 ILOG 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;
         }