package splar.core.constraints;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import splar.core.util.hypergraphs.Hyperedge;
import splar.core.util.hypergraphs.Hypergraph;
import splar.core.util.hypergraphs.Vertex;
public class PropositionalFormula {
protected String name;
protected ArrayList<BooleanVariable> variables;
protected String formula;
protected PFParser parser;
protected HashMap<String,PropositionalFormulaState> states;
public PropositionalFormula(String name, String formula) throws Exception {
this.name = name;
this.formula = formula;
variables = new ArrayList <BooleanVariable>();
states = new HashMap<String,PropositionalFormulaState>();
parser = new PFParser(this);
parser.parse();
}
public void appendToFormula(String formulaPart) {
formula += formulaPart;
}
public void appendToVariables(BooleanVariable var) {
assert !variables.contains(var);
variables.add(var);
}
/* public boolean containsVariable(BooleanVariable variable) {
return variables.contains(variable);
}
public boolean isInstantiated(BooleanVariable variable) {
BooleanVariable var = getVariable(variable.getName());
if ( var != null ) {
return var.isInstantiated();
}
return false;
}
*/
public void replaceVariable( String oldName, String newName ) {
// for( Iterator<BooleanVariable> it = variables.iterator() ; it.hasNext() ; ) {
// String varName = it.next().getID();
// if ( varName.compareToIgnoreCase(oldName) == 0) {
// it.remove();
// variables.add(new BooleanVariable(newName));
// break;
// }
// }
variables = new ArrayList <BooleanVariable>();
try {
Map<String,String> replacements = new HashMap<String, String>();
replacements.put(oldName, newName);
formula = new PFParser(this).replace(replacements);
}
catch (Exception e) {
e.printStackTrace();
}
}
public Assignment getInstantiatedVariables() {
Assignment a = new Assignment();
for( Iterator<BooleanVariable> it = variables.iterator() ; it.hasNext() ; ) {
BooleanVariable var = it.next();
if ( var.isInstantiated() ) {
a.add(var);
}
}
return a;
}
public String getName() {
return name;
}
public String getType() {
return "undefined-type";
}
public String getVariableListAsString() {
return ""+variables;
}
public Collection<BooleanVariable> getVariables() {
return variables;
}
protected void addVariable(BooleanVariable var) {
if ( !variables.contains(var) ) {
var.assignValue(-1);
variables.add(var);
}
}
public BooleanVariable getVariable(String name) {
return variables.get(getIndex(name));
}
protected void removeVariable(BooleanVariable var) {
variables.remove(variables.get(getIndex(getName())));
}
public String toString() {
return toCNFClauses().toArray(new CNFClause[0])[0].toString();
// String toString = name + ": ";
// formula = "";
// for( CNFClause clause : toCNFClauses() ) {
// formula += clause.toString();
// }
// toString += formula;
// return toString;
// StringBuffer toString = new StringBuffer(200);
// toString.append(getName());
// toString.append(": <");
// for( Iterator<BooleanVariable> it = variables.iterator() ; it.hasNext() ; ) {
// BooleanVariable bi = it.next();
// toString.append(bi.getID());
// toString.append(":");
// toString.append(bi.getValue());
// if ( it.hasNext() ) {
// toString.append(",");
// }
// }
// toString.append(">");
// return toString.toString();
}
public int getIndex(String varName) {
int length = variables.size();
for( int i = 0 ; i < length ; i++ ) {
BooleanVariable vi = variables.get(i);
if ( vi.getID().equals(varName) )
return i;
}
return -1;
}
public void saveState(String stateID) {
if ( !states.containsKey(stateID) ) {
PropositionalFormulaState state = new PropositionalFormulaState(this);
state.save();
states.put(stateID, state);
}
}
public void restoreState(String stateID) {
PropositionalFormulaState state = states.get(stateID);
state.restore();
states.remove(stateID);
}
public void discardState(String stateID) {
states.remove(stateID);
}
public void assignValue(String varName, int value) {
BooleanVariable var = variables.get(getIndex(varName));
if ( var != null ) {
var.assignValue(value);
}
}
public int countVars() {
return variables.size();
}
public String getFormula() {
return formula;
}
/*
* Generic function that builds a hypergraph where
* - vertices = constraint variables
* - hyperedges = single hyperedge linking all vertices (constraint variables)
*/
public Hypergraph buildHyperGraph() {
Hypergraph hGraph = new Hypergraph();
// a single hyperedge connects all varibles
Hyperedge hyperEdge = new Hyperedge();
// Constraint variables become hypergraph vertices
for( Iterator<BooleanVariable> it = variables.iterator(); it.hasNext() ; ) {
String varName = it.next().getID();
Vertex vertex = new Vertex(varName);
hGraph.addVertex(vertex);
hyperEdge.addVertex(vertex);
}
// add hyperedge to the hypergraph
hGraph.addHyperEdge(hyperEdge);
return hGraph;
}
/* To be fixed: the method only works if the propositional formula is already in CNF :) - sorry */
public Collection<CNFClause> toCNFClauses() {
Collection<CNFClause> clauses = new Vector<CNFClause>();
CNFClause clause = new CNFClause();
for( Iterator<BooleanVariable> it = variables.iterator(); it.hasNext() ; ) {
BooleanVariable variable = it.next();
clause.addLiteral(new CNFLiteral(variable, variable.isPositive()));
}
clauses.add(clause);
return clauses;
}
}
/*
* Propositional Formulas Grammar
* ------------------------------
* F ::= p | ~F | F op F | (F)
* op ::= | | & | -> | <-> | OR | AND | IMP | BIIMP (case INsensitive)
* p ::= variable (letter + letter|digit|_)
*
* Remarks:
* Operator "~" should only precede variables (never formulas)
*
*/
class PFParser {
protected int index = 0;
private static final int AND = 1;
private static final int OR = 2;
private static final int IMP = 3;
private static final int BIIMP = 4;
protected static String letters = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
protected static String digits = "0123456789";
protected static String others = "_";
protected String all = letters + digits + others;
protected PropositionalFormula pformula;
protected String parsedFormula = "";
protected Map<String,String> replacements;
public PFParser(PropositionalFormula pformula) {
this.pformula = pformula;
replacements = null;
}
public String replace(Map<String,String> replacements) throws Exception {
parsedFormula = "";
this.replacements = replacements;
parse();
return parsedFormula;
}
public void parse() throws Exception {
parsedFormula = "";
parse(pformula.getFormula());
}
protected void parse(String formula) throws Exception {
index = 0;
F(formula.trim());
}
protected String currentChar(String formula) {
return formula.substring(index,index+1);
}
protected void F(String formula) throws Exception {
// end of the formula
if (!EOF(formula)) {
// operator !
if (currentChar(formula).equals("~")) {
parsedFormula += "~";
incrementIndex(formula);
skipBlanks(formula);
if ( isLetter(currentChar(formula)) ){
parsedFormula += extractVar(formula, false);
}
skipBlanks(formula);
parsedFormula += " ";
if (!EOF(formula)) {
if (isLetter(currentChar(formula)) || currentChar(formula).equals("&") || currentChar(formula).equals("|") ||
currentChar(formula).equals("-") ||currentChar(formula).equals("<")) {
parsedFormula += operator(formula);
skipBlanks(formula);
parsedFormula += " ";
}
}
}
// parenthesis "("
else if (currentChar(formula).equals("(")) {
parsedFormula += "(";
incrementIndex(formula);
skipBlanks(formula);
parsedFormula += " ";
F(formula);
if (!currentChar(formula).equals(")")){
throw new Exception("Error on formula " + pformula.getFormula() +" at index (" + index + ")");
}
parsedFormula += ")";
incrementIndex(formula);
if (!EOF(formula)) {
skipBlanks(formula);
parsedFormula += " ";
if (isLetter(currentChar(formula))||currentChar(formula).equals("&") || currentChar(formula).equals("|") ||
currentChar(formula).equals("-") ||currentChar(formula).equals("<")) {
parsedFormula += operator(formula);
skipBlanks(formula);
parsedFormula += " ";
F(formula);
}
else if (!currentChar(formula).equals(")")) {
throw new Exception("Error at index (" + index + ")");
}
}
}
// variable name
else {
parsedFormula += extractVar(formula, true);
skipBlanks(formula);
parsedFormula += " ";
if ( !EOF(formula) && !currentChar(formula).startsWith(")")) {
parsedFormula += operator(formula);
skipBlanks(formula);
parsedFormula += " ";
F(formula);
}
}
}
}
protected String operator(String formula) throws Exception {
int op = -1;
String opStr = "<error>";
if ( isLetter(currentChar(formula))) {
opStr = extractOperator(formula);
if ( opStr.compareToIgnoreCase("and") == 0 ) {
op = AND;
}
else if ( opStr.compareToIgnoreCase("or") == 0 ) {
op = OR;
}
else if ( opStr.compareToIgnoreCase("imp") == 0 ) {
op = IMP;
}
else if ( opStr.compareToIgnoreCase("biimp") == 0 ) {
op = BIIMP;
}
else {
throw new Exception("Error at index (" + index + ")");
}
}
else if ( currentChar(formula).startsWith("|")) {
incrementIndex(formula);
op = OR;
}
else if (currentChar(formula).startsWith("&")) {
incrementIndex(formula);
op = AND;
}
else if (currentChar(formula).startsWith("-")) {
incrementIndex(formula);
if (!currentChar(formula).startsWith(">")) {
throw new Exception("Error at index (" + index + ")");
}
incrementIndex(formula);
op = IMP;
}
else if (currentChar(formula).startsWith("<")) {
incrementIndex(formula);
if (!currentChar(formula).startsWith("-")) {
throw new Exception("Error at index (" + index + ")");
}
incrementIndex(formula);
if (!currentChar(formula).startsWith(">")) {
throw new Exception("Error at index (" + index + ")");
}
incrementIndex(formula);
op = BIIMP;
}
if ( op == -1 )
throw new Exception("Error at index (" + index + "): Invalid operator!");
return opStr;
}
private String extractOperator(String formula) {
StringBuffer opName = new StringBuffer();
if ( isLetter(currentChar(formula)) ) {
opName.append(currentChar(formula));
incrementIndex(formula);
while( !EOF(formula) && isValidChar(currentChar(formula))) {
opName.append(currentChar(formula));
incrementIndex(formula);
}
}
return opName.toString();
}
protected String extractVar(String formula, boolean varState) {
String varName = "";
if ( isLetter(currentChar(formula)) ) {
varName += currentChar(formula);
incrementIndex(formula);
while( !EOF(formula) && isValidChar(currentChar(formula))) {
varName += currentChar(formula);
incrementIndex(formula);
}
if ( replacements != null ) {
String newVarName = replacements.get(varName);
if ( newVarName != null ) {
varName = newVarName;
}
}
// pformula already prevents the inclusion of duplicates
BooleanVariable variable = new BooleanVariable(varName);
variable.setState(varState);
pformula.addVariable(variable);
}
return varName;
}
protected boolean EOF(String formula) {
if ( index >= formula.length() ) {
return true;
}
return false;
}
protected boolean isLetter(String str) {
if (letters.indexOf(str)!= -1) {
return true;
}
return false;
}
protected boolean isValidChar(String str) {
if (all.indexOf(str) != -1) {
return true;
}
return false;
}
protected void skipBlanks(String formula) {
if (!EOF(formula)) {
while (currentChar(formula).startsWith(" ")) {
incrementIndex(formula);
}
}
}
protected void incrementIndex(String formula) {
index++;
}
}
class PropositionalFormulaState {
protected int savedVariables[];
private PropositionalFormula formula;
public PropositionalFormulaState(PropositionalFormula formula) {
this.formula = formula;
}
public void save() {
int size = formula.variables.size();
savedVariables = new int[size];
for( int i = 0 ; i < size ; i++ ) {
BooleanVariable bi = formula.variables.get(i);
savedVariables[i] = bi.getValue();
}
}
public void restore() {
for( int i = 0 ; i < savedVariables.length; i++ ) {
BooleanVariable bi = formula.variables.get(i);
bi.assignValue(savedVariables[i]);
}
}
}