/** * Logically ands the provided terms with the terms in the formula, replacing this formula with * the result * * @param other the terms to and with this formula * @return this object. */ public BooleanFormula andWith(BooleanFormula other) { if (other.isTrue()) { return this; } if (other.isFalse() || isFalse()) { if (booleanTerms == null) { booleanTerms = new HashSet<BooleanTerm>(); } else { booleanTerms.clear(); } isSimplified = true; return this; } if (isTrue()) { booleanTerms = new HashSet<BooleanTerm>(other.booleanTerms); return this; } BooleanFormula newTerms = new BooleanFormula(); for (BooleanTerm otherTerm : other) { for (BooleanTerm term : booleanTerms) { BooleanTerm newTerm = term.andWith(otherTerm); if (newTerm != null) { newTerms.add(newTerm); } } } booleanTerms = newTerms.booleanTerms; isSimplified = newTerms.isSimplified; return this; }
/** * Resolves the formula using the boolean values specified in <code>features</code>. If there are * no more un-resolved variables in the forumula, the resulting formula will be either TRUE or * FALSE. * * @param features the values to assign to variables in the formula * @return this object */ public BooleanFormula resolveWith(Features features) { if (isTrue() || isFalse()) { return this; } BooleanFormula formula = new BooleanFormula(); for (BooleanTerm term : this) { BooleanTerm evaluated = term.resolveWith(features); if (evaluated.isFalse()) { // term is false. Don't add to result } else if (evaluated.isTrue()) { // term is true so formula is true booleanTerms = null; isSimplified = true; return this; } else { formula.add(evaluated); } } booleanTerms = formula.booleanTerms; isSimplified = formula.isSimplified; return this; }
/** * Returns an instance of this class which is the simplified representation of the formula * represented by this object. May return this object if the formula is already simplified. * * <p>This method uses the Quine-McCluskey algorithm and code described at * http://en.literateprograms.org/Quine-McCluskey_algorithm_%28Java%29 * * @return The simplified representation of this formula, or this object, if already simplified. */ public BooleanFormula simplify() { if (isSimplified) { return this; } if (booleanTerms == null || booleanTerms.size() < 2) { isSimplified = true; return this; } // Remove true and false terms. False terms are discarded. True terms // make the entire formula evaluate to true. Set<BooleanTerm> trimmed = new HashSet<BooleanTerm>(); for (BooleanTerm term : booleanTerms) { if (term.isTrue()) { booleanTerms = null; isSimplified = true; return this; } else if (term.isFalse()) { continue; // omitting a false term } else { trimmed.add(term); } } if (trimmed.size() != booleanTerms.size()) { booleanTerms = trimmed; } // Determine number of unique variable names in the formula Map<String, Integer> names = new TreeMap<String, Integer>(); for (Set<BooleanVar> term : booleanTerms) { for (BooleanVar state : term) { names.put(state.name, -1); } } int i = 0; for (Map.Entry<String, Integer> entry : names.entrySet()) { entry.setValue(i++); } int count = names.size(); if (count >= Integer.SIZE) { throw new IllegalArgumentException(Integer.toString(count)); } List<Term> terms = new ArrayList<Term>(booleanTerms.size()); for (Set<BooleanVar> term : booleanTerms) { byte[] bytes = new byte[count]; for (i = 0; i < count; i++) bytes[i] = Term.DontCare; boolean ignoreTerm = false; for (BooleanVar state : term) { int index = names.get(state.name); byte val = state.state ? (byte) 1 : (byte) 0; if (bytes[index] == Term.DontCare) bytes[index] = val; else if (bytes[index] != val) { // Mutually exclusive states. Don't consider this term ignoreTerm = true; break; } } if (!ignoreTerm) { terms.add(new Term(bytes)); } } Set<BooleanTerm> result = new HashSet<BooleanTerm>(); if (terms.size() == 0) { return new BooleanFormula(false); } terms = expandDontCares(count, terms); Formula formula = new Formula(terms); formula.reduceToPrimeImplicants(); formula.reducePrimeImplicantsToSubset(); // now convert back to featureExpression form List<Term> termList = formula.getTermList(); if (termList.size() == 0) { return new BooleanFormula(false); } for (Term term : termList) { byte[] varValues = term.getVarValues(); Set<BooleanVar> states = new HashSet<BooleanVar>(); for (Map.Entry<String, Integer> entry : names.entrySet()) { if (varValues[entry.getValue()] == (byte) 1) { states.add(new BooleanVar(entry.getKey(), true)); } else if (varValues[entry.getValue()] == (byte) 0) { states.add(new BooleanVar(entry.getKey(), false)); } } if (states.size() > 0) { result.add(new BooleanTerm(states)); } } if (result.size() == 0) { return new BooleanFormula(true); } BooleanFormula newFormula = new BooleanFormula(); newFormula.booleanTerms = result; newFormula.isSimplified = true; return newFormula; }