From f3ddd342c6bb0049711f48c40e7690aac6e90d66 Mon Sep 17 00:00:00 2001 From: Naveen Sundar Govindarajulu Date: Sun, 15 Jan 2017 18:54:56 -0500 Subject: [PATCH] More tweaks --- .../Maven__com_diogonunes_JCDP_2_0_1.xml | 13 ++ ...Maven__org_fusesource_jansi_jansi_1_11.xml | 13 ++ .idea/vcs.xml | 6 + pom.xml | 5 + snark-20120808r02/snark-interface.lisp | 36 ++++- .../java/edu/rpi/rair/DepthFirstPlanner.java | 52 +++++-- src/main/java/edu/rpi/rair/Goal.java | 25 ++++ src/main/java/edu/rpi/rair/GoalTracker.java | 4 + src/main/java/edu/rpi/rair/Operations.java | 107 ++++++++++++-- .../rpi/rair/utils/GoalTrackingProblem.java | 96 +++++++++++++ .../edu/rpi/rair/utils/PlanningProblem.java | 99 ++++++------- src/main/java/edu/rpi/rair/utils/RunDemo.java | 55 ++++++++ .../edu/rpi/rair/completeness_problems.clj | 132 ++++++++++-------- src/main/resources/edu/rpi/rair/debug.clj | 14 ++ .../edu/rpi/rair/goal_tracking_tests.clj | 77 +++++++--- .../edu/rpi/rair/DepthFirstPlannerTest.java | 4 +- .../java/edu/rpi/rair/GoalTrackerTest.java | 56 ++++++++ target/classes/edu/rpi/rair/debug.clj | 14 ++ .../edu/rpi/rair/goal_tracking_tests.clj | 77 +++++++--- .../rpi/rair/utils/GoalTrackingProblem.class | Bin 0 -> 5158 bytes .../classes/edu/rpi/rair/utils/RunDemo.class | Bin 0 -> 2789 bytes .../edu/rpi/rair/GoalTrackerTest.class | Bin 0 -> 2801 bytes 22 files changed, 710 insertions(+), 175 deletions(-) create mode 100644 .idea/libraries/Maven__com_diogonunes_JCDP_2_0_1.xml create mode 100644 .idea/libraries/Maven__org_fusesource_jansi_jansi_1_11.xml create mode 100644 .idea/vcs.xml create mode 100644 src/main/java/edu/rpi/rair/utils/GoalTrackingProblem.java create mode 100644 src/main/java/edu/rpi/rair/utils/RunDemo.java create mode 100644 src/test/java/edu/rpi/rair/GoalTrackerTest.java create mode 100644 target/classes/edu/rpi/rair/utils/GoalTrackingProblem.class create mode 100644 target/classes/edu/rpi/rair/utils/RunDemo.class create mode 100644 target/test-classes/edu/rpi/rair/GoalTrackerTest.class diff --git a/.idea/libraries/Maven__com_diogonunes_JCDP_2_0_1.xml b/.idea/libraries/Maven__com_diogonunes_JCDP_2_0_1.xml new file mode 100644 index 0000000..574defc --- /dev/null +++ b/.idea/libraries/Maven__com_diogonunes_JCDP_2_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_fusesource_jansi_jansi_1_11.xml b/.idea/libraries/Maven__org_fusesource_jansi_jansi_1_11.xml new file mode 100644 index 0000000..2ab51a7 --- /dev/null +++ b/.idea/libraries/Maven__org_fusesource_jansi_jansi_1_11.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index d7191e8..ebdc119 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,11 @@ test + + com.diogonunes + JCDP + 2.0.1 + us.bpsm edn-java diff --git a/snark-20120808r02/snark-interface.lisp b/snark-20120808r02/snark-interface.lisp index 8771762..6149fb0 100644 --- a/snark-20120808r02/snark-interface.lisp +++ b/snark-20120808r02/snark-interface.lisp @@ -40,6 +40,7 @@ (snark:prove-supported t) (snark:use-hyperresolution t) (snark:use-paramodulation t) + (snark:allow-skolem-symbols-in-answers nil)) (defun row-formula (name)) @@ -135,6 +136,9 @@ ""))))) +(defun get-answer-string (proof) + (string-downcase (princ-to-string (@! (rest (snark:answer proof)))))) + (defun prove-from-axioms-and-get-answers (all-axioms f vars &key (time-limit 5) @@ -157,9 +161,39 @@ (let ((proof (snark:prove (!@ f) :answer (!@ (cons 'ans vars)) ))) (if (equalp :PROOF-FOUND proof) - (string-downcase (princ-to-string (@! (rest (snark:answer proof) )))) + (get-answer-string proof) ""))))) +(defun prove-from-axioms-and-get-multiple-answers (all-axioms f vars + &key + (time-limit 5) + (verbose nil) + sortal-setup-fn) + (let ((axioms (remove-duplicates all-axioms :test #'equalp))) + (setup-snark :time-limit time-limit :verbose verbose) + (if sortal-setup-fn (funcall sortal-setup-fn)) + (let* ((n-a (make-hash-table :test #'equalp)) + (a-n (make-hash-table :test #'equalp))) + (mapcar (lambda (axiom) + (let ((name (gensym))) + (setf (gethash (princ-to-string axiom) a-n) name) + (setf (gethash (princ-to-string name) n-a) axiom))) axioms) + (mapcar (lambda (axiom) + (snark::assert axiom :name (gethash (princ-to-string axiom) a-n) + )) + (mapcar #'!@ axioms)) + + (let ((proof (snark:prove (!@ f) :answer (!@ (cons 'ans vars)) ))) + + (if (equalp :PROOF-FOUND proof) + (princ-to-string (cons (get-answer-string proof) (call))) + ""))))) + +(defun call () + (let ((proof (snark:closure))) + (if (equalp :PROOF-FOUND proof) + (cons (get-answer-string proof) (call)) + ()))) (defun proved? (ans) (first ans)) (defun used-premises (ans) (second ans)) diff --git a/src/main/java/edu/rpi/rair/DepthFirstPlanner.java b/src/main/java/edu/rpi/rair/DepthFirstPlanner.java index 97c4639..fa32817 100644 --- a/src/main/java/edu/rpi/rair/DepthFirstPlanner.java +++ b/src/main/java/edu/rpi/rair/DepthFirstPlanner.java @@ -14,10 +14,26 @@ import java.util.stream.Collectors; public class DepthFirstPlanner implements Planner { + private static final int MAX_DEPTH = 4; + + @Override public Optional> plan(Set background, Set actions, State start, State goal) { + return planInternal(Sets.newSet(), 0, background, actions, start, goal); + + + } + + + + private Optional> planInternal(Set> history, int currentDepth, Set background, Set actions, State start, State goal) { + + if(currentDepth>=MAX_DEPTH){ + return Optional.empty(); + } + 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))); @@ -29,29 +45,38 @@ public class DepthFirstPlanner implements Planner { for (Action action : actions) { - Optional> nextStateActionPair = Operations.apply(background, action, start); + Optional>> nextStateActionPairs = Operations.apply(background, action, start); - if (nextStateActionPair.isPresent()) { + if (nextStateActionPairs.isPresent()) { - Optional> planOpt = plan(background, actions, nextStateActionPair.get().first(), goal); + for (Pair stateActionPair : nextStateActionPairs.get()) { - if (planOpt.isPresent()) { - atleastOnePlanFound = true; - Set nextPlans = planOpt.get(); - State nextSate = nextStateActionPair.get().first(); - Action instantiatedAction = nextStateActionPair.get().second(); + Optional> planOpt = planInternal(history, currentDepth+1, background, actions, stateActionPair.first(), goal); - Set augmentedPlans = nextPlans.stream(). - map(plan -> plan.getPlanByStartingWith(instantiatedAction, nextSate)). - collect(Collectors.toSet()); + if (planOpt.isPresent()) { - allPlans.addAll(augmentedPlans); - //TODO: store different plans and return the best plan. + atleastOnePlanFound = true; + Set nextPlans = planOpt.get(); + + State nextSate = stateActionPair.first(); + Action instantiatedAction = stateActionPair.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) { @@ -67,4 +92,5 @@ public class DepthFirstPlanner implements Planner { } + } diff --git a/src/main/java/edu/rpi/rair/Goal.java b/src/main/java/edu/rpi/rair/Goal.java index f8cdd50..bc4c36e 100644 --- a/src/main/java/edu/rpi/rair/Goal.java +++ b/src/main/java/edu/rpi/rair/Goal.java @@ -1,5 +1,7 @@ package edu.rpi.rair; +import java.util.concurrent.atomic.AtomicInteger; + /** * Created by naveensundarg on 1/14/17. */ @@ -7,18 +9,36 @@ public class Goal { private final State goalState; private final int priority; + private final String name; + private static final AtomicInteger nameCounter; + static { + nameCounter = new AtomicInteger(0); + } private Goal(State goalState, int priority) { this.goalState = goalState; this.priority = priority; + this.name = "G" + nameCounter.incrementAndGet(); } + private Goal(State goalState, int priority, String name) { + this.goalState = goalState; + this.priority = priority; + this.name = name; + } public static Goal makeGoal(State goalState, int priority){ return new Goal(goalState, priority); } + public static Goal makeGoal(State goalState, int priority, String name){ + + return new Goal(goalState, priority, name); + + } + + public State getGoalState() { return goalState; } @@ -27,11 +47,16 @@ public class Goal { return priority; } + public String getName() { + return name; + } + @Override public String toString() { return "Goal{" + "goalState=" + goalState + ", priority=" + priority + + ", name='" + name + '\'' + '}'; } diff --git a/src/main/java/edu/rpi/rair/GoalTracker.java b/src/main/java/edu/rpi/rair/GoalTracker.java index 8bd84a5..e979c8f 100644 --- a/src/main/java/edu/rpi/rair/GoalTracker.java +++ b/src/main/java/edu/rpi/rair/GoalTracker.java @@ -14,6 +14,9 @@ import java.util.Set; public class GoalTracker { + + + private final Set background; private State currentState; private final Set currentGoals; @@ -32,6 +35,7 @@ public class GoalTracker { public boolean adoptGoal(Goal goal) { + Optional> possiblePlans = planner.plan(background, actions, currentState, goal.getGoalState()); if (!possiblePlans.isPresent()) { diff --git a/src/main/java/edu/rpi/rair/Operations.java b/src/main/java/edu/rpi/rair/Operations.java index 326d4a7..81575cf 100644 --- a/src/main/java/edu/rpi/rair/Operations.java +++ b/src/main/java/edu/rpi/rair/Operations.java @@ -3,9 +3,11 @@ 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.BiConditional; 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.ImmutablePair; import com.naveensundarg.shadow.prover.utils.Pair; import com.naveensundarg.shadow.prover.utils.Sets; @@ -14,6 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.*; import java.util.stream.Collectors; import static edu.rpi.rair.State.FALSE; @@ -23,6 +26,7 @@ import static edu.rpi.rair.State.FALSE; */ public class Operations { + private static boolean DEEP_EQUIVALENCE = false; private static Prover prover; static{ @@ -31,38 +35,125 @@ public class Operations { public static synchronized Optional> proveAndGetBindings(Set givens, Formula goal, List variables){ - return prover.proveAndGetBindings(givens, goal, variables); + Future>> future = new FutureTask<>(()->{ + return prover.proveAndGetBindings(givens, goal, variables); + + + }); + + Optional> answer; + + try{ + + answer = future.get(1, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + answer = Optional.empty(); + } + + return answer; } - public static Optional> apply(Set background, Action action, State state){ - Prover prover = new SnarkWrapper(); + public static synchronized Optional>> proveAndGetMultipleBindings(Set givens, Formula goal, List variables){ + + return prover.proveAndGetMultipleBindings(givens, goal, variables); + + /* Future>>> future = new FutureTask<>(()-> prover.proveAndGetMultipleBindings(givens, goal, variables)); + + Optional>> answer; + + try{ + + answer = future.get(50, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e ) { + answer = Optional.empty(); + } + return answer; + +*/ + } + + public static Optional>> apply(Set background, Action action, State state){ + Set givens = Sets.union(background, state.getFormulae()); - Optional> bingdingsOpt = proveAndGetBindings(givens, action.getPrecondition(), action.openVars()); + Optional>> bindingsOpt = proveAndGetMultipleBindings(givens, action.getPrecondition(), action.openVars()); State newState; - if(!bingdingsOpt.isPresent()){ + if(!bindingsOpt.isPresent()){ return Optional.empty(); } + + Set> nexts = Sets.newSet(); + for(Map binding: bindingsOpt.get()){ + + if(binding.values().stream().anyMatch(x-> x instanceof Variable)){ + + continue; + } + + Set instantiatedDeletions = action.instantiateDeletions(binding); + + Set formulaeToRemove = state.getFormulae().stream(). + filter(f-> instantiatedDeletions.stream().anyMatch(d-> equivalent(background, f,d))).collect(Collectors.toSet()); + Set newFormulae = state.getFormulae(); - newFormulae = Sets.union(newFormulae, action.instantiateAdditions(bingdingsOpt.get())); + newFormulae = Sets.union(newFormulae, action.instantiateAdditions(binding)); + + + newFormulae = Sets.difference(newFormulae, formulaeToRemove); - newFormulae = Sets.difference(newFormulae, action.instantiateDeletions(bingdingsOpt.get())); newState = State.initializeWith(newFormulae); - return Optional.of(ImmutablePair.from(newState, action.instantiate(bingdingsOpt.get()))); + nexts.add(ImmutablePair.from(newState, action.instantiate(binding))); + + + } + + if(nexts.isEmpty()){ + + Map emptyBinding = CollectionUtils.newMap(); + Set instantiatedDeletions = action.instantiateDeletions(emptyBinding); + + Set formulaeToRemove = state.getFormulae().stream(). + filter(f-> instantiatedDeletions.stream().anyMatch(d-> equivalent(background, f,d))).collect(Collectors.toSet()); + + Set newFormulae = state.getFormulae(); + + newFormulae = Sets.union(newFormulae, action.instantiateAdditions(emptyBinding)); + + + newFormulae = Sets.difference(newFormulae, formulaeToRemove); + + + newState = State.initializeWith(newFormulae); + + nexts.add(ImmutablePair.from(newState, action.instantiate(emptyBinding))); + + + } + + return Optional.of(nexts); } + public static boolean equivalent(Set background, Formula f1, Formula f2){ + + if(!DEEP_EQUIVALENCE){ + return f1.equals(f2); + } + + BiConditional biConditional = new BiConditional(f1, f2); + return prover.prove(background,biConditional).isPresent(); + } public static boolean satisfies(Set background, State state, State goal){ diff --git a/src/main/java/edu/rpi/rair/utils/GoalTrackingProblem.java b/src/main/java/edu/rpi/rair/utils/GoalTrackingProblem.java new file mode 100644 index 0000000..94104b7 --- /dev/null +++ b/src/main/java/edu/rpi/rair/utils/GoalTrackingProblem.java @@ -0,0 +1,96 @@ +package edu.rpi.rair.utils; + +import com.naveensundarg.shadow.prover.representations.formula.Formula; +import com.naveensundarg.shadow.prover.utils.CollectionUtils; +import com.naveensundarg.shadow.prover.utils.Reader; +import edu.rpi.rair.Goal; +import edu.rpi.rair.State; +import us.bpsm.edn.Keyword; +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.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; + +/** + * Created by naveensundarg on 1/13/17. + */ +public class GoalTrackingProblem { + + private final PlanningProblem planningProblem; + private final Set goals; + private final Map goalNameMap; + + private static final Keyword DEFINITIONS = Keyword.newKeyword("definitions"); + private static final Keyword GOALS = Keyword.newKeyword("goals"); + + private static final Keyword PRIORITY = Keyword.newKeyword("priority"); + private static final Keyword STATE = Keyword.newKeyword("state"); + + public GoalTrackingProblem(PlanningProblem planningProblem, Set goals) { + this.planningProblem = planningProblem; + this.goals = goals; + this.goalNameMap = CollectionUtils.newMap(); + + for(Goal g: goals){ + goalNameMap.put(g.getName(), g); + } + + + } + + public static List readFromFile(InputStream inputStream) throws Reader.ParsingException { + + Parseable parseable = Parsers.newParseable(new InputStreamReader(inputStream)); + Parser parser = Parsers.newParser(Parsers.defaultConfiguration()); + + List goalTrackingProblems = CollectionUtils.newEmptyList(); + + Object nextValue = parser.nextValue(parseable); + + Set goals = CollectionUtils.newEmptySet(); + while (!nextValue.equals(Token.END_OF_INPUT)) { + Map goalTrackingProblemSpec = (Map) nextValue; + + PlanningProblem planningProblem = PlanningProblem.readFromObject(goalTrackingProblemSpec.get(DEFINITIONS)); + + + Map goalSpecs = (Map) goalTrackingProblemSpec.get(GOALS); + + for(Map.Entry entry : goalSpecs.entrySet()){ + + String name = entry.getKey().toString(); + Map goalSpec = (Map)entry.getValue(); + + int priority = Math.toIntExact((Long) goalSpec.get(PRIORITY)); + Set stateFormulae = PlanningProblem.readFrom((List) goalSpec.get(STATE)); + + goals.add(Goal.makeGoal(State.initializeWith(stateFormulae), priority, name)); + + } + + goalTrackingProblems.add(new GoalTrackingProblem(planningProblem, goals)); + nextValue = parser.nextValue(parseable); + + + } + + return goalTrackingProblems; + } + + public PlanningProblem getPlanningProblem() { + return planningProblem; + } + + public Set getGoals() { + return goals; + } + + public Goal getGoalNamed(String goalName) { + return goalNameMap.get(goalName); + } +} diff --git a/src/main/java/edu/rpi/rair/utils/PlanningProblem.java b/src/main/java/edu/rpi/rair/utils/PlanningProblem.java index b598cd2..d806dbd 100644 --- a/src/main/java/edu/rpi/rair/utils/PlanningProblem.java +++ b/src/main/java/edu/rpi/rair/utils/PlanningProblem.java @@ -81,52 +81,7 @@ public class PlanningProblem { 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); - Map actionMap = CollectionUtils.newMap(); - - actions.stream().forEach(action->{ - actionMap.put(action.getName(), action); - }); - if(planningProblemSpec.containsKey(EXPECTED_PLANS)){ - List plans = (List) planningProblemSpec.get(EXPECTED_PLANS); - - Set> expectedActions = plans.stream().map(plan->{ - - List instantActionList = (List) plan; - - List actionsList = instantActionList.stream().map(x -> { - try { - return readInstantiatedAction(actionMap, x); - } catch (Reader.ParsingException e) { - return null; - } - }).collect(Collectors.toList()); - - if(actionsList.stream().anyMatch(Objects::isNull)){ - return null; - } else { - return actionsList; - } - - }).collect(Collectors.toSet()); - - - planningProblems.add(new PlanningProblem(name, background, State.initializeWith(start), - State.initializeWith(goal), actions, expectedActions)); - } else { - - planningProblems.add(new PlanningProblem(name, background, State.initializeWith(start), - State.initializeWith(goal), actions)); - } + planningProblems.add(readFromObject(nextValue)); @@ -137,6 +92,56 @@ public class PlanningProblem { } + public static PlanningProblem readFromObject(Object nextValue) throws Reader.ParsingException { + 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); + Map actionMap = CollectionUtils.newMap(); + + actions.stream().forEach(action->{ + actionMap.put(action.getName(), action); + }); + if(planningProblemSpec.containsKey(EXPECTED_PLANS)){ + List plans = (List) planningProblemSpec.get(EXPECTED_PLANS); + + Set> expectedActions = plans.stream().map(plan->{ + + List instantActionList = (List) plan; + + List actionsList = instantActionList.stream().map(x -> { + try { + return readInstantiatedAction(actionMap, x); + } catch (Reader.ParsingException e) { + return null; + } + }).collect(Collectors.toList()); + + if(actionsList.stream().anyMatch(Objects::isNull)){ + return null; + } else { + return actionsList; + } + + }).collect(Collectors.toSet()); + + + return new PlanningProblem(name, background, State.initializeWith(start), + State.initializeWith(goal), actions, expectedActions); + } else { + + return new PlanningProblem(name, background, State.initializeWith(start), + State.initializeWith(goal), actions); + } + } private static Action readInstantiatedAction(Map actionMap, Object instantiatedActionSpec) throws Reader.ParsingException { @@ -222,7 +227,7 @@ public class PlanningProblem { } - private static Set readFrom(List objects) throws Reader.ParsingException { + public static Set readFrom(List objects) throws Reader.ParsingException { Set formulae = objects.stream().map(x -> { try { diff --git a/src/main/java/edu/rpi/rair/utils/RunDemo.java b/src/main/java/edu/rpi/rair/utils/RunDemo.java new file mode 100644 index 0000000..082cb1c --- /dev/null +++ b/src/main/java/edu/rpi/rair/utils/RunDemo.java @@ -0,0 +1,55 @@ +package edu.rpi.rair.utils; + +import com.diogonunes.jcdp.color.ColoredPrinter; +import com.diogonunes.jcdp.color.api.Ansi; +import com.naveensundarg.shadow.prover.utils.Reader; +import edu.rpi.rair.GoalTracker; +import edu.rpi.rair.Planner; + +import java.util.List; + +/** + * Created by naveensundarg on 1/15/17. + */ +public class RunDemo { + + public static void main(String[] args) throws Reader.ParsingException { + + List goalTrackingProblemList = (GoalTrackingProblem.readFromFile(Planner.class.getResourceAsStream("goal_tracking_tests.clj"))); + + + GoalTrackingProblem goalTrackingProblem = goalTrackingProblemList.get(0); + + GoalTracker goalTracker = new GoalTracker(goalTrackingProblem.getPlanningProblem().getBackground(), + goalTrackingProblem.getPlanningProblem().getStart(), + goalTrackingProblem.getPlanningProblem().getActions()); + + + ColoredPrinter cp = new ColoredPrinter.Builder(1, false).build(); + + + cp.setForegroundColor(Ansi.FColor.WHITE); + cp.setBackgroundColor(Ansi.BColor.BLUE); //setting format + cp.println("Adding goal G1"); + cp.clear(); + + boolean res1 = goalTracker.adoptGoal(goalTrackingProblem.getGoalNamed("G1")); + + cp.setForegroundColor(Ansi.FColor.WHITE); + cp.setBackgroundColor(Ansi.BColor.BLUE); //setting format + cp.println("Adding goal G2"); + cp.clear(); + + goalTracker.adoptGoal(goalTrackingProblem.getGoalNamed("G2")); + + cp.setForegroundColor(Ansi.FColor.WHITE); + cp.setBackgroundColor(Ansi.BColor.BLUE); //setting format + cp.println("Adding goal G3"); + cp.clear(); + goalTracker.adoptGoal(goalTrackingProblem.getGoalNamed("G3")); + + + + } + +} diff --git a/src/main/resources/edu/rpi/rair/completeness_problems.clj b/src/main/resources/edu/rpi/rair/completeness_problems.clj index cc8d55a..b006894 100644 --- a/src/main/resources/edu/rpi/rair/completeness_problems.clj +++ b/src/main/resources/edu/rpi/rair/completeness_problems.clj @@ -1,12 +1,12 @@ -{:name "test 1" - :background [P] - :start [Q] - :goal [R] +{:name "test 1" + :background [p] + :start [q] + :goal [r] :actions - [(define-action a1 () - {:preconditions [(or Q R)] - :additions [R] - :deletions [Q]})] + [(define-action a1 () + {:preconditions [(or q r)] + :additions [r] + :deletions [q]})] :expected-plans ([a1]) } @@ -15,13 +15,13 @@ {:name "simple killing" :background [] - :start [(forall ?x (Alive ?x))] - :goal [(forall ?x (Dead ?x))] + :start [(forall ?x (alive ?x))] + :goal [(forall ?x (dead ?x))] :actions [(define-action kill () - {:preconditions [(Alive ?x)] - :additions [(Dead ?x)] - :deletions [(Alive ?x)]})] + {:preconditions [(alive ?x)] + :additions [(dead ?x)] + :deletions [(alive ?x)]})] :expected-plans ([kill]) @@ -111,62 +111,74 @@ [drink eat work])} -{:name "bidding problem" - :background [] - :start [(bid 0)] - :goal [(bid 5)] + + +{:name "demo 1" + :background [ + (not (= room1 room2)) + (not (= prisoner commander)) + (not (= self prisoner)) + (not (= self commander)) + (person prisoner) + (person commander) + ] + :start [(in self room1) + (in commander room2) + (in prisoner room1) + (open (door room2)) + (not (open (door room1)))] + :goal [(interrogates commander prisoner)] :actions - [(define-action post-new-bid (?number) - {:preconditions [(bid ?number)] - :additions [(bid ($$sum 1 ?number))] - :deletions [(bid ?number)]})] + [(define-action open-door [?room] + {:preconditions [(not (open (door ?room)))] + :additions [(open (door ?room))] + :deletions [(not (open (door ?room)))]}) - :expected-plans ([(post-new-bid 0) - (post-new-bid 1) - (post-new-bid 2) - (post-new-bid 3) - (post-new-bid 4)])} -{:name "Moving Between Rooms" - :background [ (not (= room1 room2))] - :start [(In self room1) - (In commander room2) - (In prisoner room1) - (Open (door room2)) - (not (Open (door room1))) ] - :goal [(In prisoner room2)] - :actions - [(define-action open-door [?room] - {:preconditions [(not (Open (door ?room)))] - :additions [(Open (door ?room))] - :deletions [(not (Open (door ?room)))]}) + (define-action accompany[?person ?room1 ?room2] + {:preconditions [(not (= ?room1 ?room2)) + (in ?person ?room1) + (in self ?room1) + (open (door ?room1)) + (open (door ?room2))] - (define-action move-thing-from-to [?thing ?room1 ?room2] - {:preconditions [(not (= ?room1 ?room2)) - (In ?thing ?room1) - (Open (door ?room1)) - (Open (door ?room2))] + :additions [(in ?person ?room2) + (in self ?room2)] + :deletions [(in ?person ?room1) + (in self ?room1)]}) - :additions [(In ?thing ?room2)] - :deletions [(In ?thing ?room1) - (In self ?room1)]}) - (define-action accompany-from-to [?thing ?room1 ?room2] - {:preconditions [(not (= ?room1 ?room2)) - (In self ?room1) - (In ?thing ?room1) - (Open (door ?room1)) - (Open (door ?room2))] + (define-action request-move [?person ?room2 ?room1] + {:preconditions [(not (= ?room1 ?room2)) + (in ?person ?room2) + (not (= ?person prisoner)) + (open (door ?room1)) + (open (door ?room2))] - :additions [(In ?thing ?room2) - (In ?self ?room2)] - :deletions [(In ?thing ?room1) - (In self ?room1)]})] + :additions [(in ?person ?room1)] + :deletions [(in ?person ?room2)]}) - :expected-plans ([(open-door room1) - (accompany-from-to prisoner room1 room2)] + (define-action get-interrogated [?room] + {:preconditions [(in commander ?room) + (in prisoner ?room)] + + :additions [(interrogates commander prisoner)] + :deletions []}) + ] + + :expected-plans ( [(open-door room1) - (move-thing-from-to prisoner room1 room2)]) + (request-move commander room2 room1) + (get-interrogated room1) + ] + + [(open-door room1) + (accompany prisoner room1 room2) + (get-interrogated room2) + ] + + ) } + diff --git a/src/main/resources/edu/rpi/rair/debug.clj b/src/main/resources/edu/rpi/rair/debug.clj index 8b13789..09ad17e 100644 --- a/src/main/resources/edu/rpi/rair/debug.clj +++ b/src/main/resources/edu/rpi/rair/debug.clj @@ -1 +1,15 @@ +{: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)]})] + :expected-plans ([(post-new-bid 0) + (post-new-bid 1) + (post-new-bid 2) + (post-new-bid 3) + (post-new-bid 4)])} diff --git a/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj b/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj index 1715e5b..1cbd653 100644 --- a/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj +++ b/src/main/resources/edu/rpi/rair/goal_tracking_tests.clj @@ -1,30 +1,63 @@ -{:name "Sim" - :background [] - :start [(In self room1) - (In commander room2) - (In prisoner room1) - (Open (door room2)) - (not (Open (door room1))) ] +{:definitions + {:name "Moving Between Rooms" + :background [(not (= room1 room2)) + (forall [?x] (iff (Locked ?x) (not (Open ?x)))) + (forall [?x ?y ?z] (if (and (In ?x ?y) (not (= ?z ?y))) + (not (In ?x ?z))))] + :start [(In self room1) + (In commander room2) + (In prisoner room1) + (Open (door room2)) + (not (Open (door room1)))] + :goal [] + :actions + [(define-action open-door [?room] + {:preconditions [(not (Open (door ?room)))] + :additions [(Open (door ?room))] + :deletions [(not (Open (door ?room)))]}) - :actions [(define-action open-door [?room] - {:preconditions [(not (Open (door ?room)))] - :additions [(Open (door ?room))] - :deletions [(not (Open (door ?room)))]}) + (define-action move-thing-from-to [?thing ?room1 ?room2] + {:preconditions [(not (= ?room1 ?room2)) + (In ?thing ?room1) + (Open (door ?room1)) + (Open (door ?room2))] + :additions [(In ?thing ?room2)] + :deletions [(In ?thing ?room1) + (In self ?room1)]}) + (define-action accompany-from-to [?thing ?room1 ?room2] + {:preconditions [(not (= ?room1 ?room2)) + (In self ?room1) + (In ?thing ?room1) + (Open (door ?room1)) + (Open (door ?room2))] + :additions [(In ?thing ?room2) + (In ?self ?room2)] + :deletions [(In ?thing ?room1) + (In self ?room1)]}) - (define-action accompany-from-to [?thing ?room1 ?room2] - {:preconditions [(In self ?room1) - (In ?thing ?room1) - (Open (door ?room1)) - (Open (door ?room2))] + (define-action interrogate [?A ?B] + {:preconditions [(In ?room ?A) + (In ?room ?B)] - :additions [(In ?thing ?room2) - (In ?self ?room2)] - :deletions [(In ?thing ?room1) - (In self ?room1)]})] + :additions [(Interrogates ?A ?B)] + :deletions [(In ?thing ?room1) + (In self ?room1)]})] +} - :expected-plans ([(open-door room1) - (accompany-from-to prisoner room1 room2)]) + :goals {G1 {:priority 1 + :state [(not (Open (door room1)))]} + + G2 {:priority 1 + :state [(In prisoner room1)]} + + G3 {:priority 1 + :state [(forall [?room] + (if (In prisoner ?room) + (In self ?room)))] + } + + } } \ 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 index 51ec9e5..1586553 100644 --- a/src/test/java/edu/rpi/rair/DepthFirstPlannerTest.java +++ b/src/test/java/edu/rpi/rair/DepthFirstPlannerTest.java @@ -33,8 +33,8 @@ public class DepthFirstPlannerTest { Planner depthFirstPlanner = new DepthFirstPlanner(); - PlanningProblem planningProblem = planningProblemList.get(2); - System.out.println(depthFirstPlanner.plan(planningProblem.getBackground(), planningProblem.getActions(), planningProblem.getStart(), planningProblem.getGoal())); + PlanningProblem planningProblem = planningProblemList.get(5); + depthFirstPlanner.plan(planningProblem.getBackground(), planningProblem.getActions(), planningProblem.getStart(), planningProblem.getGoal()).get().forEach(System.out::println); } @DataProvider diff --git a/src/test/java/edu/rpi/rair/GoalTrackerTest.java b/src/test/java/edu/rpi/rair/GoalTrackerTest.java new file mode 100644 index 0000000..fb352dc --- /dev/null +++ b/src/test/java/edu/rpi/rair/GoalTrackerTest.java @@ -0,0 +1,56 @@ +package edu.rpi.rair; + +import com.diogonunes.jcdp.color.ColoredPrinter; +import com.diogonunes.jcdp.color.api.Ansi; +import com.naveensundarg.shadow.prover.utils.Reader; +import edu.rpi.rair.utils.GoalTrackingProblem; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + * Created by naveensundarg on 1/15/17. + */ +public class GoalTrackerTest { + + + public static void main(String[] args) throws Reader.ParsingException { + + List goalTrackingProblemList = (GoalTrackingProblem.readFromFile(Planner.class.getResourceAsStream("goal_tracking_tests.clj"))); + + + GoalTrackingProblem goalTrackingProblem = goalTrackingProblemList.get(0); + + GoalTracker goalTracker = new GoalTracker(goalTrackingProblem.getPlanningProblem().getBackground(), + goalTrackingProblem.getPlanningProblem().getStart(), + goalTrackingProblem.getPlanningProblem().getActions()); + + + ColoredPrinter cp = new ColoredPrinter.Builder(1, false).build(); + + + cp.setForegroundColor(Ansi.FColor.WHITE); + cp.setBackgroundColor(Ansi.BColor.BLUE); //setting format + cp.println("Adding goal G1"); + cp.clear(); + + boolean res1 = goalTracker.adoptGoal(goalTrackingProblem.getGoalNamed("G1")); + + cp.setForegroundColor(Ansi.FColor.WHITE); + cp.setBackgroundColor(Ansi.BColor.BLUE); //setting format + cp.println("Adding goal G2"); + cp.clear(); + + goalTracker.adoptGoal(goalTrackingProblem.getGoalNamed("G2")); + + cp.setForegroundColor(Ansi.FColor.WHITE); + cp.setBackgroundColor(Ansi.BColor.BLUE); //setting format + cp.println("Adding goal G3"); + cp.clear(); + goalTracker.adoptGoal(goalTrackingProblem.getGoalNamed("G3")); + + + + } +} \ No newline at end of file diff --git a/target/classes/edu/rpi/rair/debug.clj b/target/classes/edu/rpi/rair/debug.clj index 8b13789..09ad17e 100644 --- a/target/classes/edu/rpi/rair/debug.clj +++ b/target/classes/edu/rpi/rair/debug.clj @@ -1 +1,15 @@ +{: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)]})] + :expected-plans ([(post-new-bid 0) + (post-new-bid 1) + (post-new-bid 2) + (post-new-bid 3) + (post-new-bid 4)])} diff --git a/target/classes/edu/rpi/rair/goal_tracking_tests.clj b/target/classes/edu/rpi/rair/goal_tracking_tests.clj index 1715e5b..1cbd653 100644 --- a/target/classes/edu/rpi/rair/goal_tracking_tests.clj +++ b/target/classes/edu/rpi/rair/goal_tracking_tests.clj @@ -1,30 +1,63 @@ -{:name "Sim" - :background [] - :start [(In self room1) - (In commander room2) - (In prisoner room1) - (Open (door room2)) - (not (Open (door room1))) ] +{:definitions + {:name "Moving Between Rooms" + :background [(not (= room1 room2)) + (forall [?x] (iff (Locked ?x) (not (Open ?x)))) + (forall [?x ?y ?z] (if (and (In ?x ?y) (not (= ?z ?y))) + (not (In ?x ?z))))] + :start [(In self room1) + (In commander room2) + (In prisoner room1) + (Open (door room2)) + (not (Open (door room1)))] + :goal [] + :actions + [(define-action open-door [?room] + {:preconditions [(not (Open (door ?room)))] + :additions [(Open (door ?room))] + :deletions [(not (Open (door ?room)))]}) - :actions [(define-action open-door [?room] - {:preconditions [(not (Open (door ?room)))] - :additions [(Open (door ?room))] - :deletions [(not (Open (door ?room)))]}) + (define-action move-thing-from-to [?thing ?room1 ?room2] + {:preconditions [(not (= ?room1 ?room2)) + (In ?thing ?room1) + (Open (door ?room1)) + (Open (door ?room2))] + :additions [(In ?thing ?room2)] + :deletions [(In ?thing ?room1) + (In self ?room1)]}) + (define-action accompany-from-to [?thing ?room1 ?room2] + {:preconditions [(not (= ?room1 ?room2)) + (In self ?room1) + (In ?thing ?room1) + (Open (door ?room1)) + (Open (door ?room2))] + :additions [(In ?thing ?room2) + (In ?self ?room2)] + :deletions [(In ?thing ?room1) + (In self ?room1)]}) - (define-action accompany-from-to [?thing ?room1 ?room2] - {:preconditions [(In self ?room1) - (In ?thing ?room1) - (Open (door ?room1)) - (Open (door ?room2))] + (define-action interrogate [?A ?B] + {:preconditions [(In ?room ?A) + (In ?room ?B)] - :additions [(In ?thing ?room2) - (In ?self ?room2)] - :deletions [(In ?thing ?room1) - (In self ?room1)]})] + :additions [(Interrogates ?A ?B)] + :deletions [(In ?thing ?room1) + (In self ?room1)]})] +} - :expected-plans ([(open-door room1) - (accompany-from-to prisoner room1 room2)]) + :goals {G1 {:priority 1 + :state [(not (Open (door room1)))]} + + G2 {:priority 1 + :state [(In prisoner room1)]} + + G3 {:priority 1 + :state [(forall [?room] + (if (In prisoner ?room) + (In self ?room)))] + } + + } } \ No newline at end of file diff --git a/target/classes/edu/rpi/rair/utils/GoalTrackingProblem.class b/target/classes/edu/rpi/rair/utils/GoalTrackingProblem.class new file mode 100644 index 0000000000000000000000000000000000000000..d5e015a0c9f665806eea345d80d24b89e7744a1f GIT binary patch literal 5158 zcmb7IXKqV!t>oi{GJfri}%U${j&Ukio3#?hY!ld zLoz!oXCG4W;SlEIBO!bgACsMrtN4VFelmo+agXS7L{vPg;@%LCkA<-iM*}z>!U^O9 zSRTNZ047x2r(i}Vsi#tj)M&q%-kCJU6g2l3Be|%VNkmOOVMcRSBAJc$7vJhoP&Jy? zlUXw8*`x2%?Q79N!{SMBFfp3at(<8Hv!c_^V&3b?qGL5l!osXqA2T-TnPQgQ;Q0y< z8}4*EOX@Tl9kfhp-!UEIbzR-@-uO_wuXj*EeNQeM-I>XbMU9bEbfYo8KW&bPE$jQ% z^zb~;KM?O5h!1V!*5J^Zp)Ljf&O|Cbs#Uje%;?YyUXx*Z~w>CXOBxdv^QbuoX zY^Pxk=|oyVZBKewPj1o8gsk07WmG|3u_PNM^09U&h<8~va3+(Mt9mA z%O!P^R~aeGa z+quUW7M$xmG?H0uZIX`zo?XUqXU}kYESl2y8Ad9bOO5E}Xf(T9A4%_zX3X?H!;G3n z#x$}-TelMFR5rTHaY58|g`MOP57PqLuE3b*OjIw4C@0z0pYIhiR&l?I&!{-XBFK`) zda5AQbzs=Y*s7@boPz5vEbjgfsSM3g!zxJ&1&dl*i<7r}nUEMZEU|}fn?;(UDoFoSi{%x4Gj)UC8R ziB7R^6wLGX)6#lIhfa5Fs`!tBRZmw{96X#5XqGz3_EyMj8hrlN@(W|RHl0ke{t?H` z^1NZ;O&R+cA*IR4Ehb|iQGlVLC@&}B;T?6ip6z9=RlpS5F8#}1%$~e&M@ymVs?1s^ z_lhsLj~Oyyb5yX>En8k4QF-U8>7}^Fm*yFX!jp{c44PZUu%Yx`BSj6mde`mf>)sLX z?cY2^UzD@RzDlNkC zw}Ab!vaR(~3%;efXQiD0=9GKxvm=;fjdbVCjSWThbCYiEX1}r0@s!ndKp&<#zLpKG ze98qTl~pj`HE_yHCC!og)D~4bzHcoywi>%w>dC~7#@2)gTIl6O%{`gGIUh0{lco8Q#chg zdAWG2^kkm#$7CCSVgf2^rJr+FD=i%guI9V~E4gM@FRVMzD7}Q5feFA<3y-OybD!2m+I0+~?g<#Cr zb}yCG} z0qUpx>o7nwX>P^MGsW_XfNe75D84+A_X>Rv0x zVg<)>Nh~b$O9jt{m=@8Fpvh%5|2P)paoLJ$*=%+<7v`}jRuid;)a0?azB&@lqh$iE z6@vWjOHQI~TSSdiod7Lp=Vrl@!{<7d+)a}m#|&UL=SvCXm8c`ca~MrcglZupX(=P= zYIM*UtFf7{rEx~dLBe(`opFe}c{=9|-S7Z<@F+I%@zsyV39UHt7P|N#oj8aggh|ms z4lznOghkkbt*9pTY&?gKtRde)Y{T;qqO_xUKJWR-{Vv<#D(P;+_1u#HI*T260Y?pw zLB~!yzYdRJ7$bE496SgEyXe>^YBY-7v~VF#+u2cN2g|k08b^}^IXLq76y)zM$WKtd zBQ-&(4&NmCI^0$=WF*kK;XB7Izlt#xY?)~l85K7$;(&9^tkC%fD)^jYO!8~TVL!i;k5P^i^i|BS3UOP7ollaqAdmvJlLJ+5rYJZ-K%Hdv5?7WI zZ!bga)Q}s={DpWCzoLOuh6;`~lHm*{#yS(el-u<-w+82CA!%#yV)~y|8ZW_3F2630 z@;ASBNgh`m#hluxJvP=Zwa2E~EA6pas)u4*TWi;Xd1P}jX5v!jcoPM^l;;(=8PDa| cNcYU+KjOCgg9P%k_&l@x`}`l?5B$NW03a27Jpcdz literal 0 HcmV?d00001 diff --git a/target/classes/edu/rpi/rair/utils/RunDemo.class b/target/classes/edu/rpi/rair/utils/RunDemo.class new file mode 100644 index 0000000000000000000000000000000000000000..70a58f921d92af6b20ba97634c6b4699123ea9dd GIT binary patch literal 2789 zcmb7G*>@9F9R6-QVbXLc5NIKY3Roe9(qR!43YE4{h=x+yvK0}h$u&$#X2Q&*EN-~q zzMxM&dVKLkAM_zbImhF(f0W1X&ZH>`K}#O)y>sXLZQpO1{Qb`#e*$;`-zBgahjko@ zV<>@_aWnxP!<`txsE%Vgj;rUf1Ww?jS~6;RC4o3z)p06;E=;K9Oa~@0l|UBL9XN|~ z>U2Ji3u?cpmYFy%DNU~_(aUkX9>jdu;Q@o*ujuMd%EwOfHvyprNFAJ z?a1*;X;ymE)@+eC$*h~RisvlPR?oFdEx2m?0-LfjUopM1ZF-jNnU%mU`sQTCIVMZ) zAa#~3+Y#tVU&_u|^Ojk(oPs$Oc(zj*3~gFofm+tKcrCEL;9A9L&&pjRe8O{Syp*;5 zKwx#GO<6P54K1y00TxKNa__{WYN?>Ju0VPM8yf}dBGMzYEms!UkE*Qq$t zH|KKsvYB&>u4j&_RpuucXAnwgp7i$!h#7Lx$mXr`BBO_zf;!yjLPTxdktIq7hv-t` z_|2Rw2e#|@I+(M>lw0v~a?Dl|17G8tX5?P=o=cW$O0 zb21m`xF>K#1@2h$QaXOc$+J^T|EiUDZVl4LFy`>El}*;qmfO-DO88_J=mD$N#E5dhn;olhM|qmN1`EN&x4 zByd03mTa#=yN_6QXZ!D1(T2aEpL&4!#r`Tfsz^jzXS5j$SULUxT^F_X1+1!K^&u^# z{f0GFB-OsQighV1*c1uKwhPDpFN!JP>Pvd+H(FrU-Yw1?=gEV9(TGD&BUe zcxTYVHHl7i^R%AyY+#fr?87Dule!GaJ44zo@XcjP*kt26`M54u>M1u!A_z$}i|Ank9fADPfY&eblj=6795i1AFCOXy literal 0 HcmV?d00001 diff --git a/target/test-classes/edu/rpi/rair/GoalTrackerTest.class b/target/test-classes/edu/rpi/rair/GoalTrackerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..f18090a4b6e6286a084141dfab471f7a7f10667a GIT binary patch literal 2801 zcmb7G+jkR19R4Ov*fd>Q2v7(h0#-E2u>|cNX{s({;@NELyaZJJS zIEE8=2`3Uzkm{NIz^Y@GZTZ6jZRy?%0?|RL8dX?c_hBB8IC@n8OVPMHMA5z`GixEUT)(rUu{=y;L|TE4Zn`g{Q(tMa8^a?Z7Psw*~gC z)ZINJ6|0z+Mkr5KYF3&xTGTzy3}oI>aTjkXcw5E0xUb?pyszK`6%X){ijVP$KxZbO zr|H{eT5LZxsNz$6rs8wyvxt2C0$-~53ST!P_sj1b8uZ%_U zctsYF=}($okTw~QHEQZ5f!=hB!VR}9N6XsfiXTFmgDNTcG1n=DS+~1JZNl|7r8$Y6 zfilvFpqkl|sEfdcbhZW#+D7OQ!jt?OBx=2WnStrvR`t?^BYS5<1VYa>p#)a*h!N&~ z!FA|xfwh!gS8~df9VbrAl&`zgw7dCm?)xS&31TuvP?iD*YYqtvl`?BeO{^htrf|2V9P zE#v5!{uujY=;WHrf%H?zkfyFg;gLm!7Z=fy-1(L28**y;)|29?^sUK|`YL64D-_u@ zH!Q8KT6PD)Gm56p_N6j;WQQErOD1EvSWgXiXk!XVG!<=UZzu;;nVKyiy}XC|pQfp> zZ2mtl*s7o9&y9Q{5b}EA_#EFf&VqAn&jQ3R!RH>1tAfogJkPZn0;9|MXT7jw?Db5ic}Sw55-#Gwk*MI4RIG+z@AwG+g5`~ zd)pxGok2Ip_2|Gxu2OW*W?H!g2e1tpx+}|_bF}#q(O2mSi(a@%#2xIxef05e+KY#D z=6BeK?=grUu^&H?y@11k4~IiP5#7ggI`A|4$zTfL2MmxGA@%{egVZO3TVx+Vl&75K zZ|OmL`4Cw$4k7a}S1)oW%J~SnN4bt*h-gsHD1Sn87-yu8AdfdWPvRclIg#Su=skRR GBJ~fig9w-a literal 0 HcmV?d00001