jump-dev / PiecewiseLinearOpt.jl

Solve optimization problems containing piecewise linear functions
Other
53 stars 21 forks source link

Breakpoints in PiecewiseLinearOpt #41

Closed AmaraBruno closed 3 years ago

AmaraBruno commented 3 years ago

Hello there, thanks for reading this message. I have a question about the PiecewiseLinearOpt.jl package. I thought when defining the breakpoints for the piecewise approximation, my non-linear function (nl_func) would be evaluated only in the prespecified points for the later linear interpolation. Coding some examples, a realized that it's not much like that. In the code below (Example code), i defined the following breakpoints for the x and y dimensions: -x breakpoints: 0.0, 3.0, 6.0 -y breakpoints: 0.0, 4.0, 8.0 Inside my NL function, i'm printing the inputs received so that i'm able to see whats going on in the backend. On the log messages produced by the model, its possible to see the the NL function is evaluated in points outside the breakpoints defined, like (x, y) = (1.5, 6.0) for example. Is this supposed to happen? Can someone explain that?

Example code:

Packages

using JuMP, Cbc, PiecewiseLinearOpt;

Creating optimization problem

Set optimizer

model=Model(Cbc.Optimizer)

Adding variables to the model

@variable(model, x>=0.0) @variable(model, y>=0.0)

Defining breakpoints for piecewise linear approximations

x_brkpts=[0.0, 3.0, 6.0]; y_brkpts=[0.0, 4.0, 8.0]; pos_x_axis=5.0; pos_y_axis=5.0;

Non-linear constraint

r(x, y; x_pos, y_pos) = (x-x_pos)^2+(y-y_pos)^2

Piecewise approx. for r

r_approx=piecewiselinear(model, x, y, x_brkpts, y_brkpts, (x, y) -> r(x, y, x_pos=pos_x_axis, y_pos=pos_y_axis))

Adding constraints to the model

@constraint(model, 2.0*x+y>=18.0) @constraint(model, r_approx <= 15.0) # NL constraint

Defining objective function

function nl_func(x, y) println("Inputs: X=$x / Y=$y") return y - x^2 end

Piecewiselinear approx. for objective function

nl_func_approx=piecewiselinear(model, x, y, x_brkpts, y_brkpts, (u, v) -> nl_func(u, v))

Adding objective function

@objective(model, Max, nl_func_approx)

Show model

println(model)

Optimizing

optimize!(model)

Results

println("Optimal value: $(objective_value(model))") println("Opt. X: $(value(x))") println("Opt. Y: $(value(y))")

joehuchette commented 3 years ago

Yes, it's supposed to happen. By default, we will evaluate the user-provided function at the center of each cell in order to select the orientation of the triangulation in that cell (https://github.com/joehuchette/PiecewiseLinearOpt.jl/blob/3ee7d49aa92ce86b095b8147b22fad9b95e0e22c/src/types.jl#L71-L79). If this is a problem for you, you can explicitly pass in a different triangulation pattern, e.g.

BivariatePWLFunction(x_brkpts, y_brkpts, nl_func; pattern=:UnionJack)