OptaPlanner N queens を考える その3

中身を覗いてみよう編だ。

まず logback.xml でクラス名を出しておこう。

<pattern>%d [%t] %-5p [%c] %m%n</pattern>

するとキーポイントになるクラスが出てくるかなー。

TRACE [org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor]     Model annotations parsed for Solution NQueens:
TRACE [org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor]         Entity Queen:
TRACE [org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor]             Variable row (genuine)
INFO  [org.optaplanner.examples.nqueens.persistence.NQueensGenerator] NQueens 4 has 4 queens with a search space of 256.
INFO  [org.optaplanner.core.impl.solver.DefaultSolver] Solving started: time spent (55), best score (uninitialized/0), random (JDK with seed 0).
TRACE [org.optaplanner.core.impl.heuristic.selector.entity.decorator.SortingEntitySelector]     Created cachedEntityList with size (4) in entitySelector(Sorting(FromSolutionEntitySelector(Queen))).
TRACE [org.optaplanner.core.impl.heuristic.selector.entity.decorator.SortingEntitySelector]     Sorted cachedEntityList with size (4) in entitySelector(Sorting(FromSolutionEntitySelector(Queen))).
TRACE [org.optaplanner.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider]         Move index (0), score (0), move (col2@null => row0).
DEBUG [org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase]     CH step (0), time spent (82), score (0), selected move count (1), picked move (col2@null => row0).
...
INFO  [org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase] Construction Heuristic phase (0) ended: step total (4), time spent (111), best score (-1).
TRACE [org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider]         Move index (0), score (-2), accepted (true), move (col0@row1 => row0).
TRACE [org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider]         Move index (1) not doable, ignoring move (col0@row1 => row1).
TRACE [org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider]         Move index (2), score (-2), accepted (true), move (col0@row1 => row2).
TRACE [org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider]         Move index (3), score (-2), accepted (true), move (col0@row1 => row3).
TRACE [org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider]         Move index (4), score (-2), accepted (true), move (col1@row2 => row0).
...
DEBUG [org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase]     LS step (0), time spent (128), score (-1),     best score (-1), accepted/selected move count (12/12), picked move (col1@row2 => row3).
...
INFO  [org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase] Local Search phase (1) ended: step total (2), time spent (138), best score (0).
INFO  [org.optaplanner.core.impl.solver.DefaultSolver] Solving ended: time spent (140), best score (0), average calculate count per second (278).

で、ログを出力しているところらへんにブレークポイントを張って、デバッガでうろうろする。

DefaultSolver

nqueensSolverConfig.xml を元に SolverFactory からボコっと作られるのが DefaultSolver。これが phaseList を保持し、各 Phase を実行する。

DefaultConstructionHeuristicPhase

ConstructionHeuristicPhase を管理する。solveメソッド内で、Step のループを行う。ループは entityPlacer から受け取る Placement 毎に 1 Step となる。

ConstructionHeuristicDecider

各 Step 内で、placement から供給される Move の中から一つの Move を決定する。ConstructionHeuristicMoveScope が Move のラッパーとして役立っているようだ。

DefaultLocalSearchPhase

LocalSearchPhase を管理する。solveメソッド内で、Step のループを行う。ループは Phase が terminate されるまで続ける。

LocalSearchDecider

moveSelector, acceptor, forager を従えた重要なプレイヤーだ。各 Step 内で、moveSelector から供給される Move の中から一つの Move を決定する。processMoveメソッドで、acceptor がその Move を accept するか判定する。LocalSearchMoveScope が Move のラッパーとして役立っているようだ。

PhaseLifecycleListener

多くのクラスが PhaseLifecycleListener を implements しており、phaseStarted/phaseEnded, stepStarted/stepEnded のライフサイクルに応じて、整然と処理を実行している。

DroolsScoreDirector

ConstructionHeuristicDecider.processMove() / LocalSearchDecider.processMove() -> DefaultSolverScope.calculateScore() -> DroolsScoreDirector.calculateScore() の流れで呼ばれ、DRL を元にスコアを計算する。これは Drools じゃなくてもよい。例えば EasyScoreCalculator を implements し、スコアの計算方法を Java で実装することもできる。N Queen には NQueensEasyScoreCalculator が既にあるので、nqueensSolverConfig.xml で指定すれば使える。