예제 #1
0
  private static Interval mergeAllRanges(Collection<Interval> is) throws EmptyRangeException {
    Interval rv = new Interval(-Double.MAX_VALUE, Double.MAX_VALUE);

    for (Interval i : is) {
      rv.min = Math.max(rv.min, i.min);
      rv.max = Math.min(rv.max, i.max);
    }

    if (rv.max < rv.min) throw new EmptyRangeException("range is unsatisfiable");

    return rv;
  }
예제 #2
0
  /**
   * Merge the two ranges. For example [-5, 4] and [2, 10] will merge to be [2, 4].
   *
   * @param left a range for each variable
   * @param right the other range for each variable, may include more or less variables as well
   * @return the merged set of constraints
   * @throws EmptyRangeException if the ranges don't overlap
   */
  private static TreeMap<String, Interval> mergeTreeRanges(
      TreeMap<String, Interval> left, TreeMap<String, Interval> right) throws EmptyRangeException {
    TreeMap<String, Interval> rv = new TreeMap<String, Interval>();

    rv.putAll(left);

    for (Entry<String, Interval> e : right.entrySet()) {
      String key = e.getKey();
      Interval val = e.getValue();

      Interval i = rv.get(key);

      if (i == null) rv.put(key, val);
      else {
        // take the tighter of the two extremes
        i.min = Math.max(i.min, val.min);
        i.max = Math.min(i.max, val.max);

        if (i.max < i.min) throw new EmptyRangeException("range for " + key + " is unsatisfiable");
      }
    }

    return rv;
  }
예제 #3
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());
  }