package LBJ2.infer; /** * Represents the constraint that at least <code>m</code> of the children * constraints must be true. * * @author Nick Rizzolo **/ public class PropositionalAtLeast extends PropositionalNAryConstraint { /** The children are stored in an array in this class. */ protected PropositionalConstraint[] children; /** The number of child constraints that must be true. */ protected int m; /** Default constructor. */ private PropositionalAtLeast() { } /** * Initializing constructor. * * @param c A collection of children constraints. * @param m The number of children that must be true. **/ public PropositionalAtLeast(PropositionalConstraint[] c, int m) { this.m = m; children = c; super.children = null; } /** * Returns the children of this constraint in an array. * * @return The children of this constraint in an array. **/ public Constraint[] getChildren() { return (PropositionalConstraint[]) children.clone(); } /** Returns the value of <code>m</code>. */ public int getM() { return m; } /** * Determines whether the given constraint is a term of this constraint. * * @param c The given constraint. * @return <code>true</code> iff the given constraint is contained in this * constraint. **/ public boolean contains(PropositionalConstraint c) { for (int i = 0; i < children.length; ++i) if (c.equals(children[i])) return true; return false; } /** * Returns the number of terms in this constraint. * * @return The number of terms in this constraint. **/ public int size() { return children.length; } /** Determines whether the constraint is satisfied. */ public boolean evaluate() { int trueChildren = 0; for (int i = 0; i < children.length && trueChildren < m; ++i) if (children[i].evaluate()) ++trueChildren; return trueChildren == m; } /** * Replaces the <code>children</code> array with a new array containing all * the same elements except the element with the given index. * * @param r The index of the child to remove. **/ public void remove(int r) { PropositionalConstraint[] temp = new PropositionalConstraint[children.length - 1]; for (int i = 0, j = 0; i < children.length; ++i) { if (i == r) continue; temp[j++] = children[i]; } children = temp; } /** * Produces a new, logically simplified version of this constraint, * preserving variable consolidation. * * @see Constraint#consolidateVariables(java.util.AbstractMap) * @return A logically simplified version of this constraint. **/ public PropositionalConstraint simplify() { if (m <= 0) return PropositionalConstant.True; if (m > children.length) return PropositionalConstant.False; PropositionalAtLeast result = new PropositionalAtLeast(); result.m = m; result.children = new PropositionalConstraint[children.length]; for (int i = 0; i < children.length; ++i) result.children[i] = children[i].simplify(); for (int i = result.children.length - 1; i >= 0; --i) { if (result.children[i] == PropositionalConstant.True) { result.remove(i); --result.m; } else if (result.children[i] == PropositionalConstant.False) result.remove(i); } /* HashSet positive = new HashSet(); HashSet negative = new HashSet(); for (int i = 0; i < result.children.length; ++i) { if (result.children[i] instanceof PropositionalNegation) negative.add(result.children[i].getChildren()[0]); else positive.add(result.children[i]); } for (Iterator I = positive.iterator(); I.hasNext(); ) { PropositionalConstraint p = (PropositionalConstraint) I.next(); if (negative.contains(p)) { LinkedList positiveIndexes = new LinkedList(); LinkedList negativeIndexes = new LinkedList(); for (int i = 0; i < result.children.length; ++i) { if (result.children[i].equals(p)) positiveIndexes.add(new Integer(i)); else if (result.children[i].equals(new PropositionalNegation(p))) negativeIndexes.add(new Integer(i)); } int toRemove = positiveIndexes.size(); if (negativeIndexes.size() < toRemove) toRemove = negativeIndexes.size(); Integer[] removedIndexes = new Integer[toRemove * 2]; for (int i = 0; i < toRemove; ++i) { removedIndexes[2 * i] = (Integer) positiveIndexes.removeLast(); removedIndexes[2 * i + 1] = (Integer) negativeIndexes.removeLast(); } Arrays.sort(removedIndexes); for (int i = removedIndexes.length - 1; i >= 0; --i) result.remove(removedIndexes[i].intValue()); result.m -= toRemove; } } */ if (result.m <= 0) return PropositionalConstant.True; if (result.m > result.children.length) return PropositionalConstant.False; if (result.children.length == 1) return result.children[0]; if (result.m == 1) { PropositionalDisjunction disjunction = new PropositionalDisjunction(result.children[0], result.children[1]); for (int i = 2; i < result.children.length; ++i) disjunction = new PropositionalDisjunction(disjunction, result.children[i]); return disjunction.simplify(); } return result; } /** * The negation of an at-least(m) is the at-least(n-m+1) of the negated * children. * * @return A simplified constraint representing the negation of this * constraint. **/ public PropositionalConstraint negate() { PropositionalAtLeast result = new PropositionalAtLeast(); result.children = new PropositionalConstraint[children.length]; for (int i = 0; i < children.length; ++i) result.children[i] = children[i].negate(); result.m = children.length - m + 1; return result; } /** * Produces a new, logically simplified version of this constraint in * conjunctive normal form (CNF). * * @return The conjunctive normal form of this constraint. **/ public PropositionalConstraint CNF() { return DNF().CNF(); } /** * Produces a new, logically simplified version of this constraint in * disjunctive normal form (DNF). * * @return The disjunctive normal form of this constraint. **/ public PropositionalConstraint DNF() { PropositionalConstraint result = null; if (m == 1) { result = new PropositionalDisjunction(children[0], children[1]); for (int i = 2; i < m; ++i) result = new PropositionalDisjunction(result, children[i]); } else { result = new PropositionalConjunction(children[0], children[1]); for (int i = 2; i < m; ++i) result = new PropositionalConjunction(result, children[i]); int[] indexes = new int[m]; for (int i = 0; i < m; ++i) indexes[i] = i; while (nextChoice(indexes, children.length - 1)) { PropositionalConjunction term = new PropositionalConjunction(children[indexes[0]], children[indexes[1]]); for (int i = 2; i < m; ++i) term = new PropositionalConjunction(term, children[indexes[i]]); result = new PropositionalDisjunction(result, term); } } return result; } /** * Given a particular choice of k of the first n non-negative integers, * this method computes the next logical choice of k integers, modifying * the input array to contain that choice. The parameter <code>I</code> * contains the current choice, and it must be sorted in ascending order. * The parameter <code>max</code> contains the largest allowable value for * any integer in <code>I</code>. Therefore, n = <code>max</code> + 1, and * k = <code>I.length</code>. It is also assumed that the "first" choice * is the integers 0 through k - 1 inclusive and the "last" choice is * <code>max</code> - k + 1 through <code>max</code> inclusive. * * @param I The current choice of k out of the first n non-negative * integers, sorted in decreasing order. * @param max The largest value allowed to appear in <code>I</code> (n - * 1). * @return <code>true</code> iff the input did not represent the last * choice. **/ protected static boolean nextChoice(int[] I, int max) { int i = 1; while (i < I.length && I[i] - I[i - 1] == 1) ++i; if (i == I.length && I[i - 1] == max) return false; ++I[i - 1]; for (int j = 0; j < i - 1; ++j) I[j] = j; return true; } /** * Compares topology to determine if this constraint is more general than * the given constraint; <i>note: this method is not required to be correct * when it answers <code>false</code></i>. * * @param c The given constraint. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given constraint. **/ public boolean moreGeneralThan(PropositionalConstraint c) { return c.moreSpecificThan(this); } /** * Compares topology to determine if this constraint is more specific than * the given implication; <i>note: this method is not required to be * correct when it answers <code>false</code></i>. * * @param c The given implication. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given implication. **/ public boolean moreSpecificThan(PropositionalImplication c) { return false; } /** * Compares topology to determine if this constraint is more specific than * the given double implication; <i>note: this method is not required to be * correct when it answers <code>false</code></i>. * * @param c The given double implication. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given double implication. **/ public boolean moreSpecificThan(PropositionalDoubleImplication c) { return false; } /** * Compares topology to determine if this constraint is more specific than * the given conjunction; <i>note: this method is not required to be * correct when it answers <code>false</code></i>. * * @param c The given conjunction. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given conjunction. **/ public boolean moreSpecificThan(PropositionalConjunction c) { return false; } /** * Compares topology to determine if this constraint is more specific than * the given disjunction; <i>note: this method is not required to be * correct when it answers <code>false</code></i>. * * @param c The given disjunction. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given disjunction. **/ public boolean moreSpecificThan(PropositionalDisjunction c) { return false; } /** * Compares topology to determine if this constraint is more specific than * the given at-least; <i>note: this method is not required to be correct * when it answers <code>false</code></i>. * * @param c The given at-least. * @return <code>true</code> if a topological analysis determined that this * constraint is more specific than the given disjunction. **/ public boolean moreSpecificThan(PropositionalAtLeast c) { if (c.children.length != children.length) return false; for (int i = 0; i < children.length; ++i) if (!children[i].equals(c.children[i])) return false; return m >= c.m; } /** * Compares topology to determine if this constraint is more specific than * the given negation; <i>note: this method is not required to be correct * when it answers <code>false</code></i>. * * @param c The given negation. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given negation. **/ public boolean moreSpecificThan(PropositionalNegation c) { return false; } /** * Compares topology to determine if this constraint is more specific than * the given variable; <i>note: this method is not required to be correct * when it answers <code>false</code></i>. * * @param c The given variable. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given variable. **/ public boolean moreSpecificThan(PropositionalVariable c) { return false; } /** * Compares topology to determine if this constraint is more specific than * the given constant; <i>note: this method is not required to be correct * when it answers <code>false</code></i>. * * @param c The given constant. * @return <code>true</code> if a topological analysis determined that this * constraint is more general than the given constant. **/ public boolean moreSpecificThan(PropositionalConstant c) { return c.evaluate(); } /** * The hash code of a <code>PropositionalAtLeast</code> is the sum of * the hash codes of its children plus two. * * @return The hash code for this <code>PropositionalConjunction</code>. **/ public int hashCode() { int result = 2; for (int i = 0; i < children.length; ++i) result += children[i].hashCode(); return result; } /** * Two <code>PropositionalAtLeast</code>s are equivalent when they are * topologically equivalent; this implementation currently does not respect * the associativity and commutativity of at-least. * * @return <code>true</code> iff the argument is an equivalent * <code>PropositionalAtLeast</code>. **/ public boolean equals(Object o) { if (!(o instanceof PropositionalAtLeast)) return false; PropositionalAtLeast a = (PropositionalAtLeast) o; if (children.length != a.children.length) return false; for (int i = 0; i < children.length; ++i) if (!children[i].equals(a.children[i])) return false; return true; } /** * Calls the appropriate <code>visit(·)</code> method of the given * <code>Inference</code> for this <code>Constraint</code>, as per the * visitor pattern. * * @param infer The inference visiting this constraint. **/ public void runVisit(Inference infer) { infer.visit(this); } /** * Creates a string respresentation of this constraint using the string * representations of the objects involved. * * @param buffer The output of this method will be appended to this buffer. **/ public void write(StringBuffer buffer) { buffer.append("(atleast " + m + " of "); children[0].write(buffer); for (int i = 1; i < children.length; ++i) { buffer.append(", "); children[i].write(buffer); } buffer.append(")"); } /** * This method returns a shallow clone. * * @return A shallow clone. **/ public Object clone() { PropositionalAtLeast clone = null; try { clone = (PropositionalAtLeast) super.clone(); } catch (Exception e) { System.err.println("Error cloning PropositionalAtLeast:"); e.printStackTrace(); System.exit(1); } clone.children = (PropositionalConstraint[]) clone.children.clone(); return clone; } }