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;
///
///
public abstract class Polynomial : Analytic, IPolynomial
{
///
///
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)));
///
///
public bool IsConstant =>
Decorators.WithTol(1E-30, () => Coefficients.Skip(1).All(x => x.IsEqualApprox(Complex.Zero)));
///
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);
}
}
///
///
public virtual string Representation =>
string.Join(
" + ",
Coefficients
.Zip(Enumerable.Range(0, Degree + 1))
.Select(
x
=> "(" +
ComplexFieldStructure.Structure.Representation(x.First) +
$")x^{x.Second}"
)
);
///
///
public abstract IEnumerable Roots { get; }
///
public abstract int Dim { get; }
///
public int Degree
{
get
{
for (int i = 0; i <= Dim; i++)
if (Coefficients[^(i + 1)] != Complex.Zero)
return Dim - i;
return 0;
}
}
///
public Complex[] Coefficients { get; set; } = Array.Empty();
///
public abstract BivariantContinuous Re { get; }
///
public abstract BivariantContinuous Im { get; }
///
///
///
///
///
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)
};
}
///
///
///
///
///
public static Polynomial operator +(Polynomial a, Complex b) => a + new C0Polynomial(b);
///
///
///
///
///
public static Polynomial operator +(Complex b, Polynomial a) => a + b;
///
///
///
///
///
public static Polynomial operator -(Polynomial a, Complex b) => a + new C0Polynomial(-b);
///
///
///
///
///
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);
}
///
///
///
///
public static Polynomial operator -(Polynomial a)
=> Dispatch(a.Coefficients.Select(x => -x).ToArray());
///
///
///
///
///
public static Polynomial operator -(Polynomial a, Polynomial b) => -b + a;
///
///
///
///
///
public static Polynomial operator *(Polynomial a, Complex b)
=> Dispatch(a.Coefficients.Select(x => x * b).ToArray());
///
///
///
///
///
public static Polynomial operator *(Complex b, Polynomial a) => a * b;
///
///
///
///
///
public static Polynomial operator /(Polynomial a, Complex b)
=> Dispatch(a.Coefficients.Select(x => x / b).ToArray());
///
///
///
///
///
///
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);
}
///
///
///
///
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);
}
///
///
///
///
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;
}
///
///
protected void Fix()
{
for (int i = 0; i < Dim; i++)
Coefficients[i] = ComplexFieldStructure.Structure.Fix(Coefficients[i]);
}
///
public override Complex Evaluate(Complex x)
=> Enumerable
.Range(0, Degree + 1)
.Reverse()
.Select(i => Coefficients[i])
.Aggregate((x1, x2) => x1 * x + x2);
}