Skip to content

Commit a26b409

Browse files
committed
First implementation for heuristic forward state-space search added.
1 parent 84bcb92 commit a26b409

File tree

8 files changed

+207
-93
lines changed

8 files changed

+207
-93
lines changed

aima-core/src/main/java/aima/core/logic/fol/inference/FOLFCAsk.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public InferenceResult ask(FOLKnowledgeBase KB, Sentence query) {
8686
Literal alpha = new Literal((AtomicSentence) query);
8787

8888
// local variables: new, the new sentences inferred on each iteration
89-
List<Literal> newSentences = new ArrayList<Literal>();
89+
List<Literal> newSentences = new ArrayList<>();
9090

9191
// Ensure query is not already a know fact before
9292
// attempting forward chaining.

aima-core/src/main/java/aima/core/logic/fol/parsing/ast/Predicate.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313
public class Predicate implements AtomicSentence {
1414
private String predicateName;
15-
private List<Term> terms = new ArrayList<Term>();
15+
private List<Term> terms = new ArrayList<>();
1616
private String stringRep = null;
1717
private int hashCode = 0;
1818

@@ -48,7 +48,7 @@ public Object accept(FOLVisitor v, Object arg) {
4848
}
4949

5050
public Predicate copy() {
51-
List<Term> copyTerms = new ArrayList<Term>();
51+
List<Term> copyTerms = new ArrayList<>();
5252
for (Term t : terms) {
5353
copyTerms.add(t.copy());
5454
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
* @author Ruediger Lunde
1818
*/
1919
public class BackwardStateSpaceSearchProblem extends GeneralProblem<List<Literal>, ActionSchema> {
20-
PlanningProblem pProblem;
21-
List<ActionSchema> propositionalisedActions;
20+
protected PlanningProblem pProblem;
21+
protected List<ActionSchema> propositionalisedActions;
2222

2323
public BackwardStateSpaceSearchProblem(PlanningProblem pProblem) {
2424
this.pProblem = pProblem;

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import aima.core.logic.fol.kb.data.Literal;
44
import aima.core.search.framework.problem.GeneralProblem;
5+
import aima.core.search.framework.problem.StepCostFunction;
56

67
import java.util.ArrayList;
78
import java.util.Comparator;
@@ -17,18 +18,23 @@
1718
* @author Ruediger Lunde
1819
*/
1920
public class ForwardStateSpaceSearchProblem extends GeneralProblem<List<Literal>, ActionSchema> {
20-
PlanningProblem pProblem;
21-
List<ActionSchema> propositionalisedActions;
21+
protected PlanningProblem pProblem;
22+
protected List<ActionSchema> propositionalisedActions;
2223

2324
public ForwardStateSpaceSearchProblem(PlanningProblem pProblem) {
25+
this(pProblem, pProblem.getPropositionalisedActions(), (s, a, sp) -> 1);
26+
}
27+
28+
public ForwardStateSpaceSearchProblem(PlanningProblem pProblem, List<ActionSchema> propositionalisedActions,
29+
StepCostFunction<List<Literal>, ActionSchema> stepCostFn) {
2430
this.pProblem = pProblem;
25-
propositionalisedActions = pProblem.getPropositionalisedActions();
31+
this.propositionalisedActions = propositionalisedActions;
2632

2733
initialState = pProblem.getInitialState().getFluents();
2834
actionsFn = this::actions;
2935
resultFn = this::result;
3036
goalTest = s -> s.containsAll(pProblem.getGoalState().getFluents());
31-
stepCostFn = (s, a, sp) -> 1;
37+
this.stepCostFn = stepCostFn;
3238
}
3339

3440
List<ActionSchema> actions(List<Literal> state) {

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22

33
import aima.core.logic.fol.kb.data.Literal;
44

5-
import java.util.ArrayList;
6-
import java.util.Collections;
7-
import java.util.HashMap;
8-
import java.util.List;
5+
import java.util.*;
96

107
/**
118
* Artificial Intelligence A Modern Approach (3rd Edition): page 379.<br>
@@ -52,7 +49,36 @@ public void expand(PlanningProblem problem) {
5249
literalLevels.add(litLevelNext);
5350
}
5451

55-
private Level<ActionSchema, Literal> createActionLevel(Level<Literal, ActionSchema> prevLevel, PlanningProblem problem) {
52+
/**
53+
* A graph is said to be levelled off if two consecutive levels are identical.
54+
*
55+
* @return Boolean stating if the graph is levelled off.
56+
*/
57+
public boolean levelledOff() {
58+
if (numLevels() < 2)
59+
return false;
60+
return getLiteralLevel(numLevels() - 1).equals(getLiteralLevel(numLevels() - 2));
61+
}
62+
63+
public Set<ActionSchema> getAllActions() {
64+
Set<ActionSchema> result = new LinkedHashSet<>();
65+
for (Level<ActionSchema, Literal> level : actionLevels)
66+
result.addAll(level.getLevelObjects());
67+
return result;
68+
}
69+
70+
public int getFirstLevelOfOccurrence(Literal literal) {
71+
int result = 0;
72+
for (Level<Literal, ActionSchema> level : literalLevels) {
73+
if (level.getLevelObjects().contains(literal))
74+
return result;
75+
result++;
76+
}
77+
return Integer.MAX_VALUE;
78+
}
79+
80+
private Level<ActionSchema, Literal> createActionLevel(Level<Literal, ActionSchema> prevLevel,
81+
PlanningProblem problem) {
5682
Level<ActionSchema, Literal> result = new Level<>(prevLevel, problem);
5783
// add actions with empty precondition
5884
for (ActionSchema action : problem.getPropositionalisedActions()) {
@@ -67,7 +93,8 @@ private Level<ActionSchema, Literal> createActionLevel(Level<Literal, ActionSche
6793
}
6894

6995
// prevLevel can be null
70-
private Level<Literal, ActionSchema> createLiteralLevel(Level<ActionSchema, Literal> prevLevel, PlanningProblem problem) {
96+
private Level<Literal, ActionSchema> createLiteralLevel(Level<ActionSchema, Literal> prevLevel,
97+
PlanningProblem problem) {
7198
Level<Literal, ActionSchema> result = (prevLevel == null)
7299
? new Level<>(problem.getInitialState().getFluents(), problem)
73100
: new Level<>(prevLevel, problem);

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

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public List<List<ActionSchema>> graphPlan(PlanningProblem problem) {
7171
nogoods.put(tl, goals);
7272
}
7373
// if graph and nogoods have both leveled off then return failure
74-
if (levelledOff(graph) && leveledOff(nogoods))
74+
if (graph.levelledOff() && leveledOff(nogoods))
7575
return null;
7676
// graph ← EXPAND-GRAPH(graph, problem)
7777
graph.expand(problem);
@@ -180,29 +180,13 @@ private boolean checkAllGoalsNonMutex(Level<Literal, ActionSchema> level, List<L
180180
return (!mutexCheck);
181181
}
182182

183-
/**
184-
* A graph is said to be levelled off if two consecutive levels are identical.
185-
*
186-
* @return Boolean stating if the hashtable is levelled off.
187-
*/
188183
private boolean leveledOff(Hashtable<Integer, List<Literal>> nogoods) {
189184
int lastLevel = nogoods.size()-1;
190185
if (lastLevel < 1)
191186
return false;
192187
return nogoods.get(lastLevel).equals(nogoods.get(lastLevel-1));
193188
}
194189

195-
/**
196-
* A graph is said to be levelled off if two consecutive levels are identical.
197-
*
198-
* @return Boolean stating if the graph is levelled off.
199-
*/
200-
private boolean levelledOff(Graph graph) {
201-
if (graph.numLevels() < 2)
202-
return false;
203-
return graph.getLiteralLevel(graph.numLevels() - 1).equals(graph.getLiteralLevel(graph.numLevels() - 2));
204-
}
205-
206190
public List<List<ActionSchema>> generateCombinations(List<List<ActionSchema>> actionLists) {
207191
List<List<ActionSchema>> result = new ArrayList<>();
208192
if (actionLists.size() == 1) {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package aima.core.logic.planning;
2+
3+
import aima.core.logic.fol.kb.data.Literal;
4+
import aima.core.search.framework.Node;
5+
import aima.core.search.framework.QueueBasedSearch;
6+
import aima.core.search.framework.problem.StepCostFunction;
7+
import aima.core.search.framework.qsearch.GraphSearch;
8+
import aima.core.search.informed.AStarSearch;
9+
10+
import java.util.*;
11+
import java.util.function.ToDoubleFunction;
12+
13+
/**
14+
* Implements a simple heuristic forward state-space search algorithm using A*. By default, a level sum heuristic
15+
* is used. Heuristic function as well as the step-cost function can be replaced.
16+
*
17+
* @author Ruediger Lunde
18+
*/
19+
public class HeuristicForwardStateSpaceSearchAlgorithm {
20+
21+
private ToDoubleFunction<Node<List<Literal>, ActionSchema>> heuristicFn = n -> levelSumHeuristic(n.getState());
22+
private StepCostFunction<List<Literal>, ActionSchema> stepCostFn = (s0, a, s1) -> 1;
23+
24+
PlanningProblem pProblem;
25+
private final Graph graph;
26+
private final HashMap<Literal, Integer> literalLookup = new HashMap<>();
27+
28+
public HeuristicForwardStateSpaceSearchAlgorithm(final PlanningProblem pProblem) {
29+
this.pProblem = pProblem;
30+
// Compute planning graph. It is used to filter propositionalised actions and for heuristic value computation.
31+
graph = new Graph(pProblem);
32+
while (!graph.levelledOff())
33+
graph.expand(pProblem);
34+
literalLookup.clear();
35+
}
36+
37+
public void setHeuristicFn(ToDoubleFunction<Node<List<Literal>, ActionSchema>> heuristicFn) {
38+
this.heuristicFn = heuristicFn;
39+
}
40+
41+
public void setStepCostFn(StepCostFunction<List<Literal>, ActionSchema> stepCostFn) {
42+
this.stepCostFn = stepCostFn;
43+
}
44+
45+
public Optional<List<ActionSchema>> search() {
46+
ForwardStateSpaceSearchProblem sProblem =
47+
new ForwardStateSpaceSearchProblem(pProblem, new ArrayList<>(graph.getAllActions()), stepCostFn);
48+
QueueBasedSearch<List<Literal>, ActionSchema> search =
49+
new AStarSearch<>(new GraphSearch<>(), heuristicFn);
50+
return search.findActions(sProblem);
51+
}
52+
53+
private double levelSumHeuristic(List<Literal> state) {
54+
double result = 0;
55+
for (Literal literal : pProblem.getGoalState().getFluents()) {
56+
if (!state.contains(literal)) {
57+
Integer level = literalLookup.get(literal);
58+
if (level == null) {
59+
level = graph.getFirstLevelOfOccurrence(literal);
60+
literalLookup.put(literal, level);
61+
}
62+
result = result + level;
63+
}
64+
}
65+
return result;
66+
}
67+
}

0 commit comments

Comments
 (0)