JuliaConstraints / CPLEXCP.jl

Julia interface for CPLEX CP Optimizer
MIT License
3 stars 1 forks source link

Setting CPLEX parameters #9

Closed matheusdiogenesandrade closed 1 year ago

matheusdiogenesandrade commented 1 year ago

Hello.

I am trying to set the time limit and the verbose flag for the Cplex CP solver. But I am struggling to make this work. Follows the commands I am trying and the obtained errors:

1st command

MOI.set(model, MOI.RawParameter("CPX_PARAM_TILIM"), 3600)

Obtained error:

ERROR: LoadError: UndefVarError: attr not defined
Stacktrace:
 [1] set(model::CPLEXCP.Optimizer, param::MathOptInterface.RawParameter, x::Int64)
   @ CPLEXCP ~/.julia/packages/CPLEXCP/If8ky/src/MOI/wrapper.jl:487
 [2] top-level scope
   @ .../test.jl:28
 [3] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [4] top-level scope
   @ REPL[2]:1
in expression starting at .../test.jl:28

2nd command

MOI.set(model, MOI.TimeLimitSec, 70)

Obtained error:

ERROR: LoadError: MethodError: no method matching set(::CPLEXCP.Optimizer, ::Type{MathOptInterface.TimeLimitSec}, ::Int64)
Closest candidates are:
  set(::CPLEXCP.Optimizer, ::MathOptInterface.NumberOfThreads, ::Int64) at ~/.julia/packages/CPLEXCP/If8ky/src/MOI/wrapper.jl:452
  set(::CPLEXCP.Optimizer, ::MathOptInterface.TimeLimitSec, ::Union{Nothing, Number}) at ~/.julia/packages/CPLEXCP/If8ky/src/MOI/wrapper.jl:463
  set(::CPLEXCP.Optimizer, ::MathOptInterface.RawParameter, ::Int64) at ~/.julia/packages/CPLEXCP/If8ky/src/MOI/wrapper.jl:486
  ...
Stacktrace:
 [1] top-level scope
   @ .../test.jl:27
 [2] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [3] top-level scope
   @ REPL[2]:1
in expression starting at .../test.jl:27

3rd command

MOI.set(model, MOI.Silent, true)

Obtained error:

ERROR: LoadError: MethodError: no method matching set(::CPLEXCP.Optimizer, ::Type{MathOptInterface.Silent}, ::Bool)
Closest candidates are:
  set(::CPLEXCP.Optimizer, ::MathOptInterface.Silent, ::Bool) at ~/.julia/packages/CPLEXCP/If8ky/src/MOI/wrapper.jl:437
  set(::CPLEXCP.Optimizer, ::MathOptInterface.TimeLimitSec, ::Union{Nothing, Number}) at ~/.julia/packages/CPLEXCP/If8ky/src/MOI/wrapper.jl:463
  set(::MathOptInterface.ModelLike, ::Union{MathOptInterface.AbstractConstraintAttribute, MathOptInterface.AbstractModelAttribute, MathOptInterface.AbstractOptimizerAttribute, MathOptInterface.AbstractVariableAttribute}, ::Any...) at ~/.julia/packages/MathOptInterface/YDdD3/src/attributes.jl:409
  ...
Stacktrace:
 [1] top-level scope
   @ .../test.jl:29
 [2] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [3] top-level scope
   @ REPL[2]:1
in expression starting at .../test.jl:29

The link of the entire code is here. Furthermore, I am also trying to retrieve information about the CPLEXCP solver, such as incurred time, number of branches, number of fails, best bound, and search speed.

Case there is any confusion in my message, please let me know. Thanks and regards.

dourouc05 commented 1 year ago

It's strange that you are still using MOI.RawParameter, it has been deprecated a while ago, in 2021.

For MOI.TimeLimitSec and MOI.Silent, maybe you have to instantiate:

MOI.set(model, MOI.TimeLimitSec(), 70)
MOI.set(model, MOI.Silent(), true)

Otherwise, this project hasn't been updated in two years or so: it's not maintained for the moment.

matheusdiogenesandrade commented 1 year ago

Thank you very much. For the MOI.set(model, MOI.Silent(), true) worked well, but the other MOI.set(model, MOI.TimeLimitSec(), 70), still fails.

matheusdiogenesandrade commented 1 year ago

Interestingly, the MOI.set command work for the objective function, but it doesn't seem to work for other features.

Happy scenarios:

MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
MOI.set(model, MOI.ObjectiveFunction{typeof(objFunc)}(), objFunc)

Sad scenarios:

MOI.set(model, MOI.TIME_LIMIT, 70)
MOI.set(model, MOI.NumberOfThreads(), 1)
MOI.set(model, MOI.TimeLimitSec(), 70)

Regards.

dourouc05 commented 1 year ago

It's expected that MOI.set(model, MOI.TIME_LIMIT, 70) fails, because MOI.TIME_LIMIT is an error code returned by a solver. For the other two, they should work; what are the errors exactly? (I don't have access to CPLEX for now.)

matheusdiogenesandrade commented 1 year ago

It seems that the parameter attr::MOI.TerminationStatus, required by the function _throw_if_optimize_in_progress, is out of scope for the functions

Surprisingly, the function _throw_if_optimize_in_progress is not being called by the function MOI.set(model::Optimizer, ::MOI.Silent, flag::Bool).

I tried to set the time limit parameter directly from the cpo_java_getdoubleparam function, but the following message was obtained:

cpo_java_setdoubleparameter(model.inner, "TimeLimit", Float64(10.0))
ERROR: JavaCall.JavaCallError("Error calling Java: java.lang.NoSuchMethodError: setParameter")
Stacktrace:
 [1] geterror(allow::Bool)
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:418
 [2] jcall(::JavaCall.JavaObject{Symbol("ilog.cp.IloCP")}, ::String, ::Type, ::Tuple{DataType, DataType}, ::JavaCall.JavaObject{Symbol("ilog.cp.IloCP\$DoubleParam")}, ::Vararg{Any})
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:244
 [3] cpo_java_setdoubleparameter(cp::JavaCPOModel, name::String, value::Float64)
   @ CPLEXCP ~/.julia/packages/CPLEXCP/jbgSe/src/api_java.jl:7114
 [4] top-level scope
   @ REPL[7]:1

I also tried to run the commands from the function cpo_java_getdoubleparameter(cp::JavaCPOModel, name::String), and it seems that I do not have access to the jfield scope.

param = jfield(IloDoubleParam, name, IloDoubleParam)
return jcall(cp.cp, "getParameter", jdouble, (IloDoubleParam,), param)
ERROR: UndefVarError: jfield not defined
Stacktrace:
 [1] top-level scope
   @ REPL[9]:1

Btw, I also tried the same steps but using JuMP as a wrapper instead, but the same issue happened, code here. Code using CPLEXCP only is here.

I will take the time to make the function cpo_java_getdoubleparameter(cp::JavaCPOModel, name::String) to work.

Thanks and regards.

matheusdiogenesandrade commented 1 year ago

Hello again.

After some time reading the code back and forth. I could set the desired parameters by calling inner functions of the project. For more details, cf. here.

Basically, I replace the commands

MOI.set(model, MOI.NumberOfThreads(), 1)
MOI.set(model, MOI.TimeLimitSec(), Float64(10.0))

by

param = CPLEXCP.jfield(CPLEXCP.IloIntParam, "Workers", CPLEXCP.IloIntParam)
CPLEXCP.jcall(model.inner.cp, "setParameter", Nothing, (CPLEXCP.IloIntParam, CPLEXCP.jint), param, 1)

param = CPLEXCP.jfield(CPLEXCP.IloDoubleParam, "TimeLimit", CPLEXCP.IloDoubleParam)
CPLEXCP.jcall(model.inner.cp, "setParameter", Nothing, (CPLEXCP.IloDoubleParam, CPLEXCP.jdouble), param, Float64(10.0))

and everything works find. I got this insight from the official docs.

Below we can see the output after setting the above parameters.

 ! --------------------------------------------------- CP Optimizer 20.1.0.0 --
 ! Maximization problem - 3 variables, 0 constraints
 ! TimeLimit            = 10
 ! Workers              = 1
 ...
 ! ----------------------------------------------------------------------------

I tried to implement the fix locally, but I am afraid of breaking other parts of the code. So I will list the follow-up I made that I think may be enough to solve this bug:

function cpo_java_setdoubleparameter(
    cp::JavaCPOModel,
    name::String,
    value::Real,
)
    param = jfield(IloDoubleParam, name, IloDoubleParam)
    return jcall(
        cp.cp,
        "setParameter",
        Nothing,
        (IloDoubleParam, jdouble),
        param,
        value,
    )
end

Thanks for the support, let me know what can I do for helping, and if there is any misunderstanding from my side.

Regards.

ps.: I will wait to see the next comments of this issue, to, then, decide if I will close it or not.

dourouc05 commented 1 year ago

Thanks for debugging this! I believe that it wasn't that easy. I've committed your first proposed change: https://github.com/JuliaConstraints/CPLEXCP.jl/commit/677619575c302a7459521345ac89a38444c2ae15. Could you test this version locally? That would be your code, plus running the test suite. It amounts to doing the following (install the latest Git commit on the main branch, run the tests):

]dev CPLEXCP
]test CPLEXCP
# Test your own code.
matheusdiogenesandrade commented 1 year ago

Thanks for debugging this! I believe that it wasn't that easy. I've committed your first proposed change: 6776195. Could you test this version locally? That would be your code, plus running the test suite. It amounts to doing the following (install the latest Git commit on the main branch, run the tests):

]dev CPLEXCP
]test CPLEXCP
# Test your own code.

The submited PR is here. I thought in creating a CONTRIBUTING.md, I could create such file with general guidelines, but it would be necessary someone who developed the project to write the technical specificities.

Let me know of any work on my side.

Thanks and regards.

dourouc05 commented 1 year ago

Thanks for your PR!

Regarding a CONTRIBUTING file, I'm not too keen: JuMP already has one, while this project is part of that ecosystem/nebula; apart from that, I'm just hoping that people will use GitHub as it was intended to be used.

matheusdiogenesandrade commented 1 year ago

Thanks for the support!