Example #1
0
        /// <summary>
        /// Process and check the complex goal for loop detection
        /// </summary>
        /// <param name="currentGoal">The complex goal to be checked and processed</param>
        /// <param name="currentBeliefs">The current set of beliefs</param>
        /// <param name="previousStates">The list of previous states</param>
        /// <param name="itemsToProcess">The stack of items to process</param>
        /// <returns>True if the complex goal does not contain loops and is processed, false otherwise</returns>
        private static bool DecomposeAndCheckComplexGoal(ComplexGoal currentGoal, List <Fact> currentBeliefs, List <State> previousStates, Stack <IStackItem> itemsToProcess)
        {
            //only if the complex goal is not fulfilled, do we need to process and check it
            if (!currentGoal.IsFulFilled(currentBeliefs))
            {
                //if a loop is detected, we end execution, else we add this state to the list of states
                if (CheckForLoop(currentBeliefs, currentGoal, previousStates))
                {
                    return(false);
                }
                else
                {
                    previousStates.Add(new State {
                        CurrentComplexGoal = currentGoal, CurrentBeliefs = currentBeliefs
                    });
                }

                //we repush the complex goal in the items to process so it can be checked again after all subgoals have been fulfilled
                //this is done to avoid that the solution to a subgoal 'destroys' another fulfilled subgoal
                itemsToProcess.Push(currentGoal);
                //all subgoals are pushed on the stack
                foreach (var simpleGoal in currentGoal.Goals)
                {
                    itemsToProcess.Push(simpleGoal);
                }
            }
            return(true);
        }
Example #2
0
        /// <summary>
        /// Check for a loop in the execution of our planner so that we do not introduce infinite loops.
        /// We test this by testing if we encountered the same current beliefs and the same complex goal somewhere before.
        /// If so, this indicated that we're stuck in a loop and we need to exit the current choice of actions to find a proper path
        /// of steps/actions that lead to the fulfillment of all given goals.
        /// </summary>
        /// <param name="currentBeliefs">The set of facts we current believe to be true</param>
        /// <param name="goal">The complex goal currently being processed</param>
        /// <param name="states">The list of previous states we encountered</param>
        /// <returns>True if a state can be found that contains the same given goal and where the set of beliefs of that state
        /// completely matches the current set of beliefs.</returns>
        private static bool CheckForLoop(List <Fact> currentBeliefs, ComplexGoal goal, List <State> states)
        {
            foreach (var state in states)
            {
                if (goal.IsSame(state.CurrentComplexGoal) && state.CurrentBeliefs.Count() == currentBeliefs.Count() &&
                    state.CurrentBeliefs.All(x => currentBeliefs.Any(y => y.IsSameAs(x))))
                {
                    return(true);
                }
            }

            return(false);
        }
Example #3
0
        /// <summary>
        /// Check to see if a complex goal is the same as another
        /// </summary>
        /// <param name="goal">The other complex goal to test for equality</param>
        /// <returns>True if they have the same amount of subgoals and if every subgoal
        /// in its ordered list is the same goal in the ordered list of the other complex goal</returns>
        internal bool IsSame(ComplexGoal goal)
        {
            //not same amount of goals so can't be equal
            if (goal.Goals.Count() != Goals.Count())
            {
                return(false);
            }

            //test if all subgoals (ordered) match (return false if one set does not match)
            for (var i = 0; i < goal.Goals.Count(); i++)
            {
                if (!goal.Goals[i].Fact.IsSameAs(Goals[i].Fact))
                {
                    return(false);
                }
            }

            return(true);
        }
Example #4
0
        /// <summary>
        /// Fulfill a simple goal when needed. This is done by finding an action that has a more general version of the goal in its add list.
        /// If we find an action, we instantiate it and add it along with its preconditions to the stack (preconditions first).
        /// Some loopdetection is performed to see if we haven't already added a precondition of the action as this indicates a loop.
        /// Multiple actions are possible so if choosing one action ends in an unplannable situation (due to a loop or no choice of actions further down the line)
        /// we simply backtrack to the previous choice of actions and choose another. When looking for an optimal path, this backtracking is done for every choice so
        /// we can guarantee that we make the most optimal choice at any point of the execution.
        /// </summary>
        /// <param name="simpleGoal">The goal we wish to see fulfilled by choosing an action</param>
        /// <param name="plan">The current plan</param>
        /// <param name="optimal">A flag indicating if we're looking for the optimal plan or not</param>
        /// <param name="itemsToProcess">The stack of items to process containing goals and actions</param>
        /// <param name="previousStates">A list of previous states to be used in loop detection</param>
        /// <param name="currentBeliefs">The current set of beliefs</param>
        /// <param name="preconditions">A list of preconditions used in loop detection</param>
        /// <param name="actions">A list of executable actions of the agent</param>
        /// <returns>True if we find a plan that fulfills the goal and all remaining items in the stack, false otherwise</returns>
        private static bool FulFillSimpleGoal <TAction>(SimpleGoal simpleGoal, Plan <TAction> plan, bool optimal, Stack <IStackItem> itemsToProcess,
                                                        List <State> previousStates, List <Fact> currentBeliefs, List <Fact> preconditions, List <Action> actions) where TAction : Action
        {
            //only look for an action when the goal hasn't been achieved yet
            if (!simpleGoal.IsFulFilled(currentBeliefs))
            {
                //add the fact of the goal in the list of visited preconditions
                preconditions.Add(simpleGoal.Fact);
                //look for possible actions to execute
                var possibleActions = actions.Where(x => x.IsApplicableFor(simpleGoal, currentBeliefs));
                var iter            = possibleActions.GetEnumerator();

                //keep a list of plans and beliefsets for each action that is possible (for optimization later)
                var subPlansForAction = new List <Tuple <Plan <TAction>, List <Fact> > >();
                while (iter.MoveNext())
                {
                    var action = iter.Current;
                    //instantiate the action as much as possible
                    action = action.InstantiateFor(simpleGoal, currentBeliefs);

                    //perform loopdetection
                    var lstPre = action.Preconditions.ToList();
                    lstPre.Reverse();
                    var faulty = lstPre.Any(x => IsAlreadyACondition(x, preconditions));
                    if (!faulty)
                    {
                        //create the complex goal with the preconditions of the action
                        var complex = new ComplexGoal();
                        foreach (var precondition in lstPre)
                        {
                            complex.Goals.Add(new SimpleGoal(precondition, action));
                        }

                        //create a new stack but with action and complex goal added
                        var newStack = new Stack <IStackItem>(itemsToProcess.Reverse());
                        newStack.Push(action);
                        newStack.Push(complex);

                        //perform create plan for the new stack
                        (Plan <TAction> subPlanForAction, List <Fact> lstBeliefs) = CreatePlan <TAction>(newStack, currentBeliefs.ToList(), preconditions.ToList(),
                                                                                                         previousStates.ToList(), actions, optimal);

                        //the chosen action gives a valid plan so add the plan (and beliefset) to the possible plans we can choose from
                        if (subPlanForAction != null)
                        {
                            subPlansForAction.Add(Tuple.Create(subPlanForAction, lstBeliefs));
                            if (optimal)
                            {
                                break;
                            }
                        }
                    }
                }
                //no plan found for this goal and current beliefset so return null
                if (!subPlansForAction.Any())
                {
                    return(false);
                }
                else
                {
                    //we look for the minimal path (minimal number of steps) asuming that each step has an equal 'cost'
                    var minSteps = subPlansForAction.Min(x => x.Item1.Steps.Count());
                    var best     = subPlansForAction.First(x => x.Item1.Steps.Count() == minSteps);
                    //add the steps of the optimal subplan to this plan and update the current set of beliefs
                    plan.Steps.AddRange(best.Item1.Steps);
                    currentBeliefs = best.Item2;
                    //clear the stack as we already processed all items in the stack when looking for all subplans
                    itemsToProcess.Clear();
                }
            }
            return(true);
        }