diff --git a/aima-core/src/main/java/aima/core/logic/planning/PlanningProblemFactory.java b/aima-core/src/main/java/aima/core/logic/planning/PlanningProblemFactory.java index 5389fa60ff..30e41604c1 100644 --- a/aima-core/src/main/java/aima/core/logic/planning/PlanningProblemFactory.java +++ b/aima-core/src/main/java/aima/core/logic/planning/PlanningProblemFactory.java @@ -1,12 +1,12 @@ package aima.core.logic.planning; +import aima.core.logic.fol.kb.data.Literal; import aima.core.logic.fol.parsing.ast.Constant; import aima.core.logic.fol.parsing.ast.Variable; +import aima.core.logic.planning.angelicsearch.AngelicHLA; import aima.core.logic.planning.hierarchicalsearch.HighLevelAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; /** * A problem factory to generate planning problems. @@ -142,4 +142,22 @@ public static HighLevelAction getHlaAct(Problem problem) { act.addRefinement(new ArrayList<>()); return act; } + + public static Problem getAngelicABProblem(){ + return new Problem(new State("~A"), + new State("A^C"), + new HashSet<>()); + } + + public static List getAngelicInitialPlan(List refinements,Problem problem,String goal){ + List effects = new ArrayList<>(); + AngelicHLA act = new AngelicHLA("act",null,problem.getInitialState().getFluents(), + Utils.angelicParse(goal)); + for (Object obj : + refinements) { + act.addRefinement(Arrays.asList(obj, act)); + } + act.addRefinement(new ArrayList<>()); + return Collections.singletonList(act); + } } diff --git a/aima-core/src/main/java/aima/core/logic/planning/State.java b/aima-core/src/main/java/aima/core/logic/planning/State.java index 320420b141..3daaec21cc 100644 --- a/aima-core/src/main/java/aima/core/logic/planning/State.java +++ b/aima-core/src/main/java/aima/core/logic/planning/State.java @@ -1,8 +1,10 @@ package aima.core.logic.planning; import aima.core.logic.fol.kb.data.Literal; +import aima.core.logic.planning.angelicsearch.AngelicHLA; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; /** @@ -83,6 +85,10 @@ public boolean isApplicable(ActionSchema a) { return this.getFluents().containsAll(a.getPrecondition()); } + public boolean isApplicable(AngelicHLA angelicHLA) { + return this.getFluents().containsAll(angelicHLA.getPrecondition()); + } + public List getFluents() { return fluents; } @@ -104,4 +110,156 @@ public int hashCode() { } return hashCode; } + + public HashSet optimisticReach(AngelicHLA angelicAction) { + HashSet result = new HashSet<>(); + State thisStateCopy = new State(new ArrayList<>(this.getFluents())); + if (!this.isApplicable(angelicAction)) { + result.add(new State(new ArrayList<>(this.getFluents()))); + return result; + } else { + for (Literal fluent : + angelicAction.getEffectsNegativeLiterals()) { + Literal tempFluent = new Literal(fluent.getAtomicSentence()); + thisStateCopy.fluents.remove(tempFluent); + tempFluent = new Literal(fluent.getAtomicSentence(), true); + if (!thisStateCopy.fluents.contains(tempFluent)) + thisStateCopy.fluents.add(tempFluent); + } + for (Literal fluent : + angelicAction.getEffectsPositiveLiterals()) { + Literal tempFluent = new Literal(fluent.getAtomicSentence(), true); + tempFluent = new Literal(tempFluent.getAtomicSentence()); + if (!thisStateCopy.fluents.contains(tempFluent)) { + thisStateCopy.fluents.add(tempFluent); + tempFluent = new Literal(tempFluent.getAtomicSentence(), true); + thisStateCopy.fluents.remove(tempFluent); + } + } + result.add(new State(new ArrayList<>(thisStateCopy.getFluents()))); + for (Literal literal : + angelicAction.getEffectsMaybePositiveLiterals()) { + List listToAdd = new ArrayList<>(); + for (State state : + result) { + State tempCopyState = new State(new ArrayList<>(state.getFluents())); + if (!tempCopyState.getFluents().contains(literal)) { + Literal tempFluent = new Literal(literal.getAtomicSentence(), true); + tempCopyState.fluents.remove(tempFluent); + tempCopyState.getFluents().add(literal); + listToAdd.add(new State(new ArrayList<>(tempCopyState.getFluents()))); + } + } + result.addAll(listToAdd); + } + for (Literal literal : + angelicAction.getEffectsMaybeNegativeLiterals()) { + List listToAdd = new ArrayList<>(); + for (State state : + result) { + State tempCopyState = new State(new ArrayList<>(state.getFluents())); + Literal tempFluent = new Literal(literal.getAtomicSentence(), true); + if (!tempCopyState.getFluents().contains(tempFluent)) { + tempFluent = new Literal(tempFluent.getAtomicSentence()); + tempCopyState.getFluents().remove(tempFluent); + tempFluent = new Literal(tempFluent.getAtomicSentence(), true); + tempCopyState.fluents.add(tempFluent); + listToAdd.add(new State(new ArrayList<>(tempCopyState.getFluents()))); + } + } + result.addAll(listToAdd); + } + } + return result; + } + + public HashSet pessimisticReach(AngelicHLA angelicAction) { + HashSet result = new HashSet<>(); + State thisStateCopy = new State(new ArrayList<>(this.getFluents())); + if (!this.isApplicable(angelicAction)) { + result.add(new State(new ArrayList<>(this.getFluents()))); + return result; + } else { + for (Literal fluent : + angelicAction.getEffectsNegativeLiterals()) { + Literal tempFluent = new Literal(fluent.getAtomicSentence()); + thisStateCopy.fluents.remove(tempFluent); + tempFluent = new Literal(fluent.getAtomicSentence(), true); + if (!thisStateCopy.fluents.contains(tempFluent)) + thisStateCopy.fluents.add(tempFluent); + } + for (Literal fluent : + angelicAction.getEffectsPositiveLiterals()) { + Literal tempFluent = new Literal(fluent.getAtomicSentence(), true); + tempFluent = new Literal(tempFluent.getAtomicSentence()); + if (!thisStateCopy.fluents.contains(tempFluent)) { + thisStateCopy.fluents.add(tempFluent); + tempFluent = new Literal(tempFluent.getAtomicSentence(), true); + thisStateCopy.fluents.remove(tempFluent); + } + } + result.add(new State(new ArrayList<>(thisStateCopy.getFluents()))); + return result; + } + } + + public HashSet optimisticReach(List plan) { + HashSet result = new HashSet<>(); + result.add(new State(this.getFluents())); + if (plan.isEmpty()) { + return result; + } + for (Object action : + plan) { + HashSet currResult = new HashSet<>(); + if (action instanceof ActionSchema) { + for (State state : + result) { + currResult.add(state.result((ActionSchema) action)); + } + } else if (action instanceof AngelicHLA) { + for (State state : + result) { + currResult.addAll(state.optimisticReach((AngelicHLA) action)); + } + } + result = currResult; + } + return result; + } + + public HashSet pessimisticReach(List plan) { + HashSet result = new HashSet<>(); + result.add(new State(this.getFluents())); + if (plan.isEmpty()) { + return result; + } + for (Object action : + plan) { + HashSet currResult = new HashSet<>(); + if (action instanceof ActionSchema) { + for (State state : + result) { + currResult.add(state.result((ActionSchema) action)); + } + } else if (action instanceof AngelicHLA) { + for (State state : + result) { + currResult.addAll(state.pessimisticReach((AngelicHLA) action)); + } + } + result = currResult; + } + return result; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder("State:"); + for (Literal literal : + this.getFluents()) { + result.append("\n").append(literal.toString()); + } + return result.toString(); + } } diff --git a/aima-core/src/main/java/aima/core/logic/planning/Utils.java b/aima-core/src/main/java/aima/core/logic/planning/Utils.java index c862072909..f3cfb5cbee 100644 --- a/aima-core/src/main/java/aima/core/logic/planning/Utils.java +++ b/aima-core/src/main/java/aima/core/logic/planning/Utils.java @@ -7,6 +7,8 @@ import aima.core.logic.fol.parsing.ast.Variable; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; /** @@ -50,4 +52,64 @@ public static List parse(String s) { } return literals; } + + public static List> angelicParse(String s){ + HashSet positive = new HashSet<>(); + HashSet negative = new HashSet<>(); + HashSet maybePositive = new HashSet<>(); + HashSet maybeNegative = new HashSet<>(); + if (s.isEmpty()) + return new ArrayList<>(Arrays.asList(positive,negative,maybePositive,maybeNegative)); + s = s.replaceAll("\\s+", ""); + String[] tokens = s.split("\\^"); + Literal literal; + for (String token : + tokens) { + String[] terms = token.split("[(,)]"); + ArrayList literalTerms = new ArrayList<>(); + Term term; + String termString; + for (int i = 1; i < terms.length; i++) { + termString = terms[i]; + if (termString.equals(termString.toLowerCase())) { + term = new Variable(termString); + } else { + term = new Constant(termString); + } + literalTerms.add(term); + } + + String name = terms[0]; + if (name.charAt(0) == '~'){ + if (name.charAt(1)=='+'){ + if (name.charAt(2)=='-') { + name = name.substring(3); + literal = new Literal(new Predicate(name,literalTerms)); + maybeNegative.add(literal); + maybePositive.add(literal); + } + else { + name = name.substring(2); + literal = new Literal(new Predicate(name,literalTerms)); + maybePositive.add(literal); + } + } + else if (name.charAt(1)=='-'){ + name = name.substring(2); + literal = new Literal(new Predicate(name,literalTerms)); + maybeNegative.add(literal); + } + else { + name = name.substring(1); + literal = new Literal(new Predicate(name,literalTerms)); + negative.add(literal); + } + } + else { + literal = new Literal(new Predicate(name,literalTerms)); + positive.add(literal); + } + } + return new ArrayList<>(Arrays.asList(positive,negative,maybePositive,maybeNegative)); + } } diff --git a/aima-core/src/main/java/aima/core/logic/planning/angelicsearch/AngelicHLA.java b/aima-core/src/main/java/aima/core/logic/planning/angelicsearch/AngelicHLA.java new file mode 100644 index 0000000000..feac2f002a --- /dev/null +++ b/aima-core/src/main/java/aima/core/logic/planning/angelicsearch/AngelicHLA.java @@ -0,0 +1,190 @@ +package aima.core.logic.planning.angelicsearch; + +import aima.core.logic.fol.kb.data.Literal; +import aima.core.logic.fol.parsing.ast.Term; +import aima.core.logic.planning.ActionSchema; +import aima.core.logic.planning.Utils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class AngelicHLA { + List variables;// list of variables + List precondition; //PRECONDITION: treated as a conjunction of fluents + List> effects;//EFFECT: treated as a conjunction of fluents + HashSet effectsPositiveLiterals; + HashSet effectsNegativeLiterals; + HashSet effectsMaybePositiveLiterals; + HashSet effectsMaybeNegativeLiterals; + List> refinements = new ArrayList<>(); + private String name;//action name + + public AngelicHLA(String name, List variables, + List precondition, List> effects) { + if (variables == null) + variables = new ArrayList<>(); + this.name = name; + this.variables = variables; + this.precondition = precondition; + this.effects = effects; + effectsNegativeLiterals = new HashSet<>(); + effectsPositiveLiterals = new HashSet<>(); + effectsMaybePositiveLiterals = new HashSet<>(); + effectsMaybeNegativeLiterals = new HashSet<>(); + this.sortEffects(); + } + + public AngelicHLA(String name, List variables, String precondition, String effects) { + this(name, variables, Utils.parse(precondition), Utils.angelicParse(effects)); + } + + public void addRefinement(List newRefinement) { + this.refinements.add(newRefinement); + } + + public List> getRefinements() { + return refinements; + } + + public void setRefinements(List> refinements) { + this.refinements = refinements; + } + + private void sortEffects() { + effectsPositiveLiterals.addAll(this.effects.get(0)); + effectsNegativeLiterals.addAll(this.effects.get(1)); + effectsMaybePositiveLiterals.addAll(this.effects.get(2)); + effectsMaybeNegativeLiterals.addAll(this.effects.get(3)); + } + + public List getVariables() { + return variables; + } + + public List getPrecondition() { + return precondition; + } + + public List> getEffects() { + return effects; + } + + public String getName() { + return name; + } + + public HashSet getEffectsPositiveLiterals() { + return effectsPositiveLiterals; + } + + public HashSet getEffectsNegativeLiterals() { + return effectsNegativeLiterals; + } + + public HashSet getEffectsMaybePositiveLiterals() { + return effectsMaybePositiveLiterals; + } + + public HashSet getEffectsMaybeNegativeLiterals() { + return effectsMaybeNegativeLiterals; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder("Action(" + this.getName() + ")\n\tPRECOND:"); + for (Literal precond : + getPrecondition()) { + result.append("^").append(precond.toString()); + } + result.append("\n\tEFFECT:"); + for (Literal effect : + getEffectsPositiveLiterals()) { + result.append("^").append(effect.toString()); + } + + for (Literal effect : + getEffectsNegativeLiterals()) { + result.append("^~").append(effect.toString()); + } + + for (Literal effect : + getEffectsMaybePositiveLiterals()) { + if (getEffectsMaybeNegativeLiterals().contains(effect)) + result.append("^~+-").append(effect.toString()); + else + result.append("^~+").append(effect.toString()); + } + + for (Literal effect : + getEffectsMaybeNegativeLiterals()) { + result.append("^~-").append(effect.toString()); + } + for (List refinement : + this.getRefinements()) { + result.append("\n"); + for (Object act : + refinement) { + result.append("\n").append(((AngelicHLA) act).getName()); + } + } + + + return result.toString(); + } + + @Override + public int hashCode() { + int hashCode = 17; + for (Literal preCo : + this.getPrecondition()) { + hashCode = 37 * hashCode + preCo.hashCode(); + } + for (Literal effect : + this.getEffectsPositiveLiterals()) { + hashCode = 37 * hashCode + effect.hashCode(); + } + + for (Literal effect : + this.getEffectsNegativeLiterals()) { + hashCode = 37 * hashCode + effect.hashCode(); + } + + for (Literal effect : + this.getEffectsMaybePositiveLiterals()) { + hashCode = 37 * hashCode + effect.hashCode(); + } + + for (Literal effect : + this.getEffectsMaybeNegativeLiterals()) { + hashCode = 37 * hashCode + effect.hashCode(); + } + + for (Term var : + this.getVariables()) { + hashCode = 37 * hashCode + var.hashCode(); + } + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!(obj instanceof AngelicHLA)) + return false; + return this.getName().equals(((AngelicHLA) obj).getName()) && + this.getPrecondition().containsAll(((AngelicHLA) obj).getPrecondition()) + && ((AngelicHLA) obj).getPrecondition().containsAll(this.getPrecondition()) + && this.getEffectsPositiveLiterals().containsAll(((AngelicHLA) obj).getEffectsPositiveLiterals()) + && ((AngelicHLA) obj).getEffectsPositiveLiterals().containsAll(this.getEffectsPositiveLiterals()) + && this.getEffectsNegativeLiterals().containsAll(((AngelicHLA) obj).getEffectsNegativeLiterals()) + && ((AngelicHLA) obj).getEffectsNegativeLiterals().containsAll(this.getEffectsNegativeLiterals()) + && this.getEffectsMaybePositiveLiterals().containsAll(((AngelicHLA) obj).getEffectsMaybePositiveLiterals()) + && ((AngelicHLA) obj).getEffectsMaybePositiveLiterals().containsAll(this.getEffectsMaybePositiveLiterals()) + && this.getEffectsMaybeNegativeLiterals().containsAll(((AngelicHLA) obj).getEffectsMaybeNegativeLiterals()) + && ((AngelicHLA) obj).getEffectsMaybeNegativeLiterals().containsAll(this.getEffectsNegativeLiterals()); + } + + +} diff --git a/aima-core/src/main/java/aima/core/logic/planning/angelicsearch/AngelicSearchAlgorithm.java b/aima-core/src/main/java/aima/core/logic/planning/angelicsearch/AngelicSearchAlgorithm.java new file mode 100644 index 0000000000..e9a934f2cb --- /dev/null +++ b/aima-core/src/main/java/aima/core/logic/planning/angelicsearch/AngelicSearchAlgorithm.java @@ -0,0 +1,142 @@ +package aima.core.logic.planning.angelicsearch; + +import aima.core.logic.planning.ActionSchema; +import aima.core.logic.planning.Problem; +import aima.core.logic.planning.State; + +import java.util.*; + +public class AngelicSearchAlgorithm { + public List angelicSearch(Problem problem, List initialPlan) { + Queue> frontier = new LinkedList<>(); + frontier.add(initialPlan); + while (true) { + if (frontier.isEmpty()) + return null; + for (List obj : + frontier) { + System.out.println("Frontier list"); + for (Object object: + obj) { + System.out.println(object.toString()); + } + } + List plan = frontier.poll(); + boolean flag = false; + for (State state : + problem.getInitialState().optimisticReach(plan)) { + if (state.getFluents().containsAll(problem.getGoalState().getFluents())) + flag = true; + } + System.out.println("Flag ========"+flag); + if (flag) { + if (checkPrimitive(plan)) + return plan; + HashSet guaranteed = new HashSet<>(); + for (State state : + problem.getInitialState().pessimisticReach(plan)) { + if (state.getFluents().containsAll(problem.getGoalState().getFluents())){ + guaranteed.add(state); + System.out.println("guaranteed state== "+ state.toString() ); + } + } + System.out.println( makingProgress(plan, initialPlan) ); + if ((!guaranteed.isEmpty()) && makingProgress(plan, initialPlan)) { + State finalState = guaranteed.iterator().next(); + System.out.println("BOOOOOYEAHHHH"); + return decompose(problem.getInitialState(), plan, finalState); + } + int i = 0; + AngelicHLA hla; + while (i < plan.size() && !(plan.get(i) instanceof AngelicHLA)) + i++; + if (i < plan.size()) + hla = (AngelicHLA) plan.get(i); + else + hla = null; + // prefix,suffix ← the action subsequences before and after hla in plan + List prefix = new ArrayList<>(); + List suffix = new ArrayList<>(); + for (int j = 0; j < i; j++) { + prefix.add( plan.get(j)); + } + System.out.println("Prefix ===== "+prefix.size()); + System.out.println("Prefix"); + for (int j = i + 1; j < plan.size(); j++) { + suffix.add(plan.get(j)); + } + List tempInsertionList = new ArrayList<>(); + HashSet outcomeStates = problem.getInitialState().optimisticReach(prefix); + for (List sequence : + refinements(hla,outcomeStates)){ + tempInsertionList.clear(); + tempInsertionList.addAll(prefix); + tempInsertionList.addAll(sequence); + tempInsertionList.addAll(suffix); + ((LinkedList>) frontier).addLast(new ArrayList<>(tempInsertionList)); + } + } + } + } + + private boolean makingProgress(List plan, List initialPlan) { + return !(plan.containsAll(initialPlan)&&initialPlan.containsAll(plan)); + } + + private boolean checkPrimitive(List plan) { + for (Object obj : + plan) { + if (!(obj instanceof ActionSchema)) + return false; + } + return true; + } + + private List decompose(State initialState, List plan, State finalState) { + List solution = new ArrayList<>(); + while(!plan.isEmpty()){ + Object action = plan.remove(plan.size()-1); + State si = new State(""); + for (State state : + initialState.pessimisticReach(plan)) { + if (state.pessimisticReach(Collections.singletonList(action)).contains(finalState)){ + si = state; + break; + } + } + Problem problem = new Problem(si,finalState,new HashSet<>()); + solution.add(angelicSearch(problem,Collections.singletonList(action))); + finalState = si; + } + return solution; + } + + public List> refinements(AngelicHLA hla, HashSet outcome) { + List> result = new ArrayList<>(); + for (List refinement : + hla.getRefinements()) { + if (refinement.size() > 0) { + if (refinement.get(0) instanceof AngelicHLA) { + for (State state : + outcome) { + if (state.isApplicable((AngelicHLA) refinement.get(0))) { + result.add(refinement); + break; + } + } + } else { + for (State state : + outcome) { + if (state.isApplicable((ActionSchema) refinement.get(0))) { + result.add(refinement); + break; + } + } + } + } else + result.add(refinement); + } + return result; + } +} + diff --git a/aima-core/src/test/java/aima/test/core/unit/logic/planning/StateTest.java b/aima-core/src/test/java/aima/test/core/unit/logic/planning/StateTest.java index e6d1a84c9b..5c333f4493 100644 --- a/aima-core/src/test/java/aima/test/core/unit/logic/planning/StateTest.java +++ b/aima-core/src/test/java/aima/test/core/unit/logic/planning/StateTest.java @@ -5,20 +5,23 @@ import aima.core.logic.fol.parsing.ast.Predicate; import aima.core.logic.planning.ActionSchema; import aima.core.logic.planning.State; +import aima.core.logic.planning.angelicsearch.AngelicHLA; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; /** * @author samagra */ public class StateTest { private Literal testFluentOne, testFluentTwo, testFluentThree, testFluentFour; - private State testState; + private State stateOne, stateTwo, testState; private ActionSchema flyActionOne, flyActionTwo; + private AngelicHLA h1, h2; @Before public void setup() { @@ -38,6 +41,11 @@ public void setup() { flyActionTwo = new ActionSchema("Fly", null, "At(P1,JFK)^Plane(P1)^Airport(SFO)^Airport(JFK)", "~At(P1,JFK)^At(P1,SFO)"); + + h1 = new AngelicHLA("h1", null, "~A", "A^~-B"); + h2 = new AngelicHLA("h2", null, "~B", "~+A^~+-C"); + stateOne = new State("~A"); + stateTwo = new State("~B"); } @Test @@ -52,6 +60,10 @@ public void constructorTest() { public void isApplicableTest() { Assert.assertTrue(testState.isApplicable(flyActionOne)); Assert.assertFalse(testState.isApplicable(flyActionTwo)); + Assert.assertTrue(stateOne.isApplicable(h1)); + Assert.assertFalse(stateOne.isApplicable(h2)); + Assert.assertTrue(stateTwo.isApplicable(h2)); + Assert.assertFalse(stateTwo.isApplicable(h1)); } @Test @@ -69,4 +81,51 @@ public void resultTest() { newState = testState.result(flyActionTwo); Assert.assertEquals(initState, newState); } + + @Test + public void optimisticReachTest() { + // States obtained after applying h1 to stateOne + State stateOneResultOne = new State("A^~B"); + State stateOneResultTwo = new State("A"); + Assert.assertTrue(stateOne.optimisticReach(h1).containsAll(Arrays.asList(stateOneResultTwo, stateOneResultOne))); + Assert.assertEquals(2, stateOne.optimisticReach(h1).size()); + // States obtained after applying h2 to stateTwo + Assert.assertEquals(6, stateTwo.optimisticReach(h2).size()); + State[] statesResultTwo = { + stateTwo, + new State("~B^~C"), + new State("~B^A^C"), + new State("~B^A"), + new State("~B^C"), + new State("~B^A^~C") + }; + Assert.assertTrue(stateTwo.optimisticReach(h2).containsAll(Arrays.asList(statesResultTwo))); + } + + @Test + public void pessimisticReachTest() { + Assert.assertEquals(1, stateOne.pessimisticReach(h1).size()); + Assert.assertTrue(stateOne.pessimisticReach(h1). + contains(new State("A"))); + Assert.assertEquals(1, stateTwo.pessimisticReach(h2).size()); + Assert.assertTrue(stateTwo.pessimisticReach(h2). + contains(new State("~B"))); + } + + @Test + public void optimisticReachListTest() { + HashSet resultingStates = stateOne.optimisticReach(Arrays.asList(h1, h2)); + Assert.assertEquals(4, resultingStates.size()); + Assert.assertTrue(resultingStates.contains(new State("A"))); + Assert.assertTrue(resultingStates.contains(new State("A^~B"))); + Assert.assertTrue(resultingStates.contains(new State("A^~B^C"))); + Assert.assertTrue(resultingStates.contains(new State("A^~B^~C"))); + } + + @Test + public void pessimisticReachTestList() { + HashSet resultStates = stateOne.pessimisticReach(Arrays.asList(h1, h2)); + Assert.assertEquals(1, resultStates.size()); + Assert.assertTrue(resultStates.contains(new State("A"))); + } } diff --git a/aima-core/src/test/java/aima/test/core/unit/logic/planning/UtilsTest.java b/aima-core/src/test/java/aima/test/core/unit/logic/planning/UtilsTest.java index 4b19e4c718..21a01706f8 100644 --- a/aima-core/src/test/java/aima/test/core/unit/logic/planning/UtilsTest.java +++ b/aima-core/src/test/java/aima/test/core/unit/logic/planning/UtilsTest.java @@ -1,10 +1,14 @@ package aima.test.core.unit.logic.planning; import aima.core.logic.fol.kb.data.Literal; +import aima.core.logic.fol.parsing.ast.Predicate; import aima.core.logic.planning.Utils; +import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; /** * @author samagra @@ -15,4 +19,43 @@ public void parserTest() { String precondition = "At(C1,JFK) ^ At(C2,SFO)"; ArrayList literals = (ArrayList) Utils.parse(precondition); } + + @Test + public void angelicParserTest(){ + String first = "~A"; + String second = "A^~-B"; + String third = "~+A^~+-C"; + Literal a = new Literal(new Predicate("A",new ArrayList<>())); + Literal b = new Literal(new Predicate("B",new ArrayList<>())); + Literal c = new Literal(new Predicate("C",new ArrayList<>())); + + // ~A + List> parsed = Utils.angelicParse(first); + Assert.assertFalse(parsed.get(0).contains(a)); + Assert.assertTrue(parsed.get(1).contains(a)); + Assert.assertFalse(parsed.get(2).contains(a)); + Assert.assertFalse(parsed.get(3).contains(a)); + + // A^~-B + parsed = Utils.angelicParse(second); + Assert.assertTrue(parsed.get(0).contains(a)); + Assert.assertFalse(parsed.get(1).contains(a)); + Assert.assertFalse(parsed.get(2).contains(a)); + Assert.assertFalse(parsed.get(3).contains(a)); + Assert.assertFalse(parsed.get(0).contains(b)); + Assert.assertFalse(parsed.get(1).contains(b)); + Assert.assertFalse(parsed.get(2).contains(b)); + Assert.assertTrue(parsed.get(3).contains(b)); + + //~+A^~+-C + parsed = Utils.angelicParse(third); + Assert.assertFalse(parsed.get(0).contains(a)); + Assert.assertFalse(parsed.get(1).contains(a)); + Assert.assertTrue(parsed.get(2).contains(a)); + Assert.assertFalse(parsed.get(3).contains(a)); + Assert.assertFalse(parsed.get(0).contains(c)); + Assert.assertFalse(parsed.get(1).contains(c)); + Assert.assertTrue(parsed.get(2).contains(c)); + Assert.assertTrue(parsed.get(3).contains(c)); + } } diff --git a/aima-core/src/test/java/aima/test/core/unit/logic/planning/angelicsearch/AngelicSearchTest.java b/aima-core/src/test/java/aima/test/core/unit/logic/planning/angelicsearch/AngelicSearchTest.java new file mode 100644 index 0000000000..982ec29aff --- /dev/null +++ b/aima-core/src/test/java/aima/test/core/unit/logic/planning/angelicsearch/AngelicSearchTest.java @@ -0,0 +1,25 @@ +package aima.test.core.unit.logic.planning.angelicsearch; + +import aima.core.logic.planning.ActionSchema; +import aima.core.logic.planning.PlanningProblemFactory; +import aima.core.logic.planning.angelicsearch.AngelicHLA; +import aima.core.logic.planning.angelicsearch.AngelicSearchAlgorithm; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class AngelicSearchTest { + @Test + public void angelicSearchTest(){ + AngelicHLA h1 = new AngelicHLA("h1", null, "~A", "A^~-B"); + AngelicHLA h2 = new AngelicHLA("h2", null, "~B", "~+A^~+-C"); + ActionSchema + AngelicSearchAlgorithm algo = new AngelicSearchAlgorithm(); + System.out.println("Answer"); + List list = algo.angelicSearch(PlanningProblemFactory.getAngelicABProblem(), + PlanningProblemFactory.getAngelicInitialPlan(new ArrayList<>(Arrays.asList(h1,h2)),PlanningProblemFactory.getAngelicABProblem(),"A^C")); + System.out.println(list.size()); + } +}