262 lines
8.2 KiB
C#
262 lines
8.2 KiB
C#
using System.Numerics;
|
|
using Skeleton.Algebra.Extensions;
|
|
using Skeleton.Algebra.ScalarFieldStructure;
|
|
using Skeleton.Analysis.AnalyticFunctions.Implements;
|
|
using Skeleton.Analysis.BivariantFunctions.Real.Implements;
|
|
using Skeleton.DataStructure.Packs;
|
|
using Skeleton.Utils.Helpers;
|
|
|
|
namespace Skeleton.Analysis.AnalyticFunctions.Polynomials.Implements;
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public abstract class Polynomial : Analytic, IPolynomial
|
|
{
|
|
/// <summary>
|
|
/// </summary>
|
|
protected static readonly Polynomial Zero = new C0Polynomial(0);
|
|
|
|
private static readonly Polynomial One = new C0Polynomial(1);
|
|
private static readonly Polynomial X = new C1Polynomial(0, 1);
|
|
private static readonly Polynomial X2 = new C2Polynomial(0, 0, 1);
|
|
private static readonly Polynomial X3 = new C3Polynomial(0, 0, 0, 1);
|
|
private static readonly Polynomial X4 = new C4Polynomial(0, 0, 0, 0, 1);
|
|
private bool IsZero => Decorators.WithTol(1e-30, () => Coefficients.All(x => x.IsEqualApprox(Complex.Zero)));
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public bool IsConstant =>
|
|
Decorators.WithTol(1E-30, () => Coefficients.Skip(1).All(x => x.IsEqualApprox(Complex.Zero)));
|
|
|
|
/// <inheritdoc />
|
|
public override Polynomial Derivative
|
|
{
|
|
get
|
|
{
|
|
Complex[] coeff = new Complex[Dim];
|
|
for (int i = 1; i <= Dim; i++)
|
|
coeff[i - 1] = Coefficients[i] * i;
|
|
return Dispatch(coeff);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public virtual string Representation =>
|
|
string.Join(
|
|
" + ",
|
|
Coefficients
|
|
.Zip(Enumerable.Range(0, Degree + 1))
|
|
.Select(
|
|
x
|
|
=> "(" +
|
|
ComplexFieldStructure.Structure.Representation(x.First) +
|
|
$")x^{x.Second}"
|
|
)
|
|
);
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public abstract IEnumerable<Complex> Roots { get; }
|
|
|
|
/// <inheritdoc />
|
|
public abstract int Dim { get; }
|
|
|
|
/// <inheritdoc />
|
|
public int Degree
|
|
{
|
|
get
|
|
{
|
|
for (int i = 0; i <= Dim; i++)
|
|
if (Coefficients[^(i + 1)] != Complex.Zero)
|
|
return Dim - i;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Complex[] Coefficients { get; set; } = Array.Empty<Complex>();
|
|
|
|
/// <inheritdoc />
|
|
public abstract BivariantContinuous Re { get; }
|
|
|
|
/// <inheritdoc />
|
|
public abstract BivariantContinuous Im { get; }
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="coefficients"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="Exception"></exception>
|
|
public static Polynomial Dispatch(Complex[] coefficients)
|
|
{
|
|
return coefficients.Length switch
|
|
{
|
|
1 => new C0Polynomial(coefficients[0]),
|
|
2 => new C1Polynomial(coefficients[0], coefficients[1]),
|
|
3 => new C2Polynomial(coefficients[0], coefficients[1], coefficients[2]),
|
|
4 => new C3Polynomial(coefficients[0], coefficients[1], coefficients[2], coefficients[3]),
|
|
5 => new C4Polynomial(coefficients[0], coefficients[1], coefficients[2], coefficients[3], coefficients[4]),
|
|
_ => new GeneralPolynomial(coefficients.Length - 1, coefficients)
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator +(Polynomial a, Complex b) => a + new C0Polynomial(b);
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="b"></param>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator +(Complex b, Polynomial a) => a + b;
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator -(Polynomial a, Complex b) => a + new C0Polynomial(-b);
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator +(Polynomial a, Polynomial b)
|
|
{
|
|
int d = Math.Max(a.Degree, b.Degree);
|
|
int md = Math.Min(a.Degree, b.Degree);
|
|
Polynomial lp = new[] { a, b }.MaxBy(p => p.Degree)!;
|
|
Complex[] coefficients = new Complex[d + 1];
|
|
for (int i = 0; i <= d; i++)
|
|
if (i <= md)
|
|
coefficients[i] = a.Coefficients[i] + b.Coefficients[i];
|
|
else
|
|
coefficients[i] = lp.Coefficients[i];
|
|
return Dispatch(coefficients);
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator -(Polynomial a)
|
|
=> Dispatch(a.Coefficients.Select(x => -x).ToArray());
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator -(Polynomial a, Polynomial b) => -b + a;
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator *(Polynomial a, Complex b)
|
|
=> Dispatch(a.Coefficients.Select(x => x * b).ToArray());
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="b"></param>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator *(Complex b, Polynomial a) => a * b;
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static Polynomial operator /(Polynomial a, Complex b)
|
|
=> Dispatch(a.Coefficients.Select(x => x / b).ToArray());
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="Exception"></exception>
|
|
public static Polynomial operator *(Polynomial a, Polynomial b)
|
|
{
|
|
int cd = a.Degree + b.Degree;
|
|
if (cd > 4)
|
|
throw new Exception("TODO");
|
|
Complex[] coefficients = new Complex[cd + 1];
|
|
for (int i = 0; i <= a.Degree; i++)
|
|
for (int j = 0; j <= b.Degree; j++)
|
|
coefficients[i + j] += a.Coefficients[i] * b.Coefficients[j];
|
|
return Dispatch(coefficients);
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public PolynomialDivisionResult LongDivision(Polynomial a)
|
|
{
|
|
if (a.Degree > Degree)
|
|
return new PolynomialDivisionResult(Zero, a);
|
|
Complex leadingC = Coefficients[Degree] / a.Coefficients[a.Degree];
|
|
int degreeDifference = Degree - a.Degree;
|
|
Polynomial q = leadingC * new Xd(degreeDifference);
|
|
Complex[] rCoefficients = Coefficients.Select(x => x).ToArray();
|
|
rCoefficients[Degree] = 0;
|
|
Polynomial r = Dispatch(rCoefficients); //this - q * a;
|
|
if (r.Degree < a.Degree || (r.Degree == 0 && a.Degree == 0))
|
|
return new PolynomialDivisionResult(q, r);
|
|
PolynomialDivisionResult rDiv = r.LongDivision(a);
|
|
return new PolynomialDivisionResult(q + rDiv.Quotient, rDiv.Remainder);
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="o"></param>
|
|
/// <returns></returns>
|
|
public Polynomial GreatestCommonDivisor(Polynomial o)
|
|
{
|
|
Polynomial g, l;
|
|
if (Degree > o.Degree)
|
|
{
|
|
g = this;
|
|
l = o;
|
|
}
|
|
else
|
|
{
|
|
g = o;
|
|
l = this;
|
|
}
|
|
|
|
while (!l.IsZero)
|
|
{
|
|
PolynomialDivisionResult div = g.LongDivision(l); // = g.LongDivision(l);
|
|
g = l;
|
|
l = div.Remainder;
|
|
}
|
|
|
|
return g;
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
protected void Fix()
|
|
{
|
|
for (int i = 0; i < Dim; i++)
|
|
Coefficients[i] = ComplexFieldStructure.Structure.Fix(Coefficients[i]);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override Complex Evaluate(Complex x)
|
|
=> Enumerable
|
|
.Range(0, Degree + 1)
|
|
.Reverse()
|
|
.Select(i => Coefficients[i])
|
|
.Aggregate((x1, x2) => x1 * x + x2);
|
|
} |