All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.metacsp.booleanSAT.BooleanConstraint Maven / Gradle / Ivy

There is a newer version: 1.3.5
Show newest version
/*******************************************************************************
 * Copyright (c) 2010-2013 Federico Pecora 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ******************************************************************************/

package org.metacsp.booleanSAT;

import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;

import org.metacsp.framework.Constraint;
import org.metacsp.utility.logging.MetaCSPLogging;
import org.sat4j.core.VecInt;

import aima.core.logic.propositional.parsing.PEParser;
import aima.core.logic.propositional.parsing.ast.Sentence;
import aima.core.logic.propositional.parsing.ast.Symbol;
import aima.core.logic.propositional.visitors.CNFClauseGatherer;
import aima.core.logic.propositional.visitors.CNFTransformer;
import aima.core.logic.propositional.visitors.SymbolClassifier;
import aima.core.util.Converter;

/**
 * Class for representing disjunctive Boolean clauses, e.g., (x1 v x2 v ~x3).
 * Note that {@link BooleanConstraint}s can be instantiated with a factory method from non-CNF formulas
 * (see {@link #createBooleanConstraints(BooleanVariable[], String)}.
 * 
 * @author Federico Pecora
 *
 */
public class BooleanConstraint extends Constraint {
	
	private boolean[] positive;
	
//	private static ClassicalLogic logic = new ClassicalLogic();
	
//	/**
//	 * A factory method for creating {@link BooleanConstraint}s from an arbitrary
//	 * propositional logic formula (wff).  Allowed connectives are
//	 * {'^' (and), 'v' (or), '~' (not), '->' (implies), '<->' (iff)}.
//	 * Atoms in the formula should be named "xN" where
//	 * x is in [a-z] and N is in {1..scope.length}. The signature
//	 * of the formula must contain all and only the variables in the scope.
//	 * 
//	 * The conversion to CNF is provided by a clause translation algorithm
//	 * implemented in the Orbital library (see symbolaris.com/orbital)
//	 * ["David A. Plaisted & Steven Greenbaum. A structure-preserving clause form translation. J. Symb. Comput., Academic Press, Inc., 1986, 2, 293-304.", "Rolf Socher-Ambrosius. Boolean algebra admits no convergent term rewriting system, Springer Lecture Notes in Computer Science 488, RTA '91."].
//	 * @param scope The {@link BooleanVariable}s referred to in the formula.
//	 * @param wff An arbitrary propositional logic formula.
//	 * @return One or more {@link BooleanConstraint}s representing the given formula in CNF.
//	 */
//	public static BooleanConstraint[] createBooleanConstraints(BooleanVariable[] scope, String wff) {
//		try {
//			wff = wff.replace('^', '&');
//			wff = wff.replace('v', '|');
//			MetaCSPLogging.getLogger(BooleanConstraint.class).finest("Converting WFF: " + wff);
//			Formula f = (Formula)logic.createExpression(wff);
//			if (f.getSignature().size() != scope.length) throw new Error("WFF must include all and only the variables in the scope");
//			
//			//get CNF from wff
//			DefaultClausalFactory cf = new DefaultClausalFactory();
//			ClausalSetImpl cs = (ClausalSetImpl)cf.asClausalSet(f);
//			Formula newF = cs.toFormula();
//			
//			//get formula signature
//			Signature newSig = newF.getSignature();
//			@SuppressWarnings("unchecked")
//			Iterator itSig = newSig.iterator();
//			Vector trueLits = new Vector();
//			Vector falseLits = new Vector();
//			while (itSig.hasNext()) {
//				SymbolBase var = itSig.next();
//				Formula trueF = (Formula)logic.createExpression(""+var);
//				Formula falseF = (Formula)logic.createExpression("~"+var);
//				trueLits.add(trueF);
//				falseLits.add(falseF);
//			}
//			
//			//get literals in clauses
//			@SuppressWarnings("unchecked")
//			Iterator itClauses = cs.iterator();
//			Vector cons = new Vector();
//			while (itClauses.hasNext()) {
//				HashMap newClause = new HashMap();
//				IndexedClauseImpl cl = (IndexedClauseImpl)itClauses.next();
//				try {
//					for (Formula lit : trueLits) {
//						if (!cl.getUnifiables(lit).isEmpty()) {
//							BooleanVariable bv = scope[Integer.parseInt(lit.toString().substring(1))-1];
//							newClause.put(bv, true);
//						}
//					}
//					for (Formula lit : falseLits) {
//						if (!cl.getUnifiables(lit).isEmpty()) {
//							BooleanVariable bv = scope[Integer.parseInt(lit.toString().substring(2))-1];
//							if (newClause.containsKey(bv)) newClause.remove(bv);
//							else newClause.put(bv, false);
//						}
//					}
//				}
//				catch (ArrayIndexOutOfBoundsException e) { throw new Error("Variable numbering in WFF must be within scope"); }
//				catch (NumberFormatException e) { throw new Error("Variables in WFF must be in the format [a-z][1-MAXINT]"); }			
//				if (newClause.size() > 0) {
//					BooleanVariable[] relevantVars = new BooleanVariable[newClause.size()];
//					boolean[] positive = new boolean[newClause.size()];
//					int counter = 0;
//					for (Entry ent : newClause.entrySet()) {
//						relevantVars[counter] = ent.getKey();
//						positive[counter++] = ent.getValue();
//					}
//					BooleanConstraint bc = new BooleanConstraint(relevantVars, positive);
//					MetaCSPLogging.getLogger(BooleanConstraint.class).finest("Created constraint " + bc);
//					boolean subsumed = false;
//					for (BooleanConstraint otherBc : cons) {
//						if (bc.isEquivalent(otherBc)) {
//							subsumed = true;
//							break;
//						}
//					}
//					if (!subsumed) cons.add(bc);
//				}
//			}
//			MetaCSPLogging.getLogger(BooleanConstraint.class).finest("CNF(WFF): " + cons);
//			return cons.toArray(new BooleanConstraint[cons.size()]);
//		}
//		catch (ParseException e) { throw new Error("Malformed BooleanConstraint - allowed logical connectives:\n\t^ : AND\n\tv : OR\n\t-> : implication\n\t<-> : iff\n\t~ : NOT"); }
//		catch (TokenMgrError e) { throw new Error("Malformed BooleanConstraint - allowed logical connectives:\n\t^ : AND\n\tv : OR\n\t-> : implication\n\t<-> : iff\n\t~ : NOT"); }
//	}


	/**
	 * A factory method for creating {@link BooleanConstraint}s from an arbitrary
	 * propositional logic formula (wff).  Allowed connectives are
	 * ^ (and), v (or), ~ (not), -> (implies), <-> (iff)}.
	 * Atoms in the formula should be named "xN" where
	 * x is in [a-z] and N is in {1..scope.length}. The signature
	 * of the formula must contain all and only the variables in the scope. 
	 * The conversion to CNF is provided by the propositional logic CNFTransformer class
	 * of the aima-java library (see aima-java.googlecode.com).
	 * 
* Note: the given wff must be composed of binary clauses (i.e., all parantheses must be made explicit). * For example, the following wff *
* (x1 ^ x2) ^ (x2 v ~x3 ^ x4) ^ (~x1 v x3) ^ (x2 v ~x3 ^ ~x4) *
* must be input as *
* ((((x1 ^ x2) ^ (x2 v (~x3 ^ x4))) ^ (~x1 v x3)) ^ (x2 v (~x3 ^ ~x4))) *
* or as *
* (((x1 ^ x2) ^ (x2 v (~x3 ^ x4))) ^ ((~x1 v x3) ^ (x2 v (~x3 ^ ~x4)))) *
* @param scope The {@link BooleanVariable}s referred to in the formula. * @param wff An arbitrary propositional logic formula. * @return One or more {@link BooleanConstraint}s representing the given formula in CNF. */ public static BooleanConstraint[] createBooleanConstraints(BooleanVariable[] scope, String wff) { try { wff = wff.replace("~", "NOT "); wff = wff.replace("-", "="); wff = wff.replace("v", "OR"); wff = wff.replace("^", "AND"); MetaCSPLogging.getLogger(BooleanConstraint.class).finest("Converting WFF: " + wff); Converter sConv = new Converter(); PEParser parser = new PEParser(); Sentence s = (Sentence) parser.parse(wff); Set clauses = new CNFClauseGatherer().getClausesFrom(new CNFTransformer().transform(s)); //List signature = sConv.setToList(new SymbolClassifier().getSymbolsIn(s)); Vector cons = new Vector(); for (Sentence cl : clauses) { HashMap newClause = new HashMap(); List positiveSymbols = sConv.setToList(new SymbolClassifier().getPositiveSymbolsIn(cl)); List negativeSymbols = sConv.setToList(new SymbolClassifier().getNegativeSymbolsIn(cl)); try { for (Symbol ps : positiveSymbols) { BooleanVariable bv = scope[Integer.parseInt(ps.toString().substring(1))-1]; newClause.put(bv,true); } for (Symbol ns : negativeSymbols) { BooleanVariable bv = scope[Integer.parseInt(ns.toString().substring(1))-1]; if (newClause.containsKey(bv)) newClause.remove(bv); else newClause.put(bv, false); } } catch (ArrayIndexOutOfBoundsException e) { throw new Error("Variable numbering in WFF must be within scope"); } catch (NumberFormatException e) { throw new Error("Variables in WFF must be in the format [a-z][1-MAXINT]"); } if (newClause.size() > 0) { BooleanVariable[] relevantVars = new BooleanVariable[newClause.size()]; boolean[] positive = new boolean[newClause.size()]; int counter = 0; for (Entry ent : newClause.entrySet()) { relevantVars[counter] = ent.getKey(); positive[counter++] = ent.getValue(); } BooleanConstraint bc = new BooleanConstraint(relevantVars, positive); MetaCSPLogging.getLogger(BooleanConstraint.class).finest("Created constraint " + bc); boolean subsumed = false; for (BooleanConstraint otherBc : cons) { if (bc.isEquivalent(otherBc)) { subsumed = true; break; } } if (!subsumed) cons.add(bc); } } MetaCSPLogging.getLogger(BooleanConstraint.class).finest("CNF(WFF): " + cons); return cons.toArray(new BooleanConstraint[cons.size()]); } catch (java.lang.RuntimeException e) { throw new Error("Malformed BooleanConstraint - allowed logical connectives:\n\t^ : AND\n\tv : OR\n\t-> : implication\n\t<-> : iff\n\t~ : NOT"); } } /** * Create a {@link BooleanConstraint} given its scope and a specification * of the polarity of literals. * @param scope The scope of the clause. * @param positive Polarity of literals. */ public BooleanConstraint(BooleanVariable[] scope, boolean[] positive) { this.positive = positive; this.setScope(scope); } /** * */ private static final long serialVersionUID = 8863340939973901776L; public VecInt getLiterals() { int[] literals = new int[this.getScope().length]; for (int i = 0; i < this.getScope().length; i++) { if (positive[i]) literals[i] = this.getScope()[i].getID(); else literals[i] = -this.getScope()[i].getID(); } return new VecInt(literals); } @Override public String toString() { String ret = "("; for (int i = 0; i < this.getScope().length; i++) { BooleanVariable bv = (BooleanVariable)this.getScope()[i]; if (!this.positive[i]) ret += "~x" + bv.getID(); else ret += "x" + bv.getID(); if (i == this.getScope().length-1) ret += ")"; else ret += " v "; } return ret; } @Override public String getEdgeLabel() { return this.toString(); } @Override public Object clone() { BooleanConstraint ret = new BooleanConstraint((BooleanVariable[])this.getScope(), this.positive); ret.autoRemovable = autoRemovable; return ret; } @Override public boolean isEquivalent(Constraint c) { if (!(c instanceof BooleanConstraint)) return false; if (this.getScope().length != c.getScope().length) return false; for (int i = 0; i < this.getScope().length; i++) { if (!this.getScope()[i].equals(c.getScope()[i])) return false; if (this.positive[i] && !((BooleanConstraint)c).positive[i]) return false; if (!this.positive[i] && ((BooleanConstraint)c).positive[i]) return false; } return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy