Need help with prod() or any custom function with JuMP

All I want is to be able to run an optimization which can use prod() or any custom function i can make.

I tried everything normal and NL objectives, constraints vs…

Ipopt optimizer does what i want but it does with float numbers, I need integer results.

using JuMP
using Printf
using SCIP


#optimizer = Juniper.Optimizer
#params = Dict{Symbol,Any}()
#params[:nl_solver] = with_optimizer(Ipopt.Optimizer,max_cpu_time=5.0,print_level=0)

#m = Model(with_optimizer(optimizer, params))
#m =  Model(with_optimizer(Ipopt.Optimizer, max_cpu_time=160.0))
m =  Model(with_optimizer(SCIP.Optimizer))
#m = Model(with_optimizer(AmplNLSolver, "Couenne"))

@variable(m, 0 <=groups[1:41]<=250, integer=true)

@constraint(m,[i in 1:41],sum(groups[i] for i in 1:41)==250)



@objective(m, Max,prod(groups[i] for i in 1:41))

optimize!(m)



for i in 1:41

        @printf("%d info in %f\n ", i,value(groups[i]))

end

@printf("Object cost= %f\n", objective_value(m))

You cannot use generator expression inside prod inside @objective and @constraint macro:

julia> using JuMP

julia> @objective(model, Max, prod(i for i in 1:2))
ERROR: LoadError: Expected sum outside generator expression; got prod
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] _parse_generator(::Expr, ::Symbol, ::Array{Any,1}, ::Array{Any,1}, ::Symbol) at /home/blegat/.julia/packages/JuMP/iGamg/src/parse_expr.jl:387
 [3] _parse_expr(::Expr, ::Symbol, ::Array{Any,1}, ::Array{Any,1}, ::Symbol) at /home/blegat/.julia/packages/JuMP/iGamg/src/parse_expr.jl:524
 [4] _parse_expr at /home/blegat/.julia/packages/JuMP/iGamg/src/parse_expr.jl:429 [inlined]
 [5] _parse_expr_toplevel(::Expr, ::Symbol) at /home/blegat/.julia/packages/JuMP/iGamg/src/parse_expr.jl:401
 [6] @objective(::LineNumberNode, ::Module, ::Any, ::Vararg{Any,N} where N) at /home/blegat/.julia/packages/JuMP/iGamg/src/macros.jl:975
in expression starting at REPL[2]:100:

However, you can use it outside the macro

obj = prod(groups[i] for i in eachindex(groups))
@objective(m, Max, obj)

and you can also simply avoid using the generator expression:

julia> @objective(model, Max, prod(groups))
ERROR: Cannot multiply a quadratic expression by a variable

however, as shown in the error message, it won’t work unless length(groups) <= 2 as we only support affine and quadratic exception outside of the @NLobjective and @NLconstraint macros.
Your problem is nonlinear and you can solve it with an NLP solver if you use @NLobjective.

You could also use a convex solver by doing

@variable(m, t)
@constraint(m, [t; groups] in MOI.GeometricMeanCone(length(groups) + 1))
@objective(m, Max, t)

as GeometricMeanCone is such that t <= prod(groups)^(1/n).
Note that the elements of groups are additionally constrained to be nonnegative which, depending on your actual need may or may be reasonable.

1 Like

Thank you so much for your wide explanation.

As i mention Ipopt Optimizer actually solves it but gives float results in “groups” array.

I guess i need a “MINLP = Mixed-integer nonlinear programming” solver. But i could not find a working one with Jump.

I will try convex solver.
Thanks again for explanation.
@blegat

You can try MISOCP solvers listed in https://www.juliaopt.org/JuMP.jl/dev/installation/.
The GeometricMeanCone will be bridged by the GeoMeanBridge into RotatedSecondOrderCone. Then, if the solver does not support RotatedSecondOrderCone, it will be bridged into SecondOrderCone by the RSOCBridge.
So you need to search for a solver supporting both integer variables and Second Order Cone (SOC) constraints, hence MISOCP solvers.

Did you encounter any error with using SCIP?
Both integer variables and SOC constraints are supported. So, with bridges, it should work for your problem.

Scip gives this

> ...
> ERROR: LoadError: LoadError: Expected sum outside generator expression; got prod
> 
> Stacktrace:
> 
> [1] error(::String) at .\error.jl:33
> 
> [2] _parse_generator(::Expr, ::Symbol, ::Array{Any,1}, ::Array{Any,1}, ::Symbol) at C:\Users\Xentios\.julia\packages\JuMP\MsUSY\src\parse_expr.jl:387
> 
> [3] _parse_expr(::Expr, ::Symbol, ::Array{Any,1}, ::Array{Any,1}, ::Symbol) at C:\Users\Xentios\.julia\packages\JuMP\MsUSY\src\parse_expr.jl:524
> 
> [4] _parse_expr at C:\Users\Xentios\.julia\packages\JuMP\MsUSY\src\parse_expr.jl:429 [inlined]
> 
> [5] _parse_expr_toplevel(::Expr, ::Symbol) at C:\Users\Xentios\.julia\packages\JuMP\MsUSY\src\parse_expr.jl:401
> 
> [6] @objective(::LineNumberNode, ::Module, ::Any, ::Vararg{Any,N} where N) at C:\Users\Xentios\.julia\packages\JuMP\MsUSY\src\macros.jl:975
> 
> [7] include at .\boot.jl:328 [inlined]
> 
> [8] include_relative(::Module, ::String) at .\loading.jl:1094
> 
> [9] include(::Module, ::String) at .\Base.jl:31
> 
> [10] exec_options(::Base.JLOptions) at .\client.jl:295
> 
> [11] _start() at .\client.jl:464
> 
> in expression starting at c:\Users\Xentios\Desktop\work\Old\Julia\cop.jl:21
> 
> in expression starting at c:\Users\Xentios\Desktop\work\Old\Julia\cop.jl:21
> ...

Btw i did something linear so for now my problem is solved. Thank you all for your interest and help.

I think @leethargo meant using SCIP with the GeometricMeanCone formulation.

Yes, that error message comes from JuMP, so I don’t think that switching from SCIP to IPOPT should make any difference there.