[jboss-svn-commits] JBL Code SVN: r30823 - in labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US: Chapter-Benchmarking_and_tweaking and 5 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Fri Dec 25 09:05:10 EST 2009
Author: ge0ffrey
Date: 2009-12-25 09:05:09 -0500 (Fri, 25 Dec 2009)
New Revision: 30823
Added:
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Chapter-Benchmarking_and_tweaking.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Chapter-Local_search.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Chapter-Planner_configuration.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Chapter-Planner_introduction.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Chapter-Score_calculation.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Chapter-Use_cases_and_examples.xml
Removed:
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Section-Benchmarking_and_tweaking.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Section-Local_search.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Section-Planner_configuration.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Section-Planner_introduction.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Section-Score_calculation.xml
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Section-Use_cases_and_examples.xml
Modified:
labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/master.xml
Log:
rename section to chapter
Copied: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Chapter-Benchmarking_and_tweaking.xml (from rev 30822, labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Section-Benchmarking_and_tweaking.xml)
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Chapter-Benchmarking_and_tweaking.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Chapter-Benchmarking_and_tweaking.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
+ http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
+ version="5.0" xml:base="./">
+
+ <title>Benchmarking and tweaking</title>
+
+ <section>
+ <title>Finding the best configuration</title>
+
+ <para>Drools Planner supports several solver types, but you're probably wondering which is the best one? Although
+ some solver types generally perform better then others, it really depends on your problem domain. Most solver types
+ also have settings which can be tweaked. Those settings can influence the results of a solver a lot, although most
+ settings perform pretty good out-of-the-box.
+ </para>
+
+ <para>Luckily, Drools Planner includes a benchmarker, which allows you to play out different solver types and
+ different settings against each other, so you can pick the best configuration for your problem domain.
+ </para>
+ </section>
+
+ <section>
+ <title>Building a Benchmarker</title>
+
+ <para>You can build a
+ <literal>Benchmarker</literal>
+ instance with the<literal>XmlSolverBenchmarker</literal>.
+ Configure it with a benchmarker configuration xml file:
+ </para>
+
+ <programlisting>XmlSolverBenchmarker benchmarker = new XmlSolverBenchmarker();
+ benchmarker.configure("/org/drools/planner/examples/nqueens/benchmark/nqueensSolverBenchmarkConfig.xml");
+ benchmarker.benchmark();
+ benchmarker.writeResults(resultFile);
+ </programlisting>
+
+ <para>A basic benchmarker configuration file looks something like this:</para>
+
+ <programlisting><?xml version="1.0" encoding="UTF-8"?>
+ <solverBenchmarkSuite>
+ <solvedSolutionFilesDirectory>local/data/nqueens/solved</solvedSolutionFilesDirectory>
+
+ <inheritedUnsolvedSolutionFile>data/nqueens/unsolved/unsolvedNQueens32.xml</inheritedUnsolvedSolutionFile>
+ <inheritedUnsolvedSolutionFile>data/nqueens/unsolved/unsolvedNQueens64.xml</inheritedUnsolvedSolutionFile>
+ <inheritedLocalSearchSolver>
+ <scoreDrl>/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl>
+ <scoreDefinition>
+ <scoreDefinitionType>SIMPLE</scoreDefinitionType>
+ </scoreDefinition>
+ <termination>
+ <maximumSecondsSpend>20</maximumSecondsSpend>
+ </termination>
+ <selector>
+ <moveFactoryClass>org.drools.planner.examples.nqueens.solver.move.factory.NQueensMoveFactory</moveFactoryClass>
+ </selector>
+ <forager>
+ <foragerType>MAX_SCORE_OF_ALL</foragerType>
+ </forager>
+ </inheritedLocalSearchSolver>
+
+ <solverBenchmark>
+ <name>Solution tabu</name>
+ <localSearchSolver>
+ <acceptor>
+ <completeSolutionTabuSize>1000</completeSolutionTabuSize>
+ </acceptor>
+ </localSearchSolver>
+ </solverBenchmark>
+ <solverBenchmark>
+ <name>Move tabu 5</name>
+ <localSearchSolver>
+ <acceptor>
+ <completeMoveTabuSize>5</completeMoveTabuSize>
+ </acceptor>
+ </localSearchSolver>
+ </solverBenchmark>
+ <solverBenchmark>
+ <name>Move tabu 7</name>
+ <localSearchSolver>
+ <acceptor>
+ <completeMoveTabuSize>7</completeMoveTabuSize>
+ </acceptor>
+ </localSearchSolver>
+ </solverBenchmark>
+ <solverBenchmark>
+ <name>Solution tabu and move tabu 7</name>
+ <localSearchSolver>
+ <acceptor>
+ <completeSolutionTabuSize>1000</completeSolutionTabuSize>
+ <completeMoveTabuSize>7</completeMoveTabuSize>
+ </acceptor>
+ </localSearchSolver>
+ </solverBenchmark>
+ </solverBenchmarkSuite></programlisting>
+
+ <para>This benchmarker will try 4 configurations (1 solution tabu, 2 move tabu's and 1 solution-move tabu) on 2 data
+ sets (32 and 64 queens), so it will run 8 solvers.
+ </para>
+
+ <para>Every
+ <literal>solverBenchmark</literal>
+ entity contains a solver configuration (for example a local search
+ solver) and one or more
+ <literal>unsolvedSolutionFile</literal>
+ entities. It will run the solver configuration on
+ each of those unsolved solution files. A
+ <literal>name</literal>
+ is optional and generated if absent. The common
+ part of multiple
+ <literal>solverBenchmark</literal>
+ entities can be extracted to the
+ <literal>inherited</literal>
+ entities and can be overwritten per
+ <literal>solverBenchmark</literal>
+ entity.
+ </para>
+
+ <para>If you specify a
+ <literal>solvedSolutionFilesDirectory</literal>
+ (relative to the working directory), the best
+ solution of each solver run will be written to that directory.
+ </para>
+ </section>
+</chapter>
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Chapter-Benchmarking_and_tweaking.xml
___________________________________________________________________
Name: svn:executable
+ *
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Section-Benchmarking_and_tweaking.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Section-Benchmarking_and_tweaking.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Benchmarking_and_tweaking/Section-Benchmarking_and_tweaking.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -1,128 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
- http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
- version="5.0" xml:base="./">
-
- <title>Benchmarking and tweaking</title>
-
- <section>
- <title>Finding the best configuration</title>
-
- <para>Drools Planner supports several solver types, but you're probably wondering which is the best one? Although
- some solver types generally perform better then others, it really depends on your problem domain. Most solver types
- also have settings which can be tweaked. Those settings can influence the results of a solver a lot, although most
- settings perform pretty good out-of-the-box.
- </para>
-
- <para>Luckily, Drools Planner includes a benchmarker, which allows you to play out different solver types and
- different settings against each other, so you can pick the best configuration for your problem domain.
- </para>
- </section>
-
- <section>
- <title>Building a Benchmarker</title>
-
- <para>You can build a
- <literal>Benchmarker</literal>
- instance with the<literal>XmlSolverBenchmarker</literal>.
- Configure it with a benchmarker configuration xml file:
- </para>
-
- <programlisting>XmlSolverBenchmarker benchmarker = new XmlSolverBenchmarker();
- benchmarker.configure("/org/drools/planner/examples/nqueens/benchmark/nqueensSolverBenchmarkConfig.xml");
- benchmarker.benchmark();
- benchmarker.writeResults(resultFile);
- </programlisting>
-
- <para>A basic benchmarker configuration file looks something like this:</para>
-
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
- <solverBenchmarkSuite>
- <solvedSolutionFilesDirectory>local/data/nqueens/solved</solvedSolutionFilesDirectory>
-
- <inheritedUnsolvedSolutionFile>data/nqueens/unsolved/unsolvedNQueens32.xml</inheritedUnsolvedSolutionFile>
- <inheritedUnsolvedSolutionFile>data/nqueens/unsolved/unsolvedNQueens64.xml</inheritedUnsolvedSolutionFile>
- <inheritedLocalSearchSolver>
- <scoreDrl>/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl>
- <scoreDefinition>
- <scoreDefinitionType>SIMPLE</scoreDefinitionType>
- </scoreDefinition>
- <termination>
- <maximumSecondsSpend>20</maximumSecondsSpend>
- </termination>
- <selector>
- <moveFactoryClass>org.drools.planner.examples.nqueens.solver.move.factory.NQueensMoveFactory</moveFactoryClass>
- </selector>
- <forager>
- <foragerType>MAX_SCORE_OF_ALL</foragerType>
- </forager>
- </inheritedLocalSearchSolver>
-
- <solverBenchmark>
- <name>Solution tabu</name>
- <localSearchSolver>
- <acceptor>
- <completeSolutionTabuSize>1000</completeSolutionTabuSize>
- </acceptor>
- </localSearchSolver>
- </solverBenchmark>
- <solverBenchmark>
- <name>Move tabu 5</name>
- <localSearchSolver>
- <acceptor>
- <completeMoveTabuSize>5</completeMoveTabuSize>
- </acceptor>
- </localSearchSolver>
- </solverBenchmark>
- <solverBenchmark>
- <name>Move tabu 7</name>
- <localSearchSolver>
- <acceptor>
- <completeMoveTabuSize>7</completeMoveTabuSize>
- </acceptor>
- </localSearchSolver>
- </solverBenchmark>
- <solverBenchmark>
- <name>Solution tabu and move tabu 7</name>
- <localSearchSolver>
- <acceptor>
- <completeSolutionTabuSize>1000</completeSolutionTabuSize>
- <completeMoveTabuSize>7</completeMoveTabuSize>
- </acceptor>
- </localSearchSolver>
- </solverBenchmark>
- </solverBenchmarkSuite></programlisting>
-
- <para>This benchmarker will try 4 configurations (1 solution tabu, 2 move tabu's and 1 solution-move tabu) on 2 data
- sets (32 and 64 queens), so it will run 8 solvers.
- </para>
-
- <para>Every
- <literal>solverBenchmark</literal>
- entity contains a solver configuration (for example a local search
- solver) and one or more
- <literal>unsolvedSolutionFile</literal>
- entities. It will run the solver configuration on
- each of those unsolved solution files. A
- <literal>name</literal>
- is optional and generated if absent. The common
- part of multiple
- <literal>solverBenchmark</literal>
- entities can be extracted to the
- <literal>inherited</literal>
- entities and can be overwritten per
- <literal>solverBenchmark</literal>
- entity.
- </para>
-
- <para>If you specify a
- <literal>solvedSolutionFilesDirectory</literal>
- (relative to the working directory), the best
- solution of each solver run will be written to that directory.
- </para>
- </section>
-</chapter>
Copied: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Chapter-Local_search.xml (from rev 30822, labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Section-Local_search.xml)
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Chapter-Local_search.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Chapter-Local_search.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -0,0 +1,771 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
+ http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
+ version="5.0" xml:base="./">
+
+ <title>Local search solver</title>
+
+ <section>
+ <title>Overview</title>
+
+ <para>In number of possible solutions for a planning problem can be mind blowing. For example:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>4 queens has 256 possible solutions (<literal>n ^ n</literal>) and 2 optimal solutions.</para>
+ </listitem>
+
+ <listitem>
+ <para>5 queens has 3125 possible solutions (<literal>n ^ n</literal>) and 1 optimal solution.</para>
+ </listitem>
+
+ <listitem>
+ <para>8 queens has 16777216 possible solutions (<literal>n ^ n</literal>) and 92 optimal solutions.</para>
+ </listitem>
+
+ <listitem>
+ <para>Most real-life planning problems have an incredible number of possible solutions and only 1 optimal
+ solution.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>An algorithm that checks every possible solution (even with pruning) can easily run for billions of years on a
+ single real-life planning problem. Most of the time, we are happy with a feasible solution found in a limited amount
+ of time. Local search tends to find a feasible solution relatively fast. Because it acts very much like a human, it
+ is also pretty natural to program.</para>
+
+ <para>Local search solves a problem by making a move on the current solution which changes it into a better
+ solution. It does that number of times till it is satisfied with the solution. It starts with the starting
+ solution.</para>
+
+ <para>A local search algorithm and the drools rule engine turn out to be a really nice combination, because:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>A rule engine such as Drools is <emphasis role="bold">great for calculating the score</emphasis> of a
+ solution of a planning problem. It make it easy to add additional soft or hard constraints such as "a teacher
+ shouldn't teach more then 7 hours a day". However it tends to be too complex to use to actually find new
+ solutions.</para>
+ </listitem>
+
+ <listitem>
+ <para>A local search algorithm is <emphasis role="bold">great at finding new improving solutions</emphasis> for
+ a planning problem, without brute-forcing every possibility. However it needs to know the score of a solution
+ and normally offers no support in calculating that score.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Drools Planner's local search implementation combines both. On top of that, it also offers additional support
+ for benchmarking etc.</para>
+ </section>
+
+ <section>
+ <title>A move</title>
+
+ <para>A move is the change from a solution A to a solution B. For example, below you can see a single move on the
+ starting solution of 4 queens that moves a single queen to another row:</para>
+
+ <figure>
+ <title>A single move (4 queens example)</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Local_search/singleMoveNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A move can have a small or large impact. In the above example, the move of queen <emphasis>C0 to C2</emphasis>
+ is a small move. Some moves are the same move type. These are some possibilities for move types in n queens:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Move a single queen to another row. This is a small move. For example, move queen <emphasis>C0 to
+ C2</emphasis>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Move all queens a number of rows down or up. This a big move.</para>
+ </listitem>
+
+ <listitem>
+ <para>Move a single queen to another column. This is a small move. For example, move queen <emphasis>C2 to
+ A0</emphasis> (placing it on top of queen A0).</para>
+ </listitem>
+
+ <listitem>
+ <para>Add a queen to the board at a certain row and column.</para>
+ </listitem>
+
+ <listitem>
+ <para>Remove a queen from the board.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Because we have decided that all queens will be on the board at all times and each queen has an appointed
+ column (for performance reasons), only the first 2 move types are usable in our example. Furthermore, we 're only
+ using the first move type in the example because we think it gives the best performance, but you are welcome to
+ prove us wrong.</para>
+
+ <para>Each of your move types will be an implementation of the <literal>Move</literal> interface:</para>
+
+ <programlisting>public interface Move {
+
+ boolean isMoveDoable(EvaluationHandler evaluationHandler);
+
+ Move createUndoMove(EvaluationHandler evaluationHandler);
+
+ void doMove(EvaluationHandler evaluationHandler);
+
+}</programlisting>
+
+ <para>Let's take a look at the <literal>Move</literal> implementation for 4 queens which moves a queen to a
+ different row:</para>
+
+ <programlisting>public class YChangeMove implements Move {
+
+ private Queen queen;
+ private int toY;
+
+ public YChangeMove(Queen queen, int toY) {
+ this.queen = queen;
+ this.toY = toY;
+ }
+
+ // ... see below
+
+}</programlisting>
+
+ <para>An instance of <literal>YChangeMove</literal> moves a queen from it's current y to a different y.</para>
+
+ <para>Drools Planner calls the <literal>doMove(WorkingMemory)</literal> method to do a move. The
+ <literal>Move</literal> implementation must notify the working memory of any changes it does on the solution
+ facts:</para>
+
+ <programlisting> public void doMove(WorkingMemory workingMemory) {
+ FactHandle queenHandle = workingMemory.getFactHandle(queen);
+ workingMemory.modifyRetract(queenHandle); // before changes are made
+ queen.setY(toY);
+ workingMemory.modifyInsert(queenHandle, queen); // after changes are made
+ }</programlisting>
+
+ <para>Drools Planner disables shadow facts for increased performance, so you cannot use the
+ <literal>workingMemory.update(FactHandle, Object)</literal> method, instead you need to call the
+ <literal>workingMemory.modifyRetract(FactHandle)</literal> method before modifying the fact and the
+ <literal>workingMemory.modifyInsert(FactHandle, Object)</literal> method after modifying the fact. Note that you can
+ alter multiple facts in a single move and effectively create a big move (also known as a coarse-grained
+ move).</para>
+
+ <para>Drools Planner automatically filters out <emphasis>non doable moves</emphasis> by calling the
+ <literal>isDoable(WorkingMemory)</literal> method on a move. A <emphasis>non doable move</emphasis> is:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>A move that changes nothing on the current solution. For example, moving queen B0 to row 0 is not
+ doable.</para>
+ </listitem>
+
+ <listitem>
+ <para>A move that is impossible to do on the current solution. For example, moving queen B0 to row 10 is not
+ doable because it would move it outside the board limits.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>In the n queens example, a move which moves the queen from it's current row to the same row isn't
+ doable:</para>
+
+ <programlisting> public boolean isMoveDoable(WorkingMemory workingMemory) {
+ int fromY = queen.getY();
+ return fromY != toY;
+ }</programlisting>
+
+ <para>Because we won't generate a move which can move a queen outside the board limits, we don't need to check it. A
+ move that is currently not doable can become doable on a later solution.</para>
+
+ <para>Each move has an <emphasis>undo move</emphasis>: a move (usually of the same type) which does the exact
+ opposite. In the above example the undo move of <emphasis>C0 to C2</emphasis> would be the move <emphasis>C2 to
+ C0</emphasis>. An undo move can be created from a move, but only before the move has been done on the current
+ solution.</para>
+
+ <programlisting> public Move createUndoMove(WorkingMemory workingMemory) {
+ return new YChangeMove(queen, queen.getY());
+ }</programlisting>
+
+ <para>Notice that if C0 would have already been moved to C2, the undo move would create the move <emphasis>C2 to
+ C2</emphasis>, instead of the move <emphasis>C2 to C0</emphasis>.</para>
+
+ <para>The local search solver can do and undo a move more than once, even on different (successive)
+ solutions.</para>
+
+ <para>A move must implement the <literal>equals()</literal> and <literal>hashcode()</literal> methods. 2 moves which
+ make the same change on a solution, must be equal.</para>
+
+ <programlisting> public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ } else if (o instanceof YChangeMove) {
+ YChangeMove other = (YChangeMove) o;
+ return new EqualsBuilder()
+ .append(queen, other.queen)
+ .append(toY, other.toY)
+ .isEquals();
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return new HashCodeBuilder()
+ .append(queen)
+ .append(toY)
+ .toHashCode();
+ }</programlisting>
+
+ <para>In the above example, the <literal>Queen</literal> class uses the default <literal>Object</literal>
+ <literal>equal()</literal> and <literal>hashcode()</literal> implementations. Notice that it checks if the other
+ move is an instance of the same move type. This is important because a move will be compared to a move with another
+ move type if you're using more then 1 move type.</para>
+
+ <para>It's also recommended to implement the <literal>toString()</literal> method as it allows you to read
+ Drools Planner's logging more easily:</para>
+
+ <programlisting> public String toString() {
+ return queen + " => " + toY;
+ }</programlisting>
+
+ <para>Now that we can make a single move, let's take a look at generating moves.</para>
+ </section>
+
+ <section>
+ <title>Move generation</title>
+
+ <para>At each solution, local search will try all possible moves and pick the best move to change to the next
+ solution. It's up to you to generate those moves. Let's take a look at all the possible moves on the starting
+ solution of 4 queens:</para>
+
+ <figure>
+ <title>Possible moves at step 0 (4 queens example)</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Local_search/possibleMovesNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>As you can see, not all the moves are doable. At the starting solution we have 12 doable moves (<literal>n *
+ (n - 1)</literal>), one of which will be move which changes the starting solution into the next solution. Notice
+ that the number of possible solutions is 256 (<literal>n ^ n</literal>), much more that the amount of doable moves.
+ Don't create a move to every possible solution. Instead use moves which can be sequentially combined to reach every
+ possible solution.</para>
+
+ <para>It's highly recommended that you verify all solutions are connected by your move set. This means that by
+ combining a finite number of moves you can reach any solution from any solution. Otherwise you're already excluding
+ solutions at the start. Especially if you're using only big moves, you should check it. Just because big moves
+ outperform small moves in a short test run, it doesn't mean that they will outperform them in a long test
+ run.</para>
+
+ <para>You can mix different move types. Usually you're better off preferring small (fine-grained) moves over big
+ (course-grained) moves because the score delta calculation will pay off more. However, as the traveling tournament
+ example proves, if you can remove a hard constraint by using a certain set of big moves, you can win performance and
+ scalability. Try it yourself: run both the simple (small moves) and the smart (big moves) version of the traveling
+ tournament example. The smart version evaluates a lot less unfeasible solutions, which enables it to outperform and
+ outscale the simple version.</para>
+
+ <para>Move generation currently happens with a <literal>MoveFactory</literal>:</para>
+
+ <programlisting>public class NQueensMoveFactory extends CachedMoveListMoveFactory {
+
+ public List<Move> createMoveList(Solution solution) {
+ NQueens nQueens = (NQueens) solution;
+ List<Move> moveList = new ArrayList<Move>();
+ for (Queen queen : nQueens.getQueenList()) {
+ for (int n : nQueens.createNList()) {
+ moveList.add(new YChangeMove(queen, n));
+ }
+ }
+ return moveList;
+ }
+
+}</programlisting>
+
+ <para>But we'll be making move generation part of the drl's soon.</para>
+ </section>
+
+ <section>
+ <title>A step</title>
+
+ <para>A step is the winning move. The local search solver tries every move on the current solution and picks the
+ best accepted move as the step:</para>
+
+ <figure>
+ <title>Decide the next step at step 0 (4 queens example)</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Local_search/decideNextStepNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Because the move <emphasis>B0 to B3</emphasis> has the highest score (<literal>-3</literal>), it is picked as
+ the next step. Notice that <emphasis>C0 to C3</emphasis> (not shown) could also have been picked because it also has
+ the score <literal>-3</literal>. If multiple moves have the same highest score, one is picked randomly, in this case
+ <emphasis>B0 to B3</emphasis>.</para>
+
+ <para>The step is made and from that new solution, the local search solver tries all the possible moves again, to
+ decide the next step after that. It continually does this in a loop, and we get something like this:</para>
+
+ <figure>
+ <title>All steps (4 queens example)</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Local_search/allStepsNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Notice that the local search solver doesn't use a search tree, but a search path. The search path is
+ highlighted by the green arrows. At each step it tries all possible moves, but unless it's the step, it doesn't
+ investigate that solution further. This is one of the reasons why local search is very scalable.</para>
+
+ <para>As you can see, the local search solver solves the 4 queens problem by starting with the starting solution and
+ make the following steps sequentially:</para>
+
+ <orderedlist>
+ <listitem>
+ <para><emphasis>B0 to B3</emphasis></para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>D0 to B2</emphasis></para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>A0 to B1</emphasis></para>
+ </listitem>
+ </orderedlist>
+
+ <para>If we turn on INFO logging, this is reflected into the logging:</para>
+
+ <programlisting>INFO Solving with random seed (0).
+INFO Initial score (-6) is starting best score. Updating best solution and best score.
+INFO Step (0), time spend (0) doing next step ([Queen-1] 1 @ 0 => 3).
+INFO New score (-3) is better then last best score (-6). Updating best solution and best score.
+INFO Step (1), time spend (0) doing next step ([Queen-3] 3 @ 0 => 2).
+INFO New score (-1) is better then last best score (-3). Updating best solution and best score.
+INFO Step (2), time spend (15) doing next step ([Queen-0] 0 @ 0 => 1).
+INFO New score (0) is better then last best score (-1). Updating best solution and best score.
+INFO Solved in 3 steps and 15 time millis spend.</programlisting>
+
+ <para>Notice that the logging used the <literal>toString()</literal> method from our <literal>Move</literal>
+ implementation: <literal>[Queen-1] 1 @ 0 => 3</literal>.</para>
+
+ <para>The local search solver solves the 4 queens problem in 3 steps, by evaluating only 37 possible solutions (3
+ steps with 12 moves each + 1 starting solution), which is only fraction of all 256 possible solutions. It solves 16
+ queens in 31 steps, by evaluating only 7441 out of 18446744073709551616 possible solutions.</para>
+ </section>
+
+ <section>
+ <title>Getting stuck in local optima</title>
+
+ <para>A <emphasis>simple local search</emphasis> always takes improving moves. This may seem like a good thing, but
+ it's not. It suffers from a number of problems:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It can get stuck in a local optimum. For example if it reaches a solution X with a score -1 and there is
+ no improving move, it is forced to take a next step that leads to a solution Y with score -2, after that
+ however, it's very real that it will pick the step back to solution X with score -1. It will then start looping
+ between solution X and Y.</para>
+ </listitem>
+
+ <listitem>
+ <para>It can start walking in it's own footsteps, picking the same next step at every step.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Of course Drools Planner implements better local searches, such as <emphasis>tabu search</emphasis> and
+ <emphasis>simulated annealing</emphasis> which can avoid these problems. It's recommended to never use a simple
+ local search, unless you're absolutely sure there are no local optima in your planning problem.</para>
+ </section>
+
+ <section>
+ <title>Deciding the next step</title>
+
+ <para>The local search solver decides the next step with the aid of 3 configurable components:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>A <emphasis>selector</emphasis> which selects (or generates) the possible moves of the current
+ solution.</para>
+ </listitem>
+
+ <listitem>
+ <para>An <emphasis>acceptor</emphasis> which filters out unacceptable moves. It can also weigh a move it
+ accepts.</para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>forager</emphasis> which gathers all accepted moves and picks the next step from them.</para>
+ </listitem>
+ </itemizedlist>
+
+ <figure>
+ <title>Decide the next step at step 0 (4 queens example)</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Local_search/decideNextStepNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>In the above example the selector generated the moves shown with the blue lines, the acceptor accepted all of
+ them and the forager picked the move <emphasis>B0 to B3</emphasis>.</para>
+
+ <para>If we turn on DEBUG logging, we can see the decision making in the log:</para>
+
+ <programlisting>INFO Solving with random seed (0).
+INFO Initial score (-6) is starting best score. Updating best solution and best score.
+DEBUG Move ([Queen-0] 0 @ 0 => 0) ignored because not doable.
+DEBUG Move ([Queen-0] 0 @ 1 => 1) with score (-4) and acceptChance (1.0).
+DEBUG Move ([Queen-0] 0 @ 2 => 2) with score (-4) and acceptChance (1.0).
+...
+DEBUG Move ([Queen-1] 1 @ 3 => 3) with score (-3) and acceptChance (1.0).
+...
+DEBUG Move ([Queen-3] 3 @ 3 => 3) with score (-4) and acceptChance (1.0).
+INFO Step (0), time spend (0) doing next step ([Queen-1] 1 @ 0 => 3).
+INFO New score (-3) is better then last best score (-6). Updating best solution and best score.
+...</programlisting>
+
+ <section>
+ <title>Selector</title>
+
+ <para>A selector is currently based on a <literal>MoveFactory</literal>.</para>
+
+ <programlisting> <selector>
+ <moveFactoryClass>org.drools.planner.examples.nqueens.solver.NQueensMoveFactory</moveFactoryClass>
+ </selector></programlisting>
+
+ <para>You're not obligated to generate the same stable set of moves at each step. You could start with generating
+ only big moves initially, and gradually switch to small moves. There's no build-in support for this yet
+ though.</para>
+
+ <para>If there are many possible moves, it can become inefficient to evaluate all of them every step. With
+ relativeSelection only a random subset of them is evaluated:</para>
+
+ <programlisting> <selector>
+ <moveFactoryClass>org.drools.planner.examples.examination.solver.move.factory.RoomChangeMoveFactory</moveFactoryClass>
+ <relativeSelection>0.002</relativeSelection>
+ </selector></programlisting>
+ </section>
+
+ <section>
+ <title>Acceptor</title>
+
+ <para>An acceptor is used (together with a forager) to active tabu search, simulated annealing, great deluge, ...
+ For each move it generates an accept chance. If a move is rejected it is given an accept chance of
+ <literal>0.0</literal>.</para>
+
+ <para>You can implement your own <literal>Acceptor</literal>, although the build-in acceptors should suffice for
+ most needs. You can also combine multiple acceptors.</para>
+
+ <section>
+ <title>Tabu search acceptor</title>
+
+ <para>When tabu search takes steps it creates tabu's. It does not accept a move as the next step if that move
+ breaks tabu. Drools Planner implements several tabu types:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Solution tabu</emphasis> makes recently visited solutions tabu. It does not accept a move
+ that leads to one of those solutions. If you can spare the memory, don't be cheap on the tabu size. We
+ recommend this type of tabu because it tends to give the best results and requires little or no
+ tweaking.</para>
+
+ <programlisting> <acceptor>
+ <completeSolutionTabuSize>1000</completeSolutionTabuSize>
+ </acceptor></programlisting>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Move tabu</emphasis> makes recent steps tabu. It does not accept a move equal to one of
+ those steps.</para>
+
+ <programlisting> <acceptor>
+ <completeMoveTabuSize>1000</completeMoveTabuSize>
+ </acceptor></programlisting>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Undo move tabu </emphasis>makes the undo move of recent steps tabu.</para>
+
+ <programlisting> <acceptor>
+ <completeUndoMoveTabuSize>1000</completeUndoMoveTabuSize>
+ </acceptor></programlisting>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Property tabu</emphasis> makes a property of recent steps tabu. For example, it can make the
+ queen tabu, so that a recently moved queen can't be moved.</para>
+
+ <programlisting> <acceptor>
+ <completePropertyTabuSize>1000</completePropertyTabuSize>
+ </acceptor></programlisting>
+
+ <para>To use property tabu, your moves must implement the <literal>TabuPropertyEnabled</literal> interface,
+ for example:</para>
+
+ <programlisting>public class YChangeMove implements Move, TabuPropertyEnabled {
+
+ private Queen queen;
+ private int toY;
+
+ // ...
+
+ public List<? extends Object> getTabuPropertyList() {
+ return Collections.singletonList(queen);
+ }
+
+}</programlisting>
+ </listitem>
+ </itemizedlist>
+
+ <para>You can even combine tabu types:</para>
+
+ <programlisting> <acceptor>
+ <completeSolutionTabuSize>1000</completeSolutionTabuSize>
+ <completeUndoMoveTabuSize>10</completeUndoMoveTabuSize>
+ </acceptor></programlisting>
+
+ <para>If you pick a too small tabu size, your solver can still get stuck in a local optimum. On the other hand,
+ with the exception of solution tabu, if you pick a too large tabu size, your solver can get stuck by bouncing of
+ the walls. Use the benchmarker to fine tweak your configuration.</para>
+
+ <para>A tabu search acceptor should be combined with a <emphasis>maximum score of all</emphasis> or
+ <emphasis>first best score improving</emphasis> forager.</para>
+ </section>
+
+ <section>
+ <title>Simulated annealing acceptor</title>
+
+ <para>Simulated annealing does not pick the move with the highest score, neither does it evaluate all moves. At
+ least at first.</para>
+
+ <para>It gives unimproving moves a chance, depending on it's score and the temperature. The
+ <emphasis>temperature</emphasis> is relative to how long it has been solving. In the end, it gradually turns
+ into a simple local search, only accepting improving moves.</para>
+
+ <para>A simulated annealing acceptor should be combined with a <emphasis>first randomly accepted</emphasis>
+ forager.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Forager</title>
+
+ <para>A forager gathers all accepted moves and picks the move which is the next step. A forager can choose to
+ allow only a subset of all selected moves to be evaluated, by quitting early if a suitable move has been
+ accepted.</para>
+
+ <para>You can implement your own <literal>Forager</literal>, although the build-in foragers should suffice for
+ most needs.</para>
+
+ <section>
+ <title>Maximum score of all forager</title>
+
+ <para>Allows all selected moves to be evaluated and picks the accepted move with the highest score. If several
+ accepted moves have the highest score, one is picked randomly, weighted on their accept chance.</para>
+
+ <programlisting> <forager>
+ <foragerType>MAX_SCORE_OF_ALL</foragerType>
+ </forager></programlisting>
+ </section>
+
+ <section>
+ <title>First best score improving forager</title>
+
+ <para>Picks the first accepted move that improves the best score. If none improve the best score, it behaves
+ exactly like the maximum score of all forager.</para>
+
+ <programlisting> <forager>
+ <foragerType>FIRST_BEST_SCORE_IMPROVING</foragerType>
+ </forager></programlisting>
+ </section>
+
+ <section>
+ <title>First last step score improving forager</title>
+
+ <para>Picks the first accepted move that improves the last step score. If none improve the last step score, it
+ behaves exactly like the maximum score of all forager.</para>
+
+ <programlisting> <forager>
+ <foragerType>FIRST_BEST_SCORE_IMPROVING</foragerType>
+ </forager></programlisting>
+ </section>
+
+ <section>
+ <title>First randomly accepted forager</title>
+
+ <para>Generates a random number for each accepted move and if the move's accept chance is higher, it picks that
+ move as the next move.</para>
+
+ <programlisting> <forager>
+ <foragerType>FIRST_RANDOMLY_ACCEPTED</foragerType>
+ </forager></programlisting>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Best solution</title>
+
+ <para>Because the current solution can degrade (especially in tabu search and simulated annealing), the local search
+ solver remembers the best solution it has encountered through the entire search path. Each time the current solution
+ is better than the last best solution, the current solution is cloned and referenced as the new best
+ solution.</para>
+
+ <para>You can listen to solver events, including when the best solution changes during solving, by adding a
+ <literal>SolverEventListener</literal> to the <literal>Solver</literal>:</para>
+
+ <programlisting>public interface Solver {
+
+ // ...
+
+ void addEventListener(SolverEventListener eventListener);
+ void removeEventListener(SolverEventListener eventListener);
+
+}</programlisting>
+ </section>
+
+ <section>
+ <title>Termination</title>
+
+ <para>Sooner or later the local search solver will have to stop solving. This can be because of a number of reasons:
+ the time is up, the perfect score has been reached, ... The only thing you can't depend on is on finding the optimal
+ solution (unless you know the optimal score), because a local search solver doesn't know that when it finds the
+ optimal solution. For real-life problems this doesn't turn out to be much of a problem, because finding the optimal
+ solution would take years, so you 'll want to terminate sooner anyway.</para>
+
+ <para>You can configure when a local search solver needs to stop by configuring a Termination. You can implement
+ your own <literal>Termination</literal>, although the build-in Terminations should suffice for most needs.</para>
+
+ <section>
+ <title>TimeMillisSpendTermination</title>
+
+ <para>Terminates when an amount of time has been reached:</para>
+
+ <programlisting> <termination>
+ <maximumMinutesSpend>2</maximumMinutesSpend>
+ </termination></programlisting>
+
+ <para>or</para>
+
+ <programlisting> <termination>
+ <maximumHoursSpend>1</maximumHoursSpend>
+ </termination></programlisting>
+
+ <para>Note that the time taken by a <literal>StartingSolutionInitializer</literal> also is taken into account by
+ this Termination. So if you give the solver 2 minutes to solve something, but the initializer takes 1 minute, the
+ local search solver will only have a minute left.</para>
+
+ <para>Note that if you use this Termination, you will most likely sacrifice reproducability. The best solution
+ will depend on available CPU time, not only because it influences the amount of steps taken, but also because time
+ gradient based algorithms (such as simulated annealing) will probably act differently on each run.</para>
+ </section>
+
+ <section>
+ <title>StepCountTermination</title>
+
+ <para>Terminates when an amount of steps has been reached:</para>
+
+ <programlisting> <termination>
+ <maximumStepCount>100</maximumStepCount>
+ </termination></programlisting>
+ </section>
+
+ <section>
+ <title>ScoreAttainedTermination</title>
+
+ <para>Terminates when a certain score has been reached. You can use this Termination if you know the perfect
+ score, for example for 4 queens:</para>
+
+ <programlisting> <termination>
+ <scoreAttained>0</scoreAttained>
+ </termination></programlisting>
+
+ <para>You can also use this Termination to terminate once it reaches a feasible solution. For a solver problem
+ with hard and soft contraints, it could look like this:</para>
+
+ <programlisting> <termination>
+ <scoreAttained>0hard/-5000soft</scoreAttained>
+ </termination></programlisting>
+ </section>
+
+ <section>
+ <title>UnimprovedStepCountTermination</title>
+
+ <para>Terminates when the best score hasn't improved in a number of steps:</para>
+
+ <programlisting> <termination>
+ <maximumUnimprovedStepCount>100</maximumUnimprovedStepCount>
+ </termination></programlisting>
+
+ <para>If it hasn't improved recently, it's probably not going to improve soon anyway and it's not worth the effort
+ to continue. We have observed that once a new best solution is found (even after a long time of no improvement on
+ the best solution), the next few step tend to improve the best solution too.</para>
+ </section>
+
+ <section>
+ <title>Combining Terminations</title>
+
+ <para>Terminations can be combined, for example: terminate after 100 steps or if a score of 0 has been
+ reached:</para>
+
+ <programlisting> <termination>
+ <terminationCompositionStyle>OR</terminationCompositionStyle>
+ <maximumStepCount>100</maximumStepCount>
+ <scoreAttained>0</scoreAttained>
+ </termination></programlisting>
+
+ <para>Alternatively you can use AND, for example: terminate after reaching a feasible score of at least -100 and
+ no improvements in 5 steps:</para>
+
+ <programlisting> <termination>
+ <terminationCompositionStyle>AND</terminationCompositionStyle>
+ <maximumUnimprovedStepCount>5</maximumUnimprovedStepCount>
+ <scoreAttained>-100</scoreAttained>
+ </termination></programlisting>
+
+ <para>This ensures it doesn't just terminate after finding a feasible solution, but also makes any obvious
+ improvements on that solution before terminating.</para>
+ </section>
+
+ <section>
+ <title>Another thread can ask a Solver to terminate early</title>
+
+ <para>Sometimes you 'll want to terminate a Solver early from another thread, for example because a user action or
+ a server restart. That cannot be configured by a <literal>Termination</literal> as it's impossible to predict when
+ and if it will occur. Therefor the <literal>Solver</literal> interface has these 2 thread-safe methods:</para>
+
+ <programlisting>public interface Solver {
+
+ // ...
+
+ boolean terminateEarly();
+ boolean isTerminatedEarly();
+
+}</programlisting>
+
+ <para>If you call the <literal>terminateEarly()</literal> method from another thread, the
+ <literal>Solver</literal> will terminate at its earliest convenience and the <literal>solve()</literal> method
+ will return in the original solver thread.</para>
+ </section>
+ </section>
+</chapter>
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Chapter-Local_search.xml
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Section-Local_search.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Section-Local_search.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Local_search/Section-Local_search.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -1,771 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
- http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
- version="5.0" xml:base="./">
-
- <title>Local search solver</title>
-
- <section>
- <title>Overview</title>
-
- <para>In number of possible solutions for a planning problem can be mind blowing. For example:</para>
-
- <itemizedlist>
- <listitem>
- <para>4 queens has 256 possible solutions (<literal>n ^ n</literal>) and 2 optimal solutions.</para>
- </listitem>
-
- <listitem>
- <para>5 queens has 3125 possible solutions (<literal>n ^ n</literal>) and 1 optimal solution.</para>
- </listitem>
-
- <listitem>
- <para>8 queens has 16777216 possible solutions (<literal>n ^ n</literal>) and 92 optimal solutions.</para>
- </listitem>
-
- <listitem>
- <para>Most real-life planning problems have an incredible number of possible solutions and only 1 optimal
- solution.</para>
- </listitem>
- </itemizedlist>
-
- <para>An algorithm that checks every possible solution (even with pruning) can easily run for billions of years on a
- single real-life planning problem. Most of the time, we are happy with a feasible solution found in a limited amount
- of time. Local search tends to find a feasible solution relatively fast. Because it acts very much like a human, it
- is also pretty natural to program.</para>
-
- <para>Local search solves a problem by making a move on the current solution which changes it into a better
- solution. It does that number of times till it is satisfied with the solution. It starts with the starting
- solution.</para>
-
- <para>A local search algorithm and the drools rule engine turn out to be a really nice combination, because:</para>
-
- <itemizedlist>
- <listitem>
- <para>A rule engine such as Drools is <emphasis role="bold">great for calculating the score</emphasis> of a
- solution of a planning problem. It make it easy to add additional soft or hard constraints such as "a teacher
- shouldn't teach more then 7 hours a day". However it tends to be too complex to use to actually find new
- solutions.</para>
- </listitem>
-
- <listitem>
- <para>A local search algorithm is <emphasis role="bold">great at finding new improving solutions</emphasis> for
- a planning problem, without brute-forcing every possibility. However it needs to know the score of a solution
- and normally offers no support in calculating that score.</para>
- </listitem>
- </itemizedlist>
-
- <para>Drools Planner's local search implementation combines both. On top of that, it also offers additional support
- for benchmarking etc.</para>
- </section>
-
- <section>
- <title>A move</title>
-
- <para>A move is the change from a solution A to a solution B. For example, below you can see a single move on the
- starting solution of 4 queens that moves a single queen to another row:</para>
-
- <figure>
- <title>A single move (4 queens example)</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Local_search/singleMoveNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>A move can have a small or large impact. In the above example, the move of queen <emphasis>C0 to C2</emphasis>
- is a small move. Some moves are the same move type. These are some possibilities for move types in n queens:</para>
-
- <itemizedlist>
- <listitem>
- <para>Move a single queen to another row. This is a small move. For example, move queen <emphasis>C0 to
- C2</emphasis>.</para>
- </listitem>
-
- <listitem>
- <para>Move all queens a number of rows down or up. This a big move.</para>
- </listitem>
-
- <listitem>
- <para>Move a single queen to another column. This is a small move. For example, move queen <emphasis>C2 to
- A0</emphasis> (placing it on top of queen A0).</para>
- </listitem>
-
- <listitem>
- <para>Add a queen to the board at a certain row and column.</para>
- </listitem>
-
- <listitem>
- <para>Remove a queen from the board.</para>
- </listitem>
- </itemizedlist>
-
- <para>Because we have decided that all queens will be on the board at all times and each queen has an appointed
- column (for performance reasons), only the first 2 move types are usable in our example. Furthermore, we 're only
- using the first move type in the example because we think it gives the best performance, but you are welcome to
- prove us wrong.</para>
-
- <para>Each of your move types will be an implementation of the <literal>Move</literal> interface:</para>
-
- <programlisting>public interface Move {
-
- boolean isMoveDoable(EvaluationHandler evaluationHandler);
-
- Move createUndoMove(EvaluationHandler evaluationHandler);
-
- void doMove(EvaluationHandler evaluationHandler);
-
-}</programlisting>
-
- <para>Let's take a look at the <literal>Move</literal> implementation for 4 queens which moves a queen to a
- different row:</para>
-
- <programlisting>public class YChangeMove implements Move {
-
- private Queen queen;
- private int toY;
-
- public YChangeMove(Queen queen, int toY) {
- this.queen = queen;
- this.toY = toY;
- }
-
- // ... see below
-
-}</programlisting>
-
- <para>An instance of <literal>YChangeMove</literal> moves a queen from it's current y to a different y.</para>
-
- <para>Drools Planner calls the <literal>doMove(WorkingMemory)</literal> method to do a move. The
- <literal>Move</literal> implementation must notify the working memory of any changes it does on the solution
- facts:</para>
-
- <programlisting> public void doMove(WorkingMemory workingMemory) {
- FactHandle queenHandle = workingMemory.getFactHandle(queen);
- workingMemory.modifyRetract(queenHandle); // before changes are made
- queen.setY(toY);
- workingMemory.modifyInsert(queenHandle, queen); // after changes are made
- }</programlisting>
-
- <para>Drools Planner disables shadow facts for increased performance, so you cannot use the
- <literal>workingMemory.update(FactHandle, Object)</literal> method, instead you need to call the
- <literal>workingMemory.modifyRetract(FactHandle)</literal> method before modifying the fact and the
- <literal>workingMemory.modifyInsert(FactHandle, Object)</literal> method after modifying the fact. Note that you can
- alter multiple facts in a single move and effectively create a big move (also known as a coarse-grained
- move).</para>
-
- <para>Drools Planner automatically filters out <emphasis>non doable moves</emphasis> by calling the
- <literal>isDoable(WorkingMemory)</literal> method on a move. A <emphasis>non doable move</emphasis> is:</para>
-
- <itemizedlist>
- <listitem>
- <para>A move that changes nothing on the current solution. For example, moving queen B0 to row 0 is not
- doable.</para>
- </listitem>
-
- <listitem>
- <para>A move that is impossible to do on the current solution. For example, moving queen B0 to row 10 is not
- doable because it would move it outside the board limits.</para>
- </listitem>
- </itemizedlist>
-
- <para>In the n queens example, a move which moves the queen from it's current row to the same row isn't
- doable:</para>
-
- <programlisting> public boolean isMoveDoable(WorkingMemory workingMemory) {
- int fromY = queen.getY();
- return fromY != toY;
- }</programlisting>
-
- <para>Because we won't generate a move which can move a queen outside the board limits, we don't need to check it. A
- move that is currently not doable can become doable on a later solution.</para>
-
- <para>Each move has an <emphasis>undo move</emphasis>: a move (usually of the same type) which does the exact
- opposite. In the above example the undo move of <emphasis>C0 to C2</emphasis> would be the move <emphasis>C2 to
- C0</emphasis>. An undo move can be created from a move, but only before the move has been done on the current
- solution.</para>
-
- <programlisting> public Move createUndoMove(WorkingMemory workingMemory) {
- return new YChangeMove(queen, queen.getY());
- }</programlisting>
-
- <para>Notice that if C0 would have already been moved to C2, the undo move would create the move <emphasis>C2 to
- C2</emphasis>, instead of the move <emphasis>C2 to C0</emphasis>.</para>
-
- <para>The local search solver can do and undo a move more than once, even on different (successive)
- solutions.</para>
-
- <para>A move must implement the <literal>equals()</literal> and <literal>hashcode()</literal> methods. 2 moves which
- make the same change on a solution, must be equal.</para>
-
- <programlisting> public boolean equals(Object o) {
- if (this == o) {
- return true;
- } else if (o instanceof YChangeMove) {
- YChangeMove other = (YChangeMove) o;
- return new EqualsBuilder()
- .append(queen, other.queen)
- .append(toY, other.toY)
- .isEquals();
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return new HashCodeBuilder()
- .append(queen)
- .append(toY)
- .toHashCode();
- }</programlisting>
-
- <para>In the above example, the <literal>Queen</literal> class uses the default <literal>Object</literal>
- <literal>equal()</literal> and <literal>hashcode()</literal> implementations. Notice that it checks if the other
- move is an instance of the same move type. This is important because a move will be compared to a move with another
- move type if you're using more then 1 move type.</para>
-
- <para>It's also recommended to implement the <literal>toString()</literal> method as it allows you to read
- Drools Planner's logging more easily:</para>
-
- <programlisting> public String toString() {
- return queen + " => " + toY;
- }</programlisting>
-
- <para>Now that we can make a single move, let's take a look at generating moves.</para>
- </section>
-
- <section>
- <title>Move generation</title>
-
- <para>At each solution, local search will try all possible moves and pick the best move to change to the next
- solution. It's up to you to generate those moves. Let's take a look at all the possible moves on the starting
- solution of 4 queens:</para>
-
- <figure>
- <title>Possible moves at step 0 (4 queens example)</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Local_search/possibleMovesNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>As you can see, not all the moves are doable. At the starting solution we have 12 doable moves (<literal>n *
- (n - 1)</literal>), one of which will be move which changes the starting solution into the next solution. Notice
- that the number of possible solutions is 256 (<literal>n ^ n</literal>), much more that the amount of doable moves.
- Don't create a move to every possible solution. Instead use moves which can be sequentially combined to reach every
- possible solution.</para>
-
- <para>It's highly recommended that you verify all solutions are connected by your move set. This means that by
- combining a finite number of moves you can reach any solution from any solution. Otherwise you're already excluding
- solutions at the start. Especially if you're using only big moves, you should check it. Just because big moves
- outperform small moves in a short test run, it doesn't mean that they will outperform them in a long test
- run.</para>
-
- <para>You can mix different move types. Usually you're better off preferring small (fine-grained) moves over big
- (course-grained) moves because the score delta calculation will pay off more. However, as the traveling tournament
- example proves, if you can remove a hard constraint by using a certain set of big moves, you can win performance and
- scalability. Try it yourself: run both the simple (small moves) and the smart (big moves) version of the traveling
- tournament example. The smart version evaluates a lot less unfeasible solutions, which enables it to outperform and
- outscale the simple version.</para>
-
- <para>Move generation currently happens with a <literal>MoveFactory</literal>:</para>
-
- <programlisting>public class NQueensMoveFactory extends CachedMoveListMoveFactory {
-
- public List<Move> createMoveList(Solution solution) {
- NQueens nQueens = (NQueens) solution;
- List<Move> moveList = new ArrayList<Move>();
- for (Queen queen : nQueens.getQueenList()) {
- for (int n : nQueens.createNList()) {
- moveList.add(new YChangeMove(queen, n));
- }
- }
- return moveList;
- }
-
-}</programlisting>
-
- <para>But we'll be making move generation part of the drl's soon.</para>
- </section>
-
- <section>
- <title>A step</title>
-
- <para>A step is the winning move. The local search solver tries every move on the current solution and picks the
- best accepted move as the step:</para>
-
- <figure>
- <title>Decide the next step at step 0 (4 queens example)</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Local_search/decideNextStepNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Because the move <emphasis>B0 to B3</emphasis> has the highest score (<literal>-3</literal>), it is picked as
- the next step. Notice that <emphasis>C0 to C3</emphasis> (not shown) could also have been picked because it also has
- the score <literal>-3</literal>. If multiple moves have the same highest score, one is picked randomly, in this case
- <emphasis>B0 to B3</emphasis>.</para>
-
- <para>The step is made and from that new solution, the local search solver tries all the possible moves again, to
- decide the next step after that. It continually does this in a loop, and we get something like this:</para>
-
- <figure>
- <title>All steps (4 queens example)</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Local_search/allStepsNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Notice that the local search solver doesn't use a search tree, but a search path. The search path is
- highlighted by the green arrows. At each step it tries all possible moves, but unless it's the step, it doesn't
- investigate that solution further. This is one of the reasons why local search is very scalable.</para>
-
- <para>As you can see, the local search solver solves the 4 queens problem by starting with the starting solution and
- make the following steps sequentially:</para>
-
- <orderedlist>
- <listitem>
- <para><emphasis>B0 to B3</emphasis></para>
- </listitem>
-
- <listitem>
- <para><emphasis>D0 to B2</emphasis></para>
- </listitem>
-
- <listitem>
- <para><emphasis>A0 to B1</emphasis></para>
- </listitem>
- </orderedlist>
-
- <para>If we turn on INFO logging, this is reflected into the logging:</para>
-
- <programlisting>INFO Solving with random seed (0).
-INFO Initial score (-6) is starting best score. Updating best solution and best score.
-INFO Step (0), time spend (0) doing next step ([Queen-1] 1 @ 0 => 3).
-INFO New score (-3) is better then last best score (-6). Updating best solution and best score.
-INFO Step (1), time spend (0) doing next step ([Queen-3] 3 @ 0 => 2).
-INFO New score (-1) is better then last best score (-3). Updating best solution and best score.
-INFO Step (2), time spend (15) doing next step ([Queen-0] 0 @ 0 => 1).
-INFO New score (0) is better then last best score (-1). Updating best solution and best score.
-INFO Solved in 3 steps and 15 time millis spend.</programlisting>
-
- <para>Notice that the logging used the <literal>toString()</literal> method from our <literal>Move</literal>
- implementation: <literal>[Queen-1] 1 @ 0 => 3</literal>.</para>
-
- <para>The local search solver solves the 4 queens problem in 3 steps, by evaluating only 37 possible solutions (3
- steps with 12 moves each + 1 starting solution), which is only fraction of all 256 possible solutions. It solves 16
- queens in 31 steps, by evaluating only 7441 out of 18446744073709551616 possible solutions.</para>
- </section>
-
- <section>
- <title>Getting stuck in local optima</title>
-
- <para>A <emphasis>simple local search</emphasis> always takes improving moves. This may seem like a good thing, but
- it's not. It suffers from a number of problems:</para>
-
- <itemizedlist>
- <listitem>
- <para>It can get stuck in a local optimum. For example if it reaches a solution X with a score -1 and there is
- no improving move, it is forced to take a next step that leads to a solution Y with score -2, after that
- however, it's very real that it will pick the step back to solution X with score -1. It will then start looping
- between solution X and Y.</para>
- </listitem>
-
- <listitem>
- <para>It can start walking in it's own footsteps, picking the same next step at every step.</para>
- </listitem>
- </itemizedlist>
-
- <para>Of course Drools Planner implements better local searches, such as <emphasis>tabu search</emphasis> and
- <emphasis>simulated annealing</emphasis> which can avoid these problems. It's recommended to never use a simple
- local search, unless you're absolutely sure there are no local optima in your planning problem.</para>
- </section>
-
- <section>
- <title>Deciding the next step</title>
-
- <para>The local search solver decides the next step with the aid of 3 configurable components:</para>
-
- <itemizedlist>
- <listitem>
- <para>A <emphasis>selector</emphasis> which selects (or generates) the possible moves of the current
- solution.</para>
- </listitem>
-
- <listitem>
- <para>An <emphasis>acceptor</emphasis> which filters out unacceptable moves. It can also weigh a move it
- accepts.</para>
- </listitem>
-
- <listitem>
- <para>A <emphasis>forager</emphasis> which gathers all accepted moves and picks the next step from them.</para>
- </listitem>
- </itemizedlist>
-
- <figure>
- <title>Decide the next step at step 0 (4 queens example)</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Local_search/decideNextStepNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>In the above example the selector generated the moves shown with the blue lines, the acceptor accepted all of
- them and the forager picked the move <emphasis>B0 to B3</emphasis>.</para>
-
- <para>If we turn on DEBUG logging, we can see the decision making in the log:</para>
-
- <programlisting>INFO Solving with random seed (0).
-INFO Initial score (-6) is starting best score. Updating best solution and best score.
-DEBUG Move ([Queen-0] 0 @ 0 => 0) ignored because not doable.
-DEBUG Move ([Queen-0] 0 @ 1 => 1) with score (-4) and acceptChance (1.0).
-DEBUG Move ([Queen-0] 0 @ 2 => 2) with score (-4) and acceptChance (1.0).
-...
-DEBUG Move ([Queen-1] 1 @ 3 => 3) with score (-3) and acceptChance (1.0).
-...
-DEBUG Move ([Queen-3] 3 @ 3 => 3) with score (-4) and acceptChance (1.0).
-INFO Step (0), time spend (0) doing next step ([Queen-1] 1 @ 0 => 3).
-INFO New score (-3) is better then last best score (-6). Updating best solution and best score.
-...</programlisting>
-
- <section>
- <title>Selector</title>
-
- <para>A selector is currently based on a <literal>MoveFactory</literal>.</para>
-
- <programlisting> <selector>
- <moveFactoryClass>org.drools.planner.examples.nqueens.solver.NQueensMoveFactory</moveFactoryClass>
- </selector></programlisting>
-
- <para>You're not obligated to generate the same stable set of moves at each step. You could start with generating
- only big moves initially, and gradually switch to small moves. There's no build-in support for this yet
- though.</para>
-
- <para>If there are many possible moves, it can become inefficient to evaluate all of them every step. With
- relativeSelection only a random subset of them is evaluated:</para>
-
- <programlisting> <selector>
- <moveFactoryClass>org.drools.planner.examples.examination.solver.move.factory.RoomChangeMoveFactory</moveFactoryClass>
- <relativeSelection>0.002</relativeSelection>
- </selector></programlisting>
- </section>
-
- <section>
- <title>Acceptor</title>
-
- <para>An acceptor is used (together with a forager) to active tabu search, simulated annealing, great deluge, ...
- For each move it generates an accept chance. If a move is rejected it is given an accept chance of
- <literal>0.0</literal>.</para>
-
- <para>You can implement your own <literal>Acceptor</literal>, although the build-in acceptors should suffice for
- most needs. You can also combine multiple acceptors.</para>
-
- <section>
- <title>Tabu search acceptor</title>
-
- <para>When tabu search takes steps it creates tabu's. It does not accept a move as the next step if that move
- breaks tabu. Drools Planner implements several tabu types:</para>
-
- <itemizedlist>
- <listitem>
- <para><emphasis>Solution tabu</emphasis> makes recently visited solutions tabu. It does not accept a move
- that leads to one of those solutions. If you can spare the memory, don't be cheap on the tabu size. We
- recommend this type of tabu because it tends to give the best results and requires little or no
- tweaking.</para>
-
- <programlisting> <acceptor>
- <completeSolutionTabuSize>1000</completeSolutionTabuSize>
- </acceptor></programlisting>
- </listitem>
-
- <listitem>
- <para><emphasis>Move tabu</emphasis> makes recent steps tabu. It does not accept a move equal to one of
- those steps.</para>
-
- <programlisting> <acceptor>
- <completeMoveTabuSize>1000</completeMoveTabuSize>
- </acceptor></programlisting>
- </listitem>
-
- <listitem>
- <para><emphasis>Undo move tabu </emphasis>makes the undo move of recent steps tabu.</para>
-
- <programlisting> <acceptor>
- <completeUndoMoveTabuSize>1000</completeUndoMoveTabuSize>
- </acceptor></programlisting>
- </listitem>
-
- <listitem>
- <para><emphasis>Property tabu</emphasis> makes a property of recent steps tabu. For example, it can make the
- queen tabu, so that a recently moved queen can't be moved.</para>
-
- <programlisting> <acceptor>
- <completePropertyTabuSize>1000</completePropertyTabuSize>
- </acceptor></programlisting>
-
- <para>To use property tabu, your moves must implement the <literal>TabuPropertyEnabled</literal> interface,
- for example:</para>
-
- <programlisting>public class YChangeMove implements Move, TabuPropertyEnabled {
-
- private Queen queen;
- private int toY;
-
- // ...
-
- public List<? extends Object> getTabuPropertyList() {
- return Collections.singletonList(queen);
- }
-
-}</programlisting>
- </listitem>
- </itemizedlist>
-
- <para>You can even combine tabu types:</para>
-
- <programlisting> <acceptor>
- <completeSolutionTabuSize>1000</completeSolutionTabuSize>
- <completeUndoMoveTabuSize>10</completeUndoMoveTabuSize>
- </acceptor></programlisting>
-
- <para>If you pick a too small tabu size, your solver can still get stuck in a local optimum. On the other hand,
- with the exception of solution tabu, if you pick a too large tabu size, your solver can get stuck by bouncing of
- the walls. Use the benchmarker to fine tweak your configuration.</para>
-
- <para>A tabu search acceptor should be combined with a <emphasis>maximum score of all</emphasis> or
- <emphasis>first best score improving</emphasis> forager.</para>
- </section>
-
- <section>
- <title>Simulated annealing acceptor</title>
-
- <para>Simulated annealing does not pick the move with the highest score, neither does it evaluate all moves. At
- least at first.</para>
-
- <para>It gives unimproving moves a chance, depending on it's score and the temperature. The
- <emphasis>temperature</emphasis> is relative to how long it has been solving. In the end, it gradually turns
- into a simple local search, only accepting improving moves.</para>
-
- <para>A simulated annealing acceptor should be combined with a <emphasis>first randomly accepted</emphasis>
- forager.</para>
- </section>
- </section>
-
- <section>
- <title>Forager</title>
-
- <para>A forager gathers all accepted moves and picks the move which is the next step. A forager can choose to
- allow only a subset of all selected moves to be evaluated, by quitting early if a suitable move has been
- accepted.</para>
-
- <para>You can implement your own <literal>Forager</literal>, although the build-in foragers should suffice for
- most needs.</para>
-
- <section>
- <title>Maximum score of all forager</title>
-
- <para>Allows all selected moves to be evaluated and picks the accepted move with the highest score. If several
- accepted moves have the highest score, one is picked randomly, weighted on their accept chance.</para>
-
- <programlisting> <forager>
- <foragerType>MAX_SCORE_OF_ALL</foragerType>
- </forager></programlisting>
- </section>
-
- <section>
- <title>First best score improving forager</title>
-
- <para>Picks the first accepted move that improves the best score. If none improve the best score, it behaves
- exactly like the maximum score of all forager.</para>
-
- <programlisting> <forager>
- <foragerType>FIRST_BEST_SCORE_IMPROVING</foragerType>
- </forager></programlisting>
- </section>
-
- <section>
- <title>First last step score improving forager</title>
-
- <para>Picks the first accepted move that improves the last step score. If none improve the last step score, it
- behaves exactly like the maximum score of all forager.</para>
-
- <programlisting> <forager>
- <foragerType>FIRST_BEST_SCORE_IMPROVING</foragerType>
- </forager></programlisting>
- </section>
-
- <section>
- <title>First randomly accepted forager</title>
-
- <para>Generates a random number for each accepted move and if the move's accept chance is higher, it picks that
- move as the next move.</para>
-
- <programlisting> <forager>
- <foragerType>FIRST_RANDOMLY_ACCEPTED</foragerType>
- </forager></programlisting>
- </section>
- </section>
- </section>
-
- <section>
- <title>Best solution</title>
-
- <para>Because the current solution can degrade (especially in tabu search and simulated annealing), the local search
- solver remembers the best solution it has encountered through the entire search path. Each time the current solution
- is better than the last best solution, the current solution is cloned and referenced as the new best
- solution.</para>
-
- <para>You can listen to solver events, including when the best solution changes during solving, by adding a
- <literal>SolverEventListener</literal> to the <literal>Solver</literal>:</para>
-
- <programlisting>public interface Solver {
-
- // ...
-
- void addEventListener(SolverEventListener eventListener);
- void removeEventListener(SolverEventListener eventListener);
-
-}</programlisting>
- </section>
-
- <section>
- <title>Termination</title>
-
- <para>Sooner or later the local search solver will have to stop solving. This can be because of a number of reasons:
- the time is up, the perfect score has been reached, ... The only thing you can't depend on is on finding the optimal
- solution (unless you know the optimal score), because a local search solver doesn't know that when it finds the
- optimal solution. For real-life problems this doesn't turn out to be much of a problem, because finding the optimal
- solution would take years, so you 'll want to terminate sooner anyway.</para>
-
- <para>You can configure when a local search solver needs to stop by configuring a Termination. You can implement
- your own <literal>Termination</literal>, although the build-in Terminations should suffice for most needs.</para>
-
- <section>
- <title>TimeMillisSpendTermination</title>
-
- <para>Terminates when an amount of time has been reached:</para>
-
- <programlisting> <termination>
- <maximumMinutesSpend>2</maximumMinutesSpend>
- </termination></programlisting>
-
- <para>or</para>
-
- <programlisting> <termination>
- <maximumHoursSpend>1</maximumHoursSpend>
- </termination></programlisting>
-
- <para>Note that the time taken by a <literal>StartingSolutionInitializer</literal> also is taken into account by
- this Termination. So if you give the solver 2 minutes to solve something, but the initializer takes 1 minute, the
- local search solver will only have a minute left.</para>
-
- <para>Note that if you use this Termination, you will most likely sacrifice reproducability. The best solution
- will depend on available CPU time, not only because it influences the amount of steps taken, but also because time
- gradient based algorithms (such as simulated annealing) will probably act differently on each run.</para>
- </section>
-
- <section>
- <title>StepCountTermination</title>
-
- <para>Terminates when an amount of steps has been reached:</para>
-
- <programlisting> <termination>
- <maximumStepCount>100</maximumStepCount>
- </termination></programlisting>
- </section>
-
- <section>
- <title>ScoreAttainedTermination</title>
-
- <para>Terminates when a certain score has been reached. You can use this Termination if you know the perfect
- score, for example for 4 queens:</para>
-
- <programlisting> <termination>
- <scoreAttained>0</scoreAttained>
- </termination></programlisting>
-
- <para>You can also use this Termination to terminate once it reaches a feasible solution. For a solver problem
- with hard and soft contraints, it could look like this:</para>
-
- <programlisting> <termination>
- <scoreAttained>0hard/-5000soft</scoreAttained>
- </termination></programlisting>
- </section>
-
- <section>
- <title>UnimprovedStepCountTermination</title>
-
- <para>Terminates when the best score hasn't improved in a number of steps:</para>
-
- <programlisting> <termination>
- <maximumUnimprovedStepCount>100</maximumUnimprovedStepCount>
- </termination></programlisting>
-
- <para>If it hasn't improved recently, it's probably not going to improve soon anyway and it's not worth the effort
- to continue. We have observed that once a new best solution is found (even after a long time of no improvement on
- the best solution), the next few step tend to improve the best solution too.</para>
- </section>
-
- <section>
- <title>Combining Terminations</title>
-
- <para>Terminations can be combined, for example: terminate after 100 steps or if a score of 0 has been
- reached:</para>
-
- <programlisting> <termination>
- <terminationCompositionStyle>OR</terminationCompositionStyle>
- <maximumStepCount>100</maximumStepCount>
- <scoreAttained>0</scoreAttained>
- </termination></programlisting>
-
- <para>Alternatively you can use AND, for example: terminate after reaching a feasible score of at least -100 and
- no improvements in 5 steps:</para>
-
- <programlisting> <termination>
- <terminationCompositionStyle>AND</terminationCompositionStyle>
- <maximumUnimprovedStepCount>5</maximumUnimprovedStepCount>
- <scoreAttained>-100</scoreAttained>
- </termination></programlisting>
-
- <para>This ensures it doesn't just terminate after finding a feasible solution, but also makes any obvious
- improvements on that solution before terminating.</para>
- </section>
-
- <section>
- <title>Another thread can ask a Solver to terminate early</title>
-
- <para>Sometimes you 'll want to terminate a Solver early from another thread, for example because a user action or
- a server restart. That cannot be configured by a <literal>Termination</literal> as it's impossible to predict when
- and if it will occur. Therefor the <literal>Solver</literal> interface has these 2 thread-safe methods:</para>
-
- <programlisting>public interface Solver {
-
- // ...
-
- boolean terminateEarly();
- boolean isTerminatedEarly();
-
-}</programlisting>
-
- <para>If you call the <literal>terminateEarly()</literal> method from another thread, the
- <literal>Solver</literal> will terminate at its earliest convenience and the <literal>solve()</literal> method
- will return in the original solver thread.</para>
- </section>
- </section>
-</chapter>
Copied: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Chapter-Planner_configuration.xml (from rev 30822, labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Section-Planner_configuration.xml)
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Chapter-Planner_configuration.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Chapter-Planner_configuration.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -0,0 +1,514 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
+ http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
+ version="5.0" xml:base="./">
+
+ <title>Planner configuration</title>
+
+ <section>
+ <title>Types of solvers</title>
+
+ <para>Different solvers solve problems in different ways. Each type has advantages and disadvantages. We 'll roughly
+ discuss a few of the solver types here. You can safely skip this section.</para>
+
+ <section>
+ <title>Brute force</title>
+
+ <para>Brute force creates and evaluates every possible solution, usually by creating a search tree.</para>
+
+ <para>Advantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It knows when it has found an optimal solution. If there is more then 1 optimal solution, it finds all
+ optimal solutions.</para>
+ </listitem>
+
+ <listitem>
+ <para>It is straightforward and simple to implement.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Disadvantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It performs and scales horribly. Mostly unusable for a real-world problem due to time
+ limitations.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Brute force is currently not implemented in Drools Planner. But we have plans to implement it in the future,
+ as a reference for validating the output of the other solver types.</para>
+ </section>
+
+ <section>
+ <title>Branch and bound</title>
+
+ <para>Branch and bound is an improvement over brute force, as it prunes away subsets of solutions which cannot
+ have a better solution than the best solution already found at that point.</para>
+
+ <para>Advantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It knows when it has found an optimal solution. If there is more then 1 optimal solution, it can find
+ all optimal solutions if needed.</para>
+ </listitem>
+
+ <listitem>
+ <para>It can determine the bounds of a problem, which gives an indication of the quality of a solution.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Disadvantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It still scales very badly. Mostly unusable for a real-world problem due to time limitations.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Branch and bound is currently not implemented in Drools Planner. But we have plans to implement it in the
+ future, as a reference for validating the output of the other solver types.</para>
+ </section>
+
+ <section>
+ <title>Simplex</title>
+
+ <para>Simplex is an algorithm to find the numerical solution of a linear programming problem.</para>
+
+ <para>Advantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It knows when it has found an optimal solution.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Disadvantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It's complex and mathematical to implement constraints.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Drools Planner does not implement simplex.</para>
+ </section>
+
+ <section>
+ <title>Genetic algorithms</title>
+
+ <para>Advantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It's scalable</para>
+ </listitem>
+
+ <listitem>
+ <para>Given a limited time, it can still deliver a pretty decent solution.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Disadvantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It does not know when it has found an optimal solution.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the optimal score is unknown (which is usually the case), it must be told when to stop looking (for
+ example based on time spend, user input, ...).</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The genetic algorithm is currently not implemented in Drools Planner.</para>
+ </section>
+
+ <section>
+ <title>Local search (tabu search, simulated annealing, ...)</title>
+
+ <para>Local search starts from an initial solution and evolves that single solution into a mostly better and
+ better solution. It uses a single search path of solutions, not a search tree. At each solution in this path it
+ evaluates a number of moves on the solution and applies the most suitable move to take the step to the next
+ solution.</para>
+
+ <para>Local search works a lot like a human planner: it uses a single search path and moves facts around to find a
+ good feasible solution.</para>
+
+ <para>A simple local search can easily get stuck in a local optima, but improvements (such as tabu search and
+ simulated annealing) address this problem.</para>
+
+ <para>Advantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It's relatively simple and natural to implement constraints (at least in Drools Planner's
+ implementation).</para>
+ </listitem>
+
+ <listitem>
+ <para>It's very scalable, even when adding extra constraints (at least in Drools Planner's
+ implementation).</para>
+ </listitem>
+
+ <listitem>
+ <para>Given a limited time, it can still deliver a pretty decent solution.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Disadvantages:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It does not know when it has found an optimal solution.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the optimal score is unknown (which is usually the case), it must be told when to stop looking (for
+ example based on time spend, user input, ...).</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Drools Planner implements local search, including tabu search and simulated annealing.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>The size of real world problems</title>
+
+ <para>As a planning problem gets bigger, the search space tends to blow up really fast. It's not uncommon to see
+ that it's possible to optimally plan 5 people in less then a second, while planning 6 people optimally would take
+ years. Take a look at the problem size of the examples: many instances have a lot more possible solutions than there
+ are supposedly atoms in the known universe (10^80).</para>
+
+ <para>Planning competitions (such as the International Timetabling Competition) show that local search variations
+ (tabu search, simulated annealing, ...) usually perform best for real-world problems given real-world time
+ limitations.</para>
+ </section>
+
+ <section>
+ <title>The Solver interface</title>
+
+ <para>Every build-in solver implemented in Drools Planner implements the <literal>Solver</literal> interface:</para>
+
+ <programlisting>public interface Solver {
+
+ void setStartingSolution(Solution solution);
+
+ Solution getBestSolution();
+
+ void solve();
+
+ // ...
+
+}</programlisting>
+
+ <para>Solving a planning problem with Drools Planner consists out of 4 steps:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Build a solver, for example a tabu search solver for any NQueens puzzle.</para>
+ </listitem>
+
+ <listitem>
+ <para>Set a starting solution on the solver, for example a 4 Queens puzzle instance.</para>
+ </listitem>
+
+ <listitem>
+ <para>Solve it.</para>
+ </listitem>
+
+ <listitem>
+ <para>Get the best solution found by the solver.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>A <literal>Solver</literal> should only be accessed from a single thread, except for the methods that are
+ specifically javadocced as thread-safe.</para>
+ </section>
+
+ <section>
+ <title>Building a solver</title>
+
+ <para>You can build a <literal>Solver</literal> instance with the <literal>XmlSolverConfigurer</literal>. Configure
+ it with a solver configuration xml file:</para>
+
+ <programlisting> XmlSolverConfigurer configurer = new XmlSolverConfigurer();
+ configurer.configure("/org/drools/planner/examples/nqueens/solver/nqueensSolverConfig.xml");
+ Solver solver = configurer.buildSolver();</programlisting>
+
+ <para>A basic solver configuration file looks something like this:</para>
+
+ <programlisting><?xml version="1.0" encoding="UTF-8"?>
+<localSearchSolver>
+ <scoreDrl>/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl>
+ <scoreDefinition>
+ <scoreDefinitionType>SIMPLE</scoreDefinitionType>
+ </scoreDefinition>
+ <termination>
+ <scoreAttained>0</scoreAttained>
+ </termination>
+ <selector>
+ <moveFactoryClass>org.drools.planner.examples.nqueens.solver.NQueensMoveFactory</moveFactoryClass>
+ </selector>
+ <acceptor>
+ <completeSolutionTabuSize>1000</completeSolutionTabuSize>
+ </acceptor>
+ <forager>
+ <foragerType>MAX_SCORE_OF_ALL</foragerType>
+ </forager>
+</localSearchSolver></programlisting>
+
+ <para>This is a tabu search configuration for n queens. We 'll explain the various parts of a configuration later in
+ this manual.</para>
+
+ <para><emphasis role="bold">Drools Planner makes it relatively easy to switch a solver type just by changing the
+ configuration.</emphasis> There's even a benchmark utility which allows you to play out different configurations
+ against each other and report the most appropriate configuration for your problem. You could for example play out
+ tabu search versus simulated annealing, on 4 queens and 64 queens.</para>
+
+ <para>A solver has a single <literal>Random</literal> instance. Some solver configurations use that instance a lot
+ more than others. For example simulated annealing depends highly on random numbers, while tabu search only depends
+ on it to deal with score ties. In any case, during your testing it's advisable to set that <literal>Random</literal>
+ instance, so your tests are reproducible.</para>
+ </section>
+
+ <section>
+ <title>The Solution interface</title>
+
+ <para>A Solver can only solve 1 problem at a time.</para>
+
+ <para>You need to present the problem as a starting <literal>Solution</literal> instance to the solver.</para>
+
+ <para>You need to implement the <literal>Solution</literal> interface:</para>
+
+ <programlisting>public interface Solution {
+
+ Score getScore();
+ void setScore(Score score);
+
+ Collection<? extends Object> getFacts();
+
+ Solution cloneSolution();
+
+}</programlisting>
+
+ <para>For example, an NQueens instance just holds a list of all it's queens:</para>
+
+ <programlisting>public class NQueens implements Solution {
+
+ private List<Queen> queenList;
+
+ // ...
+
+}</programlisting>
+
+ <section>
+ <title>The getScore and setScore methods</title>
+
+ <para>A <literal>Solution</literal> requires a score property. The score property is null if the
+ <literal>Solution</literal> is unitialized or if the score has not yet been (re)calculated.The score property is
+ ussually typed to the specific <literal>Score</literal> implementation you use. For example, NQueens uses a
+ <literal>SimpleScore</literal>:</para>
+
+ <programlisting> private SimpleScore score;
+
+ public SimpleScore getScore() {
+ return score;
+ }
+
+ public void setScore(Score score) {
+ this.score = (SimpleScore) score;
+ }</programlisting>
+ </section>
+
+ <section>
+ <title>The getFacts method</title>
+
+ <para>All Objects returned by the <literal>getFacts()</literal> method will be asserted into the drools working
+ memory. Those facts can be used by the score rules. For example, <literal>NQueens</literal> just returns all
+ <literal>Queen</literal> instances.</para>
+
+ <programlisting> public Collection<? extends Object> getFacts() {
+ return queenList;
+ }</programlisting>
+ </section>
+
+ <section>
+ <title>The cloneSolution method</title>
+
+ <para>Most solvers use the <literal>cloneSolution()</literal> method to clone the solution each time they
+ encounter a new best solution. The <literal>NQueens</literal> implementation just clones all
+ <literal>Queen</literal> instances:</para>
+
+ <programlisting> public NQueens cloneSolution() {
+ NQueens clone = new NQueens();
+ List<Queen> clonedQueenList = new ArrayList<Queen>(queenList.size());
+ for (Queen queen : queenList) {
+ clonedQueenList.add(queen.clone());
+ }
+ clone.queenList = clonedQueenList;
+ clone.score = score;
+ return clone;
+ }</programlisting>
+
+ <para>The <literal>cloneSolution()</literal> method should clone no more and no less than the parts of the
+ <literal>Solution</literal> that can change during solving. For example, in the lesson schedule example the
+ lessons are cloned, but teachers, groups and timeslots are not cloned because only a lesson's appointed timeslot
+ changes during solving:</para>
+
+ <programlisting> /**
+ * Clone will only deep copy the lessons
+ */
+ public LessonSchedule cloneSolution() {
+ LessonSchedule clone = new LessonSchedule();
+ clone.timeslotList = timeslotList; // No Deep copy
+ clone.teacherList = teacherList; // No Deep copy
+ clone.groupList = groupList; // No Deep copy
+ List<Lesson> clonedLessonList = new ArrayList<Lesson>(lessonList.size());
+ for (Lesson lesson : lessonList) {
+ clonedLessonList.add(lesson.clone());
+ }
+ clone.lessonList = clonedLessonList;
+ clone.score = score;
+ return clone;
+ }</programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>The starting solution</title>
+
+ <para>First, you will need to make a starting solution and set that on the solver:</para>
+
+ <programlisting>solver.setStartingSolution(startingSolution);</programlisting>
+ </section>
+
+ <section>
+ <title>A simple filler algorithm</title>
+
+ <para>For 4 queens we use a simple filler algorithm that creates a starting solution with all queens on a different
+ x and on the same y (with y = 0).</para>
+
+ <figure>
+ <title>Starting solution for the 4 queens puzzle</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Planner_configuration/unsolvedNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Here's how we generate it:</para>
+
+ <programlisting> private NQueens createNQueens(int n) {
+ NQueens nQueens = new NQueens();
+ nQueens.setId(0L);
+ List<Queen> queenList = new ArrayList<Queen>(n);
+ for (int i = 0; i < n; i++) {
+ Queen queen = new Queen();
+ queen.setId((long) i);
+ queen.setX(i); // Different column
+ queen.setY(0); // Same row
+ queenList.add(queen);
+ }
+ nQueens.setQueenList(queenList);
+ return nQueens;
+ }</programlisting>
+
+ <para>The starting solution will probably be far from optimal (or even feasible). Here, it's actually the worst
+ possible solution. However, we 'll let the solver find a much better solution for us anyway.</para>
+
+ <section>
+ <title>StartingSolutionInitializer</title>
+
+ <para>For large problems, a simple filler algorithm like <literal>createNQueens(int)</literal> doesn't suffice. A
+ (local search) solver starting from a bad starting solution wastes a lot of time to reach a solution which an
+ initializer algorithm can generate in a fraction of that time.</para>
+
+ <para>An initializer algorithm ussually works something like this:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>It sorts the unplanned elements in a queue according to some general rules, for example by exam student
+ size.</para>
+ </listitem>
+
+ <listitem>
+ <para>Next, it plans them in the order they come from the queue. Each element is put the best, still available
+ spot.</para>
+ </listitem>
+
+ <listitem>
+ <para>It doesn't change an already planned element. It exits when the queue is empty and all elements are
+ planned.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Such an algorithm is very deterministic: it's really fast, but you can't give it more time to generate an
+ even better solution. In some cases the solution it generates will be feasible, but in most cases it won't. You
+ 'll need a real solver to get to a feasible or more optimal solution. Nevertheless you 'll want to such an
+ initializer to give the real solver a serious head start. You can do this by implementing the
+ <literal>StartingSolutionInitializer</literal> interface:</para>
+
+ <programlisting>public interface StartingSolutionInitializer extends SolverAware {
+
+ boolean isSolutionInitialized(Solution solution);
+
+ void initializeSolution(Solution solution);
+
+}</programlisting>
+
+ <para>You'll need to set a (uninitialized) solution on the solver. Once the solver starts, it will first call the
+ <literal>StartingSolutionInitializer</literal> to initialize the solution. If the
+ <literal>StartingSolutionInitializer</literal> adds, edits or removes facts it needs to notify the workingMemory
+ about this. It can use score calculation during its initialization process.</para>
+
+ <para>Here's an example on how you add the <literal>StartingSolutionInitializer</literal> to the
+ configuration:</para>
+
+ <programlisting><localSearchSolver>
+ ...
+ <startingSolutionInitializerClass>org.drools.planner.examples.examination.solver.solution.initializer.ExaminationStartingSolutionInitializer</startingSolutionInitializerClass>
+ ...
+</localSearchSolver></programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Solving a problem</title>
+
+ <para>Solving a problem is quite easy once you have a solver and the starting solution:</para>
+
+ <programlisting> solver.setStartingSolution(startingSolution);
+ solver.solve();
+ Solution bestSolution = solver.getBestSolution();</programlisting>
+
+ <para>The <literal>solve()</literal> method will take a long time (depending on the problem size and the solver
+ configuration). The solver will remember (actually clone) the best solution it encounters during its solving.
+ Depending on a number factors (including problem size, how long you allow the solver to work, which solver type you
+ use, ...), that best solution will be a feasible or even an optimal solution.</para>
+
+ <figure>
+ <title>Best solution for the 4 queens puzzle (also an optimal solution)</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Planner_configuration/solvedNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>After a problem is solved, you can reuse the same solver instance to solve another problem (of the same
+ problem type).</para>
+ </section>
+</chapter>
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Chapter-Planner_configuration.xml
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Section-Planner_configuration.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Section-Planner_configuration.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_configuration/Section-Planner_configuration.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -1,514 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
- http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
- version="5.0" xml:base="./">
-
- <title>Planner configuration</title>
-
- <section>
- <title>Types of solvers</title>
-
- <para>Different solvers solve problems in different ways. Each type has advantages and disadvantages. We 'll roughly
- discuss a few of the solver types here. You can safely skip this section.</para>
-
- <section>
- <title>Brute force</title>
-
- <para>Brute force creates and evaluates every possible solution, usually by creating a search tree.</para>
-
- <para>Advantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It knows when it has found an optimal solution. If there is more then 1 optimal solution, it finds all
- optimal solutions.</para>
- </listitem>
-
- <listitem>
- <para>It is straightforward and simple to implement.</para>
- </listitem>
- </itemizedlist>
-
- <para>Disadvantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It performs and scales horribly. Mostly unusable for a real-world problem due to time
- limitations.</para>
- </listitem>
- </itemizedlist>
-
- <para>Brute force is currently not implemented in Drools Planner. But we have plans to implement it in the future,
- as a reference for validating the output of the other solver types.</para>
- </section>
-
- <section>
- <title>Branch and bound</title>
-
- <para>Branch and bound is an improvement over brute force, as it prunes away subsets of solutions which cannot
- have a better solution than the best solution already found at that point.</para>
-
- <para>Advantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It knows when it has found an optimal solution. If there is more then 1 optimal solution, it can find
- all optimal solutions if needed.</para>
- </listitem>
-
- <listitem>
- <para>It can determine the bounds of a problem, which gives an indication of the quality of a solution.</para>
- </listitem>
- </itemizedlist>
-
- <para>Disadvantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It still scales very badly. Mostly unusable for a real-world problem due to time limitations.</para>
- </listitem>
- </itemizedlist>
-
- <para>Branch and bound is currently not implemented in Drools Planner. But we have plans to implement it in the
- future, as a reference for validating the output of the other solver types.</para>
- </section>
-
- <section>
- <title>Simplex</title>
-
- <para>Simplex is an algorithm to find the numerical solution of a linear programming problem.</para>
-
- <para>Advantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It knows when it has found an optimal solution.</para>
- </listitem>
- </itemizedlist>
-
- <para>Disadvantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It's complex and mathematical to implement constraints.</para>
- </listitem>
- </itemizedlist>
-
- <para>Drools Planner does not implement simplex.</para>
- </section>
-
- <section>
- <title>Genetic algorithms</title>
-
- <para>Advantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It's scalable</para>
- </listitem>
-
- <listitem>
- <para>Given a limited time, it can still deliver a pretty decent solution.</para>
- </listitem>
- </itemizedlist>
-
- <para>Disadvantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It does not know when it has found an optimal solution.</para>
- </listitem>
-
- <listitem>
- <para>If the optimal score is unknown (which is usually the case), it must be told when to stop looking (for
- example based on time spend, user input, ...).</para>
- </listitem>
- </itemizedlist>
-
- <para>The genetic algorithm is currently not implemented in Drools Planner.</para>
- </section>
-
- <section>
- <title>Local search (tabu search, simulated annealing, ...)</title>
-
- <para>Local search starts from an initial solution and evolves that single solution into a mostly better and
- better solution. It uses a single search path of solutions, not a search tree. At each solution in this path it
- evaluates a number of moves on the solution and applies the most suitable move to take the step to the next
- solution.</para>
-
- <para>Local search works a lot like a human planner: it uses a single search path and moves facts around to find a
- good feasible solution.</para>
-
- <para>A simple local search can easily get stuck in a local optima, but improvements (such as tabu search and
- simulated annealing) address this problem.</para>
-
- <para>Advantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It's relatively simple and natural to implement constraints (at least in Drools Planner's
- implementation).</para>
- </listitem>
-
- <listitem>
- <para>It's very scalable, even when adding extra constraints (at least in Drools Planner's
- implementation).</para>
- </listitem>
-
- <listitem>
- <para>Given a limited time, it can still deliver a pretty decent solution.</para>
- </listitem>
- </itemizedlist>
-
- <para>Disadvantages:</para>
-
- <itemizedlist>
- <listitem>
- <para>It does not know when it has found an optimal solution.</para>
- </listitem>
-
- <listitem>
- <para>If the optimal score is unknown (which is usually the case), it must be told when to stop looking (for
- example based on time spend, user input, ...).</para>
- </listitem>
- </itemizedlist>
-
- <para>Drools Planner implements local search, including tabu search and simulated annealing.</para>
- </section>
- </section>
-
- <section>
- <title>The size of real world problems</title>
-
- <para>As a planning problem gets bigger, the search space tends to blow up really fast. It's not uncommon to see
- that it's possible to optimally plan 5 people in less then a second, while planning 6 people optimally would take
- years. Take a look at the problem size of the examples: many instances have a lot more possible solutions than there
- are supposedly atoms in the known universe (10^80).</para>
-
- <para>Planning competitions (such as the International Timetabling Competition) show that local search variations
- (tabu search, simulated annealing, ...) usually perform best for real-world problems given real-world time
- limitations.</para>
- </section>
-
- <section>
- <title>The Solver interface</title>
-
- <para>Every build-in solver implemented in Drools Planner implements the <literal>Solver</literal> interface:</para>
-
- <programlisting>public interface Solver {
-
- void setStartingSolution(Solution solution);
-
- Solution getBestSolution();
-
- void solve();
-
- // ...
-
-}</programlisting>
-
- <para>Solving a planning problem with Drools Planner consists out of 4 steps:</para>
-
- <orderedlist>
- <listitem>
- <para>Build a solver, for example a tabu search solver for any NQueens puzzle.</para>
- </listitem>
-
- <listitem>
- <para>Set a starting solution on the solver, for example a 4 Queens puzzle instance.</para>
- </listitem>
-
- <listitem>
- <para>Solve it.</para>
- </listitem>
-
- <listitem>
- <para>Get the best solution found by the solver.</para>
- </listitem>
- </orderedlist>
-
- <para>A <literal>Solver</literal> should only be accessed from a single thread, except for the methods that are
- specifically javadocced as thread-safe.</para>
- </section>
-
- <section>
- <title>Building a solver</title>
-
- <para>You can build a <literal>Solver</literal> instance with the <literal>XmlSolverConfigurer</literal>. Configure
- it with a solver configuration xml file:</para>
-
- <programlisting> XmlSolverConfigurer configurer = new XmlSolverConfigurer();
- configurer.configure("/org/drools/planner/examples/nqueens/solver/nqueensSolverConfig.xml");
- Solver solver = configurer.buildSolver();</programlisting>
-
- <para>A basic solver configuration file looks something like this:</para>
-
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
-<localSearchSolver>
- <scoreDrl>/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl>
- <scoreDefinition>
- <scoreDefinitionType>SIMPLE</scoreDefinitionType>
- </scoreDefinition>
- <termination>
- <scoreAttained>0</scoreAttained>
- </termination>
- <selector>
- <moveFactoryClass>org.drools.planner.examples.nqueens.solver.NQueensMoveFactory</moveFactoryClass>
- </selector>
- <acceptor>
- <completeSolutionTabuSize>1000</completeSolutionTabuSize>
- </acceptor>
- <forager>
- <foragerType>MAX_SCORE_OF_ALL</foragerType>
- </forager>
-</localSearchSolver></programlisting>
-
- <para>This is a tabu search configuration for n queens. We 'll explain the various parts of a configuration later in
- this manual.</para>
-
- <para><emphasis role="bold">Drools Planner makes it relatively easy to switch a solver type just by changing the
- configuration.</emphasis> There's even a benchmark utility which allows you to play out different configurations
- against each other and report the most appropriate configuration for your problem. You could for example play out
- tabu search versus simulated annealing, on 4 queens and 64 queens.</para>
-
- <para>A solver has a single <literal>Random</literal> instance. Some solver configurations use that instance a lot
- more than others. For example simulated annealing depends highly on random numbers, while tabu search only depends
- on it to deal with score ties. In any case, during your testing it's advisable to set that <literal>Random</literal>
- instance, so your tests are reproducible.</para>
- </section>
-
- <section>
- <title>The Solution interface</title>
-
- <para>A Solver can only solve 1 problem at a time.</para>
-
- <para>You need to present the problem as a starting <literal>Solution</literal> instance to the solver.</para>
-
- <para>You need to implement the <literal>Solution</literal> interface:</para>
-
- <programlisting>public interface Solution {
-
- Score getScore();
- void setScore(Score score);
-
- Collection<? extends Object> getFacts();
-
- Solution cloneSolution();
-
-}</programlisting>
-
- <para>For example, an NQueens instance just holds a list of all it's queens:</para>
-
- <programlisting>public class NQueens implements Solution {
-
- private List<Queen> queenList;
-
- // ...
-
-}</programlisting>
-
- <section>
- <title>The getScore and setScore methods</title>
-
- <para>A <literal>Solution</literal> requires a score property. The score property is null if the
- <literal>Solution</literal> is unitialized or if the score has not yet been (re)calculated.The score property is
- ussually typed to the specific <literal>Score</literal> implementation you use. For example, NQueens uses a
- <literal>SimpleScore</literal>:</para>
-
- <programlisting> private SimpleScore score;
-
- public SimpleScore getScore() {
- return score;
- }
-
- public void setScore(Score score) {
- this.score = (SimpleScore) score;
- }</programlisting>
- </section>
-
- <section>
- <title>The getFacts method</title>
-
- <para>All Objects returned by the <literal>getFacts()</literal> method will be asserted into the drools working
- memory. Those facts can be used by the score rules. For example, <literal>NQueens</literal> just returns all
- <literal>Queen</literal> instances.</para>
-
- <programlisting> public Collection<? extends Object> getFacts() {
- return queenList;
- }</programlisting>
- </section>
-
- <section>
- <title>The cloneSolution method</title>
-
- <para>Most solvers use the <literal>cloneSolution()</literal> method to clone the solution each time they
- encounter a new best solution. The <literal>NQueens</literal> implementation just clones all
- <literal>Queen</literal> instances:</para>
-
- <programlisting> public NQueens cloneSolution() {
- NQueens clone = new NQueens();
- List<Queen> clonedQueenList = new ArrayList<Queen>(queenList.size());
- for (Queen queen : queenList) {
- clonedQueenList.add(queen.clone());
- }
- clone.queenList = clonedQueenList;
- clone.score = score;
- return clone;
- }</programlisting>
-
- <para>The <literal>cloneSolution()</literal> method should clone no more and no less than the parts of the
- <literal>Solution</literal> that can change during solving. For example, in the lesson schedule example the
- lessons are cloned, but teachers, groups and timeslots are not cloned because only a lesson's appointed timeslot
- changes during solving:</para>
-
- <programlisting> /**
- * Clone will only deep copy the lessons
- */
- public LessonSchedule cloneSolution() {
- LessonSchedule clone = new LessonSchedule();
- clone.timeslotList = timeslotList; // No Deep copy
- clone.teacherList = teacherList; // No Deep copy
- clone.groupList = groupList; // No Deep copy
- List<Lesson> clonedLessonList = new ArrayList<Lesson>(lessonList.size());
- for (Lesson lesson : lessonList) {
- clonedLessonList.add(lesson.clone());
- }
- clone.lessonList = clonedLessonList;
- clone.score = score;
- return clone;
- }</programlisting>
- </section>
- </section>
-
- <section>
- <title>The starting solution</title>
-
- <para>First, you will need to make a starting solution and set that on the solver:</para>
-
- <programlisting>solver.setStartingSolution(startingSolution);</programlisting>
- </section>
-
- <section>
- <title>A simple filler algorithm</title>
-
- <para>For 4 queens we use a simple filler algorithm that creates a starting solution with all queens on a different
- x and on the same y (with y = 0).</para>
-
- <figure>
- <title>Starting solution for the 4 queens puzzle</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Planner_configuration/unsolvedNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Here's how we generate it:</para>
-
- <programlisting> private NQueens createNQueens(int n) {
- NQueens nQueens = new NQueens();
- nQueens.setId(0L);
- List<Queen> queenList = new ArrayList<Queen>(n);
- for (int i = 0; i < n; i++) {
- Queen queen = new Queen();
- queen.setId((long) i);
- queen.setX(i); // Different column
- queen.setY(0); // Same row
- queenList.add(queen);
- }
- nQueens.setQueenList(queenList);
- return nQueens;
- }</programlisting>
-
- <para>The starting solution will probably be far from optimal (or even feasible). Here, it's actually the worst
- possible solution. However, we 'll let the solver find a much better solution for us anyway.</para>
-
- <section>
- <title>StartingSolutionInitializer</title>
-
- <para>For large problems, a simple filler algorithm like <literal>createNQueens(int)</literal> doesn't suffice. A
- (local search) solver starting from a bad starting solution wastes a lot of time to reach a solution which an
- initializer algorithm can generate in a fraction of that time.</para>
-
- <para>An initializer algorithm ussually works something like this:</para>
-
- <itemizedlist>
- <listitem>
- <para>It sorts the unplanned elements in a queue according to some general rules, for example by exam student
- size.</para>
- </listitem>
-
- <listitem>
- <para>Next, it plans them in the order they come from the queue. Each element is put the best, still available
- spot.</para>
- </listitem>
-
- <listitem>
- <para>It doesn't change an already planned element. It exits when the queue is empty and all elements are
- planned.</para>
- </listitem>
- </itemizedlist>
-
- <para>Such an algorithm is very deterministic: it's really fast, but you can't give it more time to generate an
- even better solution. In some cases the solution it generates will be feasible, but in most cases it won't. You
- 'll need a real solver to get to a feasible or more optimal solution. Nevertheless you 'll want to such an
- initializer to give the real solver a serious head start. You can do this by implementing the
- <literal>StartingSolutionInitializer</literal> interface:</para>
-
- <programlisting>public interface StartingSolutionInitializer extends SolverAware {
-
- boolean isSolutionInitialized(Solution solution);
-
- void initializeSolution(Solution solution);
-
-}</programlisting>
-
- <para>You'll need to set a (uninitialized) solution on the solver. Once the solver starts, it will first call the
- <literal>StartingSolutionInitializer</literal> to initialize the solution. If the
- <literal>StartingSolutionInitializer</literal> adds, edits or removes facts it needs to notify the workingMemory
- about this. It can use score calculation during its initialization process.</para>
-
- <para>Here's an example on how you add the <literal>StartingSolutionInitializer</literal> to the
- configuration:</para>
-
- <programlisting><localSearchSolver>
- ...
- <startingSolutionInitializerClass>org.drools.planner.examples.examination.solver.solution.initializer.ExaminationStartingSolutionInitializer</startingSolutionInitializerClass>
- ...
-</localSearchSolver></programlisting>
- </section>
- </section>
-
- <section>
- <title>Solving a problem</title>
-
- <para>Solving a problem is quite easy once you have a solver and the starting solution:</para>
-
- <programlisting> solver.setStartingSolution(startingSolution);
- solver.solve();
- Solution bestSolution = solver.getBestSolution();</programlisting>
-
- <para>The <literal>solve()</literal> method will take a long time (depending on the problem size and the solver
- configuration). The solver will remember (actually clone) the best solution it encounters during its solving.
- Depending on a number factors (including problem size, how long you allow the solver to work, which solver type you
- use, ...), that best solution will be a feasible or even an optimal solution.</para>
-
- <figure>
- <title>Best solution for the 4 queens puzzle (also an optimal solution)</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Planner_configuration/solvedNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>After a problem is solved, you can reuse the same solver instance to solve another problem (of the same
- problem type).</para>
- </section>
-</chapter>
Copied: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Chapter-Planner_introduction.xml (from rev 30817, labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Section-Planner_introduction.xml)
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Chapter-Planner_introduction.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Chapter-Planner_introduction.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
+ http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
+ version="5.0" xml:base="./">
+
+ <title>Planner introduction</title>
+
+ <section>
+ <title>What is Drools Planner?</title>
+
+ <para><emphasis role="bold">Drools Planner does automated planning </emphasis>by combining a search algorithm with
+ the power of the Drools rule engine. Good examples of such planning problems include:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Employee shift rostering</para>
+ </listitem>
+
+ <listitem>
+ <para>Freight routing</para>
+ </listitem>
+
+ <listitem>
+ <para>Supply sorting</para>
+ </listitem>
+
+ <listitem>
+ <para>Lesson scheduling</para>
+ </listitem>
+
+ <listitem>
+ <para>Exam scheduling</para>
+ </listitem>
+
+ <listitem>
+ <para>Bin packaging</para>
+ </listitem>
+
+ <listitem>
+ <para><link xlink:href="http://en.wikipedia.org/wiki/Travelling_salesman_problem">The traveling salesman
+ problem</link></para>
+ </listitem>
+
+ <listitem>
+ <para><link xlink:href="http://mat.gsia.cmu.edu/TOURN/">The traveling tournament problem</link></para>
+ </listitem>
+
+ <listitem>
+ <para>Miss manners too (although the Drools Planner example solves this differently than the pure Drools rule
+ engine example)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>A planning problem consists out of a number of constraints. Generally, there are 3 types of
+ constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>A <emphasis>(negative) hard constraint</emphasis> must not be broken. For example: <emphasis>1 teacher can
+ not teach 2 different lessons at the same time</emphasis>.</para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>(negative) soft constraint</emphasis> should not be broken if it can be avoided. For example:
+ <emphasis>Teacher A does not like to teach on Friday afternoon</emphasis>.</para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>positive constraint (or reward)</emphasis> should be fulfilled if possible. For example:
+ <emphasis>Teacher B likes to teach on Monday morning</emphasis>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>These constraints define the <emphasis>score function</emphasis> of a planning problem. This is where the
+ drools rule engine comes into play: <emphasis role="bold">adding constraints with score rules is easy and
+ scalable</emphasis>.</para>
+
+ <para>A planning problem has a number of <emphasis>solutions</emphasis>. Each solution has a score. There are 3
+ categories of solutions:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>A <emphasis>possible solution</emphasis> is a solution that does or does not break any number of
+ constraints. Planning problems tend to have a incredibly large number of possible solutions. Most of those
+ solutions are worthless.</para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>feasible solution</emphasis> is a solution that does not break any (negative) hard
+ constraints. The number of feasible solutions tends to be relative to the number of possible solutions.
+ Sometimes there are no feasible solutions. Every feasible solution is a possible solution.</para>
+ </listitem>
+
+ <listitem>
+ <para>An <emphasis>optimal solution</emphasis> is a solution with the highest score. Planning problems tend to
+ have 1 or a few optimal solutions. There is always at least 1 optimal solution, even in the remote case that
+ it's not a feasible solution because there are no feasible solutions.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Drools Planner supports several search algorithms to efficiently wade through the incredibly large number of
+ possible solutions. <emphasis role="bold">It makes it easy to switch the search algorithm</emphasis>, by simply
+ changing the solver configuration.</para>
+ </section>
+
+ <section>
+ <title>Status of Drools Planner</title>
+
+ <para>Drools Planner is a beta module of Drools. The API is almost stable but backward incompatible changes can
+ occur. With the recipe called <filename>UpgradeFromPreviousVersionRecipe.txt</filename> you can easily upgrade and
+ deal with any backwards incompatible changes between versions. You can find this recipe in subversion and in every
+ release.</para>
+
+ <para>Drools Planner, like Drools, is open source software under the Apache Software License.</para>
+ </section>
+
+ <section>
+ <title>Getting Drools Planner and running the examples</title>
+
+ <section>
+ <title>Getting the release package and running the examples</title>
+
+ <para>You can download a release of Drools Planner from <link
+ xlink:href="http://www.jboss.org/drools/downloads.html">the drools download site</link>. To run an example, just
+ run the script (<filename>runExamples.sh</filename> on linux or <filename>runExamples.bat</filename> on windows)
+ and pick an example:</para>
+
+ <programlisting>$ ./runExamples.sh</programlisting>
+ </section>
+
+ <section>
+ <title>Get it with maven 2</title>
+
+ <para>The Drools Planner jars are available on <link xlink:href="http://repository.jboss.com/maven2/">the jboss
+ maven repository</link>. If you use maven 2, just add a dependency to <literal>drools-planner-core</literal> in
+ your project's <filename>pom.xml</filename>:</para>
+
+ <programlisting> <dependency>
+ <groupId>org.drools.planner</groupId>
+ <artifactId>drools-planner-core</artifactId>
+ <version>5.x</version>
+ </dependency></programlisting>
+
+ <para>You might also need to add the jboss repository in your repository manager (nexus, archiva, ...) or your
+ <filename>~/settings.xml</filename>:</para>
+
+ <programlisting> <repositories>
+ <repository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ </repository>
+ ...
+ </repositories></programlisting>
+ </section>
+
+ <section>
+ <title>Build it from source</title>
+
+ <para>You can also easily build it from source yourself. Checkout drools from subversion and do a maven 2
+ build:</para>
+
+ <programlisting>$ svn checkout http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/ drools
+...
+$ cd drools
+$ mvn -DskipTests clean install
+...</programlisting>
+
+ <para>After that, you can run any example directly from the command line, just run this command and pick an
+ example:</para>
+
+ <programlisting>$ cd drools-planner/drools-planner-examples/
+$ mvn exec:exec -Dexec.mainClass="org.drools.planner.examples.app.ExamplesApp"
+...</programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Questions, issues and patches</title>
+
+ <para>Your questions are welcome on <link xlink:href="http://www.jboss.org/drools/lists.html">the user mailing
+ list</link>. You can read/write to the mailing list without littering your mailbox through <link
+ xlink:href="nntp://news.gmane.org/gmane.comp.java.drools.user">this newsgroup</link>.</para>
+
+ <para>Feel free to report an issue (such as a bug, improvement or a new feature request) for the Drools Planner code
+ or for this manual to <link xlink:href="https://jira.jboss.org/jira/browse/JBRULES">the drools JIRA</link>. Select
+ the component <literal>drools-planner</literal>.</para>
+
+ <para>Patches are very welcome and get priority treatment! Attach them to a JIRA issue and optionally send a mail to
+ the dev mailing list to get the issue fixed fast. By open sourcing your improvements, you 'll benefit from
+ improvements made upon your improvements.</para>
+ </section>
+</chapter>
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Chapter-Planner_introduction.xml
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Section-Planner_introduction.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Section-Planner_introduction.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Planner_introduction/Section-Planner_introduction.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -1,202 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
- http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
- version="5.0" xml:base="./">
-
- <title>Planner introduction</title>
-
- <section>
- <title>What is Drools Planner?</title>
-
- <para><emphasis role="bold">Drools Planner does automated planning </emphasis>by combining a search algorithm with
- the power of the Drools rule engine. Good examples of such planning problems include:</para>
-
- <itemizedlist>
- <listitem>
- <para>Employee shift rostering</para>
- </listitem>
-
- <listitem>
- <para>Freight routing</para>
- </listitem>
-
- <listitem>
- <para>Supply sorting</para>
- </listitem>
-
- <listitem>
- <para>Lesson scheduling</para>
- </listitem>
-
- <listitem>
- <para>Exam scheduling</para>
- </listitem>
-
- <listitem>
- <para>Bin packaging</para>
- </listitem>
-
- <listitem>
- <para><link xlink:href="http://en.wikipedia.org/wiki/Travelling_salesman_problem">The traveling salesman
- problem</link></para>
- </listitem>
-
- <listitem>
- <para><link xlink:href="http://mat.gsia.cmu.edu/TOURN/">The traveling tournament problem</link></para>
- </listitem>
-
- <listitem>
- <para>Miss manners too (although the Drools Planner example solves this differently than the pure Drools rule
- engine example)</para>
- </listitem>
- </itemizedlist>
-
- <para>A planning problem consists out of a number of constraints. Generally, there are 3 types of
- constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>A <emphasis>(negative) hard constraint</emphasis> must not be broken. For example: <emphasis>1 teacher can
- not teach 2 different lessons at the same time</emphasis>.</para>
- </listitem>
-
- <listitem>
- <para>A <emphasis>(negative) soft constraint</emphasis> should not be broken if it can be avoided. For example:
- <emphasis>Teacher A does not like to teach on Friday afternoon</emphasis>.</para>
- </listitem>
-
- <listitem>
- <para>A <emphasis>positive constraint (or reward)</emphasis> should be fulfilled if possible. For example:
- <emphasis>Teacher B likes to teach on Monday morning</emphasis>.</para>
- </listitem>
- </itemizedlist>
-
- <para>These constraints define the <emphasis>score function</emphasis> of a planning problem. This is where the
- drools rule engine comes into play: <emphasis role="bold">adding constraints with score rules is easy and
- scalable</emphasis>.</para>
-
- <para>A planning problem has a number of <emphasis>solutions</emphasis>. Each solution has a score. There are 3
- categories of solutions:</para>
-
- <itemizedlist>
- <listitem>
- <para>A <emphasis>possible solution</emphasis> is a solution that does or does not break any number of
- constraints. Planning problems tend to have a incredibly large number of possible solutions. Most of those
- solutions are worthless.</para>
- </listitem>
-
- <listitem>
- <para>A <emphasis>feasible solution</emphasis> is a solution that does not break any (negative) hard
- constraints. The number of feasible solutions tends to be relative to the number of possible solutions.
- Sometimes there are no feasible solutions. Every feasible solution is a possible solution.</para>
- </listitem>
-
- <listitem>
- <para>An <emphasis>optimal solution</emphasis> is a solution with the highest score. Planning problems tend to
- have 1 or a few optimal solutions. There is always at least 1 optimal solution, even in the remote case that
- it's not a feasible solution because there are no feasible solutions.</para>
- </listitem>
- </itemizedlist>
-
- <para>Drools Planner supports several search algorithms to efficiently wade through the incredibly large number of
- possible solutions. <emphasis role="bold">It makes it easy to switch the search algorithm</emphasis>, by simply
- changing the solver configuration.</para>
- </section>
-
- <section>
- <title>Status of Drools Planner</title>
-
- <para>Drools Planner is a beta module of Drools. The API is almost stable but backward incompatible changes can
- occur. With the recipe called <filename>UpgradeFromPreviousVersionRecipe.txt</filename> you can easily upgrade and
- deal with any backwards incompatible changes between versions. You can find this recipe in subversion and in every
- release.</para>
-
- <para>Drools Planner, like Drools, is open source software under the Apache Software License.</para>
- </section>
-
- <section>
- <title>Getting Drools Planner and running the examples</title>
-
- <section>
- <title>Getting the release package and running the examples</title>
-
- <para>You can download a release of Drools Planner from <link
- xlink:href="http://www.jboss.org/drools/downloads.html">the drools download site</link>. To run an example, just
- run the script (<filename>runExamples.sh</filename> on linux or <filename>runExamples.bat</filename> on windows)
- and pick an example:</para>
-
- <programlisting>$ ./runExamples.sh</programlisting>
- </section>
-
- <section>
- <title>Get it with maven 2</title>
-
- <para>The Drools Planner jars are available on <link xlink:href="http://repository.jboss.com/maven2/">the jboss
- maven repository</link>. If you use maven 2, just add a dependency to <literal>drools-planner-core</literal> in
- your project's <filename>pom.xml</filename>:</para>
-
- <programlisting> <dependency>
- <groupId>org.drools.planner</groupId>
- <artifactId>drools-planner-core</artifactId>
- <version>5.x</version>
- </dependency></programlisting>
-
- <para>You might also need to add the jboss repository in your repository manager (nexus, archiva, ...) or your
- <filename>~/settings.xml</filename>:</para>
-
- <programlisting> <repositories>
- <repository>
- <id>repository.jboss.org</id>
- <url>http://repository.jboss.org/maven2</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <releases>
- <enabled>true</enabled>
- </releases>
- </repository>
- ...
- </repositories></programlisting>
- </section>
-
- <section>
- <title>Build it from source</title>
-
- <para>You can also easily build it from source yourself. Checkout drools from subversion and do a maven 2
- build:</para>
-
- <programlisting>$ svn checkout http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/ drools
-...
-$ cd drools
-$ mvn -DskipTests clean install
-...</programlisting>
-
- <para>After that, you can run any example directly from the command line, just run this command and pick an
- example:</para>
-
- <programlisting>$ cd drools-planner/drools-planner-examples/
-$ mvn exec:exec -Dexec.mainClass="org.drools.planner.examples.app.ExamplesApp"
-...</programlisting>
- </section>
- </section>
-
- <section>
- <title>Questions, issues and patches</title>
-
- <para>Your questions are welcome on <link xlink:href="http://www.jboss.org/drools/lists.html">the user mailing
- list</link>. You can read/write to the mailing list without littering your mailbox through <link
- xlink:href="nntp://news.gmane.org/gmane.comp.java.drools.user">this newsgroup</link>.</para>
-
- <para>Feel free to report an issue (such as a bug, improvement or a new feature request) for the Drools Planner code
- or for this manual to <link xlink:href="https://jira.jboss.org/jira/browse/JBRULES">the drools JIRA</link>. Select
- the component <literal>drools-planner</literal>.</para>
-
- <para>Patches are very welcome and get priority treatment! Attach them to a JIRA issue and optionally send a mail to
- the dev mailing list to get the issue fixed fast. By open sourcing your improvements, you 'll benefit from
- improvements made upon your improvements.</para>
- </section>
-</chapter>
Copied: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Chapter-Score_calculation.xml (from rev 30817, labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Section-Score_calculation.xml)
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Chapter-Score_calculation.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Chapter-Score_calculation.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
+ http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
+ version="5.0" xml:base="./">
+
+ <title>Score calculation with a rule engine</title>
+
+ <section>
+ <title>Rule based score calculation</title>
+
+ <para>The score calculation of a planning problem is based on constraints (such as hard constraints, soft
+ constraints, rewards, ...). A rules engine, such as drools, makes it easy to implement those constraints as
+ <emphasis>score rules</emphasis>.</para>
+
+ <para>Here's an example of a constraint implemented as a score rule in drools:</para>
+
+ <programlisting>rule "multipleQueensHorizontal"
+ when
+ $q1 : Queen($id : id, $y : y);
+ $q2 : Queen(id > $id, y == $y);
+ then
+ insertLogical(new UnweightedConstraintOccurrence("multipleQueensHorizontal", $q1, $q2));
+end</programlisting>
+
+ <para>This score rule will fire once for every 2 queens with the same <literal>y</literal>. The <literal>(id >
+ $id)</literal> condition is needed to assure that for 2 queens A and B, it can only fire for (A, B) and not for (B,
+ A), (A, A) or (B, B). Let's take a closer look at this score rule on the starting solution of 4 queens:</para>
+
+ <figure>
+ <title>Starting solution for the 4 queens puzzle</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Score_calculation/unsolvedNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>In this starting solution the multipleQueensHorizontal score rule will fire for 6 queen couples: (A, B), (A,
+ C), (A, D), (B, C), (B, D) and (C, D). Because none of the queens are on the same vertical or diagonal line, this
+ starting solution will have a score of <literal>-6</literal>. An optimal solution of 4 queens has a score of
+ <literal>0</literal>.</para>
+
+ <para>You need to add your score rules drl files in the solver configuration, for example:</para>
+
+ <programlisting> <scoreDrl>/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl></programlisting>
+
+ <para>You can add multiple <literal><scoreDrl></literal> entries if needed.</para>
+
+ <para>It's recommended to use drools in forward-chaining mode (which is the default behaviour), as for solver
+ implementations this will create the effect of a <emphasis>delta based score calculation</emphasis> instead of a
+ full score calculation on each solution evaluation. For example, if a single queen moves from y <literal>0</literal>
+ to <literal>3</literal>, it won't bother to recalculate the "multiple queens on the same horizontal line" constraint
+ for queens with y <literal>1</literal> or <literal>2</literal>. This is a huge performance gain. <emphasis
+ role="bold">Drools Planner gives you this huge performance gain without forcing you to write a very complicated delta
+ based score calculation algorithm.</emphasis> Just let the drools rule engine do the hard work.</para>
+
+ <para><emphasis role="bold">Adding more constraints is <emphasis role="bold">easy and </emphasis>scalable</emphasis>
+ (once you understand the drools rule syntax). This allows you to add a bunch of soft constraint score rules on top
+ of the hard constraints score rules with little effort and at a reasonable performance cost. For example, for a
+ freight routing problem you could add a soft constraint to avoid the certain flagged highways at rush hour.</para>
+ </section>
+
+ <section>
+ <title>The ScoreDefinition interface</title>
+
+ <para>The <literal>ScoreDefinition</literal> interface defines the score representation. The score must a
+ <literal>Score</literal> instance and the instance type (for example <literal>DefaultHardAndSoftScore</literal>)
+ must be stable throughout the solver runtime.</para>
+
+ <para>The solver aims to find the solution with the highest score. <emphasis>The best solution</emphasis> is the
+ solution with the highest score that it has encountered during its solving.</para>
+
+ <para>Most planning problems tend to use negative scores (the amount of negative constraints being broken) with an
+ impossible perfect score of 0. This explains why the score of a solution of 4 queens is the negative of the number
+ of queen couples which can attack each other.</para>
+
+ <para>A <literal>ScoreDefinition</literal> instance is configured in the solver configuration:</para>
+
+ <programlisting> <scoreDefinition>
+ <scoreDefinitionType>SIMPLE</scoreDefinitionType>
+ </scoreDefinition></programlisting>
+
+ <para>There are a couple of build-in <literal>ScoreDefinition</literal> implementations:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>SIMPLE: The <literal>SimpleScoreDefinition</literal> defines the <literal>Score</literal> as a
+ <literal>SimpleScore</literal> which has a single int value, for example <literal>-123</literal>.</para>
+ </listitem>
+
+ <listitem>
+ <para>HARD_AND_SOFT: The <literal>HardAndSoftScoreDefinition</literal> defines the <literal>Score</literal> as a
+ <literal>HardAndSoftScore</literal> which has a hard int value and a soft int value, for example
+ <literal>-123hard/-456soft</literal>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>You can implement your own <literal>ScoreDefinition</literal>, although the build-in score definitions should
+ suffice for most needs.</para>
+
+ <para>A <literal>ScoreCalculator</literal> instance is asserted into the working memory as a global called
+ <literal>scoreCalculator</literal>. Your score rules need to (indirectly) update that instance. Usually you 'll make
+ a single rule as an aggregation of the other rules to update the score:</para>
+
+ <programlisting>global SimpleScoreCalculator scoreCalculator;
+
+rule "multipleQueensHorizontal"
+ when
+ $q1 : Queen($id : id, $y : y);
+ $q2 : Queen(id > $id, y == $y);
+ then
+ insertLogical(new UnweightedConstraintOccurrence("multipleQueensHorizontal", $q1, $q2));
+end
+
+// multipleQueensVertical is obsolete because it is always 0
+
+rule "multipleQueensAscendingDiagonal"
+ when
+ $q1 : Queen($id : id, $ascendingD : ascendingD);
+ $q2 : Queen(id > $id, ascendingD == $ascendingD);
+ then
+ insertLogical(new UnweightedConstraintOccurrence("multipleQueensAscendingDiagonal", $q1, $q2));
+end
+
+rule "multipleQueensDescendingDiagonal"
+ when
+ $q1 : Queen($id : id, $descendingD : descendingD);
+ $q2 : Queen(id > $id, descendingD == $descendingD);
+ then
+ insertLogical(new UnweightedConstraintOccurrence("multipleQueensDescendingDiagonal", $q1, $q2));
+end
+
+rule "hardConstraintsBroken"
+ when
+ $occurrenceCount : Number() from accumulate(
+ $unweightedConstraintOccurrence : UnweightedConstraintOccurrence(),
+ count($unweightedConstraintOccurrence)
+ );
+ then
+ scoreCalculator.setScore(- $occurrenceCount.intValue());
+end</programlisting>
+
+ <para>Optionally, you can also weigh your constraints differently, by multiplying the count of each score rule with
+ its weight. For example in freight routing, you can make 5 broken "avoid crossroads" soft constraints count as much
+ as 1 broken "avoid highways at rush hour" soft constraint. This allows your business analysts to easily tweak the
+ score function as they see fit.</para>
+
+ <para>Here's an example of all the NQueens constraints written as a single rule, using multi pattern accumulates and
+ making multipleQueensHorizontal constraint outweigh the other constraints 5 times:</para>
+
+ <programlisting>// Warning: This currently triggers backwards chaining instead of forward chaining and seriously hurts performance and scalability.
+rule "constraintsBroken"
+ when
+ $multipleQueensHorizontal : Long()
+ from accumulate(
+ $q1 : Queen($id : id, $y : y)
+ and Queen(id > $id, y == $y),
+ count($q1)
+ );
+ $multipleQueensAscendingDiagonal : Long()
+ from accumulate(
+ $q2 : Queen($id : id, $ascendingD : ascendingD)
+ and Queen(id > $id, ascendingD == $ascendingD),
+ count($q2)
+ );
+ $multipleQueensDescendingDiagonal : Long()
+ from accumulate(
+ $q3 : Queen($id : id, $descendingD : descendingD)
+ and Queen(id > $id, descendingD == $descendingD),
+ count($q3)
+ );
+ then
+ scoreCalculator.setScore(- (5 * $multipleQueensHorizontal) - $multipleQueensAscendingDiagonal - $multipleQueensDescendingDiagonal);
+end</programlisting>
+ </section>
+
+ <section>
+ <title>Tips and tricks</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>If you know a certain constraint can never be broken, don't bother writing a score rule for it. For
+ example, the n queens example doesn't have a "multipleQueensVertical" rule because a queen's
+ <literal>x</literal> never changes and the starting solution puts each queen on a different
+ <literal>x</literal>. This tends to give a huge performance gain, not just because the score function is faster,
+ but mainly because most solver implementations will spend less time evaluating unfeasible solutions.</para>
+ </listitem>
+
+ <listitem>
+ <para>Be watchfull for score traps. A score trap is a state in which several moves need to be done to resolve or
+ lower the weight of a single constraint occurrence. Some examples of score traps:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>If you need 2 doctors at each table, but you're only moving 1 doctor at a time, then the solver has no
+ insentive to move a doctor to a table with no doctors. Punish a table with no doctors more then a table with
+ only 1 doctor in your score function.</para>
+ </listitem>
+
+ <listitem>
+ <para>If you only add the table as a cause of the ConstraintOccurrence and forget the jobType (which is
+ doctor or politician), then the solver has no insentive to move a docter to table which is short of a doctor
+ and a politician.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>If you use tabu search, combine it with a <literal>relativeSelection</literal> selector. Take some time to
+ tweak the value of <literal>relativeSelection</literal>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Verify that your score calculation happens in the correct <literal>Number</literal> type. If you're making
+ the sum of integer values, don't let drools use Double's or your performance will hurt. Solver implementations
+ will usually spend most of their execution time running the score function.</para>
+ </listitem>
+
+ <listitem>
+ <para>Always remember that premature optimization is the root of all evil. Make sure your design is flexible
+ enough to allow configuration based tweaking.</para>
+ </listitem>
+
+ <listitem>
+ <para>Currently, don't allow drools to backward chain instead of forward chain, so avoid query's. It kills
+ scalibilty.</para>
+ </listitem>
+
+ <listitem>
+ <para>Currently, don't allow drools to switch to MVEL mode, for performance. You can avoid this by using
+ <literal>eval</literal> in the score rules, for example: <literal>eval(day.getIndex() == $day1.getIndex() +
+ 3)</literal>.</para>
+ </listitem>
+
+ <listitem>
+ <para>For optimal performance, use at least java 1.6 and always use server mode (<literal>java
+ -server</literal>). We have seen performance increases of 30% by switching from java 1.5 to 1.6 and 50% by
+ turning on server mode.</para>
+ </listitem>
+
+ <listitem>
+ <para>If you're doing performance tests, always remember that the JVM needs to warm up. First load your solver
+ and do a short run, before you start benchmarking it.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>In case you haven't figured it out yet: performance (and scalability) is very important for solving planning
+ problems. What good is a real-time freight routing solver that takes a day to find a feasible solution? Even small
+ and innocent looking problems can hide an enormous problem size. For example, they probably still don't know the
+ optimal solution of the traveling tournament problem for as little as 10 traveling teams.</para>
+ </section>
+</chapter>
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Chapter-Score_calculation.xml
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Section-Score_calculation.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Section-Score_calculation.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Score_calculation/Section-Score_calculation.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -1,257 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
- http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
- version="5.0" xml:base="./">
-
- <title>Score calculation with a rule engine</title>
-
- <section>
- <title>Rule based score calculation</title>
-
- <para>The score calculation of a planning problem is based on constraints (such as hard constraints, soft
- constraints, rewards, ...). A rules engine, such as drools, makes it easy to implement those constraints as
- <emphasis>score rules</emphasis>.</para>
-
- <para>Here's an example of a constraint implemented as a score rule in drools:</para>
-
- <programlisting>rule "multipleQueensHorizontal"
- when
- $q1 : Queen($id : id, $y : y);
- $q2 : Queen(id > $id, y == $y);
- then
- insertLogical(new UnweightedConstraintOccurrence("multipleQueensHorizontal", $q1, $q2));
-end</programlisting>
-
- <para>This score rule will fire once for every 2 queens with the same <literal>y</literal>. The <literal>(id >
- $id)</literal> condition is needed to assure that for 2 queens A and B, it can only fire for (A, B) and not for (B,
- A), (A, A) or (B, B). Let's take a closer look at this score rule on the starting solution of 4 queens:</para>
-
- <figure>
- <title>Starting solution for the 4 queens puzzle</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Score_calculation/unsolvedNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>In this starting solution the multipleQueensHorizontal score rule will fire for 6 queen couples: (A, B), (A,
- C), (A, D), (B, C), (B, D) and (C, D). Because none of the queens are on the same vertical or diagonal line, this
- starting solution will have a score of <literal>-6</literal>. An optimal solution of 4 queens has a score of
- <literal>0</literal>.</para>
-
- <para>You need to add your score rules drl files in the solver configuration, for example:</para>
-
- <programlisting> <scoreDrl>/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl></programlisting>
-
- <para>You can add multiple <literal><scoreDrl></literal> entries if needed.</para>
-
- <para>It's recommended to use drools in forward-chaining mode (which is the default behaviour), as for solver
- implementations this will create the effect of a <emphasis>delta based score calculation</emphasis> instead of a
- full score calculation on each solution evaluation. For example, if a single queen moves from y <literal>0</literal>
- to <literal>3</literal>, it won't bother to recalculate the "multiple queens on the same horizontal line" constraint
- for queens with y <literal>1</literal> or <literal>2</literal>. This is a huge performance gain. <emphasis
- role="bold">Drools Planner gives you this huge performance gain without forcing you to write a very complicated delta
- based score calculation algorithm.</emphasis> Just let the drools rule engine do the hard work.</para>
-
- <para><emphasis role="bold">Adding more constraints is <emphasis role="bold">easy and </emphasis>scalable</emphasis>
- (once you understand the drools rule syntax). This allows you to add a bunch of soft constraint score rules on top
- of the hard constraints score rules with little effort and at a reasonable performance cost. For example, for a
- freight routing problem you could add a soft constraint to avoid the certain flagged highways at rush hour.</para>
- </section>
-
- <section>
- <title>The ScoreDefinition interface</title>
-
- <para>The <literal>ScoreDefinition</literal> interface defines the score representation. The score must a
- <literal>Score</literal> instance and the instance type (for example <literal>DefaultHardAndSoftScore</literal>)
- must be stable throughout the solver runtime.</para>
-
- <para>The solver aims to find the solution with the highest score. <emphasis>The best solution</emphasis> is the
- solution with the highest score that it has encountered during its solving.</para>
-
- <para>Most planning problems tend to use negative scores (the amount of negative constraints being broken) with an
- impossible perfect score of 0. This explains why the score of a solution of 4 queens is the negative of the number
- of queen couples which can attack each other.</para>
-
- <para>A <literal>ScoreDefinition</literal> instance is configured in the solver configuration:</para>
-
- <programlisting> <scoreDefinition>
- <scoreDefinitionType>SIMPLE</scoreDefinitionType>
- </scoreDefinition></programlisting>
-
- <para>There are a couple of build-in <literal>ScoreDefinition</literal> implementations:</para>
-
- <itemizedlist>
- <listitem>
- <para>SIMPLE: The <literal>SimpleScoreDefinition</literal> defines the <literal>Score</literal> as a
- <literal>SimpleScore</literal> which has a single int value, for example <literal>-123</literal>.</para>
- </listitem>
-
- <listitem>
- <para>HARD_AND_SOFT: The <literal>HardAndSoftScoreDefinition</literal> defines the <literal>Score</literal> as a
- <literal>HardAndSoftScore</literal> which has a hard int value and a soft int value, for example
- <literal>-123hard/-456soft</literal>.</para>
- </listitem>
- </itemizedlist>
-
- <para>You can implement your own <literal>ScoreDefinition</literal>, although the build-in score definitions should
- suffice for most needs.</para>
-
- <para>A <literal>ScoreCalculator</literal> instance is asserted into the working memory as a global called
- <literal>scoreCalculator</literal>. Your score rules need to (indirectly) update that instance. Usually you 'll make
- a single rule as an aggregation of the other rules to update the score:</para>
-
- <programlisting>global SimpleScoreCalculator scoreCalculator;
-
-rule "multipleQueensHorizontal"
- when
- $q1 : Queen($id : id, $y : y);
- $q2 : Queen(id > $id, y == $y);
- then
- insertLogical(new UnweightedConstraintOccurrence("multipleQueensHorizontal", $q1, $q2));
-end
-
-// multipleQueensVertical is obsolete because it is always 0
-
-rule "multipleQueensAscendingDiagonal"
- when
- $q1 : Queen($id : id, $ascendingD : ascendingD);
- $q2 : Queen(id > $id, ascendingD == $ascendingD);
- then
- insertLogical(new UnweightedConstraintOccurrence("multipleQueensAscendingDiagonal", $q1, $q2));
-end
-
-rule "multipleQueensDescendingDiagonal"
- when
- $q1 : Queen($id : id, $descendingD : descendingD);
- $q2 : Queen(id > $id, descendingD == $descendingD);
- then
- insertLogical(new UnweightedConstraintOccurrence("multipleQueensDescendingDiagonal", $q1, $q2));
-end
-
-rule "hardConstraintsBroken"
- when
- $occurrenceCount : Number() from accumulate(
- $unweightedConstraintOccurrence : UnweightedConstraintOccurrence(),
- count($unweightedConstraintOccurrence)
- );
- then
- scoreCalculator.setScore(- $occurrenceCount.intValue());
-end</programlisting>
-
- <para>Optionally, you can also weigh your constraints differently, by multiplying the count of each score rule with
- its weight. For example in freight routing, you can make 5 broken "avoid crossroads" soft constraints count as much
- as 1 broken "avoid highways at rush hour" soft constraint. This allows your business analysts to easily tweak the
- score function as they see fit.</para>
-
- <para>Here's an example of all the NQueens constraints written as a single rule, using multi pattern accumulates and
- making multipleQueensHorizontal constraint outweigh the other constraints 5 times:</para>
-
- <programlisting>// Warning: This currently triggers backwards chaining instead of forward chaining and seriously hurts performance and scalability.
-rule "constraintsBroken"
- when
- $multipleQueensHorizontal : Long()
- from accumulate(
- $q1 : Queen($id : id, $y : y)
- and Queen(id > $id, y == $y),
- count($q1)
- );
- $multipleQueensAscendingDiagonal : Long()
- from accumulate(
- $q2 : Queen($id : id, $ascendingD : ascendingD)
- and Queen(id > $id, ascendingD == $ascendingD),
- count($q2)
- );
- $multipleQueensDescendingDiagonal : Long()
- from accumulate(
- $q3 : Queen($id : id, $descendingD : descendingD)
- and Queen(id > $id, descendingD == $descendingD),
- count($q3)
- );
- then
- scoreCalculator.setScore(- (5 * $multipleQueensHorizontal) - $multipleQueensAscendingDiagonal - $multipleQueensDescendingDiagonal);
-end</programlisting>
- </section>
-
- <section>
- <title>Tips and tricks</title>
-
- <itemizedlist>
- <listitem>
- <para>If you know a certain constraint can never be broken, don't bother writing a score rule for it. For
- example, the n queens example doesn't have a "multipleQueensVertical" rule because a queen's
- <literal>x</literal> never changes and the starting solution puts each queen on a different
- <literal>x</literal>. This tends to give a huge performance gain, not just because the score function is faster,
- but mainly because most solver implementations will spend less time evaluating unfeasible solutions.</para>
- </listitem>
-
- <listitem>
- <para>Be watchfull for score traps. A score trap is a state in which several moves need to be done to resolve or
- lower the weight of a single constraint occurrence. Some examples of score traps:</para>
-
- <itemizedlist>
- <listitem>
- <para>If you need 2 doctors at each table, but you're only moving 1 doctor at a time, then the solver has no
- insentive to move a doctor to a table with no doctors. Punish a table with no doctors more then a table with
- only 1 doctor in your score function.</para>
- </listitem>
-
- <listitem>
- <para>If you only add the table as a cause of the ConstraintOccurrence and forget the jobType (which is
- doctor or politician), then the solver has no insentive to move a docter to table which is short of a doctor
- and a politician.</para>
- </listitem>
- </itemizedlist>
- </listitem>
-
- <listitem>
- <para>If you use tabu search, combine it with a <literal>relativeSelection</literal> selector. Take some time to
- tweak the value of <literal>relativeSelection</literal>.</para>
- </listitem>
-
- <listitem>
- <para>Verify that your score calculation happens in the correct <literal>Number</literal> type. If you're making
- the sum of integer values, don't let drools use Double's or your performance will hurt. Solver implementations
- will usually spend most of their execution time running the score function.</para>
- </listitem>
-
- <listitem>
- <para>Always remember that premature optimization is the root of all evil. Make sure your design is flexible
- enough to allow configuration based tweaking.</para>
- </listitem>
-
- <listitem>
- <para>Currently, don't allow drools to backward chain instead of forward chain, so avoid query's. It kills
- scalibilty.</para>
- </listitem>
-
- <listitem>
- <para>Currently, don't allow drools to switch to MVEL mode, for performance. You can avoid this by using
- <literal>eval</literal> in the score rules, for example: <literal>eval(day.getIndex() == $day1.getIndex() +
- 3)</literal>.</para>
- </listitem>
-
- <listitem>
- <para>For optimal performance, use at least java 1.6 and always use server mode (<literal>java
- -server</literal>). We have seen performance increases of 30% by switching from java 1.5 to 1.6 and 50% by
- turning on server mode.</para>
- </listitem>
-
- <listitem>
- <para>If you're doing performance tests, always remember that the JVM needs to warm up. First load your solver
- and do a short run, before you start benchmarking it.</para>
- </listitem>
- </itemizedlist>
-
- <para>In case you haven't figured it out yet: performance (and scalability) is very important for solving planning
- problems. What good is a real-time freight routing solver that takes a day to find a feasible solution? Even small
- and innocent looking problems can hide an enormous problem size. For example, they probably still don't know the
- optimal solution of the traveling tournament problem for as little as 10 traveling teams.</para>
- </section>
-</chapter>
Copied: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Chapter-Use_cases_and_examples.xml (from rev 30817, labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Section-Use_cases_and_examples.xml)
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Chapter-Use_cases_and_examples.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Chapter-Use_cases_and_examples.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -0,0 +1,1007 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
+ http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
+ version="5.0" xml:base="./">
+
+ <title>Use cases and examples</title>
+
+ <section>
+ <title>Introduction</title>
+
+ <para>Drools Planner has several examples. In this manual we explain Drools Planner mainly using the n queens example.
+ So it's advisable to read at least the section about that example. For advanced users, the Examination example is
+ recommended.</para>
+
+ <para>You can find the source code of all these examples in the drools source distribution and also in subversion
+ under <literal>drools-planner/drools-planner-examples</literal>.</para>
+ </section>
+
+ <section>
+ <title>The n queens example</title>
+
+ <section>
+ <title>Screenshot</title>
+
+ <para>Here is a screenshot of the example:</para>
+
+ <figure>
+ <title>Screenshot of the n queens example</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotNQueens.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+ <section>
+ <title>Problem statement</title>
+
+ <para>The <emphasis>n queens puzzle</emphasis> is a puzzle with the follow constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Use a chessboard of n rows and n columns.</para>
+ </listitem>
+
+ <listitem>
+ <para>Place n queens on the chessboard.</para>
+ </listitem>
+
+ <listitem>
+ <para>No 2 queens can attack each other. Note that a queen can attack any other queen on the same horizontal,
+ vertical or diagonal line.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The most common n queens puzzle is the 8 queens puzzle, with <emphasis>n = 8</emphasis>. We 'll explain
+ Drools Planner using the 4 queens puzzle as the primary example.</para>
+
+ <para>A proposed solution could be:</para>
+
+ <figure>
+ <title>A wrong solution for the 4 queens puzzle</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Use_cases_and_examples/partiallySolvedNQueens04Explained.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The above solution is wrong because queens A1 and B0 can attack each other (as can queens B0 and D0).
+ Removing queen B0 would respect the "no 2 queens can attack each other" constraint, but would break the "place n
+ queens" constraint.</para>
+ </section>
+
+ <section>
+ <title>Solution(s)</title>
+
+ <para>Below is a correct solution:</para>
+
+ <figure>
+ <title>A correct solution for the 4 queens puzzle</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Use_cases_and_examples/solvedNQueens04.png" format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>All the constraints have been met, so the solution is correct. Note that most n queens puzzles have multiple
+ correct solutions. We 'll focus on finding a single correct solution for a given n, not on finding the number of
+ possible correct solutions for a given n.</para>
+ </section>
+
+ <section>
+ <title>Problem size</title>
+
+ <para>These numbers might give you some insight on the size of this problem.</para>
+
+ <table>
+ <title>NQueens problem size</title>
+
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry># queens (n)</entry>
+
+ <entry># possible solutions (each queen it's own column)</entry>
+
+ <entry># feasible solutions (distinct)</entry>
+
+ <entry># optimal solutions (distinct)</entry>
+
+ <entry># possible / # optimal</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>4</entry>
+
+ <entry>256</entry>
+
+ <entry>2</entry>
+
+ <entry>2</entry>
+
+ <entry>128</entry>
+ </row>
+
+ <row>
+ <entry>8</entry>
+
+ <entry>16777216</entry>
+
+ <entry>64</entry>
+
+ <entry>64</entry>
+
+ <entry>262144</entry>
+ </row>
+
+ <row>
+ <entry>16</entry>
+
+ <entry>18446744073709551616</entry>
+
+ <entry>14772512</entry>
+
+ <entry>14772512</entry>
+
+ <entry>1248720872503</entry>
+ </row>
+
+ <row>
+ <entry>32</entry>
+
+ <entry>1.46150163733090291820368483e+48</entry>
+
+ <entry>?</entry>
+
+ <entry>?</entry>
+
+ <entry>?</entry>
+ </row>
+
+ <row>
+ <entry>64</entry>
+
+ <entry>3.94020061963944792122790401e+115</entry>
+
+ <entry>?</entry>
+
+ <entry>?</entry>
+
+ <entry>?</entry>
+ </row>
+
+ <row>
+ <entry>n</entry>
+
+ <entry>n ^ n</entry>
+
+ <entry>?</entry>
+
+ <entry># feasible solutions</entry>
+
+ <entry>?</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>The Drools Planner implementation has not been optimized because it functions as a beginner example.
+ Nevertheless, it can easily handle 64 queens.</para>
+ </section>
+
+ <section>
+ <title>Domain class diagram</title>
+
+ <para>Use a good domain model and it will be easier to understand and solve your problem with Drools Planner. We
+ 'll use this domain model for the n queens example:</para>
+
+ <figure>
+ <title>NQueens domain class diagram</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Use_cases_and_examples/nQueensDomainDiagram.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A <literal>Queen</literal> instance has an x (its column, for example: 0 is column A, 1 is column B, ...)
+ and a y (its row, for example: 0 is row 0, 1 is row 1, ...). Based on the x and y, the ascending diagonal line as
+ well as the descending diagonal line can be calculated. The x and y indexes start from the upper left corner of
+ the chessboard.</para>
+
+ <table>
+ <title>A solution for the 4 queens puzzle shown in the domain model</title>
+
+ <tgroup cols="6">
+ <thead>
+ <row>
+ <entry align="center">A solution</entry>
+
+ <entry align="center">Queen</entry>
+
+ <entry>x</entry>
+
+ <entry>y</entry>
+
+ <entry>ascendingD (x + y)</entry>
+
+ <entry>descendingD (x - y)</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry morerows="3"><mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Use_cases_and_examples/partiallySolvedNQueens04Explained.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject></entry>
+
+ <entry>A1</entry>
+
+ <entry>0</entry>
+
+ <entry>1</entry>
+
+ <entry>1 (**)</entry>
+
+ <entry>-1</entry>
+ </row>
+
+ <row>
+ <entry>B0</entry>
+
+ <entry>1</entry>
+
+ <entry>0 (*)</entry>
+
+ <entry>1 (**)</entry>
+
+ <entry>1</entry>
+ </row>
+
+ <row>
+ <entry>C2</entry>
+
+ <entry>2</entry>
+
+ <entry>2</entry>
+
+ <entry>4</entry>
+
+ <entry>0</entry>
+ </row>
+
+ <row>
+ <entry>D0</entry>
+
+ <entry>3</entry>
+
+ <entry>0 (*)</entry>
+
+ <entry>3</entry>
+
+ <entry>3</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>A single <literal>NQueens</literal> instance contains a list of all <literal>Queen</literal> instances. It
+ is the <literal>Solution</literal> implementation which will be supplied to and retrieved from the Solver.
+ Notice that in the 4 queens example, NQueens's <literal>getN()</literal> method will always return 4.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>The lesson schedule example</title>
+
+ <section>
+ <title>Screenshot</title>
+
+ <para>Here is a screenshot of the example:</para>
+
+ <figure>
+ <title>Screenshot of the lesson schedule example</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotLessonSchedule.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+ <section>
+ <title>Problem statement</title>
+
+ <para>Schedule lessons with the follow constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>No teacher with 2 lessons in the same timeslot</para>
+ </listitem>
+
+ <listitem>
+ <para>No group with 2 lessons in the same timeslot</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section>
+ <title>The traveling tournament example</title>
+
+ <section>
+ <title>Screenshot</title>
+
+ <para>Here is a screenshot of the example:</para>
+
+ <figure>
+ <title>Screenshot of the traveling tournament example</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotTravelingTournament.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+ <section>
+ <title>Problem statement</title>
+
+ <para>Schedule matches between teams with the following hard constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Each team plays twice against every other team: once home and once away</para>
+ </listitem>
+
+ <listitem>
+ <para>Each team has exactly 1 match on each playing day</para>
+ </listitem>
+
+ <listitem>
+ <para>No more than 3 consecutive home or 3 consecutive away matches for any team</para>
+ </listitem>
+
+ <listitem>
+ <para>No repeaters: 2 consecutive matches of the same 2 teams (so each team plays once home and once
+ away</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>and the following soft constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Minimize the total distance traveled of all teams.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para><link xlink:href="http://mat.gsia.cmu.edu/TOURN/">You can find a detailed description as well as several
+ records of this problem here.</link></para>
+ </section>
+
+ <section>
+ <title>Simple and smart implementation</title>
+
+ <para>There are 2 implementations (simple and smart) to demonstrate the importance of some performance tips. The
+ <literal>ExamplesApp</literal> always runs the smart implementation, but with these commands you can compare the 2
+ implementations yourself:</para>
+
+ <programlisting>$ mvn exec:exec -Dexec.mainClass="org.drools.planner.examples.travelingtournament.app.simple.SimpleTravelingTournamentApp"
+...
+$ mvn exec:exec -Dexec.mainClass="org.drools.planner.examples.travelingtournament.app.smart.SmartTravelingTournamentApp"
+...</programlisting>
+
+ <para>The smart implementation performs and scales exponentially better than the simple implementation.</para>
+ </section>
+
+ <section>
+ <title>Problem size</title>
+
+ <para>These numbers might give you some insight on the size of this problem.</para>
+
+ <table>
+ <title>Traveling tournament problem size</title>
+
+ <tgroup cols="7">
+ <thead>
+ <row>
+ <entry># teams</entry>
+
+ <entry># days</entry>
+
+ <entry># matches</entry>
+
+ <entry># possible solutions (simple)</entry>
+
+ <entry># possible solutions (smart)</entry>
+
+ <entry># feasible solutions</entry>
+
+ <entry># optimal solutions</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>4</entry>
+
+ <entry>6</entry>
+
+ <entry>12</entry>
+
+ <entry>2176782336</entry>
+
+ <entry><= 518400</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>6</entry>
+
+ <entry>10</entry>
+
+ <entry>30</entry>
+
+ <entry>1000000000000000000000000000000</entry>
+
+ <entry><= 47784725839872000000</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>8</entry>
+
+ <entry>14</entry>
+
+ <entry>56</entry>
+
+ <entry>1.52464943788290465606136043e+64</entry>
+
+ <entry><= 5.77608277425558771434498864e+43</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>10</entry>
+
+ <entry>18</entry>
+
+ <entry>90</entry>
+
+ <entry>9.43029892325559280477052413e+112</entry>
+
+ <entry><= 1.07573451027871200629339068e+79</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>12</entry>
+
+ <entry>22</entry>
+
+ <entry>132</entry>
+
+ <entry>1.58414112478195320415135060e+177</entry>
+
+ <entry><= 2.01650616733413376416949843e+126</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>14</entry>
+
+ <entry>26</entry>
+
+ <entry>182</entry>
+
+ <entry>3.35080635695103223315189511e+257</entry>
+
+ <entry><= 1.73513467024013808570420241e+186</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>16</entry>
+
+ <entry>30</entry>
+
+ <entry>240</entry>
+
+ <entry>3.22924601799855400751522483e+354</entry>
+
+ <entry><= 2.45064610271441678267620602e+259</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>n</entry>
+
+ <entry>2 * (n - 1)</entry>
+
+ <entry>n * (n - 1)</entry>
+
+ <entry>(2 * (n - 1)) ^ (n * (n - 1))</entry>
+
+ <entry><= (((2 * (n - 1))!) ^ (n / 2))</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+ </section>
+
+ <section>
+ <title>The ITC 2007 examination example</title>
+
+ <section>
+ <title>Screenshot</title>
+
+ <para>Here is a screenshot of the example:</para>
+
+ <figure>
+ <title>Screenshot of the examination example</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotExamination.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+ <section>
+ <title>Problem statement</title>
+
+ <para>Schedule each exam into a period and into a room. Multiple exams can share the same room during the same
+ period.</para>
+
+ <para>There are a number of hard constraints that cannot be broken:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Exam conflict: 2 exams that share students should not occur in the same period.</para>
+ </listitem>
+
+ <listitem>
+ <para>Room capacity: A room's seating capacity should suffice at all times.</para>
+ </listitem>
+
+ <listitem>
+ <para>Period duration: A period's duration should suffice for all of its exams.</para>
+ </listitem>
+
+ <listitem>
+ <para>Period related hard constraints should be fulfilled:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Coincidence: 2 exams should use the same period (but possibly another room).</para>
+ </listitem>
+
+ <listitem>
+ <para>Exclusion: 2 exams should not use the same period.</para>
+ </listitem>
+
+ <listitem>
+ <para>After: 1 exam should occur in a period after another exam's period.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>Room related hard constraints should be fulfilled:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Exclusive: 1 exam should not have to share its room with any other exam.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+
+ <para>There are also a number of soft constraints that should be minimized (each of which has parameterized
+ penalty's):</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>2 exams in a row.</para>
+ </listitem>
+
+ <listitem>
+ <para>2 exams in a day.</para>
+ </listitem>
+
+ <listitem>
+ <para>Period spread: 2 exams that share students should be a number of periods apart.</para>
+ </listitem>
+
+ <listitem>
+ <para>Mixed durations: 2 exams that share a room should not have different durations.</para>
+ </listitem>
+
+ <listitem>
+ <para>Front load: Large exams should be scheduled earlier in the schedule.</para>
+ </listitem>
+
+ <listitem>
+ <para>Period penalty: Some periods have a penalty when used.</para>
+ </listitem>
+
+ <listitem>
+ <para>Room penalty: Some rooms have a penalty when used.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>It uses large test data sets of real-life universities.</para>
+
+ <para><link xlink:href="http://www.cs.qub.ac.uk/itc2007/examtrack/exam_track_index.htm">You can find a more
+ detailed description of this problem here.</link></para>
+ </section>
+
+ <section>
+ <title>Problem size</title>
+
+ <para>These numbers might give you some insight on the size of this problem.</para>
+
+ <table>
+ <title>Examination problem size</title>
+
+ <tgroup cols="8">
+ <thead>
+ <row>
+ <entry>Set</entry>
+
+ <entry># students</entry>
+
+ <entry># exams/topics</entry>
+
+ <entry># periods</entry>
+
+ <entry># rooms</entry>
+
+ <entry># possible solutions</entry>
+
+ <entry># feasible solutions</entry>
+
+ <entry># optimal solutions</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>exam_comp_set1</entry>
+
+ <entry>7883</entry>
+
+ <entry>607</entry>
+
+ <entry>54</entry>
+
+ <entry>7</entry>
+
+ <entry>10^1564</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set2</entry>
+
+ <entry>12484</entry>
+
+ <entry>870</entry>
+
+ <entry>40</entry>
+
+ <entry>49</entry>
+
+ <entry>10^2864</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set3</entry>
+
+ <entry>16365</entry>
+
+ <entry>934</entry>
+
+ <entry>36</entry>
+
+ <entry>48</entry>
+
+ <entry>10^3023</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set4</entry>
+
+ <entry>4421</entry>
+
+ <entry>273</entry>
+
+ <entry>21</entry>
+
+ <entry>1</entry>
+
+ <entry>10^360</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set5</entry>
+
+ <entry>8719</entry>
+
+ <entry>1018</entry>
+
+ <entry>42</entry>
+
+ <entry>3</entry>
+
+ <entry>10^2138</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set6</entry>
+
+ <entry>7909</entry>
+
+ <entry>242</entry>
+
+ <entry>16</entry>
+
+ <entry>8</entry>
+
+ <entry>10^509</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set7</entry>
+
+ <entry>13795</entry>
+
+ <entry>1096</entry>
+
+ <entry>80</entry>
+
+ <entry>28</entry>
+
+ <entry>10^3671</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>exam_comp_set8</entry>
+
+ <entry>7718</entry>
+
+ <entry>598</entry>
+
+ <entry>80</entry>
+
+ <entry>8</entry>
+
+ <entry>10^1678</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+
+ <row>
+ <entry>?</entry>
+
+ <entry>s</entry>
+
+ <entry>t</entry>
+
+ <entry>p</entry>
+
+ <entry>r</entry>
+
+ <entry>(p * r) ^ e</entry>
+
+ <entry>?</entry>
+
+ <entry>1?</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>Geoffrey De Smet (the Drools Planner lead) finished 4th in the International Timetabling Competition 2007's
+ examination track with a very early version of Drools Planner. Many improvements have been made since then.</para>
+ </section>
+
+ <section>
+ <title>Domain class diagram</title>
+
+ <para>Below you can see the main examination domain classes:</para>
+
+ <figure>
+ <title>Examination domain class diagram</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Use_cases_and_examples/examinationDomainDiagram.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Notice that we've split up the exam concept into an <literal>Exam</literal> class and a
+ <literal>Topic</literal> class. The <literal>Exam</literal> instances change during solving, when they get another
+ period or room property. The <literal>Topic</literal>, <literal>Period</literal> and <literal>Room</literal>
+ instances never change during solving.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>The ITC 2007 curriculum course example</title>
+
+ <section>
+ <title>Problem statement</title>
+
+ <para>Schedule lectures into rooms and time periods.</para>
+
+ <para><link xlink:href="http://www.cs.qub.ac.uk/itc2007/curriculmcourse/course_curriculm_index.htm">You can find a
+ more detailed description of this problem here.</link></para>
+ </section>
+ </section>
+
+ <section>
+ <title>The Manners 2009 example</title>
+
+ <section>
+ <title>Problem statement</title>
+
+ <para>In Manners 2009, miss Manners is throwing a party again.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>This time she invited 144 guests and prepared 12 round tables with 12 seats each.</para>
+ </listitem>
+
+ <listitem>
+ <para>Every guest should sit next to someone (left and right) of the opposite gender.</para>
+ </listitem>
+
+ <listitem>
+ <para>And that neighbour should have at least one hobby in common with the guest.</para>
+ </listitem>
+
+ <listitem>
+ <para>Also, this time there should be 2 politicians, 2 doctors, 2 socialites, 2 sports stars, 2 teachers and 2
+ programmers at each table.</para>
+ </listitem>
+
+ <listitem>
+ <para>And the 2 politicians, 2 doctors, 2 sports stars and 2 programmers shouldn't be the same kind.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section>
+ <title>Patient admission scheduling (PAS)</title>
+
+ <para>In this problem, we have to assign each patient (that will come to the hospital) a bed for each night that the
+ patient will stay in the hospital. Each bed belongs to a room and each room belongs to a department. The arrival and
+ departure dates of the patients is fixed: only a bed needs to be assigned for each night.</para>
+
+ <para>There are a couple of hard constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>2 patients shouldn't be assigned to the same bed in the same night.</para>
+ </listitem>
+
+ <listitem>
+ <para>A room can have a gender limitation: only females, only males, the same gender in the same night or no
+ gender limitation at all.</para>
+ </listitem>
+
+ <listitem>
+ <para>A departement can have a minimum or maximum age.</para>
+ </listitem>
+
+ <listitem>
+ <para>A patient can require a room with specific equipment(s).</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>And of course, there are also some soft constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>A patient can prefer a maximum room size, for example if he/she want a single room.</para>
+ </listitem>
+
+ <listitem>
+ <para>A patient is best assigned to a department that specializes in his/her problem.</para>
+ </listitem>
+
+ <listitem>
+ <para>A patient is best assigned to a room that specializes in his/her problem.</para>
+ </listitem>
+
+ <listitem>
+ <para>A patient can prefer a room with specific equipment(s).</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The problem is defined on <link xlink:href="http://allserv.kahosl.be/~peter/pas/">this webpage</link> and the
+ test data comes from real world hospitals.</para>
+ </section>
+</chapter>
Property changes on: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Chapter-Use_cases_and_examples.xml
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Deleted: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Section-Use_cases_and_examples.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Section-Use_cases_and_examples.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/Chapter-Use_cases_and_examples/Section-Use_cases_and_examples.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -1,1007 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
- http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
- version="5.0" xml:base="./">
-
- <title>Use cases and examples</title>
-
- <section>
- <title>Introduction</title>
-
- <para>Drools Planner has several examples. In this manual we explain Drools Planner mainly using the n queens example.
- So it's advisable to read at least the section about that example. For advanced users, the Examination example is
- recommended.</para>
-
- <para>You can find the source code of all these examples in the drools source distribution and also in subversion
- under <literal>drools-planner/drools-planner-examples</literal>.</para>
- </section>
-
- <section>
- <title>The n queens example</title>
-
- <section>
- <title>Screenshot</title>
-
- <para>Here is a screenshot of the example:</para>
-
- <figure>
- <title>Screenshot of the n queens example</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotNQueens.png"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
- </section>
-
- <section>
- <title>Problem statement</title>
-
- <para>The <emphasis>n queens puzzle</emphasis> is a puzzle with the follow constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>Use a chessboard of n rows and n columns.</para>
- </listitem>
-
- <listitem>
- <para>Place n queens on the chessboard.</para>
- </listitem>
-
- <listitem>
- <para>No 2 queens can attack each other. Note that a queen can attack any other queen on the same horizontal,
- vertical or diagonal line.</para>
- </listitem>
- </itemizedlist>
-
- <para>The most common n queens puzzle is the 8 queens puzzle, with <emphasis>n = 8</emphasis>. We 'll explain
- Drools Planner using the 4 queens puzzle as the primary example.</para>
-
- <para>A proposed solution could be:</para>
-
- <figure>
- <title>A wrong solution for the 4 queens puzzle</title>
-
- <mediaobject>
- <imageobject>
- <imagedata align="center"
- fileref="images/Chapter-Use_cases_and_examples/partiallySolvedNQueens04Explained.png"
- format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>The above solution is wrong because queens A1 and B0 can attack each other (as can queens B0 and D0).
- Removing queen B0 would respect the "no 2 queens can attack each other" constraint, but would break the "place n
- queens" constraint.</para>
- </section>
-
- <section>
- <title>Solution(s)</title>
-
- <para>Below is a correct solution:</para>
-
- <figure>
- <title>A correct solution for the 4 queens puzzle</title>
-
- <mediaobject>
- <imageobject>
- <imagedata align="center" fileref="images/Chapter-Use_cases_and_examples/solvedNQueens04.png" format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>All the constraints have been met, so the solution is correct. Note that most n queens puzzles have multiple
- correct solutions. We 'll focus on finding a single correct solution for a given n, not on finding the number of
- possible correct solutions for a given n.</para>
- </section>
-
- <section>
- <title>Problem size</title>
-
- <para>These numbers might give you some insight on the size of this problem.</para>
-
- <table>
- <title>NQueens problem size</title>
-
- <tgroup cols="5">
- <thead>
- <row>
- <entry># queens (n)</entry>
-
- <entry># possible solutions (each queen it's own column)</entry>
-
- <entry># feasible solutions (distinct)</entry>
-
- <entry># optimal solutions (distinct)</entry>
-
- <entry># possible / # optimal</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>4</entry>
-
- <entry>256</entry>
-
- <entry>2</entry>
-
- <entry>2</entry>
-
- <entry>128</entry>
- </row>
-
- <row>
- <entry>8</entry>
-
- <entry>16777216</entry>
-
- <entry>64</entry>
-
- <entry>64</entry>
-
- <entry>262144</entry>
- </row>
-
- <row>
- <entry>16</entry>
-
- <entry>18446744073709551616</entry>
-
- <entry>14772512</entry>
-
- <entry>14772512</entry>
-
- <entry>1248720872503</entry>
- </row>
-
- <row>
- <entry>32</entry>
-
- <entry>1.46150163733090291820368483e+48</entry>
-
- <entry>?</entry>
-
- <entry>?</entry>
-
- <entry>?</entry>
- </row>
-
- <row>
- <entry>64</entry>
-
- <entry>3.94020061963944792122790401e+115</entry>
-
- <entry>?</entry>
-
- <entry>?</entry>
-
- <entry>?</entry>
- </row>
-
- <row>
- <entry>n</entry>
-
- <entry>n ^ n</entry>
-
- <entry>?</entry>
-
- <entry># feasible solutions</entry>
-
- <entry>?</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>The Drools Planner implementation has not been optimized because it functions as a beginner example.
- Nevertheless, it can easily handle 64 queens.</para>
- </section>
-
- <section>
- <title>Domain class diagram</title>
-
- <para>Use a good domain model and it will be easier to understand and solve your problem with Drools Planner. We
- 'll use this domain model for the n queens example:</para>
-
- <figure>
- <title>NQueens domain class diagram</title>
-
- <mediaobject>
- <imageobject>
- <imagedata align="center" fileref="images/Chapter-Use_cases_and_examples/nQueensDomainDiagram.png"
- format="PNG"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>A <literal>Queen</literal> instance has an x (its column, for example: 0 is column A, 1 is column B, ...)
- and a y (its row, for example: 0 is row 0, 1 is row 1, ...). Based on the x and y, the ascending diagonal line as
- well as the descending diagonal line can be calculated. The x and y indexes start from the upper left corner of
- the chessboard.</para>
-
- <table>
- <title>A solution for the 4 queens puzzle shown in the domain model</title>
-
- <tgroup cols="6">
- <thead>
- <row>
- <entry align="center">A solution</entry>
-
- <entry align="center">Queen</entry>
-
- <entry>x</entry>
-
- <entry>y</entry>
-
- <entry>ascendingD (x + y)</entry>
-
- <entry>descendingD (x - y)</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry morerows="3"><mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Use_cases_and_examples/partiallySolvedNQueens04Explained.png"
- format="PNG"></imagedata>
- </imageobject>
- </mediaobject></entry>
-
- <entry>A1</entry>
-
- <entry>0</entry>
-
- <entry>1</entry>
-
- <entry>1 (**)</entry>
-
- <entry>-1</entry>
- </row>
-
- <row>
- <entry>B0</entry>
-
- <entry>1</entry>
-
- <entry>0 (*)</entry>
-
- <entry>1 (**)</entry>
-
- <entry>1</entry>
- </row>
-
- <row>
- <entry>C2</entry>
-
- <entry>2</entry>
-
- <entry>2</entry>
-
- <entry>4</entry>
-
- <entry>0</entry>
- </row>
-
- <row>
- <entry>D0</entry>
-
- <entry>3</entry>
-
- <entry>0 (*)</entry>
-
- <entry>3</entry>
-
- <entry>3</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>A single <literal>NQueens</literal> instance contains a list of all <literal>Queen</literal> instances. It
- is the <literal>Solution</literal> implementation which will be supplied to and retrieved from the Solver.
- Notice that in the 4 queens example, NQueens's <literal>getN()</literal> method will always return 4.</para>
- </section>
- </section>
-
- <section>
- <title>The lesson schedule example</title>
-
- <section>
- <title>Screenshot</title>
-
- <para>Here is a screenshot of the example:</para>
-
- <figure>
- <title>Screenshot of the lesson schedule example</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotLessonSchedule.png"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
- </section>
-
- <section>
- <title>Problem statement</title>
-
- <para>Schedule lessons with the follow constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>No teacher with 2 lessons in the same timeslot</para>
- </listitem>
-
- <listitem>
- <para>No group with 2 lessons in the same timeslot</para>
- </listitem>
- </itemizedlist>
- </section>
- </section>
-
- <section>
- <title>The traveling tournament example</title>
-
- <section>
- <title>Screenshot</title>
-
- <para>Here is a screenshot of the example:</para>
-
- <figure>
- <title>Screenshot of the traveling tournament example</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotTravelingTournament.png"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
- </section>
-
- <section>
- <title>Problem statement</title>
-
- <para>Schedule matches between teams with the following hard constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>Each team plays twice against every other team: once home and once away</para>
- </listitem>
-
- <listitem>
- <para>Each team has exactly 1 match on each playing day</para>
- </listitem>
-
- <listitem>
- <para>No more than 3 consecutive home or 3 consecutive away matches for any team</para>
- </listitem>
-
- <listitem>
- <para>No repeaters: 2 consecutive matches of the same 2 teams (so each team plays once home and once
- away</para>
- </listitem>
- </itemizedlist>
-
- <para>and the following soft constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>Minimize the total distance traveled of all teams.</para>
- </listitem>
- </itemizedlist>
-
- <para><link xlink:href="http://mat.gsia.cmu.edu/TOURN/">You can find a detailed description as well as several
- records of this problem here.</link></para>
- </section>
-
- <section>
- <title>Simple and smart implementation</title>
-
- <para>There are 2 implementations (simple and smart) to demonstrate the importance of some performance tips. The
- <literal>ExamplesApp</literal> always runs the smart implementation, but with these commands you can compare the 2
- implementations yourself:</para>
-
- <programlisting>$ mvn exec:exec -Dexec.mainClass="org.drools.planner.examples.travelingtournament.app.simple.SimpleTravelingTournamentApp"
-...
-$ mvn exec:exec -Dexec.mainClass="org.drools.planner.examples.travelingtournament.app.smart.SmartTravelingTournamentApp"
-...</programlisting>
-
- <para>The smart implementation performs and scales exponentially better than the simple implementation.</para>
- </section>
-
- <section>
- <title>Problem size</title>
-
- <para>These numbers might give you some insight on the size of this problem.</para>
-
- <table>
- <title>Traveling tournament problem size</title>
-
- <tgroup cols="7">
- <thead>
- <row>
- <entry># teams</entry>
-
- <entry># days</entry>
-
- <entry># matches</entry>
-
- <entry># possible solutions (simple)</entry>
-
- <entry># possible solutions (smart)</entry>
-
- <entry># feasible solutions</entry>
-
- <entry># optimal solutions</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>4</entry>
-
- <entry>6</entry>
-
- <entry>12</entry>
-
- <entry>2176782336</entry>
-
- <entry><= 518400</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>6</entry>
-
- <entry>10</entry>
-
- <entry>30</entry>
-
- <entry>1000000000000000000000000000000</entry>
-
- <entry><= 47784725839872000000</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>8</entry>
-
- <entry>14</entry>
-
- <entry>56</entry>
-
- <entry>1.52464943788290465606136043e+64</entry>
-
- <entry><= 5.77608277425558771434498864e+43</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>10</entry>
-
- <entry>18</entry>
-
- <entry>90</entry>
-
- <entry>9.43029892325559280477052413e+112</entry>
-
- <entry><= 1.07573451027871200629339068e+79</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>12</entry>
-
- <entry>22</entry>
-
- <entry>132</entry>
-
- <entry>1.58414112478195320415135060e+177</entry>
-
- <entry><= 2.01650616733413376416949843e+126</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>14</entry>
-
- <entry>26</entry>
-
- <entry>182</entry>
-
- <entry>3.35080635695103223315189511e+257</entry>
-
- <entry><= 1.73513467024013808570420241e+186</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>16</entry>
-
- <entry>30</entry>
-
- <entry>240</entry>
-
- <entry>3.22924601799855400751522483e+354</entry>
-
- <entry><= 2.45064610271441678267620602e+259</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>n</entry>
-
- <entry>2 * (n - 1)</entry>
-
- <entry>n * (n - 1)</entry>
-
- <entry>(2 * (n - 1)) ^ (n * (n - 1))</entry>
-
- <entry><= (((2 * (n - 1))!) ^ (n / 2))</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </section>
- </section>
-
- <section>
- <title>The ITC 2007 examination example</title>
-
- <section>
- <title>Screenshot</title>
-
- <para>Here is a screenshot of the example:</para>
-
- <figure>
- <title>Screenshot of the examination example</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Use_cases_and_examples/screenshotExamination.png"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
- </section>
-
- <section>
- <title>Problem statement</title>
-
- <para>Schedule each exam into a period and into a room. Multiple exams can share the same room during the same
- period.</para>
-
- <para>There are a number of hard constraints that cannot be broken:</para>
-
- <itemizedlist>
- <listitem>
- <para>Exam conflict: 2 exams that share students should not occur in the same period.</para>
- </listitem>
-
- <listitem>
- <para>Room capacity: A room's seating capacity should suffice at all times.</para>
- </listitem>
-
- <listitem>
- <para>Period duration: A period's duration should suffice for all of its exams.</para>
- </listitem>
-
- <listitem>
- <para>Period related hard constraints should be fulfilled:</para>
-
- <itemizedlist>
- <listitem>
- <para>Coincidence: 2 exams should use the same period (but possibly another room).</para>
- </listitem>
-
- <listitem>
- <para>Exclusion: 2 exams should not use the same period.</para>
- </listitem>
-
- <listitem>
- <para>After: 1 exam should occur in a period after another exam's period.</para>
- </listitem>
- </itemizedlist>
- </listitem>
-
- <listitem>
- <para>Room related hard constraints should be fulfilled:</para>
-
- <itemizedlist>
- <listitem>
- <para>Exclusive: 1 exam should not have to share its room with any other exam.</para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
-
- <para>There are also a number of soft constraints that should be minimized (each of which has parameterized
- penalty's):</para>
-
- <itemizedlist>
- <listitem>
- <para>2 exams in a row.</para>
- </listitem>
-
- <listitem>
- <para>2 exams in a day.</para>
- </listitem>
-
- <listitem>
- <para>Period spread: 2 exams that share students should be a number of periods apart.</para>
- </listitem>
-
- <listitem>
- <para>Mixed durations: 2 exams that share a room should not have different durations.</para>
- </listitem>
-
- <listitem>
- <para>Front load: Large exams should be scheduled earlier in the schedule.</para>
- </listitem>
-
- <listitem>
- <para>Period penalty: Some periods have a penalty when used.</para>
- </listitem>
-
- <listitem>
- <para>Room penalty: Some rooms have a penalty when used.</para>
- </listitem>
- </itemizedlist>
-
- <para>It uses large test data sets of real-life universities.</para>
-
- <para><link xlink:href="http://www.cs.qub.ac.uk/itc2007/examtrack/exam_track_index.htm">You can find a more
- detailed description of this problem here.</link></para>
- </section>
-
- <section>
- <title>Problem size</title>
-
- <para>These numbers might give you some insight on the size of this problem.</para>
-
- <table>
- <title>Examination problem size</title>
-
- <tgroup cols="8">
- <thead>
- <row>
- <entry>Set</entry>
-
- <entry># students</entry>
-
- <entry># exams/topics</entry>
-
- <entry># periods</entry>
-
- <entry># rooms</entry>
-
- <entry># possible solutions</entry>
-
- <entry># feasible solutions</entry>
-
- <entry># optimal solutions</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>exam_comp_set1</entry>
-
- <entry>7883</entry>
-
- <entry>607</entry>
-
- <entry>54</entry>
-
- <entry>7</entry>
-
- <entry>10^1564</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set2</entry>
-
- <entry>12484</entry>
-
- <entry>870</entry>
-
- <entry>40</entry>
-
- <entry>49</entry>
-
- <entry>10^2864</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set3</entry>
-
- <entry>16365</entry>
-
- <entry>934</entry>
-
- <entry>36</entry>
-
- <entry>48</entry>
-
- <entry>10^3023</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set4</entry>
-
- <entry>4421</entry>
-
- <entry>273</entry>
-
- <entry>21</entry>
-
- <entry>1</entry>
-
- <entry>10^360</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set5</entry>
-
- <entry>8719</entry>
-
- <entry>1018</entry>
-
- <entry>42</entry>
-
- <entry>3</entry>
-
- <entry>10^2138</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set6</entry>
-
- <entry>7909</entry>
-
- <entry>242</entry>
-
- <entry>16</entry>
-
- <entry>8</entry>
-
- <entry>10^509</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set7</entry>
-
- <entry>13795</entry>
-
- <entry>1096</entry>
-
- <entry>80</entry>
-
- <entry>28</entry>
-
- <entry>10^3671</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>exam_comp_set8</entry>
-
- <entry>7718</entry>
-
- <entry>598</entry>
-
- <entry>80</entry>
-
- <entry>8</entry>
-
- <entry>10^1678</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
-
- <row>
- <entry>?</entry>
-
- <entry>s</entry>
-
- <entry>t</entry>
-
- <entry>p</entry>
-
- <entry>r</entry>
-
- <entry>(p * r) ^ e</entry>
-
- <entry>?</entry>
-
- <entry>1?</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>Geoffrey De Smet (the Drools Planner lead) finished 4th in the International Timetabling Competition 2007's
- examination track with a very early version of Drools Planner. Many improvements have been made since then.</para>
- </section>
-
- <section>
- <title>Domain class diagram</title>
-
- <para>Below you can see the main examination domain classes:</para>
-
- <figure>
- <title>Examination domain class diagram</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/Chapter-Use_cases_and_examples/examinationDomainDiagram.png"></imagedata>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Notice that we've split up the exam concept into an <literal>Exam</literal> class and a
- <literal>Topic</literal> class. The <literal>Exam</literal> instances change during solving, when they get another
- period or room property. The <literal>Topic</literal>, <literal>Period</literal> and <literal>Room</literal>
- instances never change during solving.</para>
- </section>
- </section>
-
- <section>
- <title>The ITC 2007 curriculum course example</title>
-
- <section>
- <title>Problem statement</title>
-
- <para>Schedule lectures into rooms and time periods.</para>
-
- <para><link xlink:href="http://www.cs.qub.ac.uk/itc2007/curriculmcourse/course_curriculm_index.htm">You can find a
- more detailed description of this problem here.</link></para>
- </section>
- </section>
-
- <section>
- <title>The Manners 2009 example</title>
-
- <section>
- <title>Problem statement</title>
-
- <para>In Manners 2009, miss Manners is throwing a party again.</para>
-
- <itemizedlist>
- <listitem>
- <para>This time she invited 144 guests and prepared 12 round tables with 12 seats each.</para>
- </listitem>
-
- <listitem>
- <para>Every guest should sit next to someone (left and right) of the opposite gender.</para>
- </listitem>
-
- <listitem>
- <para>And that neighbour should have at least one hobby in common with the guest.</para>
- </listitem>
-
- <listitem>
- <para>Also, this time there should be 2 politicians, 2 doctors, 2 socialites, 2 sports stars, 2 teachers and 2
- programmers at each table.</para>
- </listitem>
-
- <listitem>
- <para>And the 2 politicians, 2 doctors, 2 sports stars and 2 programmers shouldn't be the same kind.</para>
- </listitem>
- </itemizedlist>
- </section>
- </section>
-
- <section>
- <title>Patient admission scheduling (PAS)</title>
-
- <para>In this problem, we have to assign each patient (that will come to the hospital) a bed for each night that the
- patient will stay in the hospital. Each bed belongs to a room and each room belongs to a department. The arrival and
- departure dates of the patients is fixed: only a bed needs to be assigned for each night.</para>
-
- <para>There are a couple of hard constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>2 patients shouldn't be assigned to the same bed in the same night.</para>
- </listitem>
-
- <listitem>
- <para>A room can have a gender limitation: only females, only males, the same gender in the same night or no
- gender limitation at all.</para>
- </listitem>
-
- <listitem>
- <para>A departement can have a minimum or maximum age.</para>
- </listitem>
-
- <listitem>
- <para>A patient can require a room with specific equipment(s).</para>
- </listitem>
- </itemizedlist>
-
- <para>And of course, there are also some soft constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para>A patient can prefer a maximum room size, for example if he/she want a single room.</para>
- </listitem>
-
- <listitem>
- <para>A patient is best assigned to a department that specializes in his/her problem.</para>
- </listitem>
-
- <listitem>
- <para>A patient is best assigned to a room that specializes in his/her problem.</para>
- </listitem>
-
- <listitem>
- <para>A patient can prefer a room with specific equipment(s).</para>
- </listitem>
- </itemizedlist>
-
- <para>The problem is defined on <link xlink:href="http://allserv.kahosl.be/~peter/pas/">this webpage</link> and the
- test data comes from real world hospitals.</para>
- </section>
-</chapter>
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/master.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/master.xml 2009-12-25 14:00:30 UTC (rev 30822)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-planner/src/main/docbook/en-US/master.xml 2009-12-25 14:05:09 UTC (rev 30823)
@@ -20,17 +20,17 @@
</author>
</info>
- <xi:include href="Chapter-Planner_introduction/Section-Planner_introduction.xml" />
+ <xi:include href="Chapter-Planner_introduction/Chapter-Planner_introduction.xml" />
- <xi:include href="Chapter-Use_cases_and_examples/Section-Use_cases_and_examples.xml" />
+ <xi:include href="Chapter-Use_cases_and_examples/Chapter-Use_cases_and_examples.xml" />
- <xi:include href="Chapter-Planner_configuration/Section-Planner_configuration.xml" />
+ <xi:include href="Chapter-Planner_configuration/Chapter-Planner_configuration.xml" />
- <xi:include href="Chapter-Score_calculation/Section-Score_calculation.xml" />
+ <xi:include href="Chapter-Score_calculation/Chapter-Score_calculation.xml" />
- <xi:include href="Chapter-Local_search/Section-Local_search.xml" />
+ <xi:include href="Chapter-Local_search/Chapter-Local_search.xml" />
- <xi:include href="Chapter-Benchmarking_and_tweaking/Section-Benchmarking_and_tweaking.xml" />
+ <xi:include href="Chapter-Benchmarking_and_tweaking/Chapter-Benchmarking_and_tweaking.xml" />
<index/>
</book>
More information about the jboss-svn-commits
mailing list