def __init__(self, data, V=None):
        if isinstance(data, (tuple, list)):
            self._dict = {}
            for mon, mult in data:
                mon = V(mon)
                if mon.is_zero():
                    raise ValueError('zero in denominator')
                mult = ZZ(mult)
                if mult <= 0:
                    raise ValueError('non-positive multiplicity in denominator')
                mon.set_immutable()
                self._dict[mon] = mult

        elif isinstance(data, dict):
            self._dict = data

        elif isinstance(data, FactoredDenominator):
            self._dict = data._dict
            self._tuple = data._tuple
            return

        elif isinstance(data, Vector_integer_dense):
            data = V(data)
            data.set_immutable()
            self._dict = {data: ZZ.one()}
            self._tuple = ((data, ZZ.one()),)
            return

        else:
            raise TypeError('invalid data of type {} to initialized a FactoredDenominator'.format(type(data)))

        self._tuple = tuple(sorted(self._dict.items()))
 def __init__(self, k, p=None, prec_cap=20, base=None, character=None, tuplegen=None, act_on_left=False):
     """
     - ``character`` --
       - None (default)
       - (chi, None)
       - (None, n) (n integral)
       - (chi, n)
       - lambda (for n half-integral use this form)
     """
     if p is not None:
         p = ZZ(p)
     if base is None:
         if p is None: raise ValueError("specify p or a base")
         base = ZpCA(p,prec_cap)
     elif isinstance(base, pAdicGeneric):
         if base.prime() != p: raise ValueError("p must be the same as the prime of base")
         if base.precision_cap() != prec_cap: raise ValueError("prec_cap must match the precision cap of base")
     elif prec_cap > k+1: # non-classical
         if p is None or not p.is_prime(): raise ValueError("p must be prime for non-classical weight")
     from sage.rings.padics.pow_computer import PowComputer_long
     # should eventually be the PowComputer on ZpCA once that uses longs.
     Dist, WeightKAction = get_dist_classes(p, prec_cap, base)
     self.Element = Dist
     if Dist is Dist_long:
         self.prime_pow = PowComputer_long(p, prec_cap, prec_cap, prec_cap, 0)
     Parent.__init__(self, base)
     self._k = k
     self._p = p
     self._prec_cap = prec_cap
     act = WeightKAction(self, character, tuplegen, act_on_left)
     self._act = act
     self._populate_coercion_lists_(action_list=[act])
Exemple #3
0
    def random_element(self, bound=100, *args, **kwds):
        r"""
        Return a random element of `{\rm SL}_2(\ZZ)` with entries whose
        absolute value is strictly less than bound (default 100).
        Additional arguments and keywords are passed to the random_element
        method of ZZ.

        (Algorithm: Generate a random pair of integers at most bound. If they
        are not coprime, throw them away and start again. If they are, find an
        element of `{\rm SL}_2(\ZZ)` whose bottom row is that, and
        left-multiply it by `\begin{pmatrix} 1 & w \\ 0 & 1\end{pmatrix}` for
        an integer `w` randomly chosen from a small enough range that the
        answer still has entries at most bound.)

        It is, unfortunately, not true that all elements of SL2Z with entries <
        bound appear with equal probability; those with larger bottom rows are
        favoured, because there are fewer valid possibilities for w.

        EXAMPLES::

            sage: SL2Z.random_element()
            [60 13]
            [83 18]
            sage: SL2Z.random_element(5)
            [-1  3]
            [ 1 -4]

        Passes extra positional or keyword arguments through::

            sage: SL2Z.random_element(5, distribution='1/n')
            [ 1 -4]
            [ 0  1]
        """
        if bound <= 1: raise ValueError("bound must be greater than 1")
        c = ZZ.random_element(1-bound, bound, *args, **kwds)
        d = ZZ.random_element(1-bound, bound, *args, **kwds)
        if gcd(c,d) != 1: # try again
            return self.random_element(bound, *args, **kwds)
        else:
            a,b,c,d = lift_to_sl2z(c,d,0)
            whi = bound
            wlo = bound
            if c > 0:
                whi = min(whi, ((bound - a)/ZZ(c)).ceil())
                wlo = min(wlo, ((bound + a)/ZZ(c)).ceil())
            elif c < 0:
                whi = min(whi, ((bound + a)/ZZ(-c)).ceil())
                wlo = min(wlo, ((bound - a)/ZZ(-c)).ceil())

            if d > 0:
                whi = min(whi, ((bound - b)/ZZ(d)).ceil())
                wlo = min(wlo, ((bound + b)/ZZ(d)).ceil())
            elif d < 0:
                whi = min(whi, ((bound + b)/ZZ(-d)).ceil())
                wlo = min(wlo, ((bound - b)/ZZ(-d)).ceil())

            w = ZZ.random_element(1-wlo, whi, *args, **kwds)
            a += c*w
            b += d*w
            return self([a,b,c,d])
Exemple #4
0
    def random_element(self, algorithm='default'):
        r"""
        Returns a random element of self, optionally using the
        algorithm argument to decide how it generates the
        element. Algorithms currently implemented:

        - default: Choose `a_i`, `i >= 0`, randomly between `0` and
          `p-1` until a nonzero choice is made. Then continue choosing
          `a_i` randomly between `0` and `p-1` until we reach
          precision_cap, and return `\sum a_i p^i`.

        EXAMPLES::

            sage: Zp(5,6).random_element()
            3 + 3*5 + 2*5^2 + 3*5^3 + 2*5^4 + 5^5 + O(5^6)
            sage: ZpCA(5,6).random_element()
            4*5^2 + 5^3 + O(5^6)
            sage: ZpFM(5,6).random_element()
            2 + 4*5^2 + 2*5^4 + 5^5 + O(5^6)
        """
        if (algorithm == 'default'):
            if self.is_capped_relative():
                i = 0
                a_i = ZZ.random_element(self.prime())
                while a_i.is_zero():
                    i += 1
                    a_i = ZZ.random_element(self.prime())
                return self((self.prime()**i)*(a_i + self.prime()*ZZ.random_element(self.prime_pow.pow_Integer_Integer(self.precision_cap()-1))))
            else:
                return self(ZZ.random_element(self.prime_pow.pow_Integer_Integer(self.precision_cap())))
        else:
            raise NotImplementedError("Don't know %s algorithm"%algorithm)
Exemple #5
0
    def _validate(self, n):
        """
        Verify that n is positive and has at most 4095 digits.

        INPUT:

        - ``n`` -- integer.

        OUTPUT:

        The integer as a Sage integer.  This function raises a
        ValueError if the two conditions listed above are not both
        satisfied.  It is here because GMP-ECM silently ignores all
        digits of input after the 4095th!

        EXAMPLES::

            sage: ecm = ECM()
            sage: ecm._validate(3)
            3
            sage: ecm._validate(0)
            Traceback (most recent call last):
            ...
            ValueError: n must be positive
            sage: ecm._validate(10^5000)
            Traceback (most recent call last):
            ...
            ValueError: n must have at most 4095 digits
        """
        n = ZZ(n)
        if n <= 0:
            raise ValueError("n must be positive")
        if n.ndigits() > 4095:
            raise ValueError("n must have at most 4095 digits")
        return n
    def lift(self, P, prec=20):
        r"""
        Given a point `P` in the formal group of the elliptic curve `E` with split multiplicative reduction,
        this produces an element `u` in `\QQ_p^{\times}` mapped to the point `P` by the Tate parametrisation.
        The algorithm return the unique such element in `1+p\ZZ_p`.

        INPUT:

        - ``P`` - a point on the elliptic curve.

        - ``prec`` - the `p`-adic precision, default is 20.

        EXAMPLES::

            sage: e = EllipticCurve('130a1')
            sage: eq = e.tate_curve(5)
            sage: P = e([-6,10])
            sage: l = eq.lift(12*P, prec=10); l
            1 + 4*5 + 5^3 + 5^4 + 4*5^5 + 5^6 + 5^7 + 4*5^8 + 5^9 + O(5^10)

        Now we map the lift l back and check that it is indeed right.::

            sage: eq.parametrisation_onto_original_curve(l)
            (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^20))
            sage: e5 = e.change_ring(Qp(5,9))
            sage: e5(12*P)
            (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^9))
        """
        p = self._p
        R = Qp(self._p, prec)
        if not self._E == P.curve():
            raise ValueError("The point must lie on the original curve.")
        if not self.is_split():
            raise ValueError("The curve must have split multiplicative reduction.")
        if P.is_zero():
            return R.one()
        if P[0].valuation(p) >= 0:
            raise ValueError("The point must lie in the formal group.")

        Eq = self.curve(prec=prec)
        C, r, s, t = self._isomorphism(prec=prec)
        xx = r + C ** 2 * P[0]
        yy = t + s * C ** 2 * P[0] + C ** 3 * P[1]
        try:
            Eq([xx, yy])
        except Exception:
            raise RuntimeError("Bug : Point %s does not lie on the curve " %
                               (xx, yy))

        tt = -xx / yy
        eqhat = Eq.formal()
        eqlog = eqhat.log(prec + 3)
        z = eqlog(tt)
        u = ZZ.one()
        fac = ZZ.one()
        for i in range(1, 2 * prec + 1):
            fac *= i
            u += z ** i / fac
        return u
def is_hyperbolic(self, p):
    r"""
    Check if the quadratic form is a sum of hyperbolic planes over
    the `p`-adic numbers `\QQ_p` or over the real numbers `\RR`.

    REFERENCES:

    This criteria follows from Cassels's "Rational Quadratic Forms":

    - local invariants for hyperbolic plane (Lemma 2.4, p58)
    - direct sum formulas (Lemma 2.3, p58)

    INPUT:

    - `p` -- a prime number > 0 or `-1` for the infinite place

    OUTPUT:

    boolean

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1])
        sage: Q.is_hyperbolic(-1)
        False
        sage: Q.is_hyperbolic(2)
        False
        sage: Q.is_hyperbolic(3)
        False
        sage: Q.is_hyperbolic(5)     ## Here -1 is a square, so it's true.
        True
        sage: Q.is_hyperbolic(7)
        False
        sage: Q.is_hyperbolic(13)    ## Here -1 is a square, so it's true.
        True
    """
    ## False for odd-dim'l forms
    if self.dim() % 2:
        return False

    ## True for the zero form
    if not self.dim():
        return True

    ## Compare local invariants
    ## Note: since the dimension is even, the extra powers of 2 in
    ##        self.det() := Det(2*Q) don't affect the answer!
    m = ZZ(self.dim() // 2)
    if p == -1:
        return self.signature() == 0

    if p == 2:
        return (QQ(self.det() * (-1) ** m).is_padic_square(p) and
                self.hasse_invariant(p) ==
                (-1) ** m.binomial(2))  # here -1 is hilbert_symbol(-1,-1,2)

    return (QQ(self.det() * (-1) ** m).is_padic_square(p) and
            self.hasse_invariant(p) == 1)
def iterator_fast(n, l):
    """
    Iterate over all ``l`` weighted integer vectors with total weight ``n``.

    INPUT:

    - ``n`` -- an integer
    - ``l`` -- the weights in weakly decreasing order

    EXAMPLES::

        sage: from sage.combinat.integer_vector_weighted import iterator_fast
        sage: list(iterator_fast(3, [2,1,1]))
        [[1, 1, 0], [1, 0, 1], [0, 3, 0], [0, 2, 1], [0, 1, 2], [0, 0, 3]]
        sage: list(iterator_fast(2, [2]))
        [[1]]

    Test that :trac:`20491` is fixed::

        sage: type(list(iterator_fast(2, [2]))[0][0])
        <type 'sage.rings.integer.Integer'>
    """
    if n < 0:
        return

    zero = ZZ.zero()
    one = ZZ.one()

    if not l:
        if n == 0:
            yield []
        return
    if len(l) == 1:
        if n % l[0] == 0:
            yield [n // l[0]]
        return

    k = 0
    cur = [n // l[k] + one]
    rem = n - cur[-1] * l[k] # Amount remaining
    while cur:
        cur[-1] -= one
        rem += l[k]
        if rem == zero:
            yield cur + [zero] * (len(l) - len(cur))
        elif cur[-1] < zero or rem < zero:
            rem += cur.pop() * l[k]
            k -= 1
        elif len(l) == len(cur) + 1:
            if rem % l[-1] == zero:
                yield cur + [rem // l[-1]]
        else:
            k += 1
            cur.append(rem // l[k] + one)
            rem -= cur[-1] * l[k]
            def rank(self, x):
                r"""
                Return the rank of an element of this Cartesian product.

                The *rank* of ``x`` is its position in the
                enumeration. It is an integer between ``0`` and
                ``n-1`` where ``n`` is the cardinality of this set.

                .. SEEALSO::

                    - :meth:`EnumeratedSets.ParentMethods.rank`
                    - :meth:`unrank`

                EXAMPLES::

                    sage: C = cartesian_product([GF(2), GF(11), GF(7)])
                    sage: C.rank(C((1,2,5)))
                    96
                    sage: C.rank(C((0,0,0)))
                    0

                    sage: for c in C: print(C.rank(c))
                    0
                    1
                    2
                    3
                    4
                    5
                    ...
                    150
                    151
                    152
                    153

                    sage: F1 = FiniteEnumeratedSet('abcdefgh')
                    sage: F2 = IntegerRange(250)
                    sage: F3 = Partitions(20)
                    sage: C = cartesian_product([F1, F2, F3])
                    sage: c = C(('a', 86, [7,5,4,4]))
                    sage: C.rank(c)
                    54213
                    sage: C.unrank(54213)
                    ('a', 86, [7, 5, 4, 4])
                """
                from builtins import zip
                from sage.rings.integer_ring import ZZ
                x = self(x)
                b = ZZ.one()
                rank = ZZ.zero()
                for f, c in zip(reversed(x.cartesian_factors()),
                                reversed(self.cartesian_factors())):
                    rank += b * c.rank(f)
                    b *= c.cardinality()
                return rank
 def getcoeff(self, key, **kwds) :
     (ch, k) = key
     if ch != self.__ch :
         return ZZ.zero()
     
     if self.__series is None :
         self.__series = \
          self.__factory.by_taylor_expansion( self.__fs, self.__weight )
     
     try :
         return self.__series[k]
     except KeyError :
         return ZZ.zero()
    def Heisenberg(p):
        r"""
        Return the Heisenberg origami.

        EXAMPLES::

            sage: from surface_dynamics.all import *

            sage: h2 = origamis.Heisenberg(2)
            sage: h2.stratum_component()
            H_3(1^4)^c
            sage: h2.veech_group().index()
            3
            sage: h2.sum_of_lyapunov_exponents()
            2

            sage: h3 = origamis.Heisenberg(3)
            sage: h3.stratum_component()
            H_10(2^9)^even
            sage: h3.veech_group().index()
            1
            sage: h3.sum_of_lyapunov_exponents()
            5

            sage: h5 = origamis.Heisenberg(5)
            sage: h5.stratum_component()
            H_51(4^25)^even
            sage: h5.veech_group().index()
            1
            sage: h5.sum_of_lyapunov_exponents()
            15
        """
        p = ZZ(p)
        if not p.is_prime():
            raise ValueError("p (={}) must be prime".format(p))
        N = p**3  # map (a,b,d) -> a*p**2 + b*p + d
        pp = p*p
        r = [None]*N
        u = [None]*N
        for a in xrange(p):
            for b in xrange(p):
                for d in xrange(p):
                    n = a*pp + b*p + d
                    r[n] = ((a+1)%p)*pp + b*p + d
                    u[n] = a*pp + ((b+1)%p)*p + ((a+d)%p)
        return Origami(r,u,
                as_tuple=True,
                name="Heisenberg origami on GF(%d)"%p)
        def number_of_reflection_hyperplanes(self):
            r"""
            Return the number of reflection hyperplanes of ``self``.

            This is also the number of distinguished reflections.  For
            real groups, this coincides with the number of
            reflections.

            This implementation uses that it is given by the sum of
            the codegrees of ``self`` plus its rank.

            .. SEEALSO:: :meth:`number_of_reflections`

            EXAMPLES::

                sage: W = ColoredPermutations(1,3)
                sage: W.number_of_reflection_hyperplanes()
                3
                sage: W = ColoredPermutations(2,3)
                sage: W.number_of_reflection_hyperplanes()
                9
                sage: W = ColoredPermutations(4,3)
                sage: W.number_of_reflection_hyperplanes()
                15
                sage: W = ReflectionGroup((4,2,3))          # optional - gap3
                sage: W.number_of_reflection_hyperplanes()  # optional - gap3
                15
            """
            from sage.rings.all import ZZ
            return ZZ.sum(codeg + 1 for codeg in self.codegrees())
        def number_of_reflections(self):
            r"""
            Return the number of reflections of ``self``.

            For real groups, this coincides with the number of
            reflection hyperplanes.

            This implementation uses that it is given by the sum of
            the degrees of ``self`` minus its rank.

            .. SEEALSO:: :meth:`number_of_reflection_hyperplanes`

            EXAMPLES::

                sage: [SymmetricGroup(i).number_of_reflections() for i in range(int(8))]
                [0, 0, 1, 3, 6, 10, 15, 21]

                sage: W = ColoredPermutations(1,3)
                sage: W.number_of_reflections()
                3
                sage: W = ColoredPermutations(2,3)
                sage: W.number_of_reflections()
                9
                sage: W = ColoredPermutations(4,3)
                sage: W.number_of_reflections()
                21
                sage: W = ReflectionGroup((4,2,3))         # optional - gap3
                sage: W.number_of_reflections()            # optional - gap3
                15
            """
            from sage.rings.all import ZZ
            return ZZ.sum(deg - 1 for deg in self.degrees())
        def character_ring(self, modules_base_ring = None, base_ring = None, side = 'right', q = None):
            """
            Returns the character ring of ``self``

            EXAMPLES::

                sage: S = Semigroups().Finite().example()
                sage: S.rename("S")

                sage: A = S.character_ring(); A
                The right-character ring of S over Rational Field

                sage: A.category()
                Category of character rings of finite semigroups over Integer Ring with realizations

                sage: QQ.<q> = QQ[]
                sage: A = S.character_ring(q = q); A
                The right-character ring of S over Rational Field
            """
            from sage.rings.rational_field import QQ
            if modules_base_ring is None:
                modules_base_ring = QQ
            from sage.rings.integer_ring import ZZ
            if q is None:
                q = ZZ.one()
            if base_ring is None:
                base_ring = q.parent()
            from sage.categories.rings import Rings
            assert base_ring in Rings()
            assert q in base_ring
            from sage_semigroups.monoids.character_ring import AbstractCharacterRing
            return AbstractCharacterRing(self, modules_base_ring, base_ring, side = side, q = q)
    def degree(self):
        r"""
        EXAMPLES::

            sage: from surface_dynamics.misc.factored_denominator import FactoredDenominator

            sage: V = ZZ**3
            sage: FactoredDenominator([], None).degree()
            0
            sage: FactoredDenominator([((1,0,0), 2)], V).degree()
            2
            sage: FactoredDenominator([((0,1,2), 3), ((1,1,1), 1)], V).degree()
            4
            sage: FactoredDenominator([((0,-1,2), 1), ((1,0,0), 1), ((0,0,2), 1)], V).degree()
            3

        TESTS::

            sage: parent(FactoredDenominator([], None).degree())
            Integer Ring
            sage: parent(FactoredDenominator([((1,0,0), 2)], V).degree())
            Integer Ring
        """
        if not self._tuple:
            return ZZ.zero()
        return sum(m for _,m in self._tuple)
Exemple #16
0
def build_Lambdalist_from_AB(A,B,T, scaling):
    # T is the matrix of Hecke acting on Homology
    try:
        x,y,z,t = T.list()
    except AttributeError:
        x,y,z,t = T
    alpha = ZZ(z)/ZZ(y)
    beta = ZZ(t-x)/ZZ(y)
    d = alpha.denominator().lcm(beta.denominator())
    alpha, beta = ZZ(d*alpha), ZZ(d*beta)
    ans = []
    K = A.parent()
    for A0, B0 in product(our_nroot(A,scaling,return_all=True),our_nroot(B,scaling,return_all=True)):
        for B1 in our_nroot(B0, d,return_all=True):
            ans.append(Matrix(K,2,2,[A0,B0,B1**alpha,A0*B1**beta]))
    return ans
Exemple #17
0
    def phi(self, i):
        r"""
        Return the value of `\varphi_i` on ``self``.

        INPUT:

        - ``i`` -- an element of the index set

        EXAMPLES::

            sage: M = crystals.infinity.NakajimaMonomials(['D',4,3])
            sage: m = M.module_generators[0].f(1)
            sage: [m.phi(i) for i in M.index_set()]
            [1, -1, 1]

            sage: M = crystals.infinity.NakajimaMonomials(['C',4,1])
            sage: m = M.module_generators[0].f_string([4,2,3])
            sage: [m.phi(i) for i in M.index_set()]
            [0, 1, -1, 2, -1]
        """
        if i not in self.parent().index_set():
            raise ValueError("i must be an element of the index set")
        if not self._Y or all(x[0] != i for x in self._Y):
            return ZZ.zero()

        d = copy(self._Y)
        K = max(x[1] for x in d if x[0] == i)
        for a in range(K):
            if (i,a) in d:
                continue
            else:
                d[(i,a)] = 0
        S = sorted((x for x in six.iteritems(d) if x[0][0] == i), key=lambda x: x[0][1])
        return max(sum(S[k][1] for k in range(s)) for s in range(1,len(S)+1))
Exemple #18
0
def number_of_rooted_trees(n):
    r"""
    Return the number of rooted trees with `n` nodes.

    Compute the number `a(n)` of rooted trees with `n` nodes using the
    recursive formula ([SL000081]_):

    .. MATH::

        a(n+1) = \frac{1}{n} \sum_{k=1}^{n} \left( \sum_{d|k} d a(d) \right) a(n-k+1)

    EXAMPLES::

        sage: from sage.combinat.rooted_tree import number_of_rooted_trees
        sage: [number_of_rooted_trees(i) for i in range(10)]
        [0, 1, 1, 2, 4, 9, 20, 48, 115, 286]

    REFERENCES:

    .. [SL000081] Sloane's :oeis:`A000081`
    """
    if n == 0:
        return Integer(0)
    if n == 1:
        return Integer(1)
    n = Integer(n)
    return sum(sum(d * number_of_rooted_trees(d) for d in k.divisors()) *
               number_of_rooted_trees(n - k)
               for k in ZZ.range(1, n)) // (n - 1)
Exemple #19
0
    def _kf(self, i):
        r"""
        Return the value `k_f` with respect to ``i`` and ``self``.

        INPUT:

        - ``i`` -- an element of the index set

        EXAMPLES::

            sage: M = crystals.infinity.NakajimaMonomials(['F',4,1])
            sage: m = M.module_generators[0].f_string([0,1,4,3])
            sage: [m._kf(i) for i in M.index_set()]
            [0, 0, 2, 0, 0]
        """
        if all(i != x[0] for x in self._Y):
            return ZZ.zero()

        d = copy(self._Y)
        K = max(key[1] for key in d if key[0] == i)
        for a in range(K):
            if (i,a) in d:
                continue
            else:
                d[(i,a)] = 0
        S = sorted((x for x in six.iteritems(d) if x[0][0] == i), key=lambda x: x[0][1])
        sum = 0
        phi = self.phi(i)
        for var,exp in S:
            sum += exp
            if sum == phi:
                return var[1]
Exemple #20
0
    def __contains__(self, x):
        r"""
        Tests if ``x`` is an element of ``self``.

        INPUT:

        - ``x`` -- matrix

        EXAMPLES::

            sage: from sage.combinat.integer_matrices import IntegerMatrices
            sage: IM = IntegerMatrices([4], [1,2,1])
            sage: matrix([[1, 2, 1]]) in IM
            True
            sage: matrix(QQ, [[1, 2, 1]]) in IM
            True
            sage: matrix([[2, 1, 1]]) in IM
            False

        TESTS::

            sage: from sage.combinat.integer_matrices import IntegerMatrices
            sage: IM = IntegerMatrices([4], [1,2,1])
            sage: [1, 2, 1] in IM
            False
            sage: matrix([[-1, 3, 1]]) in IM
            False

        """
        from sage.matrix.matrix import Matrix

        if not isinstance(x, Matrix):
            return False
        row_sums = [ZZ.zero()] * x.nrows()
        col_sums = [ZZ.zero()] * x.ncols()
        for i in range(x.nrows()):
            for j in range(x.ncols()):
                x_ij = x[i, j]
                if x_ij not in ZZ or x_ij < 0:
                    return False
                row_sums[i] += x_ij
                col_sums[j] += x_ij
            if row_sums[i] != self._row_sums[i]:
                return False
        if col_sums != self._col_sums:
            return False
        return True
Exemple #21
0
    def cardinality(self):
        r"""
        Return the number of integer necklaces with the evaluation ``content``.

        The formula for the number of necklaces of content `\alpha`
        a composition of `n` is:

        .. MATH::

            \sum_{d|gcd(\alpha)} \phi(d)
            \binom{n/d}{\alpha_1/d, \ldots, \alpha_\ell/d},

        where `\phi(d)` is the Euler `\phi` function.

        EXAMPLES::

            sage: Necklaces([]).cardinality()
            0
            sage: Necklaces([2,2]).cardinality()
            2
            sage: Necklaces([2,3,2]).cardinality()
            30
            sage: Necklaces([0,3,2]).cardinality()
            2

        Check to make sure that the count matches up with the number of
        necklace words generated.

        ::

            sage: comps = [[],[2,2],[3,2,7],[4,2],[0,4,2],[2,0,4]]+Compositions(4).list()
            sage: ns = [Necklaces(comp) for comp in comps]
            sage: all(n.cardinality() == len(n.list()) for n in ns)
            True
        """
        evaluation = self._content
        le = list(evaluation)
        if not le:
            return ZZ.zero()

        n = sum(le)

        return ZZ.sum(euler_phi(j) * factorial(n // j) //
                      prod(factorial(ni // j) for ni in evaluation)
                      for j in divisors(gcd(le))) // n
Exemple #22
0
    def _rank_dict(self):
        r"""
        Builds the rank dictionnary of the poset, if it exists, i.e.
        a dictionary ``d`` where ``d[object] = self.rank_function()(object)

        A *rank function* of a poset `P` is a function `r`
        that maps elements of `P` to integers and satisfies:
        `r(x) = r(y) + 1` if `x` covers `y`. The function `r`
        is normalized such that its smallest value is `0`.
        When `P` has several components, this is done for each
        component separately.

        EXAMPLES::

            sage: H = Poset()._hasse_diagram
            sage: H._rank_dict
            {}
            sage: H = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]])._hasse_diagram
            sage: H._rank_dict
            {0: 0, 1: 1, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 3}
            sage: H = Poset(([1,2,3,4,5],[[1,2],[2,3],[3,4],[1,5],[5,4]]))._hasse_diagram
            sage: H._rank_dict is None
            True

        """
        rank_fcn = {}  # rank_fcn will be the dictionary whose i-th entry
                       # is the rank of vertex i for every i.
        not_found = set(self.vertices())
        while not_found:
            y = not_found.pop()
            rank_fcn[y] = ZZ.zero()  # We set some vertex to have rank 0
            component = set([y])
            queue = set([y])
            while queue:  # look at the neighbors of y and set the ranks;
                          # then look at the neighbors of the neighbors ...
                y = queue.pop()
                for x in self.neighbors_out(y):
                    if x not in rank_fcn:
                        rank_fcn[x] = rank_fcn[y] + 1
                        queue.add(x)
                        component.add(x)
                for x in self.neighbors_in(y):
                    if x not in rank_fcn:
                        rank_fcn[x] = rank_fcn[y] - 1
                        queue.add(x)
                        component.add(x)
                    elif rank_fcn[x] != rank_fcn[y] - 1:
                        return None
            # Normalize the ranks of vertices in the connected component
            # so that smallest is 0:
            m = min(rank_fcn[j] for j in component)
            for j in component:
                rank_fcn[j] -= m
            not_found.difference_update(component)
        #now, all ranks are set.
        return rank_fcn
    def _coerce_map_from_(self, S):
        """
        This is called implicitly by arithmetic methods.

        EXAMPLES::

            sage: k = GF(7)
            sage: e = k(6)
            sage: e * 2 # indirect doctest
            5
            sage: 12 % 7
            5
            sage: ZZ.residue_field(7).hom(GF(7))(1)  # See trac 11319
            1
            sage: K.<w> = QuadraticField(337)  # See trac 11319
            sage: pp = K.ideal(13).factor()[0][0]
            sage: RF13 = K.residue_field(pp)
            sage: RF13.hom([GF(13)(1)])
            Ring morphism:
             From: Residue field of Fractional ideal (w + 18)
             To:   Finite Field of size 13
             Defn: 1 |--> 1

        Check that :trac:`19573` is resolved::

            sage: Integers(9).hom(GF(3))
            Natural morphism:
              From: Ring of integers modulo 9
              To:   Finite Field of size 3

            sage: Integers(9).hom(GF(5))
            Traceback (most recent call last):
            ...
            TypeError: natural coercion morphism from Ring of integers modulo 9 to Finite Field of size 5 not defined

        There is no coercion from a `p`-adic ring to its residue field::

            sage: GF(3).has_coerce_map_from(Zp(3))
            False
        """
        if S is int:
            return integer_mod.Int_to_IntegerMod(self)
        elif S is ZZ:
            return integer_mod.Integer_to_IntegerMod(self)
        elif isinstance(S, IntegerModRing_generic):
            from .residue_field import ResidueField_generic
            if (S.characteristic() % self.characteristic() == 0 and
                    (not isinstance(S, ResidueField_generic) or
                     S.degree() == 1)):
                try:
                    return integer_mod.IntegerMod_to_IntegerMod(S, self)
                except TypeError:
                    pass
        to_ZZ = ZZ._internal_coerce_map_from(S)
        if to_ZZ is not None:
            return integer_mod.Integer_to_IntegerMod(self) * to_ZZ
    def random_element(self, prec=None, integral=False):
        """
        Return a random element of this ring.

        INPUT:

        - ``prec`` -- an integer or ``None`` (the default): the
          absolute precision of the generated random element

        - ``integral`` -- a boolean (default: ``False``); if true
          return an element in the ring of integers

        EXAMPLES::

            sage: K = QpLC(2)
            sage: K.random_element()   # random
            2^-8 + 2^-7 + 2^-6 + 2^-5 + 2^-3 + 1 + 2^2 + 2^3 + 2^5 + O(2^12)
            sage: K.random_element(integral=True)    # random
            2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^10 + 2^11 + 2^14 + 2^15 + 2^16 + 2^17 + 2^18 + 2^19 + O(2^20)

            sage: K.random_element(prec=10)    # random
            2^(-3) + 1 + 2 + 2^4 + 2^8 + O(2^10)

        If the given precision is higher than the internal cap of the
        parent, then the cap is used::

            sage: K.precision_cap_relative()
            20
            sage: K.random_element(prec=100)    # random
            2^5 + 2^8 + 2^11 + 2^12 + 2^14 + 2^18 + 2^20 + 2^24 + O(2^25)
        """
        if integral:
            val = 0
        else:
            val = ZZ.random_element()
        if prec is None:
            prec = self._prec_cap_absolute - val
        p = self.prime()
        x = ZZ.random_element(p**prec)
        relcap = x.valuation(p) + self._prec_cap_relative
        if relcap < prec:
            prec = relcap
        return self._element_class(self, x*(p**val), prec=prec)
Exemple #25
0
        def gcd(self,other):
            """
            Greatest common divisor.

            NOTE:

            Since we are in a field and the greatest common divisor is
            only determined up to a unit, it is correct to either return
            zero or one. Note that fraction fields of unique factorization
            domains provide a more sophisticated gcd.

            EXAMPLES::

                sage: GF(5)(1).gcd(GF(5)(1))
                1
                sage: GF(5)(1).gcd(GF(5)(0))
                1
                sage: GF(5)(0).gcd(GF(5)(0))
                0

            For fields of characteristic zero (i.e., containing the
            integers as a sub-ring), evaluation in the integer ring is
            attempted. This is for backwards compatibility::

                sage: gcd(6.0,8); gcd(6.0,8).parent()
                2
                Integer Ring

            If this fails, we resort to the default we see above::

                sage: gcd(6.0*CC.0,8*CC.0); gcd(6.0*CC.0,8*CC.0).parent()
                1.00000000000000
                Complex Field with 53 bits of precision

            AUTHOR:

            - Simon King (2011-02): Trac ticket #10771

            """
            P = self.parent()
            try:
                other = P(other)
            except (TypeError, ValueError):
                raise ArithmeticError, "The second argument can not be interpreted in the parent of the first argument. Can't compute the gcd"
            from sage.rings.integer_ring import ZZ
            if ZZ.is_subring(P):
                try:
                    return ZZ(self).gcd(ZZ(other))
                except TypeError:
                    pass
            # there is no custom gcd, so, we resort to something that always exists
            # (that's new behaviour)
            if self==0 and other==0:
                return P.zero()
            return P.one()
Exemple #26
0
    def init_dir_char(self, chi):
        """
        Initiate with a Web Dirichlet character.
        """
        self.original_object = [chi]
        chi = chi.chi.primitive_character()
        self.object_type = "dirichletcharacter"
        self.dim = 1
        self.motivic_weight = 0
        self.conductor = ZZ(chi.conductor())
        self.bad_semistable_primes = []
        self.bad_pot_good = self.conductor.prime_factors()
        if chi.is_odd():
            aa = 1
            bb = I
        else:
            aa = 0
            bb = 1
        self.sign = chi.gauss_sum_numerical() / (bb * float(sqrt(chi.modulus())) )
        # this has now type python complex. later we need a gp complex
        self.sign = ComplexField()(self.sign)
        self.mu_fe = [aa]
        self.nu_fe = []
        self.gammaV = [aa]
        self.langlands = True
        self.selfdual = (chi.multiplicative_order() <= 2)
        # rather than all(  abs(chi(m).imag) < 0.0001 for m in range(chi.modulus() ) )
        self.primitive = True
        self.set_dokchitser_Lfunction()
        self.set_number_of_coefficients()
        self.dirichlet_coefficients = [ chi(m) for m in range(self.numcoeff + 1) ]
        if self.selfdual:
            self.coefficient_type = 2
        else:
            self.coefficient_type = 3
        self.coefficient_period = chi.modulus()
        self.besancon_bound = 10000

        def eu(p):
            """
            local euler factor
            """
            if self.selfdual:
                K = QQ
            else:
                K = ComplexField()
            R = PolynomialRing(K, "T")
            T = R.gens()[0]
            if self.conductor % p != 0:
                return  1 - ComplexField()(chi(p)) * T
            else:
                return R(1)

        self.local_euler_factor = eu
        self.ld.gp().quit()
def find_primitive_p_divisible_vector__random(self, p):
    """
    Finds a random `p`-primitive vector in `L/pL` whose value is `p`-divisible.

    .. note::

        Since there are about `p^{(n-2)}` of these lines, we have a `1/p`
        chance of randomly finding an appropriate vector.

    .. warning::

        If there are local obstructions for this to happen, then this algorithm
        will never terminate... =(  We should check for this too!

    EXAMPLES::

        sage: Q = QuadraticForm(ZZ, 2, [10,1,4])
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (1, 1)
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (1, 0)
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (2, 0)
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (2, 2)
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (3, 3)
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (3, 3)
        sage: Q.find_primitive_p_divisible_vector__random(5)    # random
        (2, 0)

    """
    n = self.dim()
    v = vector([ZZ.random_element(p)  for i in range(n)])

    ## Repeatedly choose random vectors, and evaluate until the value is p-divisible.
    while True:
        if (self(v) % p == 0) and (v != 0):
            return v
        else:
            v[ZZ.random_element(n)] = ZZ.random_element(p)      ## Replace a random entry and try again.
Exemple #28
0
 def random_element(self,prec=Infinity,precrandom=None):
     from ZZp_element import ZZp_element
     if precrandom is None:
         if prec is not Infinity:
             precrandom = prec
         else:
             precrandom = self._prec
     modulo = self._p ** precrandom
     approximation = ZZ.random_element(modulo)
     precision = self.precision()(prec)
     return ZZp_element(self, approximation, precision)
Exemple #29
0
    def one(self):
        r"""
        Return the identity element of the fundamental group.

        EXAMPLES::

            sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup
            sage: FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True).one()
            pi[0]
        """
        return self(ZZ.zero())
Exemple #30
0
    def group_generators(self):
        r"""
        Return group generators for ``self``.

        EXAMPLES::

            sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup
            sage: FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True).group_generators()
            (pi[1],)
        """
        return (self(ZZ.one()),)
Exemple #31
0
    def __init__(self, *args, **kwargs):
        """
        Construct a substitution box (S-box) for a given lookup table
        `S`.

        INPUT:

        - ``S`` - a finite iterable defining the S-box with integer or
          finite field elements

        - ``big_endian`` - controls whether bits shall be ordered in
          big endian order (default: ``True``)

        EXAMPLE:

        We construct a 3-bit S-box where e.g. the bits (0,0,1) are
        mapped to (1,1,1).::

            sage: S = mq.SBox(7,6,0,4,2,5,1,3); S
            (7, 6, 0, 4, 2, 5, 1, 3)

            sage: S(0)
            7

        TESTS::

            sage: S = mq.SBox()
            Traceback (most recent call last):
            ...
            TypeError: No lookup table provided.
            sage: S = mq.SBox(1, 2, 3)
            Traceback (most recent call last):
            ...
            TypeError: Lookup table length is not a power of 2.
            sage: S = mq.SBox(5, 6, 0, 3, 4, 2, 1, 2)
            sage: S.n
            3
        """
        if "S" in kwargs:
            S = kwargs["S"]
        elif len(args) == 1:
            S = args[0]
        elif len(args) > 1:
            S = args
        else:
            raise TypeError("No lookup table provided.")

        _S = []
        for e in S:
            if is_FiniteFieldElement(e):
                e = e.polynomial().change_ring(ZZ).subs(
                    e.parent().characteristic())
            _S.append(e)
        S = _S

        if not ZZ(len(S)).is_power_of(2):
            raise TypeError("Lookup table length is not a power of 2.")
        self._S = S

        self.m = ZZ(len(S)).exact_log(2)
        self.n = ZZ(max(S)).nbits()
        self._F = GF(2)
        self._big_endian = kwargs.get("big_endian", True)
Exemple #32
0
    def __call__(self, X):
        """
        Apply substitution to ``X``.

        If ``X`` is a list, it is interpreted as a sequence of bits
        depending on the bit order of this S-box.

        INPUT:

        - ``X`` - either an integer, a tuple of `\GF{2}` elements of
          length ``len(self)`` or a finite field element in
          `\GF{2^n}`. As a last resort this function tries to convert
          ``X`` to an integer.

        EXAMPLE::

            sage: S = mq.SBox([7,6,0,4,2,5,1,3])
            sage: S(7)
            3

            sage: S((0,2,3))
            [0, 1, 1]

            sage: S[0]
            7

            sage: S[(0,0,1)]
            [1, 1, 0]

            sage: k.<a> = GF(2^3)
            sage: S(a^2)
            a

            sage: S(QQ(3))
            4

            sage: S([1]*10^6)
            Traceback (most recent call last):
            ...
            TypeError: Cannot apply SBox to provided element.

            sage: S(1/2)
            Traceback (most recent call last):
            ...
            TypeError: Cannot apply SBox to 1/2.

            sage: S = mq.SBox(3, 0, 1, 3, 1, 0, 2, 2)
            sage: S(0)
            3
            sage: S([0,0,0])
            [1, 1]
        """
        if isinstance(X, (int, long, Integer)):
            return self._S[ZZ(X)]

        try:
            from sage.modules.free_module_element import vector
            K = X.parent()
            if K.order() == 2**self.n:
                X = vector(X)
            else:
                raise TypeError
            if not self._big_endian:
                X = list(reversed(X))
            else:
                X = list(X)
            X = ZZ(map(ZZ, X), 2)
            out = self.to_bits(self._S[X], self.n)
            if self._big_endian:
                out = list(reversed(out))
            return K(vector(GF(2), out))
        except (AttributeError, TypeError):
            pass

        try:
            if len(X) == self.m:
                if self._big_endian:
                    X = list(reversed(X))
                X = ZZ(map(ZZ, X), 2)
                out = self._S[X]
                return self.to_bits(out, self.n)
        except TypeError:
            pass

        try:
            return self._S[ZZ(X)]
        except TypeError:
            pass

        if len(str(X)) > 50:
            raise TypeError, "Cannot apply SBox to provided element."
        else:
            raise TypeError, "Cannot apply SBox to %s." % (X, )
Exemple #33
0
    def __init__(self, number_field, proof=True):
        """
        Create a unit group of a number field.

        INPUT:

        - ``number_field`` - a number field
        - ``proof`` - boolean (default True): proof flag

        The proof flag is passed to pari via the ``pari_bnf()`` function
        which computes the unit group.  See the documentation for the
        number_field module.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: K.<a> = NumberField(x^2-38)
            sage: UK = K.unit_group(); UK
            Unit group with structure C2 x Z of Number Field in a with defining polynomial x^2 - 38
            sage: UK.gens()
            (u0, u1)
            sage: UK.gens_values()
            [-1, 6*a - 37]

            sage: K.<a> = QuadraticField(-3)
            sage: UK = K.unit_group(); UK
            Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3
            sage: UK.gens()
            (u,)
            sage: UK.gens_values()
            [-1/2*a + 1/2]

            sage: K.<z> = CyclotomicField(13)
            sage: UK = K.unit_group(); UK
            Unit group with structure C26 x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12
            sage: UK.gens()
            (u0, u1, u2, u3, u4, u5)
            sage: UK.gens_values() # random
            [-z^11, z^5 + z^3, z^6 + z^5, z^9 + z^7 + z^5, z^9 + z^5 + z^4 + 1, z^5 + z]
            """
        proof = get_flag(proof, "number_field")
        K = number_field
        pK = K.pari_bnf(proof)
        self.__number_field = K

        # compute the units via pari:
        fu = [K(u) for u in pK.bnfunit()]

        # compute a torsion generator and pick the 'simplest' one:
        n, z = pK.nfrootsof1()
        n = ZZ(n)
        self.__ntu = n
        z = K(z)

        # If we replaced z by another torsion generator we would need
        # to allow for this in the dlog function!  So we do not.

        # Store the actual generators (torsion first):
        gens = [z] + fu
        values = Sequence(gens, immutable=True, universe=self, check=False)
        # Construct the abtract group:
        gens_orders = tuple([ZZ(n)] + [ZZ(0)] * len(fu))
        AbelianGroupWithValues_class.__init__(self, gens_orders, 'u', values,
                                              number_field)
def vectors_by_length(self, bound):
    """
    Returns a list of short vectors together with their values.

    This is a naive algorithm which uses the Cholesky decomposition,
    but does not use the LLL-reduction algorithm.

    INPUT:
       bound -- an integer >= 0

    OUTPUT:
        A list L of length (bound + 1) whose entry L `[i]` is a list of
        all vectors of length `i`.

    Reference: This is a slightly modified version of Cohn's Algorithm
    2.7.5 in "A Course in Computational Number Theory", with the
    increment step moved around and slightly re-indexed to allow clean
    looping.

    Note: We could speed this up for very skew matrices by using LLL
    first, and then changing coordinates back, but for our purposes
    the simpler method is efficient enough. =)

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1])
        sage: Q.vectors_by_length(5)
        [[[0, 0]],
         [[0, -1], [-1, 0]],
         [[-1, -1], [1, -1]],
         [],
         [[0, -2], [-2, 0]],
         [[-1, -2], [1, -2], [-2, -1], [2, -1]]]

    ::

        sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q1.vectors_by_length(5)
        [[[0, 0, 0, 0]],
         [[-1, 0, 0, 0]],
         [],
         [[0, -1, 0, 0]],
         [[-1, -1, 0, 0], [1, -1, 0, 0], [-2, 0, 0, 0]],
         [[0, 0, -1, 0]]]

    ::

        sage: Q = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1])
        sage: map(len, Q.vectors_by_length(2))
        [1, 12, 12]

    ::

        sage: Q = QuadraticForm(ZZ, 4, [1,-1,-1,-1, 1,0,0, 4,-3, 4])
        sage: map(len, Q.vectors_by_length(3))
        [1, 3, 0, 3]
    """
    # pari uses eps = 1e-6 ; nothing bad should happen if eps is too big
    # but if eps is too small, roundoff errors may knock off some
    # vectors of norm = bound (see #7100)
    eps = RDF(1e-6)
    bound = ZZ(floor(max(bound, 0)))
    Theta_Precision = bound + eps
    n = self.dim()

    ## Make the vector of vectors which have a given value
    ## (So theta_vec[i] will have all vectors v with Q(v) = i.)
    theta_vec = [[] for i in range(bound + 1)]

    ## Initialize Q with zeros and Copy the Cholesky array into Q
    Q = self.cholesky_decomposition()

    ## 1. Initialize
    T = n * [RDF(0)]  ## Note: We index the entries as 0 --> n-1
    U = n * [RDF(0)]
    i = n - 1
    T[i] = RDF(Theta_Precision)
    U[i] = RDF(0)

    L = n * [0]
    x = n * [0]
    Z = RDF(0)

    ## 2. Compute bounds
    Z = (T[i] / Q[i][i]).sqrt(extend=False)
    L[i] = (Z - U[i]).floor()
    x[i] = (-Z - U[i]).ceil()

    done_flag = False
    Q_val_double = RDF(0)
    Q_val = 0  ## WARNING: Still need a good way of checking overflow for this value...

    ## Big loop which runs through all vectors
    while not done_flag:

        ## 3b. Main loop -- try to generate a complete vector x (when i=0)
        while (i > 0):
            #print " i = ", i
            #print " T[i] = ", T[i]
            #print " Q[i][i] = ", Q[i][i]
            #print " x[i] = ", x[i]
            #print " U[i] = ", U[i]
            #print " x[i] + U[i] = ", (x[i] + U[i])
            #print " T[i-1] = ", T[i-1]

            T[i - 1] = T[i] - Q[i][i] * (x[i] + U[i]) * (x[i] + U[i])

            #print " T[i-1] = ",  T[i-1]
            #print " x = ", x
            #print

            i = i - 1
            U[i] = 0
            for j in range(i + 1, n):
                U[i] = U[i] + Q[i][j] * x[j]

            ## Now go back and compute the bounds...
            ## 2. Compute bounds
            Z = (T[i] / Q[i][i]).sqrt(extend=False)
            L[i] = (Z - U[i]).floor()
            x[i] = (-Z - U[i]).ceil()

            # carry if we go out of bounds -- when Z is so small that
            # there aren't any integral vectors between the bounds
            # Note: this ensures T[i-1] >= 0 in the next iteration
            while (x[i] > L[i]):
                i += 1
                x[i] += 1

        ## 4. Solution found (This happens when i = 0)
        #print "-- Solution found! --"
        #print " x = ", x
        #print " Q_val = Q(x) = ", Q_val
        Q_val_double = Theta_Precision - T[0] + Q[0][0] * (x[0] + U[0]) * (
            x[0] + U[0])
        Q_val = Q_val_double.round()

        ## SANITY CHECK: Roundoff Error is < 0.001
        if abs(Q_val_double - Q_val) > 0.001:
            print " x = ", x
            print " Float = ", Q_val_double, "   Long = ", Q_val
            raise RuntimeError, "The roundoff error is bigger than 0.001, so we should use more precision somewhere..."

        #print " Float = ", Q_val_double, "   Long = ", Q_val, "  XX "
        #print " The float value is ", Q_val_double
        #print " The associated long value is ", Q_val

        if (Q_val <= bound):
            #print " Have vector ",  x, " with value ", Q_val
            theta_vec[Q_val].append(deepcopy(x))

        ## 5. Check if x = 0, for exit condition. =)
        j = 0
        done_flag = True
        while (j < n):
            if (x[j] != 0):
                done_flag = False
            j += 1

        ## 3a. Increment (and carry if we go out of bounds)
        x[i] += 1
        while (x[i] > L[i]) and (i < n - 1):
            i += 1
            x[i] += 1

    #print " Leaving ThetaVectors()"
    return theta_vec
def zeta__exact(n):
    r"""
    Returns the exact value of the Riemann Zeta function

    The argument must be a critical value, namely either positive even
    or negative odd.

    See for example [Iwa1972]_, p13, Special value of `\zeta(2k)`

    EXAMPLES:

    Let us test the accuracy for negative special values::

        sage: RR = RealField(100)
        sage: for i in range(1,10):
        ....:     print("zeta({}): {}".format(1-2*i, RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i))))
        zeta(-1): 0.00000000000000000000000000000
        zeta(-3): 0.00000000000000000000000000000
        zeta(-5): 0.00000000000000000000000000000
        zeta(-7): 0.00000000000000000000000000000
        zeta(-9): 0.00000000000000000000000000000
        zeta(-11): 0.00000000000000000000000000000
        zeta(-13): 0.00000000000000000000000000000
        zeta(-15): 0.00000000000000000000000000000
        zeta(-17): 0.00000000000000000000000000000

    Let us test the accuracy for positive special values::

        sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10))
        True

    TESTS::

        sage: zeta__exact(4)
        1/90*pi^4
        sage: zeta__exact(-3)
        1/120
        sage: zeta__exact(0)
        -1/2
        sage: zeta__exact(5)
        Traceback (most recent call last):
        ...
        TypeError: n must be a critical value (i.e. even > 0 or odd < 0)

    REFERENCES:

    - [Iwa1972]_
    - [IR1990]_
    - [Was1997]_
    """
    if n < 0:
        return bernoulli(1-n)/(n-1)
    elif n > 1:
        if (n % 2 == 0):
            return ZZ(-1)**(n//2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n)
        else:
            raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)")
    elif n == 1:
        return infinity
    elif n == 0:
        return QQ((-1, 2))
    def block_design_checker(self, t, v, k, lmbda, type=None):
        """
        This is *not* a wrapper for GAP Design's IsBlockDesign. The GAP
        Design function IsBlockDesign
        http://www.gap-system.org/Manuals/pkg/design/htm/CHAP004.htm
        apparently simply checks the record structure and no mathematical
        properties. Instead, the function below checks some necessary (but
        not sufficient) "easy" identities arising from the identity.

        INPUT:

        - ``t`` - the t as in "t-design"

        - ``v`` - the number of points

        - ``k`` - the number of blocks incident to a point

        - ``lmbda`` - each t-tuple of points should be incident with
          lmbda blocks

        - ``type`` - can be 'simple' or 'binary' or 'connected'
          Depending on the option, this wraps IsBinaryBlockDesign,
          IsSimpleBlockDesign, or IsConnectedBlockDesign.

          - Binary: no block has a repeated element.

          - Simple: no block is repeated.

          - Connected: its incidence graph is a connected graph.

        WARNING: This is very fast but can return false positives.

        EXAMPLES::

            sage: from sage.combinat.designs.block_design import BlockDesign
            sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
            sage: BD.is_block_design()
            (True, [2, 7, 3, 1])
            sage: BD.block_design_checker(2, 7, 3, 1)
            True
            sage: BD.block_design_checker(2, 7, 3, 1,"binary")
            True
            sage: BD.block_design_checker(2, 7, 3, 1,"connected")
            True
            sage: BD.block_design_checker(2, 7, 3, 1,"simple")
            True
        """
        from sage.sets.set import Set
        if not(v == len(self.points())):
            return False
        b = lmbda*binomial(v, t)/binomial(k, t)
        r = int(b*k/v)
        if not(b == len(self.blocks())):
            return False
        if not(ZZ(v).divides(b*k)):
            return False
        A = self.incidence_matrix()
        #k = sum(A.columns()[0])
        #r = sum(A.rows()[0])
        for i in range(b):
            if not(sum(A.columns()[i]) == k):
                return False
        for i in range(v):
            if not(sum(A.rows()[i]) == r):
                return False
        if type is None:
            return True
        if type == "binary":
            for b in self.blocks():
                if len(b) != len(Set(b)):
                    return False
            return True
        if type == "simple":
            B = self.blocks()
            for b in B:
                if B.count(b) > 1:
                    return False
            return True
        if type == "connected":
            Gamma = self.incidence_graph()
            if Gamma.is_connected():
                return True
            else:
                return False
    def H_value(self, p, f, t, ring=None):
        """
        Return the trace of the Frobenius, computed in terms of Gauss sums
        using the hypergeometric trace formula.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``ring`` -- optional (default ``UniversalCyclotomicfield``)

        The ring could be also ``ComplexField(n)`` or ``QQbar``.

        OUTPUT:

        an integer

        .. WARNING::

            This is apparently working correctly as can be tested
            using ComplexField(70) as value ring.

            Using instead UniversalCyclotomicfield, this is much
            slower than the `p`-adic version :meth:`padic_H_value`.

        EXAMPLES:

        With values in the UniversalCyclotomicField (slow)::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.H_value(7,i,-1) for i in range(1,3)]  # not tested
            [0, -476]
            sage: [H.H_value(11,i,-1) for i in range(1,3)]  # not tested
            [0, -4972]
            sage: [H.H_value(13,i,-1) for i in range(1,3)]  # not tested
            [-84, -1420]

        With values in ComplexField::

            sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)]
            [-4, 276]

        Check issue from :trac:`28404`::

            sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2]))
            sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1]))
            sage: [H1.H_value(5,1,i) for i in range(2,5)]
            [1, -4, -4]
            sage: [H2.H_value(5,1,QQ(i)) for i in range(2,5)]
            [-4, 1, -4]

        REFERENCES:

        - [BeCoMe]_ (Theorem 1.3)
        - [Benasque2009]_
        """
        alpha = self._alpha
        beta = self._beta
        t = QQ(t)
        if 0 in alpha:
            return self._swap.H_value(p, f, ~t, ring)
        if ring is None:
            ring = UniversalCyclotomicField()
        gamma = self.gamma_array()
        q = p**f

        m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2
        M = self.M_value()

        Fq = GF(q)
        gen = Fq.multiplicative_generator()
        zeta_q = ring.zeta(q - 1)

        tM = Fq(M / t)
        for k in range(q - 1):
            if gen**k == tM:
                teich = zeta_q**k
                break

        gauss_table = [gauss_sum(zeta_q**r, Fq) for r in range(q - 1)]

        sigma = sum(q**(D + m[0] - m[r]) *
                    prod(gauss_table[(-v * r) % (q - 1)]**gv
                         for v, gv in gamma.items()) * teich**r
                    for r in range(q - 1))
        resu = ZZ(-1)**m[0] / (1 - q) * sigma
        if not ring.is_exact():
            resu = resu.real_part().round()
        return resu
def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True):
    r"""
    Return a list of pairs `(s_i, L_i)` where `L_i` is a maximal
    `p^{s_i}`-unimodular Jordan component which is further decomposed into
    block diagonals of block size `\le 2`.

    For each `L_i` the 2x2 blocks are listed after the 1x1 blocks
    (which follows from the convention of the
    :meth:`local_normal_form` method).

    .. NOTE::

        The decomposition of each `L_i` into smaller blocks is not unique!

    The ``safe_flag`` argument allows us to select whether we want a copy of
    the output, or the original output.  By default ``safe_flag = True``, so we
    return a copy of the cached information.  If this is set to ``False``, then
    the routine is much faster but the return values are vulnerable to being
    corrupted by the user.

    INPUT:

    - `p` -- a prime number > 0.

    OUTPUT:

    A list of pairs `(s_i, L_i)` where:

    - `s_i` is an integer,
    - `L_i` is a block-diagonal unimodular quadratic form over `\ZZ_p`.

    .. note::

        These forms `L_i` are defined over the `p`-adic integers, but by a
        matrix over `\ZZ` (or `\QQ`?).

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7])
        sage: Q.jordan_blocks_by_scale_and_unimodular(3)
        [(0, Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 1 0 0 ]
        [ * 5 0 ]
        [ * * 7 ]), (2, Quadratic form in 1 variables over Integer Ring with coefficients:
        [ 1 ])]

    ::

        sage: Q2 = QuadraticForm(ZZ, 2, [1,1,1])
        sage: Q2.jordan_blocks_by_scale_and_unimodular(2)
        [(-1, Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 2 2 ]
        [ * 2 ])]
        sage: Q = Q2 + Q2.scale_by_factor(2)
        sage: Q.jordan_blocks_by_scale_and_unimodular(2)
        [(-1, Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 2 2 ]
        [ * 2 ]), (0, Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 2 2 ]
        [ * 2 ])]
    """
    # Try to use the cached result
    try:
        if safe_flag:
            return copy.deepcopy(
                self.__jordan_blocks_by_scale_and_unimodular_dict[p])
        else:
            return self.__jordan_blocks_by_scale_and_unimodular_dict[p]
    except Exception:
        # Initialize the global dictionary if it doesn't exist
        if not hasattr(self, '__jordan_blocks_by_scale_and_unimodular_dict'):
            self.__jordan_blocks_by_scale_and_unimodular_dict = {}

    # Deal with zero dim'l forms
    if self.dim() == 0:
        return []

    # Find the Local Normal form of Q at p
    Q1 = self.local_normal_form(p)

    # Parse this into Jordan Blocks
    n = Q1.dim()
    tmp_Jordan_list = []
    i = 0
    start_ind = 0
    if (n >= 2) and (Q1[0, 1] != 0):
        start_scale = valuation(Q1[0, 1], p) - 1
    else:
        start_scale = valuation(Q1[0, 0], p)

    while (i < n):

        # Determine the size of the current block
        if (i == n - 1) or (Q1[i, i + 1] == 0):
            block_size = 1
        else:
            block_size = 2

        # Determine the valuation of the current block
        if block_size == 1:
            block_scale = valuation(Q1[i, i], p)
        else:
            block_scale = valuation(Q1[i, i + 1], p) - 1

        # Process the previous block if the valuation increased
        if block_scale > start_scale:
            tmp_Jordan_list += [
                (start_scale, Q1.extract_variables(
                    range(start_ind,
                          i)).scale_by_factor(ZZ(1) / (QQ(p)**(start_scale))))
            ]
            start_ind = i
            start_scale = block_scale

        # Increment the index
        i += block_size

    # Add the last block
    tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(
        start_ind, n)).scale_by_factor(ZZ(1) / QQ(p)**(start_scale)))]

    # Cache the result
    self.__jordan_blocks_by_scale_and_unimodular_dict[p] = tmp_Jordan_list

    # Return the result
    return tmp_Jordan_list
def local_normal_form(self, p):
    r"""
    Return a locally integrally equivalent quadratic form over
    the `p`-adic integers `\ZZ_p` which gives the Jordan decomposition.

    The Jordan components are written as sums of blocks of size <= 2
    and are arranged by increasing scale, and then by increasing norm.
    This is equivalent to saying that we put the 1x1 blocks before
    the 2x2 blocks in each Jordan component.

    INPUT:

    - `p` -- a positive prime number.

    OUTPUT:

    a quadratic form over `\ZZ`

    .. WARNING::

        Currently this only works for quadratic forms defined over `\ZZ`.

    EXAMPLES::

        sage: Q = QuadraticForm(ZZ, 2, [10,4,1])
        sage: Q.local_normal_form(5)
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 1 0 ]
        [ * 6 ]

    ::

        sage: Q.local_normal_form(3)
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 10 0 ]
        [ * 15 ]

        sage: Q.local_normal_form(2)
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 1 0 ]
        [ * 6 ]
    """
    # Sanity Checks
    if (self.base_ring() != IntegerRing()):
        raise NotImplementedError(
            "Oops!  This currently only works for quadratic forms defined over IntegerRing(). =("
        )
    if not ((p >= 2) and is_prime(p)):
        raise TypeError("Oops!  p is not a positive prime number. =(")

    # Some useful local variables
    Q = self.parent()(self.base_ring(), self.dim(), self.coefficients())

    # Prepare the final form to return
    Q_Jordan = copy.deepcopy(self)
    Q_Jordan.__init__(self.base_ring(), 0)

    while Q.dim() > 0:
        n = Q.dim()

        # Step 1: Find the minimally p-divisible matrix entry, preferring diagonals
        # -------------------------------------------------------------------------
        (min_i, min_j) = Q.find_entry_with_minimal_scale_at_prime(p)
        if min_i == min_j:
            min_val = valuation(2 * Q[min_i, min_j], p)
        else:
            min_val = valuation(Q[min_i, min_j], p)

        # Error if we still haven't seen non-zero coefficients!
        if (min_val == Infinity):
            raise RuntimeError("Oops!  The original matrix is degenerate. =(")

        # Step 2: Arrange for the upper leftmost entry to have minimal valuation
        # ----------------------------------------------------------------------
        if (min_i == min_j):
            block_size = 1
            Q.swap_variables(0, min_i, in_place=True)
        else:
            # Work in the upper-left 2x2 block, and replace it by its 2-adic equivalent form
            Q.swap_variables(0, min_i, in_place=True)
            Q.swap_variables(1, min_j, in_place=True)

            # 1x1 => make upper left the smallest
            if (p != 2):
                block_size = 1
                Q.add_symmetric(1, 0, 1, in_place=True)
            # 2x2 => replace it with the appropriate 2x2 matrix
            else:
                block_size = 2

        # Step 3: Clear out the remaining entries
        #  ---------------------------------------
        min_scale = p**min_val  # This is the minimal valuation of the Hessian matrix entries.

        # Perform cancellation over Z by ensuring divisibility
        if (block_size == 1):
            a = 2 * Q[0, 0]
            for j in range(block_size, n):
                b = Q[0, j]
                g = GCD(a, b)

                # Sanity Check:  a/g is a p-unit
                if valuation(g, p) != valuation(a, p):
                    raise RuntimeError(
                        "Oops!  We have a problem with our rescaling not preserving p-integrality!"
                    )

                Q.multiply_variable(
                    ZZ(a / g), j, in_place=True
                )  # Ensures that the new b entry is divisible by a
                Q.add_symmetric(ZZ(-b / g), j, 0,
                                in_place=True)  # Performs the cancellation

        elif (block_size == 2):
            a1 = 2 * Q[0, 0]
            a2 = Q[0, 1]
            b1 = Q[1, 0]  # This is the same as a2
            b2 = 2 * Q[1, 1]

            big_det = (a1 * b2 - a2 * b1)
            small_det = big_det / (min_scale * min_scale)

            # Cancels out the rows/columns of the 2x2 block
            for j in range(block_size, n):
                a = Q[0, j]
                b = Q[1, j]

                # Ensures an integral result (scale jth row/column by big_det)
                Q.multiply_variable(big_det, j, in_place=True)

                # Performs the cancellation (by producing -big_det * jth row/column)
                Q.add_symmetric(ZZ(-(a * b2 - b * a2)), j, 0, in_place=True)
                Q.add_symmetric(ZZ(-(-a * b1 + b * a1)), j, 1, in_place=True)

                # Now remove the extra factor (non p-unit factor) in big_det we introduced above
                Q.divide_variable(ZZ(min_scale * min_scale), j, in_place=True)

            # Uses Cassels's proof to replace the remaining 2 x 2 block
            if (((1 + small_det) % 8) == 0):
                Q[0, 0] = 0
                Q[1, 1] = 0
                Q[0, 1] = min_scale
            elif (((5 + small_det) % 8) == 0):
                Q[0, 0] = min_scale
                Q[1, 1] = min_scale
                Q[0, 1] = min_scale
            else:
                raise RuntimeError(
                    "Error in LocalNormal: Impossible behavior for a 2x2 block! \n"
                )

        # Check that the cancellation worked, extract the upper-left block, and trim Q to handle the next block.
        for i in range(block_size):
            for j in range(block_size, n):
                if Q[i, j] != 0:
                    raise RuntimeError(
                        "Oops!  The cancellation didn't work properly at entry ("
                        + str(i) + ", " + str(j) + ").")
        Q_Jordan = Q_Jordan + Q.extract_variables(range(block_size))
        Q = Q.extract_variables(range(block_size, n))

    return Q_Jordan
Exemple #40
0
 def __call__(self, cm, aut):
     self.count += ZZ(1)
     self.weighted_count += QQ((1, (1 if aut is None else aut.group_cardinality())))
Exemple #41
0
 def __init__(self):
     self.count = ZZ(0)
     self.weighted_count = QQ(0)
def basis_of_short_vectors(self, show_lengths=False):
    r"""
    Return a basis for `\ZZ^n` made of vectors with minimal lengths Q(`v`).

    OUTPUT:

    a tuple of vectors, and optionally a tuple of values for each vector.

    This uses :pari:`qfminim`.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.basis_of_short_vectors()
        ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
        sage: Q.basis_of_short_vectors(True)
        (((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), (1, 3, 5, 7))

    The returned vectors are immutable::

        sage: v = Q.basis_of_short_vectors()[0]
        sage: v
        (1, 0, 0, 0)
        sage: v[0] = 0
        Traceback (most recent call last):
        ...
        ValueError: vector is immutable; please change a copy instead (use copy())
    """
    # Set an upper bound for the number of vectors to consider
    Max_number_of_vectors = 10000

    # Generate a PARI matrix for the associated Hessian matrix
    M_pari = self.__pari__()

    # Run through all possible minimal lengths to find a spanning set of vectors
    n = self.dim()
    M1 = Matrix([[0]])
    vec_len = 0
    while M1.rank() < n:
        vec_len += 1
        pari_mat = M_pari.qfminim(vec_len, Max_number_of_vectors)[2]
        number_of_vecs = ZZ(pari_mat.matsize()[1])
        vector_list = []
        for i in range(number_of_vecs):
            new_vec = vector([ZZ(x) for x in list(pari_mat[i])])
            vector_list.append(new_vec)

        # Make a matrix from the short vectors
        if vector_list:
            M1 = Matrix(vector_list)

    # Organize these vectors by length (and also introduce their negatives)
    max_len = vec_len // 2
    vector_list_by_length = [[] for _ in range(max_len + 1)]
    for v in vector_list:
        l = self(v)
        vector_list_by_length[l].append(v)
        vector_list_by_length[l].append(vector([-x for x in v]))

    # Make a matrix from the column vectors (in order of ascending length).
    sorted_list = []
    for i in range(len(vector_list_by_length)):
        for v in vector_list_by_length[i]:
            sorted_list.append(v)
    sorted_matrix = Matrix(sorted_list).transpose()

    # Determine a basis of vectors of minimal length
    pivots = sorted_matrix.pivots()
    basis = tuple(sorted_matrix.column(i) for i in pivots)
    for v in basis:
        v.set_immutable()

    # Return the appropriate result
    if show_lengths:
        pivot_lengths = tuple(self(v) for v in basis)
        return basis, pivot_lengths
    else:
        return basis
    def integral(self, var=None):
        """
        Return the integral of this polynomial.

        By default, the integration variable is the variable of the
        polynomial.

        Otherwise, the integration variable is the optional parameter ``var``

        .. NOTE::

            The integral is always chosen so that the constant term is 0.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(ZZ, sparse=True)
            sage: (1 + 3*x^10 - 2*x^100).integral()
            -2/101*x^101 + 3/11*x^11 + x

        TESTS:

        Check that :trac:`18600` is fixed::

            sage: R.<x> = PolynomialRing(ZZ, sparse=True)
            sage: (x^2^100).integral()
            1/1267650600228229401496703205377*x^1267650600228229401496703205377

        Check the correctness when the base ring is a polynomial ring::

            sage: R.<x> = PolynomialRing(ZZ, sparse=True)
            sage: S.<t> = PolynomialRing(R, sparse=True)
            sage: (x*t+1).integral()
            1/2*x*t^2 + t
            sage: (x*t+1).integral(x)
            1/2*x^2*t + x

        Check the correctness when the base ring is not an integral domain::

            sage: R.<x> = PolynomialRing(Zmod(4), sparse=True)
            sage: (x^4 + 2*x^2  + 3).integral()
            x^5 + 2*x^3 + 3*x
            sage: x.integral()
            Traceback (most recent call last):
            ...
            ZeroDivisionError: Inverse does not exist.
        """
        R = self.parent()
        # TODO:
        # calling the coercion model bin_op is much more accurate than using the
        # true division (which is bypassed by polynomials). But it does not work
        # in all cases!!
        from sage.structure.element import coercion_model as cm
        import operator
        try:
            Q = cm.bin_op(R.one(), ZZ.one(), operator.div).parent()
        except TypeError:
            F = (R.base_ring().one() / ZZ.one()).parent()
            Q = R.change_ring(F)

        if var is not None and var != R.gen():
            return Q(
                {k: v.integral(var)
                 for k, v in six.iteritems(self.__coeffs)},
                check=False)

        return Q({k + 1: v / (k + 1)
                  for k, v in six.iteritems(self.__coeffs)},
                 check=False)
Exemple #44
0
def theta_series_degree_2(Q, prec):
    r"""
    Compute the theta series of degree 2 for the quadratic form Q.

    INPUT:

    - ``prec`` -- an integer.

    OUTPUT:

    dictionary, where:

    - keys are `{\rm GL}_2(\ZZ)`-reduced binary quadratic forms (given as triples of
      coefficients)
    - values are coefficients

    EXAMPLES::

        sage: Q2 = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1])
        sage: S = Q2.theta_series_degree_2(10)
        sage: S[(0,0,2)]
        24
        sage: S[(1,0,1)]
        144
        sage: S[(1,1,1)]
        192

    AUTHORS:

    - Gonzalo Tornaria (2010-03-23)

    REFERENCE:

    - Raum, Ryan, Skoruppa, Tornaria, 'On Formal Siegel Modular Forms'
      (preprint)
    """
    if Q.base_ring() != ZZ:
        raise TypeError, "The quadratic form must be integral"
    if not Q.is_positive_definite():
        raise ValueError, "The quadratic form must be positive definite"
    try:
        X = ZZ(prec - 1)  # maximum discriminant
    except TypeError:
        raise TypeError, "prec is not an integer"

    if X < -1:
        raise ValueError, "prec must be >= 0"

    if X == -1:
        return {}

    V = ZZ**Q.dim()
    H = Q.Hessian_matrix()

    t = cputime()
    max = int(floor((X + 1) / 4))
    v_list = (Q.vectors_by_length(max))  # assume a>0
    v_list = map(lambda (vs): map(V, vs), v_list)  # coerce vectors into V
    verbose("Computed vectors_by_length", t)

    # Deal with the singular part
    coeffs = {(0, 0, 0): ZZ(1)}
    for i in range(1, max + 1):
        coeffs[(0, 0, i)] = ZZ(2) * len(v_list[i])

    # Now deal with the non-singular part
    a_max = int(floor(sqrt(X / 3)))
    for a in range(1, a_max + 1):
        t = cputime()
        c_max = int(floor((a * a + X) / (4 * a)))
        for c in range(a, c_max + 1):
            for v1 in v_list[a]:
                v1_H = v1 * H

                def B_v1(v):
                    return v1_H * v2

                for v2 in v_list[c]:
                    b = abs(B_v1(v2))
                    if b <= a and 4 * a * c - b * b <= X:
                        qf = (a, b, c)
                        count = ZZ(4) if b == 0 else ZZ(2)
                        coeffs[qf] = coeffs.get(qf, ZZ(0)) + count
        verbose("done a = %d" % a, t)

    return coeffs
Exemple #45
0
    def _get_powers(self,g,emb = None):
        r"""
        Auxiliary function to compute the Sigma_0(p)^2 action on moments.

        The action sends a monomial x^i to (gx)^i, where gx = (b+dx)/(a+cx). The 
        action on two-variable functions is simply the product of two copies of the
        one variable action.

        Input:
                - g : Sigma0SquaredElement object (in the relevant Sigma_0(p)^2 group)

        Returns:
                matrix of (g_x,g_y) acting on distributions in the basis given by monomials

        EXAMPLES::

                sage: D = BianchiDistributions(11,2)
                sage: h = D.Sigma0Squared()([1,1,0,1],[1,1,0,1])
                sage: D._get_powers(h)
                [1 0 0 0]
                [1 1 0 0]
                [1 0 1 0]
                [1 1 1 1]
                sage: h = D.Sigma0Squared()([2,3,11,1],[12,1,22,1])
                sage: D._get_powers(h)
                [1 0 0 0]
                [7 6 0 0]
                [1 0 1 0]
                [7 6 7 6]

        """
        ## We want to ultimately compute actions on distributions. The matrix describing the (left)
        ## action of g on distributions is the transpose of the action of adjoint(g) acting on the (left)
        ## of analytic functions, so we start by taking adjoints. Then put the matrix entries into lists

        ## NOTE: First apply the adjuster defined above; permutes a,b,c,d to allow for different conventions.
        abcdx = g.first_element()
        abcdy = g.second_element()

        ## Adjust for action: change of convention is encoded in our_adjuster class above
        adjuster = self._adjuster
        abcdx = adjuster(abcdx.matrix())
        abcdy = adjuster(abcdy.matrix())

        ## We want better keys; keys in Zp are not great. Store them instead in ZZ
        abcdxZZ = tuple(ZZ(t) for t in abcdx)
        abcdyZZ = tuple(ZZ(t) for t in abcdy)

        ## check to see if the action of (g,h) has already been computed and cached
        try:
            return self._cache_powers[(abcdxZZ,abcdyZZ)]
        except KeyError:
            pass

        ## Sanity check output
        verbose('The element [{},{}] has not been stored. Computing:'.format(abcdxZZ,abcdyZZ), level=2)

        R = self._PowerSeries ## Zp[[x,y]
        y = R.gen()
        x = R.base_ring().gen()

        ## get values of a,b,c,d for x and y
        if emb is None:
            a,b,c,d = abcdx
            A,B,C,D = abcdy
        else:
            gg = emb(abcdy)
            a,b,c,d = gg[0].list()
            A,B,C,D = gg[1].list()

        ## Initialise terms
        num_x = b + d * x ## b + az + O(11^depth)R
        denom_x = a + c * x ## d + cz + O(11^depth)R
        num_y = B+ D * x
        denom_y = A + C * x

        ## Ratios
        r = R.base_ring()(num_x / denom_x) ## after action on x
        s = num_y / denom_y ## after action on y

        r = r.change_ring(ZZ)
        s = s.change_ring(ZZ)

        RZ = self._PowerSeries_ZZ
        phi = s.parent().hom([RZ.gen()])
        ## Constant term
        const = r.parent()(1)
        spows = [const]
        for n in range(self._depth):
            spows.append(s * spows[-1])

        acted_monomials = {}
        for j in range(self._depth):
            acted_monomials[(0, j)] = phi(spows[j])
        rpow = 1
        for i in range(1, self._depth):
            rpow *= r
            rpow.add_bigoh(self._depth)
            for j in range(self._depth):
                acted_monomials[(i,j)] = rpow * phi(spows[j])

        matrix_rows = []
        for n in range(self._dimension):
            f = acted_monomials[tuple(self.ij_from_pos(n))]
            new_row = []
            for polx in f.padded_list(self._depth):
                new_row.extend(polx.padded_list(self._depth))
            matrix_rows.append(new_row)


        ## Build matrix . DO NOT TAKE TRANSPOSE, (built this in as a consequence of implementation)
        matrix_action = Matrix(ZZ, matrix_rows)
        #acted_monomials_list = Matrix(R.base_ring(),self._depth,self._depth,acted_monomials_list)#.apply_map(ZZ)
        self._cache_powers[(abcdxZZ,abcdyZZ)] = matrix_action
        return matrix_action
Exemple #46
0
        def _singularity_analysis_(self, var, zeta, precision):
            r"""
            Perform singularity analysis on this growth element.

            INPUT:

            - ``var`` -- a string denoting the variable

            - ``zeta`` -- a number

            - ``precision`` -- an integer

            OUTPUT:

            An asymptotic expansion for `[z^n] f` where `n` is ``var``
            and `f` has this growth element as a singular expansion
            in `T=\frac{1}{1-\frac{z}{\zeta}}\to \infty` where this
            element is a growth element in `T`.

            EXAMPLES::

                sage: from sage.rings.asymptotic.growth_group import GrowthGroup
                sage: G = GrowthGroup('exp(x)^QQ * x^QQ * log(x)^QQ')
                sage: G(x^(1/2))._singularity_analysis_('n', 2, precision=2)
                1/sqrt(pi)*(1/2)^n*n^(-1/2) - 1/8/sqrt(pi)*(1/2)^n*n^(-3/2)
                + O((1/2)^n*n^(-5/2))
                sage: G(log(x))._singularity_analysis_('n', 1, precision=5)
                n^(-1) + O(n^(-3))
                sage: G(x*log(x))._singularity_analysis_('n', 1, precision=5)
                log(n) + euler_gamma + 1/2*n^(-1) + O(n^(-2))

            TESTS::

                sage: G('exp(x)*log(x)')._singularity_analysis_('n', 1, precision=5)
                Traceback (most recent call last):
                ...
                NotImplementedError: singularity analysis of exp(x)*log(x)
                not implemented
                sage: G('exp(x)*x*log(x)')._singularity_analysis_('n', 1, precision=5)
                Traceback (most recent call last):
                ...
                NotImplementedError: singularity analysis of exp(x)*x*log(x)
                not yet implemented since it has more than two factors
                sage: G(1)._singularity_analysis_('n', 2, precision=3)
                Traceback (most recent call last):
                ...
                NotImplementedOZero: The error term in the result is O(0)
                which means 0 for sufficiently large n.
                sage: G('exp(x)')._singularity_analysis_('n', 2, precision=3)
                Traceback (most recent call last):
                ...
                NotImplementedError: singularity analysis of exp(x)
                not implemented
            """
            factors = self.factors()
            if len(factors) == 0:
                from .asymptotic_expansion_generators import asymptotic_expansions
                from .misc import NotImplementedOZero
                raise NotImplementedOZero(var=var)
            elif len(factors) == 1:
                return factors[0]._singularity_analysis_(var=var,
                                                         zeta=zeta,
                                                         precision=precision)
            elif len(factors) == 2:
                from .growth_group import MonomialGrowthGroup
                from sage.rings.integer_ring import ZZ

                a, b = factors
                if all(isinstance(f.parent(), MonomialGrowthGroup)
                       for f in factors) \
                        and a.parent().gens_monomial() \
                        and b.parent().gens_logarithmic() \
                        and a.parent().variable_name() == \
                            b.parent().variable_name():
                    if b.exponent not in ZZ:
                        raise NotImplementedError(
                            'singularity analysis of {} not implemented '
                            'since exponent {} of {} is not an integer'.format(
                                self, b.exponent,
                                b.parent().gen()))

                    from sage.rings.asymptotic.asymptotic_expansion_generators import \
                        asymptotic_expansions
                    return asymptotic_expansions.SingularityAnalysis(
                        var=var,
                        zeta=zeta,
                        alpha=a.exponent,
                        beta=ZZ(b.exponent),
                        delta=0,
                        precision=precision,
                        normalized=False)
                else:
                    raise NotImplementedError(
                        'singularity analysis of {} not implemented'.format(
                            self))
            else:
                raise NotImplementedError(
                    'singularity analysis of {} not yet implemented '
                    'since it has more than two factors'.format(self))
Exemple #47
0
def krawtchouk(n, q, l, x, check=True):
    r"""
    Compute ``K^{n,q}_l(x)``, the Krawtchouk (a.k.a. Kravchuk) polynomial.

    See :wikipedia:`Kravchuk_polynomials`.

    It is defined by the generating function

    .. MATH::

        (1+(q-1)z)^{n-x}(1-z)^x=\sum_{l} K^{n,q}_l(x)z^l

    and is equal to

    .. MATH::

        K^{n,q}_l(x)=\sum_{j=0}^l (-1)^j (q-1)^{(l-j)} \binom{x}{j} \binom{n-x}{l-j},

    INPUT:

    - ``n, q, x`` -- arbitrary numbers

    - ``l`` -- a nonnegative integer

    - ``check`` -- check the input for correctness. ``True`` by
      default. Otherwise, pass it as it is. Use ``check=False`` at
      your own risk.

    EXAMPLES::

        sage: codes.bounds.krawtchouk(24,2,5,4)
        2224
        sage: codes.bounds.krawtchouk(12300,4,5,6)
        567785569973042442072

    TESTS:

    check that the bug reported on :trac:`19561` is fixed::

        sage: codes.bounds.krawtchouk(3,2,3,3)
        -1
        sage: codes.bounds.krawtchouk(int(3),int(2),int(3),int(3))
        -1
        sage: codes.bounds.krawtchouk(int(3),int(2),int(3),int(3),check=False)
        -1.0
        sage: codes.bounds.krawtchouk(24,2,5,4)
        2224

    other unusual inputs ::

        sage: codes.bounds.krawtchouk(sqrt(5),1-I*sqrt(3),3,55.3).n()
        211295.892797... + 1186.42763...*I
        sage: codes.bounds.krawtchouk(-5/2,7*I,3,-1/10)
        480053/250*I - 357231/400
        sage: codes.bounds.krawtchouk(1,1,-1,1)
        Traceback (most recent call last):
        ...
        ValueError: l must be a nonnegative integer
        sage: codes.bounds.krawtchouk(1,1,3/2,1)
        Traceback (most recent call last):
        ...
        TypeError: no conversion of this rational to integer
    """
    from sage.arith.all import binomial
    from sage.arith.srange import srange
    # Use the expression in equation (55) of MacWilliams & Sloane, pg 151
    # We write jth term = some_factor * (j-1)th term
    if check:
        from sage.rings.integer_ring import ZZ
        l0 = ZZ(l)
        if l0 != l or l0 < 0:
            raise ValueError('l must be a nonnegative integer')
        l = l0
    kraw = jth_term = (q - 1)**l * binomial(n, l)  # j=0
    for j in srange(1, l + 1):
        jth_term *= -q * (l - j + 1) * (x - j + 1) / ((q - 1) * j *
                                                      (n - j + 1))
        kraw += jth_term
    return kraw
Exemple #48
0
    def _find_scaling_L_ratio(self):
        r"""
        This function is use to set ``_scaling``, the factor used to adjust the
        scalar multiple of the modular symbol.
        If `[0]`, the modular symbol evaluated at 0, is non-zero, we can just scale
        it with respect to the approximation of the L-value. It is known that
        the quotient is a rational number with small denominator.
        Otherwise we try to scale using quadratic twists.

        ``_scaling`` will be set to a rational non-zero multiple if we succeed and to 1 otherwise.
        Even if we fail we scale at least to make up the difference between the periods
        of the `X_0`-optimal curve and our given curve `E` in the isogeny class.

        EXAMPLES::

            sage : m = EllipticCurve('11a1').modular_symbol(use_eclib=True)
            sage : m._scaling
            1
            sage: m = EllipticCurve('11a2').modular_symbol(use_eclib=True)
            sage: m._scaling
            5/2
            sage: m = EllipticCurve('11a3').modular_symbol(use_eclib=True)
            sage: m._scaling
            1/10
            sage: m = EllipticCurve('11a1').modular_symbol(use_eclib=False)
            sage: m._scaling
            1/5
            sage: m = EllipticCurve('11a2').modular_symbol(use_eclib=False)
            sage: m._scaling
            1
            sage: m = EllipticCurve('11a3').modular_symbol(use_eclib=False)
            sage: m._scaling
            1/25
            sage: m = EllipticCurve('37a1').modular_symbol(use_eclib=False)
            sage: m._scaling
            1
            sage: m = EllipticCurve('37a1').modular_symbol(use_eclib=True)
            sage: m._scaling
            -1
            sage: m = EllipticCurve('389a1').modular_symbol(use_eclib=True)
            sage: m._scaling
            -1/2
            sage: m = EllipticCurve('389a1').modular_symbol(use_eclib=False)
            sage: m._scaling
            2
            sage: m = EllipticCurve('196a1').modular_symbol(use_eclib=False)
            sage: m._scaling
            1/2

        Some harder cases fail::

            sage: m = EllipticCurve('121b1').modular_symbol(use_eclib=False)
            Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by -1, 2 or -2.
            sage: m._scaling
            1

        TESTS::

            sage: rk0 = ['11a1', '11a2', '15a1', '27a1', '37b1']
            sage: for la in rk0:  # long time (3s on sage.math, 2011)
            ...          E = EllipticCurve(la)
            ...          me = E.modular_symbol(use_eclib = True)
            ...          ms = E.modular_symbol(use_eclib = False)
            ...          print E.lseries().L_ratio()*E.real_components(), me(0), ms(0)
            1/5 1/5 1/5
            1 1 1
            1/4 1/4 1/4
            1/3 1/3 1/3
            2/3 2/3 2/3

            sage: rk1 = ['37a1','43a1','53a1', '91b1','91b2','91b3']
            sage: [EllipticCurve(la).modular_symbol(use_eclib=True)(0) for la in rk1]  # long time (1s on sage.math, 2011)
            [0, 0, 0, 0, 0, 0]
            sage: for la in rk1:  # long time (8s on sage.math, 2011)
            ...       E = EllipticCurve(la)
            ...       m = E.modular_symbol(use_eclib = True)
            ...       lp = E.padic_lseries(5)
            ...       for D in [5,17,12,8]:
            ...           ED = E.quadratic_twist(D)
            ...           md = sum([kronecker(D,u)*m(ZZ(u)/D) for u in range(D)])
            ...           etaa = lp._quotient_of_periods_to_twist(D)
            ...           assert ED.lseries().L_ratio()*ED.real_components()*etaa == md

        """
        E = self._E
        self._scaling = 1  # by now.
        self._failed_to_scale = False

        if self._sign == 1:
            at0 = self(0)
            # print 'modular symbol evaluates to ',at0,' at 0'
            if at0 != 0:
                l1 = self.__lalg__(1)
                if at0 != l1:
                    verbose('scale modular symbols by %s' % (l1 / at0))
                    self._scaling = l1 / at0
            else:
                # if [0] = 0, we can still hope to scale it correctly by considering twists of E
                Dlist = [
                    5, 8, 12, 13, 17, 21, 24, 28, 29, 33, 37, 40, 41, 44, 53,
                    56, 57, 60, 61, 65, 69, 73, 76, 77, 85, 88, 89, 92, 93, 97
                ]  # a list of positive fundamental discriminants
                j = 0
                at0 = 0
                # computes [0]+ for the twist of E by D until one value is non-zero
                while j < 30 and at0 == 0:
                    D = Dlist[j]
                    # the following line checks if the twist of the newform of E by D is a newform
                    # this is to avoid that we 'twist back'
                    if all(
                            valuation(E.conductor(), ell) <= valuation(D, ell)
                            for ell in prime_divisors(D)):
                        at0 = sum([
                            kronecker_symbol(D, u) * self(ZZ(u) / D)
                            for u in range(1, abs(D))
                        ])
                    j += 1
                if j == 30 and at0 == 0:  # curves like "121b1", "225a1", "225e1", "256a1", "256b1", "289a1", "361a1", "400a1", "400c1", "400h1", "441b1", "441c1", "441d1", "441f1 .. will arrive here
                    self._failed_to_scale = True
                    self.__scale_by_periods_only__()
                else:
                    l1 = self.__lalg__(D)
                    if at0 != l1:
                        verbose('scale modular symbols by %s found at D=%s ' %
                                (l1 / at0, D),
                                level=2)
                        self._scaling = l1 / at0

        else:  # that is when sign = -1
            Dlist = [
                -3, -4, -7, -8, -11, -15, -19, -20, -23, -24, -31, -35, -39,
                -40, -43, -47, -51, -52, -55, -56, -59, -67, -68, -71, -79,
                -83, -84, -87, -88, -91
            ]  # a list of negative fundamental discriminants
            j = 0
            at0 = 0
            while j < 30 and at0 == 0:
                # computes [0]+ for the twist of E by D until one value is non-zero
                D = Dlist[j]
                if all(
                        valuation(E.conductor(), ell) <= valuation(D, ell)
                        for ell in prime_divisors(D)):
                    at0 = -sum([
                        kronecker_symbol(D, u) * self(ZZ(u) / D)
                        for u in range(1, abs(D))
                    ])
                j += 1
            if j == 30 and at0 == 0:  # no more hope for a normalization
                # we do at least a scaling with the quotient of the periods
                self._failed_to_scale = True
                self.__scale_by_periods_only__()
            else:
                l1 = self.__lalg__(D)
                if at0 != l1:
                    verbose('scale modular symbols by %s' % (l1 / at0))
                    self._scaling = l1 / at0
Exemple #49
0
 def __repr__(self):
     r"""
     Represent self's Fourier expansion as a power series c(v) q1^v q2^(v'), where v runs through totally-positive elements in the dual of the ring of integers.
     """
     K = self.__base_field
     h = self.true_fourier_expansion()
     hprec = h.prec()
     d = self.scale()
     if h:
         D = K.discriminant()
         sqrtD = K(D).sqrt()
         if not D % 4:
             sqrtD /= 2
         s = ''
         sign = False
         for i, p in enumerate(h.list()):
             i = ZZ(i)
             for n in p.exponents():
                 c = p[n]
                 if c:
                     q2exp = (i - n / sqrtD) / (d + d)
                     q1exp = i / d - q2exp
                     coef = True
                     if sign:
                         if c > 0 and c != 1:
                             s += ' + ' + str(c)
                         elif c + 1 and c != 1:
                             s += ' - ' + str(-c)
                         elif c + 1:
                             s += ' + '
                             coef = False
                         elif c - 1:
                             s += ' - '
                             coef = False
                     else:
                         if abs(c) != 1 or not q1exp:
                             s += str(c)
                         else:
                             coef = False
                             if c == -1:
                                 s += '-'
                         sign = True
                     if q1exp:
                         if coef:
                             s += '*'
                         if q1exp != q2exp or q1exp not in ZZ:
                             s += 'q1^(%s)*q2^(%s)' % (q1exp, q2exp)
                         elif q1exp != 1:
                             s += 'q1^%s*q2^%s' % (q1exp, q2exp)
                         else:
                             s += 'q1*q2'
                     sign = True
         if hprec % d:
             self.__string = s + ' + O(q1, q2)^(%s)' % (hprec / d)
         else:
             self.__string = s + ' + O(q1, q2)^%s' % (hprec / d)
     else:
         if hprec % d:
             self.__string = 'O(q1, q2)^(%s)' % (hprec / d)
         else:
             self.__string = 'O(q1, q2)^%s' % (hprec / d)
     return self.__string
Exemple #50
0
    def __init__(self, E, sign, normalize="L_ratio"):
        r"""
        Modular symbols attached to `E` using ``eclib``.

        INPUT:

        - ``E`` - an elliptic curve
        - ``sign`` - an integer, -1 or 1
        - ``normalize`` - either 'L_ratio' (default) or 'none';
          For 'L_ratio', the modular symbol is correctly normalized
          by comparing it to the quotient of `L(E,1)` by the least
          positive period for the curve and some small twists.
          For 'none', the modular symbol is almost certainly
          not correctly normalized, i.e. all values will be a
          fixed scalar multiple of what they should be.

        EXAMPLES::

            sage: import sage.schemes.elliptic_curves.ell_modular_symbols
            sage: E=EllipticCurve('11a1')
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolECLIB(E,+1)
            sage: M
            Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
            sage: M(0)
            1/5
            sage: E=EllipticCurve('11a2')
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolECLIB(E,+1)
            sage: M(0)
            1

        This is a rank 1 case with vanishing positive twists.
        The modular symbol can not be adjusted::

            sage: E=EllipticCurve('121b1')
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolECLIB(E,+1)
            Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by -1, 2 or -2.
            sage: M(0)
            0
            sage: M(1/7)
            -2

            sage: M = EllipticCurve('121d1').modular_symbol(use_eclib=True)
            sage: M(0)
            2
            sage: M = EllipticCurve('121d1').modular_symbol(use_eclib=True,normalize='none')
            sage: M(0)
            8

            sage: E = EllipticCurve('15a1')
            sage: [C.modular_symbol(use_eclib=True,normalize='L_ratio')(0) for C in E.isogeny_class(use_tuple=False)]
            [1/4, 1/8, 1/4, 1/2, 1/8, 1/16, 1/2, 1]
            sage: [C.modular_symbol(use_eclib=True,normalize='none')(0) for C in E.isogeny_class(use_tuple=False)]
            [1/4, 1/4, 1/4, 1/4, 1/4, 1/4, 1/4, 1/4]

        Currently, the interface for negative modular symbols in eclib is not yet written::

            sage: E.modular_symbol(use_eclib=True,sign=-1)
            Traceback (most recent call last):
            ...
            NotImplementedError: Despite that eclib has now -1 modular symbols the interface to them is not yet written.

        TESTS (for trac 10236)::

            sage: E = EllipticCurve('11a1')
            sage: m = E.modular_symbol(use_eclib=True)
            sage: m(1/7)
            7/10
            sage: m(0)
            1/5
        """
        self._sign = ZZ(sign)
        if self._sign != sign:
            raise TypeError, 'sign must be an integer'
        if self._sign != -1 and self._sign != 1:
            raise TypeError, 'sign must -1 or 1'
        if self._sign == -1:
            raise NotImplementedError, "Despite that eclib has now -1 modular symbols the interface to them is not yet written."
        self._E = E
        self._use_eclib = True
        self._base_ring = QQ
        self._normalize = normalize
        self._modsym = ECModularSymbol(E)
        p = ZZ(2)
        while not E.is_good(p):
            p = p.next_prime()
        # this computes {0,oo} using the Hecke-operator at p
        self._atzero = sum([self._modsym(ZZ(a) / p)
                            for a in range(p)]) / E.Np(p)

        if normalize == "L_ratio":
            self._find_scaling_L_ratio()
        elif normalize == "none":
            self._scaling = ZZ(1)
        else:
            raise ValueError, "no normalization '%s' known for modular symbols using John Cremona's eclib" % normalize
def siegel_product(self, u):
    """
    Computes the infinite product of local densities of the quadratic
    form for the number `u`.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1])
        sage: Q.theta_series(11)
        1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 + O(q^11)

        sage: Q.siegel_product(1)
        8
        sage: Q.siegel_product(2)      ## This one is wrong -- expect 24, and the higher powers of 2 don't work... =(
        24
        sage: Q.siegel_product(3)
        32
        sage: Q.siegel_product(5)
        48
        sage: Q.siegel_product(6)
        96
        sage: Q.siegel_product(7)
        64
        sage: Q.siegel_product(9)
        104

        sage: Q.local_density(2,1)
        1
        sage: M = 4; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 1]) / M^3
        1
        sage: M = 16; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 1]) / M^3  # long time (41s on sage.math, 2011)
        1

        sage: Q.local_density(2,2)
        3/2
        sage: M = 4; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 2]) / M^3
        3/2
        sage: M = 16; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 2]) / M^3  # long time (41s on sage.math, 2011)
        3/2

    TESTS::

        sage: [1] + [Q.siegel_product(ZZ(a))  for a in range(1,11)] == Q.theta_series(11).list()
        True
    """
    ## Protect u (since it fails often if it's an just an int!)
    u = ZZ(u)

    n = self.dim()
    d = self.det(
    )  ## ??? Warning: This is a factor of 2^n larger than it should be!

    ## DIAGNOSTIC
    verbose("n = " + str(n))
    verbose("d = " + str(d))
    verbose("In siegel_product:  d = ", d, "\n")

    ## Product of "bad" places to omit
    S = 2 * d * u

    ## DIAGNOSTIC
    verbose("siegel_product Break 1. \n")
    verbose(" u = ", u, "\n")

    ## Make the odd generic factors
    if ((n % 2) == 1):
        m = (n - 1) / 2
        d1 = fundamental_discriminant(
            ((-1)**m) * 2 * d *
            u)  ## Replaced d by 2d here to compensate for the determinant
        f = abs(
            d1)  ## gaining an odd power of 2 by using the matrix of 2Q instead
        ## of the matrix of Q.
        ##  --> Old d1 = CoreDiscriminant((mpz_class(-1)^m) * d * u);

        ## Make the ratio of factorials factor: [(2m)! / m!] * prod_{i=1}^m (2*i-1)
        factor1 = 1
        for i in range(1, m + 1):
            factor1 *= 2 * i - 1
        for i in range(m + 1, 2 * m + 1):
            factor1 *= i

        genericfactor = factor1 * ((u / f) ** m) \
            * QQ(sqrt((2 ** n) *  f) / (u * d)) \
            * abs(QuadraticBernoulliNumber(m, d1) / bernoulli(2*m))

    ## DIAGNOSTIC
    verbose("siegel_product Break 2. \n")

    ## Make the even generic factor
    if ((n % 2) == 0):
        m = n / 2
        d1 = fundamental_discriminant(((-1)**m) * d)
        f = abs(d1)

        ## DIAGNOSTIC
        #cout << " mpz_class(-1)^m = " << (mpz_class(-1)^m) << " and d = " << d << endl;
        #cout << " f = " << f << " and d1 = " << d1 << endl;


        genericfactor = m / QQ(sqrt(f*d)) \
            * ((u/2) ** (m-1)) * (f ** m) \
            / abs(QuadraticBernoulliNumber(m, d1)) \
            * (2 ** m)                                               ## This last factor compensates for using the matrix of 2*Q

    ##return genericfactor

    ## Omit the generic factors in S and compute them separately
    omit = 1
    include = 1

    S_divisors = prime_divisors(S)

    ## DIAGNOSTIC
    #cout << "\n S is " << S << endl;
    #cout << " The Prime divisors of S are :";
    #PrintV(S_divisors);

    for p in S_divisors:
        Q_normal = self.local_normal_form(p)

        ## DIAGNOSTIC
        verbose(" p = " + str(p) + " and its Kronecker symbol (d1/p) = (" +
                str(d1) + "/" + str(p) + ") is " +
                str(kronecker_symbol(d1, p)) + "\n")

        omit *= 1 / (1 - (kronecker_symbol(d1, p) / (p**m)))

        ## DIAGNOSTIC
        verbose(" omit = " + str(omit) + "\n")
        verbose(" Q_normal is \n" + str(Q_normal) + "\n")
        verbose(" Q_normal = \n" + str(Q_normal))
        verbose(" p = " + str(p) + "\n")
        verbose(" u = " + str(u) + "\n")
        verbose(" include = " + str(include) + "\n")

        include *= Q_normal.local_density(p, u)

        ## DIAGNOSTIC
        #cout << " Including the p = " << p << " factor: " << local_density(Q_normal, p, u) << endl;

        ## DIAGNSOTIC
        verbose("    ---  Exiting loop \n")

    #// ****************  Important *******************
    #// Additional fix (only included for n=4) to deal
    #// with the power of 2 introduced at the real place
    #// by working with Q instead of 2*Q.  This needs to
    #// be done for all other n as well...
    #/*
    #if (n==4)
    #  genericfactor = 4 * genericfactor;
    #*/

    ## DIAGNSOTIC
    #cout << endl;
    #cout << " generic factor = " << genericfactor << endl;
    #cout << " omit = " << omit << endl;
    #cout << " include = " << include << endl;
    #cout << endl;

    ## DIAGNSOTIC
    #//  cout << "siegel_product Break 3. " << endl;

    ## Return the final factor (and divide by 2 if n=2)
    if (n == 2):
        return (genericfactor * omit * include / 2)
    else:
        return (genericfactor * omit * include)
    def padic_H_value(self, p, f, t, prec=None):
        """
        Return the `p`-adic trace of Frobenius, computed using the
        Gross-Koblitz formula.

        If left unspecified, `prec` is set to the minimum `p`-adic precision
        needed to recover the Euler factor.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``prec`` -- precision (optional)

        OUTPUT:

        an integer

        EXAMPLES:

        From Benasque report [Benasque2009]_, page 8::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.padic_H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.padic_H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.padic_H_value(7,i,-1) for i in range(1,3)]
            [0, -476]
            sage: [H.padic_H_value(11,i,-1) for i in range(1,3)]
            [0, -4972]

        From [Roberts2015]_ (but note conventions regarding `t`)::

            sage: H = Hyp(gamma_list=[-6,-1,4,3])
            sage: t = 189/125
            sage: H.padic_H_value(13,1,1/t)
            0

        Check issue from :trac:`28404`::

            sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2]))
            sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1]))
            sage: [H1.padic_H_value(5,1,i) for i in range(2,5)]
            [1, -4, -4]
            sage: [H2.padic_H_value(5,1,i) for i in range(2,5)]
            [-4, 1, -4]

        REFERENCES:

        - [MagmaHGM]_
        """
        alpha = self._alpha
        beta = self._beta
        t = QQ(t)
        if 0 in alpha:
            return self._swap.padic_H_value(p, f, ~t, prec)
        gamma = self.gamma_array()
        q = p**f

        # m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        m = array.array('i', [0] * (q - 1))
        for b in beta:
            u = b * (q - 1)
            if u.is_integer():
                m[u] += 1
        M = self.M_value()
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2

        if prec is None:
            prec = (self.weight() * f) // 2 + ceil(log(self.degree(), p)) + 1
        # For some reason, working in Qp instead of Zp is much faster;
        # it appears to avoid some costly conversions.
        p_ring = Qp(p, prec=prec)
        teich = p_ring.teichmuller(M / t)

        gauss_table = [None] * (q - 1)
        for r in range(q - 1):
            if gauss_table[r] is None:
                gauss_table[r] = padic_gauss_sum(r,
                                                 p,
                                                 f,
                                                 prec,
                                                 factored=True,
                                                 algorithm='sage',
                                                 parent=p_ring)
                r1 = (r * p) % (q - 1)
                while r1 != r:
                    gauss_table[r1] = gauss_table[r]
                    r1 = (r1 * p) % (q - 1)

        sigma = p_ring.zero()
        u1 = p_ring.one()
        for r in range(q - 1):
            i = int(0)
            u = u1
            u1 *= teich
            for v, gv in gamma.items():
                r1 = (v * r) % (q - 1)
                i += gauss_table[r1][0] * gv
                u *= gauss_table[r1][1]**gv
            sigma += (-p)**(i // (p - 1)) * u << (f * (D + m[0] - m[r]))
        resu = ZZ(-1)**m[0] / (1 - q) * sigma
        return IntegerModRing(p**prec)(resu).lift_centered()
Exemple #53
0
def _compute_sw_spherical_harm(s, l, m, theta, phi, condon_shortley=True,
                               numerical=None):
    r"""
    Compute the spin-weighted spherical harmonic of spin weight ``s`` and
    indices ``(l,m)`` as a callable symbolic expression in (theta,phi)

    INPUT:

    - ``s`` -- integer; the spin weight
    - ``l`` -- non-negative integer; the harmonic degree
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number
    - ``theta`` -- colatitude angle
    - ``phi`` -- azimuthal angle
    - ``condon_shortley`` -- (default: ``True``) determines whether the
      Condon-Shortley phase of `(-1)^m` is taken into account (see below)
    - ``numerical`` -- (default: ``None``) determines whether a symbolic or
      a numerical computation of a given type is performed; allowed values are

      - ``None``: a symbolic computation is performed
      - ``RDF``: Sage's machine double precision floating-point numbers
        (``RealDoubleField``)
      - ``RealField(n)``, where ``n`` is a number of bits: Sage's
        floating-point numbers with an arbitrary precision; note that ``RR`` is
        a shortcut for ``RealField(53)``.
      - ``float``: Python's floating-point numbers


    OUTPUT:

    - `{}_s Y_l^m(\theta,\phi)` either

      - as a symbolic expression if ``numerical`` is ``None``
      - or a pair of floating-point numbers, each of them being of the type
        corresponding to ``numerical`` and representing respectively the
        real and imaginary parts of `{}_s Y_l^m(\theta,\phi)`

    ALGORITHM:

    The spin-weighted spherical harmonic is evaluated according to Eq. (3.1)
    of J. N. Golberg et al., J. Math. Phys. **8**, 2155 (1967)
    [:doi:`10.1063/1.1705135`], with an extra `(-1)^m` factor (the so-called
    *Condon-Shortley phase*) if ``condon_shortley`` is ``True``, the actual
    formula being then the one given in
    :wikipedia:`Spin-weighted_spherical_harmonics#Calculating`

    TESTS::

        sage: from kerrgeodesic_gw.spin_weighted_spherical_harm import _compute_sw_spherical_harm
        sage: theta, phi = var("theta phi")
        sage: _compute_sw_spherical_harm(-2, 2, 1, theta, phi)
        1/4*(sqrt(5)*cos(theta) + sqrt(5))*e^(I*phi)*sin(theta)/sqrt(pi)

    """
    if abs(s)>l:
        return ZZ(0)
    if abs(theta) < 1.e-6:     # TODO: fix the treatment of small theta values
        if theta < 0:          #       possibly with exact formula for theta=0
            theta = -1.e-6     #
        else:                  #
            theta = 1.e-6      #
    cott2 = cos(theta/2)/sin(theta/2)
    res = 0
    for r in range(l-s+1):
        res += (-1)**(l-r-s) * (binomial(l-s, r) * binomial(l+s, r+s-m)
                                * cott2**(2*r+s-m))
    res *= sin(theta/2)**(2*l)
    ff = factorial(l+m)*factorial(l-m)*(2*l+1) / (factorial(l+s)*factorial(l-s))
    if numerical:
        pre = sqrt(numerical(ff)/numerical(pi))/2
    else:
        pre = sqrt(ff)/(2*sqrt(pi))
    res *= pre
    if condon_shortley:
        res *= (-1)**m
    if numerical:
        return (numerical(res*cos(m*phi)), numerical(res*sin(m*phi)))
    # Symbolic case:
    res = res.simplify_full()
    res = res.reduce_trig()    # get rid of cos(theta/2) and sin(theta/2)
    res = res.simplify_trig()  # further trigonometric simplifications
    res *= exp(I*m*phi)
    return res
        def permutahedron(self, point=None, base_ring=None):
            r"""
            Return the permutahedron of ``self``,

            This is the convex hull of the point ``point`` in the weight
            basis under the action of ``self`` on the underlying vector
            space `V`.

            .. SEEALSO::

                :meth:`~sage.combinat.root_system.reflection_group_real.permutahedron`

            INPUT:

            - ``point`` -- optional, a point given by its coordinates in
              the weight basis (default is `(1, 1, 1, \ldots)`)
            - ``base_ring`` -- optional, the base ring of the polytope

            .. NOTE::

                The result is expressed in the root basis coordinates.

            .. NOTE::

                If function is too slow, switching the base ring to
                :class:`RDF` will almost certainly speed things up.

            EXAMPLES::

                sage: W = CoxeterGroup(['H',3], base_ring=RDF)
                sage: W.permutahedron()
                A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 120 vertices

                sage: W = CoxeterGroup(['I',7])
                sage: W.permutahedron()
                A 2-dimensional polyhedron in AA^2 defined as the convex hull of 14 vertices
                sage: W.permutahedron(base_ring=RDF)
                A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 14 vertices

                sage: W = ReflectionGroup(['A',3])                          # optional - gap3
                sage: W.permutahedron()                                     # optional - gap3
                A 3-dimensional polyhedron in QQ^3 defined as the convex hull
                of 24 vertices

                sage: W = ReflectionGroup(['A',3],['B',2])                  # optional - gap3
                sage: W.permutahedron()                                     # optional - gap3
                A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 192 vertices

            TESTS::

                sage: W = ReflectionGroup(['A',3])                          # optional - gap3
                sage: W.permutahedron([3,5,8])                              # optional - gap3
                A 3-dimensional polyhedron in QQ^3 defined as the convex hull
                of 24 vertices


            .. PLOT::
                :width: 300 px

                W = CoxeterGroup(['I',7])
                p = W.permutahedron()
                sphinx_plot(p)

            """
            n = self.one().canonical_matrix().rank()
            weights = self.fundamental_weights()
            if point is None:
                point = [ZZ.one()] * n
            v = sum(point[i-1] * weights[i] for i in weights.keys())
            from sage.geometry.polyhedron.constructor import Polyhedron
            vertices = [v*w for w in self]
            if base_ring is None and v.base_ring() in [UniversalCyclotomicField(), QQbar]:
                vertices = [v.change_ring(AA) for v in vertices]
                base_ring = AA
            return Polyhedron(vertices=vertices, base_ring=base_ring)
Exemple #55
0
    def __init__(self, E, sign, normalize="L_ratio"):
        """
        Modular symbols attached to `E` using ``sage``.

        INPUT:

        - ``E`` -- an elliptic curve
        - ``sign`` -- an integer, -1 or 1
        - ``normalize`` -- either 'L_ratio' (default), 'period', or 'none';
          For 'L_ratio', the modular symbol is correctly normalized
          by comparing it to the quotient of `L(E,1)` by the least
          positive period for the curve and some small twists.
          The normalization 'period' uses the integral_period_map
          for modular symbols and is known to be equal to the above
          normalization up to the sign and a possible power of 2.
          For 'none', the modular symbol is almost certainly
          not correctly normalized, i.e. all values will be a
          fixed scalar multiple of what they should be.  But
          the initial computation of the modular symbol is
          much faster, though evaluation of
          it after computing it won't be any faster.

        EXAMPLES::

            sage: E=EllipticCurve('11a1')
            sage: import sage.schemes.elliptic_curves.ell_modular_symbols
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1)
            sage: M
            Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
            sage: M(0)
            1/5
            sage: E=EllipticCurve('11a2')
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1)
            sage: M(0)
            1
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,-1)
            sage: M(1/3)
            1

        This is a rank 1 case with vanishing positive twists.
        The modular symbol is adjusted by -2::

            sage: E=EllipticCurve('121b1')
            sage: M=sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,-1,normalize='L_ratio')
            sage: M(1/3)
            2
            sage: M._scaling
            -2

            sage: M = EllipticCurve('121d1').modular_symbol(use_eclib=False)
            sage: M(0)
            2
            sage: M = EllipticCurve('121d1').modular_symbol(use_eclib=False,normalize='none')
            sage: M(0)
            1

            sage: E = EllipticCurve('15a1')
            sage: [C.modular_symbol(use_eclib=False, normalize='L_ratio')(0) for C in E.isogeny_class(use_tuple=False)]
            [1/4, 1/8, 1/4, 1/2, 1/8, 1/16, 1/2, 1]
            sage: [C.modular_symbol(use_eclib=False, normalize='period')(0) for C in E.isogeny_class(use_tuple=False)]
            [1/8, 1/16, 1/8, 1/4, 1/16, 1/32, 1/4, 1/2]
            sage: [C.modular_symbol(use_eclib=False, normalize='none')(0) for C in E.isogeny_class(use_tuple=False)]
            [1, 1, 1, 1, 1, 1, 1, 1]

        """
        self._sign = ZZ(sign)
        if self._sign != sign:
            raise TypeError, 'sign must be an integer'
        if self._sign != -1 and self._sign != 1:
            raise TypeError, 'sign must -1 or 1'
        self._E = E
        self._use_eclib = False
        self._normalize = normalize
        self._modsym = E.modular_symbol_space(sign=self._sign)
        self._base_ring = self._modsym.base_ring()
        self._ambient_modsym = self._modsym.ambient_module()

        if normalize == "L_ratio":
            self._e = self._modsym.dual_eigenvector()
            self._find_scaling_L_ratio()
            if self._failed_to_scale:
                self._find_scaling_period()  # will reset _e and _scaling
            else:
                self._e *= self._scaling
        elif normalize == "period":
            self._find_scaling_period()  # this will set _e and _scaling
        elif normalize == "none":
            self._scaling = 1
            self._e = self._modsym.dual_eigenvector()
        else:
            raise ValueError, "no normalization %s known for modular symbols" % normalize
Exemple #56
0
def shift_factor(p, ram=ZZ.one(), q=1):
    """
    Returns the roots of p in an appropriate extension of the base ring, sorted according to
    shift equivalence classes.

    INPUT:

    - ``p`` -- a univariate polynomial over QQ or a number field
    - ``ram`` (optional) -- positive integer
    - ``q`` (optional) -- if set to a quantity different from 1 or 0, the factorization will be
      made according to the q-shift instead of the ordinary shift. The value must not be a root
      of unity. 

    OUTPUT:

    A list of pairs (q, e) where

    - q is an irreducible factor of p
    - e is a tuple of pairs (a, b) of nonnegative integers 
    - p = c*prod( sigma^(a/ram)(q)^b for (q, e) in output list for (a, b) in e ) for some nonzero constant c
      (in the q-case, a possible power of x is also omitted)
    - e[0][0] == 0, and e[i][0] < e[i+1][0] for all i 
    - any two distinct q have no roots at integer distance.

    The constant domain must have characteristic zero. 

    In the q-case, ramification greater than 1 requires that q^(1/ram) exists in the constant domain. 
    
    Note that rootof(q) is the largest root of every class. The other roots are given by rootof(q) - e[i][0]/ram.

    EXAMPLES::

        sage: from ore_algebra.tools import shift_factor
        sage: x = ZZ['x'].gen()
        sage: shift_factor((x-2)*(x-4)*(x-8)*(2*x+3)*(2*x+15))
        [[x - 8, [(0, 1), (4, 1), (6, 1)]], [2*x + 3, [(0, 1), (6, 1)]]]
        sage: shift_factor((x-2)*(x-4)*(x-8)*(2*x+3)*(2*x+15), q=2)
        [[-1/8*x + 1, [(0, 1), (1, 1), (2, 1)]], [2/3*x + 1, [(0, 1)]], [2/15*x + 1, [(0, 1)]]]
    """

    classes = []
    x = p.parent().gen()

    qq = q
    assert (x.parent().characteristic() == 0)
    if qq == 1:

        def sigma(u, n=1):
            return u(x + n)

        def candidate(u, v):
            d = u.degree()
            return ram * (u[d] * v[d - 1] - u[d - 1] * v[d]) / (u[d] * v[d] *
                                                                d)
    else:

        def sigma(u, n=1):
            return u(x * qq**n)

        def candidate(u, v):
            d = u.degree()
            try:
                return -q_log(qq, (u[d] / v[d])**ram) / d
            except:
                return None

    for (q, b) in make_factor_iterator(p.parent())(p):

        if q.degree() < 1:
            continue
        if qq != 1:
            if q[0].is_zero():
                continue
            else:
                q /= q[0]

        # have we already seen a member of the shift equivalence class of q?
        new = True
        for i in xrange(len(classes)):
            u = classes[i][0]
            if u.degree() != q.degree():
                continue
            a = candidate(q, u)
            if a not in ZZ or sigma(q, a / ram) != u:
                continue
            # yes, we have: q(x+a) == u(x); u(x-a) == q(x)
            # register it and stop searching
            a = ZZ(a)
            new = False
            if a < 0:
                classes[i][1].append((-a, b))
            elif a > 0:
                classes[i][0] = q
                classes[i][1] = [(n + a, m) for (n, m) in classes[i][1]]
                classes[i][1].append((0, b))
            break

        # no, we haven't. this is the first.
        if new:
            classes.append([q, [(0, b)]])

    for c in classes:
        c[1].sort(key=lambda e: e[0])

    return classes
Exemple #57
0
    def __init__(self, number_field, proof=True, S=None):
        """
        Create a unit group of a number field.

        INPUT:

        - ``number_field`` - a number field
        - ``proof`` - boolean (default True): proof flag
        - ``S`` - tuple of prime ideals, or an ideal, or a single
          ideal or element from which an ideal can be constructed, in
          which case the support is used.  If None, the global unit
          group is constructed; otherwise, the S-unit group is
          constructed.

        The proof flag is passed to pari via the ``pari_bnf()`` function
        which computes the unit group.  See the documentation for the
        number_field module.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: K.<a> = NumberField(x^2-38)
            sage: UK = K.unit_group(); UK
            Unit group with structure C2 x Z of Number Field in a with defining polynomial x^2 - 38
            sage: UK.gens()
            (u0, u1)
            sage: UK.gens_values()
            [-1, -6*a + 37]

            sage: K.<a> = QuadraticField(-3)
            sage: UK = K.unit_group(); UK
            Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
            sage: UK.gens()
            (u,)
            sage: UK.gens_values()
            [-1/2*a + 1/2]

            sage: K.<z> = CyclotomicField(13)
            sage: UK = K.unit_group(); UK
            Unit group with structure C26 x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12
            sage: UK.gens()
            (u0, u1, u2, u3, u4, u5)
            sage: UK.gens_values() # random
            [-z^11, z^5 + z^3, z^6 + z^5, z^9 + z^7 + z^5, z^9 + z^5 + z^4 + 1, z^5 + z]
            sage: SUK = UnitGroup(K,S=2); SUK
            S-unit group with structure C26 x Z x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12 with S = (Fractional ideal (2),)

        TESTS:

        Number fields defined by non-monic and non-integral
        polynomials are supported (:trac:`252`);
        the representation depends on the PARI version::

            sage: K.<a> = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123)
            sage: K.unit_group()
            Unit group with structure C2 x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123
            sage: UnitGroup(K, S=tuple(K.primes_above(7)))
            S-unit group with structure C2 x Z x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 with S = (Fractional ideal (...),)
            sage: K.primes_above(7)[0] in (7/225*a^2 - 7/75*a - 42/25, 28/225*a^2 + 77/75*a - 133/25)
            True

        Conversion from unit group to a number field and back
        gives the right results (:trac:`25874`)::

            sage: K = QuadraticField(-3).composite_fields(QuadraticField(2))[0]
            sage: U = K.unit_group()
            sage: tuple(U(K(u)) for u in U.gens()) == U.gens()
            True
            sage: US = K.S_unit_group(3)
            sage: tuple(US(K(u)) for u in US.gens()) == US.gens()
            True

        """
        proof = get_flag(proof, "number_field")
        K = number_field
        pK = K.pari_bnf(proof)
        self.__number_field = K
        self.__pari_number_field = pK

        # process the parameter S:
        if not S:
            S = self.__S = ()
        else:
            if isinstance(S, list):
                S = tuple(S)
            if not isinstance(S, tuple):
                try:
                    S = tuple(K.ideal(S).prime_factors())
                except (NameError, TypeError, ValueError):
                    raise ValueError("Cannot make a set of primes from %s" %
                                     (S, ))
            else:
                try:
                    S = tuple(K.ideal(P) for P in S)
                except (NameError, TypeError, ValueError):
                    raise ValueError("Cannot make a set of primes from %s" %
                                     (S, ))
                if not all(P.is_prime() for P in S):
                    raise ValueError(
                        "Not all elements of %s are prime ideals" % (S, ))
            self.__S = S
            self.__pS = pS = [P.pari_prime() for P in S]

        # compute the fundamental units via pari:
        fu = [K(u, check=False) for u in pK.bnf_get_fu()]
        self.__nfu = len(fu)

        # compute the additional S-unit generators:
        if S:
            self.__S_unit_data = pK.bnfunits(pS)
        else:
            self.__S_unit_data = pK.bnfunits()
        # TODO: converting the factored matrix representation of bnfunits into polynomial
        # form is a *big* waste of time
        su_fu_tu = [
            pK.nfbasistoalg(pK.nffactorback(z)) for z in self.__S_unit_data[0]
        ]

        self.__nfu = len(pK.bnf_get_fu())  # number of fundamental units
        self.__nsu = len(su_fu_tu) - self.__nfu - 1  # number of S-units
        self.__ntu = pK.bnf_get_tu()[0]  # order of torsion
        self.__rank = self.__nfu + self.__nsu

        # Move the torsion unit first, then fundamental units then S-units
        gens = [K(u, check=False) for u in su_fu_tu]
        gens = [gens[-1]] + gens[self.__nsu:-1] + gens[:self.__nsu]

        # Construct the abstract group:
        gens_orders = tuple([ZZ(self.__ntu)] + [ZZ(0)] * (self.__rank))
        AbelianGroupWithValues_class.__init__(self, gens_orders, 'u', gens,
                                              number_field)
Exemple #58
0
    def zeta(self, n=2, all=False):
        """
        Return one, or a list of all, primitive n-th root of unity in this unit group.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: K.<z> = NumberField(x^2 + 3)
            sage: U = UnitGroup(K)
            sage: U.zeta(1)
            1
            sage: U.zeta(2)
            -1
            sage: U.zeta(2, all=True)
            [-1]
            sage: U.zeta(3)
            -1/2*z - 1/2
            sage: U.zeta(3, all=True)
            [-1/2*z - 1/2, 1/2*z - 1/2]
            sage: U.zeta(4)
            Traceback (most recent call last):
            ...
            ValueError: n (=4) does not divide order of generator

            sage: r.<x> = QQ[]
            sage: K.<b> = NumberField(x^2+1)
            sage: U = UnitGroup(K)
            sage: U.zeta(4)
            b
            sage: U.zeta(4,all=True)
            [b, -b]
            sage: U.zeta(3)
            Traceback (most recent call last):
            ...
            ValueError: n (=3) does not divide order of generator
            sage: U.zeta(3,all=True)
            []

        """
        N = self.__ntu
        K = self.number_field()
        n = ZZ(n)
        if n <= 0:
            raise ValueError("n (=%s) must be positive" % n)
        if n == 1:
            if all:
                return [K(1)]
            else:
                return K(1)
        elif n == 2:
            if all:
                return [K(-1)]
            else:
                return K(-1)
        if n.divides(N):
            z = self.torsion_generator().value()**(N // n)
            if all:
                return [z**i for i in n.coprime_integers(n)]
            else:
                return z
        else:
            if all:
                return []
            else:
                raise ValueError("n (=%s) does not divide order of generator" %
                                 n)
def normalize_args_vectorspace(*args, **kwds):
    """
    Normalize the arguments that relate to a vector space.

    INPUT:

    Something that defines an affine space. For example

    * An affine space itself:

      - ``A`` -- affine space

    * A vector space:

      - ``V`` -- a vector space

    * Degree and base ring:

      - ``degree`` -- integer. The degree of the affine group, that
        is, the dimension of the affine space the group is acting on.

      - ``ring`` -- a ring or an integer. The base ring of the affine
        space. If an integer is given, it must be a prime power and
        the corresponding finite field is constructed.

      - ``var='a'`` -- optional keyword argument to specify the finite
        field generator name in the case where ``ring`` is a prime
        power.

    OUTPUT:

    A pair ``(degree, ring)``.

    TESTS::

        sage: from sage.groups.matrix_gps.named_group import normalize_args_vectorspace
        sage: A = AffineSpace(2, GF(4,'a'));  A
        Affine Space of dimension 2 over Finite Field in a of size 2^2
        sage: normalize_args_vectorspace(A)
        (2, Finite Field in a of size 2^2)

        sage: normalize_args_vectorspace(2,4)   # shorthand
        (2, Finite Field in a of size 2^2)

        sage: V = ZZ^3;  V
        Ambient free module of rank 3 over the principal ideal domain Integer Ring
        sage: normalize_args_vectorspace(V)
        (3, Integer Ring)

        sage: normalize_args_vectorspace(2, QQ)
        (2, Rational Field)
    """
    from sage.rings.integer_ring import ZZ
    if len(args) == 1:
        V = args[0]
        try:
            degree = V.dimension_relative()
        except AttributeError:
            degree = V.dimension()
        ring = V.base_ring()
    if len(args) == 2:
        degree, ring = args
        try:
            ring = ZZ(ring)
            from sage.rings.finite_rings.finite_field_constructor import FiniteField
            var = kwds.get('var', 'a')
            ring = FiniteField(ring, var)
        except (ValueError, TypeError):
            pass
    return (ZZ(degree), ring)
Exemple #60
0
    def __call__(self, key):
        r"""
        Return all round keys in a list.

        INPUT:

        - ``key`` -- integer or bit list-like; the 64-bit key

        OUTPUT:

        - A list containing the round keys. If ``key`` is an integer the
          elements of the output list will be too. If ``key`` is list-like the
          element of the output list will be  bit vectors.

        EXAMPLES:

        This implementation is using bit vectors for all internal
        representations. So you can invoke the key schedule with a bit
        vector::

            sage: from sage.crypto.block_cipher.des import DES_KS
            sage: K = vector(GF(2),[0,0,0,1,0,0,1,1,0,0,1,1,0,1,0,0,0,1,0,1,0,
            ....:                   1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,
            ....:                   1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1])
            sage: ks = DES_KS(16, K)
            sage: [k for k in ks]
            [(0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1,
              1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
              0, 0, 1, 0),
             (0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0,
              0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0,
              0, 1, 0, 1),
             ...
             (1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0,
              1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1,
              0, 1, 0, 1)]

        But of course you can invoke it with hex representation as well::

            sage: K = 0x133457799bbcdff1
            sage: ks = DES_KS(16, K)
            sage: [k.hex() for k in ks]
            ['1b02effc7072',
             '79aed9dbc9e5',
             ...
             'cb3d8b0e17f5']

        .. NOTE::

            If you want to use a DES_KS object as an iterable you have to
            pass a ``masterKey`` value on initialisation. Otherwise you can
            omit ``masterKey`` and pass a key when you call the object.
        """
        if isinstance(key, (list, tuple, Vector_mod2_dense)):
            inputType = 'vector'
        elif isinstance(key, (Integer, int)):
            inputType = 'integer'
        key = convert_to_vector(key, self._keySize)
        roundKeys = []
        C, D = self._pc1(key)
        for i in range(16):
            C, D = self._left_shift(C, i), self._left_shift(D, i)
            roundKeys.append(self._pc2(list(C) + list(D)))
        return roundKeys if inputType == 'vector' else [
            ZZ(list(k)[::-1], 2) for k in roundKeys
        ]