Reformulating Logarithmic Objective Function for Gurobi in Julia with JuMP

Hi,

I’m working on an optimization problem in Julia where I need to maximize a logarithmic objective function (maximize sum of logs ):

@objective(model, Max, sum(alp[i] * log( p[i]) for i in 1:n))

where alp is vector of ones and p is a variable.
However, I’ve found that Gurobi doesn’t support logarithmic functions directly, and my attempts to access the C API using grb = backend(model) resulted in a “backend couldn’t be found” error.

Could anyone suggest how I might reformulate this objective in a way compatible with Gurobi, or provide guidance on using the Gurobi C API in Julia to handle this type of problem? Any advice on alternative approaches would also be much appreciated.

Thank you!

Hi @Beyza_Aydin, welcome to the forum :smile:

Here you go:

julia> using JuMP

julia> import Gurobi

julia> n = 3
3

julia> model = direct_model(Gurobi.Optimizer())
A JuMP Model
├ mode: DIRECT
├ solver: Gurobi
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 0
├ num_constraints: 0
└ Names registered in the model: none

julia> @variable(model, p[i in 1:n] == i)
3-element Vector{VariableRef}:
 p[1]
 p[2]
 p[3]

julia> @variable(model, log_p[1:n])
3-element Vector{VariableRef}:
 log_p[1]
 log_p[2]
 log_p[3]

julia> grb = backend(model)
    sense  : minimize
    number of variables             = 0
    number of linear constraints    = 0
    number of quadratic constraints = 0
    number of sos constraints       = 0
    number of non-zero coeffs       = 0
    number of non-zero qp objective terms  = 0
    number of non-zero qp constraint terms = 0


julia> column(x::VariableRef) = Gurobi.c_column(grb, index(x))
column (generic function with 1 method)

julia> for i in 1:n
           Gurobi.GRBaddgenconstrLog(grb, "log(p[$i])", column(p[i]), column(log_p[i]), "")
       end

julia> optimize!(model)
Gurobi Optimizer version 11.0.3 build v11.0.3rc0 (mac64[x86] - Darwin 23.5.0 23F79)

CPU model: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
Thread count: 4 physical cores, 8 logical processors, using up to 8 threads

Optimize a model with 0 rows, 6 columns and 0 nonzeros
Model fingerprint: 0xe8e701e1
Model has 3 general constraints
Variable types: 6 continuous, 0 integer (0 binary)
Coefficient statistics:
  Matrix range     [0e+00, 0e+00]
  Objective range  [0e+00, 0e+00]
  Bounds range     [1e+00, 3e+00]
  RHS range        [0e+00, 0e+00]
Presolve removed 0 rows and 6 columns
Presolve time: 0.00s
Presolve: All rows and columns removed

Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)
Thread count was 1 (of 8 available processors)

Solution count 1: 0 

Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%

User-callback calls 90, time in user-callback 0.00 sec

julia> value.(p)
3-element Vector{Float64}:
 1.0
 2.0
 3.0

julia> value.(log_p)
3-element Vector{Float64}:
 0.0
 0.6931471805599453
 1.0986122886681098

julia> log.(value.(p))
3-element Vector{Float64}:
 0.0
 0.6931471805599453
 1.0986122886681098
1 Like

Thank you very much! My code is finally working :slight_smile:
I guess the important part is to import Gurobi, and not using using Gurobi
I also added this objective function:

@objective(model, Max, sum(alp.*log_p))
1 Like

I guess the important part is to import Gurobi , and not using using Gurobi

This should have nothing to do with it. If you use import Gurobi, then you need to prefix all calls to Gurobi with Gurobi.. If you use using Gurobi, then all of the GRBxxx symbols are brought into scope and you can use GRBaddgenconstrLog without Gurobi..