如何异步中止 docplex 中的求解?
How to asynchronously abort a solve in docplex?
我有 2 个同时使用 docplex 求解 运行,我想在另一个求解完成后立即停止其中一个求解。有没有办法结束一个解决方案?
您可以使用 get_cplex()
函数返回的 low-level 引擎对象来执行此操作。这是 Cplex class of the CPLEX Python API. You can install an Aborter into that instance using function use_aborter().
的实例
如果您对所有 Cplex
个实例使用相同的中止器,那么您最终可以调用中止器 abort()
函数来停止所有求解。
请注意,中止请求并不总是立即得到处理。在 CPLEX 引擎确认中止之前可能会有一小段延迟。
谢谢,我能够使用以下代码添加该功能:
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()```
我有 2 个同时使用 docplex 求解 运行,我想在另一个求解完成后立即停止其中一个求解。有没有办法结束一个解决方案?
您可以使用 get_cplex()
函数返回的 low-level 引擎对象来执行此操作。这是 Cplex class of the CPLEX Python API. You can install an Aborter into that instance using function use_aborter().
如果您对所有 Cplex
个实例使用相同的中止器,那么您最终可以调用中止器 abort()
函数来停止所有求解。
请注意,中止请求并不总是立即得到处理。在 CPLEX 引擎确认中止之前可能会有一小段延迟。
谢谢,我能够使用以下代码添加该功能:
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()```