I'm quite new to CPLEX+Java. I try to implement a variant of an Orienteering Problem and a Pickup and Delivery problem. I would like to use a LazyConstraintCallback to ensure Subtour Elimination in Integer Solutions.
Due to the orienteering component, I need an additional variable (z[q]) in for the Callback, which is so far not included in the model.
protected void main() throws IloException {
// first: test if more than one route exists
int[][] cycles = getCycles(getLongRoute());
int count = countCycles(cycles);
IloNumVar[] z = model.boolVarArray(count);
if (count > 1) {
// add connectivity constraints
int b = 1;
for (int q = 0;q<cycles.length; q++) {
IloLinearNumExpr expr1 = model.linearNumExpr();
int[] cycle = cycles[q];
int m = 0;
for (int p = 0; p<cycle.length; p++) {
int i = ArrayHandler.getIndex(allLocations_k, cycle[p]);
for (int l = 0; l<cycle.length; l++) {
int j = ArrayHandler.getIndex(allLocations_k, cycle[l]);
if (i!=j) {
expr1.addTerm(1.0, x[i][j]);
}
}
if (ArrayHandler.contains(deliveryLocation_k, allLocations_k[i])) {
expr1.addTerm(ak[i], 1.0);
} else {
m++;
expr1.addTerm(ak[i], -1.0);
}
}
for (int p = 0; p<loc_k; p++) {
int i = allLocations_k[p];
if (!ArrayHandler.contains(cycle, i)) {
IloLinearNumExpr expr2 = model.linearNumExpr();
if (ArrayHandler.contains(deliveryLocation_k, i)) {
expr2.addTerm(ak[p], 1.0);
expr2.addTerm(z[q],-1.0);
this.add(model.le(expr2,0.0));
//this.addLe(expr2, z[q]);
} else {
expr2.addTerm(ak[p], 1.0);
expr2.addTerm(z[q], 1.0);
this.add(model.ge(expr2,1.0));
//model.addLe(1.0,expr2);
}
}
}
expr1.setConstant(m);
expr1.addTerm(z[q], -1.0);
this.add(model.le(0.0, expr1));
}
}
}
It throws an "Unknown Object" Error after reading "this.add(model.ge(expr2,z[q]));", which is the first constraint it should add. I guess that this behavior is somehow connected to the unknown variable z[q]. Do I have to add this at another location? I don't know the final dimension of z[q], as I need a z[q] for every subtour found during the execution, this can grow exponentially large (that's why I hoped to be able to create it on the fly). Maybe the error message helps:
ilog.cplex.IloCplex$UnknownObjectException: CPLEX Error: object is unknown to IloCplex
at ilog.cplex.CpxNumVar.getVarIndexValue(CpxNumVar.java:295)
at ilog.cplex.CpxLinearExpr.removeDuplicatesSafe(CpxLinearExpr.java:476)
at ilog.cplex.CpxCutCallback.addCut(CpxCutCallback.java:75)
at ilog.cplex.IloCplex$LazyConstraintCallback.add(IloCplex.java:14920)
at PDOP$IntegerCutCallback.main(PDOP.java:334)
at ilog.cplex.CpxCallback.callmain(CpxCallback.java:160)
at ilog.cplex.CpxLazyConstraintCallbackFunction.callIt(CpxLazyConstraintCallbackFunction.java:45)
at ilog.cplex.Cplex.CPXmipopt(Native Method)
at ilog.cplex.CplexI$SolveHandle.start(CplexI.java:2786)
at ilog.cplex.CplexI.solve(CplexI.java:2912)
at ilog.cplex.IloCplex.solve(IloCplex.java:10434)
at PDOP.solveIBR(PDOP.java:193)
at Application.main(Application.java:33)
I hope that this is no "too" stupid question, I've tried to find something on this behavior online, but did not find any examples in which an added variable was required.