diff --git a/source/_static/cumulative-decomposition.png b/source/_static/cumulative-decomposition.png
new file mode 100644
index 0000000..c04ab91
Binary files /dev/null and b/source/_static/cumulative-decomposition.png differ
diff --git a/source/_static/cumulative_binary.png b/source/_static/cumulative_binary.png
new file mode 100644
index 0000000..261a2cb
Binary files /dev/null and b/source/_static/cumulative_binary.png differ
diff --git a/source/_static/discrepancy-search.svg b/source/_static/discrepancy-search.svg
new file mode 100644
index 0000000..2dd82d0
--- /dev/null
+++ b/source/_static/discrepancy-search.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/source/_static/vrp-search.svg b/source/_static/vrp-search.svg
new file mode 100644
index 0000000..b816bb2
--- /dev/null
+++ b/source/_static/vrp-search.svg
@@ -0,0 +1,3 @@
+
+
+
6
6
8
8
12
12
4
4
7
7
10
10
3
3
s0
s0
5
5
s1
s1
9
9
11
11
s2
s2
t0
t0
t1
t1
t2
t2
\ No newline at end of file
diff --git a/source/learning_minicp/exercises.rst b/source/learning_minicp/exercises.rst
index 9cc09a2..632b9f7 100644
--- a/source/learning_minicp/exercises.rst
+++ b/source/learning_minicp/exercises.rst
@@ -34,7 +34,7 @@ Of course you should get a strong inspiration from the
`TableCT.java `_
implementation you did in a previous exercise.
-Check that your implementation passes the tests `NegTableTest.java `_
+Verify that your implementation passes the tests of `NegTableTest.java `_
diff --git a/source/learning_minicp/part_1.rst b/source/learning_minicp/part_1.rst
index 141981a..20b8c24 100644
--- a/source/learning_minicp/part_1.rst
+++ b/source/learning_minicp/part_1.rst
@@ -40,23 +40,36 @@ Less-or-equal Reified Constraint
Implement `IsLessOrEqual.java `_.
-This is a propagator for the constraint `b iff x <= c`, which is called the `reified constraint` (or: `reification`) of the constraint `x <= c`: it holds if Boolean variable `b` is true if and only if variable `x` is less than or equal to value `c`.
+This is a propagator for the constraint :math:`b \Leftrightarrow x \leq c`, which is called the `reified constraint` (or: `reification`) of the constraint :math:`x \leq c`: it holds if the value of Boolean variable :math:`b` is true if and only if the value of variable :math:`x` is less than or equal to the value :math:`c`.
For example, the constraint holds for
-.. code-block:: java
+.. math::
- b = true , x = 4, c = 5
- b = false, x = 4, c = 2
+ \text{Dom}(b) = \{\mathit{true}\} , \text{Dom}(x) = \{4\}, c = 5
+
+and
+
+.. math::
+
+ \text{Dom}(b) = \{\mathit{false}\}, \text{Dom}(x) = \{4\}, c = 2
but is violated for
-.. code-block:: java
+.. math::
+
+ \text{Dom}(b) = \{\mathit{true}\} , \text{Dom}(x) = \{5\}, c = 4
+
+and violated for
+
+.. math::
+
+ \text{Dom}(b) = \{\mathit{false}\}, \text{Dom}(x) = \{2\}, c = 4
+
- b = true , x = 5, c = 4
- b = false, x = 2, c = 4
+where the function :math:`\text{Dom}` returns the domain of the given variable.
-For an example of reification, you can look at `IsEqual.java `_.
+**Hint**: use `IsEqual.java `_ as a reference when implementing the constraint.
-Check that your implementation passes the tests `IsLessOrEqualTest.java `_.
+Verify that your implementation passes the tests of `IsLessOrEqualTest.java `_.
diff --git a/source/learning_minicp/part_10.rst b/source/learning_minicp/part_10.rst
index fa2df25..39277e9 100644
--- a/source/learning_minicp/part_10.rst
+++ b/source/learning_minicp/part_10.rst
@@ -32,7 +32,22 @@ Your task is to make the Disjunctive constraint more efficient than by using the
This will be useful for implementing the decomposition of the Disjunctive constraint.
* Test your implementation in `IsLessOrEqualVarTest.java. `_.
* Implement the decomposition with reified constraints for `Disjunctive.java. `_.
-* Make sure your implementation passes all the tests *except* `testOverloadChecker`, `testDetectablePrecedence`, and `testNotLast` (those are for the programming exercise below) in `DisjunctiveTest.java `_.
+ For each pair of tasks, :math:`i` and :math:`j`, with :math:`i \neq j`, the binary decomposition constrains the two tasks not to overlap in time:
+
+ * either task :math:`i` ends before task :math:`j` starts (:math:`b_{ij} \Leftrightarrow e_i \leq s_j`) or
+ * task :math:`j` ends before task :math:`i` starts (:math:`b_{ji} \Leftrightarrow e_j \leq s_i`),
+
+ with :math:`b_{ij} \neq b_{ji}`.
+
+ .. image:: ../_static/cumulative-decomposition.png
+ :width: 574
+ :alt: cumulative decomposition
+ :align: center
+
+
+ Task `j` cannot end before task `i` starts since :math:`e_j \leq s_i` does not hold (:math:`b_{ji} = \mathit{false}`).
+
+* Verify that your implementation passes the tests `testAllDiffDisjunctive`, `testNotRemovingSolutions`, and `testBinaryDecomposition` of `DisjunctiveTest.java `_.
* Test whether, as expected, this decomposition prunes more than the formulation with timetable filtering for the Cumulative constraint.
For example, observe on `JobShop.java `_ that the number of backtracks is reduced with the decomposition compared to the formulation with Cumulative.
Test for instance on the small instance `data/jobshop/sascha/jobshop-4-4-2` with 4 jobs, 4 machines, and 16 activities.
@@ -46,9 +61,30 @@ The Global Disjunctive Constraint: Overload Checker, Detectable Precedence, and
To make sure you understand it, add a unit test with 4 activities and compare the results with a manual computation.
* Overload checking, detectable precedences, not-first-not-last, and edge finding only filter one side of the activities.
To get the symmetrical filtering, implement the mirroring activities trick similarly to `Cumulative.java `_.
+* **Hint**: overload checking, detectable precedences, and not-last all require an array `permEst` that is a permutation of the indices of the activities sorted increasingly by their earliest starting times
+ (`permEst[0]` holds the activity with the smallest earliest starting time, while `permEst[n - 1]` holds the activity with the greatest earliest starting time), as well as an
+ array `rankEst` that is the inverse of `permEst` (if `permEst[j] = i`, then `rankEst[i] = j`).
+
+ Create a helper method that sorts the array `permEst` and updates the array `rankEst` (both arrays are preferably instance variables of the `Disjunctive` class).
* Implement the overload checker in `Disjunctive.java `_.
+
+ Verify that your implementation passes the test `testOverloadChecker` of `DisjunctiveTest.java `_.
* The overload checker should already make a big difference to prune the search tree. Make sure that larger job-shop instances are now solved faster; for instance, `data/jobshop/sascha/jobshop-6-6-0` should now become easy to solve.
* Implement detectable precedences in `Disjunctive.java `_.
+
+ **Note:** given activity `i`, when updating the temporary earliest start time integer value:
+
+ .. math::
+
+ est^{\prime}_{i} \leftarrow \max (est_{i}, ect_{\theta \setminus \{i\}})
+
+ if the activity `i` has already been added to the theta tree, then it must first be removed before updating :math:`est^{\prime}_{i}` and reinserted again after updating :math:`est^{\prime}_{i}` (as indicated by :math:`\theta \setminus \{i\}`).
+
+ Verify that your implementation passes the test `testDetectablePrecedence` of `DisjunctiveTest.java `_.
+
* Implement not-first-not-last in `Disjunctive.java `_.
-* Make sure your implementation passes the tests `DisjunctiveTest.java `_.
+
+ Make sure your implementation passes the test `testNotLast` of `DisjunctiveTest.java `_.
+
+* Make sure your implementation passes all tests in `DisjunctiveTest.java `_.
* (optional) Implement edge finding in `Disjunctive.java `_ (you will also need to implement the ThetaLambdaTree data structure).
diff --git a/source/learning_minicp/part_2.rst b/source/learning_minicp/part_2.rst
index 472bb7a..e0c36fe 100644
--- a/source/learning_minicp/part_2.rst
+++ b/source/learning_minicp/part_2.rst
@@ -30,16 +30,16 @@ Implement the missing constructor in `IntVarImpl.java `_.
+Verify that your implementation passes the tests of `IntVarTest.java `_.
Implement a Domain Iterator
======================================
Many filtering algorithms require iteration over the values of a domain.
-A naive (but correct) way of iterating over a domain is:
+A naive (and correct) way of iterating over the values of a domain is:
.. code-block:: java
@@ -50,25 +50,23 @@ A naive (but correct) way of iterating over a domain is:
}
}
-This method is rather inefficient because it will also consider the values that are not present in the domain.
+This method is rather inefficient as it will (possibly) iterate over values that are not present in the domain.
Instead, the `fillArray` method from `StateSparseSet.java `_
-allows filling an array with all the values present in the sparse set.
-In case of an offset value of 0, you could even use the very efficient `System.arraycopy`.
-
-The main advantage over the iterator mechanism is that no object is created (and thus garbage collected).
-Indeed `dest` is typically a container array stored as an instance variable and reused many times.
-It is important for efficiency to avoid creating objects on the heap at each execution of a propagator.
-Never forget that a `propagate()` method of `Constraint` may be called thousands of times per second.
-This implementation using `fillArray` avoids the `ConcurrentModificationException` discussion
-when implementing an Iterator: should we allow modifying a domain while iterating on it?
-The answer here is very clear: you get a snapshot of the domain at the time of the call to `fillArray` and you can thus
-safely iterate over this `dest` array and modify the domain at the same time.
+allows filling an array only with the values present in the sparse set.
+Additionally, if the offset is 0, then the very efficient method `System.arraycopy` can be used.
+
+If the array that stores the returned array of the method `fillArray` is an instance variable, then it will not be garbage collected by the java garbage collector, resulting in a very efficient implementation.
+It is important for efficiency to avoid creating objects on the heap (such as arrays) at each execution of propagators that need to be garbage collected,
+as the `propagate()` method of a constraint can be called thousands of times every second.
+
+Since the implementation using `fillArray` iterates on a copy of the array containing the domain, any modification on the actual domain will not carry over to the copy, and vice versa, removing any
+`ConcurrentModificationException` exceptions that might otherwise have been thrown.
To do:
-* Improve the efficiency of `fillArray` from `StateSparseSet.java `_ in order to use `System.arraycopy` when possible.
+* Improve the efficiency of `fillArray` from `StateSparseSet.java `_, using `System.arraycopy` where possible.
* Implement `public int fillArray(int [] dest)` in `IntVarImpl.java `_.
-* Check that your implementation passes the tests `IntVarTest.java `_ and `StateSparseSetTest.java `_. Additionally, add more tests to `IntVarTest.java `_.
+* Verify that your implementation passes the tests of `IntVarTest.java `_ and `StateSparseSetTest.java `_. Additionally, add more tests to `IntVarTest.java `_.
The Absolute Value Constraint
==============================
@@ -80,7 +78,7 @@ Several directions of implementation are possible:
1. The full domain-consistent version (use the `fillArray` method to iterate over domains).
2. A hybrid domain-bound consistent one.
-Check that your implementation passes the tests `AbsoluteTest.java `_.
+Verify that your implementation passes the tests of `AbsoluteTest.java `_.
The Maximum Constraint
@@ -90,4 +88,6 @@ Implement `Maximum.java `_.
+**Hint**: Given :math:`y = \max (X)`, where :math:`X` is an array of variables, what are the lower and upper bounds of :math:`y`?
+
+Verify that your implementation passes the tests of `MaximumTest.java `_.
diff --git a/source/learning_minicp/part_3.rst b/source/learning_minicp/part_3.rst
index eff9d9b..d007761 100644
--- a/source/learning_minicp/part_3.rst
+++ b/source/learning_minicp/part_3.rst
@@ -38,13 +38,20 @@ Consider the following search tree where branches to execute are represented as
:align: center
-A DFS exploration should execute the above branches in the following sequence `A, D, E, B, C, F, G`.
+A DFS exploration should execute the above branches in the following sequence `A, D, E, B, C, F, G`, where executing a branch
+means:
+1. performing the variable and value selection associated with the branch (most often fixing a variable to a value, or removing the value from the domain of a variable)
+2. propagating all constraints until fix-point is reached.
+
When backtracking, the previous state must be restored, requiring that the state is saved with the
-`save` operation before the branch is executed and restored with the `restore` operation when the branch terminates.
-For example; a valid sequence that successfully saves and restores the state when backtracking is:
-`save->A->save->D->restore->save->E->restore->restore->save->B->restore->save->C->save->F->restore->save->G->restore->restore`.
-Note that the state manager performs a `save` operation prior to searching and a `restore` operation after search
-concludes. The `save` operation is executed in pre-order fashion while the `restore` operation is executed in a post-order fashion.
+`save` operation before the branch is executed and restored with the `restore` operation when the branch finishes terminating.
+The `save` operation is executed in pre-order fashion while the `restore` operation is executed in a post-order fashion.
+
+For example; given the figure above, a valid sequence that successfully saves and restores the state when backtracking is:
+`save⮕A⮕save⮕D⮕restore⮕save⮕E⮕restore⮕restore⮕save⮕B⮕restore⮕save⮕C⮕save⮕F⮕restore⮕save⮕G⮕restore⮕restore`.
+
+Note that the state manager performs a `save` operation prior to searching (before any branching is performed) and a `restore` operation after search
+concludes.
The following code snippet shows a recursive implementation. Note that the saving and restoring of states is performed
in the method `withNewState` of the state manager `sm`:
@@ -80,8 +87,7 @@ in the method `withNewState` of the state manager `sm`:
}
}
-Skeleton code for a solution is given below. However, there are many possible implementations, so feel free to not use
-the skeleton code.
+Skeleton code is given below. However, there are many possible implementations, so feel free to not use the skeleton code.
.. code-block:: java
:emphasize-lines: 6
@@ -119,13 +125,13 @@ If such an exception is caught, then the number of failures is to be increased,
the failure is to be notified, and no sub-branches of the corresponding branch are to be expanded.
-Check that your implementation passes the tests `DFSearchTest.java `_.
+Verify that your implementation passes the tests of `DFSearchTest.java `_.
Remark (optional): It is possible to reduce the number of operations by skipping the save and restore
operations for the for the last branch of any node (the branches B, C, E, and G in the
example above).
-The sequence of operations becomes `save->A->save->D->restore->E->restore->save->B->restore->C->save->F->restore->G`.
-As stated above, the state manager will perform a save operation before searching and a restore operation once searching
+The sequence of operations becomes `save⮕A⮕save⮕D⮕restore⮕E⮕restore⮕save⮕B⮕restore⮕C⮕save⮕F⮕restore⮕G`.
+As stated above, the state manager will perform a save operation before the search starts and a restore operation once the search
concludes.
Implement a Custom Search
@@ -136,8 +142,9 @@ constraint of :ref:`Part 4: Sum and Element Constraints`), modify the model `QAP
`_,
where variable `x[i]` denotes the location of facility `i`,
in order to implement a custom search strategy (and ignore the
-instructions on discrepancy search). A skeleton code for a custom search is as follows:
+instructions on discrepancy search).
+Here follows some skeleton code for a custom search heuristic of the quadratic assignment problem:
.. code-block:: java
@@ -155,23 +162,29 @@ instructions on discrepancy search). A skeleton code for a custom search is as f
);
});
+To do:
+
+1. Find a pair of integers `i` and `j` (representing facilities `i` and `j`), with `i != j`, where `x[i]` is unfixed (a facility not yet assigned to a location) and `x[j]` is fixed or unfixed, that has maximum weight `w[i][j]`.
+2. Find a pair of integers `k` and `l` (representing the locations of facilities `i` and `j` respectively), with minimum distance `distances[k][l]`.
+
+* As a variable selection heuristic, select facility `x[i]`.
+* As a value selection heuristic, select location `k`.
+* On the first branch, fix `x[i]` to `k` and on the second branch, remove the value `k` from the domain of `x[i]`.
-* As a variable selection heuristic, select an unfixed variable `x[i]` (a facility `i` not yet assigned to a location) that has a maximum weight `w[i][j]` with another facility `j` (where `x[j]` may be fixed or not).
-* As a value selection heuristic, on the left branch place this facility on a location :math:`k` which is the closest possible to another location possible for the facility `j` you selected earlier. On the right branch remove the value :math:`k`.
-* Hint: `selectMin` is a generic method parameterized by 'T' and 'N' (the type on which the minimum is computed). To implement this heuristic, adding pairs `(i,j)` as a type for `T` is probably the easiest way to go:
+**Hint**: `selectMin` is a generic method parameterized by 'T' and 'N' (the type on which the minimum is computed). To implement this heuristic, adding pairs `(i,j)` as a type for `T` is probably the easiest way to go:
.. code-block:: java
public static > T selectMin(T[] x, Predicate p, Function f)
-Check that your implementation passes the tests `QAPTest.java `_.
+Verify that your implementation passes the tests of `QAPTest.java `_.
Sequencer Combinator
======================
-Sometimes we wish to branch in a given order on two families of variables, say `x[]` and then `y[]`, as shown in the next picture.
-A variable in `y` should not be branched on before all the variables in `x` have been fixed.
+Sometimes we wish to branch in a given order on two arrays of variables, say `x[]` and then `y[]`, as shown in the next picture.
+A variable in `y` should not be branched on before there are no more variables in `x` to branch on (most often when all variables in `x` are fixed).
Furthermore, we may want to apply a specific heuristic on `x` that is different from the heuristic we want to apply on `y`:
@@ -192,7 +205,7 @@ This can be achieved as follows:
The `and` factory method creates a `Sequencer.java `_.
You must complete its implementation.
-Check that your implementation passes the tests `SequencerTest.java `_.
+Verify that your implementation passes the tests of `SequencerTest.java `_.
Check on INGInious
diff --git a/source/learning_minicp/part_4.rst b/source/learning_minicp/part_4.rst
index 3a671b1..087a7f3 100644
--- a/source/learning_minicp/part_4.rst
+++ b/source/learning_minicp/part_4.rst
@@ -24,36 +24,46 @@ Theoretical Questions
Element1D Constraint
=================================
-Given an array `T` of integers and the variables `y` and `z`, the `Element1D` constraint enforces that `z` takes the value at index
-`y` of `T`: the relation `T[y]=z` must hold (where indexing starts from 0).
+Given an array :math:`T` of integers and the variables :math:`y` and :math:`z`, the `Element1D` constraint enforces that :math:`z` takes the value at index
+:math:`y` of :math:`T`: the relation :math:`T[y]=z` must hold (where indexing starts from 0).
-Assuming `T=[1,3,5,7,3]`, the constraint holds for
+Given the element constraint :math:`T=[1,3,5,7,3]`, the constraint holds for
-.. code-block:: java
+.. math::
+
+ \text{Dom}(y) = \{1\}, \text{Dom}(z) = \{3\}
- y = 1, z = 3
- y = 3, z = 7
+and
+
+.. math::
+
+ \text{Dom}(y) = \{3\}, \text{Dom}(z) = \{7\}
but is violated for
-.. code-block:: java
+.. math::
+
+ \text{Dom}(y) = \{0\}, \text{Dom}(z) = \{2\}
+
+and violated for
+
+.. math::
- y = 0, z = 2
- y = 3, z = 3
+ \text{Dom}(y) = \{3\}, \text{Dom}(z) = \{3\}
Implement a propagator
`Element1D.java `_
by following the ideas (also in the slides) for `Element2D`,
which however do not lead to domain consistency for both variables.
-Check that your implementation passes the tests
-`Element1DTest.java `_.
+
+Verify that your implementation passes the tests of `Element1DTest.java `_.
Also implement a propagator
`Element1DDomainConsistent.java `_
that achieves domain consistency for both variables.
-Check that your implementation passes the tests
-`Element1DDCTest.java `_.
+
+Verify that your implementation passes the tests of `Element1DDCTest.java `_.
Element1DVar Constraint with an Array of Variables
@@ -62,23 +72,26 @@ Element1DVar Constraint with an Array of Variables
Implement a propagator
`Element1DVar.java `_.
This constraint is more general than `Element1D` above,
-since `T` is here an array of variables.
+since :math:`T` is here an array of variables.
The filtering algorithm is nontrivial,
at least if you want to do it efficiently.
Two directions of implementation are:
* The hybrid domain-bound consistent propagator
- achieves bounds consistency for `z` and all the `T[i]`
- but domain consistency for `y`.
+ achieves bounds consistency for :math:`z` and all the :math:`T[i]`
+ but domain consistency for :math:`y` (recommended).
* The domain-consistent propagator
- achieves domain consistency for `y`, `z`, and all the `T[i]`.
+ achieves domain consistency for :math:`y`, :math:`z`, and all the :math:`T[i]`.
-Check that your implementation passes the tests
-`Element1DVarTest.java `_.
-Those tests do not check that your propagator achieves domain
+Note: given :math:`T=[x_0, x_1]`, :math:`\text{Dom}(x_0)=\{3, 4\}`, :math:`\text{Dom}(x_1)=\{4, 5\}`, :math:`\text{Dom}(y)=\{0, 1\}`, and :math:`\text{Dom}(z)={4}`, the value :math:`3` **cannot** be removed from the domain of :math:`x_0`
+and the value :math:`5` **cannot** be removed from :math:`x_1`. However, when :math:`y` becomes fixed, say to :math:`0`, then :math:`3` is to be removed from the
+domain of :math:`x_0` (the same is true when :math:`y` becomes fixed to :math:`1`, for the value :math:`5` and the variable :math:`x_1`).
+
+Verify that your implementation passes the tests of `Element1DVarTest.java `_.
+The tests do not verify that your propagator achieves domain
consistency for all the variables, so you have to write additional tests
-in order to help convince yourself that it does so, if you take that direction.
+in order to verify that your implementation is correct if you are implementing the domain-consistent propagator.
The Stable Matching Problem
@@ -88,4 +101,5 @@ Complete the partial model `StableMatching.java `_.
+
+Verify that your implementation passes the tests of `StableMatchingTest.java `_.
diff --git a/source/learning_minicp/part_5.rst b/source/learning_minicp/part_5.rst
index 57ed879..a29d6fb 100644
--- a/source/learning_minicp/part_5.rst
+++ b/source/learning_minicp/part_5.rst
@@ -52,6 +52,7 @@ For your implementation, use the following arrays of stateful integers as the da
where:
+* The domain of `x[i]` is the set containing all potential successors nodes of `i`;
* `dest[i]` is the last (non-fixed) node that can be reached from node `i` if node `i` is fixed and on a partial path; otherwise it is `i`;
* `orig[i]` is the first (fixed) node that can reach node `i` if node `i` is on a partial path; otherwise it is `i`;
* `lengthToDest[i]` is the length of the partial path from node `i` to node `dest[i]` if node `i` is on a partial path; otherwise it is 0.
@@ -63,8 +64,7 @@ Consider the following example where edges originating from fixed nodes are colo
:alt: Circuit
:align: center
-Before node 5 has been fixed, the green edge has not yet been added,
-so we have:
+Before node 5 has been fixed (the green edge has not yet been added), we have (by abuse of notation):
.. code-block:: java
@@ -72,7 +72,7 @@ so we have:
orig = [0,1,0,4,4,4];
lengthToDest = [1,0,0,1,2,0];
-After node 5 has been fixed, the green edge has been added, so we have:
+After node 5 has been fixed (the green edge has been added), we have (by abuse of notation):
.. code-block:: java
@@ -82,18 +82,17 @@ After node 5 has been fixed, the green edge has been added, so we have:
In your implementation, you must update the stateful integers in order
to reflect the changes after the addition of new edges to the circuit.
-An edge is added whenever a node becomes fixed: you can use the `CPIntVar.whenBind(...)` method to run some code block
-when this event occurs.
+An edge is to be added whenever a node becomes fixed: you can use the `CPIntVar.whenFixed(p)` method to execute the some procedure `p` when this event occurs.
-The filtering algorithm is to prevent closing each
-partial path that would have a length less than `n` (the total number of nodes) as that would result in a non-Hamiltonian circuit.
+The filtering algorithm is to prevent creating sub-circuits (any circuit that does not contain all nodes), as that would result in a non-Hamiltonian circuit.
Since node 4 (the origin of a partial path) has a length to its destination (node 2) of 4 (<6), the destination node 2 cannot
have the origin node 4 as a successor and the red edge is deleted.
This filtering was introduced in [TSP1998]_ for solving the traveling
salesperson problem (TSP) with CP.
Implement a propagator `Circuit.java `_.
-Check that your implementation passes the tests `CircuitTest.java `_.
+
+Verify that your implementation passes the tests of `CircuitTest.java `_.
.. [TSP1998] Pesant, G., Gendreau, M., Potvin, J. Y., & Rousseau, J. M. (1998). An exact constraint logic programming algorithm for the traveling salesman problem with time windows. Transportation Science, 32(1), 12-29.
@@ -126,17 +125,17 @@ vehicle routing problem (VRP) in general.
The one you design should be more similar to the decision you would
make in a greedy algorithm.
For instance, you can select as a successor for `xi`
-a closest city in its domain.
+a closest node in its domain.
-Hint: Since there is no iterator on the domain of a variable, you can
+**Hint**: Since there is no iterator on the domain of a variable, you can
iterate from its minimum value to its maximum one by using a `for` loop
and checking that the value of the current iteration is in the domain using the `contains` method.
You can also use your iterator from :ref:`Part 2: Domains, Variables, Constraints`.
You can also implement a min-regret variable selection strategy:
it selects a variable with the largest difference between a closest
-successor city and a second-closest one.
-The idea is that it is critical to decide the successor for this city first,
+successor node and a second-closest one.
+The idea is that it is critical to decide the successor for this node first,
because otherwise one will regret it the most.
Observe the first solution obtained to the provided instance and its objective value:
@@ -144,7 +143,7 @@ is it better than upon naive first-fail?
Also observe the time and number of backtracks necessary for proving optimality:
by how much did you reduce the computation time and number of backtracks?
-Check that your implementation passes the tests `TSPTest.java `_.
+Verify that your implementation passes the tests of `TSPTest.java `_.
LNS Applied to TSP
@@ -155,7 +154,10 @@ Implement and apply large-neighborhood search (LNS) by modifying
What you should do:
-* Record the current best solution. Hint: Use the `onSolution` call-back on the `DFSearch` object.
+* Record the current best solution.
+
+ **Hint**: Use the `onSolution` call-back on the `DFSearch` object.
+
* Implement a restart strategy fixing randomly 10% of the variables to their value in the current best solution.
* Each restart has a failure limit of 100 backtracks.
@@ -166,9 +168,9 @@ You can simply copy/paste/modify this implementation for the TSP:
* What is the impact of the percentage of variables relaxed (experiment with 5%, 10%, and 20%)?
* What is the impact of the failure limit (experiment with 50, 100, and 1000)?
* Which parameter setting works best? How did you choose it?
-* Implement a relaxation that is specific to this problem. Try and relax the variables that have the strongest impact on the objective with a greater probability (the choice of relaxed variables should still be somehow randomized). You can for instance select a subset of cities with the largest distance to their successor and permit those cities to be reinserted anywhere in the circuit. This requires keeping the relaxed cities (those that are to be reinserted) within the domains of the successor variables of the non-relaxed cities.
+* Implement a relaxation that is specific to this problem. Try and relax the variables that have the strongest impact on the objective with a greater probability (the choice of relaxed variables should still be somehow randomized). You can for instance select a subset of nodes with the largest distance to their successor and permit those nodes to be reinserted anywhere in the circuit. This requires keeping the relaxed nodes (those that are to be reinserted) within the domains of the successor variables of the non-relaxed nodes.
-Check that your implementation passes the tests `TSPTest.java `_.
+Verify that your implementation passes the tests of `TSPTest.java `_.
From TSP to VRP
@@ -176,10 +178,33 @@ From TSP to VRP
Create a new file called `VRP.java` working with the same distance matrix as the TSP but assuming
that there are now :math:`k` vehicles (make it a parameter and experiment with :math:`k=3`).
-The depot is the city at index `0`, and every other city must be
+The depot is the node at index `0`, and every other node must be
visited exactly once by exactly one of the :math:`k` vehicles:
* Variant 1: Minimize the total distance traveled by the three vehicles.
* Variant 2 (advanced): Minimize the longest distance traveled by the three vehicles (in order to be fair among the vehicle drivers).
+ A good branching strategy for this variant is to:
+ 1. as a variable selection heuristic select the last node `x[i]` on the path of vehicle `v`, where `v` currently has the shortest travel time of all vehicles,
+ 2. as a value selection heuristic greedily select the node `j` that is closest to node `x[i]` among all nodes in the domain of `x[i]`.
+
+ As an example of the search heuristic, consider the following figure where
+
+ * :math:`s_v` is the start node of vehicle :math:`v` (the depot),
+ * :math:`t_v` is the end node of vehicle :math:`v` (the depot), and
+ * the nodes :math:`\{4,6,7,8,10,12\}` are successors of no nodes:
+
+ .. image:: ../_static/vrp-search.svg
+ :width: 512
+ :alt: VRP Search Heuristic
+ :align: center
+
+ The distances the vehicles have traveled this far are:
+
+ * :math:`d_0 = \text{distance}[s_0][3]` for vehicle :math:`0`,
+ * :math:`d_1 = \text{distance}[s_1][5] + \text{distance}[5][9]` for vehicle :math:`1`, and
+ * :math:`d_2 = \text{distance}[s_2][11]` for vehicle :math:`2`.
+
+ Say distance :math:`d_1` is the shortest distance, then the variable selected would be node `x[9]`.
+ The value selected would correspond to the shortest distance from node `9` to any node in the domain of `x[9]`.
You can also use LNS to speed up the search.
diff --git a/source/learning_minicp/part_6.rst b/source/learning_minicp/part_6.rst
index 12d5374..24763e8 100644
--- a/source/learning_minicp/part_6.rst
+++ b/source/learning_minicp/part_6.rst
@@ -45,10 +45,8 @@ Domain-Consistent Filtering
The objective is to implement the filtering algorithm described in [Regin94]_
to remove every impossible value for the `AllDifferent` constraint (this is called generalized arc consistency and is also known as domain consistency).
-More precisely, you must:
-* Implement the constraint `AllDifferentDC.java `_.
-* Test your implementation in `AllDifferentDCTest.java. `_.
+Implement the constraint `AllDifferentDC.java `_.
Régin's algorithm is a four-step procedure that can be described with the following figure:
@@ -99,8 +97,9 @@ to represent the residual graph of the maximum matching:
It uses an adjacency list that is updated in the method `updateGraph()`.
We advise you to use a dense representation with node ids as illustrated on the black nodes of the example (step2: directed graph).
-Once your code passes the tests, you can experiment your new
-constraint on all the models you have seen so far in order
-to measure the pruning gain on the number of nodes (n-Queens, TSP, QAP, etc).
+Verify that your implementation passes the tests of `AllDifferentDCTest.java. `_.
+
+Once your implementation passes the tests, you can experiment on all previously seen models that make use of the `AllDifferent` constraint (n-Queens, TSP, QAP, etc),
+by replacing each usage of the binary decomposition constraint with this one. Is there a big difference in the number of nodes in the search trees?
.. [Regin94] Régin, J.-C. (1994). A filtering algorithm for constraints of difference in CSPs. 12th National Conference on Artificial Intelligence (AAAI-94). (`PDF `_)
diff --git a/source/learning_minicp/part_7.rst b/source/learning_minicp/part_7.rst
index 8edf537..b609b03 100644
--- a/source/learning_minicp/part_7.rst
+++ b/source/learning_minicp/part_7.rst
@@ -156,7 +156,7 @@ You "simply" have to compute, for each call to `propagate()`:
* You can now intersect the set of globally supported tuples with each variable-value pair in `supports`.
If the value supports no tuples (i.e., if the intersection is empty), then the value can be removed.
-Check that your implementation passes the tests `TableTest.java `_.
+Verify that your implementation passes the tests of `TableTest.java `_.
.. [CT2016] Demeulenaere, J., Hartert, R., Lecoutre, C., Perez, G., Perron, L., Régin, J.-C., & Schaus, P. (2016). Compact-table: Efficiently filtering table constraints with reversible sparse bit-sets. International Conference on Principles and Practice of Constraint Programming, pp. 207-223. Springer. (`PDF `_)
@@ -172,4 +172,4 @@ Your task is to finish the implementation in
* Model the problem using Table constraints.
* Search for a feasible solution using branching combinators.
-Check that your implementation passes the tests `EternityTest.java `_.
+Verify that your implementation passes the tests of `EternityTest.java `_.
diff --git a/source/learning_minicp/part_8.rst b/source/learning_minicp/part_8.rst
index cb41bd5..a958ac0 100644
--- a/source/learning_minicp/part_8.rst
+++ b/source/learning_minicp/part_8.rst
@@ -23,6 +23,10 @@ Conflict-based Search Strategies
Implement the Last Conflict [LC2009]_ and Conflict Ordering Search [COS2015]_ heuristics.
+In MiniCP, a conflict is when when an inconsistency occurs during search.
+The last conflicting variable is the most recent variable that was branched on.
+In MiniCP, when an inconsistency occurs, an `InconsistencyException` is thrown and needs to be caught during branching by the conflict search heuristic.
+
Test your implementations in `LastConflictSearchTest.java `_
and `ConflictOrderingSearchTest.java. `_.
@@ -40,16 +44,28 @@ Implement within `TSPBoundImpact.java `_)
Limited Discrepancy Search (optional)
=================================================================
-Implement `LimitedDiscrepancyBranching`, a branching that can wrap any branching
-to limit the discrepancy of the branching.
+Implement `LimitedDiscrepancyBranching`, a branching that can wrap any branching to limit the discrepancy of the branching.
+
+The following figure depicts a search tree where the number of each node is the discrepancy of that node:
+
+.. image:: ../_static/discrepancy-search.svg
+ :width: 600
+ :alt: Discrepancy Search
+ :align: center
+
-Test your implementation in `LimitedDiscrepancyBranchingTest.java. `_.
+Verify that your implementation passes the tests of `LimitedDiscrepancyBranchingTest.java. `_.
diff --git a/source/learning_minicp/part_9.rst b/source/learning_minicp/part_9.rst
index 78772a4..9046ab1 100644
--- a/source/learning_minicp/part_9.rst
+++ b/source/learning_minicp/part_9.rst
@@ -113,7 +113,7 @@ sure `overlaps` has the intended meaning:
}
-Check that your implementation passes the tests `CumulativeDecompTest.java `_.
+Verify that your implementation passes the tests of `CumulativeDecompTest.java `_.
@@ -229,7 +229,7 @@ activity (if needed) to the earliest slot when it can be executed without exceed
}
-Check that your implementation passes the tests `CumulativeTest.java `_.
+Verify that your implementation passes the tests of `CumulativeTest.java `_.
.. [TT2015] Gay, S., Hartert, R., & Schaus, P. (2015). Simple and scalable time-table filtering for the cumulative constraint. International Conference on Principles and Practice of Constraint Programming, pp. 149-157. Springer. (`PDF `_)
@@ -252,4 +252,4 @@ Several instances of increasing size are available, with 30, 60, 90, and 120 act
In order to test your model, note that the instance ``j30_1_1.rcp`` should have a minimum makespan of 43.
Do not expect to prove optimality for large-size instances, but you should reach it easily for 30 activities.
-Check that your implementation passes the tests `RCPSPTest.java `_.
+Verify that your implementation passes the tests of `RCPSPTest.java `_.