Skip to content

Commit 3859e6c

Browse files
committed
Classes Graph and Level refactored for further debugging. Generics are used to support compile-time type checking.
1 parent 69df2bb commit 3859e6c

File tree

6 files changed

+280
-288
lines changed

6 files changed

+280
-288
lines changed
Lines changed: 163 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package aima.core.logic.planning;
22

3+
import aima.core.agent.Action;
4+
import aima.core.logic.fol.kb.data.Literal;
5+
36
import java.util.ArrayList;
7+
import java.util.Collections;
8+
import java.util.HashMap;
49
import java.util.List;
510

611
/**
@@ -12,42 +17,181 @@
1217
* followed by A i ; until we reach a termination condition.
1318
*
1419
* @author samagra
20+
* @author Ruediger Lunde
1521
*/
1622
public class Graph {
17-
private ArrayList<Level> levels;// Levels
18-
private List<ActionSchema> propositionalisedActions;
23+
private final List<Level<Literal, ActionSchema>> literalLevels;
24+
private final List<Level<ActionSchema, Literal>> actionLevels;
1925

2026
public Graph(Problem problem) {
21-
levels = new ArrayList<>();
22-
levels.add(new Level(null, problem));
23-
propositionalisedActions = problem.getPropositionalisedActions();
27+
literalLevels = new ArrayList<>();
28+
literalLevels.add(createLiteralLevel(null, problem));
29+
actionLevels = new ArrayList<>();
2430
}
2531

26-
public Level getLevel(int i) {
27-
return levels.get(i);
32+
public Level<Literal, ActionSchema> getLiteralLevel(int i) {
33+
return literalLevels.get(i);
2834
}
2935

30-
public int numLevels() {
31-
return levels.size();
36+
public Level<ActionSchema, Literal> getActionLevel(int i) {
37+
return actionLevels.get(i);
3238
}
3339

34-
public ArrayList<Level> getLevels() {
35-
return levels;
40+
public List<Level<Literal, ActionSchema>> getLiteralLevels() {
41+
return literalLevels;
3642
}
3743

38-
public List<ActionSchema> getPropositionalisedActions() {
39-
return propositionalisedActions;
44+
public int numLevels() {
45+
return literalLevels.size();
4046
}
4147

4248
/**
43-
* This method adds levels (an action and a state level) for a new state
49+
* This method adds a level (an action and a state level) for a new state
4450
* to the planning graph.
4551
*/
4652
public void expand(Problem problem) {
47-
Level level0 = levels.get(levels.size() - 1);
48-
Level level1 = new Level(level0, problem); // new action level
49-
Level level2 = new Level(level1, problem); // new state level
50-
levels.add(level1);
51-
levels.add(level2);
53+
Level<Literal, ActionSchema> litLevelCurr = literalLevels.get(numLevels() - 1);
54+
Level<ActionSchema, Literal> actLevelNext = createActionLevel(litLevelCurr, problem);
55+
Level<Literal, ActionSchema> litLevelNext = createLiteralLevel(actLevelNext, problem);
56+
actionLevels.add(actLevelNext);
57+
literalLevels.add(litLevelNext);
58+
}
59+
60+
private Level<ActionSchema, Literal> createActionLevel(Level<Literal, ActionSchema> prevLevel, Problem problem) {
61+
Level<ActionSchema, Literal> result = new Level<>(prevLevel, problem);
62+
// add actions with empty precondition
63+
for (ActionSchema action : problem.getPropositionalisedActions()) {
64+
if (action.getPrecondition().size()==0)
65+
result.getLevelObjects().add(action);
66+
}
67+
// set next links
68+
for (ActionSchema action : result.getLevelObjects())
69+
result.putToNextLinks(action, new ArrayList<>(action.getEffects()));
70+
calculateMutexLinksForActionLevel(result);
71+
return result;
72+
}
73+
74+
// prevLevel can be null
75+
private Level<Literal, ActionSchema> createLiteralLevel(Level<ActionSchema, Literal> prevLevel, Problem problem) {
76+
Level<Literal, ActionSchema> result = (prevLevel == null)
77+
? new Level<>(problem.getInitialState().getFluents(), problem)
78+
: new Level<>(prevLevel, problem);
79+
calculateNextLinks(result, problem);
80+
calculateMutexLinksForLiteralLevel(result);
81+
return result;
82+
}
83+
84+
private void calculateNextLinks(Level<Literal, ActionSchema> level, Problem problem) {
85+
// add applicable actions:
86+
for (ActionSchema action : problem.getPropositionalisedActions()) {
87+
if (level.getLevelObjects().containsAll(action.getPrecondition()))
88+
for (Literal literal : action.getPrecondition())
89+
level.addToNextLinks(literal, action);
90+
}
91+
// add persistence actions:
92+
for (Literal literal : level.getLevelObjects()) {
93+
ActionSchema action = new ActionSchema(ActionSchema.NO_OP, null,
94+
Collections.singletonList(literal),
95+
Collections.singletonList(literal));
96+
level.addToNextLinks(literal, action);
97+
}
98+
}
99+
100+
private void calculateMutexLinksForActionLevel(Level<ActionSchema, Literal> level) {
101+
List<ActionSchema> actions = level.getLevelObjects();
102+
ActionSchema firstAction, secondAction;
103+
boolean checkMutex;
104+
105+
for (int i = 0; i < actions.size(); i++) {
106+
firstAction = actions.get(i);
107+
List<Literal> firstActionEffects = firstAction.getEffects();
108+
List<Literal> firstActionPositiveEffects = firstAction.getEffectsPositiveLiterals();
109+
List<Literal> firstActionPreconditions = firstAction.getPrecondition();
110+
for (int j = i + 1; j < actions.size(); j++) {
111+
checkMutex = false;
112+
secondAction = actions.get(j);
113+
List<Literal> secondActionEffects = secondAction.getEffects();
114+
List<Literal> secondActionNegatedLiterals = secondAction.getEffectsNegativeLiterals();
115+
List<Literal> secondActionPreconditions = secondAction.getPrecondition();
116+
for (Literal posLiteral : firstActionPositiveEffects) {
117+
for (Literal negatedLit : secondActionNegatedLiterals)
118+
if (posLiteral.equals(new Literal(negatedLit.getAtomicSentence(), false)))
119+
checkMutex = true;
120+
}
121+
if (!checkMutex) {
122+
if (checkInterference(secondActionPreconditions, firstActionEffects))
123+
checkMutex = true;
124+
if (checkInterference(firstActionPreconditions, secondActionEffects))
125+
checkMutex = true;
126+
}
127+
if (!checkMutex) {
128+
HashMap<Literal, List<Literal>> prevMutex = level.getPrevLevel().getMutexLinks();
129+
if (prevMutex != null) {
130+
for (Literal firstActionPrecondition : firstActionPreconditions)
131+
for (Literal secondActionPrecondition : secondActionPreconditions)
132+
if (prevMutex.get(firstActionPrecondition) != null
133+
&& prevMutex.get(firstActionPrecondition).contains
134+
(secondActionPrecondition))
135+
checkMutex = true;
136+
}
137+
}
138+
if (checkMutex) {
139+
level.addToMutexLinks(firstAction, secondAction);
140+
level.addToMutexLinks(secondAction, firstAction);
141+
}
142+
}
143+
}
144+
}
145+
146+
private boolean checkInterference(List<Literal> firstActionPreconditions, List<Literal> secondActionEffects) {
147+
boolean checkMutex = false;
148+
for (Literal secondActionEffect : secondActionEffects) {
149+
for (Literal firstActionPrecondition : firstActionPreconditions) {
150+
if (secondActionEffect.equals(new Literal(firstActionPrecondition.getAtomicSentence(),
151+
firstActionPrecondition.isPositiveLiteral()))) {
152+
checkMutex = true;
153+
}
154+
}
155+
}
156+
return checkMutex;
157+
}
158+
159+
private void calculateMutexLinksForLiteralLevel(Level<Literal, ActionSchema> level) {
160+
Level<ActionSchema, Literal> prevLevel = level.getPrevLevel();
161+
if (prevLevel == null)
162+
return;
163+
List<Literal> literals = level.getLevelObjects();
164+
Literal firstLiteral, secondLiteral;
165+
List<ActionSchema> possibleActionsFirst, possibleActionsSecond;
166+
for (int i = 0; i < literals.size(); i++) {
167+
firstLiteral = literals.get(i);
168+
possibleActionsFirst = level.getPrevLinks().get(firstLiteral);
169+
for (int j = i; j < literals.size(); j++) {
170+
secondLiteral = literals.get(j);
171+
possibleActionsSecond = level.getPrevLinks().get(secondLiteral);
172+
if (firstLiteral.getAtomicSentence().getSymbolicName().equals
173+
(secondLiteral.getAtomicSentence().getSymbolicName()) &&
174+
((firstLiteral.isNegativeLiteral() && secondLiteral.isPositiveLiteral()) ||
175+
firstLiteral.isPositiveLiteral() && secondLiteral.isNegativeLiteral())) {
176+
level.addToMutexLinks(firstLiteral, secondLiteral);
177+
level.addToMutexLinks(secondLiteral, firstLiteral);
178+
} else {
179+
boolean eachPossiblePairExclusive = true;
180+
HashMap<ActionSchema, List<ActionSchema>> prevMutexes = prevLevel.getMutexLinks();
181+
for (ActionSchema firstAction : possibleActionsFirst) {
182+
for (ActionSchema secondAction : possibleActionsSecond) {
183+
if ((!prevMutexes.containsKey(firstAction))
184+
|| (!prevMutexes.get(firstAction).contains(secondAction))) {
185+
eachPossiblePairExclusive = false;
186+
}
187+
}
188+
}
189+
if (eachPossiblePairExclusive) {
190+
level.addToMutexLinks(firstLiteral, secondLiteral);
191+
level.addToMutexLinks(secondLiteral, firstLiteral);
192+
}
193+
}
194+
}
195+
}
52196
}
53197
}

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

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ public List<List<ActionSchema>> graphPlan(Problem problem) {
4747
List<Literal> goals = problem.getGoalState().getFluents();
4848
// nogoods ← an empty hash table
4949
Hashtable<Integer, List<Literal>> nogoods = new Hashtable<>();
50-
Level state;
50+
Level<Literal, ActionSchema> state;
5151
// for tl = 0 to ∞ do
5252
for (int tl = 0; ; tl++) {
5353
// St
54-
state = graph.getLevels().get(2 * tl);
54+
state = graph.getLiteralLevels().get(tl);
5555
// if goals all non-mutex in St of graph then
5656
if (checkAllGoalsNonMutex(state, goals)) {
5757
// solution ← EXTRACT-SOLUTION(graph, goals, NUMLEVELS(graph), nogoods)
58-
List<List<ActionSchema>> solution = extractSolution(graph, goals, graph.numLevels()-1, nogoods);
58+
List<List<ActionSchema>> solution = extractSolution(graph, goals, tl, nogoods);
5959
// if solution ≠ failure then return solution
6060
if (solution != null && solution.size() != 0)
6161
return solution;
@@ -101,13 +101,11 @@ private List<List<ActionSchema>> extractSolution(Graph graph, List<Literal> goal
101101
if (nogoods.containsKey(level) && nogoods.get(level).contains(goals))
102102
return null;
103103

104-
Level currLevel = graph.getLevels().get(level);
104+
Level<Literal, ActionSchema> currLevel = graph.getLiteralLevels().get(level);
105105
List<List<ActionSchema>> setOfPossibleActions = new ArrayList<>();
106-
HashMap<Object, List<Object>> mutexLinks = currLevel.getPrevLevel().getMutexLinks();
106+
HashMap<ActionSchema, List<ActionSchema>> mutexLinks = currLevel.getPrevLevel().getMutexLinks();
107107
for (Literal literal : goals) {
108-
List<ActionSchema> possibleActionsPerLiteral = new ArrayList<>();
109-
for (Object action : currLevel.getPrevLinks().get(literal))
110-
possibleActionsPerLiteral.add((ActionSchema) action);
108+
List<ActionSchema> possibleActionsPerLiteral = new ArrayList<>(currLevel.getPrevLinks().get(literal));
111109
setOfPossibleActions.add(possibleActionsPerLiteral);
112110
}
113111
List<List<ActionSchema>> allPossibleSubSets = generateCombinations(setOfPossibleActions);
@@ -129,7 +127,7 @@ private List<List<ActionSchema>> extractSolution(Graph graph, List<Literal> goal
129127
newGoals.add(literal);
130128
}
131129
newGoals.sort(Comparator.comparing(Literal::hashCode)); // defined order necessary for nogood test
132-
List<List<ActionSchema>> solution = extractSolution(graph, newGoals, level-2, nogoods);
130+
List<List<ActionSchema>> solution = extractSolution(graph, newGoals, level-1, nogoods);
133131
if (solution != null) {
134132
solution.add(possibleSet);
135133
return solution;
@@ -154,15 +152,15 @@ public List<ActionSchema> asFlatList(List<List<ActionSchema>> solution) {
154152
* @param goals List of goals to be checked
155153
* @return Boolean representing if goals all non mutex in St
156154
*/
157-
private boolean checkAllGoalsNonMutex(Level level, List<Literal> goals) {
155+
private boolean checkAllGoalsNonMutex(Level<Literal, ActionSchema> level, List<Literal> goals) {
158156
if (!level.getLevelObjects().containsAll(goals))
159157
return false;
160158
boolean mutexCheck = false;
161-
for (Object literal : goals) {
162-
List<Object> mutexOfGoal = level.getMutexLinks().get(literal);
159+
for (Literal literal : goals) {
160+
List<Literal> mutexOfGoal = level.getMutexLinks().get(literal);
163161
if (mutexOfGoal != null) {
164162
for (Object object : mutexOfGoal) {
165-
if (goals.contains((Literal) object)) {
163+
if (goals.contains(object)) {
166164
mutexCheck = true;
167165
break;
168166
}
@@ -193,7 +191,7 @@ private boolean leveledOff(Hashtable<Integer, List<Literal>> nogoods) {
193191
private boolean levelledOff(Graph graph) {
194192
if (graph.numLevels() < 3)
195193
return false;
196-
return graph.getLevel(graph.numLevels() - 1).equals(graph.getLevel(graph.numLevels() - 3));
194+
return graph.getLiteralLevel(graph.numLevels() - 1).equals(graph.getLiteralLevel(graph.numLevels() - 3));
197195
}
198196

199197
public List<List<ActionSchema>> generateCombinations(List<List<ActionSchema>> actionLists) {

0 commit comments

Comments
 (0)