1

I am trying to do a warm start using the Java API and having some issues when passing the initial solution to the model. In my model file(.mod) I have a 2D decision variable defined as,

range nodes = 1..5;
range vehicles = 1..2;
dvar int service_time[nodes][vehicles];

In my java file I am building the model as below and trying to pass an initial solution to the above decision variable using the addMipStart() function (as described here),

static public void main(String[] args) throws Exception {


    int status = 127;

    try {

        IloOplFactory.setDebugMode(true);
        IloOplFactory oplF = new IloOplFactory();
        IloOplErrorHandler errHandler = oplF.createOplErrorHandler(System.out);
        IloOplModelSource modelSource = oplF.createOplModelSource(DATADIR + "/myModFile.mod");
        IloOplSettings settings = oplF.createOplSettings(errHandler);
        IloOplModelDefinition def = oplF.createOplModelDefinition(modelSource, settings);

        IloCplex cplex = oplF.createCplex();
        IloOplModel opl = oplF.createOplModel(def, cplex);

        //adding the custom data source
        IloOplDataSource dataSource = new VRPDataSource(oplF);
        opl.addDataSource(dataSource);

        //generating the model
        opl.generate();

        //creating the initial solution
        int i = 5;
        int j = 2;

        IloIntVar[][] var2D = new IloIntVar[i][];
        double[][] var2D_startingVals = new double[i][];

        for(int index1=0; index1 < i; index1++){
            var2D[index1] = new IloIntVar[j];
            var2D_startingVals[index1] = new double[j];

            for(int index2 = 0; index2 < j; index2++){
                String varName = "service_time("+ (index1+1) +")("+ (index2+1) +")";
                var2D[index1][index2] = cplex.intVar(0, 50, varName);

                //lets assume a unit matrix as the starting solution
                var2D_startingVals[index1][index2] = 1;
             }
         }

        //flatten the multi-dimensional IloNumVar and double arrays

        IloNumVar[] flat_var2D = new IloNumVar[i*j];
        double[] flat_var2D_startingVals = new double[i*j];
        for(int index1=0; index1 < i; index1++){
            for(int index2=0; index2 < j; index2++){
                flat_var2D[index1*j + index2] = var2D[index1][index2];
                flat_var2D_startingVals[index1*j + index2] = var2D_startingVals[index1][index2];
            }
        }

        // adding the MIPStart
        cplex.addMIPStart(flat_var2D, flat_var2D_startingVals, IloCplex.MIPStartEffort.Auto, "addMIPStart start");

        if(cplex.solve()){
            // more code
        }else{
            // more code
        }

        // more code

    }catch(Exception ex){
        // more code
    }
}

Unfortunately I am having an exception in the line which calls the cplex.addMIPStart() function as,

 [java]     ### CONCERT exception: The referenced IloExtractable has not been extracted by the IloAlgorithm
 [java]     ilog.concert.IloException: The referenced IloExtractable has not been extracted by the IloAlgorithm
 [java]     at ilog.cplex.cppimpl.cplex_wrapJNI.IloCplex_addMIPStart__SWIG_0(Native Method)
 [java]     at ilog.cplex.cppimpl.IloCplex.addMIPStart(IloCplex.java:866)
 [java]     at ilog.cplex.IloCplex.addMIPStart(IloCplex.java:13219)
 [java]     at ilog.cplex.IloCplex.addMIPStart(IloCplex.java:13228)
 [java]     at myJavaClass.myJavaClass.main(myJavaClass.java:412)

I am thinking the error is due to the way I prepare the initial solution, can somebody please help me to sort this out.

Thank you very much.

1 Answers1

0

The problem is that you're creating new variables, not referencing the existing variables in the model. These new variables do not exist in the objective, constraints, etc., so you get the IloException (see this technote).

You should be able to access the existing variables doing something like the following (note that this code has not been tested):

    IloIntRange nodes = opl.getElement("nodes").asIntRange();
    IloIntRange vehicles = opl.getElement("vehicles").asIntRange();
    IloIntVarMap serviceTime = opl.getElement("service_time").asIntVarMap();

    final int nbNodes = nodes.getSize();
    final int nbVehicles = vehicles.getSize();

    IloNumVar[] startX = new IloNumVar[nbNodes * nbVehicles];
    double[] startVals = new double[nbNodes * nbVehicles];
    for (int i = 0; i < nbNodes; i++) {
       IloIntVarMap inner = serviceTime.getSub(nodes.getValue(i));
       for (int j = 0; j < nbVehicles; j++) {
          int idx = i * nbVehicles + j;
          startX[idx] = inner.get(vehicles.getValue(j));
          startVals[idx] = 1.0;
       }
    }

    cplex.addMIPStart(startX, startVals);

Take a look at the Iterators.java example and the documentation for getElement.

rkersh
  • 4,447
  • 2
  • 22
  • 31
  • Thank you very much for your comment. Since "service_time" is a decision variable I am getting an error as, [java] ### CONCERT exception: Type dvar int[nodes][vehicles] expected for element "service_time". [java] at ilog.opl.IloOplElement.cpp_asNumVarMap(IloOplElement.java:506) Also the addMIPStart() function is expecting IloNumVar[] type of an array as var array. Any suggestion to overcome this? – Chathura Thilanka Feb 08 '18 at 03:32
  • I changed the snippet to use an `IloIntVarMap` for `serviceTime` instead of an `IloNumVarMap`. Does that fix it for you? – rkersh Feb 09 '18 at 18:33