Skip to content

Commit 4f79acb

Browse files
committed
Add tree-csp-solver implementation.
Patch applied and updated from pull request aimacode#143.
1 parent a65212b commit 4f79acb

File tree

3 files changed

+276
-9
lines changed

3 files changed

+276
-9
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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 224.<br>
13+
* <br>
14+
*
15+
* <pre>
16+
* <code>
17+
* function TREE-CSP-SOLVER(csp) returns a solution, or failure
18+
* inputs: csp, a CSP with components X, D, C
19+
* n &larr; number of variables in X
20+
* assignment &larr; an empty assignment
21+
* root &larr; any variable in X
22+
* X &larr; TOPOLOGICALSORT(X, root )
23+
* for j = n down to 2 do
24+
* MAKE-ARC-CONSISTENT(PARENT(Xj),Xj )
25+
* if it cannot be made consistent then return failure
26+
* for i = 1 to n do
27+
* assignment[Xi] &larr; any consistent value from Di
28+
* if there is no consistent value then return failure
29+
* return assignment
30+
* </code>
31+
* <pre>
32+
*
33+
* Figure 6.11 The TREE-CSP-SOLVER algorithm for solving tree-structured CSPs. If the
34+
* CSP has a solution, we will find it in linear time; if not, we will detect
35+
* a contradiction.
36+
*
37+
* @author Anurag Rai
38+
*
39+
*/
40+
public class TreeCSPSolver extends SolutionStrategy {
41+
42+
public static int[] parent;
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+
parent = new int[n];
53+
// Select a random root from the List of Vaiables
54+
Variable root = Util.selectRandomlyFromList(l);
55+
// Sort the variables in topological order
56+
l = topologicalSort(csp, l, root);
57+
58+
DomainRestoreInfo info = new DomainRestoreInfo();
59+
60+
for (int i = n - 1; i >= 1; i--) {
61+
Variable var = l.get(i);
62+
// get constraints to find the parent
63+
for (Constraint constraint : csp.getConstraints(var)) {
64+
if (constraint.getScope().size() == 2) {
65+
// if the neighbour is parent
66+
if (csp.getNeighbor(var, constraint) == l.get(parent[i])) {
67+
// make it Arc Consistent
68+
if (makeArcConsistent(l.get(parent[i]), var, constraint, csp, info)) {
69+
if (csp.getDomain(l.get(parent[i])).isEmpty()) {
70+
info.setEmptyDomainFound(true);
71+
assignment = null;
72+
return assignment;
73+
}
74+
}
75+
}
76+
}
77+
}
78+
}
79+
boolean assignment_consistent = false;
80+
for (int i = 0; i < n; i++) {
81+
Variable var = l.get(i);
82+
assignment_consistent = false;
83+
for (Object value : csp.getDomain(var)) {
84+
assignment.setAssignment(var, value);
85+
if (assignment.isConsistent(csp.getConstraints(var))) {
86+
assignment_consistent = true;
87+
break;
88+
}
89+
}
90+
if (!assignment_consistent) {
91+
assignment = null;
92+
return assignment;
93+
}
94+
}
95+
return assignment;
96+
}
97+
98+
private boolean makeArcConsistent(Variable xi, Variable xj, Constraint constraint, CSP csp,
99+
DomainRestoreInfo info) {
100+
boolean revised = false;
101+
Assignment assignment = new Assignment();
102+
for (Object iValue : csp.getDomain(xi)) {
103+
assignment.setAssignment(xi, iValue);
104+
boolean consistentExtensionFound = false;
105+
for (Object jValue : csp.getDomain(xj)) {
106+
assignment.setAssignment(xj, jValue);
107+
if (constraint.isSatisfiedWith(assignment)) {
108+
consistentExtensionFound = true;
109+
break;
110+
}
111+
}
112+
if (!consistentExtensionFound) {
113+
info.storeDomainFor(xi, csp.getDomain(xi));
114+
csp.removeValueFromDomain(xi, iValue);
115+
revised = true;
116+
}
117+
}
118+
return revised;
119+
}
120+
121+
// Since the graph is a tree, topologicalSort is:
122+
// Level order traversal of the tree OR BFS on tree OR Pre-oder
123+
protected List<Variable> topologicalSort(CSP csp, List<Variable> l, Variable root) {
124+
125+
List<Variable> result = new ArrayList<>();
126+
Queue<Variable> q = new LinkedList<>(); // FIFO-Queue
127+
128+
int i = 1;
129+
int parent_index = 0;
130+
int node_count = 0;
131+
q.add(root);
132+
133+
while (!q.isEmpty()) {
134+
135+
node_count = q.size(); // get number of nodes in the level
136+
137+
while (node_count > 0) {
138+
139+
Variable var = q.remove();
140+
result.add(var);
141+
// for each binary constraint of the Variable
142+
for (Constraint constraint : csp.getConstraints(var)) {
143+
Variable neighbour = csp.getNeighbor(var, constraint);
144+
// check if neighbour is root
145+
if (result.contains(neighbour))
146+
continue;
147+
parent[i] = parent_index;
148+
i++;
149+
q.add(neighbour);
150+
}
151+
node_count--;
152+
parent_index++;
153+
}
154+
}
155+
return result;
156+
}
157+
}

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: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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.CSP;
11+
import aima.core.search.csp.Constraint;
12+
import aima.core.search.csp.Domain;
13+
import aima.core.search.csp.NotEqualConstraint;
14+
import aima.core.search.csp.TreeCSPSolver;
15+
import aima.core.search.csp.Variable;
16+
17+
public class TreeCSPSolverTest {
18+
private static final Variable WA = new Variable("wa");
19+
private static final Variable NT = new Variable("nt");
20+
private static final Variable Q = new Variable("q");
21+
private static final Variable NSW = new Variable("nsw");
22+
private static final Variable V = new Variable("v");
23+
24+
private static final Constraint C1 = new NotEqualConstraint(WA, NT);
25+
private static final Constraint C2 = new NotEqualConstraint(NT, Q);
26+
private static final Constraint C3 = new NotEqualConstraint(Q, NSW);
27+
private static final Constraint C4 = new NotEqualConstraint(NSW, V);
28+
29+
private Domain colors;
30+
31+
private List<Variable> variables;
32+
33+
@Before
34+
public void setUp() {
35+
variables = new ArrayList<Variable>();
36+
variables.add(WA);
37+
variables.add(NT);
38+
variables.add(Q);
39+
variables.add(NSW);
40+
variables.add(V);
41+
colors = new Domain(new Object[] { "red", "green", "blue" });
42+
}
43+
44+
@Test
45+
public void testConstraintNetwork() {
46+
CSP csp = new CSP(variables);
47+
csp.addConstraint(C1);
48+
csp.addConstraint(C2);
49+
csp.addConstraint(C3);
50+
csp.addConstraint(C4);
51+
Assert.assertNotNull(csp.getConstraints());
52+
Assert.assertEquals(4, csp.getConstraints().size());
53+
Assert.assertNotNull(csp.getConstraints(WA));
54+
Assert.assertEquals(1, csp.getConstraints(WA).size());
55+
Assert.assertNotNull(csp.getConstraints(NT));
56+
Assert.assertEquals(2, csp.getConstraints(NT).size());
57+
Assert.assertNotNull(csp.getConstraints(Q));
58+
Assert.assertEquals(2, csp.getConstraints(Q).size());
59+
Assert.assertNotNull(csp.getConstraints(NSW));
60+
Assert.assertEquals(2, csp.getConstraints(NSW).size());
61+
}
62+
63+
@Test
64+
public void testDomainChanges() {
65+
Domain colors2 = new Domain(colors.asList());
66+
Assert.assertEquals(colors, colors2);
67+
68+
CSP csp = new CSP(variables);
69+
csp.addConstraint(C1);
70+
Assert.assertNotNull(csp.getDomain(WA));
71+
Assert.assertEquals(0, csp.getDomain(WA).size());
72+
Assert.assertNotNull(csp.getConstraints(WA));
73+
74+
csp.setDomain(WA, colors);
75+
Assert.assertEquals(colors, csp.getDomain(WA));
76+
Assert.assertEquals(3, csp.getDomain(WA).size());
77+
Assert.assertEquals("red", csp.getDomain(WA).get(0));
78+
79+
CSP cspCopy = csp.copyDomains();
80+
Assert.assertNotNull(cspCopy.getDomain(WA));
81+
Assert.assertEquals(3, cspCopy.getDomain(WA).size());
82+
Assert.assertEquals("red", cspCopy.getDomain(WA).get(0));
83+
Assert.assertNotNull(cspCopy.getDomain(NT));
84+
Assert.assertEquals(0, cspCopy.getDomain(NT).size());
85+
Assert.assertNotNull(cspCopy.getConstraints(NT));
86+
Assert.assertEquals(C1, cspCopy.getConstraints(NT).get(0));
87+
88+
cspCopy.removeValueFromDomain(WA, "red");
89+
Assert.assertEquals(2, cspCopy.getDomain(WA).size());
90+
Assert.assertEquals("green", cspCopy.getDomain(WA).get(0));
91+
Assert.assertEquals(3, csp.getDomain(WA).size());
92+
Assert.assertEquals("red", csp.getDomain(WA).get(0));
93+
}
94+
95+
@Test
96+
public void testCSPSolver() {
97+
98+
CSP csp = new CSP(variables);
99+
csp.addConstraint(C1);
100+
csp.addConstraint(C2);
101+
csp.addConstraint(C3);
102+
csp.addConstraint(C4);
103+
104+
csp.setDomain(WA, colors);
105+
csp.setDomain(NT, colors);
106+
csp.setDomain(Q, colors);
107+
csp.setDomain(NSW, colors);
108+
csp.setDomain(V, colors);
109+
110+
System.out.println(new TreeCSPSolver().solve(csp));
111+
}
112+
}

0 commit comments

Comments
 (0)