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

Support Function Calls #119

Closed
lukasscheffold opened this issue Oct 25, 2024 · 7 comments
Closed

Support Function Calls #119

lukasscheffold opened this issue Oct 25, 2024 · 7 comments

Comments

@lukasscheffold
Copy link

It would be useful to be able to implement function calls into constraints. Pyomo has a similar functionality under the external() module. Here you can supply a function call, such as a function or an external library (DLL) call, to calculate a value. This value, along with its derivatives, can then be applied to a constraint or logicalConstraint. I am thinking of a functionality like the following:

using DisjunctiveProgramming
using HiGHS

m = GDPModel(HiGHS.Optimizer)

@variable(m, 0 <= a)

function quadratic(x)
return y = (x + 2)^2 + 1
end

@constraint(m, 0 == quadratic(a))

@lukasscheffold
Copy link
Author

I have found, that a functionality for this exists for NLP using @NLconstraint(). It would be interesting to see this extended to GDP:
using Ipopt

m = Model(Ipopt.Optimizer)
#m = Model()

@variable(m, x, start=1.0)
@variable(m, y, start=1.0)

@variable(m, shiftx)
fix(shiftx, 1.0)
@variable(m, shifty)
fix(shifty, 2.0)

function call_cpp_function(x, shiftx, shifty)
return ccall((:quadratic, "DLL/quadratic.dll"), Float64, (Float64,Float64,Float64,), x, shiftx, shifty)
end

function derivative(grad, x, shiftx, shifty)
return ccall((:quadratic_derivative, "DLL/quadratic.dll"), Float64, (Float64,Float64,Float64,), x, shiftx, shifty)
end

register(m, :call_cpp_function, 3, call_cpp_function, derivative, autodiff=false)
@NLconstraint(m, y==call_cpp_function(x, shiftx, shifty))

@objective(m, Min, y)
optimize!(m)

print("Value of y: ",value(y))
print("Value of x: ",value(x))

@lukasscheffold lukasscheffold changed the title Support Function Calls Support Function Calls #enhancement Nov 21, 2024
@lukasscheffold lukasscheffold changed the title Support Function Calls #enhancement Support Function Calls Nov 21, 2024
@pulsipher
Copy link
Collaborator

Hi @lukasscheffold,

Since DisjunctiveProgramming is a JuMP extension, it inherits all the same features that JuMP has. A GDPModel is just a JuMP.Model.

I am thinking of a functionality like the following:

using DisjunctiveProgramming
using HiGHS

m = GDPModel(HiGHS.Optimizer)

@variable(m, 0 <= a)

function quadratic(x)
return y = (x + 2)^2 + 1
end

@constraint(m, 0 == quadratic(a))

This already works with DisjunctiveProgramming. It is a paradigm called function tracing, see https://jump.dev/JuMP.jl/stable/manual/nonlinear/#Function-tracing.

I have found, that a functionality for this exists for NLP using @NLconstraint(). It would be interesting to see this extended to GDP:

Registering functions is the way to add external functions to JuMP models. Note however that register and @NLconstraint correspond to the legacy nonlinear interface for JuMP. You should use @operator and @constraint instead, see https://jump.dev/JuMP.jl/stable/manual/nonlinear/#jump_user_defined_operators.

DisjunctiveProgramming will allow you to use user defined operators to build your model. However, once the model is reformulated, you'll end up with a MINLP that has user defined operators which most if not all MINLP solvers will not support. Although, maybe Juniper will... This limitation is not unique to JuMP models and is also true if you try to use an external function with Pyomo.gdp.

@lukasscheffold
Copy link
Author

Thank you for your response. I have tried the @operator implementation, first with IPOPT and a regular JuMP model (which works!). Afterwards I proceded with the GDPModel, using AMPLs bonmin (works with Pyomo.gdp and external function calls) and HiGHS. The HiGHS solver throws the error, that it is not capable of evaluating user defined nonlinear functions. The AMPL bonmin solver however throws the following error:
ERROR: MathOptInterface.UnsupportedNonlinearOperator: The nonlinear operator :op_call_cpp_function is not supported by the model.
Since I am not sure what I am doing wrong at the moment, I have attached the testing file (GDP_ExtFcnPathfinder.jl) as well as the .dll (quadratic.dll) that I am using. The dll represents a quadratic function. The script has both cases (NLP and GDP).
Git_Sup.zip
If I see this correctly, it it not a solver issue with bonmin or am I mistaking?

@pulsipher
Copy link
Collaborator

Hi @lukasscheffold, this is likely a limitation of how AmplNLWriter.jl (the Julia package) interfaces with Bonmin. Any thoughts, @odow?

In any case, the ability to have mixed-integer solvers like Bonmin support use user-defined operators is not determined by DisjunctiveProgramming.jl, but rather the JuMP (or more specifically the MathOptInterface) ecosystem and the solver itself. All DisjunctiveProgramming does is use GDP modelling objects to automate the creation of a MILP or MINLP JuMP model. How the resulting MILP/MINLP model is solved is solely determined by JuMP.

@odow
Copy link
Contributor

odow commented Nov 26, 2024

AmplNLWriter does not support user-defined functions.

@pulsipher
Copy link
Collaborator

@lukasscheffold, since this issue is not directly related to DisjunctiveProgramming, I am going to close it. To request support of user-defined operators for Bonmin, you can raise an issue with https://github.com/jump-dev/AmplNLWriter.jl.

@odow
Copy link
Contributor

odow commented Nov 27, 2024

To request support of user-defined operators for Bonmin, you can raise an issue

I have no plans to support this feature in AmplNLWriter.

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

No branches or pull requests

3 participants