Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the default behavior of lazy constraints #340

Closed
tasseff opened this issue Nov 11, 2020 · 5 comments
Closed

Change the default behavior of lazy constraints #340

tasseff opened this issue Nov 11, 2020 · 5 comments

Comments

@tasseff
Copy link

tasseff commented Nov 11, 2020

Currently, every time a constraint is added within a lazy cut callback, the MIP solution at the corresponding integer feasible node is removed from the solution space. There are circumstances where a feasible integer solution may be used to construct a cut that does not necessarily cut off that solution. I've found that the latter (expected) behavior is present in Gurobi.jl but not CPLEX.jl.

I expect this is being caused by the use of CPXcallbackrejectcandidate here, which automatically classifies the integer solution as infeasible within CPLEX. I'm not familiar enough with the C interface of CPLEX to suggest an alternative, but I'm hoping this can be addressed. Below is a small example that will result in infeasibility even though the lazy constraint that is being added should be inconsequential.

import CPLEX
import JuMP
import MathOptInterface
const MOI = MathOptInterface

model = JuMP.Model(CPLEX.Optimizer)
x = JuMP.@variable(model, lower_bound = 0.0)
z = JuMP.@variable(model, binary = true)
objective = JuMP.@objective(model, Min, x)

MOI.set(model, MOI.NumberOfThreads(), 1)

function lazy_cut_callback(cb_data)
    con = JuMP.@build_constraint(x >= 0.0) # This should do nothing.
    MOI.submit(model, MOI.LazyConstraint(cb_data), con)
end

MOI.set(model, MOI.LazyConstraintCallback(), lazy_cut_callback)
JuMP.optimize!(model)
JuMP.termination_status(model) # INFEASIBLE
@odow
Copy link
Member

odow commented Nov 11, 2020

Take note of the large warning in the JuMP documentation: https://jump.dev/JuMP.jl/stable/callbacks/#Available-solvers-1
JuMP's solver-independent callbacks are a useful abstraction of syntax. They do not guarantee equivalent behavior between solvers.

You should only submit a lazy constraint if the current solution is infeasible. Thus, your callback should be

function lazy_cut_callback(cb_data)
    if callback_value(x) < 0.0
        con = JuMP.@build_constraint(x >= 0.0)
        MOI.submit(model, MOI.LazyConstraint(cb_data), con)
    end
end

Closing since this is expected behavior.

@odow odow closed this as completed Nov 11, 2020
@4YHa
Copy link

4YHa commented Jul 18, 2024

Hi, I'm using LazyConstraintCallback in cplex via java with the following code and I'm getting a fatal error at runtime. Could you let me know what's causing this and how to fix it?
public class LazyConstraintsExample {
public static void main(String[] args) {
try {
IloCplex cplex = new IloCplex();

        // Variables
        IloIntVar x1 = cplex.boolVar("x1");
        IloIntVar x2 = cplex.boolVar("x2");
        IloIntVar x3 = cplex.boolVar("x3");

        // Objective: maximize x1 + 2x2 + 3x3
        cplex.addMaximize(cplex.sum(cplex.sum(x1, cplex.prod(2, x2)), cplex.prod(3, x3)));

        // Constraint: 2x1 + x2 + x3 <= 4
        cplex.addLe(cplex.sum(cplex.sum(cplex.prod(2, x1), x2), x3), 4);
        //cplex.addLe(cplex.sum(x1,x2), 1);

        // Add lazy constraint callback
        cplex.use(new MyLazyCallback(x1,x2,cplex));
        
        // Solve the model
        if (cplex.solve()) {
            System.out.println("Solution status: " + cplex.getStatus());
            System.out.println("Objective value: " + cplex.getObjValue());
            System.out.println("x1 = " + cplex.getValue(x1));
            System.out.println("x2 = " + cplex.getValue(x2));
            System.out.println("x3 = " + cplex.getValue(x3));
        } else {
            System.out.println("No solution found");
        }

        cplex.end();
    } catch (IloException e) {
        e.printStackTrace();
    }
}

}
public class MyLazyCallback extends IloCplex.LazyConstraintCallback {
IloNumVar x1;
IloNumVar x2;
IloCplex cplex;

MyLazyCallback(IloNumVar x1,IloNumVar x2,IloCplex cplex){
    this.x1 = x1;
    this.x2 = x2;
    this.cplex = cplex;
}
@Override
protected void main() throws IloException {
    double x1Val = getValue(x1);
    double x2Val = getValue(x2);
    System.out.println("x1:" + x1Val);
    System.out.println("x2:" + x2Val);
    // 检查是否违反了某个 Lazy 约束
    if ( x1Val + x2Val > 1) {
        // 创建并添加新的约束
        IloLinearNumExpr expr = cplex.linearNumExpr();
        expr.addTerm(1.0, x1);
        expr.addTerm(1.0, x2);
        //IloRange rng = cplex.range(Double.MIN_VALUE,expr,1);
        IloRange rng = cplex.addLe(expr,1);
        cplex.addLazyConstraint(rng);
        System.out.println("Lazy constraint added: x + y <= 1");
    }
}

}
The error that occurs is shown in the figure
callback结果

@dourouc05
Copy link
Collaborator

Hi @4YHa! Unfortunately, you are asking your question at the wrong place: this repo only contains the Julia wrapper for CPLEX, there is nothing about Java here. It is not affiliated with IBM. You can try on the official forum (https://community.ibm.com/community/user/ai-datascience/communities/community-home) or on Stack Exchange (https://or.stackexchange.com/).

@4YHa
Copy link

4YHa commented Jul 19, 2024

@dourouc05 Thank you very much for your answer.

@Zhigao111
Copy link

@dourouc05 Thank you very much for your answer.

Did you solve this problem?I got a same bug.Could you share some about this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants