Decision Optimization

Decision Optimization

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

 View Only
  • 1.  Java API- Question on generic callback implementation

    Posted Thu October 20, 2022 09:34 AM
    I am  solving traveling salesman problem(tsp),and I I am using generic callback implementation for subtour elimination. 
    Everythin is fine when I used Lazycallback(legacy callback),but when i am trying to use generic callback,I find that context.getCandidatePoint x[i][j] has problem.Results shows that sometimes I will encounter such a situation: for vertex i ,its indegree/outdegree ==0 or 2.I wonder why.
    Thanks!
    Here is my code.
    package benders;

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

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

    /**
    * @Author: Feng Jixuan
    * @Date: 2022-10-2022-10-20
    * @Description: algorithm
    * @version=1.0
    */
    public class Test {
    static int n = 127;
    static double[][] distance = new double[n][n];
    static double cost;
    static double[][] ans = new double[n][n];
    static double[] tour = new double[n];
    static ArrayList<Integer> subTour;
    static ArrayList<ArrayList<Integer>> subTourPool;
    static int run = 0;

    public static void main(String[] args) throws IloException, IOException {
    String path = "tsp" + n + ".txt";
    BufferedReader br = new BufferedReader(new FileReader(path));
    String line = null;
    int count = 0;
    while ((line = br.readLine()) != null) {
    String[] str = line.split("\\s+");
    for (int i = 0; i < n; i++) {
    distance[count][i] = Double.parseDouble(str[i]); //
    }
    count++;
    }
    long startTime = System.nanoTime();
    IloCplex cplex = new IloCplex();
    IloIntVar[][] x = new IloIntVar[n][n];

    for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
    if (i != j)
    x[i][j] = cplex.intVar(0, 1, "x" + i + "," + j);
    else
    x[i][j] = cplex.intVar(0, 0, "x" + i + "," + j);
    }
    }

    for (int i = 0; i < n; i++) {
    IloLinearIntExpr constraint = cplex.linearIntExpr();
    for (int j = 0; j < n; j++) {
    constraint.addTerm(x[j][i], 1);
    }
    cplex.addEq(cplex.sum(x[i]), 1, "outDegree " + i);
    cplex.addEq(constraint, 1, "inDegree " + i);
    }
    IloLinearNumExpr obj = cplex.linearNumExpr();
    for (int i = 0; i < n; i++) {
    obj.add(cplex.scalProd(x[i], distance[i]));
    }
    cplex.addMinimize(obj);
    cplex.exportModel("test.lp");
    MyCallback callback=new MyCallback(x);
    System.exit(0);
    cplex.use(callback,IloCplex.Callback.Context.Id.Candidate);
    // cplex.use(new MyCallback(x,cplex));
    cplex.solve();
    System.out.println(cplex.getObjValue());
    long endTime = System.nanoTime();
    System.out.println("Time cost=" + (endTime - startTime) / 1000000000.0 + "s");
    }

    private static class MyCallback implements IloCplex.Callback.Function {
    private final IloIntVar[][] x;
    // IloCplex cplex;
    private ArrayList<Integer> subTour;
    private ArrayList<ArrayList<Integer>> subTourPool;
    private double[][] arcs;

    private MyCallback(IloIntVar[][] x) {
    this.x = x;
    }

    public void invoke(IloCplex.Callback.Context context) throws IloException {
    if (context.inCandidate()) {
    arcs = new double[n][n];
    for (int i = 0; i < n; i++) {
    arcs[i] = context.getCandidatePoint(x[i]);
    }

    for (int i = 0; i < n; i++) {
    System.out.print(Arrays.toString(arcs[i]));
    for (int j = 0; j < n; j++) {
    if (arcs[i][j]>0.9) System.out.print(i+"_"+j);
    }
    System.out.println();
    }
    IloCplex cplex=context.getCplex();
    if ( !context.isCandidatePoint() )
    throw new IloException("Unbounded solution");

    if (!checkSubTour()) {
    while (!subTourPool.isEmpty()) {

    subTour = subTourPool.get(0);
    subTourPool.remove(0);
    IloLinearNumExpr constraint2 = cplex.linearNumExpr();
    System.out.println(subTour.toString());
    for (int i : subTour) {
    for (int j : subTour) {
    constraint2.addTerm(1, x[i][j]);
    }
    }
    System.out.println("Adding lazy capacity constraint " + constraint2 +"<="+
    (subTour.size() - 1));
    context.rejectCandidate((IloRange) cplex.le(constraint2, subTour.size() - 1));
    }
    }
    // cplex.exportModel("test"+n+"_"+run+".lp");
    }
    }

    public boolean checkSubTour() {
    run++;
    System.out.println("------------------" + run + "-----checkSubTour-----------------------");
    subTourPool = new ArrayList<ArrayList<Integer>>();

    int[] visited = new int[n];
    for (int i = 0; i < n; i++) {
    if (visited[i] == 1) {
    continue;
    }
    subTour = new ArrayList<Integer>();
    int cur = i;
    System.out.println("break");
    do {
    subTour.add(cur);
    visited[cur] = 1;
    boolean f=false;
    for (int j = 0; j < n; j++) {
    if (arcs[cur][j] > 0.9) {
    cur = j;
    break;
    }
    }
    } while (cur!= i);
    subTourPool.add(subTour);
    System.out.println(subTour.toString());
    }
    if (subTourPool.size() == 1) {
    System.out.println("end");
    return true;
    } else {
    System.out.println("Left:" + subTourPool.size() + " subtours");
    return false;
    }
    }
    }
    }


    ------------------------------
    Jixuan Feng
    ------------------------------

    #DecisionOptimization


  • 2.  RE: Java API- Question on generic callback implementation

    Posted Thu October 20, 2022 05:38 PM
    Immediately after calling the callback constructor, you have System.exit(0). The program should stop there, which is a bit of a conundrum. Besides that, can you reproduce the problem with a smaller test example and, if so, post the output obtained when printing the values of x[][] in the callback?

    ------------------------------
    Paul Rubin
    Professor Emeritus
    Michigan State University
    ------------------------------



  • 3.  RE: Java API- Question on generic callback implementation

    Posted Thu October 20, 2022 10:13 PM
    Edited by System Admin Fri January 20, 2023 04:20 PM
    Thank you very much! !!!!!
    I am sorry.I forget to delete it. "System.exit(0)" is for test. I have modify my code and set the thread num to 1 to avoid issues on thread safety. But I still encounter error "CPLEX Error 1217: No solution exists."
    Here is my latest version of code. Now x[][] are ok . I wonder why no solution exists.Because I am sure that the same idea works when I was using Lazycallback(legacy callback)
    Besides, when I set the thread num to default(=8), cplex.solve() will stuck. I am not so familiar with thread safety. Does that have anything to do with it?
    I am very honored that you could help me!!!!

    package benders;


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


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

    /**
    * @Author: Feng Jixuan
    * @Date: 2022-10-2022-10-20
    * @Description: algorithm
    * @version=1.0
    */
    public class Test {
    static int n = 29;
    static double[][] distance = new double[n][n];
    static double cost;
    static double[][] ans = new double[n][n];
    static double[] tour = new double[n];
    static int run = 0;

    public static void main(String[] args) throws IloException, IOException {
    String path = "tsp" + n + ".txt";
    BufferedReader br = new BufferedReader(new FileReader(path));
    String line = null;
    int count = 0;
    while ((line = br.readLine()) != null) {
    String[] str = line.split("\\s+");
    for (int i = 0; i < n; i++) {
    distance[count][i] = Double.parseDouble(str[i]);
    }
    count++;
    }
    long startTime = System.nanoTime();
    IloCplex cplex = new IloCplex();
    IloIntVar[][] x = new IloIntVar[n][n];

    for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
    if (i != j)
    x[i][j] = cplex.intVar(0, 1, "x" + i + "," + j);
    else
    x[i][j] = cplex.intVar(0, 0, "x" + i + "," + j);
    }
    }
    for (int i = 0; i < n; i++) {
    IloLinearIntExpr constraint = cplex.linearIntExpr();
    for (int j = 0; j < n; j++) {
    constraint.addTerm(x[j][i], 1);
    }
    cplex.addEq(cplex.sum(x[i]), 1, "outDegree " + i);
    cplex.addEq(constraint, 1, "inDegree " + i);
    }
    IloLinearNumExpr obj = cplex.linearNumExpr();
    for (int i = 0; i < n; i++) {
    obj.add(cplex.scalProd(x[i], distance[i]));
    }
    cplex.addMinimize(obj);
    MyCallback callback = new MyCallback(x);
    cplex.use(callback, IloCplex.Callback.Context.Id.Candidate);
    cplex.setParam(IloCplex.Param.Threads, 1);
    // cplex.setParam( IloCplex.Param.Preprocessing.Presolve,false);
    cplex.solve();
    System.out.println(cplex.getStatus());
    System.out.println(cplex.getObjValue());
    long endTime = System.nanoTime();
    System.out.println("Time cost=" + (endTime - startTime) / 1000000000.0 + "s");
    }

    private static class MyCallback implements IloCplex.Callback.Function {
    private final IloIntVar[][] x;


    private MyCallback(IloIntVar[][] x) {
    this.x = x;
    }

    public void invoke(IloCplex.Callback.Context context) throws IloException {

    if (context.inCandidate()) {
    if (!context.isCandidatePoint())
    throw new IloException("Unbounded solution");
    int n = x.length;
    IloCplex cplex = context.getCplex();
    ArrayList<Integer> subTour;
    ArrayList<ArrayList<Integer>> subTourPool = new ArrayList<ArrayList<Integer>>();
    double[][] arcs;
    arcs = new double[n][n];
    for (int i = 0; i < n; i++) {
    arcs[i] = context.getCandidatePoint(x[i]);
    }
    //check
    for (int i = 0; i < n; i++) {
    double s = 0;
    for (int j = 0; j < n; j++) {
    s += arcs[i][j];
    }
    if (Math.abs(s - 1) > 0.001) System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! hang");
    }
    for (int i = 0; i < n; i++) {
    double s = 0;
    for (int j = 0; j < n; j++) {
    s += arcs[j][i];
    }
    if (Math.abs(s - 1) > 0.001) System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! lie");
    }
    int threadNo = context.getIntInfo(IloCplex.Callback.Context.Info.ThreadId);
    System.out.println("-----------------------checkSubTour----------------------- ");
    boolean check;
    int[] visited = new int[n];
    for (int i = 0; i < n; i++) {
    if (visited[i] == 1) {
    continue;
    }
    subTour = new ArrayList<Integer>();
    int cur = i;
    do {
    subTour.add(cur);
    visited[cur] = 1;
    for (int j = 0; j < n; j++) {
    if (arcs[cur][j] > 0.9) {
    cur = j;
    break;
    }
    }
    } while (cur != i);
    subTourPool.add(subTour);
    System.out.println(subTour);
    }
    if (subTourPool.size() == 1) {
    System.out.println("solve");
    check = true;
    } else {
    System.out.println("left" + subTourPool.size() + "subtour");
    check = false;
    }

    if (!check) {
    while (!subTourPool.isEmpty()) {
    System.out.println("11111111111111111111111111111");
    subTour = subTourPool.get(0);
    subTourPool.remove(0);
    IloLinearNumExpr constraint2 = cplex.linearNumExpr();
    System.out.println(subTour.toString());
    for (int i : subTour) {
    for (int j : subTour) {
    constraint2.addTerm(1, x[i][j]);
    }
    }
    System.out.println("Adding lazy capacity constraint " + constraint2 + "<=" + (subTour.size() - 1));
    context.rejectCandidate(cplex.le(constraint2, subTour.size() - 1));
    }
    }
    }
    }


    }
    }


    ------------------------------
    Jixuan Feng
    ------------------------------



  • 4.  RE: Java API- Question on generic callback implementation

    Posted Fri October 21, 2022 12:46 AM
    Hi Mr. Rubin!
    I think I know what is happening! The data is to accuracy, which may cause problem when cplex is handling floating point number!
    Here is a glance of the distance matrix.Afrer I transform it to integer, everything is ok!

    Anyway, Thanks for your time! I learned a lot from you replies and your blogs!!

    ------------------------------
    Jixuan Feng
    ------------------------------



  • 5.  RE: Java API- Question on generic callback implementation

    Posted Fri October 21, 2022 03:29 PM
    There is no reason why objective values with fractional coefficients would cause CPLEX to generate a candidate solution that violated any of the constraints. When you round/truncate the objective coefficients to integer, you change the model, which may lead to different results. So possibly you have a problem in the model that still remains, but the change leads CPLEX to a different trajectory on this particular model instance that (by luck) avoids the problem.

    I have never used the code structure you are using (making the callback a static subclass, making the master IloCplex object a local variable in a method rather than a class field and then having to recover it in the callback with context getCplex() method, ...), so it's hard for me to see if this would cause thread safety errors. The only class variable in the callback, x, is written to only in the constructor, with all other variable changes occurring to variables local to the invoke method, so I don't see much potential for thread collisions ... but I'm no expert on thread safety either. If you are getting error 1217 with the original distance matrix but not with the integer distance matrix, I would suggest the following experiment:

    1. solve with the integer distances and record the solution (call it "sol1");
    2. return the distance matrix to the original double precision values, and in the code setting up the model fix every variable to its value in "sol1" (by setting lower bound = upper bound = value for each variable);
    3. solve again and, if error 1217 occurs, try to get a minimal conflict set, which will identify which constraints are not satisfied by "sol1".
    If "sol1" ends up satisfying the original constraints but violating one of the Benders cuts, then you need to see whether your subproblem is generating incorrect Benders cuts for some reason.

    ------------------------------
    Paul Rubin
    Professor Emeritus
    Michigan State University
    ------------------------------



  • 6.  RE: Java API- Question on generic callback implementation

    Posted Fri October 21, 2022 09:56 PM
    Edited by System Admin Fri January 20, 2023 04:24 PM
    Thank you very much! I have learned a lot!
    Thank you very much! I have learned a lot! It's very interestring to discuss with you.
    I still think CPLEX has some troubles handling decimals.I will try my best to expain.
    I have 3 TSP instances(Let's call them A,B,and C).Only A has fractional distance matrix.
    At first,I try to solve TSP using constraint generation(without callback).First, I model it as an Assignment Problem,solve it ,find all the subtours, generate constraints to eliminate subtours and add them to the model,and solve the model again(using a while loop. If there is no subtoor, the program ends). The program can handle instance B,C real quickly(and I get the correct answers), but it stuck when it comes to instance A. After I truncate the data to integer, everything is OK. Here is the CPLEX log where it stucks.



    Then, I try to solve TSP using Lazycallback.Again, I model it as an Assignment Problem, using lazycallback to eliminate subtours.It results that: solving B,C real quickly. But I get error 1217 with the original distance matrix of instance A.After I truncate the data to integer, everything is OK.

    At last, I try to solve TSP using generic callback. I encounter excatly the same problem : error 1217 with original data ... and everything is OK after I truncate the data to integer.

    What's more,it reminds to me that I once met similar problem when I used column generation to solve VRPTW.When it comes to calculate and compare the Reduced Cost , it seems necessary to truncate.Otherwise, the solve time is extremely slow.

    That's why I think CPLEX may have some troubles handling decimals. I am looking forward to you reply!
    ------------------------------
    Jixuan Feng
    ------------------------------



  • 7.  RE: Java API- Question on generic callback implementation

    Posted Sat October 22, 2022 12:14 PM
    Here are a few comments.

    1. It would be better to paste log output in as text rather than use a screenshot (which is a bit hard to read).
    2. Your log screenshot shows CPLEX solving the root relaxation very quickly. Nothing in the log indicates any problem with feasibility. If the feasibility issue came up later (in a callback), I would look to see if perhaps the cut separator was producing incorrect cuts.
    3. Do you have any constraints regarding distance, or does distance appear only in the objective function? It is not possible for the objective matrix to make a problem infeasible, since feasibility has nothing to do with the objective function.
    4. Error 1217 does not necessarily imply infeasibility. I believe it is also thrown if you attempt to access a solution that CPLEX has not yet found. So, for instance, if in a callback (candidate context) you were to ask CPLEX for the final solution as opposed to the candidate solution, I think you might get this error. Again, I don't see how there would be any connection between this (a bug in your code) and whether the distance matrix contained integer values.
    5. Where exactly is the error thrown (which line in your code)?


    ------------------------------
    Paul Rubin
    Professor Emeritus
    Michigan State University
    ------------------------------



  • 8.  RE: Java API- Question on generic callback implementation

    Posted Thu October 27, 2022 05:25 AM
    Hi Paul!
       Sorry for reply so late. And thank you so much for your kindness.
        I do not have any constraints regarding distance,and I still can not find any problem about the model/code. About comment 5, there is no error. The problem is:the log I showed is excatly where the programme keep running but no logs update. I think CPLEX is solving because CPU is fully utilized. That's why I think CPLEX might have some issues about decimals(of course I am not sure).
       Anyway, now I am more familiar of generic callback.Thanks for all your reply. I am very grateful!!



    ------------------------------
    Jixuan Feng
    ------------------------------