solutions method

  1. @override
List<Complex> solutions()
override

Calculates the roots (the solutions) of the equation.

Implementation

@override
List<Complex> solutions() {
  // In case the polynomial was a constant, just return an empty array because
  // there are no solutions
  if (coefficients.length <= 1) {
    return [];
  }

  // Proceeding with the setup since the polynomial degree is >= 1.
  final coefficientsLength = coefficients.length;
  final reversedCoeffs = coefficients.reversed.toList();

  // Buffers for numerators and denominators or real and complex parts.
  final realBuffer = reversedCoeffs.map((e) => e.real).toList();
  final imaginaryBuffer = reversedCoeffs.map((e) => e.imaginary).toList();

  // Scaling the various coefficients.
  var upperReal = realBuffer[coefficientsLength - 1];
  var upperComplex = imaginaryBuffer[coefficientsLength - 1];
  final squareSum = upperReal * upperReal + upperComplex * upperComplex;

  upperReal /= squareSum;
  upperComplex /= -squareSum;

  var k1 = 0.0;
  var k2 = 0.0;
  var k3 = 0.0;
  final s = upperComplex - upperReal;
  final t = upperReal + upperComplex;

  for (var i = 0; i < coefficientsLength - 1; ++i) {
    k1 = upperReal * (realBuffer[i] + imaginaryBuffer[i]);
    k2 = realBuffer[i] * s;
    k3 = imaginaryBuffer[i] * t;
    realBuffer[i] = k1 - k3;
    imaginaryBuffer[i] = k1 + k2;
  }

  realBuffer[coefficientsLength - 1] = 1.0;
  imaginaryBuffer[coefficientsLength - 1] = 0.0;

  // Using default values to compute the solutions. If they aren't provided,
  // we will generate default ones.
  if (initialGuess.isNotEmpty) {
    final real = initialGuess.map((e) => e.real).toList();
    final complex = initialGuess.map((e) => e.imaginary).toList();

    return _solve(
      realValues: real,
      imaginaryValues: complex,
      realBuffer: realBuffer,
      imaginaryBuffer: imaginaryBuffer,
    );
  } else {
    // If we're here, it means that no initial guesses were provided and so we
    // need to generate some good ones.
    final real = List<double>.generate(
      coefficientsLength - 1,
      (_) => 0.0,
    );
    final complex = List<double>.generate(
      coefficientsLength - 1,
      (_) => 0.0,
    );

    final factor = 0.65 *
        _bound(
          value: coefficientsLength,
          realBuffer: realBuffer,
          imaginaryBuffer: imaginaryBuffer,
        );

    final multiplier = math.cos(0.25 * 2 * math.pi);

    for (var i = 0; i < coefficientsLength - 1; ++i) {
      real[i] = factor * multiplier;
      complex[i] = factor * math.sqrt(1.0 - multiplier * multiplier);
    }

    return _solve(
      realValues: real,
      imaginaryValues: complex,
      realBuffer: realBuffer,
      imaginaryBuffer: imaginaryBuffer,
    );
  }
}