如何在TimeFold求解开始前后提取初始解决方案的详细分数信息?附缺失API示例代码说明
嗨,针对你的问题,我分两部分来解答:
一、提取初始解决方案的详细分数信息
既然你已经掌握了提取单个解决方案分数的方法,核心就是在求解启动的关键节点上拿到初始解,再执行你熟悉的分数提取操作即可,具体分两种场景:
1. 求解开始前(自行准备初始解时)
如果你是提前构造或加载好初始解决方案再交给TimeFold,那在调用Solver相关方法之前,直接对这个初始解执行分数提取操作就行——用你已经熟悉的方式,就能拿到它的详细硬约束、软约束得分情况。
2. 求解刚启动时(通过Solver流程获取初始解)
如果初始解是通过Solver的问题生成/加载逻辑(比如generate_problem)获取的,那你可以在这个环节直接处理:
在返回初始解给Solver之前,先提取并记录它的分数。比如在你的TimeFold代码里,可以给generate_problem加一步分数提取逻辑:
def generate_problem(inputfile): # 加载或生成初始解决方案 initial_solution = ... # 提取初始解的详细分数(用你熟悉的分数提取方式) initial_score = initial_solution.score print(f"初始解总分:{initial_score},硬约束得分:{initial_score.hard_score},软约束得分:{initial_score.soft_score}") return initial_solution
这样在求解刚启动、还没开始迭代优化时,就能拿到初始解的详细分数了。
另外,如果你用solve_and_listen模式,问题加载逻辑只会在求解启动时调用一次,返回的就是初始解——所以在这里插入分数提取逻辑,既能保证是Solver即将处理的初始解,也完全符合你“在求解开始前后获取分数”的需求。
二、缺失API示例代码说明(OptaPlanner vs TimeFold)
你提到的solveAndListen类API在OptaPlanner和TimeFold中有参数差异,我把两个版本的实现对比和逻辑说明整理如下:
1. OptaPlanner 版本的SolveAndListen实现
这个版本支持多阶段回调,包括最终最优解回调和异常处理回调,适配更复杂的监听场景:
def solve_live(self) -> None: """ 对应OptaPlanner SolverManager的solveAndListen方法,支持多阶段回调 """ self.job = self.context.solver_manager.solveAndListen(self.id, # 求解启动时调用一次,用于获取初始问题/解决方案 lambda the_id: self.find_by_id(the_id), # 每次最优解更新时调用,保存中间最优解 lambda solution: self.save(solution), # 求解结束时调用,保存最终最优解 lambda solution: self.save(solution), # 发生异常时的处理逻辑 lambda the_id, exc: self.exception(the_id, exc) )
2. TimeFold 版本的solve_and_listen实现
TimeFold对该API做了简化,将最终最优解的回调合并到了中间最优解回调中。如果需要模拟OptaPlanner的完整逻辑,可以在保存方法里自定义逻辑区分中间解和最终解,当前简化版实现如下:
def solve_live(self) -> None: self.job = self.context.solver_manager.solve_and_listen(self.id, # 求解启动时调用一次,生成/加载初始解 generate_problem(self.context._inputfile), # 每次最优解更新(包括最终解)时调用,保存解决方案 lambda solution: self.save(solution) )
备注:内容来源于stack exchange,提问作者AlexK73

