protected ASTNode internalReduce(ASTNode term, final IExpressionContext context) { final ASTNode result = term.createCopy(true); final MutatingNodeVisitor visitor = new MutatingNodeVisitor(context) { @Override public void visit(ASTNode node, IExpressionContext context, IIterationContext it) { if (node.hasParent()) { if (node instanceof IdentifierNode && !node.hasLiteralValue(context)) { return; } final ASTNode reduced = node.evaluate(context); debugPrintln("REDUCE: " + node + " evaluates to " + reduced); if (reduced != null && reduced != node && reduced != unwrap(node)) { debugPrintln("REDUCE: Replacing " + node + " -> " + reduced); node.replaceWith(reduced); it.astMutated(); it.stop(); } } } }; applyPostOrder(result, visitor); return result; }
public ASTNode substituteCommonTerms(ASTNode tree, IExpressionContext context) { ASTNode copy = tree.createCopy(true); final Map<Integer, List<ASTNode>> result = new HashMap<>(); final INodeVisitor visitor = new INodeVisitor() { @Override public boolean visit(ASTNode node, int currentDepth) { final Integer hash = node.hashCode(); List<ASTNode> existing = result.get(hash); if (existing == null) { existing = new ArrayList<>(); result.put(hash, existing); } existing.add(node); return true; } }; tree.visitInOrder(visitor); outer: for (Map.Entry<Integer, List<ASTNode>> entry : result.entrySet()) { final int hash = entry.getKey(); if (entry.getValue().size() <= 1) { continue; } for (ASTNode n : entry.getValue()) { if (n instanceof IdentifierNode) { continue outer; } } // create new variable final ASTNode value = entry.getValue().get(0).createCopy(true); final Identifier identifier = context.createIdentifier(value); final boolean substituted = replaceMatchingTermsWithVariable(context, copy, hash, identifier); if (substituted) { debugPrintln( "SUBSTITUTE: " + value + " => " + identifier + " ( " + entry.getValue().size() + " times )"); } else { context.remove(identifier); } } return copy; }
public ASTNode substituteIdentifiers(ASTNode input, IExpressionContext context) { ASTNode result = input.createCopy(true); final MutatingNodeVisitor visitor = new MutatingNodeVisitor(context) { @Override protected void visit(ASTNode node, IExpressionContext context, IIterationContext it) { if (node instanceof IdentifierNode) { Identifier id = ((IdentifierNode) node).getIdentifier(); ASTNode value = context.tryLookup(id); if (value != null) { node.replaceWith(value); it.astMutated(); } } } }; applyInOrder(result, visitor); return result; }
public ASTNode expand(ASTNode term, IExpressionContext context, boolean deleteExpandedVars) { final ASTNode result = term.createCopy(true); final Set<Identifier> expandedIdentifiers = new HashSet<>(); boolean expanded = false; do { expanded = false; final MutatingNodeVisitor visitor = new MutatingNodeVisitor(context) { @Override public void visit(ASTNode node, IExpressionContext context, IIterationContext it) { final ASTNode unwrapped = unwrap(node); if (node.hasParent() && unwrapped instanceof IdentifierNode) { final ASTNode expanded = unwrapped.evaluate(context); if (expanded != null && expanded != unwrapped) { debugPrintln("EXPAND: Expanding " + node + " -> " + expanded); expandedIdentifiers.add(((IdentifierNode) unwrapped).getIdentifier()); node.replaceWith(expanded); it.astMutated(); } } } }; expanded = applyPostOrder(result, visitor); } while (expanded); if (deleteExpandedVars) { for (Identifier id : expandedIdentifiers) { context.remove(id); } } return result; }
protected ASTNode simplifyTerm(ASTNode term, final IExpressionContext context) { debugPrintln("Simplifying " + term.toString(true)); final Comparator<ASTNode> comp = new Comparator<ASTNode>() { @Override public int compare(ASTNode o1, ASTNode o2) { if (o1.isLeafNode() && o2.isLeafNode()) { return o2.toString().compareTo(o1.toString()); } else if (o1.isLeafNode()) { return 1; } else if (o2.isLeafNode()) { return -1; } return 0; } }; ASTNode result = term.createCopy(true); result = reduce(result, context); int loopCounter = 0; boolean simplified = result.sortChildrenAscending(comp); do { simplified = false; // Assoziativgesetz // (a and b) and c = a and (b and c) // (a or b) or c = a or (b or c) simplified |= applyLawOfAssociativity(context, result); // Idempotenzgesetze: => x and x = x // => x or x = x simplified |= applyLawOfIdemPotency(context, result); // double negation: => not( not a) = a simplified |= applyRuleOfDoubleNegation(context, result); // Neutralitätsgesetze => a and 1 = a // => a or 0 = a simplified |= applyLawOfIdentity(context, result); // Extremalgesetze => a and 0 =0 // => a or 1 =1 simplified |= applyLawOfExtrema(context, result); // Komplementärgesetze => a and not a = 0 // => a or not a = 1 simplified |= applyLawOfComplements(context, result); // Absorptionsgesetze => a or (a and b) = a // => a and(a or b) = a simplified |= applyLawOfAbsorption(context, result); // Distributionsgesetz // a and (b or c) = (a and b) or (a and c) // a or (b and c) = (a or b) and (a or c) simplified |= applyDistributiveLaw(context, result); // De Morgansche Gesetze => not(a and b) = not a or not b // => not(a or b) = not a and not b simplified = applyLawOfDeMorgan(context, result); // De Morgansche Gesetze => not a or not b = not(a and b) // => not a and not b = not(a or b) // simplified |= applyInverseLawOfDeMorgan(context,result); loopCounter++; } while (simplified || loopCounter < 2); // get rid of all variables we eliminated context.retainOnly(gatherIdentifiers(result)); return result; }