diff --git a/src/main/java/com/naveensundarg/planner/BreadthFirstPlanner.java b/src/main/java/com/naveensundarg/planner/BreadthFirstPlanner.java index 24007c7..27efbbd 100644 --- a/src/main/java/com/naveensundarg/planner/BreadthFirstPlanner.java +++ b/src/main/java/com/naveensundarg/planner/BreadthFirstPlanner.java @@ -1,119 +1,120 @@ package com.naveensundarg.planner; -import com.naveensundarg.planner.utils.PlanningProblem; import com.naveensundarg.shadow.prover.representations.formula.Formula; -import com.naveensundarg.shadow.prover.utils.Pair; -import com.naveensundarg.shadow.prover.utils.Sets; import java.util.*; import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Triple; - - +import org.apache.commons.lang3.tuple.Pair; /** - * Created by naveensundarg on 1/13/17. + * Created by brandonrozek on 03/29/2023. */ -public class BreadthFirstPlanner implements Planner { +public class BreadthFirstPlanner { - private static int MAX_DEPTH = 7; + // The longest plan to search for, -1 means no bound + private int MAX_DEPTH = -1; + // Number of plans to look for, -1 means up to max_depth + private int K = -1; public BreadthFirstPlanner(){ } - public static int getMaxDepth() { - return MAX_DEPTH; - } - - public static void setMaxDepth(int maxDepth) { - MAX_DEPTH = maxDepth; - } - - @Override - public Optional> plan(Set background, Set actions, State start, State goal) { - + public Set plan(Set background, Set actions, State start, State goal) { // Search Space Data Structures Set history = new HashSet(); - Queue, List, Integer>> search = new ArrayDeque,List,Integer>>(); + // Each node in the search space consists of + // (state, sequence of actions from initial) + Queue, List>> search = new ArrayDeque,List>>(); // Submit Initial State - search.add(Triple.of(List.of(start), new ArrayList(), 0)); + search.add(Pair.of(List.of(start), new ArrayList())); + + // Current set of plans + Set plansFound = new HashSet(); // Breadth First Traversal until - // - Goal Reached // - No more actions can be applied // - Max depth reached - while (!search.isEmpty()) { - - Triple, List, Integer> currentSearch = search.remove(); - - // Return if we're past the depth limit - int currentDepth = currentSearch.getRight(); - if (currentDepth >= MAX_DEPTH) { - return Optional.empty(); - } + // - Found K plans + while (!search.isEmpty() && !(K > 0 && plansFound.size() >= K)) { + Pair, List> currentSearch = search.remove(); List previous_states = currentSearch.getLeft(); - List previous_actions = currentSearch.getMiddle(); - + List previous_actions = currentSearch.getRight(); State lastState = previous_states.get(previous_states.size() - 1); + // Exit loop if we've passed the depth limit + int currentDepth = previous_actions.size(); + if (MAX_DEPTH > 0 && currentDepth > MAX_DEPTH) { + break; + } + // If we're at the goal return if (Operations.satisfies(background, lastState, goal)) { - return Optional.of(Sets.with( - new Plan(previous_actions, previous_states, background) - )); + plansFound.add(new Plan(previous_actions, previous_states, background)); + continue; } - // Try to apply each action to get to the next state - for (Action action : actions.stream().filter(Action::isNonTrivial).collect(Collectors.toSet())) { - Optional>> nextStateActionPairs = Operations.apply(background, action, lastState); + // Only consider non-trivial actions + Set nonTrivialActions = actions.stream() + .filter(Action::isNonTrivial) + .collect(Collectors.toSet()); - if (nextStateActionPairs.isPresent()) { + // Apply the action to the state and add to the search space + for (Action action : nonTrivialActions) { + Optional>> optNextStateActionPairs = Operations.apply(background, action, lastState); - // Actions aren't grounded, so each nextState represents a different - // paramter binding - for (Pair stateActionPair : nextStateActionPairs.get()) { - State nextState = stateActionPair.first(); - Action nextAction = stateActionPair.second(); + // Ignore actions that aren't applicable + if (optNextStateActionPairs.isEmpty()) { + continue; + } - // Prune already visited states - if (history.contains(nextState)) { - continue; - } + // Action's aren't grounded so each nextState represents + // a different parameter binding + Set> nextStateActionPairs = optNextStateActionPairs.get(); + for (Pair stateActionPair: nextStateActionPairs) { + State nextState = stateActionPair.getLeft(); + Action nextAction = stateActionPair.getRight(); - List next_states = new ArrayList(previous_states); - next_states.add(nextState); - - List next_actions = new ArrayList(previous_actions); - next_actions.add(nextAction); - - // Add new state to history and search space - search.add(Triple.of(next_states, next_actions, currentDepth + 1)); - history.add(nextState); + // Prune already visited states + if (history.contains(nextState)) { + continue; } + + // Add to history + history.add(nextState); + + // Construct search space parameters + List next_states = new ArrayList(previous_states); + next_states.add(nextState); + + List next_actions = new ArrayList(previous_actions); + next_actions.add(nextAction); + + // Add to search space + search.add(Pair.of(next_states, next_actions)); } } - } - return Optional.empty(); + return plansFound; } - @Override - public Optional> plan(PlanningProblem problem, Set background, Set actions, State start, State goal) { - return Optional.empty(); + public int getMaxDepth() { + return MAX_DEPTH; } - - public Optional> plan(PlanningProblem problem, Set background, Set actions, State start, State goal, List planMethods){ - return Optional.empty(); + public void setMaxDepth(int maxDepth) { + MAX_DEPTH = maxDepth; } + public void setK(int k) { + K = k; + } - public Optional verify(Set background, State start, State goal, PlanSketch planSketch){ - return Optional.empty(); + public int getK() { + return K; } } \ No newline at end of file diff --git a/src/main/java/com/naveensundarg/planner/DepthFirstPlanner.java b/src/main/java/com/naveensundarg/planner/DepthFirstPlanner.java index 18bb4b4..0b7df78 100644 --- a/src/main/java/com/naveensundarg/planner/DepthFirstPlanner.java +++ b/src/main/java/com/naveensundarg/planner/DepthFirstPlanner.java @@ -6,9 +6,11 @@ import com.naveensundarg.planner.utils.Visualizer; import com.naveensundarg.shadow.prover.core.proof.Justification; import com.naveensundarg.shadow.prover.representations.formula.Formula; import com.naveensundarg.shadow.prover.utils.CollectionUtils; -import com.naveensundarg.shadow.prover.utils.Pair; import com.naveensundarg.shadow.prover.utils.Sets; +import org.apache.commons.lang3.tuple.Pair; + + import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -250,7 +252,7 @@ public class DepthFirstPlanner implements Planner { for (Pair stateActionPair : nextStateActionPairs.get()) { Visualizer.push(); - Optional> planOpt = planInternal(history, currentDepth + 1, maxDepth, background, actions, stateActionPair.first(), goal); + Optional> planOpt = planInternal(history, currentDepth + 1, maxDepth, background, actions, stateActionPair.getLeft(), goal); Visualizer.pop(); @@ -259,8 +261,8 @@ public class DepthFirstPlanner implements Planner { atleastOnePlanFound = true; Set nextPlans = planOpt.get(); - State nextSate = stateActionPair.first(); - Action instantiatedAction = stateActionPair.second(); + State nextSate = stateActionPair.getLeft(); + Action instantiatedAction = stateActionPair.getRight(); Set augmentedPlans = nextPlans.stream(). map(plan -> plan.getPlanByStartingWith(instantiatedAction, nextSate)). diff --git a/src/main/java/com/naveensundarg/planner/Operations.java b/src/main/java/com/naveensundarg/planner/Operations.java index 06d03db..0cb254f 100644 --- a/src/main/java/com/naveensundarg/planner/Operations.java +++ b/src/main/java/com/naveensundarg/planner/Operations.java @@ -10,10 +10,10 @@ import com.naveensundarg.shadow.prover.representations.formula.Predicate; 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; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Triple; import java.util.List; @@ -52,7 +52,7 @@ public class Operations { public static synchronized Optional proveCached(Set assumptions, Formula goal) { - Pair, Formula> inputPair = ImmutablePair.from(assumptions, goal); + Pair, Formula> inputPair = ImmutablePair.of(assumptions, goal); if (proverCache.containsKey(inputPair)) { @@ -62,8 +62,8 @@ public class Operations { Optional, Formula>, Optional>> cachedOptionalSuccessful = proverCache.entrySet().stream().filter(pairOptionalEntry -> { - Set cachedAssumptions = pairOptionalEntry.getKey().first(); - Formula cachedGoal = pairOptionalEntry.getKey().second(); + Set cachedAssumptions = pairOptionalEntry.getKey().getLeft(); + Formula cachedGoal = pairOptionalEntry.getKey().getRight(); return cachedGoal.equals(goal) && Sets.subset(cachedAssumptions, assumptions); }).findAny(); @@ -77,8 +77,8 @@ public class Operations { Optional, Formula>, Optional>> cachedOptionalFailed = proverCache.entrySet().stream().filter(pairOptionalEntry -> { - Set cachedAssumptions = pairOptionalEntry.getKey().first(); - Formula cachedGoal = pairOptionalEntry.getKey().second(); + Set cachedAssumptions = pairOptionalEntry.getKey().getLeft(); + Formula cachedGoal = pairOptionalEntry.getKey().getRight(); return cachedGoal.equals(goal) && Sets.subset(assumptions, cachedAssumptions); }).findAny(); @@ -249,7 +249,7 @@ public class Operations { newState = State.initializeWith(newFormulae); - nexts.add(ImmutablePair.from(newState, action.instantiate(binding))); + nexts.add(ImmutablePair.of(newState, action.instantiate(binding))); } @@ -273,12 +273,12 @@ public class Operations { newState = State.initializeWith(newFormulae); - nexts.add(ImmutablePair.from(newState, action.instantiate(emptyBinding))); + nexts.add(ImmutablePair.of(newState, action.instantiate(emptyBinding))); } - nexts = nexts.stream().filter(n-> !n.first().getFormulae().equals(state.getFormulae())).collect(Collectors.toSet());; + nexts = nexts.stream().filter(n-> !n.getLeft().getFormulae().equals(state.getFormulae())).collect(Collectors.toSet());; diff --git a/src/main/java/com/naveensundarg/planner/utils/Runner.java b/src/main/java/com/naveensundarg/planner/utils/Runner.java index 4b31bfd..d9ac3d2 100644 --- a/src/main/java/com/naveensundarg/planner/utils/Runner.java +++ b/src/main/java/com/naveensundarg/planner/utils/Runner.java @@ -44,17 +44,17 @@ public final class Runner { return; } - Planner breadthFirstPlanner = new BreadthFirstPlanner(); + BreadthFirstPlanner breadthFirstPlanner = new BreadthFirstPlanner(); for (PlanningProblem planningProblem : planningProblemList) { - Optional> optionalPlans = breadthFirstPlanner.plan( + Set plans = breadthFirstPlanner.plan( planningProblem.getBackground(), planningProblem.getActions(), planningProblem.getStart(), planningProblem.getGoal()); - if(optionalPlans.isPresent()) { - System.out.println(optionalPlans.get().toString()); + if(plans.size() > 0) { + System.out.println(plans.toString()); } else { System.out.println("FAILED");