public BiVariableMonomialsComparerTests()
 {
     _comparer = new BiVariableMonomialsComparer(Tuple.Create(1, 3));
 }
        /// <summary>
        /// Method for bivariate interpolation polynomial building
        /// </summary>
        /// <param name="degreeWeight">Weight of bivariate monomials degree</param>
        /// <param name="maxWeightedDegree">Maximum value of bivariate monomial degree</param>
        /// <param name="roots">Roots of the interpolation polynomial</param>
        /// <param name="rootsMultiplicity">Multiplicity of bivariate polynomial's roots</param>
        /// <returns>Builded interpolation polynomial</returns>
        public BiVariablePolynomial Build(Tuple <int, int> degreeWeight, int maxWeightedDegree,
                                          Tuple <FieldElement, FieldElement>[] roots, int rootsMultiplicity)
        {
            if (degreeWeight == null)
            {
                throw new ArgumentNullException(nameof(degreeWeight));
            }
            if (roots == null)
            {
                throw new ArgumentNullException(nameof(roots));
            }
            if (roots.Length == 0)
            {
                throw new ArgumentException($"{nameof(roots)} is empty");
            }

            var field      = roots[0].Item1.Field;
            var maxXDegree = maxWeightedDegree / degreeWeight.Item1;
            var maxYDegree = maxWeightedDegree / degreeWeight.Item2;

            var combinationsCache        = new FieldElement[Math.Max(maxXDegree, maxYDegree) + 1][].MakeSquare();
            var transformationMultiplier = new BiVariablePolynomial(field)
            {
                [new Tuple <int, int>(1, 0)] = field.One()
            };
            var monomialsComparer = new BiVariableMonomialsComparer(degreeWeight);

            var buildingPolynomials = new BiVariablePolynomial[maxYDegree + 1];
            var leadMonomials       = new Tuple <int, int> [maxYDegree + 1];

            for (var i = 0; i < buildingPolynomials.Length; i++)
            {
                var leadMonomial = new Tuple <int, int>(0, i);
                buildingPolynomials[i] = new BiVariablePolynomial(field, (maxXDegree + 1) * (maxYDegree + 1))
                {
                    [leadMonomial] = field.One()
                };
                leadMonomials[i] = leadMonomial;
            }

            foreach (var root in roots)
            {
                for (var r = 0; r < rootsMultiplicity; r++)
                {
                    for (var s = 0; r + s < rootsMultiplicity; s++)
                    {
                        var anyCompatiblePolynomialFound = false;
                        var nonZeroDerivatives           = new List <Tuple <int, FieldElement> >();
                        for (var i = 0; i < buildingPolynomials.Length; i++)
                        {
                            if (CalculateMonomialWeight(leadMonomials[i], degreeWeight) > maxWeightedDegree)
                            {
                                continue;
                            }

                            anyCompatiblePolynomialFound = true;
                            var hasseDerivative = buildingPolynomials[i].CalculateHasseDerivative(r, s, root.Item1, root.Item2,
                                                                                                  _combinationsCountCalculator, combinationsCache);
                            if (hasseDerivative.Representation != 0)
                            {
                                nonZeroDerivatives.Add(new Tuple <int, FieldElement>(i, hasseDerivative));
                            }
                        }

                        if (anyCompatiblePolynomialFound == false)
                        {
                            throw new NonTrivialPolynomialNotFoundException();
                        }
                        if (nonZeroDerivatives.Count == 0)
                        {
                            continue;
                        }

                        var minimumIndex = FindMinimumIndexByLeadMonomial(nonZeroDerivatives,
                                                                          i => leadMonomials[nonZeroDerivatives[i].Item1], monomialsComparer);
                        var minimumPolynomialIndex = nonZeroDerivatives[minimumIndex].Item1;
                        var minimumPolynomial      = buildingPolynomials[minimumPolynomialIndex];
                        var minimumDerivative      = nonZeroDerivatives[minimumIndex].Item2;

                        for (var i = 0; i < nonZeroDerivatives.Count; i++)
                        {
                            if (i != minimumIndex)
                            {
                                buildingPolynomials[nonZeroDerivatives[i].Item1]
                                .Subtract(nonZeroDerivatives[i].Item2.Divide(minimumDerivative), minimumPolynomial);
                            }
                        }
                        transformationMultiplier[_zeroMonomial] = FieldElement.InverseForAddition(root.Item1);
                        minimumPolynomial
                        .Multiply(minimumDerivative * transformationMultiplier);
                        leadMonomials[minimumPolynomialIndex] = new Tuple <int, int>(leadMonomials[minimumPolynomialIndex].Item1 + 1,
                                                                                     leadMonomials[minimumPolynomialIndex].Item2);
                    }
                }
            }

            var resultPolynomialIndex = FindMinimumIndexByLeadMonomial(buildingPolynomials, i => leadMonomials[i], monomialsComparer);

            if (CalculateMonomialWeight(leadMonomials[resultPolynomialIndex], degreeWeight) > maxWeightedDegree)
            {
                throw new NonTrivialPolynomialNotFoundException();
            }
            return(buildingPolynomials[resultPolynomialIndex]);
        }
 public BiVariableMonomialsComparerTests()
 {
     _comparer = new BiVariableMonomialsComparer(new Tuple <int, int>(1, 3));
 }