Files
Skeleton/src/Analysis/AnalyticFunctions/Polynomials/Implements/C4Polynomial.cs
2024-06-21 21:48:07 +08:00

140 lines
4.6 KiB
C#

using System.Numerics;
using Skeleton.Algebra.Extensions;
using Skeleton.Analysis.BivariantFunctions.Real.Implements;
using Skeleton.Analysis.BivariantFunctions.Real.PolynomialHelpers;
using Skeleton.Utils.Helpers;
namespace Skeleton.Analysis.AnalyticFunctions.Polynomials.Implements;
/// <summary>
/// </summary>
public class C4Polynomial : Polynomial
{
/// <inheritdoc />
public C4Polynomial()
{
Coefficients = new Complex[5];
Fix();
}
/// <inheritdoc />
public C4Polynomial(Complex a0, Complex a1, Complex a2, Complex a3, Complex a4)
{
Coefficients = new[] { a0, a1, a2, a3, a4 };
Fix();
}
/// <summary>
/// </summary>
public Complex A0 => Coefficients[0];
/// <summary>
/// </summary>
public Complex A1 => Coefficients[1];
/// <summary>
/// </summary>
public Complex A2 => Coefficients[2];
/// <summary>
/// </summary>
public Complex A3 => Coefficients[3];
/// <summary>
/// </summary>
public Complex A4 => Coefficients[4];
/// <inheritdoc />
public override int Dim => 4;
/// <inheritdoc />
public override Polynomial Derivative => new C3Polynomial(A1, A2 * 2, A3 * 3, A4 * 4);
/// <inheritdoc />
public override IEnumerable<Complex> Roots =>
Decorators.WithTol(1e-20, () =>
{
if (A4.IsEqualApprox(Complex.Zero))
return new C3Polynomial(A0, A1, A2, A3).Roots;
if (A0.IsEqualApprox(Complex.Zero))
return new C3Polynomial(A1, A2, A3, A4).Roots.Concat(new[] { Complex.Zero });
if (A3.IsEqualApprox(Complex.Zero) && A1.IsEqualApprox(Complex.Zero))
return new C2Polynomial(A0, A2, A4).Roots
.SelectMany(x => new[] { Complex.Sqrt(x), -Complex.Sqrt(x) });
Polynomial gcd = GreatestCommonDivisor(Derivative);
if (!gcd.IsConstant)
{
Polynomial div = LongDivision(gcd).Quotient;
return div.Roots.Concat(gcd.Roots);
}
Complex a = A4;
Complex b = A3;
Complex c = A2;
Complex d = A1;
Complex e = A0;
Complex P = (c * c + 12d * a * e - 3d * b * d) / 9d;
Complex Q = (27d * a * d * d + 2d * c * c * c + 27d * b * b * e - 72d * a * c * e - 9d * b * c * d) / 54d;
Complex D = Complex.Sqrt(Q * Q - P * P * P);
Complex ua = Complex.Pow(Q + D, 1d / 3d);
Complex ub = Complex.Pow(Q - D, 1d / 3d);
Complex u = Complex.Abs(ua) > Complex.Abs(ub) ? ua : ub;
Complex v = u.IsEqualApprox(0d) ? 0d : P / u;
Complex omega = -0.5d + Complex.Sqrt(3d) * Complex.ImaginaryOne / 2d;
Complex m(int k)
{
return Complex.Sqrt(b * b - 8d / 3d * a * c +
4d * a * (Utils.Utils.IterPow(omega, k - 1) * u +
Utils.Utils.IterPow(omega, 4 - k) * v));
}
Complex S(int k)
{
return 2d * b * b - 16d / 3d * a * c -
4d * a * (Utils.Utils.IterPow(omega, k - 1) * u + Utils.Utils.IterPow(omega, 4 - k) * v);
}
int i = new[] { 1, 2, 3 }.MaxBy(x => m(x).Magnitude);
Complex mm = m(i);
Complex SS = S(i);
Complex T = 0;
if (mm.Magnitude.IsEqualApprox(0))
{
mm = 0;
SS = b * b - 8d / 3d * a * c;
T = 0;
}
else
{
T = (8d * a * b * c - 16d * a * a * d - 2d * b * b * b) / mm;
}
Complex x(int i)
{
return (-b + Utils.Utils.SPow(Math.Ceiling(i / 2f)) * mm + Utils.Utils.SPow(i + 1) *
Complex.Sqrt(SS + Utils.Utils.SPow(Math.Ceiling(i / 2f)) * T)) /
(4d * a);
}
return new[] { x(1), x(2), x(3), x(4) };
});
/// <inheritdoc />
public override BivariantContinuous Re => new PolyCHelper.PolyC4Re(A0, A1, A2, A3, A4);
/// <inheritdoc />
public override BivariantContinuous Im => new PolyCHelper.PolyC4Im(A0, A1, A2, A3, A4);
/// <inheritdoc />
public override string Representation =>
$"{A0.Real} + {A0.Imaginary}i + ({A1.Real} + {A1.Imaginary}i)x + ({A2.Real} + {A2.Imaginary}i)x2 + ({A3.Real} + {A3.Imaginary}i)X3 + ({A4.Real} + {A4.Imaginary}i)x4";
/// <inheritdoc />
public override Complex Evaluate(Complex x)
=> A0 + x * (A1 + x * (A2 + x * (A3 + x * A4)));
}