简体   繁体   中英

Minimize the remainder in the chinese remainder theorem

I have multiple sets containing multiple congruences.

I am trying to find the smallest remainder when applying the Chinese remainder theorem on one item from each set.

For example with 2 sets:

Set 1:

7x + 1
7x + 3

Set 2:

11x
11x + 2
11x + 7
11x + 8

Taking 7x + 1 & 11x gives 77x + 22 .
I am after the smallest remainder (in the above example 77x + 8 ) without having to test all combinations.


This is very simplified version of my actual problem (being ~50 sets, with ~100 congruences in each).

I am stuck on how to approach this problem, any advice would be greatly appreciated.

Also, my apologies if my math terminology is incorrect.

There is a meet-in-the middle algorithm that finds the smallest residue in time

O(max(|S1|, |S2|) log(max(|S1|, |S2|))).

First use the Chinese Remainder Theoremt to find the set T1 of all 0 <= t < n1*n2 satisfying t mod n1 in S1 and t mod n2 == 0 and the set T2 of all 0 <= u < n1*n2 satisying t mod n1 == 0 and t mod n2 in S2.

Ie in the example given in the question:

T1 = {22, 66}

T2 = {0, 7, 35, 63}

Now the residues you are looking for are the sums (t1 + t2) mod n1*n2, for any t1 in T1 and t2 in T2. Hence the smallest residue is either the sum of the two smallest elements in T1 and T2 or two elements that are just barely larger than n1*n2. If you sort the sets T1 and T2 then the best solution for the second case can be found by scanning the first set from the smallest to the largest element and scanning the largest set from the largest to the smalles element, ie advancing the position in T1 whenever the sum is smaller than n1*n2 and decreasing the position in T2 whenever it is larger than n1*n2.

If you have more than two moduli n1.. nk then the fastest solution I can see is to divide the moduli into two sets, say n1.. nr and nr+1.. nk find the set T1 such that t in T1 iff t mod ni in Si for all 1 <= i <= r and t mod ni == 0 for all r < i <= k. T2 is defined accordingly. The complexity depends on the distribution of the moduli, but should normally be about the square root of the number of possibilities. There is an algorithm by Schroeppel and Shamir, which can save some memory, but does not decrease the time complexity.

For your application, ie 50 moduli and 100 congruences this algorithm still uses about 100^25 steps, which is infeasible. Unfortunately, it looks like there is no polynomial algorithm. In particular, it is known that finding the smallest solution x of the equation x^2 == a (mod n), where n is a highly composite integer is NP-complete. But finding such a solution can be reduced your problem. Hence, your problem should be NP-complete too in general unless the congruences have some special property that can be exploited.

Let the sets be S1, S2, ... Sk, where the modulus in each set are n1 > n2 >... > nk and the remainders in Si are a_i1 < a_i2 <... So for the example: n1 = 11, n2 = 7 and S1 = {0, 2, 7, 8}, S2 = {1,3}

Here is a pseudo code:

Find the target modulus, i.e. n = lcm(n1, n2, ..., nk)

Convert the sets Si into hashtables, so that you can check if a certain element is in the set or not.

for (int b = 0; b < n / n1; b++)
    foreach (int c in [a_11, a_12, a_13, ...])
        //candidate target reminder
        a = b*n1 + c
        works = true;
        foreach (int ni in [n2, n3, ..., nk])
           //test if there is an element in Si, which gives the correct reminder
           //if not then this candidate doesn't work, go to the next
           if( not Si contains (a % ni))
               works = false;
               break
        if (works)
            print "The solution is n*x+a"
            exit

The idea is to search for the minimum. If the minimum is a, then a can be represented as a=x*n1+y , where y is some element from S1, so I iterate over all the possibilities in increasing order. Then for each one of them I check against the other sets - whether they contain a congruence that is satisfied by the current a. Say for the second set S2: There should exist a congruence from S2, eg p*n2+q, so that a = p*n2+q for some p. But this mean that a % n2 = q (since q is the remainder). Ie a % n2 sould be in S2.

The complexity of the algorithm is O (n/n1 * |S1| * k). That's why I picked n1 to be the largest modulus. But if you really want to minimize the complexity you should pick the set Si in such a way so that n/ni * |Si| in mimimal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM