protected static ASTNode unwrap(ASTNode node) {
   ASTNode result = node;
   while (result instanceof TermNode && result.hasChildren()) {
     result = result.child(0);
   }
   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;
  }
Example #3
0
  public void testParsing() {

    String expr = "  a   or   not  ((  b  and  c ) or d)  =  e   ";

    ASTNode expression = new BooleanExpressionParser().parse(expr, false);

    System.out.println("PARSED: " + expression);

    PrintWriter writer = new PrintWriter(System.out, true);
    expression.print(writer);
    writer.flush();
    writer.close();
    assertEquals("a OR NOT ((b AND c) OR d) = e", expression.toString());
  }
  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 void moveToTopLevel(ASTNode nodeToMove) {

    final List<ASTNode> pathFromRoot = nodeToMove.getPathFromRoot();
    final ASTNode root = pathFromRoot.get(0);
    if (root == nodeToMove || pathFromRoot.size() == 2 && pathFromRoot.get(0) instanceof TermNode) {
      return; // nothing to do, already at top-level
    }

    /*
     *  Task: isolate d
     *
     * Initial term: (a or b) and (c or d) = true
     *
     * Step 1: align associated operator (OR) with outer expression so we can re-order the AST nodes
     *
     * => (a or b) and (not(c) and not(d) ) = true // de-morgan
     *
     * =>(a or b) and not(c) and not(d) = true
     *
     * =>  d or ( (a or b) and not(c) and not(d) )  = d or true
     *
     * => * => AND
     *    + => OR
     *
     *    d + ( ( a + b ) * not(c) * not(d) ) = d + true
     *
     * => d OR (a OR b) AND (d OR NOT (c)) AND (d OR NOT (d)) = d or true
     *
     * =>
     */

    /*
       //  a or  (b and c) = (a or  b) and (a or  c)
    */
  }
  public Set<Identifier> gatherIdentifiers(ASTNode node) {
    final Set<Identifier> result = new HashSet<Identifier>();
    INodeVisitor visitor =
        new INodeVisitor() {

          @Override
          public boolean visit(ASTNode node, int currentDepth) {
            if (node instanceof IdentifierNode) {
              result.add(((IdentifierNode) node).getIdentifier());
            }
            return true;
          }
        };
    node.visitInOrder(visitor);
    return result;
  }
  public Boolean isTrue(BooleanExpression expr, IExpressionContext context) {

    ASTNode lhs = expr.getLHS();
    ASTNode rhs = expr.getRHS();

    ASTNode value1 = lhs.evaluate(context);
    ASTNode value2 = rhs.evaluate(context);
    if (value1 != null && value2 != null) {
      return value1.isEquivalent(value2, context);
    }
    return null;
  }
  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 static boolean applyPreOrder(ASTNode term, MutatingNodeVisitor visitor) {
   do {
     term.visitPreOrder(visitor);
   } while (visitor.isASTMutated());
   return visitor.getMutationCount() > 0;
 }
  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;
  }
 protected ASTNode maybeWrapInTerm(ASTNode node) {
   if (node.getNodeCount() == 1) {
     return node;
   }
   return new TermNode(node);
 }
 private static boolean isNonTrivialTerm(ASTNode node) {
   return node instanceof TermNode && !node.child(0).isLeafNode();
 }