Formula.java :  » Code-Analyzer » javapathfinder » gov » nasa » ltl » trans » Java Open Source

Java Open Source » Code Analyzer » javapathfinder 
javapathfinder » gov » nasa » ltl » trans » Formula.java

//
// Copyright (C) 2005 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA).  All Rights Reserved.
// 
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3.  The NOSA has been approved by the Open Source
// Initiative.  See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
// 
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//

// Written by Dimitra Giannakopoulou, 19 Jan 2001
// Parser by Flavio Lerda, 8 Feb 2001
// Parser extended by Flavio Lerda, 21 Mar 2001
// Modified to accept && and || by Roby Joehanes 15 Jul 2002
package gov.nasa.ltl.trans;

import java.util.*;


/**
 * DOCUMENT ME!
 */
public class Formula implements Comparable {
  private static int       nId = 0;
  private static final int P_ALL = 0;
  private static final int P_IMPLIES = 1;
  private static final int P_OR = 2;
  private static final int P_AND = 3;
  private static final int P_UNTIL = 4;
  private static final int P_WUNTIL = 4;
  private static final int P_RELEASE = 5;
  private static final int P_WRELEASE = 5;
  private static final int P_NOT = 6;
  private static final int P_NEXT = 6;
  private static final int P_ALWAYS = 6;
  private static final int P_EVENTUALLY = 6;
  private static Hashtable ht = new Hashtable();
  private static Hashtable matches = new Hashtable();
  private char             content;
  private boolean          literal;
  private Formula          left;
  private Formula          right;
  private int              id;
  private int              untils_index; // index to the untils vector
  private BitSet           rightOfWhichUntils; // for bug fix - formula can be right of >1 untils
  private String           name;
  private boolean          has_been_visited;

  private Formula (char c, boolean l, Formula sx, Formula dx, String n) {
    id = nId++;
    content = c;
    literal = l;
    left = sx;
    right = dx;
    name = n;
    rightOfWhichUntils = null;
    untils_index = -1;
    has_been_visited = false;
  }

  public static boolean is_reserved_char (char ch) {
    switch (ch) {
    //    case 't':
    //    case 'f':
    case 'U':
    case 'V':
    case 'W':
    case 'M':
    case 'X':
    case ' ':
    case '<':
    case '>':
    case '(':
    case ')':
    case '[':
    case ']':
    case '-':

      // ! not allowed by Java identifiers anyway - maybe some above neither?
      return true;

    default:
      return false;
    }
  }

  public static void reset_static () {
    clearMatches();
    clearHT();
  }

  public char getContent () {
    return content;
  }

  public String getName () {
    return name;
  }

  public Formula getNext () {
    switch (content) {
    case 'U':
    case 'W':
      return this;

    case 'V':
      return this;

    case 'O':
      return null;

    default:

      //    System.out.println(content + " Switch did not find a relevant case...");
      return null;
    }
  }

  public Formula getSub1 () {
    if (content == 'V') {
      return right;
    } else {
      return left;
    }
  }

  public Formula getSub2 () {
    if (content == 'V') {
      return left;
    } else {
      return right;
    }
  }

  public void addLeft (Formula l) {
    left = l;
  }

  public void addRight (Formula r) {
    right = r;
  }

  public int compareTo (Object f) {
    Formula ff = (Formula) f;

    return (this.id - ff.id);
  }

  public int countUntils (int acc_sets) {
    has_been_visited = true;

    if (getContent() == 'U') {
      acc_sets++;
    }

    if ((left != null) && (!left.has_been_visited)) {
      acc_sets = left.countUntils(acc_sets);
    }

    if ((right != null) && (!right.has_been_visited)) {
      acc_sets = right.countUntils(acc_sets);
    }

    return acc_sets;
  }

  public BitSet get_rightOfWhichUntils () {
    return rightOfWhichUntils;
  }

  public int get_untils_index () {
    return untils_index;
  }

  public int initialize () {
    int acc_sets = countUntils(0);
    reset_visited();

    //  System.out.println("Number of Us is: " + acc_sets);
    int test = processRightUntils(0, acc_sets);
    reset_visited();

    //  System.out.println("Number of Us is: " + test);
    return acc_sets;
  }

  public boolean is_literal () {
    return literal;
  }

  public boolean is_right_of_until (int size) {
    return (rightOfWhichUntils != null);
  }

  public boolean is_special_case_of_V (TreeSet check_against) {
    Formula form = (Release(False(), this));

    if (check_against.contains(form)) {
      return true;
    } else {
      return false;
    }
  }

  public boolean is_synt_implied (TreeSet old, TreeSet next) {
    if (this.getContent() == 't') {
      return true;
    }

    if (old.contains(this)) {
      return true;
    }

    if (!is_literal()) // non-elementary formula
    {
      Formula form1 = this.getSub1();
      Formula form2 = this.getSub2();
      Formula form3 = this.getNext();

      boolean condition1;
      boolean condition2;
      boolean condition3;

      if (form2 != null) {
        condition2 = form2.is_synt_implied(old, next);
      } else {
        condition2 = true;
      }

      if (form1 != null) {
        condition1 = form1.is_synt_implied(old, next);
      } else {
        condition1 = true;
      }

      if (form3 != null) {
        if (next != null) {
          condition3 = next.contains(form3);
        } else {
          condition3 = false;
        }
      } else {
        condition3 = true;
      }

      switch (getContent()) {
      case 'U':
      case 'W':
      case 'O':
        return (condition2 || (condition1 && condition3));

      case 'V':
        return ((condition1 && condition2) || (condition1 && condition3));

      case 'X':

        if (form1 != null) {
          if (next != null) {
            return (next.contains(form1));
          } else {
            return false;
          }
        } else {
          return true;
        }

      case 'A':
        return (condition2 && condition1);

      default:
        System.out.println("Default case of switch at Form.synt_implied");

        return false;
      }
    } else {
      return false;
    }
  }

  public Formula negate () {
    return Not(this);
  }

  public static Formula parse (String str) throws ParseErrorException { // "aObAc"

    Input i = new Input(str);

    return parse(i, P_ALL);
  }

  public int processRightUntils (int current_index, int acc_sets) {
    has_been_visited = true;

    if (getContent() == 'U') {
      this.untils_index = current_index;

      if (right.rightOfWhichUntils == null) {
        right.rightOfWhichUntils = new BitSet(acc_sets);
      }

      right.rightOfWhichUntils.set(current_index);
      current_index++;
    }

    if ((left != null) && (!left.has_been_visited)) {
      current_index = left.processRightUntils(current_index, acc_sets);
    }

    if ((right != null) && (!right.has_been_visited)) {
      current_index = right.processRightUntils(current_index, acc_sets);
    }

    return current_index;
  }

  public void reset_visited () {
    has_been_visited = false;

    if (left != null) {
      left.reset_visited();
    }

    if (right != null) {
      right.reset_visited();
    }
  }

  public Formula rewrite (Formula rule, Formula rewritten) {
    switch (content) {
    case 'A':
    case 'O':
    case 'U':
    case 'V':
    case 'W':
      left = left.rewrite(rule, rewritten);
      right = right.rewrite(rule, rewritten);

      break;

    case 'X':
    case 'N':
      left = left.rewrite(rule, rewritten);

      break;

    case 't':
    case 'f':
    case 'p':
      break;
    }

    if (match(rule)) {
      Formula expr = rewritten.rewrite();

      clearMatches();

      return expr;
    }

    clearMatches();

    return this;
  }

  public int size () {
    switch (content) {
    case 'A':
    case 'O':
    case 'U':
    case 'V':
    case 'W':
      return left.size() + right.size() + 1;

    case 'X':
    case 'N':
      return left.size() + 1;

    default:
      return 0;
    }
  }

  public String toString (boolean exprId) {
    if (!exprId) {
      return toString();
    }

    switch (content) {
    case 'A':
      return "( " + left.toString(true) + " /\\ " + right.toString(true) + 
             " )[" + id + "]";

    case 'O':
      return "( " + left.toString(true) + " \\/ " + right.toString(true) + 
             " )[" + id + "]";

    case 'U':
      return "( " + left.toString(true) + " U " + right.toString(true) + 
             " )[" + id + "]";

    case 'V':
      return "( " + left.toString(true) + " V " + right.toString(true) + 
             " )[" + id + "]";

    case 'W':
      return "( " + left.toString(true) + " W " + right.toString(true) + 
             " )[" + id + "]";

    //case 'M': return "( " + left.toString(true) + " M " + right.toString(true) + " )[" + id + "]";
    case 'X':
      return "( X " + left.toString(true) + " )[" + id + "]";

    case 'N':
      return "( ! " + left.toString(true) + " )[" + id + "]";

    case 't':
      return "( true )[" + id + "]";

    case 'f':
      return "( false )[" + id + "]";

    case 'p':
      return "( \"" + name + "\" )[" + id + "]";

    default:
      return "( " + content + " )[" + id + "]";
    }
  }

  public String toString () {
    switch (content) {
    case 'A':
      return "( " + left.toString() + " /\\ " + right.toString() + " )";

    case 'O':
      return "( " + left.toString() + " \\/ " + right.toString() + " )";

    case 'U':
      return "( " + left.toString() + " U " + right.toString() + " )";

    case 'V':
      return "( " + left.toString() + " V " + right.toString() + " )";

    case 'W':
      return "( " + left.toString() + " W " + right.toString() + " )";

    //case 'M': return "( " + left.toString() + " M " + right.toString() + " )";
    case 'X':
      return "( X " + left.toString() + " )";

    case 'N':
      return "( ! " + left.toString() + " )";

    case 't':
      return "( true )";

    case 'f':
      return "( false )";

    case 'p':
      return "( \"" + name + "\" )";

    default:
      return new Character(content).toString();
    }
  }

  private static Formula Always (Formula f) {
    return unique(new Formula('V', false, False(), f, null));
  }

  private static Formula And (Formula sx, Formula dx) {
    if (sx.id < dx.id) {
      return unique(new Formula('A', false, sx, dx, null));
    } else {
      return unique(new Formula('A', false, dx, sx, null));
    }
  }

  private static Formula Eventually (Formula f) {
    return unique(new Formula('U', false, True(), f, null));
  }

  private static Formula False () {
    return unique(new Formula('f', true, null, null, null));
  }

  private static Formula Implies (Formula sx, Formula dx) {
    return Or(Not(sx), dx);
  }

  private static Formula Next (Formula f) {
    return unique(new Formula('X', false, f, null, null));
  }

  private static Formula Not (Formula f) {
    if (f.literal) {
      switch (f.content) {
      case 't':
        return False();

      case 'f':
        return True();

      case 'N':
        return f.left;

      default:
        return unique(new Formula('N', true, f, null, null));
      }
    }

    // f is not a literal, so go on...
    switch (f.content) {
    case 'A':
      return Or(Not(f.left), Not(f.right));

    case 'O':
      return And(Not(f.left), Not(f.right));

    case 'U':
      return Release(Not(f.left), Not(f.right));

    case 'V':
      return Until(Not(f.left), Not(f.right));

    case 'W':
      return WRelease(Not(f.left), Not(f.right));

    //case 'M': return WUntil(Not(f.left), Not(f.right));
    case 'N':
      return f.left;

    case 'X':
      return Next(Not(f.left));

    default:
      throw new ParserInternalError();
    }
  }

  private static Formula Or (Formula sx, Formula dx) {
    if (sx.id < dx.id) {
      return unique(new Formula('O', false, sx, dx, null));
    } else {
      return unique(new Formula('O', false, dx, sx, null));
    }
  }

  private static Formula Proposition (String name) {
    return unique(new Formula('p', true, null, null, name));
  }

  private static Formula Release (Formula sx, Formula dx) {
    return unique(new Formula('V', false, sx, dx, null));
  }

  private static Formula True () {
    return unique(new Formula('t', true, null, null, null));
  }

  private static Formula Until (Formula sx, Formula dx) {
    return unique(new Formula('U', false, sx, dx, null));
  }

  private static Formula WRelease (Formula sx, Formula dx) {
    return unique(new Formula('U', false, dx, And(sx, dx), null));
  }

  private static Formula WUntil (Formula sx, Formula dx) {
    return unique(new Formula('W', false, sx, dx, null));
  }

  private static void clearHT () {
    ht = new Hashtable();
  }

  private static void clearMatches () {
    matches = new Hashtable();
  }

  private static Formula parse (Input i, int precedence)
                         throws ParseErrorException {
    try {
      Formula formula;
      char    ch;

      while (i.get() == ' ') {
        i.skip();
      }

      switch (ch = i.get()) {
      case '/': // and
      case '&': // robbyjo's and
      case '\\': // or
      case '|': // robbyjo's or
      case 'U': // until
      case 'W': // weak until
      case 'V': // release
      case 'M': // dual of W - weak release
      case ')':
        throw new ParseErrorException("invalid character: " + ch);

      case '!': // not
        i.skip();
        formula = Not(parse(i, P_NOT));

        break;

      case 'X': // next
        i.skip();
        formula = Next(parse(i, P_NEXT));

        break;

      case '[': // always
        i.skip();

        if (i.get() != ']') {
          throw new ParseErrorException("expected ]");
        }

        i.skip();
        formula = Always(parse(i, P_ALWAYS));

        break;

      case '<': // eventually
        i.skip();

        if (i.get() != '>') {
          throw new ParseErrorException("expected >");
        }

        i.skip();
        formula = Eventually(parse(i, P_EVENTUALLY));

        break;

      case '(':
        i.skip();
        formula = parse(i, P_ALL);

        if (i.get() != ')') {
          throw new ParseErrorException("invalid character: " + ch);
        }

        i.skip();

        break;

      case '"':

        StringBuffer sb = new StringBuffer();
        i.skip();

        while ((ch = i.get()) != '"') {
          sb.append(ch);
          i.skip();
        }

        i.skip();

        formula = Proposition(sb.toString());

        break;

      default:

        if (Character.isJavaIdentifierStart(ch)) {
          StringBuffer sbf = new StringBuffer();

          sbf.append(ch);
          i.skip();

          try {
            while (Character.isJavaIdentifierPart(ch = i.get()) && 
                   (!Formula.is_reserved_char(ch))) {
              sbf.append(ch);
              i.skip();
            }
          } catch (EndOfInputException e) {
            //  return Proposition(sbf.toString());
          }

          String id = sbf.toString();

          if (id.equals("true")) {
            formula = True();
          } else if (id.equals("false")) {
            formula = False();
          } else {
            formula = Proposition(sbf.toString());
          }
        } else {
          throw new ParseErrorException("invalid character: " + ch);
        }

        break;
      }

      try {
        while (i.get() == ' ') {
          i.skip();
        }

        ch = i.get();
      } catch (EndOfInputException e) {
        return formula;
      }

      while (true) {
        switch (ch) {
        case '/': // and

          if (precedence > P_AND) {
            return formula;
          }

          i.skip();

          if (i.get() != '\\') {
            throw new ParseErrorException("expected \\");
          }

          i.skip();
          formula = And(formula, parse(i, P_AND));

          break;

        case '&': // robbyjo's and

          if (precedence > P_AND) {
            return formula;
          }

          i.skip();

          if (i.get() != '&') {
            throw new ParseErrorException("expected &&");
          }

          i.skip();
          formula = And(formula, parse(i, P_AND));

          break;

        case '\\': // or

          if (precedence > P_OR) {
            return formula;
          }

          i.skip();

          if (i.get() != '/') {
            throw new ParseErrorException("expected /");
          }

          i.skip();
          formula = Or(formula, parse(i, P_OR));

          break;

        case '|': // robbyjo's or

          if (precedence > P_OR) {
            return formula;
          }

          i.skip();

          if (i.get() != '|') {
            throw new ParseErrorException("expected ||");
          }

          i.skip();
          formula = Or(formula, parse(i, P_OR));

          break;

        case 'U': // until

          if (precedence > P_UNTIL) {
            return formula;
          }

          i.skip();
          formula = Until(formula, parse(i, P_UNTIL));

          break;

        case 'W': // weak until

          if (precedence > P_WUNTIL) {
            return formula;
          }

          i.skip();
          formula = WUntil(formula, parse(i, P_WUNTIL));

          break;

        case 'V': // release

          if (precedence > P_RELEASE) {
            return formula;
          }

          i.skip();
          formula = Release(formula, parse(i, P_RELEASE));

          break;

        case 'M': // weak_release

          if (precedence > P_WRELEASE) {
            return formula;
          }

          i.skip();
          formula = WRelease(formula, parse(i, P_WRELEASE));

          break;

        case '-': // implies

          if (precedence > P_IMPLIES) {
            return formula;
          }

          i.skip();

          if (i.get() != '>') {
            throw new ParseErrorException("expected >");
          }

          i.skip();
          formula = Implies(formula, parse(i, P_IMPLIES));

          break;

        case ')':
          return formula;

        case '!':
        case 'X':
        case '[':
        case '<':
        case '(':
        default:
          throw new ParseErrorException("invalid character: " + ch);
        }

        try {
          while (i.get() == ' ') {
            i.skip();
          }

          ch = i.get();
        } catch (EndOfInputException e) {
          break;
        }
      }

      return formula;
    } catch (EndOfInputException e) {
      throw new ParseErrorException("unexpected end of input");
    }
  }

  private static Formula unique (Formula f) {
    String s = f.toString();

    if (ht.containsKey(s)) {
      return (Formula) ht.get(s);
    }

    ht.put(s, f);

    return f;
  }

  private Formula getMatch (String name) {
    return (Formula) matches.get(name);
  }

  private void addMatch (String name, Formula expr) {
    matches.put(name, expr);
  }

  private boolean match (Formula rule) {
    if (rule.content == 'p') {
      Formula match = getMatch(rule.name);

      if (match == null) {
        addMatch(rule.name, this);

        return true;
      }

      return match == this;
    }

    if (rule.content != content) {
      return false;
    }

    Hashtable saved = (Hashtable) matches.clone();

    switch (content) {
    case 'A':
    case 'O':

      if (left.match(rule.left) && right.match(rule.right)) {
        return true;
      }

      matches = saved;

      if (right.match(rule.left) && left.match(rule.right)) {
        return true;
      }

      matches = saved;

      return false;

    case 'U':
    case 'V':
    case 'W':

      if (left.match(rule.left) && right.match(rule.right)) {
        return true;
      }

      matches = saved;

      return false;

    case 'X':
    case 'N':

      if (left.match(rule.left)) {
        return true;
      }

      matches = saved;

      return false;

    case 't':
    case 'f':
      return true;
    }

    throw new RuntimeException("code should not be reached");
  }

  private Formula rewrite () {
    if (content == 'p') {
      return getMatch(name);
    }

    switch (content) {
    case 'A':
      return And(left.rewrite(), right.rewrite());

    case 'O':
      return Or(left.rewrite(), right.rewrite());

    case 'U':
      return Until(left.rewrite(), right.rewrite());

    case 'V':
      return Release(left.rewrite(), right.rewrite());

    case 'W':
      return WUntil(left.rewrite(), right.rewrite());

    case 'X':
      return Next(left.rewrite());

    case 'N':
      return Not(left.rewrite());

    case 't':
      return True();

    case 'f':
      return False();
    }

    throw new RuntimeException("code should not be reached");
  }

  /**
   * DOCUMENT ME!
   */
  public static class EndOfInputException extends Exception {
  }

  /**
   * DOCUMENT ME!
   */
  private static class Input {
    private StringBuffer sb;

    public Input (String str) {
      sb = new StringBuffer(str);
    }

    public char get () throws EndOfInputException {
      try {
        return sb.charAt(0);
      } catch (StringIndexOutOfBoundsException e) {
        throw new EndOfInputException();
      }
    }

    public void skip () throws EndOfInputException {
      try {
        sb.deleteCharAt(0);
      } catch (StringIndexOutOfBoundsException e) {
        throw new EndOfInputException();
      }
    }
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.