mirror of
				https://github.com/RAIRLab/Spectra.git
				synced 2025-10-26 22:51:19 +00:00 
			
		
		
		
	better toString for actions and some more tests.
This commit is contained in:
		
							parent
							
								
									8c78a2f8e5
								
							
						
					
					
						commit
						598f9b3dff
					
				
					 10 changed files with 307 additions and 44 deletions
				
			
		|  | @ -2,6 +2,7 @@ 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.Compound; | ||||
| import com.naveensundarg.shadow.prover.representations.value.Value; | ||||
| import com.naveensundarg.shadow.prover.representations.value.Variable; | ||||
| import com.naveensundarg.shadow.prover.utils.CollectionUtils; | ||||
|  | @ -27,6 +28,8 @@ public class Action { | |||
| 
 | ||||
|     private int weight; | ||||
| 
 | ||||
|     private final Compound shorthand; | ||||
| 
 | ||||
|     private Action(String name, Set<Formula> preconditions, Set<Formula> additions, Set<Formula> deletions, List<Variable> freeVariables) { | ||||
|         this.name = name; | ||||
|         this.preconditions = preconditions; | ||||
|  | @ -46,6 +49,35 @@ public class Action { | |||
|         this.weight = preconditions.stream().mapToInt(Formula::getWeight).sum() + | ||||
|                 additions.stream().mapToInt(Formula::getWeight).sum() + | ||||
|                 deletions.stream().mapToInt(Formula::getWeight).sum(); | ||||
| 
 | ||||
|         List<Value> valuesList = freeVariables.stream().collect(Collectors.toList());; | ||||
|         this.shorthand = new Compound(name, valuesList); | ||||
|     } | ||||
| 
 | ||||
|     private Action(String name, Set<Formula> preconditions, Set<Formula> additions, | ||||
|                    Set<Formula> deletions, List<Variable> freeVariables, | ||||
|                    Compound shorthand | ||||
|     ) { | ||||
|         this.name = name; | ||||
|         this.preconditions = preconditions; | ||||
| 
 | ||||
|         this.additions = additions; | ||||
|         this.deletions = deletions; | ||||
|         List<Variable> 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(); | ||||
| 
 | ||||
|         this.shorthand = shorthand; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -97,16 +129,20 @@ public class Action { | |||
|                 newFreeVraibles.add(var); | ||||
|             } | ||||
|         } | ||||
|         return new Action(name, newPreconditions, newAdditions, newDeletions, newFreeVraibles); | ||||
| 
 | ||||
|         List<Value> valuesList = freeVariables.stream().collect(Collectors.toList());; | ||||
|         Compound shorthand = (Compound)(new Compound(name, valuesList)).apply(binding); | ||||
|         return new Action(name, newPreconditions, newAdditions, newDeletions, newFreeVraibles, shorthand); | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "Action{" + | ||||
|                 "preconditions=" + preconditions + | ||||
|                 ", additions=" + additions + | ||||
|                 ", deletions=" + deletions + | ||||
|                 ", name='" + name + '\'' + | ||||
|                 '}'; | ||||
|         return shorthand.getArguments().length == 0?  name: shorthand.toString(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  |  | |||
							
								
								
									
										12
									
								
								src/main/java/edu/rpi/rair/utils/Commons.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/java/edu/rpi/rair/utils/Commons.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| package edu.rpi.rair.utils; | ||||
| 
 | ||||
| import edu.rpi.rair.State; | ||||
| import us.bpsm.edn.parser.Parseable; | ||||
| 
 | ||||
| /** | ||||
|  * Created by naveensundarg on 1/15/17. | ||||
|  */ | ||||
| public class Commons { | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -2,6 +2,7 @@ package edu.rpi.rair.utils; | |||
| 
 | ||||
| import clojure.lang.Obj; | ||||
| 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.Reader; | ||||
|  | @ -16,10 +17,8 @@ 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.security.Key; | ||||
| import java.util.*; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| /** | ||||
|  | @ -27,11 +26,13 @@ import java.util.stream.Collectors; | |||
|  */ | ||||
| public class PlanningProblem { | ||||
| 
 | ||||
|     public Set<Formula> background; | ||||
|     public Set<Action> actions; | ||||
|     public State start; | ||||
|     public State goal; | ||||
|     public String name; | ||||
|     private Set<Formula> background; | ||||
|     private Set<Action> actions; | ||||
|     private State start; | ||||
|     private State goal; | ||||
|     private String name; | ||||
|     private Optional<Set<List<Action>>> expectedActionSequencesOpt; | ||||
|     private Map<String, Action> actionMap; | ||||
| 
 | ||||
|     private static final Keyword BACKGROUND = Keyword.newKeyword("background"); | ||||
|     private static final Keyword START = Keyword.newKeyword("start"); | ||||
|  | @ -45,6 +46,7 @@ public class PlanningProblem { | |||
| 
 | ||||
|     private static final Symbol ACTION_DEFINER = Symbol.newSymbol("define-action"); | ||||
| 
 | ||||
|     private static final Keyword EXPECTED_PLANS = Keyword.newKeyword("expected-plans"); | ||||
| 
 | ||||
|     public PlanningProblem(String name, Set<Formula> background, State start, State goal, Set<Action> actions) { | ||||
| 
 | ||||
|  | @ -53,6 +55,19 @@ public class PlanningProblem { | |||
|         this.actions = actions; | ||||
|         this.goal = goal; | ||||
|         this.name = name; | ||||
|         this.actionMap = CollectionUtils.newMap(); | ||||
|         this.expectedActionSequencesOpt = Optional.empty(); | ||||
|     } | ||||
| 
 | ||||
|     public PlanningProblem(String name, Set<Formula> background, State start, State goal, Set<Action> actions, Set<List<Action>> expectedActionSequences) { | ||||
| 
 | ||||
|         this.background = background; | ||||
|         this.start = start; | ||||
|         this.actions = actions; | ||||
|         this.goal = goal; | ||||
|         this.name = name; | ||||
|         this.actionMap = CollectionUtils.newMap(); | ||||
|         this.expectedActionSequencesOpt = Optional.of(expectedActionSequences); | ||||
|     } | ||||
| 
 | ||||
|     public static List<PlanningProblem> readFromFile(InputStream inputStream) throws Reader.ParsingException { | ||||
|  | @ -76,9 +91,44 @@ public class PlanningProblem { | |||
| 
 | ||||
|             String name = planningProblemSpec.get(NAME).toString(); | ||||
|             Set<Action> actions = readActionsFrom(actionDefinitions); | ||||
|             Map<String, Action> actionMap = CollectionUtils.newMap(); | ||||
| 
 | ||||
|             planningProblems.add(new PlanningProblem(name, background, State.initializeWith(start), | ||||
|             actions.stream().forEach(action->{ | ||||
|                 actionMap.put(action.getName(), action); | ||||
|             }); | ||||
|             if(planningProblemSpec.containsKey(EXPECTED_PLANS)){ | ||||
|                 List<?> plans = (List<?>) planningProblemSpec.get(EXPECTED_PLANS); | ||||
| 
 | ||||
|                 Set<List<Action>> expectedActions = plans.stream().map(plan->{ | ||||
| 
 | ||||
|                      List<?> instantActionList = (List<?>) plan; | ||||
| 
 | ||||
|                     List<Action> 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)); | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|             nextValue = parser.nextValue(parseable); | ||||
|         } | ||||
|  | @ -87,6 +137,44 @@ public class PlanningProblem { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     private  static Action readInstantiatedAction(Map<String, Action> actionMap, Object instantiatedActionSpec) throws Reader.ParsingException { | ||||
| 
 | ||||
|         if(instantiatedActionSpec instanceof List<?>){ | ||||
| 
 | ||||
|             List<?> instActionList = (List<?>) instantiatedActionSpec; | ||||
|             String name = instActionList.get(0).toString(); | ||||
|             Action general = actionMap.get(name); | ||||
| 
 | ||||
|             List<Variable> variables = general.openVars(); | ||||
|             if(variables.size()!=instActionList.size()-1){ | ||||
| 
 | ||||
|                 throw new AssertionError("Not a proper instantiation of "+ name); | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             Map<Variable, Value> binding = CollectionUtils.newMap(); | ||||
|             for(int i = 1; i<instActionList.size(); i++){ | ||||
| 
 | ||||
|                 binding.put(variables.get(i-1), Reader.readLogicValue(instActionList.get(i))); | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             return general.instantiate(binding); | ||||
|         } else { | ||||
| 
 | ||||
|             String name = instantiatedActionSpec.toString(); | ||||
| 
 | ||||
|             if(actionMap.containsKey(name)){ | ||||
|                return actionMap.get(name); | ||||
|             } | ||||
|             else{ | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static Set<Action> readActionsFrom(List<?> actionSpecs) throws Reader.ParsingException { | ||||
| 
 | ||||
|         Set<Action> actions = actionSpecs.stream().map(spec -> { | ||||
|  | @ -156,6 +244,34 @@ public class PlanningProblem { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public Set<Formula> getBackground() { | ||||
|         return background; | ||||
|     } | ||||
| 
 | ||||
|     public Set<Action> getActions() { | ||||
|         return actions; | ||||
|     } | ||||
| 
 | ||||
|     public State getStart() { | ||||
|         return start; | ||||
|     } | ||||
| 
 | ||||
|     public State getGoal() { | ||||
|         return goal; | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     public Optional<Set<List<Action>>> getExpectedActionSequencesOpt() { | ||||
|         return expectedActionSequencesOpt; | ||||
|     } | ||||
| 
 | ||||
|     public Map<String, Action> getActionMap() { | ||||
|         return actionMap; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "PlanningProblem{" + | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ | |||
|                                  :additions     [R] | ||||
|                                  :deletions     [Q]})] | ||||
| 
 | ||||
|  :expected-plan [a1] | ||||
|  :expected-plans ([a1]) | ||||
|  } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -119,4 +119,54 @@ | |||
|              [(define-action post-new-bid (?number) | ||||
|                              {:preconditions [(bid ?number)] | ||||
|                               :additions     [(bid ($$sum 1 ?number))] | ||||
|                               :deletions     [(bid ?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)])} | ||||
| 
 | ||||
| {: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 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)]})] | ||||
| 
 | ||||
|  :expected-plans ([(open-door room1) | ||||
|                    (accompany-from-to prisoner room1 room2)] | ||||
| 
 | ||||
|                    [(open-door room1) | ||||
|                    (move-thing-from-to prisoner room1 room2)]) | ||||
| 
 | ||||
|  } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								src/main/resources/edu/rpi/rair/debug.clj
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/main/resources/edu/rpi/rair/debug.clj
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| 
 | ||||
|  | @ -1,27 +1,30 @@ | |||
| { | ||||
|  :name "test 1" | ||||
|  :background [ (forall (?x ?y ?room1 ?room2) | ||||
|                        (if (and (Interrogates ?x ?y) | ||||
|                                 (In ?x ?room1) | ||||
|                                 (In ?y ?room2)) | ||||
|                          (= ?room1 ?room2))) | ||||
| 
 | ||||
| {:name       "Sim" | ||||
|  :background [] | ||||
|  :start      [(In self room1) | ||||
|               (In commander room2) | ||||
|               () | ||||
|               ] | ||||
|  :start [Be_In_Room | ||||
|          (Closed (door room1)) | ||||
|          (Accompany self prisoner)] | ||||
|               (In prisoner room1) | ||||
|               (Open (door room2)) | ||||
|               (not (Open (door room1))) ] | ||||
| 
 | ||||
|  :goalSequence [ | ||||
|                 [G1 1 [(In prisoner1 room1)]] | ||||
|                 [G2 1 [(Closed (door room1))]] | ||||
|                 [G3 1 [(Accompany self prisoner)]] | ||||
|  :actions     [(define-action open-door [?room] | ||||
|                              {:preconditions [(not (Open (door ?room)))] | ||||
|                               :additions [(Open (door ?room))] | ||||
|                               :deletions [(not (Open (door ?room)))]}) | ||||
| 
 | ||||
|                 [G4 2 [(Interrogates command robot)]] | ||||
|                 [G5 2 []] | ||||
| 
 | ||||
|                 ] | ||||
| 
 | ||||
|               (define-action accompany-from-to [?thing ?room1 ?room2] | ||||
|                              {:preconditions [(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)]})] | ||||
| 
 | ||||
|  :expected-plans ([(open-door room1) | ||||
|                    (accompany-from-to prisoner room1 room2)]) | ||||
| 
 | ||||
|  } | ||||
|  | @ -10,6 +10,7 @@ import org.testng.annotations.Test; | |||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import static org.testng.Assert.*; | ||||
| 
 | ||||
|  | @ -33,7 +34,7 @@ public class DepthFirstPlannerTest { | |||
|         Planner depthFirstPlanner = new DepthFirstPlanner(); | ||||
| 
 | ||||
|         PlanningProblem planningProblem = planningProblemList.get(2); | ||||
|         System.out.println(depthFirstPlanner.plan(planningProblem.background, planningProblem.actions, planningProblem.start, planningProblem.goal)); | ||||
|         System.out.println(depthFirstPlanner.plan(planningProblem.getBackground(), planningProblem.getActions(), planningProblem.getStart(), planningProblem.getGoal())); | ||||
|     } | ||||
| 
 | ||||
|     @DataProvider | ||||
|  | @ -55,16 +56,29 @@ public class DepthFirstPlannerTest { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     @Test(dataProvider = "testCompletenessDataProvider") | ||||
|     public void testCompletness(PlanningProblem planningProblem) throws Exception { | ||||
| 
 | ||||
|         Optional<Set<Plan>> possiblePlans = depthFirstPlanner.plan( | ||||
|                 planningProblem.background, | ||||
|                 planningProblem.actions, | ||||
|                 planningProblem.start, | ||||
|                 planningProblem.goal); | ||||
|                 planningProblem.getBackground(), | ||||
|                 planningProblem.getActions(), | ||||
|                 planningProblem.getStart(), | ||||
|                 planningProblem.getGoal()); | ||||
| 
 | ||||
|         Assert.assertTrue(possiblePlans.isPresent()); | ||||
| 
 | ||||
|         Set<Plan> plans = possiblePlans.get(); | ||||
| 
 | ||||
|         if(planningProblem.getExpectedActionSequencesOpt().isPresent()){ | ||||
| 
 | ||||
|             Set<List<Action>> actionSequences = plans.stream().map(Plan::getActions).collect(Collectors.toSet()); | ||||
|             Set<List<Action>> expectedActionSequences = planningProblem.getExpectedActionSequencesOpt().get(); | ||||
| 
 | ||||
| 
 | ||||
|             Assert.assertEquals(actionSequences, expectedActionSequences); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								target/classes/edu/rpi/rair/debug.clj
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								target/classes/edu/rpi/rair/debug.clj
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| 
 | ||||
							
								
								
									
										30
									
								
								target/classes/edu/rpi/rair/goal_tracking_tests.clj
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								target/classes/edu/rpi/rair/goal_tracking_tests.clj
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| {:name       "Sim" | ||||
|  :background [] | ||||
|  :start      [(In self room1) | ||||
|               (In commander room2) | ||||
|               (In prisoner room1) | ||||
|               (Open (door room2)) | ||||
|               (not (Open (door room1))) ] | ||||
| 
 | ||||
|  :actions     [(define-action open-door [?room] | ||||
|                              {:preconditions [(not (Open (door ?room)))] | ||||
|                               :additions [(Open (door ?room))] | ||||
|                               :deletions [(not (Open (door ?room)))]}) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|               (define-action accompany-from-to [?thing ?room1 ?room2] | ||||
|                              {:preconditions [(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)]})] | ||||
| 
 | ||||
|  :expected-plans ([(open-door room1) | ||||
|                    (accompany-from-to prisoner room1 room2)]) | ||||
| 
 | ||||
|  } | ||||
							
								
								
									
										
											BIN
										
									
								
								target/classes/edu/rpi/rair/utils/Commons.class
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								target/classes/edu/rpi/rair/utils/Commons.class
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue