mirror of
				https://github.com/RAIRLab/Spectra.git
				synced 2025-10-26 22:51:19 +00:00 
			
		
		
		
	Improving DCEC support
- Time based search algorithm - Added new variables ?now and ?next
This commit is contained in:
		
							parent
							
								
									a747b38233
								
							
						
					
					
						commit
						01883787da
					
				
					 5 changed files with 364 additions and 11 deletions
				
			
		|  | @ -4,11 +4,12 @@ import org.rairlab.planner.utils.Visualizer; | |||
| import org.rairlab.shadow.prover.core.Prover; | ||||
| import org.rairlab.shadow.prover.core.ccprovers.CognitiveCalculusProver; | ||||
| import org.rairlab.shadow.prover.core.proof.Justification; | ||||
| import org.rairlab.shadow.prover.representations.formula.BiConditional; | ||||
| import org.rairlab.shadow.prover.representations.formula.Formula; | ||||
| 
 | ||||
| import org.rairlab.shadow.prover.representations.value.Value; | ||||
| import org.rairlab.shadow.prover.representations.value.Variable; | ||||
| import org.rairlab.shadow.prover.representations.formula.*; | ||||
| import org.rairlab.shadow.prover.representations.value.Constant; | ||||
| 
 | ||||
| 
 | ||||
| import org.rairlab.shadow.prover.utils.CollectionUtils; | ||||
| 
 | ||||
| import org.rairlab.shadow.prover.utils.Sets; | ||||
|  | @ -16,11 +17,14 @@ import org.apache.commons.lang3.tuple.Pair; | |||
| import org.apache.commons.lang3.tuple.ImmutablePair; | ||||
| import org.apache.commons.lang3.tuple.Triple; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashSet; | ||||
| 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; | ||||
| 
 | ||||
| /** | ||||
|  * Created by naveensundarg on 1/13/17. | ||||
|  | @ -155,10 +159,37 @@ public class Operations { | |||
|         return Optional.of(ans.get().getRight()); | ||||
|     } | ||||
| 
 | ||||
|     public static Value getTime(int time) { | ||||
|         return new Constant("t" + time); | ||||
|     } | ||||
| 
 | ||||
|     public static Optional<Set<Pair<State, Action>>> apply(Set<Formula> background, Action action, State state) { | ||||
|     public static int getTime(Value time) { | ||||
|         String s = time.getName(); | ||||
|         String[] ss = s.split("t"); | ||||
|         if (ss.length != 2) { | ||||
|             return -1; | ||||
|         } | ||||
|         try { | ||||
|             int t = Integer.parseInt(ss[1]); | ||||
|             return t + 1; | ||||
|         } catch (NumberFormatException e) { | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|         // Get resulting states from cache if computed before | ||||
|     // Take a time value, get the integer number out and | ||||
|     // increment by 1 | ||||
|     public static Value incrementTime(Value time) { | ||||
|         int t = getTime(time); | ||||
|         if (t < 0) { | ||||
|             return new Constant("ERROR"); | ||||
|         } | ||||
|         return new Constant("t" + (t + 1)); | ||||
|     } | ||||
| 
 | ||||
|     public static Optional<Set<Pair<State, Action>>> apply(Set<Formula> background, Action action, State state, Value t) { | ||||
| 
 | ||||
|         // // Get resulting states from cache if computed before | ||||
|         if(applyCache.containsKey(Triple.of(background, action, state))){ | ||||
|             Optional<Set<Pair<State, Action>>>  ans  = applyCache.get(Triple.of(background, action, state)); | ||||
|             if(ans.isPresent()){ | ||||
|  | @ -169,7 +200,22 @@ public class Operations { | |||
| 
 | ||||
|         // Ask theorem prover for witnesses that satisfy the precondition | ||||
|         Set<Formula> givens = Sets.union(background, state.getFormulae()); | ||||
|         Optional<Set<Map<Variable, Value>>> bindingsOpt = proveAndGetBindingsCached(givens, action.getPrecondition(), action.openVars()); | ||||
| 
 | ||||
|         // TODO: Have all this ?now and (next ?now) code within Action.java | ||||
| 
 | ||||
|         // Replace ?now with current time within preconditions | ||||
|         Formula precondition = action.getPrecondition(); | ||||
|         Value now = new Variable("?now"); | ||||
|         precondition = replaceValue(precondition, now, t); | ||||
| 
 | ||||
|         // We already replaced the ?now | ||||
|         List<Variable> openVars = action.openVars() | ||||
|             .stream() | ||||
|             .filter(v -> !v.getName().equals("?now")) | ||||
|             .collect(Collectors.toList()); | ||||
| 
 | ||||
|         // TODO: Can likely more intelligently cache considering time... | ||||
|         Optional<Set<Map<Variable, Value>>> bindingsOpt = proveAndGetBindingsCached(givens, precondition, openVars); | ||||
| 
 | ||||
|         // If not witnesses found, return nothing | ||||
|         if (!bindingsOpt.isPresent()) { | ||||
|  | @ -191,9 +237,19 @@ public class Operations { | |||
|             // newState = (oldState - Deletions(a)) U Additions(a) | ||||
|             Action groundedAction = action.instantiate(binding); | ||||
| 
 | ||||
|             Set<Formula> additions = groundedAction.getAdditions(); | ||||
|             Set<Formula> deletions = groundedAction.getDeletions(); | ||||
| 
 | ||||
|             // Replace (next ?now) with appropriate time | ||||
|             Value nextTime = incrementTime(t); | ||||
|             Value nextTimeVar = new Variable("?next"); | ||||
|             additions = replaceValue(additions, nextTimeVar, nextTime); | ||||
|             deletions = replaceValue(deletions, nextTimeVar, nextTime); | ||||
| 
 | ||||
| 
 | ||||
|             State newState = State.initializeWith(Sets.union( | ||||
|                 Sets.difference(state.getFormulae(), groundedAction.getDeletions()), | ||||
|                 groundedAction.getAdditions() | ||||
|                 Sets.difference(state.getFormulae(), deletions), | ||||
|                 additions | ||||
|             )); | ||||
| 
 | ||||
|             // If the state progresses, record it as a possible next state | ||||
|  | @ -203,10 +259,102 @@ public class Operations { | |||
|         } | ||||
| 
 | ||||
|         applyCache.put(Triple.of(background, action, state), Optional.of(nextStates)); | ||||
| 
 | ||||
|         return Optional.of(nextStates); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static State replaceValue(State s, Value r, Value t) { | ||||
|         Set<Formula> newFormulae = replaceValue(s.getFormulae(), r, t); | ||||
|         return State.initializeWith(newFormulae); | ||||
|     } | ||||
| 
 | ||||
|     public static Set<Formula> replaceValue(Set<Formula> s, Value r, Value t) { | ||||
|         Set<Formula> newFormulae = new HashSet<Formula>(); | ||||
|         for (Formula f : s) { | ||||
|             newFormulae.add(replaceValue(f, r, t)); | ||||
|         } | ||||
|         return newFormulae; | ||||
|     } | ||||
| 
 | ||||
|     public static Value replaceValue(Value v, Value r, Value t) { | ||||
|         if (v.getName().equals(r.getName())) { | ||||
|             return t; | ||||
|         } | ||||
|         return v; | ||||
|     } | ||||
| 
 | ||||
|     // Everywhere where there's a ?now replace with value t | ||||
|     public static Formula replaceValue(Formula f, Value r, Value t) { | ||||
|         // Base Cases: | ||||
| 
 | ||||
|         // Bottom of Formula graph wouldn't have any time points under it | ||||
|         if (f instanceof Predicate || f instanceof Atom) { | ||||
|             return f; | ||||
|         } | ||||
| 
 | ||||
|         // Check if these quantifiers contain our bound varialbe | ||||
|         if (f instanceof UnaryModalFormula) { | ||||
|             UnaryModalFormula uf = (UnaryModalFormula) f; | ||||
| 
 | ||||
|             Value agent = uf.getAgent(); | ||||
|             Value time = uf.getTime(); | ||||
|             Value newTime = replaceValue(time, r, t); | ||||
|             Formula uf_sub = uf.getFormula(); | ||||
|             Formula new_uf_sub = replaceValue(uf_sub, r, t); | ||||
| 
 | ||||
|             if (f instanceof Belief) { | ||||
|                 return new Belief(agent, newTime, new_uf_sub); | ||||
|             } else if (f instanceof Intends) { | ||||
|                 return new Intends(agent, newTime, new_uf_sub); | ||||
|             } else if (f instanceof Knowledge) { | ||||
|                 return new Knowledge(agent, newTime, new_uf_sub); | ||||
|             } | ||||
|             // Assumes Perception | ||||
|             if (! (f instanceof Perception)) { | ||||
|                 System.out.println("[fixTimepoints:Operations.java] Doesn't account for new modal operator"); | ||||
|             } | ||||
|             return new Perception(agent, newTime, new_uf_sub); | ||||
|         } | ||||
| 
 | ||||
|         // Recusive Case: Iterate over each subformula and replace | ||||
| 
 | ||||
|         if (f instanceof Not) { | ||||
|             Formula subFormula = ((Not) f).getArgument(); | ||||
|             return new Not(replaceValue(subFormula, r, t)); | ||||
|         } else if (f instanceof Universal) { | ||||
|             Formula subFormula = ((Universal) f).getArgument(); | ||||
|             return new Universal(((Universal) f).vars(), replaceValue(subFormula, r, t)); | ||||
|         } else if (f instanceof Existential) { | ||||
|             Formula subFormula = ((Existential) f).getArgument(); | ||||
|             return new Universal(((Existential) f).vars(), replaceValue(subFormula, r, t)); | ||||
|         } else if (f instanceof Implication) { | ||||
|             Formula antecedant = ((Implication) f).getAntecedent(); | ||||
|             Formula consequent = ((Implication) f).getConsequent(); | ||||
|             return new Implication(replaceValue(antecedant, r, t), replaceValue(consequent, r, t)); | ||||
|         } else if (f instanceof BiConditional) { | ||||
|             Formula left = ((BiConditional) f).getLeft(); | ||||
|             Formula right = ((BiConditional) f).getRight(); | ||||
|             return new BiConditional(replaceValue(left, r, t), replaceValue(right, r, t)); | ||||
|         } | ||||
| 
 | ||||
|         List<Formula> subFormulae = f.getArgs(); | ||||
|         List<Formula> newArguments = new ArrayList<Formula>(); | ||||
|         for (Formula sf : subFormulae) { | ||||
|             newArguments.add(replaceValue(sf, r, t)); | ||||
|         } | ||||
| 
 | ||||
|         if (f instanceof And) { | ||||
|             return new And(newArguments); | ||||
|         } | ||||
| 
 | ||||
|         // Assume Or | ||||
|         if (! (f instanceof Or)) { | ||||
|             System.out.println("[fixTimepoints:Operations.java] Not accounting for formula type in recursive case"); | ||||
|         } | ||||
|         return new Or(newArguments); | ||||
|     } | ||||
| 
 | ||||
|     public static boolean equivalent(Set<Formula> background, Formula f1, Formula f2) { | ||||
|         if (!DEEP_EQUIVALENCE) { | ||||
|             return f1.equals(f2); | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import org.rairlab.planner.State; | |||
| import org.rairlab.planner.Action; | ||||
| import org.rairlab.planner.Plan; | ||||
| import org.rairlab.planner.Operations; | ||||
| import org.rairlab.shadow.prover.representations.value.Value; | ||||
| 
 | ||||
| import java.util.*; | ||||
| import java.util.function.Function; | ||||
|  | @ -67,6 +68,10 @@ public class AStarPlanner { | |||
|         comparator.setValue(searchStart, 0); | ||||
|         search.add(searchStart); | ||||
| 
 | ||||
|         // For debugging... | ||||
|         Map<State, List<Action>> seq = new HashMap<State, List<Action>>(); | ||||
|         seq.put(start, new ArrayList<Action>()); | ||||
| 
 | ||||
|         // Current set of plans | ||||
|         Set<Plan> plansFound = new HashSet<Plan>(); | ||||
| 
 | ||||
|  | @ -81,7 +86,11 @@ public class AStarPlanner { | |||
|             State lastState = currentSearch.getLeft(); | ||||
|             List<Action> previous_actions = currentSearch.getRight(); | ||||
| 
 | ||||
|             // System.out.println("Considering state with heuristic: " + comparator.getValue(currentSearch)); | ||||
|             System.out.println("--------------------"); | ||||
|             System.out.println("Considering state with heuristic: " + comparator.getValue(currentSearch)); | ||||
|             System.out.println("Current Plan: " + seq.get(lastState).toString()); | ||||
|             System.out.println("Current State: " + lastState.toString()); | ||||
|             System.out.println("--------------------"); | ||||
| 
 | ||||
|             // Exit loop if we've passed the depth limit | ||||
|             int currentDepth = previous_actions.size(); | ||||
|  | @ -105,7 +114,10 @@ public class AStarPlanner { | |||
| 
 | ||||
|             // Apply the action to the state and add to the search space | ||||
|             for (Action action : nonTrivialActions) { | ||||
|                 Optional<Set<Pair<State, Action>>> optNextStateActionPairs = Operations.apply(background, action, lastState); | ||||
|                 // System.out.println("Considering action: " + action.getName()); | ||||
| 
 | ||||
|                 Value currentTime = Operations.getTime(previous_actions.size()); | ||||
|                 Optional<Set<Pair<State, Action>>> optNextStateActionPairs = Operations.apply(background, action, lastState, currentTime); | ||||
| 
 | ||||
|                 // Ignore actions that aren't applicable | ||||
|                 if (optNextStateActionPairs.isEmpty()) { | ||||
|  | @ -137,6 +149,10 @@ public class AStarPlanner { | |||
|                     int heuristicValue = heuristic.apply(nextState); | ||||
|                     comparator.setValue(futureSearch, planCost + heuristicValue); | ||||
|                     search.add(futureSearch); | ||||
| 
 | ||||
|                     // For debugging... | ||||
|                     seq.put(nextState, next_actions); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ public final class Runner { | |||
|         } | ||||
| 
 | ||||
|         AStarPlanner astarplanner = new AStarPlanner(); | ||||
|         astarplanner.setK(2); | ||||
|         astarplanner.setK(1); | ||||
| 
 | ||||
|         for (PlanningProblem planningProblem : planningProblemList) { | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,108 @@ | |||
| ; Original problem from Joerg Hoffmann and Ronen Brafman | ||||
| {:name "Block-Conformant-Tiny" | ||||
|     :background [ | ||||
|         ; Setting object types | ||||
|         (block b1) | ||||
|         (block b2) | ||||
| 
 | ||||
|         ; Unique name axioms | ||||
|         (not (= b1 b2)) | ||||
| 
 | ||||
|         ; Block World Axioms | ||||
| 
 | ||||
|         ; Blocks are never on themselves | ||||
|         (forall [x] (not (on x x))) | ||||
|         ; on is not symmetric | ||||
|         (forall [x y] (if (on x y) (not (on y x)))) | ||||
|         ; Any block on a table isn't on top of another block | ||||
|         (forall [x y] (if (on-table x) (not (on x y)))) | ||||
|         ; Any block that is cleared does not have another block on top of it | ||||
|         (forall [x y] (if (clear x) (not (on y x)))) | ||||
| 
 | ||||
|         ; NOTE: Slow if we use complicated definitions | ||||
|         ;; ; A block is on the table if it isn't on top of any other block | ||||
|         ;; (forall [x] (iff (on-table x) (forall [y] (not (on x y))))) | ||||
|         ;; ; A block is cleared if there is no other block on top of it | ||||
|         ;; (forall [x] (iff (clear x) (forall [y] (not (on y x))))) | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
|     :actions [ | ||||
| 
 | ||||
|         (define-action move-bstack-to-t [?b ?b1] { | ||||
|             :preconditions [  | ||||
|                 ; Type restriction | ||||
|                 (block ?b) | ||||
|                 (block ?b1) | ||||
|                 ; Arguments unique | ||||
|                 (not (= ?b ?b1)) | ||||
| 
 | ||||
|                 ; Preconditions | ||||
|                 ;; (not (on-table ?b)) | ||||
| 
 | ||||
|             ] | ||||
|             ; TODO: Think hard about the effect | ||||
|             ;;   :effect (and (when (on ?b ?bl)  | ||||
|             ;;         (and (not (on ?b ?bl)) (on-table ?b) (clear ?bl))))) | ||||
|             :additions [ | ||||
|                 ; The following creates a contradiction because | ||||
|                 ; (on-table ?b) -> (not (on ?b ?b1)) and | ||||
|                 ; we can't have P -> \neg P | ||||
|                 ;; (if (on ?b ?b1) (and (on-table ?b) (clear ?b1)))  | ||||
| 
 | ||||
|             ] | ||||
|             :deletions [ ] | ||||
|         }) | ||||
| 
 | ||||
|         (define-action move-t-to-b [?bm ?bt ?t] { | ||||
|             :preconditions [ | ||||
|                 ; Type restrictions | ||||
|                 (block ?bm) | ||||
|                 (block ?bt) | ||||
|                 ; Arguments unique | ||||
|                 (not (= ?bm ?bt)) | ||||
|                 ; Primary preconditions | ||||
|                 (clear ?bm ?t) | ||||
|                 (clear ?bt ?t) | ||||
|                 (on-table ?bm ?t) | ||||
|             ] | ||||
|             :additions [ | ||||
|                 (on ?bm ?bt (s ?t)) | ||||
| 
 | ||||
|                 (not (clear ?bt (s ?t))) | ||||
|                 (not (on-table ?bm (s ?t))) | ||||
|             ] | ||||
|             :deletions [ | ||||
|                 ;; (not (on ?bm ?bt)) | ||||
|                  | ||||
|                 ;; (clear ?bt) | ||||
|                 ;; (on-table ?bm) | ||||
|             ] | ||||
|         }) | ||||
|     ] | ||||
|     :start [ | ||||
|         ; Unknown facts don't need to be stated  | ||||
|         ; since we don't assume closed world assumption. | ||||
| 
 | ||||
|         ; Negated predicates in this example is handled by | ||||
|         ; the block world axioms | ||||
| 
 | ||||
|         (or | ||||
|             (and  | ||||
|                 (on b2 b1 t0) | ||||
|                 (clear b2 t0) | ||||
|                 (on-table b1 t0) | ||||
|             ) | ||||
| 
 | ||||
|             (and | ||||
|                 (on b1 b2 t0) | ||||
|                 (clear b1 t0) | ||||
|                 (on-table b2 t0) | ||||
|             ) | ||||
|         ) | ||||
|     ] | ||||
|     :goal [ | ||||
|         (exists [x] (on b2 b1 x)) | ||||
|     ] | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,81 @@ | |||
| ; Original problem from Joerg Hoffmann and Ronen Brafman | ||||
| {:name "Block-Conformant-Tiny" | ||||
|     :background [ | ||||
|         ; Setting object types | ||||
|         (Believes! a t0 (block b1)) | ||||
|         (Believes! a t0 (block b2)) | ||||
| 
 | ||||
|         ; Unique name axioms | ||||
|         (Believes! a t0 (not (= b1 b2))) | ||||
| 
 | ||||
|         ; Block World Axioms | ||||
| 
 | ||||
|         ; Blocks are never on themselves | ||||
|         (Believes! a t0 (forall [x] (not (on x x)))) | ||||
|         ; on is not symmetric | ||||
|         (Believes! a t0 (forall [x y] (if (on x y) (not (on y x))))) | ||||
|         ; Any block on a table isn't on top of another block | ||||
|         (Believes! a t0 (forall [x y] (if (on-table x) (not (on x y))))) | ||||
|         ; Any block that is cleared does not have another block on top of it | ||||
|         (Believes! a t0 (forall [x y] (if (clear x) (not (on y x))))) | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
|     :actions [ | ||||
| 
 | ||||
|         (define-action move-t-to-b [?bm ?bt] { | ||||
|             :preconditions [ | ||||
|                 (Believes! a ?now (and | ||||
|                     ; Type Restrictions | ||||
|                     (block ?bm) | ||||
|                     (block ?bt) | ||||
|                     ; Arguments Unique | ||||
|                     (not (= ?bm ?bt)) | ||||
|                     ; Primary preconditions | ||||
|                     (clear ?bm) | ||||
|                     (clear ?bt) | ||||
|                     (on-table ?bm) | ||||
|                 )) | ||||
|                 ; NOTE: QA Algorithm is very barebones, | ||||
|                 ; currently does not support beliefs under | ||||
|                 ; binary operations. Example: | ||||
|                 ;; (and | ||||
|                 ;;     (Believes! a t0 (block ?bm)) | ||||
|                 ;;     (Believes! a t0 (block ?bt)) | ||||
|                 ;; ) | ||||
|             ] | ||||
|             :additions [ | ||||
|                 ; ShadowProver uses string comparisons to determine  | ||||
|                 ; ordering on time points. | ||||
|                 ; Spectra currently hacks around this by replacing | ||||
|                 ; ?next where the constant | ||||
|                 ; that represents ?now + 1. | ||||
|                 ; ShadowProver Limitation: Cannot go beyond 10 time points | ||||
|                 (Believes! a ?next (on ?bm ?bt)) | ||||
| 
 | ||||
|                 ; These below shouldn't be needed but left for posterity | ||||
|                 ;; (Believes! a ?next (not (clear ?bt))) | ||||
|                 ;; (Believes! a ?next (not (on-table ?bm))) | ||||
|             ] | ||||
|             :deletions [ ] | ||||
|         }) | ||||
|     ] | ||||
|     :start [ | ||||
|         ; Unknown facts don't need to be stated  | ||||
|         ; since we don't assume closed world assumption. | ||||
| 
 | ||||
|         ; Negated predicates in this example is handled by | ||||
|         ; the block world axioms | ||||
| 
 | ||||
|         (Believes! a t0 (on-table b2)) | ||||
|         (Believes! a t0 (on-table b1)) | ||||
|         (Believes! a t0 (clear b1)) | ||||
|         (Believes! a t0 (clear b2)) | ||||
|     ] | ||||
|     :goal [ | ||||
|         ;; (Believes! a t0 (clear ?bm)) | ||||
|         ; Try a there exists at some point | ||||
|         (exists [t] (Believes! a t (on b1 b2))) | ||||
|     ] | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue