Decision Optimization

 View Only

 multi-objective optimisation

Ross Dye's profile image
Ross Dye posted Mon June 02, 2025 12:52 AM

Can anyone provide some strategies for multi-objective optimisation in docplex cp?

Thanks

Ross

ALEX FLEISCHER's profile image
ALEX FLEISCHER

Hi

let me share https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoocpomultiobjective.py

from docplex.cp.model import CpoModel
from docplex.cp.model import CpoParameters

mdl = CpoModel(name='buses')

param=CpoParameters()
param.OptimalityTolerance=0.01
mdl.set_parameters(param)

nbbus50 = mdl.integer_var(0,10,name='nbBus50')
nbbus40 = mdl.integer_var(0,10,name='nbBus40')
nbbus30 = mdl.integer_var(0,10,name='nbBus30')
cost = mdl.integer_var(0,10000,name='cost')
co2emission = mdl.integer_var(0,10000,name='co2emission')

mdl.add(nbbus50*50+nbbus40*40 + nbbus30*30 >= 200)
mdl.add(co2emission==nbbus50*10+nbbus40*11+nbbus30*12)
mdl.add(cost==nbbus40*500 + nbbus30*400+nbbus50*625)
mdl.add(mdl.minimize_static_lex([cost,co2emission]))
msol=mdl.solve()

print(msol[nbbus50]," buses 50 seats") 
print(msol[nbbus40]," buses 40 seats")
print(msol[nbbus30]," buses 30 seats") 
print("cost = ",msol[cost])
print("co2 emission = ",msol[co2emission]/10) 
Ross Dye's profile image
Ross Dye

Thanks for your response 
I think I understand the code
Some notes:
 - this does not seem to be a scheduling problem.? is this correct?

As I mentioned, minimise_static_lex() returns the first feasible solution in my scheduling problem. It certainly is not the optimal

Regards

Ross

ALEX FLEISCHER's profile image
ALEX FLEISCHER

If you want to do this multi objective step by step you can use https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoocpomultiobjectivestepbystep.py

It works with scheduling and you can use search phases if you need

import numpy as np
np.bool = np.bool_

from docplex.cp.model import CpoModel
from docplex.cp.model import CpoParameters

mdl = CpoModel(name='buses')

param=CpoParameters()
param.OptimalityTolerance=0.01
param.set_LogVerbosity("Quiet")
mdl.set_parameters(param)

nbbus50 = mdl.integer_var(0,10,name='nbBus50')
nbbus40 = mdl.integer_var(0,10,name='nbBus40')
nbbus30 = mdl.integer_var(0,10,name='nbBus30')
cost = mdl.integer_var(0,10000,name='cost')
co2emission = mdl.integer_var(0,10000,name='co2emission')
obj=mdl.integer_var(0,10000,name='obj')

coef1 = mdl.integer_var(0,1,name='coef1')
coef2 = mdl.integer_var(0,1,name='coef2')

mdl.add(nbbus50*50+nbbus40*40 + nbbus30*30 >= 200)
mdl.add(co2emission==nbbus50*10+nbbus40*11+nbbus30*12)
mdl.add(cost==nbbus40*500 + nbbus30*400+nbbus50*625)
mdl.add(obj==coef1*cost+coef2*co2emission)
#mdl.add(mdl.minimize_static_lex([cost,co2emission]))
coef1.domain = (1,1)
coef2.domain = (0,0)
mdl.minimize(obj)
msol=mdl.solve()

print("first solve")
print(msol[nbbus50]," buses 50 seats") 
print(msol[nbbus40]," buses 40 seats")
print(msol[nbbus30]," buses 30 seats") 
print("cost = ",msol[cost])
print("co2 emission = ",msol[co2emission]/10) 

costvalue=msol[cost]

mdl.add(cost==costvalue)
coef1.domain = (0,0)
coef2.domain = (1,1)

print()
print("second solve")
msol=mdl.solve()

print(msol[nbbus50]," buses 50 seats") 
print(msol[nbbus40]," buses 40 seats")
print(msol[nbbus30]," buses 30 seats") 
print("cost = ",msol[cost])
print("co2 emission = ",msol[co2emission]/10) 
Ross Dye's profile image
Ross Dye

Thanks Alex
I will investigate this further ... tomorrow!

Ross Dye's profile image
Ross Dye

Hi Alex
I tested your strategy and advise:

After the first solve, the makespan = 706.

However if I replace the objective as minimize(makespan, i get makespan = 684
This makes no sense to me, as with the coefficients 0f (1,1) and (0,0), I should get the same???

If not, why not. I don't understand


Secondly, on the second solve, I get an immediate solver 'fail' with message "No solution, result = Unknown"
This happens even without the changes to coefficients and setting constraint on makespan

I am using CP Optimizer 22.1.1.0 with Python

Is it valid to "resolve"

Thanks

Ross

ALEX FLEISCHER's profile image
ALEX FLEISCHER

In my tiny example, 

mdl.add(cost==costvalue)

is crucial. This is what is freezing objective 1 before moving to minimizing objective 2

Ross Dye's profile image
Ross Dye

Thanks Alex
I think there is a fundamental problem with docplex & multi-objective optimisation. Hopefully someone can help me understand what is going on, and how to fix it.

When solving my model using MODEL.minimize(mdl.makespan), I get a very good solution with makespan = 684, and solve time around 36 seconds, albeit with some simplistic search phases.
However, if I use MODEL.minimize(mdl.makespan + 1) I get a makespan of 706 after search of 144 seconds. I thought it should be 685. 

Appreciate some help to understand this

Ross

Ross Dye's profile image
Ross Dye

Still searching strategies for multi-objective optimization with docplex cp
With minimize makespan(), my solver runs for around 30 seconds and produces a reasonable solution.

If I use minimize_static_lex(makespan,num_tanks_used) the solver stops in less than 1 second with makespan = 5 times worse than using makespan alone, and num_tanks_used = ALL TANKS
Looks like solver stopped at first solution found
Note, I made no changes to parameters. Maybe I should have?

Can anyone with hands on experience provide some advice please
Thanks
Ross

Olivier Lhomme's profile image
Olivier Lhomme

Hi Ross, we are still waiting for more context from your side, so that we could reproduce the problem. Maybe you missed a previous answer: https://community.ibm.com/community/user/question/minimize-static-lex