Skip to content

Commit fdf7366

Browse files
committed
Bug in GraphPlanAlgorithm fixed. Negative precondition literals must be added at graph level 0.
1 parent 74ad1e2 commit fdf7366

File tree

5 files changed

+55
-22
lines changed

5 files changed

+55
-22
lines changed

aima-core/src/main/java/aima/core/logic/planning/Graph.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,27 @@ private Level<ActionSchema, Literal> createActionLevel(Level<Literal, ActionSche
9696
private Level<Literal, ActionSchema> createLiteralLevel(Level<ActionSchema, Literal> prevLevel,
9797
PlanningProblem problem) {
9898
Level<Literal, ActionSchema> result = (prevLevel == null)
99-
? new Level<>(problem.getInitialState().getFluents(), problem)
99+
? new Level<>(getInitialPlanningState(problem), problem)
100100
: new Level<>(prevLevel, problem);
101101
calculateNextLinks(result, problem);
102102
calculateMutexLinksForLiteralLevel(result);
103103
return result;
104104
}
105105

106+
// negative precondition literals are needed for backward search...
107+
private List<Literal> getInitialPlanningState(PlanningProblem problem) {
108+
List<Literal> result = new ArrayList<>(problem.getInitialState().getFluents());
109+
for (ActionSchema action : problem.getPropositionalisedActions()) {
110+
for (Literal literal : action.getPrecondition())
111+
if (literal.isNegativeLiteral()) {
112+
Literal posLiteral = literal.getComplementaryLiteral();
113+
if (!result.contains(posLiteral))
114+
result.add(literal);
115+
}
116+
}
117+
return result;
118+
}
119+
106120
private void calculateNextLinks(Level<Literal, ActionSchema> level, PlanningProblem problem) {
107121
// add applicable actions:
108122
for (ActionSchema action : problem.getPropositionalisedActions()) {

aima-core/src/main/java/aima/core/logic/planning/Level.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
* @author Ruediger Lunde
1010
*/
1111
public class Level<CURR, PREV> {
12-
private List<CURR> levelObjects = new ArrayList<>();
12+
private final List<CURR> levelObjects = new ArrayList<>();
1313
HashMap<CURR, List<PREV>> prevLinks = new HashMap<>();
1414
HashMap<CURR, List<PREV>> nextLinks = new HashMap<>();
15-
private HashMap<CURR, List<CURR>> mutexLinks = new HashMap<>();; //can be planned alternatively
15+
private final HashMap<CURR, List<CURR>> mutexLinks = new HashMap<>(); // can be planned alternatively
1616

1717
private Level<PREV, CURR> prevLevel;
1818

aima-core/src/main/java/aima/core/logic/planning/PlanningProblem.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
* @author samagra
2424
*/
2525
public class PlanningProblem {
26-
State initialState; // initialState
27-
Set<ActionSchema> actionSchemas; // Planning Domain
28-
State goalState; // goalState
26+
private State initialState; // initialState
27+
private Set<ActionSchema> actionSchemas; // Planning Domain
28+
private List<ActionSchema> propositionalisedActionSchemas;
29+
private State goalState; // goalState
2930

3031

3132
public PlanningProblem(State initialState, State goalState, Set<ActionSchema> actionSchemas) {
@@ -35,7 +36,7 @@ public PlanningProblem(State initialState, State goalState, Set<ActionSchema> ac
3536
}
3637

3738
public PlanningProblem(State initialState, State goalState, ActionSchema... actions) {
38-
this(initialState, goalState, new HashSet<>(Arrays.asList(actions)));
39+
this(initialState, goalState, new LinkedHashSet<>(Arrays.asList(actions)));
3940
}
4041

4142
public State getInitialState() {
@@ -86,13 +87,15 @@ public List<Constant> getProblemConstants() {
8687
* @return Propositionalises all the actionschemas to return a set of possible ground actions
8788
*/
8889
public List<ActionSchema> getPropositionalisedActions() {
89-
List<Constant> problemConstants = getProblemConstants();
90-
List<ActionSchema> result = new ArrayList<>();
91-
for (ActionSchema actionSchema : getActionSchemas()) {
92-
int numberOfVars = actionSchema.getVariables().size();
93-
for (List<Constant> constants : PermutationGenerator.generatePermutations(problemConstants, numberOfVars))
94-
result.add(actionSchema.getActionBySubstitution(constants));
90+
if (propositionalisedActionSchemas == null) {
91+
List<Constant> problemConstants = getProblemConstants();
92+
propositionalisedActionSchemas = new ArrayList<>();
93+
for (ActionSchema actionSchema : getActionSchemas()) {
94+
int numberOfVars = actionSchema.getVariables().size();
95+
for (List<Constant> constants : PermutationGenerator.generatePermutations(problemConstants, numberOfVars))
96+
propositionalisedActionSchemas.add(actionSchema.getActionBySubstitution(constants));
97+
}
9598
}
96-
return result;
99+
return propositionalisedActionSchemas;
97100
}
98101
}

aima-core/src/main/java/aima/core/util/math/permute/PermutationGenerator.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package aima.core.util.math.permute;
22

3-
import java.util.ArrayList;
4-
import java.util.Arrays;
5-
import java.util.Iterator;
6-
import java.util.List;
3+
import java.util.*;
74

85
/**
96
* @author samagra
107
*/
118
public class PermutationGenerator {
129

1310
public static <T> Iterable<List<T>> generatePermutations(List<T> list, int r) {
11+
if (r > list.size())
12+
return Collections.emptyList();
1413
long rfact = (long) PermutationGenerator.factorial(r);
1514
long total = (long) CombinationGenerator.nCr(list.size(), r) * rfact;
1615
return () -> new Iterator<>() {

aima-core/src/test/java/aima/test/core/unit/logic/planning/GraphPlanAlgorithmTest.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package aima.test.core.unit.logic.planning;
22

3+
import aima.core.logic.fol.parsing.ast.Variable;
34
import aima.core.logic.planning.*;
45
import org.junit.Assert;
56
import org.junit.Test;
67

8+
import java.util.Arrays;
79
import java.util.List;
810

911
/**
10-
* @author samagra
1112
* @author Ruediger Lunde
1213
*/
1314
public class GraphPlanAlgorithmTest {
@@ -33,13 +34,29 @@ public void spareTireTest() {
3334

3435
@Test
3536
public void levelOffTest() {
36-
GraphPlanAlgorithm algorithm = new GraphPlanAlgorithm();
3737
PlanningProblem stProblem = PlanningProblemFactory.spareTireProblem();
38-
State initialState = new State("Tire(Flat)^Tire(Spare)^At(Flat,Axle)"); //^At(Spare,Trunk)");
39-
PlanningProblem modifiedProblem = new PlanningProblem(initialState, stProblem.getGoalState(), stProblem.getActionSchemas());
38+
State initialState = new State("Tire(Flat)^Tire(Spare)^At(Flat,Axle)");
39+
PlanningProblem modifiedProblem = new PlanningProblem(initialState,
40+
stProblem.getGoalState(), stProblem.getActionSchemas());
41+
GraphPlanAlgorithm algorithm = new GraphPlanAlgorithm();
4042
List<List<ActionSchema>> solution = algorithm.graphPlan(modifiedProblem);
4143
Assert.assertEquals(4, algorithm.getGraph().numLevels());
4244
Assert.assertNull(solution);
45+
}
4346

47+
@Test
48+
public void negativeLiteralsNeededInFirstGraphLevel() {
49+
State initialState = new State("Device(Radio1)");
50+
State goalState = new State("On(Radio1)");
51+
Variable d = new Variable("d");
52+
ActionSchema switchOnAction = new ActionSchema("switch-on", List.of(d),
53+
"Device(d)^~On(d)",
54+
"On(d)");
55+
PlanningProblem problem = new PlanningProblem(initialState, goalState, switchOnAction);
56+
GraphPlanAlgorithm algorithm = new GraphPlanAlgorithm();
57+
List<List<ActionSchema>> solution = algorithm.graphPlan(problem);
58+
Assert.assertEquals(1, solution.size());
4459
}
60+
61+
4562
}

0 commit comments

Comments
 (0)