I have 2 simultaneous solves running using docplex and I want to stop one of the solve as soon as the other one finishes. Is there an way to end one solve?
Asked
Active
Viewed 177 times
2 Answers
0
You can do this using the low-level engine object that is returned by the get_cplex()
function. This is an instance of the Cplex class of the CPLEX Python API. You can install an Aborter into that instance using function use_aborter().
If you use the same aborter for all Cplex
instances then you can eventually call the aborters abort()
function to stop all the solves.
Note that the request to abort is not always handled immediately. There may be a small delay before the CPLEX engine acknowledges the abort.

Daniel Junglas
- 5,830
- 1
- 5
- 22
-
Thank you, but do you have some example of this. I tried adding solver.get_cplex(cplex.Cplex().use_aborter(cplex.Aborter().abort())) to thread as soon as it completes but it doesn't seems to be working – Kartik Kaushik Sep 16 '20 at 23:13
-
You have to install the aborter *before* you start the solve and keep a reference to that aborter. Then, when you want to abort the solve you call that aborter's `abort()` method. You can take a look at the `mipex4.py` example that ships with cplex (of course you should call `abort()` way later than in this example). – Daniel Junglas Sep 17 '20 at 06:09
0
Thank you, I was able to add the feature using below code:
from docplex.mp.progress import ProgressListener, ProgressClock
class AutomaticAborter(ProgressListener):
""" a simple implementation of an automatic search stopper.
"""
def __init__(self):
super(AutomaticAborter, self).__init__(ProgressClock.All)
self.last_obj = None
self.last_obj_time = None
self.con = 0
def notify_start(self):
super(AutomaticAborter, self).notify_start()
self.last_obj = None
self.last_obj_time = None
self.con = 0
def is_improving(self, new_obj, eps=1e-4):
last_obj = self.last_obj
return last_obj is None or (abs(new_obj- last_obj) >= eps)
def notify_progress(self, pdata):
super(AutomaticAborter, self).notify_progress(pdata)
global con_f
if pdata.has_incumbent and self.is_improving(pdata.current_objective):
self.last_obj = pdata.current_objective
self.last_obj_time = pdata.time
print('----> #new objective={0}, time={1}s'.format(self.last_obj, self.last_obj_time))
else:
# a non improving move
last_obj_time = self.last_obj_time
this_time = pdata.time
if last_obj_time is not None:
self.con=con_f
if con_f>0:
print('!! aborting cplex, con_f >{}'.format(self.con))
self.abort()
else:
print('----> running {}'.format(con_f))
con_f=0
solver.add_progress_listener(AutomaticAborter())
solver1.add_progress_listener(AutomaticAborter())
def work(worker_queue, id, stop_event):
while not stop_event.is_set():
if id==1:
work.msol=solver.solve(clean_before_solve=True,log_output=True)
else:
work.msol1=solver1.solve(clean_before_solve=True,log_output=True)
# put worker ID in queue
if not stop_event.is_set():
worker_queue.put(id)
break
# queue for workers
worker_queue = Queue()
# indicator for other threads to stop
stop_event = threading.Event()
# run workers
threads = []
threads.append(Thread(target=work, args=(worker_queue, 1, stop_event)))
threads.append(Thread(target=work, args=(worker_queue, 2, stop_event)))
for thread in threads:
thread.start()
# this will block until the first element is in the queue
first_finished = worker_queue.get()
print(first_finished, 'was first!')
con_f=1
# signal the rest to stop working
stop_event.set()```

Kartik Kaushik
- 19
- 5