Exemplo n.º 1
0
        /// <summary>
        /// Hensel-lifting is used when it is necessary to solve a matrix modulo p^r
        /// where p is a prime and r an integer > 1.
        /// </summary>
        /// <param name="matrix">The matrix to solve</param>
        /// <param name="mod">the prime which the modulo consists of</param>
        /// <param name="exp">the exponent for mod</param>
        /// <returns>solution of "matrix" modulo mod^exp </returns>
        public BigInteger[] Solve(List <BigInteger[]> matrix, BigInteger mod, int exp)
        {
            List <List <BigInteger[]> > As = new List <List <BigInteger[]> >(exp + 1);
            List <BigInteger[]>         bs = new List <BigInteger[]>(exp + 1);
            List <BigInteger[]>         xs = new List <BigInteger[]>(exp + 1);

            //create As:
            As.Add(matrix);
            for (int i = 0; i < (exp - 1); i++)
            {
                As.Add(SplitMatrix(As[i], BigInteger.Pow(mod, exp - i - 1)));
            }
            As.Reverse();

            //create bs:
            for (int i = 0; i < exp; i++)
            {
                bs.Add(GetLastColumnFromMatrix(As[i]));
            }

            //find xs:
            List <BigInteger[]> A0 = As[0];

            BigInteger[] b = bs[0];
            for (int i = 0; i < exp - 1; i++)
            {
                xs.Add(gauss.Solve(CreateAb(A0, b), mod));

                BigInteger[] q = DivVector(SubVectors(MultMatrixWithVector(A0, xs[i]), b), mod);
                b = SubVectors(bs[i + 1], q);
                for (int c = 0; c <= i; c++)
                {
                    b = SubVectors(b, MultMatrixWithVector(As[c + 1], xs[i - c]));
                }
            }
            xs.Add(gauss.Solve(CreateAb(A0, b), mod));

            //glue xs together:
            BigInteger[] x = new BigInteger[xs[0].Length];
            for (int i = 0; i < exp; i++)
            {
                BigInteger p = BigInteger.Pow(mod, i);
                for (int y = 0; y < x.Length; y++)
                {
                    x[y] += xs[i][y] * p;
                }
            }

            return(x);
        }
Exemplo n.º 2
0
        public BigInteger[] Solve()
        {
            /* Solving a linear equation over a residue class is not so trivial if the modulus is not a prime.
             * This is because residue classes with a composite modulus is not a field, which means that not all elements
             * of this ring do have an inverse.
             * We cope with this problem by factorizing the modulus in its prime factors and solving gauss over them
             * separately (in the case of p^q (q>1) by using "hensel lifting").
             * We can use the chinese remainder theorem to get the solution we need then.
             * But what happens if we aren't able to factorize the modulus completely, because this is to inefficient?
             * There is a simple trick to cope with that:
             * Try the gauss algorithm with the composite modulus. Either you have luck and it works out without a problem
             * (in this case we can just go on), or the gauss algorithm will have a problem inverting some number.
             * In the last case, we can search for the gcd of this number and the composite modulus. This gcd is a factor of the modulus,
             * so that solving the equation helped us finding the factorization.
             */

            FiniteFieldGauss gauss  = new FiniteFieldGauss();
            HenselLifting    hensel = new HenselLifting();

            List <Msieve.Factor> modfactors = Msieve.TrivialFactorization(mod);
            List <KeyValuePair <BigInteger[], Msieve.Factor> > results;   //Stores the partial solutions together with their factors

            bool tryAgain;

            try
            {
                do
                {
                    results  = new List <KeyValuePair <BigInteger[], Msieve.Factor> >();
                    tryAgain = false;

                    for (int i = 0; i < modfactors.Count; i++)
                    {
                        if (modfactors[i].prime)    //mod prime
                        {
                            if (modfactors[i].count == 1)
                            {
                                results.Add(new KeyValuePair <BigInteger[], Msieve.Factor>(gauss.Solve(MatrixCopy(), modfactors[i].factor), modfactors[i]));
                            }
                            else
                            {
                                results.Add(new KeyValuePair <BigInteger[], Msieve.Factor>(hensel.Solve(MatrixCopy(), modfactors[i].factor, modfactors[i].count), modfactors[i]));
                            }
                        }
                        else    //mod composite
                        {
                            //Try using gauss:
                            try
                            {
                                BigInteger[] res = gauss.Solve(MatrixCopy(), modfactors[i].factor);
                                results.Add(new KeyValuePair <BigInteger[], Msieve.Factor>(res, modfactors[i]));   //Yeah, we had luck :)
                            }
                            catch (NotInvertibleException ex)
                            {
                                //We found a factor of modfactors[i]:
                                BigInteger           notInvertible = ex.NotInvertibleNumber;
                                List <Msieve.Factor> morefactors   = Msieve.TrivialFactorization(modfactors[i].factor / notInvertible);
                                List <Msieve.Factor> morefactors2  = Msieve.TrivialFactorization(notInvertible);
                                modfactors.RemoveAt(i);
                                ConcatFactorLists(modfactors, morefactors);
                                ConcatFactorLists(modfactors, morefactors2);
                                tryAgain = true;
                                break;
                            }
                        }
                    }
                } while (tryAgain);
            }
            catch (LinearDependentException ex)
            {
                //We have to throw away dependent rows and try again later:
                Array.Sort(ex.RowsToDelete, (a, b) => (b - a));
                foreach (int row in ex.RowsToDelete)
                {
                    matrix.RemoveAt(row);
                }
                return(null);
            }

            BigInteger[] result = new BigInteger[size];
            //"glue" the results together:
            for (int i = 0; i < size; i++)
            {
                List <KeyValuePair <BigInteger, BigInteger> > partSolItem = new List <KeyValuePair <BigInteger, BigInteger> >();
                for (int c = 0; c < results.Count; c++)
                {
                    partSolItem.Add(new KeyValuePair <BigInteger, BigInteger>(results[c].Key[i], BigInteger.Pow(results[c].Value.factor, results[c].Value.count)));
                }
                result[i] = CRT(partSolItem);
            }

            return(result);
        }