Algorithm 确定同余系是否有解

Algorithm 确定同余系是否有解,algorithm,math,modulo,Algorithm,Math,Modulo,有一个线性同余系统,我想确定它是否有解。使用简单的算法来解决这样的系统是不可能的,因为答案可能呈指数增长 我的一个假设是,如果一个同余系统没有解,那么其中有两个相互矛盾。我不知道这是否成立,如果成立的话,这将导致一个简单的O(n^2 logn)算法,因为检查一对同余是否有解需要O(logn)时间。然而,对于这个问题,我宁愿看到更接近O(n)的东西 我们可以假设没有模量超过10^6,特别是我们可以快速地将它们全部因子化。我们甚至可以进一步假设所有模的总和不超过10^6(但是,它们的乘积可能是巨大的

有一个线性同余系统,我想确定它是否有解。使用简单的算法来解决这样的系统是不可能的,因为答案可能呈指数增长

我的一个假设是,如果一个同余系统没有解,那么其中有两个相互矛盾。我不知道这是否成立,如果成立的话,这将导致一个简单的O(n^2 logn)算法,因为检查一对同余是否有解需要O(logn)时间。然而,对于这个问题,我宁愿看到更接近O(n)的东西


我们可以假设没有模量超过10^6,特别是我们可以快速地将它们全部因子化。我们甚至可以进一步假设所有模的总和不超过10^6(但是,它们的乘积可能是巨大的)。

正如您所怀疑的,有一种相当简单的方法可以确定同余集是否有解,而不需要实际构建该解。您需要:

  • 如有必要,将每个同余减少为
    x=a(mod n)
    ;从评论中,听起来好像你已经有了这个
  • 将每个模分解为素数幂的乘积:
    n=p1^e1*p2^e2*…*pk^ek
  • 将每个同余
    x=a(mod n)
    替换为一组同余
    x=a(mod pi^ei)
    ,步骤2中找到的
    k
    素数幂对应一个同余
  • 现在,独立地检查每个素数的兼容性就足够了:给定任意两个同余
    x=a(mod p^e)
    x=b(mod p^f)
    ,它们是兼容的当且仅当
    a=b(mod p^(min(e,f))
    。确定兼容性后,您可以丢弃模较小的同余,而不会丢失任何信息

    有了正确的数据结构,您可以在一次通过同余点的过程中完成所有这一切:对于遇到的每个素数
    p
    ,您需要跟踪到目前为止发现的最大指数
    e
    ,以及相应的右侧(为了方便起见,减少模
    p^e
    )。运行时间可能主要由模分解决定,但如果没有模超过
    10^6
    ,则也可以通过从
    1..10^6
    范围内的每个整数预构建到其最小素数因子的映射来加快这一步


    编辑:由于这应该是一个编程站点,这里有一些(Python 3)代码来说明上述内容。(对于Python 2,将
    range
    调用替换为
    xrange
    ,以提高效率。)


    最后一点注意:在上面,我们利用了模很小的事实,因此计算素数幂因子并不是什么大问题。但是如果你确实需要对更大的模(数百或数千位)这样做,它仍然是可行的。你可以跳过因子分解步骤,而是找到一个“互质基”对于模集合:即成对相对素数正整数的集合,这样同余中出现的每个模都可以表示为乘积(可能有重复)集合中的元素。现在按照上面的步骤进行,但要参考互质基,而不是素数和素数幂的集合。请参见Daniel Bernstein提供的计算一组正整数的互质基的有效方法。您可能会在列表中进行两次遍历:一次计算互质基,另一次d来检查一致性。

    这似乎是math.stackexchange.com的一个问题。不过,你的假设是有效的:如果一致性是成对一致的,那么它们是相互一致的。你需要这一点来计算什么大小的模?我们是否处于将这些模分解为素数幂非常容易的范围内(例如,所有的模量都小于2**32),或者这必须对更大的模量起作用吗?你能提供一个简短的证据来证明为什么这个假设是正确的吗?我把我的问题放在这里是因为唯一阻止我用O(n log n)来解它的东西事实上,存储部分解可能会超过可用内存,所以这不是一个真正的数学问题。将其分解为素数幂:根据中国剩余定理,同余是相互一致的,如果它们是模的素数幂块的相互一致模,对于每个相关素数,这就简化为这种情况其中所有模都是一个素数的幂。在这种情况下,当它们都与包含最大模的同余一致时,它们是相互一致的。证据应该可以在网上的某个地方找到;到目前为止,我发现最好的是第5页,我想通过同余可能是O(m log n)其中m是同余数,n是最大模,因为n最多可以有O(logn)个不同的素因子。这就是我需要的,谢谢!是的,如果你不考虑因子分解的成本,
    O(mlogn)
    听起来不错。
    def prime_power_factorisation(n):
        """Brain-dead factorisation routine, for illustration purposes only."""
        # DO NOT USE FOR LARGE n!
        while n > 1:
            p, pe = next(d for d in range(2, n+1) if n % d == 0), 1
            while n % p == 0:
                n, pe = n // p, pe*p
            yield p, pe
    
    
    def compatible(old_ppc, new_ppc):
        """Determine whether two prime power congruences (with the same
        prime) are compatible."""
        m, a = old_ppc
        n, b = new_ppc
        return (a - b) % min(m, n) == 0
    
    
    def are_congruences_solvable(moduli, right_hand_sides):
        """Determine whether the given congruences have a common solution."""
    
        # prime_power_congruences is a dictionary mapping each prime encountered
        # so far to a pair (prime power modulus, right-hand side).
    
        prime_power_congruences = {}
        for m, a in zip(moduli, right_hand_sides):
            for p, pe in prime_power_factorisation(m):
                # new prime-power congruence: modulus, rhs
                new_ppc = pe, a % pe
                if p in prime_power_congruences:
                    old_ppc = prime_power_congruences[p]
                    if not compatible(new_ppc, old_ppc):
                        return False
                    # Keep the one with bigger exponent.
                    prime_power_congruences[p] = max(new_ppc, old_ppc)
                else:
                    prime_power_congruences[p] = new_ppc
        # If we got this far, there are no incompatibilities, and
        # the congruences have a mutual solution.
        return True