package org.reprap.geometry.polygons; import java.util.ArrayList; import java.util.List; import java.util.Comparator; import java.util.Collections; import javax.print.attribute.Size2DSyntax; /** /** * @author adrian * * This is a program to automatically generate the Java for dealing with * the simplification of CSG expressions. That is to say that it generates * simplified expressions when two operands in a more complicated expression * are equal, or are complements. * */ /** * Boolean operators and similar * */ enum Bop { ZERO("zero"), ONE("one"), LEAF("leaf"), NOT("not"), LEFT("left"), RIGHT("right"), AND("and"), OR("or"), XOR("xor"); private String name; Bop(String name) { this.name = name; } public String toString() { return name; } /** * All above NOT are diadic; all including and below monadic * @return */ public boolean diadic() { return compareTo(NOT) > 0; } } /** * A single boolean variable with a name * @author ensab * */ class Variable implements Comparator { boolean bv; boolean init; String n; public Variable(String s) { init = false; n = s;} public boolean value() { if(!init) System.err.println("Variable undefined!"); return bv; } public boolean isSet() { return init; } public void set(boolean b) { bv = b; init = true;} public String name() { return n; } public void clean() { init = false; } public Variable(Variable v) { if(!v.init) System.err.println("Variable(Variable v): input Variable undefined!"); bv = v.bv; init = v.init; n = new String(v.n); } public static boolean same(Variable a, Variable b) { return(a.compare(a, b) == 0); } /** * Compare means compare the lexical order of the names. */ public final int compare(Object a, Object b) { return(((Variable)a).n.compareTo(((Variable)b).n)); } } /** * @author adrian * */ class BooleanExpression { /** * */ private BooleanExpression c1, c2; /** * */ private Bop leafOp; /** * */ private Variable leaf; /** * */ private Variable[] variables; /** * */ private int leafCount; /** * Make an expression from three variables in an array. * exp decides the expression. * @param variables * @param exp */ public BooleanExpression(Variable [] variables, int exp) { if(variables.length != 3) System.err.println("BooleanExpression(...): variable array not length 3!"); leafCount = -1; c1 = new BooleanExpression(variables[0]); if((exp & 1) == 1) c2 = new BooleanExpression(new BooleanExpression(variables[1]), new BooleanExpression(variables[2]), Bop.AND); else c2 = new BooleanExpression(new BooleanExpression(variables[1]), new BooleanExpression(variables[2]), Bop.OR); if((exp & 2) == 2) leafOp = Bop.AND; else leafOp = Bop.OR; recordVariables(); } /** * Operand and two operators * @param a * @param b * @param op */ public BooleanExpression(BooleanExpression a, BooleanExpression b, Bop op) { leafCount = -1; if(!op.diadic()) System.err.println("BooleanExpression(a, b): leaf operator or NOT!"); leafOp = op; leaf = null; c1 = a; c2 = b; recordVariables(); } /** * Monadic operator * @param a * @param op */ public BooleanExpression(BooleanExpression a, Bop op) { leafCount = -1; if(op != Bop.NOT) System.err.println("BooleanExpression(..., NOT): op not NOT!"); leafOp = op; leaf = null; c1 = a; c2 = null; recordVariables(); } /** * Variable leaf */ public BooleanExpression(Variable v) { leafCount = -1; c1 = null; c2 = null; leafOp = Bop.LEAF; leaf = v; recordVariables(); } /** * @return */ public int leafCount() { if(leafCount < 0) { if(leafOp == Bop.LEAF) // || leafOp == bop.ZERO || leafOp == bop.ONE) { leafCount = 1; } else if(leafOp == Bop.NOT) { leafCount = c1.leafCount(); } else leafCount = c1.leafCount()+c2.leafCount(); } return leafCount; } private void recordVariables() { int vc = leafCount(); variables = new Variable[vc]; int i = 0; int k; if(leafOp == Bop.LEAF) // || leafOp == bop.ZERO || leafOp == bop.ONE) variables[i++] = leaf; else if(leafOp == Bop.NOT) { for(k = 0; k < c1.variables.length; k++) variables[i++] = c1.variables[k]; } else { for(k = 0; k < c1.variables.length; k++) variables[i++] = c1.variables[k]; for(k = 0; k < c2.variables.length; k++) variables[i++] = c2.variables[k]; } } public void setAll(int i) { TableRow.setAll(variables, i); } public Variable [] getVariables() { return variables; } public int getIndex(Variable v) { for(int i = 0; i < variables.length; i++) { if(v == variables[i]) return i; } System.err.println("getIndex(): variable not found!"); return -1; } /** * @param v * @return */ public boolean value() { boolean r; switch(leafOp) { case LEAF: return leaf.value(); case ZERO: return false; case ONE: return true; case NOT: return !c1.value(); case LEFT: return c1.value(); case RIGHT: return c2.value(); case AND: r = c1.value(); return r & c2.value(); // && case OR: r = c1.value(); return r | c2.value(); // || case XOR: r = c1.value(); return r ^ c2.value(); default: System.err.println("generateValue_r: dud operator!"); } return false; } private String toJava_r(String r) { switch(leafOp) { case LEAF: return r + leaf.name(); case ZERO: return r + "RrCSG.nothing()"; case ONE: return r + "RrCSG.universe()"; case NOT: return c1.toJava_r(r) + ".complement()"; case LEFT: return c1.toJava_r(r); case RIGHT: return c2.toJava_r(r); case AND: r += "RrCSG.intersection("; r = c1.toJava_r(r) + ", "; r = c2.toJava_r(r) + ")"; return r; case OR: r += "RrCSG.union("; r = c1.toJava_r(r) + ", "; r = c2.toJava_r(r) + ")"; return r; case XOR: System.err.println("toJava(): got to an XOR..."); break; default: System.err.println("toJava(): dud operator"); } return r; } public String toJava() { String r = "r = "; return toJava_r(r) + ";"; } } /** * A row of variables in a function table, and the table value. * Also contains useful functions for variable arrays. * @author ensab * */ class TableRow implements Comparator { private Variable[] vs; private boolean b; public TableRow() { vs = null; } public TableRow(Variable[] vin, boolean bin) { vs = sort(vin); b = bin; } public int length() { return vs.length; } public boolean value() { return b; } public Variable get(int i) { return vs[i]; } public Variable[] all() { return vs; } public String toString() { String result = ""; for(int i = 0; i < vs.length; i++) result += vs[i].name() + " "; return result; } /** * Set all the variables in a list according to the corresponding * bits in an integer. * @param vs * @param v */ public static void setAll(Variable[] vars, int v) { int k = 1; for(int i = 0; i < vars.length; i++) { if((v & k) == 0) vars[i].set(false); else vars[i].set(true); k *= 2; } } /** * Remove one variable from a list to make a shorter list * @param vars * @param remove * @return */ public static Variable[] eliminateVariable(Variable[] vars, Variable remove) { Variable[] result = new Variable[vars.length - 1]; int k = 0; for(int i = 0; i < vars.length; i++) { if(vars[i] != remove) { result[k] = new Variable(vars[i]); k++; } } return result; } /** * Take a list of variables and return a copy lexically sorted by name * @param v * @return */ private static Variable[] sort(Variable[] vins) { Variable[] result = new Variable[vins.length]; for(int i = 0; i < vins.length; i++) result[i] = new Variable(vins[i]); java.util.Arrays.sort(result, new Variable("")); return result; } /** * Check if two lists of variables have the same variables in the same order * @param a * @param b */ public static boolean sameOrder(Variable [] a, Variable [] b) { if(a.length != b.length) return false; for(int i = 0; i < a.length; i++) { if(!Variable.same(a[i], b[i])) return false; } return true; } /** * Find the binary number represented by the list * @param a * @return */ public int number() { int result = 0; for(int i = length() - 1; i >= 0; i--) { if(get(i).value()) result |= 1; result = result << 1; } return result; } /** * Compare the binary numbers represented by two lists * @param a * @param b */ public final int compare(Object a, Object b) { int va = ((TableRow)a).number(); int vb = ((TableRow)b).number(); if(va < vb) return -1; else if(va > vb) return 1; return 0; } } /** * @author adrian * */ class FunctionTable { /** * */ List<TableRow> rows; /** * */ boolean allFalse, allTrue; /** * */ public FunctionTable() { rows = new ArrayList<TableRow>(); allFalse = true; allTrue = true; } /** * Add a new row to the function table * @param v * @param b */ public void addRow(Variable[] v, boolean b) { if(b) allFalse = false; else allTrue = false; TableRow newOne = new TableRow(v, b); // Check that each has the same variables as the first if(rows.size() > 0) { if(!TableRow.sameOrder(newOne.all(), rows.get(0).all())) System.err.println("FunctionTable.addRow() - variable lists different!"); } rows.add(newOne); } public void tableCheck() { // Check we have the right number of entries int vars = rows.get(0).all().length; int leng = 1; for(int j = 0; j < vars; j++) leng *= 2; if(leng != rows.size()) System.err.println("FunctionTable.tableCheck() - incorrect entry count: " + rows.size() + "(should be " + leng + ")"); Collections.sort(rows, new TableRow()); for(int i = 1; i < rows.size(); i++) if(rows.get(i-1).number() == rows.get(i).number()) System.err.println("FunctionTable.tableDone() - identical rows: " + rows.get(i-1).toString() + rows.get(i).toString()); } /** * @param b */ public FunctionTable(BooleanExpression b) { this(); int i; int inputs = b.leafCount(); int entries = 1; for(i = 0; i < inputs; i++) entries *= 2; for(i = 0; i < entries; i++) { b.setAll(i); addRow(b.getVariables(), b.value()); } tableCheck(); } /** * @param b * @param a * @param equal_a */ public FunctionTable(BooleanExpression b, Variable v, Variable equal_v, boolean opposite) { this(); int i; int inputs = b.leafCount() - 1; int entries = 1; for(i = 0; i < inputs; i++) entries *= 2; for(i = 0; i < entries*2; i++) { b.setAll(i); if(opposite ^ (equal_v.value() == v.value())) addRow(TableRow.eliminateVariable(b.getVariables(), equal_v), b.value()); } tableCheck(); } public boolean allOnes() { return allTrue;} public boolean allZeros() { return allFalse;} public int entries() { return rows.size(); } /** * @param a * @param b * @return */ static boolean same(FunctionTable a, FunctionTable b) { if(!TableRow.sameOrder(a.rows.get(0).all(), b.rows.get(0).all())) return false; if(a.entries() != b.entries()) return false; if(a.allFalse && b.allFalse) return true; if(a.allTrue && b.allTrue) return true; for(int i = 0; i < a.entries(); i++) if(a.rows.get(i).value() != b.rows.get(i).value()) return false; return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { String result = "\n\t// " + rows.get(0).toString(); for(int i = 0; i < entries(); i++) { TableRow tr = rows.get(i); Variable[] vs = tr.all(); result += "\n\t// "; for(int j = 0; j < vs.length; j++) { if(vs[j].value()) result += "1 "; else result += "0 "; } result += "| "; if(tr.value()) result += "1 "; else result += "0 "; } return result; } } /** * @author adrian * */ public class CodeGenerator { static BooleanExpression findEqualTwo(FunctionTable f, Variable a, Variable b) { Bop[] bopValues = Bop.values(); for(int i = 0; i < bopValues.length; i++) { if(bopValues[i].diadic()) { BooleanExpression be = new BooleanExpression(new BooleanExpression(a), new BooleanExpression(b), bopValues[i]); FunctionTable g = new FunctionTable(be); if(FunctionTable.same(f, g)) return be; BooleanExpression bf = new BooleanExpression(be, Bop.NOT); g = new FunctionTable(bf); if(FunctionTable.same(f, g)) return bf; BooleanExpression bg = new BooleanExpression(new BooleanExpression(new BooleanExpression(a), Bop.NOT), new BooleanExpression(b), bopValues[i]); g = new FunctionTable(bg); if(FunctionTable.same(f, g)) return bg; BooleanExpression bh = new BooleanExpression(new BooleanExpression(a), new BooleanExpression(new BooleanExpression(b),Bop.NOT), bopValues[i]); g = new FunctionTable(bh); if(FunctionTable.same(f, g)) return bh; BooleanExpression bi = new BooleanExpression(new BooleanExpression(new BooleanExpression(a), Bop.NOT), new BooleanExpression(new BooleanExpression(b),Bop.NOT), bopValues[i]); g = new FunctionTable(bi); if(FunctionTable.same(f, g)) return bi; } } return null; } private static void oneCase3(Variable [] variables, int exp, int j, int k, boolean opposite, boolean fts) { BooleanExpression a = new BooleanExpression(variables, exp); // FunctionTable tt = new FunctionTable(a); // System.out.println(tt.toString()+"\n\n"); FunctionTable f = new FunctionTable(a, variables[j], variables[k], opposite); // int jj = j; // int kk = 3-(j+k); // if(jj > kk) // { // int swp = kk; // kk = jj; // jj = swp; // } BooleanExpression g = findEqualTwo(f, variables[j], variables[3-(j+k)]); int caseVal = 0; if(opposite) caseVal |= 1; if(j == 1) caseVal |= 2; if(k == 2) caseVal |= 4; caseVal |= exp << 3; System.out.println("\tcase " + caseVal + ": "); if(fts) { System.out.println("\t// " + a.toJava()); System.out.print("\t// " + variables[j].name() + " = "); if(opposite) System.out.print("!"); System.out.println(variables[k].name() + " ->"); System.out.println(f.toString()); } if(g != null || f.allOnes() || f.allZeros()) { if(f.allOnes()) System.out.println("\t\tr = RrCSG.universe();"); else if(f.allZeros()) System.out.println("\t\tr = RrCSG.nothing();"); else System.out.println("\t\t" + g.toJava()); // if(g != null && fts) // { // FunctionTable h = new FunctionTable(g); // System.out.println(h.toString()); // } } else System.out.println("\t\t// No equivalence." + "\n"); System.out.println("\t\tbreak;\n"); } private static void allCases(Variable [] variables) { for(int exp = 0; exp < 4; exp++) { for(int j = 0; j < 2; j++) for(int k = j+1; k < 3; k++) { oneCase3(variables, exp, j, k, false, true); oneCase3(variables, exp, j, k, true, true); } } } /** * @param args */ public static void main(String[] args) { Variable [] variables = new Variable[3]; variables[0] = new Variable("a"); variables[1] = new Variable("b"); variables[2] = new Variable("c"); //variables[3] = new variable("d"); //oneCase3(variables, 2, 0, 2, false, true); allCases(variables); } }