如何在CPLEX中实现Lazy Constraint Callback(java API)

时间:2017-11-29 14:33:41

标签: java callback cplex

目前我正在尝试使用MTZ子巡回消除约束来实现非对称容量车辆路径问题的CPLEX精确解。

当我尝试实现Lazy Constraint Callbacks时出现问题。更具体地说,我得到一个空指针异常。几乎没有实现回调的教程,所以非常感谢您的帮助。

这是我的代码:

CVRP类

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import ilog.concert.*;
import ilog.cplex.*;

public class ACVRP {

    // euclidean distance method
    public static double distance(int x1, int y1, int x2, int y2) {
        return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }

    public static void solveModel() {
        int n = 32; // number of customers
        int k = 5; // number of vehicles
        int c = 100; // capacity of vehicles

        int datacoords[][] = new int[n][2];
        double[][] node = new double[n][n]; // dissimilarity matrix
        int[] demand = new int[n]; // demand of every customer

        try {

            // load matrixes
            FileReader frd = new FileReader("demands.txt");
            FileReader frcoords = new FileReader("coords.txt");

            BufferedReader brd = new BufferedReader(frd);
            BufferedReader brcoords = new BufferedReader(frcoords);

            String str;
            int counter = 0;

            while ((str = brd.readLine()) != null) {

                String[] splitStr = str.trim().split("\\s+");

                demand[counter] = Integer.parseInt(splitStr[1]);
                counter++;
            }

            counter = 0;

            while ((str = brcoords.readLine()) != null) {

                String[] splitStr = str.trim().split("\\s+");

                datacoords[counter][0] = Integer.parseInt(splitStr[1]);
                datacoords[counter][1] = Integer.parseInt(splitStr[2]);

                counter++;
            }

            for(int i = 0; i < n; i++){
                for(int j = 0; j < n; j++){
                    node[i][j] = distance(datacoords[i][0],datacoords[i][1],datacoords[j][0],datacoords[j][1]);
                //  if (i == j ){
                //      node[i][j] = 99999999;
                //  }
                }
            }


            brd.close();
            brcoords.close();

            IloCplex cplex = new IloCplex();

            // variables
            IloIntVar[][] x = new IloIntVar[n][];
            for (int i = 0; i < n; i++) {
                x[i] = cplex.boolVarArray(n);
                for (int j = 0; j < n; j++) {
                    x[i][j].setName("x." + i + "." + j );
                }
            }

            // mtz variables
            IloNumVar[] u = cplex.numVarArray(n, 0, Double.MAX_VALUE);
            for (int j = 0; j < n; j++) {
                u[j].setName("u." + j);
            }

            //objective
            IloLinearNumExpr conObj = cplex.linearNumExpr();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if ( i != j ){
                        conObj.addTerm(node[i][j], x[i][j]) ;
                    }
                }
            }
            cplex.addMinimize(conObj);


            // constraints
            for (int i = 1; i < n; i++) {
                IloLinearNumExpr equation1 = cplex.linearNumExpr();
                for (int j = 0; j < n; j++) {
                    if (i!=j) {
                        equation1.addTerm(1.0, x[i][j]);
                    }
                }
                cplex.addEq(equation1, 1.0);
            }

            for (int j = 1; j < n; j++) {
                IloLinearNumExpr equation2 = cplex.linearNumExpr();
                for (int i = 0; i < n; i++) {
                    if (i!=j) {
                        equation2.addTerm(1.0, x[i][j]);
                    }
                }
                cplex.addEq(equation2, 1.0);
            }

            IloLinearNumExpr equation3 = cplex.linearNumExpr();
            for (int i = 1; i < n; i++) {
                equation3.addTerm(1.0, x[i][0]);
            }
            cplex.addEq(equation3, k);

            IloLinearNumExpr equation4 = cplex.linearNumExpr();
            for (int j = 1; j < n; j++) {
                equation4.addTerm(1.0, x[0][j]);
            }
            cplex.addEq(equation4, k);

            cplex.use(new LazyContstraintMTZ(n, c, demand, x, u, cplex));

            //parameters
            //cplex.setParam(IloCplex.Param.TimeLimit,50);
            //cplex.setParam(IloCplex.Param.Preprocessing.Reduce, 0); 
           // cplex.setParam(IloCplex.Param.RootAlgorithm, IloCplex.Algorithm.Primal); 


            // solve model
            cplex.solve();
            cplex.exportModel("model.lp");
            System.out.println(cplex.getBestObjValue());
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (i != j) {
                        if (cplex.getValue(x[i][j]) != 0) {
                            System.out.println("name: " + x[i][j].getName() + " value: " + cplex.getValue(x[i][j]));
                        }
                    }
                }
            }
            // end
            cplex.end();

        } catch (IloException | NumberFormatException | IOException exc) {
            exc.printStackTrace();
        }
    }

}

延迟约束的类:

import ilog.concert.*;
import ilog.cplex.*;

public class LazyContstraintMTZ extends IloCplex.LazyConstraintCallback {

    int n; // number of customers
    int c; // capacity of vehicles
    int[] demand; // demand of every customer
    IloIntVar[][] x;
    IloNumVar[] u;
    IloCplex cplex;
    IloRange[] rng;

    //constructor
    LazyContstraintMTZ(int n, int c, int[] demand, IloIntVar[][] x, IloNumVar[] u, IloCplex cplex){
        this.n = n;
        this.c = c;
        this.demand = demand;
        this.x = x;
        this.u = u;
        this.cplex = cplex;
    }


    protected void main() throws IloException {

        // Get the current x solution

    //  double[][] sol = new double[n][n];
    //  for (int i = 0; i < n; i++) {
    //      for (int j = 0; j < n; j++) {
    //          sol[i][j] = cplex.getValue(x[i][j]);
    //      }
    //  }


        for (int i = 1; i < n; i++) {
            for (int j = 1; j < n; j++) {
                if (i!=j && demand[i]+demand[j]<=c){
                    IloLinearNumExpr equation5 = cplex.linearNumExpr();
                    equation5.addTerm(1.0, u[i]);
                    equation5.addTerm(-1.0, u[j]);
                    equation5.addTerm(c, x[i][j]);
                    rng[i].setExpr(equation5);
                    rng[i].setBounds(Double.MIN_VALUE, c-demand[j]);
                    cplex.addLazyConstraint(rng[i]);                
                }
            }
        }

        for (int i = 1; i < n; i++) {
            IloLinearNumExpr equation6 = cplex.linearNumExpr();
            equation6.addTerm(1.0, u[i]);
            rng[i].setExpr(equation6);
            rng[i].setBounds(demand[i], c);
            cplex.addLazyConstraint(rng[i]);
        }

    }

}

1 个答案:

答案 0 :(得分:0)

据我所知,rng从未在您的回调类中初始化。因此,它始终是null,一旦您尝试在其中设置元素,就会得到NullPointerException。

请注意,您甚至不需要该数组。代替

rng[i].setExpr(equation5);
rng[i].setBounds(Double.MIN_VALUE, c-demand[j]);
cplex.addLazyConstraint(rng[i]);

你可以写

IloRange rng = cplex.range(Double.MIN_VALUE, equation5, c - demand[j]);
cplex.addLazyConstraint(rng);

(对于equation6也是如此)。

还请注意,Double.MIN_VALUE可能不是您想要的。这给出了大于0的最小可表示数字。我想您想要的是Double.NEGATIVE_INFINITY,以指定一个没有下限的范围。在这种情况下,您也可以写

IloRange rng = cplex.le(equation5, c - demand[j]);