笔记 / Timefold Solver / 领域模型建模
01 / 02 / 08

PlanningClone 与 SolutionManager / ScoreManager

@DeepPlanningClone 强制问题事实参与克隆;SolutionManager 用于解可行性分析和分数分解;ScoreManager 用于对任意方案计算分数

状态
持续整理
来源
Obsidian
创建
2026/07/21
公开整理
2026/07/31

30 秒速览#

三个常被遗漏但实际项目一定会碰到的概念:

  • @DeepPlanningClone:防止 JPA 关联导致克隆不完整。
  • SolutionManager:解释方案分数、分析可行性、更新影子变量。
  • ScoreManager:给任意方案计分,不启动 Solver。

规划克隆机制#

Timefold 内部会对 PlanningSolution 做规划克隆(planning clone)。克隆时:

  • 规划实体被深克隆(它们的规划变量会被修改)。
  • 问题事实默认不克隆(它们在求解过程中不变)。

问题:JPA 双向引用导致克隆不完整#

当问题事实类通过 @ManyToOne 引用回 PlanningSolution 时,默认克隆不克隆问题事实,可能引发持久化异常:

@PlanningSolution
@Entity
public class Conference {
    @OneToMany(mappedBy = "conference")
    private List<Room> roomList;
}

@Entity
public class Room {
    @ManyToOne
    private Conference conference;   // 引用回 PlanningSolution
}
java

解决:@DeepPlanningClone#

@DeepPlanningClone
@Entity
public class Room {
    @ManyToOne
    private Conference conference;
}
java

加了 @DeepPlanningClone 后,Room 也会在规划克隆时被克隆,避免 cloned entity 和原始 entity 共享 Conference 引用。

SolutionManager#

用于分析和解释方案。不启动 Solver,只对已有方案操作。

创建#

// 手动创建
SolutionManager<MySolution, HardSoftScore> solutionManager
    = SolutionManager.create(solverFactory);
java
// Spring Boot 注入
@Autowired
SolutionManager<Timetable, HardSoftScore> solutionManager;
java

核心操作#

// 判断方案是否可行(hard 约束是否全部满足)
ScoreAnalysis<HardSoftScore> analysis = solutionManager.analyze(solution);
boolean feasible = analysis.isFeasible();

// 获取每个约束的贡献明细
Map<String, ConstraintAnalysis> constraintMap = analysis.getConstraintAnalysisMap();

// 更新影子变量(不求解,只计算派生字段)
solutionManager.updateShadowVariables(solution);
java

更新影子变量#

SolutionManager.updateShadowVariables(solution) 在给定规划变量值的前提下,触发所有影子变量更新和级联计算。用途:

  • 手工构造方案后补齐推导字段。
  • 测试时验证影子变量逻辑。
  • 插单/重排前预处理已有方案。

ScoreManager#

比 SolutionManager 更轻量,只计算分数。

创建#

// 手动创建
ScoreManager<MySolution, HardSoftScore> scoreManager
    = ScoreManager.create(solverFactory);
java
// Spring Boot 注入
@Autowired
ScoreManager<Timetable, HardSoftScore> scoreManager;
java

核心操作#

// 计算方案分数
HardSoftScore score = scoreManager.updateScore(solution);

// 获取带解释的分数
ScoreExplanation<MySolution, HardSoftScore> explanation
    = scoreManager.explainScore(solution);
java

三者对比#

工具用途是否修改方案
@DeepPlanningClone强制事实类参与克隆注解,运行时生效
SolutionManager分析可行性、解释分数、更新影子变量会更新影子变量字段
ScoreManager计算和解释分数不会修改方案
工具适用场景
SolutionManager调试分数组成、验证方案可行、影子变量测试
ScoreManagerREST 接口返回方案分数、多方案快速比较

Spring Boot 自动注入#

Timefold Spring Boot Starter 可自动注入以下类型:

  • SolverConfig
  • SolverFactory
  • SolverManager
  • SolutionManager
  • ScoreManager
  • ConstraintMetaModel
  • ConstraintVerifier

以上只需要在 Spring 组件中 @Autowired 即可,框架根据 classpath 和配置自动识别领域类。

关联笔记#