// Converts ADD and MUL to division. e.g., a/2+1 --> (a+2)/2 // This is called only when the expression is divisible. protected SimpleExpression toDivision() { SimpleExpression ret; if (sop == ADD) { List<SimpleExpression> converted = new LinkedList<SimpleExpression>(); for (SimpleExpression child : children) converted.add(child.toDivision()); SimpleExpression lcd = getLCD(converted); if (lcd.equals(sone)) ret = this; else { SimpleExpression dividend = szero; for (SimpleExpression child : converted) { if (child.sop == DIV) dividend = add(dividend, multiply(child.getChild(0), divide(lcd, child.getChild(1)))); else dividend = add(dividend, multiply(child, lcd)); } ret = divide(dividend, lcd); } } else if (sop == MUL) { SimpleExpression dividend = sone, divider = sone; for (SimpleExpression child : children) { if (child.sop == DIV) { dividend = multiply(dividend, child.getChild(0)); divider = multiply(divider, child.getChild(1)); } else dividend = multiply(dividend, child); } if (divider.equals(sone)) ret = this; else ret = divide(dividend, divider); } else ret = this; return ret; }
// Aggressively normalize divisible expressions to minimize ADD operations. // This method is called only by induction variable substitution where // the divisibility of an expression is defined well. protected SimpleExpression normalizeDivisible() { SimpleExpression ret = this; if (sop == DIV) { if (getChild(0).sop == DIV) ret = divide(getChild(0).getChild(0), multiply(getChild(0).getChild(1), getChild(1))); } else if (sop == MUL) { ret = toDivision().normalize(); } else if (sop == ADD) { ret = toDivision(); if (ret.sop == DIV && ret.getChild(0).sop == ADD) { SimpleExpression non_div = szero, dividend = szero; SimpleExpression divider = ret.getChild(1); for (SimpleExpression child : ret.getChild(0).children) { SimpleExpression divided = divide(child, divider); if (divided.sop == DIV) dividend = add(dividend, child); else non_div = add(non_div, divided); } if (non_div.equals(szero) && ret.countsOperations(ADD) >= countsOperations(ADD)) ret = this; // heuristics: no benefit from the simplification. else ret = add(non_div, divide(dividend, divider)); } } return ret; }
// Normalizes a MIN/MAX expression private SimpleExpression normalizeMINMAX() { // Literal/non-literal separation TreeSet<Double> literals = new TreeSet<Double>(); TreeSet<SimpleExpression> exprs = new TreeSet<SimpleExpression>(); SimpleExpression ret = new SimpleExpression(sop); for (SimpleExpression child : children) { if (child.sop == LIT) literals.add(child.getValue()); else exprs.add(child); } if (sop == MIN) ret.add(getInt(literals.first().intValue())); else ret.add(getInt(literals.last().intValue())); ret.addAll(exprs); // Quick return for single-entry min/max. if (ret.children.size() == 1) return ret.getChild(0); // Match min(a,max(a,b))=a or max(a,min(a,b))=a if (ret.sop == MIN && ret.children.size() == 2 && ret.getChild(1).sop == MAX && ret.getChild(1).children.size() == 2 && ret.getChild(1).children.contains(ret.getChild(0)) || ret.sop == MAX && ret.children.size() == 2 && ret.getChild(1).sop == MIN && ret.getChild(1).children.size() == 2 && ret.getChild(1).children.contains(ret.getChild(0))) return ret.getChild(0); return ret; }
// Returns the non-literal term in the simple expression. protected SimpleExpression getTerm() { SimpleExpression ret = null; if (sop == LIT) ret = sone; else if (sop != MUL) ret = this; else { ret = new SimpleExpression(MUL); for (SimpleExpression child : children) if (child.sop != LIT) ret.add(child); if (ret.children.size() == 0) ret = sone; else if (ret.children.size() == 1) ret = ret.getChild(0); } // Tools.printlnStatus("[TERM] "+this+" --> "+ret, 1); return ret; }
// Normalizes a MUL expression private SimpleExpression normalizeMUL() { SimpleExpression ret = this; if (allow(FOLD)) { SimpleExpression coef = sone; LinkedList<SimpleExpression> terms = new LinkedList<SimpleExpression>(); for (SimpleExpression child : children) { if (child.sop == LIT) coef = multiply(coef, child); else terms.add(child); } ret = new SimpleExpression(MUL); if (coef.equals(szero)) ret = szero; else { if (!coef.equals(sone) || terms.size() == 0) ret.add(coef); ret.addAll(terms); if (ret.children.size() == 1) ret = ret.getChild(0); } } ret = ret.distribute(); // Tools.printlnStatus("[MUL] "+this+" --> "+ret, 1); return ret; }
// Normalizes an ADD expression private SimpleExpression normalizeADD() { if (!allow(FOLD)) return this; TreeMap<SimpleExpression, SimpleExpression> terms = new TreeMap<SimpleExpression, SimpleExpression>(); for (SimpleExpression child : children) { SimpleExpression term = child.getTerm(), coef = child.getCoef(); if (terms.containsKey(term)) terms.put(term, add(terms.get(term), coef)); else terms.put(term, coef); } SimpleExpression ret = new SimpleExpression(ADD); for (SimpleExpression term : terms.keySet()) { SimpleExpression coef = terms.get(term); if (!coef.equals(szero)) ret.add((coef.equals(sone)) ? term : multiply(coef, term)); } if (ret.children.size() == 0) ret = szero; else if (ret.children.size() == 1) ret = ret.getChild(0); // Tools.printlnStatus("[ADD] "+this+" --> "+ret, 1); return ret; }
// Normalizes an AND|OR operation private SimpleExpression normalizeLogic() { if (!allow(LOGIC)) return this; TreeSet<SimpleExpression> set = new TreeSet<SimpleExpression>(children); TreeSet<SimpleExpression> neg = new TreeSet<SimpleExpression>(); SimpleExpression ret = new SimpleExpression(sop); for (SimpleExpression child : set) { if (sop == AND) { if (child.equals(szero) || neg.contains(child)) return szero; else if (child.sop != LIT) // ==LIT means non-zero literal. ret.add(child); } else // sop == OR { if ((child.sop == LIT && !child.equals(szero)) || neg.contains(child)) return sone; else if (child.sop != LIT) // ==LIT means zero literal. ret.add(child); } neg.add(child.negate()); } if (ret.children.size() == 0) // skipped literals. ret = (ret.sop == AND) ? sone : szero; else if (ret.children.size() == 1) ret = ret.getChild(0); // Tools.printlnStatus("[LOGIC] "+this+" --> "+ret, 1); return ret; }
// Computes the least common denominator of the two simple expression. private static SimpleExpression computeLCD(SimpleExpression se1, SimpleExpression se2) { SimpleExpression divider1 = sone, divider2 = sone; if (se1.sop == DIV) divider1 = se1.getChild(1); if (se2.sop == DIV) divider2 = se2.getChild(1); return computeLCM(divider1, divider2); }