Example #1
0
  /**
   * Get the range for a specific variable in an expression. May be null if the range is not
   * defined. If only one side of the range is defined, then the min may be -Double.MAX_VALUE, and
   * the max may be Double.MAX_VALUE
   *
   * @param expression the expression to parse
   * @param variable the name of the variable
   * @throws EmptyRangeException if expression is Constant.FALSE or otherwise unsatisfiable for any
   *     variable in 'variables'
   * @throws ConstantMismatchException is there are constants which contradict each other
   * @throws UnsupportedConditionException if there are conditions not suited for interval range
   *     extraction
   */
  public static Interval getVariableRange(Expression expression, String variable)
      throws EmptyRangeException, ConstantMismatchException, UnsupportedConditionException {
    TreeMap<String, Interval> ranges = new TreeMap<String, Interval>();

    Collection<String> equalVars = new ArrayList<String>();
    equalVars.add(variable);
    equalVars.addAll(getEqualVariables(expression, variable));
    Interval rv = null;

    try {
      Map<String, Double> constantMap = getConstants(expression);

      getVariableRangesRecursive(expression, ranges, equalVars, constantMap);

      if (ranges.size() > 0) rv = mergeAllRanges(ranges.values());
    } catch (AutomatonExportException e) {
      // this can occur, for example, if the conditions are not box-edges
      throw new EmptyRangeException(
          "Error getting range for " + variable + " in expression: " + expression.toDefaultString(),
          e);
    } catch (EmptyRangeException e) {
      throw new EmptyRangeException(
          "Empty range for " + variable + " in expression: " + expression.toDefaultString(), e);
    } catch (ConstantMismatchException e) {
      throw new ConstantMismatchException(
          "Constant mismatch in expression: " + expression.toDefaultString(), e);
    } catch (UnsupportedConditionException e) {
      throw new UnsupportedConditionException(
          "Unsupported operation for range extraction in expression: "
              + expression.toDefaultString(),
          e);
    }

    return rv;
  }
Example #2
0
  private void populateCoefficients(Expression e, boolean isLeftHandSide, List<String> vars) {
    if (e instanceof Constant) {
      Constant c = (Constant) e;

      double val = c.getVal();

      if (isLeftHandSide) rhs += -val;
      else rhs += val;
    } else if (e instanceof Variable) {
      Variable v = (Variable) e;
      int index = getVariableIndex(v, vars);

      if (isLeftHandSide) coefficients[index] += 1;
      else coefficients[index] -= 1;
    } else if (e instanceof Operation) {
      Operation o = (Operation) e;

      if (o.op == Operator.ADD) {
        populateCoefficients(o.getLeft(), isLeftHandSide, vars);
        populateCoefficients(o.getRight(), isLeftHandSide, vars);
      } else if (o.op == Operator.MULTIPLY) {
        Expression l = o.getLeft();
        Expression r = o.getRight();
        Variable v;
        Constant c;

        if (l instanceof Variable && r instanceof Constant) {
          v = (Variable) l;
          c = (Constant) r;
        } else if (l instanceof Constant && r instanceof Variable) {
          v = (Variable) r;
          c = (Constant) l;
        } else {
          throw new AutomatonExportException(
              "Couldn't parse simple linear expression: " + e.toDefaultString());
        }

        int index = getVariableIndex(v, vars);

        if (isLeftHandSide) coefficients[index] += c.getVal();
        else coefficients[index] -= c.getVal();
      } else
        throw new AutomatonExportException(
            "Could not parse operation '"
                + o.op.toDefaultString()
                + "' in linear expression: "
                + e.toDefaultString());

    } else
      throw new AutomatonExportException(
          "Could not parse linear expression: " + e.toDefaultString());
  }
Example #3
0
  private static Collection<String> getEqualVariables(Expression expression, String variable) {
    Collection<String> rv = new HashSet<String>();
    Operation o = expression.asOperation();

    if (o != null && o.children.size() == 2) {
      Expression leftExp = o.children.get(0);
      Expression rightExp = o.children.get(1);
      Operator op = o.op;

      if (op.equals(Operator.AND)) {
        rv.addAll(getEqualVariables(leftExp, variable));
        rv.addAll(getEqualVariables(rightExp, variable));
      } else if (op.equals(Operator.EQUAL)
          && leftExp instanceof Variable
          && rightExp instanceof Variable) {
        Variable left = (Variable) leftExp;
        Variable right = (Variable) rightExp;

        if (left.name.equals(variable)) rv.add(right.name);
        else if (right.name.equals(variable)) rv.add(left.name);
      }
    }

    return rv;
  }
Example #4
0
 /**
  * Get ranges for variables in a logical expression, ignores loc assignments
  *
  * @param expression the expression to parse
  * @param ranges where to store the ranges for the variables we encounter
  * @throws EmptyRangeException if expression is Constant.FALSE or otherwise unsatisfiable for any
  *     variable in 'variables'
  * @throws ConstantMismatchException if there are conflicting assignments to constants
  * @throws UnsupportedConditionException if the expression contains non-interval operations on the
  *     desired variable
  */
 public static void getVariableRanges(Expression expression, TreeMap<String, Interval> ranges)
     throws EmptyRangeException, ConstantMismatchException, UnsupportedConditionException {
   try {
     Map<String, Double> constantMap = getConstants(expression);
     getVariableRangesRecursive(expression, ranges, null, constantMap);
   } catch (AutomatonExportException e) {
     throw new AutomatonExportException(
         "Error while parsing expression: " + expression.toDefaultString(), e);
   }
 }
Example #5
0
  public static int countVariableOccurances(Expression expression, String variable) {
    int rv = 0;

    if (expression instanceof Operation) {
      Operation o = expression.asOperation();

      for (Expression c : o.children) {
        rv += countVariableOccurances(c, variable);
      }
    } else if (expression instanceof Variable) {
      Variable v = (Variable) expression;

      if (v.name.equals(variable)) ++rv;
    }

    return rv;
  }
Example #6
0
  public static Map<String, Double> getConstants(Expression expression)
      throws ConstantMismatchException {
    HashMap<String, Double> rv = new HashMap<String, Double>();

    Operation o = expression.asOperation();

    if (o != null) {
      if (o.op == Operator.AND) {
        Map<String, Double> left = getConstants(o.getLeft());
        Map<String, Double> right = getConstants(o.getRight());

        safePutAll(rv, left);
        safePutAll(rv, right);
      } else if (o.op == Operator.EQUAL) {
        double val = 0;
        String varName = null;

        Expression leftExp = o.getLeft();
        Expression rightExp = o.getRight();

        if (leftExp instanceof Variable && rightExp instanceof Constant) {
          varName = ((Variable) leftExp).name;
          val = ((Constant) rightExp).getVal();
        } else if (leftExp instanceof Constant && rightExp instanceof Variable) {
          varName = ((Variable) rightExp).name;
          val = ((Constant) leftExp).getVal();
        }

        if (varName != null && !varName.startsWith("loc(")) {
          safePut(rv, varName, val);
        }
      }
    }

    return rv;
  }
Example #7
0
  /**
   * Get the variable ranges and store them into ranges
   *
   * @param expression the expression to extract from
   * @param ranges the place to store them
   * @param vars a set of variables we are interested in. if null then get all variables
   * @param constantMap a map of variableName -> value for all constants in the original expression
   * @throws EmptyRangeException if expression is Constant.FALSE or otherwise unsatisfiable for the
   *     selected variables
   * @throws UnsupportedConditionException if the expression contains non-interval operations on the
   *     desired variable
   */
  private static void getVariableRangesRecursive(
      Expression expression,
      TreeMap<String, Interval> ranges,
      Collection<String> vars,
      Map<String, Double> constantMap)
      throws EmptyRangeException, UnsupportedConditionException {
    Operation o = expression.asOperation();

    if (o != null && o.children.size() == 2) {
      Expression leftExp = o.children.get(0);
      Expression rightExp = o.children.get(1);
      Operator op = o.op;

      if (op.equals(Operator.AND)) {
        TreeMap<String, Interval> left = new TreeMap<String, Interval>();
        TreeMap<String, Interval> right = new TreeMap<String, Interval>();

        getVariableRangesRecursive(leftExp, ranges, vars, constantMap);
        getVariableRangesRecursive(rightExp, ranges, vars, constantMap);

        ranges = mergeTreeRanges(left, right);
      } else if (expressionContainsVariables(expression, vars)) {
        double val = 0;
        String varName = null;

        // ignore location assignments
        if (leftExp instanceof Variable && ((Variable) leftExp).name.startsWith("loc(")) return;

        boolean yodaConstraint = false; // if constraint is like '5 < x' instead of the normal order
        boolean shouldSkip = false;

        if (leftExp instanceof Variable && rightExp instanceof Constant) {
          varName = ((Variable) leftExp).name;
          val = ((Constant) rightExp).getVal();

          yodaConstraint = false;
        } else if (leftExp instanceof Constant && rightExp instanceof Variable) {
          varName = ((Variable) rightExp).name;
          val = ((Constant) leftExp).getVal();

          yodaConstraint = true;
        } else if (leftExp instanceof Variable && rightExp instanceof Variable) {
          // one of them might be an expression constant, which are given by constMap

          String leftName = ((Variable) leftExp).name;
          Double constVal = constantMap.get(leftName);

          if (constVal != null) {
            varName = ((Variable) rightExp).name;
            val = constVal.doubleValue();
            yodaConstraint = true;
          } else {
            String rightName = ((Variable) rightExp).name;
            constVal = constantMap.get(rightName);

            if (constVal != null) {
              varName = ((Variable) leftExp).name;
              val = constVal.doubleValue();

              yodaConstraint = false;
            } else {
              // both are variables. This is only allowed it it's an alias assignment, which
              // we detect by checking if the operator is '=='
              if (op == Operator.EQUAL) shouldSkip = true;
              else
                throw new UnsupportedConditionException(
                    "Unsupported condition for range extraction (one "
                        + "side should be variable, the other side a constant): "
                        + expression.toDefaultString());
            }
          }
        } else {
          throw new UnsupportedConditionException(
              "Unsupported condition for range extraction (one "
                  + "side should be variable, the other side a constant): "
                  + expression.toDefaultString());
        }

        if (!shouldSkip) {
          Interval i = null;

          if (op == Operator.EQUAL) {
            i = new Interval(val);
            ranges.put(varName, i);
          } else if ((!yodaConstraint && (op == Operator.GREATER || op == Operator.GREATEREQUAL))
              || (yodaConstraint && (op == Operator.LESS || op == Operator.LESSEQUAL))) {
            i = ranges.get(varName);

            if (i == null) {
              i = new Interval(-Double.MAX_VALUE, Double.MAX_VALUE);
              ranges.put(varName, i);
            }

            i.min = val;
          } else if ((!yodaConstraint && (op == Operator.LESS || op == Operator.LESSEQUAL))
              || (yodaConstraint && (op == Operator.GREATER || op == Operator.GREATEREQUAL))) {
            i = ranges.get(varName);

            if (i == null) {
              i = new Interval(-Double.MAX_VALUE, Double.MAX_VALUE);

              ranges.put(varName, i);
            }

            i.max = val;
          } else
            throw new UnsupportedConditionException(
                "Unsupported expression during range extraction: " + expression.toDefaultString());

          if (i.max < i.min)
            throw new EmptyRangeException("range for " + varName + " is unsatisfiable");
        }
      }
    } else if (expression instanceof Variable) {
      Variable v = (Variable) expression;

      if (v.name.equals("true")) {
        // no restrictions on variable range
      } else if (v.name.equals("false")) {
        throw new EmptyRangeException("expression contains false");
      } else
        throw new AutomatonExportException(
            "Unsupported expression type (variable as condition?): "
                + expression.toDefaultString());
    } else if (expression == Constant.FALSE) // if any variable is false, the range for all is empty
    throw new EmptyRangeException("expression contains FALSE");
    else if (expression != Constant.TRUE && expressionContainsVariables(expression, vars))
      throw new UnsupportedConditionException(
          "Unsupported expression during range extraction: " + expression.toDefaultString());
  }