Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.

 View Only
Expand all | Collapse all

CPLEX warm start error when using OPL model in Java API

  • 1.  CPLEX warm start error when using OPL model in Java API

    Posted Wed February 07, 2018 05:25 AM

    Originally posted by: Chathura Thilanka


    Hello,

    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 the initial solution to the above decision variable,

    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.

     


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 2.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Wed February 07, 2018 07:02 AM

    hi

    have you had a look at the example at

    CPLEX_Studio128\opl\examples\opl\warmstart

    ?

    regards


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 3.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Wed February 07, 2018 07:10 AM

    Originally posted by: Chathura Thilanka


    Thanks Alex for the reply.

    Yes, I looked at that example too. There they have not used the Java API to generate and solve the model. The issue is with passing the initial solution to the model through Java by addMIPStart() method. I was unable to find any example regarding this.

     

    Thanks.


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 4.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Wed February 07, 2018 08:15 AM

    Hi,

    let me help you to bridge that gap:

    1) addMIPStart with 2D

    range r = 1..10;
    dvar int+ x[r][r];
    dvar int+ y[r][r];
    // The following array of values (defined as data) will be used as
    // a starting solution to warm-start the CPLEX search.
    float values[i in r][j in r] = ((i==5) &&(j==5))? 10 : 0;


    minimize
      sum( i in r ) x[i][i] + sum( j in r ) y[j][j];
    subject to{
      ctSum:    
        sum( i in r ) x[i][i] >= 10;
      forall( j in r )
        ctEqual:
          y[j][j] == j;
          
          forall(i,j in r : i != j)
            x[i][j] == 0;
          
    }

    main{
      thisOplModel.generate();  
      var def = thisOplModel.modelDefinition;   
      // Default behaviour
      writeln("Default Behaviour");
      var cplex1 = new IloCplex();
      var opl1 = new IloOplModel(def, cplex1);
      opl1.generate();
      cplex1.solve();   
      writeln(opl1.printSolution());
      // Setting initial solution
      writeln("Setting initial solution");
      var cplex2 = new IloCplex();
      var opl2 = new IloOplModel(def, cplex2);
      opl2.generate();
     
      cplex2.addMIPStart(opl2.x,opl2.values) ;
     
      cplex2.solve();   
      writeln(opl2.printSolution());

      opl1.end();
      cplex1.end();
      opl2.end();
      cplex2.end();
      0;
    }

    2) Examples on how to call OPL from java at CPLEX_Studio128\opl\examples\opl_interfaces\java

    In mulprod_main you will notice

    dataElements.getElement("Capacity").asNumMap().set("flour",capFlour);

    In your

    cplex.addMIPStart(flat_var2D, flat_var2D_startingVals, IloCplex.MIPStartEffort.Auto, "addMIPStart start");

    you should have for flat_var2D a 2D array that was extracted and that is in the cplex matrix

    regards


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 5.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Wed February 07, 2018 10:50 PM

    Originally posted by: Chathura Thilanka


    Thank you very much for your answer. It was helpful.

    I could successfully perform a warm start for my model as follows,

    There are 2 decisions variables in my model as,

    int x = 1..10; int y = 1..5;

    dvar boolean node_pair[x][x][y];
    dvar int service_time[x][z];

    I created 2 vectors in my mod file as,

    int initial_solution_node_pair[x][x][y] = ...;
    int initial_solution_service_time[x][y] = ...;

    and filled them with a feasible initial solution for a warm start.

     

    Then in my java code I attached the 2 initial solution vectors to the decision variables as,

    opl.generate();
    IloOplCplexVectors vecs = oplF.createOplCplexVectors();
    vecs.attach(opl.getElement("service_time").asIntVarMap(),opl.getElement("initial_solution_service_time").asIntMap());
    vecs.attach(opl.getElement("node_pair").asIntVarMap(),opl.getElement("initial_solution_node_pair").asIntMap());
    vecs.setStart(cplex); 

     

    By this way I could successfully do a warm start. I am wondering whether vecs.setStart() functions performs a  warm start same as in cplex.addMIPStart() function since the documentation says what setStart() does is it "restores the MIP start information".

     

    Thank You.

     

     


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 6.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Thu February 08, 2018 12:11 PM

    The difference between vecs.setStart() and cplex.addMIPStart() is the following:

    setStart() is the preferred function when you use OPL. It goes through the OPL layer and eventually sets this single start as MIP start for the underlying IloCplex object.

    addMIPStart() adds a MIP start to the underlying IloCplex object behind OPL's back. That is in general not a problem but not exactly nice. Additionally, as the method names suggest, using addMIPStart() you can add more than one MIP start while with setStart() you can only set one.

    BTW, here is the reason why your first attempt with addMIPStart() did not work: You created new variables and used those to define a MIP start. There is no relation between those variables and the variables defined in your .mod file. The right thing to do here would be to obtain the existing variables from the IloOplModel instance and use those to define the MIP start. It is a lot either to just do everything in the .mod, though.


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 7.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Thu February 08, 2018 09:40 PM

    Originally posted by: Chathura Thilanka


    Thank you very much for your explanation.

    Yeah, initially I was doing the addMIPStart() in a wrong way as you mentioned. The issue I had was extracting the decision variables from the model in as a IloNumVar[] to input to the  addMIPStart() function, as it is expecting IloNumVar[] type of an array as var array.

     

    For example when I try to do the following in my Java code,

        IloIntRange nodes = opl.getElement("nodes").asIntRange();
        IloIntRange vehicles = opl.getElement("vehicles").asIntRange();
        IloNumVarMap serviceTime = opl.getElement("service_time").asNumVarMap();

        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++) {
           IloNumVarMap 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);

     

    I am getting an exception as,

    
    ### CONCERT exception: Type dvar int[nodes][vehicles] expected for element "service_time". 
    [java] at ilog.opl.IloOplElement.cpp_asNumVarMap(IloOplElement.java:506)
    
    Do you have have any suggestions to overcome this issue?

     

    Thank you.


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 8.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Fri February 09, 2018 03:23 AM

    This sort of introspection is always a little complicated (which probably means you should avoid it Smile).

    First of all, since your variables are of type 'int' you need to convert to IntVarMap instead of NumVarMap. But then you have to jump through some more hoops. Here is a code that seems to work for your model (no guarantees):

    IloIntVarMap serviceTime = opl.getElement("service_time").asIntVarMap();
    System.out.println("Dimensions: " + serviceTime.getNbDim());
    // Since the ranges used to index the variable arrays in the .mod file may not be
    // 0-based or may be sparse we need indexer objects to access them.
    IloDiscreteDataCollectionArray indexer = serviceTime.makeMapIndexer();    
    IloDiscreteDataCollection firstIndex = indexer.get(0);
    IloDiscreteDataCollection secondIndex = indexer.get(1);
    System.out.println(firstIndex.getName() + ": " + firstIndex + ", " + firstIndex.isIntRange());
    System.out.println(secondIndex.getName() + ": " + secondIndex + ", " + secondIndex.isIntRange());
    IloIntVar[][] service_time = new IloIntVar[firstIndex.getSize()][];
    IloIntRange firstRange = (IloIntRange)firstIndex;
    IloIntRange secondRange = (IloIntRange)secondIndex;
    for (int i = 0; i < firstIndex.getSize(); ++i) {
      IloIntVarMap sub = serviceTime.getSub(i + firstRange.getLB());
      service_time[i] = new IloIntVar[sub.getSize()];
      for (int j = 0; j < secondIndex.getSize(); ++j) {
        IloIntVar v = sub.get(j + secondRange.getLB());
        service_time[i][j] = v;
        System.out.print(v);
      }
      System.out.println();
    }
    

     


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 9.  Re: CPLEX warm start error when using OPL model in Java API



  • 10.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Sun February 11, 2018 09:57 PM

    Originally posted by: Chathura Thilanka


    Hi Daniel,

    Thanks for your response, I tried the conversion from NumVarMap  to IntVarMap. The issue I am facing is  addMIPStart() expecting (IloNumVar[] vars,double[] values). Since my variables are of int type I am stuck in the addMIPStart() calling due to the argument mismatch.

     

    Thank you.


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 11.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Mon February 12, 2018 02:22 AM

    You have to copy the two-dimensional variable/value arrays into a single flat array.


    #DecisionOptimization
    #OPLusingCPLEXOptimizer


  • 12.  Re: CPLEX warm start error when using OPL model in Java API

    Posted Wed February 14, 2018 07:04 AM

    Originally posted by: Chathura Thilanka


    Thanks Daniel, It worked!


    #DecisionOptimization
    #OPLusingCPLEXOptimizer