From ecd7c004545e0e9717bcfe88a113c41ac77a250f Mon Sep 17 00:00:00 2001 From: Naveen Sundar Govindarajulu Date: Sat, 14 Jan 2017 22:07:41 -0500 Subject: [PATCH] First commit --- src/main/java/edu/rpi/rair/Action.java | 134 ++++++++++++++ .../java/edu/rpi/rair/DepthFirstPlanner.java | 70 ++++++++ src/main/java/edu/rpi/rair/Goal.java | 55 ++++++ src/main/java/edu/rpi/rair/GoalTracker.java | 107 +++++++++++ src/main/java/edu/rpi/rair/Operations.java | 80 +++++++++ src/main/java/edu/rpi/rair/Plan.java | 87 +++++++++ src/main/java/edu/rpi/rair/Planner.java | 16 ++ src/main/java/edu/rpi/rair/State.java | 83 +++++++++ .../edu/rpi/rair/utils/PlanningProblem.java | 169 ++++++++++++++++++ .../edu/rpi/rair/completeness_problems.clj | 122 +++++++++++++ .../edu/rpi/rair/goal_tracking_tests.clj | 27 +++ .../edu/rpi/rair/DepthFirstPlannerTest.java | 70 ++++++++ 12 files changed, 1020 insertions(+) create mode 100644 src/main/java/edu/rpi/rair/Action.java create mode 100644 src/main/java/edu/rpi/rair/DepthFirstPlanner.java create mode 100644 src/main/java/edu/rpi/rair/Goal.java create mode 100644 src/main/java/edu/rpi/rair/GoalTracker.java create mode 100644 src/main/java/edu/rpi/rair/Operations.java create mode 100644 src/main/java/edu/rpi/rair/Plan.java create mode 100644 src/main/java/edu/rpi/rair/Planner.java create mode 100644 src/main/java/edu/rpi/rair/State.java create mode 100644 src/main/java/edu/rpi/rair/utils/PlanningProblem.java create mode 100644 src/main/resources/edu/rpi/rair/completeness_problems.clj create mode 100644 src/main/resources/edu/rpi/rair/goal_tracking_tests.clj create mode 100644 src/test/java/edu/rpi/rair/DepthFirstPlannerTest.java diff --git a/src/main/java/edu/rpi/rair/Action.java b/src/main/java/edu/rpi/rair/Action.java new file mode 100644 index 0000000..3b51a37 --- /dev/null +++ b/src/main/java/edu/rpi/rair/Action.java @@ -0,0 +1,134 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.representations.formula.And; +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.representations.value.Value; +import com.naveensundarg.shadow.prover.representations.value.Variable; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; +import com.naveensundarg.shadow.prover.utils.Sets; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class Action { + + private final Set preconditions; + private final Set additions; + private final Set deletions; + private final List freeVariables; + + private final String name; + private final Formula precondition; + + private int weight; + + private Action(String name, Set preconditions, Set additions, Set deletions, List freeVariables) { + this.name = name; + this.preconditions = preconditions; + + this.additions = additions; + this.deletions = deletions; + List computedFreeVariables = preconditions. + stream(). + map(x -> Sets.difference(x.variablesPresent(), x.boundVariablesPresent())). + reduce(Sets.newSet(), Sets::union). + stream().sorted().collect(Collectors.toList()); + + this.freeVariables = freeVariables; + + this.precondition = new And(preconditions.stream().collect(Collectors.toList())); + + this.weight = preconditions.stream().mapToInt(Formula::getWeight).sum() + + additions.stream().mapToInt(Formula::getWeight).sum() + + deletions.stream().mapToInt(Formula::getWeight).sum(); + } + + + public static Action buildActionFrom(String name, + Set preconditions, + Set additions, + Set deletions, + List freeVariables) { + + return new Action(name, preconditions, additions, deletions, freeVariables); + + } + + public int getWeight() { + return weight; + } + + public Formula getPrecondition() { + return precondition; + } + + public List openVars() { + + return freeVariables; + + } + + public Set instantiateAdditions(Map mapping) { + + return additions.stream().map(x -> x.apply(mapping)).collect(Collectors.toSet()); + } + + public Set instantiateDeletions(Map mapping) { + + return deletions.stream().map(x -> x.apply(mapping)).collect(Collectors.toSet()); + } + + + public Action instantiate(Map binding){ + + Set newPreconditions = preconditions.stream().map(x->x.apply(binding)).collect(Collectors.toSet()); + Set newAdditions = additions.stream().map(x->x.apply(binding)).collect(Collectors.toSet()); + Set newDeletions = deletions.stream().map(x->x.apply(binding)).collect(Collectors.toSet()); + + List newFreeVraibles = CollectionUtils.newEmptyList(); + for(Variable var: freeVariables){ + + if(!binding.keySet().contains(var)){ + newFreeVraibles.add(var); + } + } + return new Action(name, newPreconditions, newAdditions, newDeletions, newFreeVraibles); + } + @Override + public String toString() { + return "Action{" + + "preconditions=" + preconditions + + ", additions=" + additions + + ", deletions=" + deletions + + ", name='" + name + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Action action = (Action) o; + + if (!preconditions.equals(action.preconditions)) return false; + if (!additions.equals(action.additions)) return false; + if (!deletions.equals(action.deletions)) return false; + return name.equals(action.name); + } + + @Override + public int hashCode() { + int result = preconditions.hashCode(); + result = 31 * result + additions.hashCode(); + result = 31 * result + deletions.hashCode(); + result = 31 * result + name.hashCode(); + return result; + } + +} diff --git a/src/main/java/edu/rpi/rair/DepthFirstPlanner.java b/src/main/java/edu/rpi/rair/DepthFirstPlanner.java new file mode 100644 index 0000000..97c4639 --- /dev/null +++ b/src/main/java/edu/rpi/rair/DepthFirstPlanner.java @@ -0,0 +1,70 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; +import com.naveensundarg.shadow.prover.utils.Pair; +import com.naveensundarg.shadow.prover.utils.Sets; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class DepthFirstPlanner implements Planner { + + + @Override + public Optional> plan(Set background, Set actions, State start, State goal) { + + + if (Operations.satisfies(background, start, goal)) { + //Already satisfied. Do nothing. Return a set with an empty plan. + return Optional.of(Sets.with(Plan.newEmptyPlan(goal, background))); + } + + + Set allPlans = Sets.newSet(); + boolean atleastOnePlanFound = false; + + for (Action action : actions) { + + Optional> nextStateActionPair = Operations.apply(background, action, start); + + if (nextStateActionPair.isPresent()) { + + Optional> planOpt = plan(background, actions, nextStateActionPair.get().first(), goal); + + if (planOpt.isPresent()) { + + atleastOnePlanFound = true; + Set nextPlans = planOpt.get(); + + State nextSate = nextStateActionPair.get().first(); + Action instantiatedAction = nextStateActionPair.get().second(); + + Set augmentedPlans = nextPlans.stream(). + map(plan -> plan.getPlanByStartingWith(instantiatedAction, nextSate)). + collect(Collectors.toSet()); + + allPlans.addAll(augmentedPlans); + //TODO: store different plans and return the best plan. + } + } + + } + + if (atleastOnePlanFound) { + + return Optional.of(allPlans); + + } else { + + //No plan found. + return Optional.empty(); + + } + + + } +} diff --git a/src/main/java/edu/rpi/rair/Goal.java b/src/main/java/edu/rpi/rair/Goal.java new file mode 100644 index 0000000..f8cdd50 --- /dev/null +++ b/src/main/java/edu/rpi/rair/Goal.java @@ -0,0 +1,55 @@ +package edu.rpi.rair; + +/** + * Created by naveensundarg on 1/14/17. + */ +public class Goal { + + private final State goalState; + private final int priority; + + private Goal(State goalState, int priority) { + this.goalState = goalState; + this.priority = priority; + } + + public static Goal makeGoal(State goalState, int priority){ + + return new Goal(goalState, priority); + + } + + public State getGoalState() { + return goalState; + } + + public int getPriority() { + return priority; + } + + @Override + public String toString() { + return "Goal{" + + "goalState=" + goalState + + ", priority=" + priority + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Goal goal = (Goal) o; + + if (priority != goal.priority) return false; + return goalState.equals(goal.goalState); + } + + @Override + public int hashCode() { + int result = goalState.hashCode(); + result = 31 * result + priority; + return result; + } +} diff --git a/src/main/java/edu/rpi/rair/GoalTracker.java b/src/main/java/edu/rpi/rair/GoalTracker.java new file mode 100644 index 0000000..8bd84a5 --- /dev/null +++ b/src/main/java/edu/rpi/rair/GoalTracker.java @@ -0,0 +1,107 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; +import com.naveensundarg.shadow.prover.utils.Pair; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Created by naveensundarg on 1/14/17. + */ +public class GoalTracker { + + + private final Set background; + private State currentState; + private final Set currentGoals; + private final Planner planner; + private final Set actions; + + public GoalTracker(Set background, State startState, Set actions) { + this.background = background; + this.currentState = startState; + this.currentGoals = CollectionUtils.newEmptySet(); + this.planner = new DepthFirstPlanner(); + this.actions = actions; + } + + + public boolean adoptGoal(Goal goal) { + + + Optional> possiblePlans = planner.plan(background, actions, currentState, goal.getGoalState()); + + if (!possiblePlans.isPresent()) { + + return false; + + } else if (possiblePlans.get().isEmpty()) { + + throw new AssertionError("Unexpected condition: possible plans is empty"); + + } else { + + Set plans = possiblePlans.get(); + + + if (plans.stream().anyMatch(plan -> plan.noConflicts(currentGoals))) { + + /* + * If there is any plan without any goal conflicts, then adopt the goal. + */ + currentGoals.add(goal); + return true; + + } else { + + /* + * Find goals to drop. + * For each plan, find the sum of the priorities of the goals that conflict. + * If any plan exists, where sum of priorities of existing goals is less than the new goal, + * add the new goal and remove the conflict goals. + * Otherwise return false and don't adopt the new goal. + */ + + boolean feasiblePlanExists = false; + int bestPriorityGap = 0; + Set bestRemovalCandidates = null; + for (Plan plan : plans) { + + Set conflictingGoals = plan.getConflictingGoals(currentGoals); + int conflictSum = conflictingGoals.stream().mapToInt(Goal::getPriority).sum(); + int gap = goal.getPriority() - conflictSum; + + if(gap > 0 && gap > bestPriorityGap ){ + + feasiblePlanExists = true; + bestPriorityGap = gap; + bestRemovalCandidates= conflictingGoals; + } + } + + if(feasiblePlanExists){ + + currentGoals.removeAll(bestRemovalCandidates); + currentGoals.add(goal); + + return true; + } + else { + + return false; + } + + + } + + + } + + + } + + +} diff --git a/src/main/java/edu/rpi/rair/Operations.java b/src/main/java/edu/rpi/rair/Operations.java new file mode 100644 index 0000000..326d4a7 --- /dev/null +++ b/src/main/java/edu/rpi/rair/Operations.java @@ -0,0 +1,80 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.core.Prover; +import com.naveensundarg.shadow.prover.core.SnarkWrapper; +import com.naveensundarg.shadow.prover.representations.formula.And; +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.representations.value.Value; +import com.naveensundarg.shadow.prover.representations.value.Variable; +import com.naveensundarg.shadow.prover.utils.ImmutablePair; +import com.naveensundarg.shadow.prover.utils.Pair; +import com.naveensundarg.shadow.prover.utils.Sets; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static edu.rpi.rair.State.FALSE; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class Operations { + + private static Prover prover; + + static{ + prover = new SnarkWrapper(); + } + + public static synchronized Optional> proveAndGetBindings(Set givens, Formula goal, List variables){ + + return prover.proveAndGetBindings(givens, goal, variables); + } + + public static Optional> apply(Set background, Action action, State state){ + + Prover prover = new SnarkWrapper(); + + + Set givens = Sets.union(background, state.getFormulae()); + + Optional> bingdingsOpt = proveAndGetBindings(givens, action.getPrecondition(), action.openVars()); + + State newState; + + if(!bingdingsOpt.isPresent()){ + + + return Optional.empty(); + + } + Set newFormulae = state.getFormulae(); + + newFormulae = Sets.union(newFormulae, action.instantiateAdditions(bingdingsOpt.get())); + + newFormulae = Sets.difference(newFormulae, action.instantiateDeletions(bingdingsOpt.get())); + + newState = State.initializeWith(newFormulae); + + return Optional.of(ImmutablePair.from(newState, action.instantiate(bingdingsOpt.get()))); + + } + + + public static boolean satisfies(Set background, State state, State goal){ + + return goal.getFormulae().stream(). + allMatch(x->prover.prove(Sets.union(background, state.getFormulae()), x).isPresent()); + + } + + public static boolean conflicts(Set background, State state1, State state2){ + + return prover.prove(Sets.union(background, Sets.union(state1.getFormulae(), state2.getFormulae())), FALSE ).isPresent(); + + } + +} diff --git a/src/main/java/edu/rpi/rair/Plan.java b/src/main/java/edu/rpi/rair/Plan.java new file mode 100644 index 0000000..ab01ff6 --- /dev/null +++ b/src/main/java/edu/rpi/rair/Plan.java @@ -0,0 +1,87 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by naveensundarg on 1/14/17. + */ +public class Plan { + + private final List actions; + private final List expectedStates; + private final Set background; + public static Plan newEmptyPlan(State currentState, Set background){ + List newActions = CollectionUtils.newEmptyList(); + List newExpectedStates = CollectionUtils.listOf(currentState); + return new Plan(newActions, newExpectedStates, background); + } + + public Plan(List actions, List expectedStates, Set background) { + this.actions = actions; + this.expectedStates = expectedStates; + this.background = background; + } + + public List getActions() { + return actions; + } + + public Plan getPlanByStartingWith(Action action, State state){ + List newActions = CollectionUtils.newEmptyList(); + newActions.addAll(actions); + newActions.add(0, action); + + List newExpectedStates = CollectionUtils.newEmptyList(); + newExpectedStates.addAll(expectedStates); + newExpectedStates.add(0, state); + + return new Plan(newActions, newExpectedStates, background); + } + + public boolean conflictsWith(Goal goal){ + + return expectedStates.stream().anyMatch(state-> Operations.conflicts(background, state,goal.getGoalState())); + + } + + + + public Set getConflictingGoals(Set goals){ + + return goals.stream().filter(this::conflictsWith).collect(Collectors.toSet()); + + } + + public boolean noConflicts(Set goals){ + + return getConflictingGoals(goals).isEmpty(); + + } + + @Override + public String toString() { + return "Plan{" + + "actions=" + actions + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Plan plan = (Plan) o; + + return actions != null ? actions.equals(plan.actions) : plan.actions == null; + } + + @Override + public int hashCode() { + return actions != null ? actions.hashCode() : 0; + } +} diff --git a/src/main/java/edu/rpi/rair/Planner.java b/src/main/java/edu/rpi/rair/Planner.java new file mode 100644 index 0000000..423555a --- /dev/null +++ b/src/main/java/edu/rpi/rair/Planner.java @@ -0,0 +1,16 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.representations.formula.Formula; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Created by naveensundarg on 1/13/17. + */ +public interface Planner { + + Optional> plan(Set background, Set actions, State start, State goal); + +} diff --git a/src/main/java/edu/rpi/rair/State.java b/src/main/java/edu/rpi/rair/State.java new file mode 100644 index 0000000..06e1ac4 --- /dev/null +++ b/src/main/java/edu/rpi/rair/State.java @@ -0,0 +1,83 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.core.Prover; +import com.naveensundarg.shadow.prover.core.SnarkWrapper; +import com.naveensundarg.shadow.prover.representations.formula.And; +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; +import com.naveensundarg.shadow.prover.utils.Reader; +import com.naveensundarg.shadow.prover.utils.Sets; + +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class State { + + final Set formulae; + private static final Prover prover = new SnarkWrapper(); + static Formula FALSE; + + static{ + + try { + FALSE = Reader.readFormulaFromString("(and P (not P))"); + } catch (Reader.ParsingException e) { + e.printStackTrace(); + FALSE = null; + } + + } + + private State(Set formulae){ + + this.formulae = formulae; + } + + public static State initializeWith(Set formulae){ + + State newState = new State(formulae); + return newState; + } + + + public void add(Set formulae){ + + this.formulae.addAll(formulae); + } + + public void remove(Set formulae){ + + this.formulae.removeAll(formulae); + + } + + public Set getFormulae() { + return CollectionUtils.setFrom(formulae); + } + + + @Override + public String toString() { + return "State{" + + "formulae=" + formulae + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + State state = (State) o; + + return formulae.equals(state.formulae); + } + + @Override + public int hashCode() { + return formulae.hashCode(); + } +} diff --git a/src/main/java/edu/rpi/rair/utils/PlanningProblem.java b/src/main/java/edu/rpi/rair/utils/PlanningProblem.java new file mode 100644 index 0000000..e78146a --- /dev/null +++ b/src/main/java/edu/rpi/rair/utils/PlanningProblem.java @@ -0,0 +1,169 @@ +package edu.rpi.rair.utils; + +import clojure.lang.Obj; +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.representations.value.Variable; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; +import com.naveensundarg.shadow.prover.utils.Reader; +import edu.rpi.rair.Action; +import edu.rpi.rair.State; +import us.bpsm.edn.Keyword; +import us.bpsm.edn.Symbol; +import us.bpsm.edn.parser.Parseable; +import us.bpsm.edn.parser.Parser; +import us.bpsm.edn.parser.Parsers; +import us.bpsm.edn.parser.Token; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class PlanningProblem { + + public Set background; + public Set actions; + public State start; + public State goal; + public String name; + + private static final Keyword BACKGROUND = Keyword.newKeyword("background"); + private static final Keyword START = Keyword.newKeyword("start"); + private static final Keyword GOAL = Keyword.newKeyword("goal"); + private static final Keyword NAME = Keyword.newKeyword("name"); + private static final Keyword ACTION = Keyword.newKeyword("actions"); + + private static final Keyword PRECONDITIONS = Keyword.newKeyword("preconditions"); + private static final Keyword ADDITIONS = Keyword.newKeyword("additions"); + private static final Keyword DELETIONS = Keyword.newKeyword("deletions"); + + private static final Symbol ACTION_DEFINER = Symbol.newSymbol("define-action"); + + + public PlanningProblem(String name, Set background, State start, State goal, Set actions) { + + this.background = background; + this.start = start; + this.actions = actions; + this.goal = goal; + this.name = name; + } + + public static List readFromFile(InputStream inputStream) throws Reader.ParsingException { + + Parseable parseable = Parsers.newParseable(new InputStreamReader(inputStream)); + Parser parser = Parsers.newParser(Parsers.defaultConfiguration()); + + List planningProblems = CollectionUtils.newEmptyList(); + + Object nextValue = parser.nextValue(parseable); + + while (!nextValue.equals(Token.END_OF_INPUT)) { + + Map planningProblemSpec = (Map) nextValue; + + Set background = readFrom((List) planningProblemSpec.get(BACKGROUND)); + Set start = readFrom((List) planningProblemSpec.get(START)); + Set goal = readFrom((List) planningProblemSpec.get(GOAL)); + + List actionDefinitions = (List) planningProblemSpec.get(ACTION); + + String name = planningProblemSpec.get(NAME).toString(); + Set actions = readActionsFrom(actionDefinitions); + + planningProblems.add(new PlanningProblem(name, background, State.initializeWith(start), + State.initializeWith(goal), actions)); + + nextValue = parser.nextValue(parseable); + } + + return planningProblems; + + } + + private static Set readActionsFrom(List actionSpecs) throws Reader.ParsingException { + + Set actions = actionSpecs.stream().map(spec -> { + List specBody = (List) spec; + if(!specBody.get(0).equals(ACTION_DEFINER)){ + + return null; + } + String name = specBody.get(1).toString(); + List vars = ((List)specBody.get(2)).stream().map(x -> { + try { + return Reader.readLogicValue(x); + } catch (Reader.ParsingException e) { + e.printStackTrace(); + return null; + } + }).map(x->(Variable)x).collect(Collectors.toList()); + + if(vars.stream().anyMatch(Objects::isNull)){ + return null; + } + Map actionSpec = (Map) specBody.get(3); + try { + + + Set preconditions = readFrom((List) actionSpec.get(PRECONDITIONS)); + Set additions = readFrom((List) actionSpec.get(ADDITIONS)); + Set deletions = readFrom((List) actionSpec.get(DELETIONS)); + + return Action.buildActionFrom(name, preconditions, additions, deletions, vars); + + + } catch (Reader.ParsingException e) { + e.printStackTrace(); + return null; + } + }).collect(Collectors.toSet()); + + if (actions.stream().anyMatch(Objects::isNull)) { + + throw new Reader.ParsingException("Couldn't read actions: " + actionSpecs); + } + + return actions; + + } + + private static Set readFrom(List objects) throws Reader.ParsingException { + + Set formulae = objects.stream().map(x -> { + try { + return Reader.readFormula(x); + } catch (Reader.ParsingException e) { + e.printStackTrace(); + return null; + } + }).collect(Collectors.toSet()); + + + if (formulae.stream().anyMatch(Objects::isNull)) { + + throw new Reader.ParsingException("Couldn't read formulae: " + objects); + } + + return formulae; + + + } + + @Override + public String toString() { + return "PlanningProblem{" + + "name='" + name + '\'' + + ", background=" + background + + ", actions=" + actions + + ", start=" + start + + ", goal=" + goal + + '}'; + } +} diff --git a/src/main/resources/edu/rpi/rair/completeness_problems.clj b/src/main/resources/edu/rpi/rair/completeness_problems.clj new file mode 100644 index 0000000..f02abad --- /dev/null +++ b/src/main/resources/edu/rpi/rair/completeness_problems.clj @@ -0,0 +1,122 @@ +{:name "test 1" + :background [P] + :start [Q] + :goal [R] + :actions + [(define-action a1 () + {:preconditions [(or Q R)] + :additions [R] + :deletions [Q]})] + + :expected-plan [a1] + } + + + +{:name "simple killing" + :background [] + :start [(forall ?x (Alive ?x))] + :goal [(forall ?x (Dead ?x))] + :actions + [(define-action kill () + {:preconditions [(Alive ?x)] + :additions [(Dead ?x)] + :deletions [(Alive ?x)]})] + + :expected-plans ([kill]) + + } + + +{:name "thirsty" + :background [] + :start [thirsty] + :goal [(not thirsty)] + :actions + [(define-action drink () + {:preconditions [thirsty] + :additions [(not thirsty)] + :deletions [thirsty]}) + (define-action eat () + {:preconditions [hungry] + :additions [(not hungry)] + :deletions [hungry]})] + + :expected-plans ([drink]) + + } + + +{:name "hungry" + :background [] + :start [hungry] + :goal [(not hungry)] + :actions + + [(define-action drink () + {:preconditions [thirsty] + :additions [(not thirsty)] + :deletions [thirsty]}) + + (define-action eat () + {:preconditions [hungry] + :additions [(not hungry)] + :deletions [hungry]})] + + :expected-plans ([eat]) + } + + +{:name "hungry and thirsty" + :background [] + :start [hungry thirsty] + :goal [(not (or hungry thirsty))] + :actions + [(define-action drink () + {:preconditions [thirsty] + :additions [(not thirsty)] + :deletions [thirsty]}) + + (define-action eat () + {:preconditions [hungry] + :additions [(not hungry)] + :deletions [hungry]})] + + :expected-plans ([eat drink] + [drink eat]) + } + +{:name "hungry and thirsty" + :background [] + :start [hungry thirsty work-unfinished] + :goal [work-finished] + :actions + + [(define-action drink () + {:preconditions [thirsty] + :additions [(not thirsty)] + :deletions [thirsty]}) + + (define-action eat () + {:preconditions [hungry] + :additions [(not hungry)] + :deletions [hungry]}) + + (define-action work () + {:preconditions [(and (not hungry) (not thirsty))] + :additions [work-finished] + :deletions [work-unfinished]})] + + :expected-plans ([eat drink work] + [drink eat work])} + + +{:name "bidding problem" + :background [] + :start [(bid 0)] + :goal [(bid 5)] + :actions + [(define-action post-new-bid (?number) + {:preconditions [(bid ?number)] + :additions [(bid ($$sum 1 ?number))] + :deletions [(bid ?number)]})]} diff --git a/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj b/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj new file mode 100644 index 0000000..572888f --- /dev/null +++ b/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj @@ -0,0 +1,27 @@ +{ + :name "test 1" + :background [ (forall (?x ?y ?room1 ?room2) + (if (and (Interrogates ?x ?y) + (In ?x ?room1) + (In ?y ?room2)) + (= ?room1 ?room2))) + + (In commander room2) + () + ] + :start [Be_In_Room + (Closed (door room1)) + (Accompany self prisoner)] + + :goalSequence [ + [G1 1 [(In prisoner1 room1)]] + [G2 1 [(Closed (door room1))]] + [G3 1 [(Accompany self prisoner)]] + + [G4 2 [(Interrogates command robot)]] + [G5 2 []] + + ] + + + } \ No newline at end of file diff --git a/src/test/java/edu/rpi/rair/DepthFirstPlannerTest.java b/src/test/java/edu/rpi/rair/DepthFirstPlannerTest.java new file mode 100644 index 0000000..43738be --- /dev/null +++ b/src/test/java/edu/rpi/rair/DepthFirstPlannerTest.java @@ -0,0 +1,70 @@ +package edu.rpi.rair; + +import com.naveensundarg.shadow.prover.utils.Reader; +import edu.rpi.rair.utils.PlanningProblem; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.testng.Assert.*; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class DepthFirstPlannerTest { + + DepthFirstPlanner depthFirstPlanner; + + @BeforeMethod + public void setUp() throws Exception { + + depthFirstPlanner = new DepthFirstPlanner(); + } + + public static void main(String[] args) throws Reader.ParsingException { + + List planningProblemList = (PlanningProblem.readFromFile(Planner.class.getResourceAsStream("completeness_problems.clj"))); + + Planner depthFirstPlanner = new DepthFirstPlanner(); + + PlanningProblem planningProblem = planningProblemList.get(2); + System.out.println(depthFirstPlanner.plan(planningProblem.background, planningProblem.actions, planningProblem.start, planningProblem.goal)); + } + + @DataProvider + public static Object[][] testCompletenessDataProvider() throws Reader.ParsingException { + + List planningProblemList = (PlanningProblem.readFromFile(Planner.class.getResourceAsStream("completeness_problems.clj"))); + + Object[][] cases = new Object[planningProblemList.size()][1]; + + for (int i = 0; i < planningProblemList.size(); i++) { + + cases[i][0] = planningProblemList.get(i); + + } + + return cases; + + + } + + + @Test(dataProvider = "testCompletenessDataProvider") + public void testCompletness(PlanningProblem planningProblem) throws Exception { + + Optional> possiblePlans = depthFirstPlanner.plan( + planningProblem.background, + planningProblem.actions, + planningProblem.start, + planningProblem.goal); + + Assert.assertTrue(possiblePlans.isPresent()); + + } +} \ No newline at end of file