# Using CPLEX Piecewise Linear function

I’m trying to solve a MILP with an piecewise linear function in the cost function. At the moment, i’m using a binairy variable per linear piece wich is not the state of the art (see for example http://www.mit.edu/~jvielma/publications/A-Note-on-a-Superior.pdf)

CPLEX has a dediacted function to create the constraints to ensure the structure of a piecewise linear function. (see https://www.ibm.com/support/knowledgecenter/SSSA5P_12.7.0/ilog.odms.cplex.help/CPLEX/UsrMan/topics/discr_optim/pwl/01_pwl_title_synopsis.html)
This performs way better than my implementation (getting great cuts and reducing number of variables etc). The problem is, I’ve only used this function in python and I wasn’t able to make it work through JuMP.

Is it even possible to make it work with JuMP?

btw i’m aware of the package PiecewiseLinearOpt.jl but it doesn’t do the trick for me as I’m looking at non-continous piecewise linear function.

Also, I transitioned to modeling using julia only recently, so it might as well be something simple I didn’t understand.

Explanations would be greatly appreciated

There is no easy to use syntax in JuMP for adding piecewise linear function in a solver-independent way but we designed the solver interface to be easily extensible precisely for this kind of use cases.

``````struct PiecewiseLinear <: MOI.AbstractScalarFunction
variable::MOI.VariableIndex
breakpoints::Vector{Int}
slopes::Vector{Float64}
x0::Float64
y0::Float64
end
``````

to use it in JuMP as in the CPLEX example, do

``````model = direct_model(CPLEX.Optimizer)
@variable(model, x)
set_objective_sense(model, MOI.MIN_SENSE)
obj = PiecewiseLinear(index(x), [4.0, 5.0, 7.0], [-0.5, 1.0, -1.0, 2.0], 4.0, 2.0)
set_objective_function(model, obj)
``````

Now you need to implement `MOI.set(::CPLEX.Optimizer, ::MOI.ObjectiveFunction{PiecewiseLinear}, ::PiecewiseLinear)` to pass it to CPLEX.

2 Likes

Thanks a lot for your help!

I’ve been trying to implement `MOI.set(::CPLEX.Optimizer, ::MOI.ObjectiveFunction{PiecewiseLinear}, ::PiecewiseLinear)` but I don’t really know how… i’ve read through the entirety of the MOI documentation and i’m still unsure how to “talk to CPLEX”. Also, in my use case, the piecewise linear function is not the only term in my objective. Is their a predefined addition between objective function, or do I have to implement it as a constraint on a dummy variable?
As I said, i’m very new to this.

I don’t really know how… i’ve read through the entirety of the MOI documentation and i’m still unsure how to “talk to CPLEX”

That’s really specific to solver interfaces, you can check https://github.com/JuliaOpt/CPLEX.jl/blob/master/src/ for examples.

Also, in my use case, the piecewise linear function is not the only term in my objective

What are the other terms ? The sum of a affine function and a piecewise linear one can be written as a piecewise linear one, can’t it ? It’s best to mirror the CPLEX interface so if CPLEX allows setting the objective as a sum of a linear function and a piecewise linear one then it makes sense to add a field in `PiecewiseLinear` to add linear terms.

That’s really specific to solver interfaces, you can check https://github.com/JuliaOpt/CPLEX.jl/blob/master/src/ for examples.

The other terms depend on other variables including somme binairy variables and integer variables (such as activation cost in my specific problem). Also for another application, i would like to have `min f(x) + g(y)` where f and g are piecewise linear function depending on different varialbes and that dosen’t share breakpoints. In thoses cases, I don’t see how i could express my objective as one piecewise linear function as you mentionned