【问题标题】:CPLEX warm start error when using OPL model in Java API在 Java API 中使用 OPL 模型时出现 CPLEX 热启动错误
【发布时间】:2018-02-07 10:57:01
【问题描述】:

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

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

在我的 java 文件中,我正在构建如下模型并尝试使用 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)

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

非常感谢。

【问题讨论】:

    标签: java cplex opl


    【解决方案1】:

    问题在于您正在创建 变量,而不是引用模型中的现有变量。这些新变量不存在于目标、约束等,所以你得到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 示例和getElement 的文档。

    【讨论】:

    • 非常感谢您的评论。由于“service_time”是一个决策变量,我收到一个错误,[java] ### CONCERT 异常:类型 dvar int[nodes][vehicles] 预计元素“service_time”。 [java] at ilog.opl.IloOplElement.cpp_asNumVarMap(IloOplElement.java:506) addMIPStart() 函数也期望 IloNumVar[] 类型的数组作为 var 数组。有什么建议可以解决这个问题吗?
    • 我将 sn-p 更改为使用 IloIntVarMap 代替 serviceTime 而不是 IloNumVarMap。这能解决你的问题吗?
    猜你喜欢
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多