Пример #1
0
        private static void ToSimplestForm(PolynomialTerm[] terms_in, out PolynomialTerm[] terms_out)
        {
            var termDictionary = new Dictionary <int, PolynomialTerm>();

            for (int i = 0; i < terms_in.Length; i++)
            {
                var degree = terms_in[i].Degree;
                if (termDictionary.ContainsKey(degree))
                {
                    var currentTerm = termDictionary[degree];

                    termDictionary[degree] = new PolynomialTerm(currentTerm.Coefficient + terms_in[i].Coefficient, degree);
                }
                else if (terms_in[i] != PolynomialTerm.Zero)
                {
                    termDictionary.Add(terms_in[i].Degree, terms_in[i]);
                }
            }
            var result =
                termDictionary.Values
                .Where(t => t != PolynomialTerm.Zero)
                .OrderBy(t => t.Degree)
                .ToArray();

            if (result.Length == 0)
            {
                result = new PolynomialTerm[1] {
                    PolynomialTerm.Zero
                }
            }
            ;
            terms_out = result;
        }
Пример #2
0
 public void ExtractTermsContainingNthRoot(
     BigInteger radicand,
     int index,
     out Polynomial p_reduced,
     out Polynomial p_extract)
 {
     p_reduced = Polynomial.Zero;
     p_extract = Polynomial.Zero;
     for (int i = 0; i < Terms.Length; i++)
     {
         var        coeff         = Terms[i].Coefficient;
         RadicalSum coeff_reduced = coeff;
         RadicalSum coeff_target  = RadicalSum.Zero;
         for (int j = 0; j < coeff.Radicals.Length; j++)
         {
             if (coeff.Radicals[j].Index == index)
             {
                 if (coeff.Radicals[j].Radicand % radicand == 0)
                 {
                     coeff_target  += coeff.Radicals[j];
                     coeff_reduced -= coeff.Radicals[j];
                 }
             }
         }
         p_reduced += new PolynomialTerm(coeff_reduced, Terms[i].Degree);
         p_extract += new PolynomialTerm(coeff_target, Terms[i].Degree);
     }
 }
Пример #3
0
        public static Polynomial Divide(Polynomial left, Radical right)
        {
            var terms = new PolynomialTerm[left.Terms.Length];

            for (int i = 0; i < left.Terms.Length; i++)
            {
                terms[i] = new PolynomialTerm(left.Terms[i].Coefficient / right, left.Terms[i].Degree);
            }
            return(new Polynomial(terms));
        }
Пример #4
0
        public static Polynomial Add(Polynomial left, Polynomial right)
        {
            var terms = new PolynomialTerm[left.Terms.Length + right.Terms.Length];

            left.Terms.CopyTo(terms, 0);
            right.Terms.CopyTo(terms, left.Terms.Length);
            var result = new Polynomial(terms);

            return(result);
        }
Пример #5
0
        public static Polynomial DivideByX(Polynomial value)
        {
            var terms = new PolynomialTerm[value.Terms.Length];

            for (int i = 0; i < value.Terms.Length; i++)
            {
                terms[i] = new PolynomialTerm(value.Terms[i].Coefficient, value.Terms[i].Degree - 1);
            }
            var result = new Polynomial(terms);

            return(result);
        }
Пример #6
0
        public static Polynomial Negate(Polynomial value)
        {
            var terms = new PolynomialTerm[value.Terms.Length];

            for (int i = 0; i < value.Terms.Length; i++)
            {
                terms[i] = -value.Terms[i];
            }
            var result = new Polynomial(terms);

            return(result);
        }
Пример #7
0
        public static Polynomial Multiply(Polynomial left, Polynomial right)
        {
            var terms = new PolynomialTerm[left.Terms.Length * right.Terms.Length];

            for (int i = 0; i < left.Terms.Length; i++)
            {
                for (int j = 0; j < right.Terms.Length; j++)
                {
                    terms[(i * right.Terms.Length) + j] = left.Terms[i] * right.Terms[j];
                }
            }
            return(new Polynomial(terms));
        }
Пример #8
0
        /// <summary>
        /// Returns multiplicative inverse, i.e., B such that this * B = 1
        /// </summary>
        /// <returns></returns>
        public static RadicalSum GetRationalizer(RadicalSum value)
        {
            // Method derived from:
            // Rationalizing Denominators
            // Allan Berele and Stefan Catoiu
            // https://www.jstor.org/stable/10.4169/mathmaga.88.issue-2
            // See Example 9

            if (value == 0)
            {
                throw new Exception("Cannot get rationalization of zero");
            }

            // Solve for the largest field extensions in turn
            // S = r_1 + r_2 + ... + r_n
            // r_n = S - r_1 - r_2 - ... - r_(n-1)
            // r_n^2 = [S - r_1 - r_2 - ... - r_(n-1)]^2


            // Create polynomial in S
            // S - r_1 - r_2 - ... - r_n = 0
            var term1 = new Polynomials.PolynomialTerm(1, 1);
            var term0 = new Polynomials.PolynomialTerm(-value, 0);
            var p     = new Polynomials.Polynomial(new Polynomials.PolynomialTerm[2] {
                term0, term1
            });

            // Get the set of unique indexes and radicands for each index
            var uniquePrimeNthRoots = p.GetUniquePrimeNthRoots();

            // Main loop
            for (int i = uniquePrimeNthRoots.Length - 1; i >= 0; i--)
            {
                var currentPrimeNthRoot = uniquePrimeNthRoots[i];
                if (currentPrimeNthRoot.Item1 < 2) // Index
                {
                    continue;
                }
                if (currentPrimeNthRoot.Item2 < 2) // Radicand
                {
                    continue;
                }
                // Solve for largest radicand
                // p = p_reduced + p_extract = 0
                // p_extract = root[currentIndex](currentRadicand) * p' for some p'
                Polynomials.Polynomial p_reduced;
                Polynomials.Polynomial p_extract;
                p.ExtractTermsContainingNthRoot(
                    radicand: currentPrimeNthRoot.Item2,
                    index: currentPrimeNthRoot.Item1,
                    p_reduced: out p_reduced,
                    p_extract: out p_extract);

                // Remove root[currentIndex](currentRadicand) to keep p' === p_extract_coefficient
                var r = new Radical(1, currentPrimeNthRoot.Item2, currentPrimeNthRoot.Item1);
                var p_extract_coefficient = p_extract /= r;

                // p_reduced = -p_extract
                // p_reduced^currentIndex = (-p_extract)^currentIndex
                // p_reduced^currentIndex = (-p_extract_coefficient)^currentIndex * currentRadicand
                // p => p_reduced^currentIndex - currentRadicand * (-p_extract_coefficient)^currentIndex = 0
                var left  = Polynomials.Polynomial.Pow(p_reduced, currentPrimeNthRoot.Item1);
                var right = Polynomials.Polynomial.Pow(-p_extract, currentPrimeNthRoot.Item1) * currentPrimeNthRoot.Item2;
                p = left - right;
            }

            // We now have a polynomial in S with all radicals removed:
            // a_0 + a_1 * S + a_2 * S^2 + ... + a_n * S^n = 0
            // Radicalizer then becomes:
            // -a_0 / S = a_1 + a_2 * S + ... + a_n * S^(n-1)
            //
            // 1   a_1 + a_2 * S + ... + a_n * S^(n-1)
            // - = -----------------------------------
            // S                 -a_0
            var constantTerm = p.GetConstantTerm();
            var constantP    = new Polynomials.Polynomial(constantTerm);

            p -= constantP;
            if (!p.IsDivisibleByX)
            {
                throw new Exception("All terms should have at least degree 1");
            }
            if (!constantTerm.IsRational)
            {
                throw new Exception("No radicals should remain in any terms");
            }
            p  = Polynomials.Polynomial.DivideByX(p);
            p /= (Rational)(-constantTerm);

            var rationalizer = p.EvaluateAt(value);

            return(rationalizer);
        }
Пример #9
0
 public Polynomial(PolynomialTerm term)
     : this(new PolynomialTerm[1] {
     term
 })
 {
 }
Пример #10
0
        public static Polynomial Pow(Polynomial value, int exponent)
        {
            // Naive implementation is SLOW
            // Attempt to make more efficient using multinomial theorem:
            // https://en.wikipedia.org/wiki/Multinomial_theorem
            // Replace x1, x2, ..., xm with polynomial terms X^0, X^1, ..., X^m-1
            // Need to partition exponent as a sum of at most value.Terms.Length === m integers

            // Pre-calculate powers of each term's coefficient in the polynomial, and cache them
            // Item1: term index
            // Item2: power
            var polynomialTermCoefficientPowers = new Dictionary <Tuple <int, int>, RadicalSum>();

            for (int termIndex = 0; termIndex < value.Terms.Length; termIndex++)
            {
                for (int power = 0; power <= exponent; power++)
                {
                    var key       = new Tuple <int, int>(termIndex, power);
                    var termPower = RadicalSum.Pow(value.Terms[termIndex].Coefficient, power);
                    polynomialTermCoefficientPowers.Add(key, termPower);
                }
            }

            // Get the unique partitions first, along with the multinomial coefficient associated with them
            // These correspond to unique integers k1, k2, ..., km such that k1 + k2 + ... + km = n
            var maxTerms         = Math.Min(exponent, value.Terms.Length);
            var degreePartitions = Combinatorics.IntegerPartition.GetIntegerPartitions(exponent, maxTerms);
            var degreePartitionsWithMultinomialCoefficient =
                degreePartitions
                .Select(p => new Tuple <Combinatorics.IntegerPartition, BigInteger>(
                            p,
                            GetMultinomialCoefficient(p.Values, exponent)))
                .ToList();
            // From the unique partitions, get all permutations
            // These correspond to all possible k1 + k2 + ... + km = n in the multinomial theorem
            // For each permutation, calculate the degree in X; this will be used to help group terms later
            // Item1: permutation
            // Item2: multinomial coefficient
            // Item3: degree in X (e.g., X^2, X^3, etc)
            var termDescriptions = new List <Tuple <Combinatorics.Permutation, BigInteger, int> >();

            foreach (Tuple <Combinatorics.IntegerPartition, BigInteger> partition in degreePartitionsWithMultinomialCoefficient)
            {
                var permutations =
                    Combinatorics.Permutation.ArrangeInSlots(partition.Item1.Values, value.Terms.Length, false);
                foreach (Combinatorics.Permutation p in permutations)
                {
                    var degreeX         = GetPermutationDegree(p.Values, value);
                    var termDescription =
                        new Tuple <Combinatorics.Permutation, BigInteger, int>(
                            p,
                            partition.Item2,
                            degreeX);
                    termDescriptions.Add(termDescription);
                }
            }

            // Start multithreading block
            // Initialize dictionary of terms for each degree in X
            var degreeRadicalSumDictionary = new Dictionary <int, List <RadicalSum> >();
            int processCount = termDescriptions.Count;
            var doneEvent    = new ManualResetEvent(false);

            for (int termDescriptionIndex = 0; termDescriptionIndex < termDescriptions.Count; termDescriptionIndex++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
                {
                    var termDescription =
                        (Tuple <Combinatorics.Permutation, BigInteger, int>)obj;
                    // Calculate term for this permutation in multinomial formula
                    var coefficient = RadicalSum.One;
                    for (int i = 0; i < value.Terms.Length; i++)
                    {
                        // term index, coefficient degree
                        var key = new Tuple <int, int>(i, termDescription.Item1.Values[i]);
                        var polynomialTermCoefficientPower = polynomialTermCoefficientPowers[key];
                        coefficient *= polynomialTermCoefficientPower;
                    }
                    coefficient *= termDescription.Item2;

                    lock (degreeRadicalSumDictionary)
                    {
                        if (degreeRadicalSumDictionary.ContainsKey(termDescription.Item3))
                        {
                            var existingTermList = degreeRadicalSumDictionary[termDescription.Item3];
                            existingTermList.Add(coefficient);
                        }
                        else
                        {
                            var termList = new List <RadicalSum>();
                            termList.Add(coefficient);
                            degreeRadicalSumDictionary.Add(termDescription.Item3, termList);
                        }
                    }

                    if (Interlocked.Decrement(ref processCount) == 0)
                    {
                        doneEvent.Set();
                    }
                }), termDescriptions[termDescriptionIndex]);
            }
            doneEvent.WaitOne();


            // Combine terms for each degree in X
            var polynomialTerms = new List <PolynomialTerm>();

            doneEvent    = new ManualResetEvent(false);
            processCount = degreeRadicalSumDictionary.Count;
            foreach (KeyValuePair <int, List <RadicalSum> > kvp in degreeRadicalSumDictionary)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
                {
                    var key =
                        (KeyValuePair <int, List <RadicalSum> >)obj;
                    // Combine terms
                    var coefficient = RadicalSum.Zero;
                    foreach (RadicalSum radicalSum in key.Value)
                    {
                        coefficient += radicalSum;
                    }
                    var term = new PolynomialTerm(coefficient, key.Key);
                    lock (polynomialTerms)
                    {
                        polynomialTerms.Add(term);
                    }
                    if (Interlocked.Decrement(ref processCount) == 0)
                    {
                        doneEvent.Set();
                    }
                }), kvp);
            }
            doneEvent.WaitOne();

            var result = new Polynomials.Polynomial(polynomialTerms.OrderBy(p => p.Degree).ToArray());

            return(result);
        }