evaluate method

  1. @override
dynamic evaluate(
  1. EvaluationType type,
  2. ContextModel context
)
override

Evaluates this expression according to given type and context.

Implementation

@override
dynamic evaluate(EvaluationType type, ContextModel context) {
  final num base = first.evaluate(type, context);
  if (type == EvaluationType.REAL) {
    // Consider the following equation: x^(2/y).
    // This equation can be evaluated for any negative x, since the sub result
    // is positive due to the even numerator. However, the IEEE Standard for
    // for Floating-Point Arithmetic defines NaN in the case of a negative
    // base and a finite non-integer as the exponent. That's why we rewrite
    // the equation manually.
    if (base.isNegative && second is Divide) {
      final Expression numerator = (second as Divide).first;
      final Expression denominator = (second as Divide).second;
      final double newBase = Power(base, numerator).evaluate(type, context);
      final double newExponent = 1 / denominator.evaluate(type, context);
      return Power(newBase, newExponent).evaluate(type, context);
    }
    // In case the exponent is a unary minus e.g. x^(-(2/y)), we rewrite the
    // equation to 1/x^(2/3), for the same reason as stated above.
    if (base.isNegative && second is UnaryMinus) {
      final Expression exponent = (second as UnaryMinus).exp;
      return 1 / Power(base, exponent).evaluate(type, context);
    }
    return math.pow(base, second.evaluate(type, context));
  }

  if (type == EvaluationType.INTERVAL) {
    // Expect base to be interval.
    final Interval interval = first.evaluate(type, context);

    // Expect exponent to be a natural number.
    dynamic exponent = second.evaluate(EvaluationType.REAL, context);

    if (exponent is double) {
      //print('Warning, expected natural exponent but is real. Interpreting as int: ${this}');
      exponent = exponent.toInt();
    }

    num evalMin, evalMax;
    // Distinction of cases depending on oddity of exponent.
    if (exponent.isOdd) {
      // [x, y]^n = [x^n, y^n] for n = odd
      evalMin = math.pow(interval.min, exponent);
      evalMax = math.pow(interval.max, exponent);
    } else {
      // [x, y]^n = [x^n, y^n] for x >= 0
      if (interval.min >= 0) {
        // Positive interval.
        evalMin = math.pow(interval.min, exponent);
        evalMax = math.pow(interval.max, exponent);
      }

      // [x, y]^n = [y^n, x^n] for y < 0
      if (interval.min >= 0) {
        // Positive interval.
        evalMin = math.pow(interval.max, exponent);
        evalMax = math.pow(interval.min, exponent);
      }

      // [x, y]^n = [0, max(x^n, y^n)] otherwise
      evalMin = 0;
      evalMax = math.max(
          math.pow(interval.min, exponent), math.pow(interval.min, exponent));
    }

    assert(evalMin <= evalMax);

    return Interval(evalMin, evalMax);
  }

  throw UnimplementedError(
      'Evaluate Power with type $type not supported yet.');
}