package agg.cons;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import agg.util.Pair;
import agg.xt_basis.Arc;
import agg.xt_basis.Graph;
import agg.xt_basis.Node;
import agg.xt_basis.Type;
import agg.xt_basis.TypeException;
import agg.xt_basis.TypeSet;
/**
* This is a help class which can be used to define a boolean formula above some evaluable objects.
* An evaluable object can be a graph constraint or a rule application condition.
* They are the variables of a boolean formula.
* The possible operations are: AND, OR, NOT, FORALL.
* (FORALL is allowed for the rule application conditions only).<br>
*
* In this class a formula is represented by a binary tree graph.
* The nodes are operations or names of the evaluable objects.
* The edges connect the nodes of a tree graph.<br>
*
* An example how to use:<br>
* <br>
* FormulaGraph fg = new FormulaGraph();<br>
* Node op = fg.setTop("AND");<br>
* Node n1 = fg.connectAt(op, "AC1");<br>
* op = fg.connectAt(op, "OR");<br>
* fg.connectAt(op, "AC2");<br>
* fg.connectAt(op, "AC3");<br>
* fg.graph2formula();<br>
* System.out.println("String by indx : "+fg.getFormulaTextByIndex());<br>
* System.out.println("String by name : "+fg.getFormulaTextByName());<br>
* <br>
* Another possibility is to use the method <br>
* <code>fg.connectAt(op, "AC1", evaluableObj);</code><br>
* where an Evaluable object should be defined. <br>
* <code>fg.getFormula()</code> returns created Formula object.
*
* @author olga
*
*/
public class FormulaGraph {
public static final String AND = "AND";
public static final String OR = "OR";
public static final String NOT = "NOT";
public static final String FORALL = "FORALL";
List<Evaluable> evals = new Vector<Evaluable>();
List<String> vars = new Vector<String>();
Formula formula;
String fStr, fNameStr;
Graph g;
Type not, and, or, forall, connectAt, refinedBy;
Node top;
final HashMap<String,Type> name2type = new HashMap<String,Type>();
final HashMap<String,Integer> name2indx = new HashMap<String,Integer>();
public FormulaGraph() {
this.g = new Graph();
createDefaultTypes(this.g.getTypeSet());
}
/*
public FormulaGraph(List<Evaluable> evalObjs) {
this();
this.evals = evalObjs;
if (this.evals != null) {
this.vars = new Vector<String>();
for (int i=0; i<this.evals.size(); i++) {
this.vars.add(String.valueOf(i+1));
}
this.createTypes(this.vars);
}
}
public FormulaGraph(List<Evaluable> evalObjs, List<String> objNames) {
this();
this.evals = evalObjs;
this.vars = objNames;
if (this.vars != null) {
this.createTypes(this.vars);
}
if (this.evals != null) {
this.vars = new Vector<String>();
for (int i=0; i<this.evals.size(); i++) {
this.vars.add(String.valueOf(i+1));
}
this.createTypes(this.vars);
}
}
*/
private void createDefaultTypes(final TypeSet types) {
// TODO create TRUE and FALSE node types
// create node types which represent operators of a formula
this.not = types.createNodeType(false);
this.not.setStringRepr(FormulaGraph.NOT);
//EditorConstants.ROUNDRECT, Color.RED);
this.not.setAdditionalRepr(":ROUNDRECT:java.awt.Color[r=255,g=0,b=0]::[NODE]:");
this.name2type.put(FormulaGraph.NOT, this.not);
this.and = types.createNodeType(false);
this.and.setStringRepr(FormulaGraph.AND);
//EditorConstants.ROUNDRECT, Color.BLACK);
this.and.setAdditionalRepr(":ROUNDRECT:java.awt.Color[r=0,g=0,b=0]::[NODE]:");
this.name2type.put(FormulaGraph.AND, this.and);
this.or = types.createNodeType(false);
this.or.setStringRepr(FormulaGraph.OR);
//EditorConstants.ROUNDRECT, Color.BLACK);
this.or.setAdditionalRepr(":ROUNDRECT:java.awt.Color[r=0,g=0,b=0]::[NODE]:");
this.name2type.put(FormulaGraph.OR, this.or);
this.forall = types.createNodeType(false);
this.forall.setStringRepr(FormulaGraph.FORALL);
//EditorConstants.ROUNDRECT, Color.BLACK);
this.forall.setAdditionalRepr(":ROUNDRECT:java.awt.Color[r=0,g=0,b=0]::[NODE]:");
this.name2type.put(FormulaGraph.FORALL, this.forall);
// create an edge type to connect nodes
this.connectAt = types.createArcType(false);
//EditorConstants.SOLID, Color.BLACK);
this.connectAt.setAdditionalRepr(":SOLID_LINE:java.awt.Color[r=0,g=0,b=0]::[EDGE]:");
// create an edge type to refine nodes
this.refinedBy = types.createArcType(false);
//EditorConstants.SOLID, Color.BLUE);
this.refinedBy.setAdditionalRepr(":SOLID_LINE:java.awt.Color[r=0,g=0,b=255]::[EDGE]:");
}
/**
* Returns the graph.
*/
public Graph getGraph() {
return this.g;
}
/**
* Returns the generated Formula instance or null.
*/
public Formula getFormula() {
return this.formula;
}
/**
* Returns a formula string containing indexes of variables (not the names!).
* This formula string can be used to create a new Formula instance.
*/
public String getFormulaTextByIndex() {
if ("".equals(this.fStr))
return "true";
else
return this.fStr;
}
/**
* Returns a formula string containing names of variables.
* Please note: This formula string can not be used
* to create a new Formula instance.
* Use method <code>getFormulaTextByIndex()</code>.
*/
public String getFormulaTextByName() {
if ("".equals(this.fStr))
return "true";
else
return this.fNameStr;
}
/**
* Set and returns the top object of the graph.
* The given String name is the name of an operation or an <code>Evaluable</code> object.<br>
* An operation is: <br>
* FormulaGraph.AND | FormulaGraph.OR | FormulaGraph.NOT | FormulaGraph.FORALL
*/
public Node setTop(final String name) {
Type t = getNodeType(name);
if (t != null) {
try {
this.top = this.g.createNode(t);
return this.top;
} catch (TypeException ex) {}
}
return null;
}
/**
* Set and returns the top object of the graph.
* The given String name is the name of an operation or an <code>Evaluable</code> object.
* In case of an operation the <code>Evaluable</code> object will be ignored.
* An operation is: <br>
* FormulaGraph.AND | FormulaGraph.OR | FormulaGraph.NOT | FormulaGraph.FORALL
*/
public Node setTop(final String name, final Evaluable obj) {
Type t = getNodeType(name);
if (t != null) {
try {
this.top = this.g.createNode(t);
if (obj != null && !this.isOpType(t)) {
this.evals.add(obj);
}
return this.top;
} catch (TypeException ex) {}
}
return null;
}
/**
* Adds and returns a new node of the graph.
* The given String name is the name of an operation or an <code>Evaluable</code> object.<br>
* A new node is connected to the specified Node node.
*/
public Node connectAt(final Node node, final String name) {
Node n = null;
if (node != null) {
Type t = getNodeType(name);
try {
n = this.g.createNode(t);
this.g.createArc(this.connectAt, node, n);
} catch (TypeException ex) {
System.out.println(ex.getLocalizedMessage());
}
}
return n;
}
/**
* Adds and returns a new node of the graph.
* The given String name is the name of an operation or an <code>Evaluable</code> object.<br>
* In case of an operation the <code>Evaluable</code> object will be ignored.
* A new node is connected to the specified Node node.
*/
public Node connectAt(final Node node, final String name, final Evaluable obj) {
Node n = null;
if (node != null) {
Type t = getNodeType(name);
try {
n = this.g.createNode(t);
this.g.createArc(this.connectAt, node, n);
if (obj != null && !this.isOpType(t)) {
this.evals.add(obj);
}
} catch (TypeException ex) {
System.out.println(ex.getLocalizedMessage());
}
}
return n;
}
/**
* Updates the formula string and object representation of the formula graph.
* It has to be called before calling
* <code>getFormulaTextByIndex()</code>,
* <code>getFormulaTextByName()</code>,
* <code>getFormula</code>.
*/
public void graph2formula() {
if (this.top != null) {
Pair<String,String> p = graph2text(this.top);
this.fNameStr = p.first;
this.fStr = p.second;
if (this.evals.size() > 0)
this.formula = new Formula(this.evals, p.second);
}
}
private Type getNodeType(final String name) {
Type t = this.name2type.get(name);
if (t == null) {
t = this.createType(name);
}
return t;
}
private Type createType(final String name) {
Type t = this.g.getTypeSet().createNodeType(false);
t.setStringRepr(name);
t.setAdditionalRepr(":RECT:java.awt.Color[r=0,g=0,b=0]::[NODE]:");
this.name2type.put(name, t);
this.vars.add(name);
this.name2indx.put(name, this.vars.size());
return t;
}
/*
private void createTypes(List<String> vars) {
for (int i=0; i<vars.size(); i++) {
String name = vars.get(i);
Type t = this.name2type.get(name);
if (t == null) {
t = this.createType(name);
}
}
}
*/
/**
* Converts recursively its graph to a formula string.<br>
* Result pair of strings contains two representations:
* the first string contains the names,
* the second string - the indexes of the variables.
* The start node has to be the top node of the graph.
*/
private Pair<String,String> graph2text(final Node n) {
Node n1 = null;
String s1 = "";
String s2 = "";
int c = n.getNumberOfOutgoingArcs();
switch (c) {
case 0:
s1 = n.getType().getName();
if (this.name2indx.get(n.getType().getName()) != null) {
s2 = String.valueOf(this.name2indx.get(n.getType().getName()).intValue());
} else {
s2 = n.getType().getName();
}
break;
case 1:
if (n.getOutgoingArcs().next().getContextUsage() == -1) {
s1 = n.getType().getName();
if (this.name2indx.get(n.getType().getName()) != null) {
s2 = String.valueOf(this.name2indx.get(n.getType().getName()).intValue());
} else {
s2 = n.getType().getName();
}
break;
}
n1 = (Node)n.getOutgoingArcs().next().getTarget();
if (n.getType().getName().equals("NOT")) {
Pair<String,String> p = graph2text(n1);
s1 = " !"+p.first;
s2 = " !"+p.second;
}
else if (n.getType().getName().equals("FORALL")) {
Pair<String,String> p1 = graph2text(n1);
s1 = " FORALL"+"("+p1.first+")";
s2 = " A"+"("+p1.second+")";
}
else {
Pair<String,String> p = graph2text(n1);
s1 = n.getType().getName()+"("+p.first+")";
s2 = n.getType().getName()+"("+p.second+")";
}
break;
case 2:
Iterator<Arc> outs = n.getOutgoingArcs();
n1 = (Node)outs.next().getTarget();
Node n2 = (Node)outs.next().getTarget();
if (n.getType().getName().equals("AND")) {
Pair<String,String> p1 = graph2text(n1);
Pair<String,String> p2 = graph2text(n2);
s1 = "("+p1.first+" & "+p2.first+")";
s2 = "("+p1.second+" & "+p2.second+")";
}
else if (n.getType().getName().equals("OR")) {
Pair<String,String> p1 = graph2text(n1);
Pair<String,String> p2 = graph2text(n2);
s1 = "("+p1.first+" | "+p2.first+")";
s2 = "("+p1.second+" | "+p2.second+")";
}
break;
}
return new Pair<String,String>(s1, s2);
}
// private Node refineBy(final Node node, final String name) {
// Node n = null;
// if (node != null) {
// Type t = getNodeType(name);
// if (!isOpType(t)) {
// try {
// n = this.g.createNode(t);
// this.g.createArc(this.refType, node, n);
// } catch (TypeException ex) {}
// }
// }
// return n;
// }
private boolean isOpType(final Type t) {
return (t == this.and || t == this.or
|| t == this.not || t == this.forall)? true : false;
}
/*
public static void main(String argv[]) {
List<Evaluable> evalTest = new Vector<Evaluable>();
evalTest.add(new AtomTest(1)); evalTest.add(new AtomTest(3));
evalTest.add(new AtomTest(2)); evalTest.add(new AtomTest(4));
FormulaGraph fg = new FormulaGraph();
Node op = fg.setTop("AND");
Node n1 = fg.connectAt(op, "AC1");
op = fg.connectAt(op, "OR");
n1 = fg.connectAt(op, "AC2");
op = fg.connectAt(op, "AND");
fg.connectAt(op, "AC3");
fg.connectAt(op, "AC4");
// test with evaluable objects
// Node n1 = fg.connectAt(op, "AC1", evalTest.get(0));
// op = fg.connectAt(op, "OR");
// n1 = fg.connectAt(op, "AC2", evalTest.get(1));
// op = fg.connectAt(op, "AND");
// fg.connectAt(op, "AC3", evalTest.get(2));
// fg.connectAt(op, "AC4", evalTest.get(3));
System.out.println(fg.g.showGraph());
fg.graph2formula();
if (fg.formula != null)
System.out.println("Formula (valid) : "+fg.formula.isValid()+" "+fg.formula);
System.out.println("by indx : "+fg.getFormulaTextByIndex());
System.out.println("by name : "+fg.getFormulaTextByName());
}
static class AtomTest implements Evaluable {
int val;
public AtomTest(int i) {
this.val = i;
}
public boolean eval(java.lang.Object o) {
return this.val % 4 == 0;
}
public boolean eval(java.lang.Object o, int tick) {
return tick % 4 == 0;
}
public boolean eval(java.lang.Object o, boolean negaition) {
return this.val % 4 == 0;
}
public boolean eval(java.lang.Object o, int tick, boolean negaition) {
return tick % 4 == 0;
}
public boolean evalForall(Object o, int tick) {
return false;
}
}
*/
}