/// <summary> /// Processes forall effects. /// </summary> /// <param name="expression">Conditions expression in CNF.</param> /// <returns>Tuple of two values, where the first is true when the positive relevance condition (inclusion) is satisfied, while the second is /// true when the negative condition (exclusion) is not violated. False otherwise.</returns> private Tuple <bool, bool> ProcessForallEffects(ConditionsCNF expression) { bool positiveCondition = false; bool negativeCondition = true; foreach (var forallEffect in Effects.ForallEffects) { EffectsRelevanceConditionsEvaluator evaluator = new EffectsRelevanceConditionsEvaluator(forallEffect.Effects, GroundingManager); IEnumerable <ISubstitution> localSubstitutions = GroundingManager.GenerateAllLocalSubstitutions(forallEffect.Parameters); foreach (var localSubstitution in localSubstitutions) { OperatorSubstitution.AddLocalSubstitution(localSubstitution); var result = evaluator.EvaluateWithExtendedResult(expression, OperatorSubstitution, null); positiveCondition |= result.Item1; negativeCondition &= result.Item2; OperatorSubstitution.RemoveLocalSubstitution(localSubstitution); if (!negativeCondition) { return(result); } } } return(Tuple.Create(positiveCondition, true)); }
/// <summary> /// Applies backwards the relevant operator effects and operator preconditions to the given target conditions. /// </summary> /// <param name="conditions">Target conditions to be modified.</param> /// <param name="operatorSubstitution">Variables substitution.</param> /// <returns>Preceding conditions.</returns> public IConditions ApplyBackwards(IConditions conditions, ISubstitution operatorSubstitution) { ConditionsCNF expression = (ConditionsCNF)conditions?.GetCNF(); if (expression == null) { return(null); } OperatorSubstitution = operatorSubstitution; Effects.GroundEffectsByCurrentOperatorSubstitution(GroundingManager, operatorSubstitution); if (expression.Parameters != null) { EffectsRelevanceConditionsEvaluator evaluator = new EffectsRelevanceConditionsEvaluator(Effects, GroundingManager); List <ConditionsCNF> subResults = new List <ConditionsCNF>(); IEnumerable <ISubstitution> expressionSubstitutions = GroundingManager.GenerateAllLocalSubstitutions(expression.Parameters); expression.Parameters = null; foreach (var expressionSubstitution in expressionSubstitutions) { // do backward apply only when the effects are relevant to the current grounding of the expression if (evaluator.Evaluate(expression, operatorSubstitution, expressionSubstitution)) { subResults.Add(ApplyBackwardsImpl(expression, expressionSubstitution)); } } return(ConstructCNFFromDisjunction(subResults)); } return(ApplyBackwardsImpl(expression, new Substitution())); }
/// <summary> /// Processes conditional (when) effects. /// </summary> /// <param name="expression">Conditions expression in CNF.</param> /// <param name="relevantConditionalEffects">Output indices of relevant conditional effects (can be null).</param> /// <returns>Tuple of two values, where the first is true when the positive relevance condition (inclusion) is satisfied, while the second is /// true when the negative condition (exclusion) is not violated. False otherwise.</returns> private Tuple <bool, bool> ProcessWhenEffects(ConditionsCNF expression, IList <int> relevantConditionalEffects) { bool positiveCondition = false; int whenEffectIndex = -1; foreach (var whenEffect in Effects.WhenEffects) { ++whenEffectIndex; List <IEffect> subEffects = new List <IEffect>(); whenEffect.Effects.ForEach(subEffect => subEffects.Add(subEffect)); EffectsRelevanceConditionsEvaluator evaluator = new EffectsRelevanceConditionsEvaluator(subEffects, GroundingManager); var result = evaluator.EvaluateWithExtendedResult(expression, OperatorSubstitution, ExpressionSubstitution, relevantConditionalEffects); if (!result.Item2) { continue; } if (result.Item1 && result.Item2) { relevantConditionalEffects?.Add(whenEffectIndex); } positiveCondition |= result.Item1; } return(Tuple.Create(positiveCondition, true)); }
/// <summary> /// Processes conditional (when) effects. /// </summary> /// <param name="expression">Conditions expression in CNF.</param> private ConditionsCNF ProcessWhenEffects(ConditionsCNF expression) { if (Effects.WhenEffects.Count == 0) { return(expression); } // Collect the relevant when effects, first List <WhenEffect> relevantWhenEffects = GetRelevantWhenEffectsForConditions(expression); // Each of the relevant when effect is either used or not (dynamic programming approach to get all combinations of when effects usage) List <ConditionsCNF> applicationResults = new List <ConditionsCNF> { expression }; foreach (var whenEffect in relevantWhenEffects) { Conditions whenCondition = new Conditions(whenEffect.Expression, EvaluationManager); EffectsBackwardsConditionsApplier innerApplier = new EffectsBackwardsConditionsApplier(whenCondition, new List <IEffect>(whenEffect.Effects), EvaluationManager); List <ConditionsCNF> currentEffectApplications = new List <ConditionsCNF>(); foreach (var currentCondition in applicationResults) { ConditionsCNF modifiedCondition = (ConditionsCNF)innerApplier.ApplyBackwards(currentCondition, new Substitution()); currentEffectApplications.Add(modifiedCondition); } applicationResults.AddRange(currentEffectApplications); } // Now, all the possible results need to be merged into a single condition via OR and converted into a valid CNF return(ConstructCNFFromDisjunction(applicationResults)); }
/// <summary> /// Merges the specified CNF conditions into the current CNF conditions. The other CNF shouldn't be used anymore (its items are reused in the current CNF). /// </summary> /// <param name="other">Other CNF conditions.</param> public void Merge(ConditionsCNF other) { if (Parameters == null) { Parameters = new Parameters(); } if (Parameters.AreConflictedWith(other.Parameters)) { EvaluationManager.RenameConditionParameters(other, Parameters.GetMaxUsedParameterId() + 1); } if (other.Parameters != null) { Parameters.AddRange(other.Parameters); } if (Parameters.Count == 0) { Parameters = null; } foreach (var items in other) { Add(items); } }
/// <summary> /// Evaluates the label of the operator with the specified preconditions and substitution. /// </summary> /// <param name="conditions">Operator conditions.</param> /// <param name="substitution">Variable substitution.</param> /// <param name="stateLabels">Atom labels in the predecessor layer.</param> /// <param name="evaluationStrategy">Evaluation strategy.</param> /// <returns>Operator label value in the relaxed planning graph.</returns> public double Evaluate(ConditionsCNF conditions, ISubstitution substitution, StateLabels stateLabels, ForwardCostEvaluationStrategy evaluationStrategy) { Substitution = substitution; StateLabels = stateLabels; EvaluationStrategy = evaluationStrategy; return(conditions.Accept(this).Item1); }
/// <summary> /// Gets a list of atoms used in the specified conditions. /// </summary> /// <param name="conditions">Conditions to be evaluated.</param> /// <returns>Collection of used atoms.</returns> public HashSet <IAtom> Collect(IConditions conditions) { ConditionsCNF conditionsCNF = (ConditionsCNF)conditions.GetCNF(); Atoms = new HashSet <IAtom>(); conditionsCNF.Accept(this); return(Atoms); }
/// <summary> /// Gets a list of atoms from the specified state that are necessary to make these conditions true. /// </summary> /// <param name="conditions">Conditions to evaluate.</param> /// <param name="substitution">Variable substitution.</param> /// <param name="predecessorState">Preceding state.</param> /// <returns>List of satisfying atoms.</returns> public List <IAtom> Evaluate(IConditions conditions, ISubstitution substitution, IState predecessorState) { ConditionsCNF conditionsCNF = (ConditionsCNF)conditions.GetCNF(); Atoms = new List <IAtom>(); Substitution = substitution; ReferenceState = predecessorState; conditionsCNF.Accept(this); return(Atoms); }
/// <summary> /// Collects relevant when effects for the specified conditions. /// </summary> /// <param name="expression">Conditions in CNF.</param> /// <returns>List of relevant when effects.</returns> private List <WhenEffect> GetRelevantWhenEffectsForConditions(ConditionsCNF expression) { List <int> relevantWhenEffectsIndices = new List <int>(); EffectsRelevanceConditionsEvaluator relevanceEvaluator = new EffectsRelevanceConditionsEvaluator(Effects, GroundingManager); relevanceEvaluator.Evaluate(expression, new Substitution(), ExpressionSubstitution, relevantWhenEffectsIndices); // empty substitution here because effects already grounded List <WhenEffect> relevantWhenEffects = new List <WhenEffect>(); relevantWhenEffectsIndices.ForEach(index => relevantWhenEffects.Add(Effects.WhenEffects[index])); return(relevantWhenEffects); }
/// <summary> /// Visits and performs a property count on CNF conjunction. /// </summary> /// <param name="expression">CNF conjunction.</param> /// <returns>Tuple (property satisfied count, property not satisfied count).</returns> public Tuple <int, int> Visit(ConditionsCNF expression) { int fulfilled = 0; int notFulfilled = 0; foreach (var conjunct in expression) { var childPropertyCounts = conjunct.Accept(this); fulfilled += childPropertyCounts.Item1; notFulfilled += childPropertyCounts.Item2; } return(Tuple.Create(fulfilled, notFulfilled)); }
/// <summary> /// Accepts a conjunctive-normal-form expression backwards applier visitor. /// </summary> /// <param name="visitor">CNF expression visitor.</param> public IElementCNF Accept(IElementCNFBackwardsApplierVisitor visitor) { ConditionsCNF newExpression = CloneEmpty(); foreach (var conjunct in this) { var resultExpression = conjunct.Accept(visitor); if (resultExpression != null) { newExpression.Add((IConjunctCNF)resultExpression); } } return(newExpression); }
/// <summary> /// Checks the equality of objects. /// </summary> /// <param name="obj">Object to be checked.</param> /// <returns>True if the objects are equal, false otherwise.</returns> public override bool Equals(object obj) { if (obj == this) { return(true); } ConditionsCNF other = obj as ConditionsCNF; if (other == null) { return(false); } return(CollectionsEquality.Equals(this, other)); }
/// <summary> /// Renames the parameters (and the corresponding occurences in the conditions), starting from the given free parameter ID. /// </summary> /// <param name="conditions">Conditions to be edited.</param> /// <param name="firstFreeParameterId">First free parameter ID.</param> public void Rename(ConditionsCNF conditions, int firstFreeParameterId) { // firstly, build a renaming map and rename the parameters ParametersRemapping.Clear(); int currentParameterId = firstFreeParameterId; foreach (var parameter in conditions.Parameters) { ParametersRemapping.Add(parameter.ParameterNameId, currentParameterId); parameter.ParameterNameId = currentParameterId; ++currentParameterId; } // rename the conditions conditions.Accept(this); }
/// <summary> /// Evaluates the conditions with the given reference state and variable substitution. /// </summary> /// <param name="conditions">Conditions to be evaluated.</param> /// <param name="substitution">Used variables substitution.</param> /// <param name="referenceState">Reference state.</param> /// <returns>True if all conditions are met in the given state, false otherwise.</returns> public bool Evaluate(ConditionsCNF conditions, ISubstitution substitution, IState referenceState = null) { // the conditions is lifted, but no direct variable substitution provided -> try whether there is a valid grounding to satisfy the conditions if (conditions.Parameters != null && substitution == null) { IEnumerable <ISubstitution> localSubstitutions = GroundingManager.GenerateAllLocalSubstitutions(conditions.Parameters); foreach (var localSubstitution in localSubstitutions) { if (ConditionsCNFEvaluator.Value.Evaluate(conditions, localSubstitution, referenceState)) { return(true); } } return(false); } else { return(ConditionsCNFEvaluator.Value.Evaluate(conditions, substitution, referenceState)); } }
/// <summary> /// Applies backwards the relevant operator effects and operator preconditions to the given target conditions. /// </summary> /// <param name="expression">Target conditions in CNF.</param> /// <param name="expressionSubstitution">Variables substitution of the expression.</param> /// <returns>Preceding conditions.</returns> private ConditionsCNF ApplyBackwardsImpl(ConditionsCNF expression, ISubstitution expressionSubstitution) { UsedGroundedPredicates.Clear(); UsedGroundedFunctions.Clear(); ExpressionSubstitution = expressionSubstitution; // remove positively contributing effects from the target conditions ConditionsCNF resultExpression = ProcessPrimitiveEffects(expression); resultExpression = ProcessForallEffects(resultExpression); resultExpression = ProcessWhenEffects(resultExpression); // unite processed conditions with partially grounded preconditions of the operator if (OperatorPreconditions != null) { var preconditions = ClearRigidRelations(OperatorPreconditions); resultExpression.Merge((ConditionsCNF)GroundConditions(preconditions).GetCNF()); } return(resultExpression); }
/// <summary> /// Processes forall effects. /// </summary> /// <param name="expression">Conditions expression in CNF.</param> private ConditionsCNF ProcessForallEffects(ConditionsCNF expression) { if (Effects.ForallEffects.Count == 0) { return(expression); } foreach (var forallEffect in Effects.ForallEffects) { EffectsBackwardsConditionsApplier innerApplier = new EffectsBackwardsConditionsApplier(null, forallEffect.Effects, EvaluationManager); IEnumerable <ISubstitution> localSubstitutions = GroundingManager.GenerateAllLocalSubstitutions(forallEffect.Parameters); foreach (var localSubstitution in localSubstitutions) { OperatorSubstitution.AddLocalSubstitution(localSubstitution); expression = (ConditionsCNF)innerApplier.ApplyBackwards(expression, OperatorSubstitution); OperatorSubstitution.RemoveLocalSubstitution(localSubstitution); } } return(expression); }
/// <summary> /// Visits and performs a property count on CNF conjunction. /// </summary> /// <param name="expression">CNF conjunction.</param> /// <returns>Tuple (property satisfied count, property not satisfied count).</returns> public Tuple <double, double> Visit(ConditionsCNF expression) { double positiveValue = 0; double negativeValue = 0; foreach (var child in expression) { var childPropertyCounts = child.Accept(this); if (EvaluationStrategy == ForwardCostEvaluationStrategy.ADDITIVE_VALUE) { positiveValue += childPropertyCounts.Item1; negativeValue += childPropertyCounts.Item2; } else { positiveValue = Math.Max(positiveValue, childPropertyCounts.Item1); negativeValue = Math.Max(negativeValue, childPropertyCounts.Item2); } } return(Tuple.Create(positiveValue, negativeValue)); }
/// <summary> /// Evaluates whether the operator effects are relevant for the specified conditions. /// </summary> /// <param name="conditions">Conditions expression.</param> /// <param name="operatorSubstitution">Variables substitution of the operator.</param> /// <param name="expressionSubstitution">Variables substitution of the expression.</param> /// <param name="relevantConditionalEffects">Output indices of relevant conditional effects (can be null).</param> /// <returns>Tuple of two values, where the first is true when the positive relevance condition (inclusion) is satisfied, while the second is /// true when the negative condition (exclusion) is not violated. False otherwise.</returns> public Tuple <bool, bool> EvaluateWithExtendedResult(IConditions conditions, ISubstitution operatorSubstitution, ISubstitution expressionSubstitution, IList <int> relevantConditionalEffects = null) { ConditionsCNF expression = (ConditionsCNF)conditions?.GetCNF(); if (expression == null) { return(Tuple.Create(false, false)); } Effects.GroundEffectsByCurrentOperatorSubstitution(GroundingManager, operatorSubstitution); OperatorSubstitution = operatorSubstitution; ExpressionSubstitution = expressionSubstitution; var primitivesResult = ProcessPrimitiveEffects(expression); if (!primitivesResult.Item2) { return(primitivesResult); } var forallResult = ProcessForallEffects(expression); if (!forallResult.Item2) { return(forallResult); } var whenResult = ProcessWhenEffects(expression, relevantConditionalEffects); if (!whenResult.Item2) { return(whenResult); } return(Tuple.Create((primitivesResult.Item1 || forallResult.Item1 || whenResult.Item1), true)); }
/// <summary> /// Builds CNF conditions form from the given conditions. /// </summary> /// <param name="conditions">Source conditions.</param> /// <returns>Expression in CNF.</returns> public ConditionsCNF Build(Conditions conditions) { IExpression expression = conditions.GetWrappedConditions(); if (expression == null) { return(null); } IExpression transformedExpression = ExpressionToCNFTransformer.Transform(expression); Debug.Assert(Stack.Count == 0); Stack.Clear(); transformedExpression.Accept(this); ConditionsCNF conditionsCNF = new ConditionsCNF(EvaluationManager, conditions.Parameters); while (Stack.Count != 0) { conditionsCNF.Add(Stack.Pop()); } return(conditionsCNF); }
/// <summary> /// Gets the number of not accomplished condition constraints for the specified state. /// </summary> /// <param name="conditions">Conditions to be evaluated.</param> /// <param name="referenceState">Reference state.</param> /// <returns>Number of not accomplished condition constraints.</returns> public int Evaluate(ConditionsCNF conditions, IState referenceState) { ReferenceState = referenceState; return(conditions.Accept(this).Item2); }
/// <summary> /// Gets the number of not accomplished condition constraints for the specified state. /// </summary> /// <param name="conditions">Conditions.</param> /// <param name="state">State to be evaluated.</param> /// <returns>Number of not accomplished condition constraints.</returns> public int GetNotAccomplishedConstraintsCount(ConditionsCNF conditions, IState state) { return(NotAccomplishedConstraintsCounterCNF.Value.Evaluate(conditions, state)); }
/// <summary> /// Computes the operator label in the relaxed planning graph. /// </summary> /// <param name="conditions">Operator preconditions.</param> /// <param name="substitution">Variable substitution.</param> /// <param name="stateLabels">Atom labels from the predecessor layer in the graph.</param> /// <param name="evaluationStrategy">Evaluation strategy of the planning graph.</param> /// <returns>Computed operator label in the relaxed planning graph.</returns> public double EvaluateOperatorPlanningGraphLabel(ConditionsCNF conditions, ISubstitution substitution, StateLabels stateLabels, ForwardCostEvaluationStrategy evaluationStrategy) { return(PlanningGraphOperatorLabelEvaluatorCNF.Value.Evaluate(conditions, substitution, stateLabels, evaluationStrategy)); }
/// <summary> /// Renames the parameters (and the corresponding occurences in the conditions), starting from the given free parameter ID. /// </summary> /// <param name="conditions">Conditions to be edited.</param> /// <param name="firstFreeParameterId">First free parameter ID.</param> public void RenameConditionParameters(ConditionsCNF conditions, int firstFreeParameterId) { ConditionsParametersRenamer.Value.Rename(conditions, firstFreeParameterId); }
/// <summary> /// Processes primitive effects. /// </summary> /// <param name="expression">Conditions expression in CNF.</param> /// <returns>Tuple of two values, where the first is true when the positive relevance condition (inclusion) is satisfied, while the second is /// true when the negative condition (exclusion) is not violated. False otherwise.</returns> private Tuple <bool, bool> ProcessPrimitiveEffects(ConditionsCNF expression) { return(expression.Accept(this)); }
/// <summary> /// Processes primitive effects. /// </summary> /// <param name="expression">Conditions expression in CNF.</param> private ConditionsCNF ProcessPrimitiveEffects(ConditionsCNF expression) { // standard processing of simple effects via visitor pattern return((ConditionsCNF)expression.Accept(this)); }