Exemple #1
0
        /// <summary>
        /// Check to see if the add list of the action can potentially be used to fulfill a goal
        /// </summary>
        /// <param name="goal">The goal to be fulfilled</param>
        /// <param name="currentBeliefs">The current beliefs that we have at the moment</param>
        /// <returns>Returns a fact that can be found in the add list that has the same name as the end goal/fact in the goal
        /// and where an assignment can be found that fulfills the goal and does not violate the constraints of the action.</returns>
        internal virtual Fact IsApplicableForAdd(SimpleGoal goal, List <Fact> currentBeliefs)
        {
            //only facts that have the same name as the goal are considered but also only those that are more general (or equally general) than the goal
            //this means that a substitution (or empty substitution) exists that transforms the fact of the addlist into the fact of the goal
            var possibeAdds = AddList.Where(y => y.Name.Equals(goal.Fact.Name) && y.IsMoreGeneralThanOrEqualTo(goal.Fact));

            //if no such facts can be found, quickly return null
            if (!possibeAdds.Any())
            {
                return(null);
            }

            //if there are no constraints, quickly return the first fact that can fulfill the goal
            if (!Constraints.Any())
            {
                return(possibeAdds.FirstOrDefault());
            }

            //return the first fact of the possible facts of the addlist where an assignment can be found that also
            //does not violate the constraints of the action
            foreach (var possibleGoal in possibeAdds)
            {
                var tuples = GetAssignment(possibleGoal, goal, currentBeliefs);
                if (CheckConstraints(tuples))
                {
                    return(possibleGoal);
                }
            }
            return(null);
        }
Exemple #2
0
        /// <summary>
        /// Instantiate an action so an instantiated goal is fulfilled
        /// </summary>
        /// <param name="goal">The goal to be fulfilled</param>
        /// <param name="currentBeliefs">The current set of beliefs</param>
        /// <returns>The instantiated action (based on the given action) that completely fulfills the given goal</returns>
        internal Action InstantiateFor(SimpleGoal goal, List <Fact> currentBeliefs)
        {
            var cloned = Clone();
            var fact   = cloned.IsApplicableForAdd(goal, currentBeliefs);
            var tuples = GetAssignment(fact, goal, currentBeliefs);

            cloned.FillParameters(tuples);
            return(cloned);
        }
Exemple #3
0
        /// <summary>
        /// Returns a potential assignment/substitution in the form of a list of keyvalue pair of names and values that
        /// fulfills the goal based on the given fact of the addlist
        /// </summary>
        /// <param name="possibleAdd">The fact of the addlist that can be instantiated to fulfill the goal.</param>
        /// <param name="goal">The goal we wish to see fulfilled</param>
        /// <param name="currentBeliefs">The current beliefs that we have at the moment</param>
        /// <returns>A potential assignment for the fact of the addlist to fulfill the given goal.</returns>
        public virtual Dictionary <string, object> GetAssignment(Fact possibleAdd, SimpleGoal goal, List <Fact> currentBeliefs)
        {
            var tuples = new Dictionary <string, object>();

            for (var i = 0; i < Math.Min(goal.Fact.Parameters.Count, possibleAdd.Parameters.Count); i++)
            {
                if (possibleAdd.Parameters[i] is NamedParameter namedParameter)
                {
                    tuples.Add(namedParameter.Name, (goal.Fact.Parameters[i] as ValueParameter).Value);
                }
            }

            return(tuples);
        }
Exemple #4
0
        /// <summary>
        /// Finds a substitution/assigment for a fact of a goal so that the instantiated fact exists in the current beliefset
        /// </summary>
        /// <param name="goal">The goal to be fulfilled</param>
        /// <param name="currentBeliefs">The current beliefset</param>
        /// <returns>An assignment/substitution for the fact of the goal such that the instantiated fact exists in the current beliefset</returns>
        private static Dictionary <string, object> FindGoodSubstitution(SimpleGoal goal, List <Fact> currentBeliefs)
        {
            var dict = new Dictionary <string, object>();
            //first look for candidate facts in the current beliefset that bear the same name as the fact in the goal
            var candidateFacts = currentBeliefs.Where(x => x.Name.Equals(goal.Fact.Name));
            var lstOk          = new List <Fact>();

            //keep a list of those facts in the reduced list that have the same value in their parameters as the goal has when it has
            //filled in valueparameters instead of named parameters
            foreach (var candidateFact in candidateFacts)
            {
                var ok = true;
                for (var i = 0; i < candidateFact.Parameters.Count && ok; i++)
                {
                    var canParam = candidateFact.Parameters[i] as ValueParameter;
                    if (goal.Fact.Parameters[i] is ValueParameter valParam && !((valParam.Value == null && canParam.Value == null) || (valParam.Value != null && (valParam.Value == canParam.Value || valParam.Value.Equals(canParam.Value)))))
                    {
                        ok = false;
                    }
                }

                if (ok)
                {
                    lstOk.Add(candidateFact);
                }
            }
            //get the first in this list (or null) :=> REMARK : possibly change this as this is inefficient
            var firstOk = lstOk.FirstOrDefault();

            if (firstOk == null)
            {
                return(null);
            }

            //for the found fact, calculate the values for the remaining named parameters and fill the subsitution with this information
            for (var i = 0; i < firstOk.Parameters.Count; i++)
            {
                if (goal.Fact.Parameters[i] is NamedParameter namedParam)
                {
                    dict.Add(namedParam.Name, ((ValueParameter)firstOk.Parameters[i]).Value);
                }
            }

            return(dict);
        }
Exemple #5
0
        /// <summary>
        /// Perform and check the subsitution but only when needed
        /// </summary>
        /// <param name="simpleGoal">The goal to perform substitution on</param>
        /// <param name="currentBeliefs">The current set of beliefs</param>
        /// <param name="preconditions">The current list of preconditions used when performing loop detection</param>
        /// <returns>True if no loops detected and substitution is possible when it is required, false otherwise</returns>
        private static bool PerformAndCheckSubstitionIfNeeded(SimpleGoal simpleGoal, List <Fact> currentBeliefs, List <Fact> preconditions)
        {
            if (simpleGoal.NeedsSubstitution())
            {
                var toSubstitute = FindGoodSubstitution(simpleGoal, currentBeliefs);
                //no substitution found so no plan possible for the current choice of actions
                if (toSubstitute == null)
                {
                    return(false);
                }

                simpleGoal.Action.FillParameters(toSubstitute);
                //simple loop detection
                if (IsAlreadyACondition(simpleGoal.Fact, preconditions))
                {
                    return(false);
                }
            }
            return(true);
        }
Exemple #6
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);
        }
Exemple #7
0
 /// <summary>
 /// Check to see if an action is applicable to fulfill a certain goal
 /// </summary>
 /// <param name="goal">The goal to be tested for potential fulfillment</param>
 /// <param name="currentBeliefs">The current set of beliefs</param>
 /// <returns>True if the action is applicable to fulfill the goal, false otherwise</returns>
 internal bool IsApplicableFor(SimpleGoal goal, List <Fact> currentBeliefs) => IsApplicableForAdd(goal, currentBeliefs) != null;