Skip to content

Commit cca79ba

Browse files
Merge branch 'AIMA3e' of https://github.com/aimacode/aima-java.git into AIMA3e
2 parents c1d111c + e339a43 commit cca79ba

File tree

4 files changed

+287
-10
lines changed

4 files changed

+287
-10
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Java implementation of algorithms from [Russell](http://www.cs.berkeley.edu/~rus
5858
|6.3|209|AC-3|[AC3Strategy](/aima-core/src/main/java/aima/core/search/csp/AC3Strategy.java)|
5959
|6.5|215|Backtracking-Search|[BacktrackingStrategy](/aima-core/src/main/java/aima/core/search/csp/BacktrackingStrategy.java)|
6060
|6.8|221|Min-Conflicts|[MinConflictsStrategy](/aima-core/src/main/java/aima/core/search/csp/MinConflictsStrategy.java)|
61-
|6.11|224|Tree-CSP-Solver|---|
61+
|6.11|224|Tree-CSP-Solver|[TreeCSPSolver](/aima-core/src/main/java/aima/core/search/csp/TreeCSPSolver.java)|
6262
|7|235|Knowledge Base|[KnowledgeBase](/aima-core/src/main/java/aima/core/logic/propositional/kb/KnowledgeBase.java)|
6363
|7.1|236|KB-Agent|[KBAgent](/aima-core/src/main/java/aima/core/logic/propositional/agent/KBAgent.java)|
6464
|7.7|244|Propositional-Logic-Sentence|[Sentence](/aima-core/src/main/java/aima/core/logic/propositional/parsing/ast/Sentence.java)|
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package aima.core.search.csp;
2+
3+
import java.util.ArrayList;
4+
import java.util.LinkedList;
5+
import java.util.List;
6+
import java.util.Queue;
7+
8+
import aima.core.util.Util;
9+
10+
/**
11+
*
12+
* Artificial Intelligence A Modern Approach (3rd Ed.): Figure 6.11, Page
13+
* 224.<br>
14+
* <br>
15+
*
16+
* <pre>
17+
* <code>
18+
* function TREE-CSP-SOLVER(csp) returns a solution, or failure
19+
* inputs: csp, a CSP with components X, D, C
20+
* n &larr; number of variables in X
21+
* assignment &larr; an empty assignment
22+
* root &larr; any variable in X
23+
* X &larr; TOPOLOGICALSORT(X, root )
24+
* for j = n down to 2 do
25+
* MAKE-ARC-CONSISTENT(PARENT(Xj),Xj )
26+
* if it cannot be made consistent then return failure
27+
* for i = 1 to n do
28+
* assignment[Xi] &larr; any consistent value from Di
29+
* if there is no consistent value then return failure
30+
* return assignment
31+
* </code>
32+
*
33+
* <pre>
34+
*
35+
* Figure 6.11 The TREE-CSP-SOLVER algorithm for solving tree-structured CSPs.
36+
* If the CSP has a solution, we will find it in linear time; if not, we will
37+
* detect a contradiction.
38+
*
39+
* @author Anurag Rai
40+
*
41+
*/
42+
public class TreeCSPSolver extends SolutionStrategy {
43+
44+
@Override
45+
public Assignment solve(CSP csp) {
46+
47+
Assignment assignment = new Assignment();
48+
// Get the list of Variables from CSP to calculate the size
49+
List<Variable> l = csp.getVariables();
50+
// Calculate the size
51+
int n = l.size();
52+
// Select a random root from the List of Vaiables
53+
Variable root = Util.selectRandomlyFromList(l);
54+
// Sort the variables in topological order
55+
l = topologicalSort(csp, l, root);
56+
57+
DomainRestoreInfo info = new DomainRestoreInfo();
58+
59+
for (int i = n - 1; i >= 1; i--) {
60+
Variable var = l.get(i);
61+
// get constraints to find the parent
62+
for (Constraint constraint : csp.getConstraints(var)) {
63+
if (constraint.getScope().size() == 2) {
64+
// if the neighbour is parent
65+
if (csp.getNeighbor(var, constraint) == l.get(parent[i])) {
66+
// make it Arc Consistent
67+
if (makeArcConsistent(l.get(parent[i]), var, constraint, csp, info)) {
68+
if (csp.getDomain(l.get(parent[i])).isEmpty()) {
69+
info.setEmptyDomainFound(true);
70+
assignment = null;
71+
return assignment;
72+
}
73+
}
74+
}
75+
}
76+
}
77+
}
78+
boolean assignment_consistent = false;
79+
for (int i = 0; i < n; i++) {
80+
Variable var = l.get(i);
81+
assignment_consistent = false;
82+
for (Object value : csp.getDomain(var)) {
83+
assignment.setAssignment(var, value);
84+
if (assignment.isConsistent(csp.getConstraints(var))) {
85+
assignment_consistent = true;
86+
break;
87+
}
88+
}
89+
if (!assignment_consistent) {
90+
assignment = null;
91+
return assignment;
92+
}
93+
}
94+
return assignment;
95+
}
96+
97+
//
98+
// Supporting Code
99+
protected int[] parent;
100+
101+
// Since the graph is a tree, topologicalSort is:
102+
// Level order traversal of the tree OR BFS on tree OR Pre-oder
103+
protected List<Variable> topologicalSort(CSP csp, List<Variable> l, Variable root) {
104+
// Track the parents
105+
parent = new int[l.size()];
106+
107+
List<Variable> result = new ArrayList<>();
108+
Queue<Variable> q = new LinkedList<>(); // FIFO-Queue
109+
110+
int i = 1;
111+
int parent_index = 0;
112+
int node_count = 0;
113+
q.add(root);
114+
115+
while (!q.isEmpty()) {
116+
117+
node_count = q.size(); // get number of nodes in the level
118+
119+
while (node_count > 0) {
120+
121+
Variable var = q.remove();
122+
result.add(var);
123+
// for each binary constraint of the Variable
124+
for (Constraint constraint : csp.getConstraints(var)) {
125+
Variable neighbour = csp.getNeighbor(var, constraint);
126+
// check if neighbour is root
127+
if (result.contains(neighbour))
128+
continue;
129+
parent[i] = parent_index;
130+
i++;
131+
q.add(neighbour);
132+
}
133+
node_count--;
134+
parent_index++;
135+
}
136+
}
137+
return result;
138+
}
139+
140+
protected boolean makeArcConsistent(Variable xi, Variable xj, Constraint constraint, CSP csp,
141+
DomainRestoreInfo info) {
142+
boolean revised = false;
143+
Assignment assignment = new Assignment();
144+
for (Object iValue : csp.getDomain(xi)) {
145+
assignment.setAssignment(xi, iValue);
146+
boolean consistentExtensionFound = false;
147+
for (Object jValue : csp.getDomain(xj)) {
148+
assignment.setAssignment(xj, jValue);
149+
if (constraint.isSatisfiedWith(assignment)) {
150+
consistentExtensionFound = true;
151+
break;
152+
}
153+
}
154+
if (!consistentExtensionFound) {
155+
info.storeDomainFor(xi, csp.getDomain(xi));
156+
csp.removeValueFromDomain(xi, iValue);
157+
revised = true;
158+
}
159+
}
160+
return revised;
161+
}
162+
}

aima-core/src/test/java/aima/test/core/unit/search/SearchTestSuite.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import aima.test.core.unit.search.csp.AssignmentTest;
44
import aima.test.core.unit.search.csp.CSPTest;
55
import aima.test.core.unit.search.csp.MapCSPTest;
6+
import aima.test.core.unit.search.csp.TreeCSPSolverTest;
67
import aima.test.core.unit.search.framework.NodeTest;
78
import aima.test.core.unit.search.framework.SolutionCheckerTest;
89
import aima.test.core.unit.search.informed.AStarSearchTest;
@@ -17,14 +18,11 @@
1718
import org.junit.runners.Suite;
1819

1920
@RunWith(Suite.class)
20-
@Suite.SuiteClasses({ AssignmentTest.class, CSPTest.class, MapCSPTest.class,
21-
AStarSearchTest.class, GreedyBestFirstSearchTest.class,
22-
RecursiveBestFirstSearchTest.class,
23-
SimulatedAnnealingSearchTest.class, AndOrSearchTest.class,
24-
LRTAStarAgentTest.class, OnlineDFSAgentTest.class,
25-
BidirectionalSearchTest.class, BreadthFirstSearchTest.class,
26-
DepthFirstSearchTest.class, DepthLimitedSearchTest.class,
27-
IterativeDeepeningSearchTest.class, UniformCostSearchTest.class,
28-
NodeTest.class, SolutionCheckerTest.class })
21+
@Suite.SuiteClasses({ AssignmentTest.class, CSPTest.class, MapCSPTest.class, TreeCSPSolverTest.class,
22+
AStarSearchTest.class, GreedyBestFirstSearchTest.class, RecursiveBestFirstSearchTest.class,
23+
SimulatedAnnealingSearchTest.class, AndOrSearchTest.class, LRTAStarAgentTest.class, OnlineDFSAgentTest.class,
24+
BidirectionalSearchTest.class, BreadthFirstSearchTest.class, DepthFirstSearchTest.class,
25+
DepthLimitedSearchTest.class, IterativeDeepeningSearchTest.class, UniformCostSearchTest.class, NodeTest.class,
26+
SolutionCheckerTest.class })
2927
public class SearchTestSuite {
3028
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package aima.test.core.unit.search.csp;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.junit.Assert;
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
10+
import aima.core.search.csp.Assignment;
11+
import aima.core.search.csp.CSP;
12+
import aima.core.search.csp.Constraint;
13+
import aima.core.search.csp.Domain;
14+
import aima.core.search.csp.NotEqualConstraint;
15+
import aima.core.search.csp.TreeCSPSolver;
16+
import aima.core.search.csp.Variable;
17+
18+
public class TreeCSPSolverTest {
19+
private static final Variable WA = new Variable("wa");
20+
private static final Variable NT = new Variable("nt");
21+
private static final Variable Q = new Variable("q");
22+
private static final Variable NSW = new Variable("nsw");
23+
private static final Variable V = new Variable("v");
24+
25+
private static final Constraint C1 = new NotEqualConstraint(WA, NT);
26+
private static final Constraint C2 = new NotEqualConstraint(NT, Q);
27+
private static final Constraint C3 = new NotEqualConstraint(Q, NSW);
28+
private static final Constraint C4 = new NotEqualConstraint(NSW, V);
29+
30+
private Domain colors;
31+
32+
private List<Variable> variables;
33+
34+
@Before
35+
public void setUp() {
36+
variables = new ArrayList<Variable>();
37+
variables.add(WA);
38+
variables.add(NT);
39+
variables.add(Q);
40+
variables.add(NSW);
41+
variables.add(V);
42+
colors = new Domain(new Object[] { "red", "green", "blue" });
43+
}
44+
45+
@Test
46+
public void testConstraintNetwork() {
47+
CSP csp = new CSP(variables);
48+
csp.addConstraint(C1);
49+
csp.addConstraint(C2);
50+
csp.addConstraint(C3);
51+
csp.addConstraint(C4);
52+
Assert.assertNotNull(csp.getConstraints());
53+
Assert.assertEquals(4, csp.getConstraints().size());
54+
Assert.assertNotNull(csp.getConstraints(WA));
55+
Assert.assertEquals(1, csp.getConstraints(WA).size());
56+
Assert.assertNotNull(csp.getConstraints(NT));
57+
Assert.assertEquals(2, csp.getConstraints(NT).size());
58+
Assert.assertNotNull(csp.getConstraints(Q));
59+
Assert.assertEquals(2, csp.getConstraints(Q).size());
60+
Assert.assertNotNull(csp.getConstraints(NSW));
61+
Assert.assertEquals(2, csp.getConstraints(NSW).size());
62+
}
63+
64+
@Test
65+
public void testDomainChanges() {
66+
Domain colors2 = new Domain(colors.asList());
67+
Assert.assertEquals(colors, colors2);
68+
69+
CSP csp = new CSP(variables);
70+
csp.addConstraint(C1);
71+
Assert.assertNotNull(csp.getDomain(WA));
72+
Assert.assertEquals(0, csp.getDomain(WA).size());
73+
Assert.assertNotNull(csp.getConstraints(WA));
74+
75+
csp.setDomain(WA, colors);
76+
Assert.assertEquals(colors, csp.getDomain(WA));
77+
Assert.assertEquals(3, csp.getDomain(WA).size());
78+
Assert.assertEquals("red", csp.getDomain(WA).get(0));
79+
80+
CSP cspCopy = csp.copyDomains();
81+
Assert.assertNotNull(cspCopy.getDomain(WA));
82+
Assert.assertEquals(3, cspCopy.getDomain(WA).size());
83+
Assert.assertEquals("red", cspCopy.getDomain(WA).get(0));
84+
Assert.assertNotNull(cspCopy.getDomain(NT));
85+
Assert.assertEquals(0, cspCopy.getDomain(NT).size());
86+
Assert.assertNotNull(cspCopy.getConstraints(NT));
87+
Assert.assertEquals(C1, cspCopy.getConstraints(NT).get(0));
88+
89+
cspCopy.removeValueFromDomain(WA, "red");
90+
Assert.assertEquals(2, cspCopy.getDomain(WA).size());
91+
Assert.assertEquals("green", cspCopy.getDomain(WA).get(0));
92+
Assert.assertEquals(3, csp.getDomain(WA).size());
93+
Assert.assertEquals("red", csp.getDomain(WA).get(0));
94+
}
95+
96+
@Test
97+
public void testCSPSolver() {
98+
99+
CSP csp = new CSP(variables);
100+
csp.addConstraint(C1);
101+
csp.addConstraint(C2);
102+
csp.addConstraint(C3);
103+
csp.addConstraint(C4);
104+
105+
csp.setDomain(WA, colors);
106+
csp.setDomain(NT, colors);
107+
csp.setDomain(Q, colors);
108+
csp.setDomain(NSW, colors);
109+
csp.setDomain(V, colors);
110+
111+
TreeCSPSolver treeCSPSolver = new TreeCSPSolver();
112+
Assignment assignment = treeCSPSolver.solve(csp);
113+
Assert.assertNotNull(assignment);
114+
Assert.assertTrue(assignment.isComplete(csp.getVariables()));
115+
Assert.assertTrue(assignment.isSolution(csp));
116+
}
117+
}

0 commit comments

Comments
 (0)