/// <summary> /// Visits and performs a property count on CNF clause. /// </summary> /// <param name="expression">CNF clause.</param> /// <returns>Tuple (property satisfied count, property not satisfied count).</returns> public Tuple <int, int> Visit(ClauseCNF expression) { int minFulfilled = int.MaxValue; int minNotFulfilled = int.MaxValue; foreach (var literal in expression) { var childPropertyCounts = literal.Accept(this); minFulfilled = Math.Min(minFulfilled, childPropertyCounts.Item1); minNotFulfilled = Math.Min(minNotFulfilled, childPropertyCounts.Item2); } return(Tuple.Create(minFulfilled, minNotFulfilled)); }
/// <summary> /// Visits and performs a property count on CNF clause. /// </summary> /// <param name="expression">CNF clause.</param> /// <returns>Tuple (property satisfied count, property not satisfied count).</returns> public Tuple <double, double> Visit(ClauseCNF expression) { double positiveValue = 0; double negativeValue = 0; foreach (var child in expression) { var childPropertyCounts = child.Accept(this); positiveValue = Math.Max(positiveValue, childPropertyCounts.Item1); negativeValue = Math.Max(negativeValue, childPropertyCounts.Item2); } return(Tuple.Create(positiveValue, negativeValue)); }
/// <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); } ClauseCNF other = obj as ClauseCNF; if (other == null) { return(false); } return(CollectionsEquality.Equals(this, other)); }
/// <summary> /// Accepts a conjunctive-normal-form expression backwards applier visitor. /// </summary> /// <param name="visitor">CNF expression visitor.</param> public IElementCNF Accept(IElementCNFBackwardsApplierVisitor visitor) { ClauseCNF newExpression = new ClauseCNF(); foreach (var literal in this) { var resultExpression = literal.Accept(visitor); if (resultExpression == null) { // any of element from the clause holds -> the whole clause holds return(null); } else { newExpression.Add((LiteralCNF)resultExpression); } } return(newExpression); }
/// <summary> /// Visits the expression. /// </summary> /// <param name="expression">Expression.</param> public override void Visit(OrExpression expression) { expression.Children.ForEach(child => child.Accept(this)); ClauseCNF clause = new ClauseCNF(); for (int i = 0; i < expression.Children.Count; ++i) { LiteralCNF literal = Stack.Pop() as LiteralCNF; if (literal != null) { clause.Add(literal); } else { Debug.Assert(false, "Source expression not in CNF!"); } } Stack.Push(clause); }
/// <summary> /// Generates all possible PDDL relative states meeting given CNF conditions (in the form of a list of conjuncts). Lazy generated recursively via yield return. /// </summary> /// <param name="index">Current index in the conjuncts list.</param> /// <param name="conjuncts">List of conjuncts of the CNF conditions.</param> /// <param name="result">Current relative state being built.</param> /// <returns>All possible PDDL relative states meeting the CNF conditions.</returns> private static IEnumerable <IRelativeState> EnumerateRelativeStatesByCNF(int index, List <IConjunctCNF> conjuncts, IRelativeState result) { if (index == 0) { // the constructed state can have trailing values from the previous unfinished enumeration! result.ClearContent(); } Action <IRelativeState, LiteralCNF> addLiteral = (state, literal) => { // Note: At the moment, there is limited support for object and numeric function assignments. // For example, numeric comparison literals like (< (numFunc) 5) will be omitted in the resulting relative state. PredicateLiteralCNF predicateLiteral = literal as PredicateLiteralCNF; if (predicateLiteral != null) { if (literal.IsNegated) { state.AddNegatedPredicate(predicateLiteral.PredicateAtom.Clone()); } else { state.AddPredicate(predicateLiteral.PredicateAtom.Clone()); } return; } EqualsLiteralCNF equalsLiteral = literal as EqualsLiteralCNF; if (equalsLiteral != null) { var assignment = equalsLiteral.TryGetObjectFunctionAssignment(); if (assignment != null) { if (!literal.IsNegated) { state.AssignObjectFunction(assignment.Item1.FunctionAtom.Clone(), assignment.Item2.NameId); } } return; } NumericCompareLiteralCNF compareLiteral = literal as NumericCompareLiteralCNF; if (compareLiteral != null) { var assignment = compareLiteral.TryGetNumericFunctionAssignment(); if (assignment != null) { if (!compareLiteral.IsNegated) { state.AssignNumericFunction(assignment.Item1.FunctionAtom.Clone(), assignment.Item2.Value); } } } }; Action <IRelativeState, LiteralCNF> removeLiteral = (state, literal) => { PredicateLiteralCNF predicateLiteral = literal as PredicateLiteralCNF; if (predicateLiteral != null) { if (literal.IsNegated) { state.RemoveNegatedPredicate(predicateLiteral.PredicateAtom.Clone()); } else { state.RemovePredicate(predicateLiteral.PredicateAtom.Clone()); } return; } EqualsLiteralCNF equalsLiteral = literal as EqualsLiteralCNF; if (equalsLiteral != null) { var assignment = equalsLiteral.TryGetObjectFunctionAssignment(); if (assignment != null) { if (!literal.IsNegated) { state.AssignObjectFunction(assignment.Item1.FunctionAtom.Clone(), ObjectFunctionTerm.UndefinedValue); } } return; } NumericCompareLiteralCNF compareLiteral = literal as NumericCompareLiteralCNF; if (compareLiteral != null) { var assignment = compareLiteral.TryGetNumericFunctionAssignment(); if (assignment != null) { if (!compareLiteral.IsNegated) { state.AssignNumericFunction(assignment.Item1.FunctionAtom.Clone(), NumericFunction.UndefinedValue); } } } }; if (index >= conjuncts.Count) { yield return((IRelativeState)result.Clone()); } else { var conjunct = conjuncts[index]; ClauseCNF clause = conjunct as ClauseCNF; if (clause != null) { foreach (var literal in clause) { addLiteral(result, literal); foreach (var item in EnumerateRelativeStatesByCNF(index + 1, conjuncts, result)) { yield return(item); } removeLiteral(result, literal); } } else { LiteralCNF literal = conjunct as LiteralCNF; Debug.Assert(literal != null); addLiteral(result, literal); foreach (var item in EnumerateRelativeStatesByCNF(index + 1, conjuncts, result)) { yield return(item); } removeLiteral(result, literal); } } }
/// <summary> /// Constructs a new CNF from the given disjunction of CNFs. /// </summary> /// <param name="cnfList">List of possible CNF expressions.</param> /// <returns>CNF expression of the CNFs disjunction.</returns> private ConditionsCNF ConstructCNFFromDisjunction(List <ConditionsCNF> cnfList) { if (cnfList.Count == 1) { return(cnfList[0]); } // adjust the CNF list, so their parameters don't collide before they will be merged Parameters mergedParameters; MakeUniqueParametersForCNFList(cnfList, out mergedParameters); HashSet <IConjunctCNF> conjuncts = new HashSet <IConjunctCNF>(); foreach (var andExpr in cnfList) { HashSet <IConjunctCNF> newConjuncts = new HashSet <IConjunctCNF>(); foreach (var andElem in andExpr) { HashSet <LiteralCNF> andElemItems = new HashSet <LiteralCNF>(); ClauseCNF orExpr = andElem as ClauseCNF; if (orExpr != null) { foreach (var child in orExpr) { andElemItems.Add(child); } } else { andElemItems.Add((LiteralCNF)andElem); } if (conjuncts.Count == 0) { newConjuncts.Add(new ClauseCNF(andElemItems)); } else { foreach (var conjunct in conjuncts) { ClauseCNF clause = conjunct as ClauseCNF; if (clause != null) { HashSet <LiteralCNF> newOrChildren = new HashSet <LiteralCNF>(); foreach (var child in clause) { newOrChildren.Add(child); } newOrChildren.UnionWith(andElemItems); newConjuncts.Add(new ClauseCNF(newOrChildren)); } else { andElemItems.Add((LiteralCNF)conjunct); newConjuncts.Add(andElemItems.Count > 1 ? new ClauseCNF(andElemItems) : conjunct); } } } } conjuncts = newConjuncts; } return(new ConditionsCNF(conjuncts, EvaluationManager, mergedParameters)); }