public void ShouldFindEmptySolution(LinearSystemSolverTestCase testCase)
        {
            // When
            var actualSolution = _gaussSolver.Solve(testCase.A, testCase.B);

            // Then
            Assert.Equal(testCase.Expected, actualSolution);
        }
        public void ShouldFindEmptySolution(FieldElement[,] a, FieldElement[] b, SystemSolution expectedSolution)
        {
            // When
            var actualSolution = _gausSolver.Solve(a, b);

            // Then
            Assert.Equal(expectedSolution, actualSolution);
        }
        /// <summary>
        /// Method for transforming linear system matrix into rectangular form and finding system solution
        /// </summary>
        /// <param name="field">Finite field from which system coefficients were taken</param>
        /// <param name="variablesCount">Variables count</param>
        /// <param name="equationsSystem">Linear system's representation</param>
        /// <returns>Linear system's solution</returns>
        private SystemSolution SolveEquationsSystem(
            GaloisField field,
            int variablesCount,
            IReadOnlyList <List <Tuple <int, FieldElement> > > equationsSystem)
        {
            var linearSystemMatrix = new FieldElement[equationsSystem.Count, variablesCount];
            var zeros = new FieldElement[equationsSystem.Count];

            for (var i = 0; i < equationsSystem.Count; i++)
            {
                zeros[i] = field.Zero();
                for (var j = 0; j < variablesCount; j++)
                {
                    linearSystemMatrix[i, j] = field.Zero();
                }
            }
            for (var i = 0; i < equationsSystem.Count; i++)
            {
                for (var j = 0; j < equationsSystem[i].Count; j++)
                {
                    linearSystemMatrix[i, equationsSystem[i][j].Item1] = equationsSystem[i][j].Item2;
                }
            }

            return(_linearSystemSolver.Solve(linearSystemMatrix, zeros));
        }
        /// <summary>
        /// Method for computing information polynomial
        /// </summary>
        /// <param name="k">Information word length</param>
        /// <param name="errorsCount">Errors count</param>
        /// <param name="equationsSystem">Equations system</param>
        /// <returns>Computed information polynomial</returns>
        private Polynomial ComputeInformationPolynomial(int k, int errorsCount, Tuple <FieldElement[, ], FieldElement[]> equationsSystem)
        {
            var solution = _linearSystemSolver.Solve(equationsSystem.Item1, equationsSystem.Item2);

            if (solution.IsEmpty)
            {
                throw new InformationPolynomialWasNotFoundException();
            }

            var field = solution.VariablesValues[0].Field;

            var q = new Polynomial(field,
                                   solution.VariablesValues
                                   .Take(k + errorsCount)
                                   .Select(x => x.Representation)
                                   .ToArray());
            var e = new Polynomial(field,
                                   solution.VariablesValues
                                   .Skip(k + errorsCount)
                                   .Select(x => x.Representation)
                                   .Concat(new[] { 1 })
                                   .ToArray());

            return(q / e);
        }
        /// <summary>
        /// Method for finding lifting polynomial for filters pair (<paramref name="h"/>, <paramref name="g"/>)
        /// </summary>
        /// <param name="h">First filter from the original pair</param>
        /// <param name="g">Second filter from the original pair</param>
        /// <param name="equationsCount">Equations count</param>
        /// <param name="variablesCount">Variables count</param>
        /// <returns>Finded lifting polynomial</returns>
        private Polynomial FindLiftingPolynomial(Polynomial h, Polynomial g, int equationsCount, int variablesCount)
        {
            var field = h.Field;
            var correctedEquationsCount = Math.Max(equationsCount, variablesCount);

            var linearSystemMatrix = new FieldElement[correctedEquationsCount, variablesCount];

            for (var i = 0; i < variablesCount; i++)
            {
                var sample      = new FieldElement(field, field.GetGeneratingElementPower(i));
                var sampleSqr   = sample * sample;
                var samplePower = field.One();
                var correction  = sampleSqr * new FieldElement(field, h.Evaluate(sample.Representation));
                for (var j = 0; j < variablesCount; j++)
                {
                    linearSystemMatrix[i, j] = samplePower * correction;
                    samplePower *= sampleSqr;
                }
            }

            var valuesVector = new FieldElement[correctedEquationsCount];

            for (var i = 0; i < correctedEquationsCount; i++)
            {
                var sample = new FieldElement(field, field.GetGeneratingElementPower(i));
                valuesVector[i] = new FieldElement(field, field.InverseForAddition(h.Evaluate(sample.Representation)))
                                  + sample * sample * new FieldElement(field, field.InverseForAddition(g.Evaluate(sample.Representation)));
            }
            for (var i = equationsCount; i < correctedEquationsCount; i++)
            {
                valuesVector[i] += field.One();
            }

            var systemSolution = _linearSystemSolver.Solve(linearSystemMatrix, valuesVector);

            if (systemSolution.IsEmpty)
            {
                throw new InvalidOperationException("Can't find lifting plynomial");
            }
            return(new Polynomial(field, systemSolution.VariablesValues.Select(x => x.Representation).ToArray()));
        }
        /// <summary>
        /// Method for obtaining decoding result in time domain
        /// </summary>
        /// <param name="n">Codeword length</param>
        /// <param name="k">Information word length</param>
        /// <param name="d">Code distance</param>
        /// <param name="generatingPolynomial">Generating polynomial of the wavelet code</param>
        /// <param name="generationPolynomialLeadZeroValuesCount">Generating polynomial's first zeros count on received points</param>
        /// <param name="decodedCodeword">Received codeword for decoding</param>
        /// <param name="frequencyDecodingResult">Decoding result in the frequency domain</param>
        /// <returns>Decoding result in the time domain</returns>
        protected Polynomial ComputeTimeDecodingResult(int n, int k, int d,
                                                       Polynomial generatingPolynomial, int generationPolynomialLeadZeroValuesCount,
                                                       Tuple <FieldElement, FieldElement>[] decodedCodeword, Polynomial frequencyDecodingResult)
        {
            var field             = generatingPolynomial.Field;
            var firstSampleNumber = Math.Min(generationPolynomialLeadZeroValuesCount, d - 1);

            var linearSystemMatrix = new FieldElement[n - d + 1, k];

            for (var i = 0; i < n - d + 1; i++)
            {
                var sample      = decodedCodeword[i + firstSampleNumber].Item1;
                var sampleSqr   = sample * sample;
                var samplePower = field.One();
                var correction  = new FieldElement(field, generatingPolynomial.Evaluate(sample.Representation));
                for (var j = 0; j < k; j++)
                {
                    linearSystemMatrix[i, j] = samplePower * correction;
                    samplePower *= sampleSqr;
                }
            }

            var valuesVector = new FieldElement[n - d + 1];

            for (var i = 0; i <= frequencyDecodingResult.Degree; i++)
            {
                valuesVector[i] = new FieldElement(field, frequencyDecodingResult[i]);
            }
            for (var i = frequencyDecodingResult.Degree + 1; i < n - d + 1; i++)
            {
                valuesVector[i] = field.Zero();
            }

            var systemSolution = _linearSystemSolver.Solve(linearSystemMatrix, valuesVector);

            return(systemSolution.IsEmpty == false
                ? new Polynomial(field, systemSolution.VariablesValues.Select(x => x.Representation).ToArray())
                : null);
        }