mirror of
https://github.com/RAIRLab/Spectra.git
synced 2024-11-21 16:36:29 -05: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…
Reference in a new issue