diff --git a/src/Numerics/Polynomial.cs b/src/Numerics/Polynomial.cs new file mode 100644 index 00000000..360cfb27 --- /dev/null +++ b/src/Numerics/Polynomial.cs @@ -0,0 +1,471 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Numerics; +using MathNet.Numerics; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.LinearAlgebra.Double; +using MathNet.Numerics.Statistics; +using MathNet.Numerics.IntegralTransforms; + +using MathNet.Numerics.LinearAlgebra.Factorization; + + +namespace MathNet.Numerics +{ + /// + /// a class handlin REAL VALUED Polynomials, complex coefficients can not be handled (yet) + /// + public class Polynomial + { + + public double[] Coeffs { get; set; } + + /// + /// indicator if Polynomial was flipped + /// + public bool IsFlipped { get; } + + /// + /// Only needed for the ToString method + /// + public string VarName = "x^"; + + /// + /// Length of Polynomial (max element + 1) e.G x^5 highest element, will give Length = 6 + /// + public int Length + { + get + { + return (Coeffs.Length); + } + } + + /// + /// constructor setting a Polynomial of size n containing only zeros + /// + /// size of Polynomial + public Polynomial(int n) + { + Coeffs = new double[n]; + } + + /// + /// constructor setting Polynomial coefficiens and flipping them if necessary. + /// + /// e.G: + /// var x = new double[] {5, 4, 3, 0, 2}; + /// var xP1 = new Polynomial(x, isFlip:true); + /// var xP2 = new Polynomial(x, isFlip:false); + /// + /// xP1: 5 x^3 + 4 x^2 + 3 x^2 + 0 x^1 + 2 + /// xP2: 2 x^3 + 0 x^2 + 3 x^2 + 4 x^1 + 5 + /// + /// WARNING cut all trailing zeros before, since they would result in zeros at the end + /// + /// Polynomial coefficiens as array + /// use true for flipping + public Polynomial(double[] coeffs, bool isFlip = false) + { + this.Coeffs = new double[Coeffs.Length]; + Array.Copy(coeffs, Coeffs, coeffs.Length); + + if (isFlip) + { + Coeffs = Coeffs.Reverse().ToArray(); + IsFlipped = true; + } + } + + /// + /// constructor setting Polynomial coefficiens + /// + /// just the x^0 part + public Polynomial(double coeff) + { + IsFlipped = false; + this.Coeffs = new double[1]; + Coeffs[0] = coeff; + } + + /// + /// constructor setting Polynomial coefficiens + /// + /// Polynomial coefficiens as array + public Polynomial(double[] Coeffs) + { + this.Coeffs = new double[Coeffs.Length]; + Array.Copy(Coeffs, this.Coeffs, Coeffs.Length); + } + + /// + /// remove all trailing zeros, e.G before: "0.00 x^2 + 1.0 x^1 + 1.00" after: "1.0 x^1 + 1.00" + /// + public void CutTrailZeros() + { + int count = 0; + for (int ii = Length - 1; ii >= 0; ii--) + { + if (Coeffs[ii] == 0.0) + { + count++; + } + else + { + double[] CoeffsHold = new double[Length]; + Coeffs.CopyTo(CoeffsHold, 0); + Array.Resize(ref CoeffsHold, Length - count); + Coeffs = new double[Length - count]; + CoeffsHold.CopyTo(Coeffs, 0); + return; + } + } + } + + #region Operators + + + /// + /// multiplies a Polynomial by a Polynomial using convolution [ASINCO.libs.subfun.conv(a.Coeffs, b.Coeffs)] + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial operator *( Polynomial a, Polynomial b) + { + // do not cut trailing zeros, since it may corrupt the outcom, if the array is of form 1 + x^-1 + x^-2 + x^-3 + //a.CutTrailZeros(); + //b.CutTrailZeros(); + + double[] ret = conv(a.Coeffs, b.Coeffs); + Polynomial ret_p = new Polynomial(ret); + + //ret_p.CutTrailZeros(); + + return (ret_p); + + } + + /// + /// multiplies a Polynomial by a scalar + /// + /// left Polynomial + /// scalar value + /// resulting Polynomial + public static Polynomial operator *( Polynomial a, double k) + { + for (int ii = 0; ii < a.Length; ii++) + a.Coeffs[ii] *= k; + + return a; + } + + /// + /// adds a scalar to a Polynomial (to the x^0 element) + /// + /// left Polynomial + /// scalar value + /// resulting Polynomial + public static Polynomial operator +( Polynomial a, double k) + { + a.Coeffs[0] += k; + return a; + } + + /// + /// substracs a scalar from a Polynomial (from the x^0 element) + /// + /// left Polynomial + /// scalar value + /// resulting Polynomial + public static Polynomial operator -( Polynomial a, double k) + { + + a.Coeffs[0] -= k; + return a; + } + + /// + /// divide Polynomial by scalar value + /// + /// left Polynomial + /// scalar value + /// resulting Polynomial + public static Polynomial operator /( Polynomial a, double k) + { + for (int ii = 0; ii < a.Length; ii++) + a.Coeffs[ii] /= k; + + return a; + } + + /// + /// Addition of two Polynomials (piecewise) + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial operator +( Polynomial a, Polynomial b) + { + return add(a, b); + } + + /// + /// substraction of two Polynomials (piecewise) + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial operator -( Polynomial a, Polynomial b) + { + return substract(a, b); + } + + /// + /// Calculates the complex roots of the Polynomial in the same way as matlab does + /// + /// a vector of complex numbers with the roots + public Complex[] GetRoots() + { + DenseMatrix A = this.GetEigValMatrix(); + Complex[] c_vec; + + if (A == null) + { + if (Coeffs.Length < 2) + { + var val = Coeffs.Length == 1 ? Coeffs[0] : Double.NaN; + c_vec = new Complex[1] { val }; + } + else + c_vec = new Complex[1] { new Complex(-Coeffs[0] / Coeffs[1], 0) }; + } + else + { + Evd eigen = A.Evd(Symmetricity.Asymmetric); + c_vec = eigen.EigenValues.ToArray(); + } + return c_vec; + } + + /// + /// get the eigenvalue matrix A of this Polynomial such that eig(A) = roots of this Polynomial + /// + /// Eigenvalue matrix A + public DenseMatrix GetEigValMatrix() + { + Polynomial pLoc = new Polynomial(this.Coeffs); + pLoc.CutTrailZeros(); + + int n = pLoc.Length - 1; + if (n < 2) + return null; + + double[] p = new double[n]; + + double a0 = pLoc.Coeffs[p.Length]; + + for (int ii = n - 1; ii >= 0; ii--) + p[ii] = -pLoc.Coeffs[ii] / a0; + + DenseMatrix A0 = DenseMatrix.CreateDiagonal(n - 1, n - 1, 1.0); + DenseMatrix A = new DenseMatrix(n); + + A.SetSubMatrix(1, 0, A0); + + A.SetRow(0, p.Reverse().ToArray()); + return A; + } + + /// + /// pointwise division of two Polynomials + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial DividePointwise( Polynomial a, Polynomial b) + { + if (a.Length != b.Length) + mkSameLength(ref a, ref b); + + int n = a.Length; + double[] res = new double[a.Length]; + + + for (int ii = 0; ii < n; ii++) + { + res[ii] = a.Coeffs[ii] / b.Coeffs[ii]; + } + Polynomial res_poly = new Polynomial(res); + return (res_poly); + } + + /// + /// pointwise multiplication of two Polynomials + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial MultiplyPointwise( Polynomial a, Polynomial b) + { + if (a.Length != b.Length) + mkSameLength(ref a, ref b); + + int n = a.Length; + double[] res = new double[a.Length]; + + + for (int ii = 0; ii < n; ii++) + { + res[ii] = a.Coeffs[ii] * b.Coeffs[ii]; + } + Polynomial res_poly = new Polynomial(res); + return (res_poly); + } + + /// + /// Addition of two Polynomials (piecewise) + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial add( Polynomial a, Polynomial b) + { + + if (a.Length != b.Length) + mkSameLength(ref a, ref b); + + int n = a.Length; + double[] res = new double[a.Length]; + + + for (int ii = 0; ii < n; ii++) + { + res[ii] = a.Coeffs[ii] + b.Coeffs[ii]; + } + Polynomial res_poly = new Polynomial(res); + return (res_poly); + } + + /// + /// substraction of two Polynomials (piecewise) + /// + /// left Polynomial + /// right Polynomial + /// resulting Polynomial + public static Polynomial substract( Polynomial a, Polynomial b) + { + + if (a.Length != b.Length) + mkSameLength(ref a, ref b); + + int n = a.Length; + double[] res = new double[a.Length]; + + + for (int ii = 0; ii < n; ii++) + { + res[ii] = a.Coeffs[ii] - b.Coeffs[ii]; + } + Polynomial res_poly = new Polynomial(res); + return (res_poly); + } + + #endregion + + #region Displaying + /// + /// "0.00 x^3 + 0.00 x^2 + 0.00 x^1 + 0.00" like display of this Polynomial + /// + /// string in displayed format + public override string ToString() + { + string strLoc = ""; + + for (int ii = Length - 1; ii >= 0; ii--) + { + + if (ii == 0) + strLoc = String.Concat(strLoc, this.Coeffs[ii].ToString()); + else + strLoc = String.Concat(strLoc, this.Coeffs[ii].ToString(), VarName, ii.ToString(), " + "); + } + return strLoc; + } + + #endregion + + #region Interfacing + + /// + /// This method returns the coefficcients of the Polynomial as an array the "IsFlipped" property, + /// which is set during construction is taken into account automatically. + /// + /// the coefficcients of the Polynomial as an array + public double[] ToArray() + { + if (IsFlipped == true) + return (Coeffs.Reverse().ToArray()); + else + return (Coeffs); + } + + #endregion + + #region Helpers + + private static void mkSameLength(ref Polynomial a, ref Polynomial b) + { + double[] aHold = new double[a.Length]; + double[] bHold = new double[b.Length]; + Array.Copy(a.Coeffs, aHold, a.Length); + Array.Copy(b.Coeffs, bHold, b.Length); + + if (a.Length < b.Length) + { + a.Coeffs = new double[b.Length]; + b.Coeffs = new double[b.Length]; + Array.Copy(aHold, a.Coeffs, aHold.Length); + Array.Copy(bHold, b.Coeffs, bHold.Length); + } + else + { + a.Coeffs = new double[a.Length]; + b.Coeffs = new double[a.Length]; + Array.Copy(aHold, a.Coeffs, aHold.Length); + Array.Copy(bHold, b.Coeffs, bHold.Length); + } + + } + + /// + /// (full) convolution of two arrays + /// + /// left vector + /// right vector + /// convolution of a and b as vector + private static double[] conv(double[] a, double[] b) + { + double[] ret = new double[a.Length + b.Length]; + + for (int i = 0; i < a.Length; i++) + { + for (int j = 0; j < b.Length; j++) + { + ret[i + j] += a[i] * b[j]; + } + } + return ret; + } + #endregion + + } + +}