/// <summary> /// Checks whether the operator effects are relevant to the given target relative state. /// </summary> /// <param name="relativeState">Relative state for the application.</param> /// <param name="operatorPreconditions">Operator preconditions.</param> /// <returns>True if the operator effects are relevant to the given relative state, false otherwise.</returns> public bool IsRelevant(IRelativeState relativeState, ISimpleConditions operatorPreconditions) { CashedVariablesCollector.Clear(); bool anyRelevant = false; foreach (var effect in this) { var relevance = effect.IsRelevant(relativeState); switch (relevance) { case EffectRelevance.ANTI_RELEVANT: { return(false); } case EffectRelevance.RELEVANT: { anyRelevant = true; CashedVariablesCollector.Add(effect.GetAssignment().GetVariable()); break; } case EffectRelevance.IRRELEVANT: { if (effect.GetConditions() != null) { CashedVariablesCollector.Add(effect.GetAssignment().GetVariable()); } break; } } } if (!anyRelevant) { return(false); } // additionally, the relative state has to be checked against operator preconditions ("hidden effects") foreach (var constraint in operatorPreconditions) { int variable = constraint.GetVariable(); if (!CashedVariablesCollector.Contains(variable)) { int value = relativeState.GetValue(variable); if (value == RelativeState.WildCardValue) { continue; } if (value != constraint.GetValue()) { return(false); } } } return(true); }
/// <summary> /// Checks whether the operator effects are relevant to the given target conditions. /// </summary> /// <param name="conditions">Conditions for the application.</param> /// <param name="operatorPreconditions">Operator preconditions.</param> /// <returns>True if the operator effects are relevant to the given conditions, false otherwise.</returns> public bool IsRelevant(IConditions conditions, ISimpleConditions operatorPreconditions) { // Besides the effects relevance, we need to check whether the operator preconditions are not in conflict with the resulting // conditions (after backward-apply). This can be done via affected variables: if some effect is relevant, then it modifies a // variable, and a constraint corresponding to this variable can be removed from the preconditions. At the end, we check the // modified precondition constraints with the target conditions and if there are conflicts, we consider the operator not // relevant. This approach works even for conditional-effects, because we take the worst case scenario. IConditions nonAffectedPreconditions = (IConditions)operatorPreconditions.Clone(); bool anyRelevant = false; foreach (var effect in this) { var relevance = effect.IsRelevant(conditions); if (relevance == EffectRelevance.ANTI_RELEVANT) { return(false); } else if (relevance == EffectRelevance.RELEVANT) { anyRelevant = true; nonAffectedPreconditions.RemoveConstraint(effect.GetAssignment()); } } return(anyRelevant && !nonAffectedPreconditions.IsConflictedWith(conditions)); }
/// <summary> /// Applies the operator backwards to the given target conditions. The result is a new set of conditions. /// </summary> /// <param name="conditions">Conditions for the application.</param> /// <param name="operatorPreconditions">Operator preconditions.</param> /// <returns>Preceding conditions.</returns> public IConditions ApplyBackwards(IConditions conditions, ISimpleConditions operatorPreconditions) { IConditions newConditions = (IConditions)conditions.Clone(); foreach (var effect in this) { newConditions = effect.ApplyBackwards(newConditions); } newConditions = newConditions.ConjunctionWith(operatorPreconditions); return(newConditions); }
/// <summary> /// Generates all possible SAS+ states meeting conditions specified by the given conditions. Lazy generated via yield return. /// </summary> /// <param name="conditions">Reference conditions.</param> /// <param name="variables">Variables of the planning problem.</param> /// <returns>All possible SAS+ states meeting the conditions.</returns> public static IEnumerable <IState> EnumerateStates(ISimpleConditions conditions, Variables variables) { Func <int, int> checker = (variable) => { int value; if (conditions.IsVariableConstrained(variable, out value)) { return(value); } return(-1); }; return(EnumerateStates(0, new State(new int[variables.Count]), checker, variables)); }
/// <summary> /// Gets the corresponding SAS+ relative state meeting specified conditions. Lazy generated via yield return. /// </summary> /// <param name="conditions">Reference conditions.</param> /// <param name="variables">Variables of the planning problem.</param> /// <returns>Corresponding SAS+ relative state meeting the conditions.</returns> private static IRelativeState GetCorrespondingRelativeState(ISimpleConditions conditions, Variables variables) { int[] initWildCards = new int[variables.Count]; for (int i = 0; i < variables.Count; ++i) { initWildCards[i] = -1; } IRelativeState newRelativeState = new RelativeState(initWildCards); foreach (var constraint in conditions) { newRelativeState.SetValue(constraint); } return(newRelativeState); }
/// <summary> /// Computes the distances to the goals for the specified pattern. /// </summary> /// <param name="pattern">Pattern (i.e. variables of the pattern) to process.</param> private PatternValuesDistances ComputePatternDistances(int[] pattern) { IHeap <double, ISimpleConditions> fringe = new LeftistHeap <ISimpleConditions>(); InsertPatternConditions(fringe, (Conditions)Problem.GoalConditions, 0, pattern); PatternValuesDistances patternValuesDistances = new PatternValuesDistances(); while (fringe.GetSize() > 0) { double distance = fringe.GetMinKey(); ISimpleConditions conditions = fringe.RemoveMin(); int[] patternValues = conditions.GetAssignedValues(); Debug.Assert(pattern.Length == conditions.GetSize()); Debug.Assert(pattern.Length == patternValues.Length); if (patternValuesDistances.ContainsKey(patternValues)) { // already processed with a lower cost continue; } patternValuesDistances.Add(patternValues, distance); foreach (var predecessor in Problem.GetPredecessors(conditions)) { IConditions predecessorConditions = (IConditions)predecessor.GetPredecessorConditions(); IOperator predecessorOperator = (IOperator)predecessor.GetAppliedOperator(); foreach (var predecessorSimpleConditions in predecessorConditions.GetSimpleConditions()) { double cost = distance + predecessorOperator.GetCost(); InsertPatternConditions(fringe, predecessorSimpleConditions, cost, pattern); } } } return(patternValuesDistances); }
/// <summary> /// Inserts all goal conditions of the corresponding pattern to fringe. I.e. fixes the goal values and generates all combinations /// for the rest of variables by the method divide-and-conquer. /// </summary> /// <param name="fringe">Fringe.</param> /// <param name="goalConditions">Goal conditions.</param> /// <param name="cost">Current cost.</param> /// <param name="pattern">Requested pattern.</param> /// <param name="currentVariableIndex">Current variable index.</param> /// <param name="values">Generated values.</param> private void InsertPatternConditions(IHeap <double, ISimpleConditions> fringe, ISimpleConditions goalConditions, double cost, int[] pattern, int currentVariableIndex, List <int> values) { if (values.Count == pattern.Length) { Conditions conditions = new Conditions(); int i = 0; foreach (var item in pattern) { conditions.Add(new Assignment(item, values[i])); i++; } fringe.Add(cost, conditions); return; } int currentVariable = pattern[currentVariableIndex]; int constrainedGoalValue; if (goalConditions.IsVariableConstrained(currentVariable, out constrainedGoalValue)) { values.Add(constrainedGoalValue); InsertPatternConditions(fringe, goalConditions, cost, pattern, currentVariableIndex + 1, values); values.RemoveAt(values.Count - 1); } else { for (int i = 0; i < Problem.Variables[currentVariable].GetDomainRange(); ++i) { values.Add(i); InsertPatternConditions(fringe, goalConditions, cost, pattern, currentVariableIndex + 1, values); values.RemoveAt(values.Count - 1); } } }
/// <summary> /// Inserts all conditions of the specified pattern satisfying the given goals to fringe (with the given cost). /// </summary> /// <param name="fringe">Fringe.</param> /// <param name="goalConditions">Current goal conditions.</param> /// <param name="cost">New conditions cost.</param> /// <param name="pattern">Requested pattern.</param> private void InsertPatternConditions(IHeap <double, ISimpleConditions> fringe, ISimpleConditions goalConditions, double cost, int[] pattern) { InsertPatternConditions(fringe, goalConditions, cost, pattern, 0, new List <int>()); }
/// <summary> /// Constructs the SAS+ operator conditional effect. /// </summary> /// <param name="conditions">Conditions.</param> /// <param name="assignment">Effect assignment.</param> public ConditionalEffect(ISimpleConditions conditions, IAssignment assignment) : base(assignment) { Conditions = conditions; }
/// <summary> /// Constructs the SAS+ operator conditional effect from the input data. /// </summary> /// <param name="inputData">Input data.</param> public ConditionalEffect(InputData.SAS.Effect inputData) : base(inputData) { Conditions = new Conditions(inputData.Conditions); }
/// <summary> /// Visits the leaf node of the SAS+ operator decision tree. /// </summary> /// <param name="treeNode">Leaf node of the tree.</param> /// <param name="sourceConditions">Source conditions being evaluated.</param> /// <param name="currentSubConditions">Currently evaluated sub-conditions.</param> /// <returns>List of predecessors.</returns> public IEnumerable <IPredecessor> Visit(OperatorDecisionTreeLeafNode treeNode, IConditions sourceConditions, ISimpleConditions currentSubConditions) { foreach (var oper in treeNode.Operators) { // relevant operator candidates need to be double-checked for the relevance with the original conditions, because there can be additional // conflicts with the operator preconditions, conditional effects constraints, and/or incompatibility with the mutex constraints if (oper.IsRelevant(sourceConditions)) { yield return(new Predecessor(sourceConditions, oper)); } } }
/// <summary> /// Visits the inner node of the SAS+ operator decision tree. /// </summary> /// <param name="treeNode">Inner node of the tree.</param> /// <param name="sourceConditions">Source conditions being evaluated.</param> /// <param name="currentSubConditions">Currently evaluated sub-conditions.</param> /// <returns>List of predecessors.</returns> public IEnumerable <IPredecessor> Visit(OperatorDecisionTreeInnerNode treeNode, IConditions sourceConditions, ISimpleConditions currentSubConditions) { int value; if (currentSubConditions.IsVariableConstrained(treeNode.DecisionVariable, out value)) { // if constrained, collect the operators only in the corresponding subtree foreach (var predecessor in treeNode.OperatorsByDecisionVariableValue[value].Accept(this, sourceConditions, currentSubConditions)) { yield return(predecessor); } } else { // if not constrained, collect operators from all the subtrees foreach (var subTree in treeNode.OperatorsByDecisionVariableValue) { foreach (var predecessor in subTree.Accept(this, sourceConditions, currentSubConditions)) { yield return(predecessor); } } } // always search in the subtree with the value-independent operators foreach (var successor in treeNode.OperatorsIndependentOnDecisionVariable.Accept(this, sourceConditions, currentSubConditions)) { yield return(successor); } }
/// <summary> /// Accepts relevance evaluation visitor. /// </summary> /// <param name="visitor">Evaluating visitor.</param> /// <param name="sourceConditions">Source conditions being evaluated.</param> /// <param name="currentSubConditions">Currently evaluated sub-conditions.</param> /// <returns>List of predecessors.</returns> public IEnumerable <IPredecessor> Accept(IOperatorDecisionTreeRelevanceVisitor visitor, IConditions sourceConditions, ISimpleConditions currentSubConditions) { return(visitor.Visit(this, sourceConditions, currentSubConditions)); }
/// <summary> /// Accepts relevance evaluation visitor. /// </summary> /// <param name="visitor">Evaluating visitor.</param> /// <param name="sourceConditions">Source conditions being evaluated.</param> /// <param name="currentSubConditions">Currently evaluated sub-conditions.</param> /// <returns>List of predecessors.</returns> public IEnumerable <IPredecessor> Accept(IOperatorDecisionTreeRelevanceVisitor visitor, IConditions sourceConditions, ISimpleConditions currentSubConditions) { yield break; }
/// <summary> /// Applies the operator backwards to the given target relative state. The result is a new relative state (or more relative states, if conditional effects are present). /// </summary> /// <param name="relativeState">Relative state for the application.</param> /// <param name="operatorPreconditions">Operator preconditions.</param> /// <returns>Preceding relative states.</returns> public IEnumerable <IRelativeState> ApplyBackwards(IRelativeState relativeState, ISimpleConditions operatorPreconditions) { IRelativeState result = (IRelativeState)relativeState.Clone(); bool anyConditionalEffect = false; foreach (var effect in this) { if (effect.GetConditions() == null) { result = effect.ApplyBackwards(result); } else { anyConditionalEffect = true; } } foreach (var constraint in operatorPreconditions) { result.SetValue(constraint.GetVariable(), constraint.GetValue()); } if (!anyConditionalEffect) { yield return(result); } else { List <IRelativeState> states = new List <IRelativeState> { result }; foreach (var effect in this) { if (effect.GetConditions() != null) { int statesCount = states.Count; for (int i = 0; i < statesCount; ++i) { var newEffect = effect.ApplyBackwards(states[i]); if (newEffect != null) { states.Add(newEffect); } } } } foreach (var state in states) { yield return(state); } } }