在 Java API 中使用 OPL 模型时出现 CPLEX 热启动错误

CPLEX warm start error when using OPL model in Java API

我正在尝试使用 Java API 进行热启动,但在将初始解决方案传递给 model 时遇到了一些问题。 在我的 model 文件 (.mod) 中,我有一个 2D 决策变量定义为,

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

在我的 java 文件中,我正在如下构建 model 并尝试使用 addMipStart() 函数(如 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
    }
}

不幸的是,我在调用 cplex.addMIPStart() 函数的行中遇到异常,

 [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)

我认为错误是由于我准备初始解决方案的方式造成的,有人可以帮我解决这个问题。

非常感谢。

问题是您正在创建 new 变量,而不是引用模型中的现有变量。 objective、约束等中不存在这些新变量,因此您得到 IloException(参见 this 技术说明)。

您应该能够访问现有变量,执行如下操作(请注意,此代码尚未经过测试):

    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);

看看Iterators.java example and the documentation for getElement