public static IComplexPolynomial GCDMod(IComplexPolynomial left, IComplexPolynomial right, Complex polynomialBase)
        {
            IComplexPolynomial a = left.Clone();
            IComplexPolynomial b = right.Clone();


            Swap(ref a, ref b);

            while (a.Degree != b.Degree)
            {
                IComplexPolynomial smallerA = ComplexPolynomial.ReduceDegree(a, polynomialBase);
                a = smallerA;

                Swap(ref a, ref b);
            }

            while (a.Degree != 1)
            {
                IComplexPolynomial smallerA = ComplexPolynomial.ReduceDegree(a, polynomialBase);
                IComplexPolynomial smallerB = ComplexPolynomial.ReduceDegree(b, polynomialBase);

                a = smallerA;
                b = smallerB;

                Swap(ref a, ref b);
            }

            while (a.Degree >= 1)
            {
                Swap(ref a, ref b);

                var bSign = b.Terms.Last().CoEfficient.Sign();
                if (bSign < 0)
                {
                    break;
                }

                while (!(b.Terms.Length == 0 || b.Terms[0].CoEfficient == 0 || a.CompareTo(b) < 0))
                {
                    var aSign = a.Terms.Last().CoEfficient.Sign();
                    bSign = b.Terms.Last().CoEfficient.Sign();

                    if (aSign < 0 || bSign < 0)
                    {
                        break;
                    }

                    a = ComplexPolynomial.Subtract(a, b);
                }
            }

            if (a.Degree == 0)
            {
                return(ComplexPolynomial.One);
            }
            else
            {
                return(a);
            }
        }
        /*
         * public static bool IsIrreducibleOverField(IPoly f, Complex m, Complex p)
         * {
         * IPoly splittingField = new ComplexPoly(
         *  new PolyTerm[] {
         *      new PolyTerm(  1, (int)Complex.Abs(p)),
         *      new PolyTerm( -1, 1)
         *  });
         *
         * IPoly reducedField = ComplexPoly.ModMod(splittingField, f, p);
         *
         * if (!EisensteinsIrreducibilityCriterion(reducedField, p))
         * {
         * return false;
         * }
         *
         * Complex fieldValue = reducedField.Evaluate(m);
         *
         * IPoly gcd = ComplexPoly.GCDMod(f, reducedField, m);
         * return (gcd.CompareTo(ComplexPoly.One) == 0);
         * }
         *
         * public static bool IsIrreducibleOverP(IPoly poly, Complex p)
         * {
         * List<Complex> coefficients = poly.Terms.Select(t => t.CoEfficient).ToList();
         *
         * Complex leadingCoefficient = coefficients.Last();
         * Complex constantCoefficient = coefficients.First();
         *
         * coefficients.Remove(leadingCoefficient);
         * coefficients.Remove(constantCoefficient);
         *
         * Complex leadingRemainder = -1;
         * Complex.DivRem(leadingCoefficient, p, out leadingRemainder);
         *
         * Complex constantRemainder = -1;
         * Complex.DivRem(constantCoefficient, p.Square(), out constantRemainder);
         *
         * bool result = (leadingRemainder != 0); // p does not divide leading coefficient
         *
         * result &= (constantRemainder != 0);    // p^2 does not divide constant coefficient
         *
         * coefficients.Add(p);
         * result &= (Maths.GCD(coefficients) == 1);
         *
         * return result;
         * }
         */

        #endregion

        public static void Swap(ref IComplexPolynomial a, ref IComplexPolynomial b)
        {
            if (b.CompareTo(a) > 0)
            {
                IComplexPolynomial swap = b;
                b = a;
                a = swap;
            }
        }
        public static IComplexPolynomial ExtendedGCD(IComplexPolynomial left, IComplexPolynomial right, Complex mod)
        {
            IComplexPolynomial rem = ComplexPolynomial.Two;
            IComplexPolynomial a   = left.Clone();
            IComplexPolynomial b   = right.Clone();
            IComplexPolynomial c   = ComplexPolynomial.Zero;


            while (c.CompareTo(ComplexPolynomial.Zero) != 0 && rem.CompareTo(ComplexPolynomial.Zero) != 0 && rem.CompareTo(ComplexPolynomial.One) != 0)
            {
                c = ComplexPolynomial.Divide(a, b, out rem);

                a = b;
                b = rem;
            }

            if (rem.CompareTo(ComplexPolynomial.Zero) != 0 || rem.CompareTo(ComplexPolynomial.One) != 0)
            {
                return(ComplexPolynomial.One);
            }

            return(rem);
        }
        public static IComplexPolynomial Mod(IComplexPolynomial poly, IComplexPolynomial mod)
        {
            int sortOrder = mod.CompareTo(poly);

            if (sortOrder > 0)
            {
                return(poly.Clone());
            }
            else if (sortOrder == 0)
            {
                return(ComplexPolynomial.Zero);
            }

            IComplexPolynomial remainder = new ComplexPolynomial();

            Divide(poly, mod, out remainder);

            return(remainder);
        }
        public static IComplexPolynomial DivideMod(IComplexPolynomial left, IComplexPolynomial right, Complex mod, out IComplexPolynomial remainder)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }
            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }
            if (right.Degree > left.Degree || right.CompareTo(left) == 1)
            {
                remainder = ComplexPolynomial.Zero; return(left);
            }

            int     rightDegree       = right.Degree;
            int     quotientDegree    = (left.Degree - rightDegree) + 1;
            Complex leadingCoefficent = right[rightDegree].Clone().Mod(mod);

            IComplexPolynomial rem      = left.Clone();
            IComplexPolynomial quotient = ComplexPolynomial.Zero;

            // The leading coefficient is the only number we ever divide by
            // (so if right is monic, polynomial division does not involve division at all!)
            for (int i = quotientDegree - 1; i >= 0; i--)
            {
                quotient[i]          = Complex.Divide(rem[rightDegree + i], leadingCoefficent).Mod(mod);
                rem[rightDegree + i] = Complex.Zero;

                for (int j = rightDegree + i - 1; j >= i; j--)
                {
                    rem[j] = Complex.Subtract(rem[j], Complex.Multiply(quotient[i], right[j - i]).Mod(mod)).Mod(mod);
                }
            }

            // Remove zeros
            rem.RemoveZeros();
            quotient.RemoveZeros();

            remainder = rem;
            return(quotient);
        }
        /*
         * public static IPoly ExponentiateMod(IPoly startPoly, Complex s2, IPoly f, Complex p)
         * {
         * IPoly result = ComplexPoly.One;
         * if (s2 == 0) { return result; }
         *
         * IPoly A = startPoly.Clone();
         *
         * byte[] byteArray = s2.ToByteArray();
         * bool[] bitArray = new BitArray(byteArray).Cast<bool>().ToArray();
         *
         * // Remove trailing zeros ?
         * if (bitArray[0] == true)
         * {
         * result = startPoly;
         * }
         *
         * int i = 1;
         * int t = bitArray.Length;
         * while (i < t)
         * {
         * A = ComplexPoly.ModMod(ComplexPoly.Square(A), f, p);
         * if (bitArray[i] == true)
         * {
         *  result = ComplexPoly.ModMod(ComplexPoly.Multiply(A, result), f, p);
         * }
         * i++;
         * }
         *
         * return result;
         * }
         */

        #endregion

        public static IComplexPolynomial ModPow(IComplexPolynomial poly, Complex exponent, IComplexPolynomial modulus)
        {
            //if (exponent.Sign() == -1)
            //{
            //	throw new NotImplementedException("Raising a polynomial to a negative exponent not supported. Build this functionality if it is needed.");
            //}
            if (exponent == Complex.Zero)
            {
                return(ComplexPolynomial.One);
            }
            else if (exponent == Complex.One)
            {
                return(poly.Clone());
            }
            else if (exponent == 2)
            {
                return(ComplexPolynomial.Square(poly));
            }

            IComplexPolynomial total = ComplexPolynomial.Square(poly);

            Complex counter = exponent - 2;

            while (counter != 0)
            {
                total = Multiply(poly, total);

                if (total.CompareTo(modulus) < 0)
                {
                    total = ComplexPolynomial.Mod(total, modulus);
                }

                counter -= 1;
            }

            return(total);
        }
 public bool Equals(IComplexPolynomial x, IComplexPolynomial y)
 {
     return(x.CompareTo(y) == 0);
 }