예제 #1
0
def solve_congruence_equations(congruences):
    """
    Return a quotient class that simultaneously solves the list of
    @p congruences; this is the Chinese Remainder Theorem.

    All representatives of the returned congruence have the remainders of
    @p congruences when taken modulo the respective moduli. The result is a
    congruence modulo the product of all moduli. Thus the function returns a
    number @f$ z \mod \prod_{i} m_i @f$ such that
    @f{align*}{
     z &\equiv a_1 \mod m_1 \\
     \vdots \\
     z &\equiv a_k \mod m_k
    @f}

    @note The moduli @f$ m_i @f$ of all congruences must be relatively prime.

    @exception ValueError      if @p congruences is empty.

    @param     congruences     An iterable of objects of QuotientClass over the
                               Integers. Every pair of two different moduli
                               must have a greatest common divisor (gcd()) of 1.

    @return    An instance of rings.quotients.naive.QuotientRing over the
               rings.integers.naive.Integers solving the @p congruences.

    @see       Robinson, D. J. S., "An Introduction to Abstract Algebra", p. 27
    """
    # The Chinese remainder theorem
    if not congruences:
        raise ValueError("cannot solve empty equation system")

    if __debug__:
        # This test is expensive; remove it in optimized execution
        pairs = [(c1, c2)
                 for c1 in congruences for c2 in congruences if c1 != c2]
        pairwise_gcds = [gcd(c1.modulus(), c2.modulus()) for c1, c2 in pairs]

        assert set(pairwise_gcds) == set([1]), \
            "the Chinese Remainder Theorem requires relatively prime moduli"

    common_modulus = reduce(mul, [c.modulus() for c in congruences])
    common_representative = 0
    for c in congruences:
        neutralizer = common_modulus // c.modulus()
        common_representative += c.remainder() * neutralizer  \
            * inverse_modulo(neutralizer, c.modulus())

    quotient_ring = QuotientRing(Integers, common_modulus)
    return quotient_ring(common_representative)
예제 #2
0
def solve_congruence_equations( congruences ):
    """
    Return a quotient class that simultaneously solves the list of
    @p congruences; this is the Chinese Remainder Theorem.
    
    All representatives of the returned congruence have the remainders of
    @p congruences when taken modulo the respective moduli. The result is a
    congruence modulo the product of all moduli. Thus the function returns a
    number @f$ z \mod \prod_{i} m_i @f$ such that
    @f{align*}{
     z &\equiv a_1 \mod m_1 \\
     \vdots \\
     z &\equiv a_k \mod m_k
    @f}
    
    @note The moduli @f$ m_i @f$ of all congruences must be relatively prime.
    
    @exception ValueError      if @p congruences is empty.

    @param     congruences     An iterable of objects of QuotientClass over the
                               Integers. Every pair of two different moduli
                               must have a greatest common divisor (gcd()) of 1.
    
    @return    An instance of rings.quotients.naive.QuotientRing over the
               rings.integers.naive.Integers solving the @p congruences.
    
    @see       Robinson, D. J. S., "An Introduction to Abstract Algebra", p. 27
    """
    # The Chinese remainder theorem
    if not congruences:
        raise ValueError( "cannot solve empty equation system" )
        
    if __debug__:
        # This test is expensive; remove it in optimized execution
        pairs = [ (c1, c2) for c1 in congruences for c2 in congruences if c1 != c2 ]
        pairwise_gcds = [ gcd( c1.modulus(), c2.modulus() ) for c1, c2 in pairs ]
    
        assert set( pairwise_gcds ) == set([ 1 ]), \
            "the Chinese Remainder Theorem requires relatively prime moduli"
    
    common_modulus = reduce( mul, [ c.modulus() for c in congruences ] )
    common_representative = 0
    for c in congruences:
        neutralizer = common_modulus // c.modulus()
        common_representative += c.remainder() * neutralizer  \
                                    * inverse_modulo( neutralizer, c.modulus() )
    
    quotient_ring = QuotientRing( Integers, common_modulus )
    return quotient_ring( common_representative )
예제 #3
0
def frobenius_trace_mod_2(curve):
    """
    Compute the trace of the Frobenius endomorphism modulo 2.

    We cannot use the implicit torsion group representation of
    frobenius_trace_mod_l() in the case @f$ l=2 @f$ because the second division
    polynomial is @f$ y @f$, and multivariate polynomial arithmetic is
    unavailable. Implementing it for this single case would be overkill.

    Instead, we test whether there are any rational 2-torsion points. If so,
    then @f$ E[2] @f$ is a subgroup of the @p curve and its order divides the
    order of the curve (which is the number of rational points). Now, the
    number of rational points in @f$ E[2] @f$ can only be 2 or 4 in this case, so
    we know that the number of rational points is even. Hence, the Frobenius
    trace must then be 0 modulo 2.

    @return    0 if the number of points on the curve is even, 1 otherwise.
               The result is a congruence class modulo 2, that is, an element
               of @c QuotientRing( Integers, 2 ).
    """
    R = Polynomials(curve.field())

    x = R(0, 1)
    A, B = curve.parameters()

    defining_polynomial = x**3 + A * x + B
    rational_characteristic = x**curve.field().size() - x

    # gcd() has an arbitrary unit as leading coefficient;
    # relatively prime polynomials have a constant gcd.
    d = gcd(rational_characteristic, defining_polynomial)
    if d.degree() == 0:
        # The rational characteristic and the defining polynomial
        # are relatively prime: no rational point of order 2 exists
        # and the Frobenius trace must be odd.
        return QuotientRing(Integers, 2)(1)
    else:
        return QuotientRing(Integers, 2)(0)
예제 #4
0
def frobenius_trace_mod_2(curve):
    """
    Compute the trace of the Frobenius endomorphism modulo 2.
    
    We cannot use the implicit torsion group representation of
    frobenius_trace_mod_l() in the case @f$ l=2 @f$ because the second division
    polynomial is @f$ y @f$, and multivariate polynomial arithmetic is
    unavailable. Implementing it for this single case would be overkill.
    
    Instead, we test whether there are any rational 2-torsion points. If so,
    then @f$ E[2] @f$ is a subgroup of the @p curve and its order divides the
    order of the curve (which is the number of rational points). Now, the
    number of rational points in @f$ E[2] @f$ can only be 2 or 4 in this case, so
    we know that the number of rational points is even. Hence, the Frobenius
    trace must then be 0 modulo 2.
    
    @return    0 if the number of points on the curve is even, 1 otherwise.
               The result is a congruence class modulo 2, that is, an element
               of @c QuotientRing( Integers, 2 ).
    """
    R = Polynomials( curve.field() )
    
    x = R(0, 1)
    A, B = curve.parameters()

    defining_polynomial = x**3 + A*x + B
    rational_characteristic = x**curve.field().size() - x
    
    # gcd() has an arbitrary unit as leading coefficient;
    # relatively prime polynomials have a constant gcd.
    d = gcd( rational_characteristic, defining_polynomial )
    if d.degree() == 0:
        # The rational characteristic and the defining polynomial
        # are relatively prime: no rational point of order 2 exists
        # and the Frobenius trace must be odd.
        return QuotientRing( Integers, 2 )(1)
    else:
        return QuotientRing( Integers, 2 )(0)
예제 #5
0
 def test_polynomial_gcd_relatively_prime(self):
     """GCD of relatively prime elements"""
     R = Polynomials(FiniteField(7))
     self.assert_(gcd(R(-1, 0, 1), R(0, 1)).degree() == 0)
예제 #6
0
 def test_integer_gcd(self):
     """Integer GCD"""
     self.assert_(gcd(17, 25) == 1)
     self.assert_(gcd(24, 27) == 3)
예제 #7
0
 def test_polynomial_gcd_relatively_prime(self):
     """GCD of relatively prime elements"""
     R = Polynomials( FiniteField(7) )
     self.assert_( gcd( R(-1, 0, 1), R(0, 1) ).degree() == 0 )
예제 #8
0
 def test_integer_gcd(self):
     """Integer GCD"""
     self.assert_( gcd( 17, 25 ) == 1 )
     self.assert_( gcd( 24, 27 ) == 3 )