相关文章推荐
要出家的烈马  ·  find -exec ...·  1 年前    · 
另类的酱肘子  ·  使用示例从 Python ...·  1 年前    · 

如何在docplex中异步地中止一个解决方案?

0 人关注

我有两个同时运行的docplex求解,我想在另一个求解完成后立即停止其中一个求解。有什么方法可以结束一个解吗?

python
docplex
Kartik Kaushik
Kartik Kaushik
发布于 2020-09-09
2 个回答
Daniel Junglas
Daniel Junglas
发布于 2020-09-18
0 人赞同

你可以使用由 get_cplex() 函数返回的低级引擎对象来做到这一点。这是一个 get_cplex() 的实例。 Cplex 类的 CPLEX Python API .你可以安装一个 堕胎 到该实例中,使用函数 use_aborter() .

如果你对所有的 Cplex 实例使用同一个中止器,那么你最终可以调用中止器的 abort() 函数来停止所有的解。

请注意,中止的请求并不总是立即处理。在CPLEX引擎确认中止之前,可能会有一个小的延迟。

谢谢你,但你是否有一些这方面的例子。我试着在线程完成后加入solver.get_cplex(cplex.Cplex().use_aborter(cplex.Aborter().abort())),但似乎并没有效果。
你必须安装中止器 before 你开始求解并保持对该终止器的引用。然后,当你想中止求解时,你就调用那个中止器的 abort() 方法。你可以看看cplex附带的 mipex4.py 的例子(当然你应该比这个例子更晚调用 abort() )。
Kartik Kaushik
Kartik Kaushik
发布于 2020-09-18
已采纳
0 人赞同

谢谢你,我能够使用下面的代码来添加这个功能。

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