Модель Гуроби оптимальна, но ограничения нарушены

Я пишу расширение проблемы маршрутизации транспортных средств (VRP) в JAVA с помощью Gurobi. У меня проблема в том, что когда я запускаю свой код, JAVA говорит, что он оптимален с объективным значением ноль. Который не должен быть, так как:

VRP работает с дугами и узлами. Используется ли дуга, определяется переменной Xijk (путешествуете ли вы от узла i до узла j на транспортном средстве k). В VRP, помимо прочего, существуют ограничения на то, что каждого клиента нужно посещать ровно один раз. Это означает, что по крайней мере один Xijk для клиента j должен быть один. Какое транспортное средство k используется и каким был предыдущий посещенный мной узел, вы просите, чтобы Гуроби выяснил.

Таким образом, только когда в целевой функции есть переменные Xijk с нулевым коэффициентом затрат, логично, что объективное значение равно нулю. Однако для меня это не так, так как я (пере) пишу целевую функцию в конце моего кода и использую расстояние между узлами i до j в качестве фактора стоимости. Даже когда я смотрю на формулировку модели, которая получается с помощью "model.write("constraintOutput.lp")", я вижу целевую функцию, которая содержит переменные Xijk с коэффициентом стоимости>0.

Итак, я искал решение, и люди упоминали, что проблема может быть:

а. При инициализации переменных третий параметр не должен быть равен нулю, поскольку он говорит о том, каким должен быть "фактор стоимости" переменной в целевой функции. Поскольку я пишу свое ограничение в последней части моего кода перед оптимизацией моей модели, я считаю, что это не должно иметь значения. Хотя я изменил этот параметр с нуля до единицы при инициализации переменных Xijk, но проблема все еще остается.

б. Я должен обновить мою модель после инициализации моих переменных и ограничений. Я сделал это, но снова проблема все еще остается.

Я даже уменьшил свою модель, сняв некоторые ограничения, но это не помогает.

У кого-нибудь есть идеи, как решить эту проблему?

Мой код:

import java.util.ArrayList;
import gurobi.GRB;
import gurobi.GRBEnv;
import gurobi.GRBException;
import gurobi.GRBLinExpr;
import gurobi.GRBModel;
import gurobi.GRBVar;

public class VRP {

public int M;                               //big number
public int speed;                           //speed km/h
public int nDepots;                         //number of depots
public int nCustomers;                      //number of customers to be visited
public ArrayList<Node> allLocations;        //All locations
public ArrayList<Vehicle> vehicleList;      //Vehicles 
public double [][] dm;                      //distance matrix

public VRP(ArrayList<Node> n, ArrayList<Node> d, ArrayList<Node> dummyd, ArrayList<Vehicle> v, double [][] distanceMatrix) throws Exception {
    this.M = 1000;
    this.speed = 60000;

    this.vehicleList = v;

    this.allLocations = new ArrayList<Node>();
    this.allLocations.addAll(d);
    this.allLocations.addAll(n);

    this.nDepots = d.size();
    this.nCustomers = n.size();

    this.dm = distanceMatrix;
}

public void solution() throws Exception{

    Functions f = new Functions();

    // 1. DEFINE MODEL ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    try{
        GRBEnv env = new GRBEnv ();
        env.set(GRB.IntParam.OutputFlag, 0);        //set to 1 to get constraint overview

        GRBModel model = new GRBModel(env);
        model.set ( GRB.StringAttr.ModelName, "VRP" );

        // 2. DEFINE VARIABLES ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

        //Xijqk

        GRBVar[][][] x = new GRBVar[this.allLocations.size()][this.allLocations.size()][this.vehicleList.size()];       

        for (int i = 0; i<this.allLocations.size(); i++){
            for (int j = 0; j < this.allLocations.size(); j++){
                for (int k = 0; k < this.vehicleList.size(); k++){

                    double dij = f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID);
                    //get.Distance retrieves the distance between two nodes that are indicated by their IDs

                    x[i][j][k] = model.addVar(0.0, 1.0, dij, GRB.BINARY, "X" + i + j + k);              //arc between node i and j used by vehicle k or not             
                }//k
            }//j
        }//i

        //aik: arival time at customer i by vehicle k 

        GRBVar[][] a = new GRBVar[this.allLocations.size()][this.vehicleList.size()];

        for (int i = 0; i<this.allLocations.size(); i++){
            for (int k = 0; k < this.vehicleList.size(); k++){
                a[i][k] = model.addVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "a" + i + k);                //arival time at node i by vehicle k 
            }//k
        }//i

        //dep: departure time from customer i by vehicle k

        GRBVar[][] dep = new GRBVar[nDepots][this.vehicleList.size()];

        for (int i = 0; i < nDepots; i++){
            for (int k = 0; k < this.vehicleList.size(); k++){
                dep[i][k] = model.addVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "dep" + i + k);                //departure time from depot i by vehicle k 
            }//k
        }//i

        model.update();

        //3. DEFINE CONSTRAINTS 

        //Constraint 1
        for (int j = nDepots; j < this.allLocations.size(); j++){

            GRBLinExpr lhs = new GRBLinExpr();
            for(int i = 0; i < this.allLocations.size(); i++){
                for (int k = 0; k < this.vehicleList.size(); k++){
                    lhs.addTerm(1, x[i][j][k]);
                }//k
            }//i

            GRBLinExpr rhs = new GRBLinExpr();
            rhs.addConstant(1);

            model.addConstr(lhs, GRB.EQUAL, rhs, "Constraint 1");
        }//j

        //Constraint 2
        for (int i = nDepots; i < this.allLocations.size(); i++){

            GRBLinExpr lhs = new GRBLinExpr();
            for(int j = 0; j < this.allLocations.size(); j++){
                for (int k = 0; k < this.vehicleList.size(); k++){
                    lhs.addTerm(1, x[i][j][k]);
                }//k
            }//i

            GRBLinExpr rhs = new GRBLinExpr();
            rhs.addConstant(1);

            model.addConstr(lhs, GRB.EQUAL, rhs, "Constraint 2:");
        }//j

        //Constraint 3
        for (int s = nDepots; s < this.allLocations.size(); s++){
            for (int k = 0; k < this.vehicleList.size(); k++){

                GRBLinExpr lhs = new GRBLinExpr();
                for (int i = 0; i < this.allLocations.size(); i++){
                    lhs.addTerm(1, x[i][s][k]);
                }//i

                GRBLinExpr rhs = new GRBLinExpr();
                rhs.addConstant(1);

                model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 3");
            }//k
        }//s

        //Constraint 4
        for (int s = nDepots; s < this.allLocations.size(); s++){
            for (int k = 0; k < this.vehicleList.size(); k++){

                GRBLinExpr lhs = new GRBLinExpr();
                for (int j = 0; j < this.allLocations.size(); j++){
                    lhs.addTerm(1, x[s][j][k]);             
                }//j

                GRBLinExpr rhs = new GRBLinExpr();
                rhs.addConstant(1);

                model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 4");
            }//k
        }//s

        //Constraint 5
        for (int k = 0; k < this.vehicleList.size(); k++){

            GRBLinExpr lhs = new GRBLinExpr();
            for (int i = 0; i < nDepots; i++){
                for (int j = nDepots; j < this.allLocations.size(); j++){
                    lhs.addTerm(1, x[i][j][k]);
                }//j
            }//i

            GRBLinExpr rhs = new GRBLinExpr();
            rhs.addConstant(1);

            model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 5:");
        }//k

        //Constraint 6
        for (int k = 0; k < this.vehicleList.size(); k++){

            GRBLinExpr lhs = new GRBLinExpr();
            for (int i = nDepots; i < this.allLocations.size(); i++){
                for (int j = 0; j < nDepots; j++){
                    lhs.addTerm(1, x[i][j][k]);
                }//j
            }//i

            GRBLinExpr rhs = new GRBLinExpr();
            rhs.addConstant(1);

            model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 6:");
        }//k        

        //Constraint 7: Capacity constraints of vehicles

        for (int k = 0; k < this.vehicleList.size(); k++){

            GRBLinExpr lhs = new GRBLinExpr();
            for (int i =0; i < this.allLocations.size(); i++){
                for (int j = 0; j < this.allLocations.size(); j++){
                    lhs.addTerm(2, x[i][j][k]);
                }//j
            }//i

            GRBLinExpr rhs = new GRBLinExpr();
            rhs.addConstant(20);

            model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 7: Capacity");
        }//k

        //Constraint 8: #vehicles entering depot cannot exceed depot capacity
        for (int j=0; j < nDepots; j++){

            GRBLinExpr lhs = new GRBLinExpr();
            for (int i = nDepots; i < this.allLocations.size(); i++){   
                for (int k=0; k < this.vehicleList.size(); k++){    
                    lhs.addTerm(1, x[i][j][k]);
                }//for k
            }// for i

            GRBLinExpr rhs = new GRBLinExpr();
            int pj = this.allLocations.get(j).vehicleCapacity;
            rhs.addConstant(pj);    

            model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 8");
        }//i

        //Constraint 9: TimeWindow
        for (int i = nDepots; i < this.allLocations.size(); i++){
            for (int k = 0; k < this.vehicleList.size(); k++){

                GRBLinExpr lhs = new GRBLinExpr();
                lhs.addTerm(1, a[i][k]);

                GRBLinExpr rhs = new GRBLinExpr();
                double stwi = this.allLocations.get(i).startTime;
                rhs.addConstant(stwi);

                model.addConstr(lhs, GRB.GREATER_EQUAL, rhs, "Constraint 9: ");
            }//k
        }//i

        //Constraint 10: TimeWindow
        for (int i = nDepots; i < this.allLocations.size(); i++){
            for (int k = 0; k < this.vehicleList.size(); k++){
                GRBLinExpr lhs = new GRBLinExpr();
                lhs.addTerm(1, a[i][k]);

                GRBLinExpr rhs = new GRBLinExpr();
                double etw = this.allLocations.get(i).endTime;
                rhs.addConstant(etw);

                model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 10:");
            }//for k
        }//i

        //Constraint 11: determine departure vehicle from depot 
        for (int i = 0; i < nDepots; i++){
            for (int k = 0; k < this.vehicleList.size(); k++){

                GRBLinExpr lhs = new GRBLinExpr();
                double eid = this.allLocations.get(i).startTime;
                lhs.addConstant(eid);

                GRBLinExpr rhs = new GRBLinExpr();
                rhs.addTerm(1, dep[i][k]);

                model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 11:" );
            }//k
        }//i

        //Constraint 12: determine returning time to depot
        for (int i = 0; i < nDepots; i++){
            for (int k = 0; k < this.vehicleList.size(); k++){

                GRBLinExpr lhs = new GRBLinExpr();
                lhs.addTerm(1, a[i][k]);

                GRBLinExpr rhs = new GRBLinExpr();
                double lid = this.allLocations.get(i).returningTime;
                rhs.addConstant(lid);

                model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 12: " );
            }//k
        }//i

        //Constraint 13: precedence constraint 1
        for (int i = nDepots; i < this.allLocations.size(); i++){
            for (int j = 0; j < this.allLocations.size(); j++){
                if (i != j){ 
                    for (int k = 0; k < this.vehicleList.size(); k++){

                        GRBLinExpr lhs = new GRBLinExpr();
                        lhs.addTerm(1, a[j][k]);

                        GRBLinExpr rhs = new GRBLinExpr();
                        rhs.addTerm(1, a[i][k]);
                        double si = this.allLocations.get(i).serviceTime;
                        rhs.addConstant(si);

                        double dtij = (this.allLocations.get(i).distance + f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID))/speed;
                        rhs.addConstant(dtij);

                        rhs.addConstant(-M);
                        rhs.addTerm(M, x[i][j][k]);

                        model.addConstr(lhs, GRB.GREATER_EQUAL, rhs, "Constraint 13: ");
                    }//k
                }//if 
            }//j
        }//i

        //Constraint 14: precedence constraint 2 - if previous node was depot
        for (int i = 0; i < nDepots; i++){
            for (int j = nDepots; j < this.allLocations.size(); j++){
                for (int k = 0; k < this.vehicleList.size(); k++){

                    GRBLinExpr lhs = new GRBLinExpr();
                    lhs.addTerm(1, a[j][k]);

                    GRBLinExpr rhs = new GRBLinExpr();
                    rhs.addTerm(1, dep[i][k]);

                    double dtij = (this.allLocations.get(i).distance + f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID))/speed;

                    rhs.addConstant(dtij);

                    rhs.addConstant(-M);
                    rhs.addTerm(M, x[i][j][k]);

                    model.addConstr(lhs, GRB.GREATER_EQUAL, rhs, "Constraint 14: ");
                }//for k
            }//for j
        }//for i

        model.update();

        //4. SET OBJECTIVE ---------------------------------------------------------------------------------------------------------------------------------------

        GRBLinExpr expr = new GRBLinExpr();

        for (int i = 0; i < this.allLocations.size(); i++){
            for (int j = 0; j < this.allLocations.size(); j++){
                if (i != j){
                    for (int k = 0; k < this.vehicleList.size(); k++){

                        double dtij = (this.allLocations.get(i).distance + f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID))/speed;
                        expr.addTerm(dtij, x[i][j][k]);
                    }//k
                }//if
            }//j
        }//i

        model.setObjective(expr, GRB.MINIMIZE);

        model.update();

        model.optimize();
        System.out.println("is the solution feasible? " + model.get(GRB.IntAttr.Status));
        model.write("constraintOutput.lp");

        //5. CONSTRUCT SOLUTION ---------------------------------------------------------------------------------------------------------------------------------------------
        double obj = model.get(GRB.DoubleAttr.ObjVal);

        for (int i = 0; i < this.allLocations.size(); i++){
            for (int j = 0; j < this.allLocations.size(); j++){
                if (i != j){
                    for (int k = 0; k < this.vehicleList.size(); k++){

                        if (x[i][j][k].get(GRB.DoubleAttr.X) > 0){
                            System.out.println(x[i][j][k].get(GRB.StringAttr.VarName) + " " + x[i][j][k].get(GRB.DoubleAttr.X));
                            System.out.println("Node: " + (i+1) + " goes to node: " + (j+1) + " by vehicle: " + (k+1));
                        }//if
                    }//k
                }//if
            }//j
        }//i

        System.out.println("The objective value is: " + obj);


        //6. DISPOSE OF MODEL AND ENVIRONMENT
        model.dispose();
        env.dispose();

    }catch  (GRBException e ){
        e.printStackTrace();
    }//catch
}//solution

} // публичная главная проблема

2 ответа

Решение

Итак, я нашел решение:

//Constraint 1
        for (int j = nDepots; j < this.allLocations.size(); j++){

            GRBLinExpr lhs = new GRBLinExpr();
            for(int i = 0; i < this.allLocations.size(); i++){
                if(i != j) {
                    for (int k = 0; k < this.vehicleList.size(); k++){
                        lhs.addTerm(1, x[i][j][k]);
                    }//k
                }
            }//i

            GRBLinExpr rhs = new GRBLinExpr();
            rhs.addConstant(1);

            model.addConstr(lhs, GRB.EQUAL, rhs, "C1 - j"+j);
        }//j

Я не включил переменные Xijk в мою целевую функцию, где i = j. Поскольку я заранее знаю, что такие переменные являются неверными ответами. Однако я забыл сделать то же самое для ограничений. Это значит, что я должен добавить цикл if с (i!= J), как показано в примере выше. Теперь мой код работает!

Каково значение дуги (депо,j), j заказчика? У меня есть наблюдение: определение var x[i][j][k], когда вы определяете двоичный файл, ставьте (0 и 1), а не (0.0 и 1.0), как это:

x[i][j][k] = model.addVar(0, 1, dij, GRB.BINARY, "X" + i + j + k)
Другие вопросы по тегам