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; }
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); } }
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)); }
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); }
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); }
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); }
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)); }
/// <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); }
public Polynomial(PolynomialTerm term) : this(new PolynomialTerm[1] { term }) { }
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); }