Esempio n. 1
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);
        }