Esempio n. 1
0
def test_tensprod_121_chi():
    C121=[1,2,-1,2,1,-2,2,0,-2,2,0,-2,-4,4,-1,-4,2,-4,0,2,-2,0,\
    -1,0,-4,-8,5,4,0,-2,7,-8,0,4,2,-4,3,0,4,0,8,-4,6,0,-2,-2,\
    8,4,-3,-8,-2,-8,-6,10,0,0,0,0,5,-2,-12,14,-4,-8,-4,0,-7,4,\
    1,4,-3,0,-4,6,4,0,0,8,10,-4,1,16,6,-4,2,12,0,0,15,-4,-8,\
    -2,-7,16,0,8,-7,-6,0,-8,-2,-4,-16,0,-2,-12,-18,10,-10,0,-3,\
    -8,9,0,-1,0,8,10,4,0,0,-24,-8,14,-9,-8,-8,0,-6,-8,18,0,0,\
    -14,5,0,-7,2,-10,4,-8,-6,0,8,0,-8,3,6,10,8,-2,0,-4,0,7,8,\
    -7,20,6,-8,-2,2,4,16,0,12,12,0,3,4,0,12,6,0,-8,0,-5,30,\
    -15,-4,7,-16,12,0,3,-14,0,16,10,0,17,8,-4,-14,4,-6,2,0,0,0]
    chi=[1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,\
    1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,\
    -1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,\
    1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,\
    1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,\
    1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,\
    -1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,\
    -1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,\
    -1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1]
    ANS=[1,-2,-1,2,1,2,-2,0,-2,-2,1,-2,4,4,-1,-4,-2,4,0,2,2,-2,\
    -1,0,-4,-8,5,-4,0,2,7,8,-1,4,-2,-4,3,0,-4,0,-8,-4,-6,2,-2,\
    2,8,4,-3,8,2,8,-6,-10,1,0,0,0,5,-2,12,-14,4,-8,4,2,-7,-4,\
    1,4,-3,0,4,-6,4,0,-2,8,-10,-4,1,16,-6,4,-2,12,0,0,15,4,-8,\
    -2,-7,-16,0,-8,-7,6,-2,-8,2,-4,-16,0,2,12,18,10,10,-2,-3,8,\
    9,0,-1,0,-8,-10,4,0,1,-24,8,14,-9,-8,8,0,6,-8,-18,-2,0,14,\
    5,0,-7,-2,10,-4,-8,6,4,8,0,-8,3,6,-10,-8,2,0,4,4,7,-8,-7,\
    20,6,8,2,-2,4,-16,-1,12,-12,0,3,4,0,-12,-6,0,8,-4,-5,-30,\
    -15,-4,7,16,-12,0,3,14,-2,16,-10,0,17,8,4,14,-4,-6,-2,4,0,0]
    R = PowerSeriesRing(ZZ, "T")
    T = R.gens()[0]
    assert ANS==tensor_get_an_deg1(C121,chi,[[11,1-T]])
    assert ANS==tensor_get_an(C121,chi,2,1,[[11,1-T,1-T]])
    assert get_euler_factor(ANS,2)==(1+2*T+2*T**2+O(T**8))
    assert get_euler_factor(ANS,3)==(1+T+3*T**2+O(T**5))
    assert get_euler_factor(ANS,5)==(1-T+5*T**2+O(T**4))
Esempio n. 2
0
def test_tensprod_11a_17a():
    C11=[1,-2,-1,2,1,2,-2,0,-2,-2,1,-2,4,4,-1,-4,-2,4,0,2,2,-2,\
    -1,0,-4,-8,5,-4,0,2,7,8,-1,4,-2,-4,3,0,-4,0,-8,-4,-6,2,-2,\
    2,8,4,-3,8,2,8,-6,-10,1,0,0,0,5,-2,12,-14,4,-8,4,2,-7,-4,\
    1,4,-3,0,4,-6,4,0,-2,8,-10,-4,1,16,-6,4,-2,12,0,0,15,4,-8,\
    -2,-7,-16,0,-8,-7,6,-2,-8,2,-4,-16,0,2,12,18,10,10,-2,-3,8,\
    9,0,-1,0,-8,-10,4,0,1,-24,8,14,-9,-8,8,0,6,-8,-18,-2,0,14,\
    5,0,-7,-2,10,-4,-8,6,4,8,0,-8,3,6,-10,-8,2,0,4,4,7,-8,-7,\
    20,6,8,2,-2,4,-16,-1,12,-12,0,3,4,0,-12,-6,0,8,-4,-5,-30,\
    -15,-4,7,16,-12,0,3,14,-2,16,-10,0,17,8,4,14,-4,-6,-2,4,0,0]
    C17=[1,-1,0,-1,-2,0,4,3,-3,2,0,0,-2,-4,0,-1,1,3,-4,2,0,0,4,\
    0,-1,2,0,-4,6,0,4,-5,0,-1,-8,3,-2,4,0,-6,-6,0,4,0,6,-4,0,\
    0,9,1,0,2,6,0,0,12,0,-6,-12,0,-10,-4,-12,7,4,0,4,-1,0,8,\
    -4,-9,-6,2,0,4,0,0,12,2,9,6,-4,0,-2,-4,0,0,10,-6,-8,-4,0,\
    0,8,0,2,-9,0,1,-10,0,8,-6,0,-6,8,0,6,0,0,-4,-14,0,-8,-6,\
    6,12,4,0,-11,10,0,-4,12,12,8,3,0,-4,16,0,-16,-4,0,3,-6,0,\
    -8,8,0,4,0,3,-12,6,0,2,-10,0,-16,-12,-3,0,-8,0,-2,-12,0,10,\
    16,-9,24,6,0,4,-4,0,-9,2,12,-4,22,0,-4,0,0,-10,12,-6,-2,8,\
    0,12,4,0,0,0,0,-8,-16,0,2,-2,0,-9,-18,0,-20,-3]
    ANS=[1,2,0,2,-2,0,-8,8,15,-4,0,0,-8,-16,0,12,-2,30,0,-4,0,0,\
    -4,0,29,-16,0,-16,0,0,28,-8,0,-4,16,30,-6,0,0,-16,48,0,-24,\
    0,-30,-8,0,0,22,58,0,-16,-36,0,0,-64,0,0,-60,0,-120,56,-120,\
    -8,16,0,-28,-4,0,32,12,120,-24,-12,0,0,0,0,-120,-24,144,96,\
    24,0,4,-48,0,0,150,-60,64,-8,0,0,0,0,-14,44,0,58,-20,0,-128,\
    -64,0,-72,144,0,60,0,0,-96,-126,0,8,0,-120,-120,16,0,-11,-240,\
    0,56,-158,-240,64,-32,0,32,-288,0,0,-56,0,-16,42,0,-80,32,0,\
    24,0,180,0,-48,0,-12,100,0,-32,0,-30,0,-56,0,14,-240,0,16,32,\
    288,96,96,0,48,48,0,142,8,0,-48,-132,0,-232,0,0,300,-180,-60,\
    -14,128,0,-32,12,0,0,0,0,0,-272,0,8,-28,0,44,36,0,0,232]
    R = PowerSeriesRing(ZZ, "T")
    T = R.gens()[0]
    B11=[11,1-T,1+11*T**2]
    B17=[17,1+2*T+17*T**2,1-T]
    assert ANS==tensor_get_an_no_deg1(C11,C17,2,2,[B11,B17])
Esempio n. 3
0
    def series(self, prec=5):
        r"""
        Return the ``prec``-th approximation to the `p`-adic `L`-series
        associated to self, as a power series in `T` (corresponding to
        `\gamma-1` with `\gamma` the chosen generator of `1+p\ZZ_p`).

        INPUT:

        - ``prec`` -- (default 5) is the precision of the power series

        EXAMPLES::

            sage: E = EllipticCurve('14a2')
            sage: p = 3
            sage: prec = 6
            sage: L = E.padic_lseries(p,implementation="pollackstevens",precision=prec) # long time
            sage: L.series(4)          # long time
            2*3 + 3^4 + 3^5 + O(3^6) + (2*3 + 3^2 + O(3^4))*T + (2*3 + O(3^2))*T^2 + (3 + O(3^2))*T^3 + O(T^4)

            sage: E = EllipticCurve("15a3")
            sage: L = E.padic_lseries(5,implementation="pollackstevens",precision=15)  # long time
            sage: L.series(3)            # long time
            O(5^15) + (2 + 4*5^2 + 3*5^3 + 5^5 + 2*5^6 + 3*5^7 + 3*5^8 + 2*5^9 + 2*5^10 + 3*5^11 + 5^12 + O(5^13))*T + (4*5 + 4*5^3 + 3*5^4 + 4*5^5 + 3*5^6 + 2*5^7 + 5^8 + 4*5^9 + 3*5^10 + O(5^11))*T^2 + O(T^3)

            sage: E = EllipticCurve("79a1")
            sage: L = E.padic_lseries(2,implementation="pollackstevens",precision=10) # not tested
            sage: L.series(4)  # not tested
            O(2^9) + (2^3 + O(2^4))*T + O(2^0)*T^2 + (O(2^-3))*T^3 + O(T^4)
        """
        p = self.prime()
        M = self.symbol().precision_relative()
        K = pAdicField(p, M)
        R = PowerSeriesRing(K, names='T')
        T = R.gens()[0]
        return R([self[i] for i in range(prec)]).add_bigoh(prec)
Esempio n. 4
0
    def series(self, n, prec):
        r"""
        Returns the `n`-th approximation to the `p`-adic `L`-series
        associated to self, as a power series in `T` (corresponding to
        `\gamma-1` with `\gamma= 1 + p` as a generator of `1+p\ZZ_p`).

        EXAMPLES::
        
            sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve
            sage: E = EllipticCurve('57a')
            sage: p = 5
            sage: prec = 4
            sage: phi = ps_modsym_from_elliptic_curve(E)
            sage: phi_stabilized = phi.p_stabilize(p,M = prec+3)
            sage: Phi = phi_stabilized.lift(p,prec,None,algorithm='stevens',eigensymbol=True)
            sage: L = pAdicLseries(Phi)
            sage: L.series(3,4)
            O(5^3) + (3*5 + 5^2 + O(5^3))*T + (5 + O(5^2))*T^2
            
            sage: L1 = E.padic_lseries(5)
            sage: L1.series(4)
            O(5^6) + (3*5 + 5^2 + O(5^3))*T + (5 + 4*5^2 + O(5^3))*T^2 + (4*5^2 + O(5^3))*T^3 + (2*5 + 4*5^2 + O(5^3))*T^4 + O(T^5)
        
        """
        p = self.prime()
        M = self.symb().precision_absolute()
        K = pAdicField(p, M)
        R = PowerSeriesRing(K, names = 'T')
        T = R.gens()[0]
        R.set_default_prec(prec)
        return sum(self[i] * T**i for i in range(n))
Esempio n. 5
0
    def series(self, prec=5):
        r"""
        Return the ``prec``-th approximation to the `p`-adic `L`-series
        associated to self, as a power series in `T` (corresponding to
        `\gamma-1` with `\gamma` the chosen generator of `1+p\ZZ_p`).

        INPUT:

        - ``prec`` -- (default 5) is the precision of the power series

        EXAMPLES::

            sage: E = EllipticCurve('14a2')
            sage: p = 3
            sage: prec = 6
            sage: L = E.padic_lseries(p,implementation="pollackstevens",precision=prec) # long time
            sage: L.series(4)          # long time
            2*3 + 3^4 + 3^5 + O(3^6) + (2*3 + 3^2 + O(3^4))*T + (2*3 + O(3^2))*T^2 + (3 + O(3^2))*T^3 + O(T^4)

            sage: E = EllipticCurve("15a3")
            sage: L = E.padic_lseries(5,implementation="pollackstevens",precision=15)  # long time
            sage: L.series(3)            # long time
            O(5^15) + (2 + 4*5^2 + 3*5^3 + 5^5 + 2*5^6 + 3*5^7 + 3*5^8 + 2*5^9 + 2*5^10 + 3*5^11 + 5^12 + O(5^13))*T + (4*5 + 4*5^3 + 3*5^4 + 4*5^5 + 3*5^6 + 2*5^7 + 5^8 + 4*5^9 + 3*5^10 + O(5^11))*T^2 + O(T^3)

            sage: E = EllipticCurve("79a1")
            sage: L = E.padic_lseries(2,implementation="pollackstevens",precision=10) # not tested
            sage: L.series(4)  # not tested
            O(2^9) + (2^3 + O(2^4))*T + O(2^0)*T^2 + (O(2^-3))*T^3 + O(T^4)
        """
        p = self.prime()
        M = self.symbol().precision_relative()
        K = pAdicField(p, M)
        R = PowerSeriesRing(K, names="T")
        T = R.gens()[0]
        return R([self[i] for i in range(prec)]).add_bigoh(prec)
Esempio n. 6
0
def test_tensprod_11a_17a():
    C11=[1,-2,-1,2,1,2,-2,0,-2,-2,1,-2,4,4,-1,-4,-2,4,0,2,2,-2,\
    -1,0,-4,-8,5,-4,0,2,7,8,-1,4,-2,-4,3,0,-4,0,-8,-4,-6,2,-2,\
    2,8,4,-3,8,2,8,-6,-10,1,0,0,0,5,-2,12,-14,4,-8,4,2,-7,-4,\
    1,4,-3,0,4,-6,4,0,-2,8,-10,-4,1,16,-6,4,-2,12,0,0,15,4,-8,\
    -2,-7,-16,0,-8,-7,6,-2,-8,2,-4,-16,0,2,12,18,10,10,-2,-3,8,\
    9,0,-1,0,-8,-10,4,0,1,-24,8,14,-9,-8,8,0,6,-8,-18,-2,0,14,\
    5,0,-7,-2,10,-4,-8,6,4,8,0,-8,3,6,-10,-8,2,0,4,4,7,-8,-7,\
    20,6,8,2,-2,4,-16,-1,12,-12,0,3,4,0,-12,-6,0,8,-4,-5,-30,\
    -15,-4,7,16,-12,0,3,14,-2,16,-10,0,17,8,4,14,-4,-6,-2,4,0,0]
    C17=[1,-1,0,-1,-2,0,4,3,-3,2,0,0,-2,-4,0,-1,1,3,-4,2,0,0,4,\
    0,-1,2,0,-4,6,0,4,-5,0,-1,-8,3,-2,4,0,-6,-6,0,4,0,6,-4,0,\
    0,9,1,0,2,6,0,0,12,0,-6,-12,0,-10,-4,-12,7,4,0,4,-1,0,8,\
    -4,-9,-6,2,0,4,0,0,12,2,9,6,-4,0,-2,-4,0,0,10,-6,-8,-4,0,\
    0,8,0,2,-9,0,1,-10,0,8,-6,0,-6,8,0,6,0,0,-4,-14,0,-8,-6,\
    6,12,4,0,-11,10,0,-4,12,12,8,3,0,-4,16,0,-16,-4,0,3,-6,0,\
    -8,8,0,4,0,3,-12,6,0,2,-10,0,-16,-12,-3,0,-8,0,-2,-12,0,10,\
    16,-9,24,6,0,4,-4,0,-9,2,12,-4,22,0,-4,0,0,-10,12,-6,-2,8,\
    0,12,4,0,0,0,0,-8,-16,0,2,-2,0,-9,-18,0,-20,-3]
    ANS=[1,2,0,2,-2,0,-8,8,15,-4,0,0,-8,-16,0,12,-2,30,0,-4,0,0,\
    -4,0,29,-16,0,-16,0,0,28,-8,0,-4,16,30,-6,0,0,-16,48,0,-24,\
    0,-30,-8,0,0,22,58,0,-16,-36,0,0,-64,0,0,-60,0,-120,56,-120,\
    -8,16,0,-28,-4,0,32,12,120,-24,-12,0,0,0,0,-120,-24,144,96,\
    24,0,4,-48,0,0,150,-60,64,-8,0,0,0,0,-14,44,0,58,-20,0,-128,\
    -64,0,-72,144,0,60,0,0,-96,-126,0,8,0,-120,-120,16,0,-11,-240,\
    0,56,-158,-240,64,-32,0,32,-288,0,0,-56,0,-16,42,0,-80,32,0,\
    24,0,180,0,-48,0,-12,100,0,-32,0,-30,0,-56,0,14,-240,0,16,32,\
    288,96,96,0,48,48,0,142,8,0,-48,-132,0,-232,0,0,300,-180,-60,\
    -14,128,0,-32,12,0,0,0,0,0,-272,0,8,-28,0,44,36,0,0,232]
    R = PowerSeriesRing(ZZ, "T")
    T = R.gens()[0]
    B11 = [11, 1 - T, 1 + 11 * T**2]
    B17 = [17, 1 + 2 * T + 17 * T**2, 1 - T]
    assert ANS == tensor_get_an_no_deg1(C11, C17, 2, 2, [B11, B17])
Esempio n. 7
0
def test_tensprod_121_chi():
    C121=[1,2,-1,2,1,-2,2,0,-2,2,0,-2,-4,4,-1,-4,2,-4,0,2,-2,0,\
    -1,0,-4,-8,5,4,0,-2,7,-8,0,4,2,-4,3,0,4,0,8,-4,6,0,-2,-2,\
    8,4,-3,-8,-2,-8,-6,10,0,0,0,0,5,-2,-12,14,-4,-8,-4,0,-7,4,\
    1,4,-3,0,-4,6,4,0,0,8,10,-4,1,16,6,-4,2,12,0,0,15,-4,-8,\
    -2,-7,16,0,8,-7,-6,0,-8,-2,-4,-16,0,-2,-12,-18,10,-10,0,-3,\
    -8,9,0,-1,0,8,10,4,0,0,-24,-8,14,-9,-8,-8,0,-6,-8,18,0,0,\
    -14,5,0,-7,2,-10,4,-8,-6,0,8,0,-8,3,6,10,8,-2,0,-4,0,7,8,\
    -7,20,6,-8,-2,2,4,16,0,12,12,0,3,4,0,12,6,0,-8,0,-5,30,\
    -15,-4,7,-16,12,0,3,-14,0,16,10,0,17,8,-4,-14,4,-6,2,0,0,0]
    chi=[1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,\
    1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,\
    -1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,\
    1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,\
    1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,\
    1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,\
    -1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,\
    -1,-1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1,1,1,1,-1,-1,\
    -1,1,-1,0,1,-1,1,1,1,-1,-1,-1,1,-1,0,1,-1]
    ANS=[1,-2,-1,2,1,2,-2,0,-2,-2,1,-2,4,4,-1,-4,-2,4,0,2,2,-2,\
    -1,0,-4,-8,5,-4,0,2,7,8,-1,4,-2,-4,3,0,-4,0,-8,-4,-6,2,-2,\
    2,8,4,-3,8,2,8,-6,-10,1,0,0,0,5,-2,12,-14,4,-8,4,2,-7,-4,\
    1,4,-3,0,4,-6,4,0,-2,8,-10,-4,1,16,-6,4,-2,12,0,0,15,4,-8,\
    -2,-7,-16,0,-8,-7,6,-2,-8,2,-4,-16,0,2,12,18,10,10,-2,-3,8,\
    9,0,-1,0,-8,-10,4,0,1,-24,8,14,-9,-8,8,0,6,-8,-18,-2,0,14,\
    5,0,-7,-2,10,-4,-8,6,4,8,0,-8,3,6,-10,-8,2,0,4,4,7,-8,-7,\
    20,6,8,2,-2,4,-16,-1,12,-12,0,3,4,0,-12,-6,0,8,-4,-5,-30,\
    -15,-4,7,16,-12,0,3,14,-2,16,-10,0,17,8,4,14,-4,-6,-2,4,0,0]
    R = PowerSeriesRing(ZZ, "T")
    T = R.gens()[0]
    assert ANS == tensor_get_an_deg1(C121, chi, [[11, 1 - T]])
    assert ANS == tensor_get_an(C121, chi, 2, 1, [[11, 1 - T, 1 - T]])
    assert get_euler_factor(ANS, 2) == (1 + 2 * T + 2 * T**2 + O(T**8))
    assert get_euler_factor(ANS, 3) == (1 + T + 3 * T**2 + O(T**5))
    assert get_euler_factor(ANS, 5) == (1 - T + 5 * T**2 + O(T**4))
Esempio n. 8
0
def list_to_euler_factor(L,prec):
    """
    takes a list [a_p, a_p^2,...
    and returns the euler factor
    """
    if isinstance(L[0], int):
        K = QQ
    else:
        K = L[0].parent()
    R = PowerSeriesRing(K, "T")
    T = R.gens()[0]
    f =  1/ R([1]+L)
    f = f.add_bigoh(prec+1)
    return f
Esempio n. 9
0
def list_to_euler_factor(L, d):
    """
    takes a list [a_p, a_p^2,...
    and returns the euler factor
    """
    if isinstance(L[0], int):
        K = QQ
    else:
        K = L[0].parent()
    R = PowerSeriesRing(K, "T")
    T = R.gens()[0]
    f = 1 / R([1] + L)
    f = f.add_bigoh(d + 1)
    return f
Esempio n. 10
0
class padic_Lfunction_two_variable(padic_Lfunction):
    def __init__(self, Phis, var='T', prec=None):
        #TODO: prec: Default it to None would make us compute it.
        self._Phis = Phis    #should we create a copy of Phis, in case Phis changes? probably
        self._coefficient_ring = Phis.base_ring()
        self._base_ring = PowerSeriesRing(self._coefficient_ring, var)    #What precision?
        self._prec = prec
    
    def base_ring(self):
        return self._base_ring
    
    def coefficient_ring(self):
        return self._coefficient_ring
    
    def variables(self):
        #returns (T, w)
        return (self._base_ring.gens()[0], self._coefficient_ring.gens()[0])
    
    def _max_coeff(self):
        Phis = self._Phis
        p = Phis.parent().prime()
        p_prec, var_prec = Phis.precision_absolute()
        max_j = Phis.parent().coefficient_module().length_of_moments(p_prec)
        n = 0
        while True:
            if max_j - (n / (p-1)).floor() - min(max_j, n) - (max_j / p).floor() <= 0:
                return n - 1
            n += 1
    
    def _on_Da(self, a, twist):
        r"""
        An internal method used by ``self._basic_integral``. The parameter ``twist`` is assumed to be either ``None`` or a primitive quaratic Dirichlet character.
        """
        p = self._Phis.parent().prime()
        if twist is None:
            return self._Phis(M2Z([1,a,0,p]))
        D = twist.level()
        DD = self._Phis.parent().coefficient_module()
        S0 = DD.action().actor()
        ans = DD.zero()
        for b in range(1, D + 1):
            if D.gcd(b) == 1:
                ans += twist(b) * (self._Phis(M2Z([1, D * a + b * p, 0, D * p])) * S0([1, b / D, 0, 1]))
        return ans
    
    @cached_method
    def _basic_integral(self, a, j, twist=None):
        r"""
        Computes the integral
        
            .. MATH::
               
               \int_{a+p\ZZ_p}(z-\omega(a))^jd\mu_\chi.
        
        If ``twist`` is ``None``, `\\chi` is the trivial character. Otherwise, ``twist`` can be a primitive quadratic character of conductor prime to `p`.
        """
        #is this the negative of what we want?
        #if Phis is fixed for this p-adic L-function, we should make this method cached
        p = self._Phis.parent().prime()
        if twist is None:
            pass
        elif twist in ZZ:
            twist = kronecker_character(twist)
            if twist.is_trivial():
                twist = None
            else:
                D = twist.level()
                assert(D.gcd(p) == 1)
        else:
            if twist.is_trivial():
                twist = None
            else:
                assert((twist**2).is_trivial())
                twist = twist.primitive_character()
                D = twist.level()
                assert(D.gcd(p) == 1)
        
        onDa = self._on_Da(a, twist)#self._Phis(Da)
        aminusat = a - self._Phis.parent().base_ring().base_ring().teichmuller(a)
        #aminusat = a - self._coefficient_ring.base_ring().teichmuller(a)
        try:
            ap = self._ap
        except AttributeError:
            self._ap = self._Phis.Tq_eigenvalue(p) #catch exception if not eigensymbol
            ap = self._ap
        if not twist is None:
            ap *= twist(p)
        if j == 0:
            return (~ap) * onDa.moment(0)
        if a == 1:
            #aminusat is 0, so only the j=r term is non-zero
            return (~ap) * (p ** j) * onDa.moment(j)
        #print "j =", j, "a = ", a
        ans = onDa.moment(0) * (aminusat ** j)
        #ans = onDa.moment(0)
        #print "\tr =", 0, " ans =", ans
        for r in range(1, j+1):
            if r == j:
                ans += binomial(j, r) * (p ** r) * onDa.moment(r)
            else:
                ans += binomial(j, r) * (aminusat ** (j - r)) * (p ** r) * onDa.moment(r)
            #print "\tr =", r, " ans =", ans
        #print " "
        return (~ap) * ans
    
    @cached_method
    def _compute_nth_coeff(self, n, twist=None):
        r"""
        Computes the coefficient of T^n.
        """
        #TODO: Check that n is not too big
        #TODO implement twist
        Phis = self._Phis
        p = Phis.parent().prime()
        if n == 0:
            return sum([self._basic_integral(a, 0, twist) for a in range(1, p)])
        p_prec, var_prec = Phis.precision_absolute()
        max_j = Phis.parent().coefficient_module().length_of_moments(p_prec)
        ans_prec = max_j - (n / (p-1)).floor() - min(max_j, n) - (max_j / p).floor()
        if ans_prec == 0:
            return self._coefficient_ring(0)
        #prec = self._Phis.parent()#precision_absolute()[0] #Not quite right, probably
        #print "@@@@n =", n, "prec =", prec
        cjns = list(logp_binom(n, p, max_j+1))
        #print cjns
        teich = Phis.parent().base_ring().base_ring().teichmuller
        #Next line should work but loses precision!!!
        ans = sum([cjns[j] * sum([((~teich(a)) ** j) * self._basic_integral(a, j, twist) for a in range(1,p)]) for j in range(1, min(max_j, len(cjns)))])
        #Instead do this messed up thing
        w = ans.parent().gen()
        #ans = 0*w
        #for j in range(1,min(max_j, len(cjns))):
        #    ans_term = [0*w] * var_prec
        #    for a in range(1,p):
        #        term = (((~teich(a)) ** j) * self._basic_integral(a, j, twist)).list()
        #        for i in range(min(var_prec, len(term))):
        #            ans_term[i] += term[i]
        #    ans += cjns[j] * sum([ans_term[i] * w**i for i in range(var_prec)])
        #print ans_prec
        ans_prec = O(p**ans_prec)
        #print ans_prec
        #print ans
        for i in range(ans.degree() + 1):
            ans += ans_prec * w**i
        return ans
    
    def coefficient(self, index, twist=None):
        r"""
        index should be some sort of pair (i,j) corresponding to T^i w^j. Maybe if
        index is just one number, i, it can return the coefficient of T^i to biggest
        possible precision in w.
        
        Should also make it so that one can pass some monomial in the variables.
        """
        pass
    
    def power_series(self, twist=None, prec=None):
        r"""
        returns a power series in base_ring, up to given precision, or max prec if prec is None
        """
        p = self._Phis.parent().prime()
        if prec is None:
            prec = self._max_coeff()#Phis.precision_absolute()[0] #Not quite right, probably
        else:
            pass #do some checks on inputted prec
        return self._base_ring([self._compute_nth_coeff(n, twist) for n in range(prec + 1)])
Esempio n. 11
0
class BianchiDistributions(Module, UniqueRepresentation):
    r"""
    This class represents the overconvergent approximation modules used to
    describe p-adic overconvergent Bianchi modular symbols.

    INPUT:

     - ``p`` - integer
        Prime with which we work

     - ``depth`` - integer (Default: None)
        Precision to which we work; work with moments x^iy^j for
        i,j up to the depth

     - ``act_on_left`` - boolean, (Default: False) 
        Encodes whether Sigma_0(p)^2 is acting on the left or right.

     - ``adjuster`` - Sigma0ActionAdjuster class (Default: _default_adjuster())
        If using a different convention for matrix actions, tell the code where a,b,c,d w
        should be mapped to.


    AUTHORS:

    - Marc Masdeu (2018-08-14)
    - Chris Williams (2018-08-16)
    """
    def __init__(self, p, depth, act_on_left=False, adjuster=None):
        self._dimension = 0  ## Hack!! Dimension was being called before it was intialised
        self._Rmod = ZpCA(p, depth - 1)  ## create Zp
        Module.__init__(self, base=self._Rmod)
        self.Element = BianchiDistributionElement
        self._R = ZZ
        self._p = p
        self._depth = depth
        self._pN = self._p**(depth - 1)
        self._cache_powers = dict()
        self._unset_coercions_used()

        ## Initialise monoid Sigma_0(p) + action; use Pollack-Stevens modular symbol code
        ## our_adjuster() is set above to allow different conventions
        if adjuster is None:
            adjuster = _default_adjuster()

        self._adjuster = adjuster

        ## Power series ring for representing distributions as strings
        self._repr_R = PowerSeriesRing(self._R,
                                       num_gens=2,
                                       default_prec=self._depth,
                                       names='X,Y')

        self._Sigma0Squared = Sigma0Squared(self._p, self._Rmod, adjuster)
        self._act = Sigma0SquaredAction(self._Sigma0Squared,
                                        self,
                                        act_on_left=act_on_left)
        self.register_action(self._act)
        self._populate_coercion_lists_()

        ## Initialise dictionaries of indices to translate between pairs and index for moments
        self._index = dict()
        self._ij = []
        m = 0

        ## Populate dictionary/array giving index of the basis element corr. to tuple (i,j), 0 <= i,j <= depth = n
        ## These things are ordered by degree of y, then degree of x: [1, x, x^2, ..., y, xy, ... ]
        for j in range(depth):
            for i in range(depth):
                self._ij.append((i, j))
                self._index[(i, j)] = m
                m += 1

        self._dimension = m  ## Number of moments we store

        ## Power series ring Zp[[x,y]]. We have to work with monomials up to x^depth * y^depth, so need prec = 2*depth
        self._PowerSeries_x = PowerSeriesRing(self._Rmod,
                                              default_prec=self._depth,
                                              names='x')
        self._PowerSeries_x_ZZ = PowerSeriesRing(ZZ,
                                                 default_prec=self._depth,
                                                 names='x')
        self._PowerSeries = PowerSeriesRing(self._PowerSeries_x,
                                            default_prec=self._depth,
                                            names='y')
        self._PowerSeries_ZZ = PowerSeriesRing(self._PowerSeries_x_ZZ,
                                               default_prec=self._depth,
                                               names='y')

    def index(self, ij):
        r"""
        Function to return index of a tuple (i,j).

        Input:
           - ij (tuple) : pair (i,j)
        Returns:
            Place in ordered basis corresponding to x^iy^j.
        """
        return self._index[tuple(ij)]

    def ij_from_pos(self, n):
        r"""
        From position in the ordered basis, returns corr. tuple (n,i)

        Input:
                - n (int) : position in basis.
        Returns:
                pair (i,j) s.t. the nth basis vector is x^iy^j
        """
        return self._ij[n]

    def monomial_from_index(self, n, R=None):
        """
        Takes index and returns the corresponding monomial in the basis
        """
        X, Y = self._repr_R.gens()
        if isinstance(n, tuple):
            (i, j) = n
        else:
            i, j = self._ij[n]
        return X**i * Y**j

    def basis_vector(self, ij):
        """
        Returns the (i,j)th basis vector (in the dual basis), which takes
        the monomial x^iy^j to 1 and every other monomial to 0.

        EXAMPLES::

            sage: from darmonpoints.ocbianchi import BianchiDistributions
            sage: D = BianchiDistributions(11,4)
            sage: D.basis_vector((2,3))
            X^2*Y^3
            sage: D.basis_vector(5)
            X*Y
        """
        moments = vector(ZZ, [0 for i in range(self._dimension)])
        if isinstance(ij, tuple):
            index = self.index(ij)
            moments[index] = 1
        else:
            moments[ij] = 1
        return self(moments)

    def analytic_functions(self):
        r"""
        Returns underlying power series of rigid analytic functions, that is,
        the space on which a distribution should take values.
        """
        return self._PowerSeries

    def analytic_vars(self):
        r"""
        Returns x,y, the variables of the underlying ring of analytic functions.
        """
        x = self.analytic_functions()(self._PowerSeries_x.gen())
        y = self.analytic_functions().gen()
        return x, y

    def Sigma0Squared(self):
        r"""
        Returns underlying monoid Sigma_0(p)^2.
        """
        return self._Sigma0Squared

    def Sigma0(self):
        r"""
        Returns underlying monoid Sigma_0(p)^2.
        """
        return self._Sigma0Squared

    def approx_module(self, M=None):
        if M is None:
            M = self.dimension()
        return MatrixSpace(self._R, M, 1)

    def clear_cache(self):
        del self._cache_powers
        self._cache_powers = dict()

    def is_overconvergent(self):
        return True

    def _an_element_(self):
        r"""
        """
        return BianchiDistributionElement(self,
                                          Matrix(self._R, self._dimension, 1,
                                                 range(1,
                                                       self._dimension + 1)),
                                          check=False)

    def _coerce_map_from_(self, S):
        # Nothing coherces here, except BianchiDistributionElement
        return False

    def _element_constructor_(self, x, check=True, normalize=False):
        #Code how to coherce x into the space
        #Admissible values of x?
        return BianchiDistributionElement(self, x)

    def acting_matrix(self, g, M):
        G = g.parent()
        qrep = G.quaternion_to_matrix(g)
        qrep_bar = qrep.apply_map(lambda x: x.trace() - x)
        first, second = qrep.apply_map(G._F_to_local), qrep_bar.apply_map(
            G._F_to_local)
        return self._get_powers(self.Sigma0Squared()(first, second))

    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: from darmonpoints.ocbianchi import BianchiDistributions
            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

    def _repr_(self):
        r"""
        This returns the representation of self as a string.
        """
        return "Space of %s-adic Bianchi distributions with k=0 action and precision cap %s" % (
            self._p, self._dimension - 1)

    def prime(self):
        r"""
        Returns underlying prime.
        """
        return self._p

    def basis(self):
        r"""
        A basis of the module.

        Returns all monomials in x,y of degree (in each variable) up to the specified depth-1.

        """
        try:
            return self._basis
        except:
            pass
        self._basis = [
            BianchiDistributionElement(self,
                                       Matrix(self._R,
                                              self._dimension,
                                              1, {(jj, 0): 1},
                                              sparse=False),
                                       check=False)
            for jj in range(self._dimension)
        ]
        return self._basis

    def base_ring(self):
        r"""
        This function returns the base ring of the overconvergent element.
        """
        return self._Rmod

    def depth(self):
        r"""
        Returns the depth of the module. If the depth is d, then a basis for the approximation
        modules is x^iy^j with i,j in {0,...,d-1}.
        """
        return self._depth

    def dimension(self):
        r"""
        Returns the dimension (rank) of the module.
        """
        return self._dimension

    def precision_cap(self):
        r"""
        Returns the depth of the module. If the depth is d, then a basis for the approximation
        modules is x^iy^j with i,j in {0,...,d-1}.
        """
        return self._depth

    def is_exact(self):
        r"""
        All distributions are finite approximations. They are only exact as elements of
        D/Fil^{d,d}D, where d is the depth.
        """
        return False
Esempio n. 12
0
class padic_Lfunction_two_variable(padic_Lfunction):
    def __init__(self, Phis, var='T', prec=None):
        #TODO: prec: Default it to None would make us compute it.
        self._Phis = Phis  #should we create a copy of Phis, in case Phis changes? probably
        self._coefficient_ring = Phis.base_ring()
        self._base_ring = PowerSeriesRing(self._coefficient_ring,
                                          var)  #What precision?
        self._prec = prec

    def base_ring(self):
        return self._base_ring

    def coefficient_ring(self):
        return self._coefficient_ring

    def variables(self):
        #returns (T, w)
        return (self._base_ring.gens()[0], self._coefficient_ring.gens()[0])

    def _max_coeff(self):
        Phis = self._Phis
        p = Phis.parent().prime()
        p_prec, var_prec = Phis.precision_absolute()
        max_j = Phis.parent().coefficient_module().length_of_moments(p_prec)
        n = 0
        while True:
            if max_j - (n / (p - 1)).floor() - min(
                    max_j, n) - (max_j / p).floor() <= 0:
                return n - 1
            n += 1

    def _on_Da(self, a, twist):
        r"""
        An internal method used by ``self._basic_integral``. The parameter ``twist`` is assumed to be either ``None`` or a primitive quaratic Dirichlet character.
        """
        p = self._Phis.parent().prime()
        if twist is None:
            return self._Phis(M2Z([1, a, 0, p]))
        D = twist.level()
        DD = self._Phis.parent().coefficient_module()
        S0 = DD.action().actor()
        ans = DD.zero()
        for b in range(1, D + 1):
            if D.gcd(b) == 1:
                ans += twist(b) * (self._Phis(M2Z([1, D * a + b * p, 0, D * p
                                                   ])) * S0([1, b / D, 0, 1]))
        return ans

    @cached_method
    def _basic_integral(self, a, j, twist=None):
        r"""
        Computes the integral
        
            .. MATH::
               
               \int_{a+p\ZZ_p}(z-\omega(a))^jd\mu_\chi.
        
        If ``twist`` is ``None``, `\\chi` is the trivial character. Otherwise, ``twist`` can be a primitive quadratic character of conductor prime to `p`.
        """
        #is this the negative of what we want?
        #if Phis is fixed for this p-adic L-function, we should make this method cached
        p = self._Phis.parent().prime()
        if twist is None:
            pass
        elif twist in ZZ:
            twist = kronecker_character(twist)
            if twist.is_trivial():
                twist = None
            else:
                D = twist.level()
                assert (D.gcd(p) == 1)
        else:
            if twist.is_trivial():
                twist = None
            else:
                assert ((twist**2).is_trivial())
                twist = twist.primitive_character()
                D = twist.level()
                assert (D.gcd(p) == 1)

        onDa = self._on_Da(a, twist)  #self._Phis(Da)
        aminusat = a - self._Phis.parent().base_ring().base_ring().teichmuller(
            a)
        #aminusat = a - self._coefficient_ring.base_ring().teichmuller(a)
        try:
            ap = self._ap
        except AttributeError:
            self._ap = self._Phis.Tq_eigenvalue(
                p)  #catch exception if not eigensymbol
            ap = self._ap
        if not twist is None:
            ap *= twist(p)
        if j == 0:
            return (~ap) * onDa.moment(0)
        if a == 1:
            #aminusat is 0, so only the j=r term is non-zero
            return (~ap) * (p**j) * onDa.moment(j)
        #print "j =", j, "a = ", a
        ans = onDa.moment(0) * (aminusat**j)
        #ans = onDa.moment(0)
        #print "\tr =", 0, " ans =", ans
        for r in range(1, j + 1):
            if r == j:
                ans += binomial(j, r) * (p**r) * onDa.moment(r)
            else:
                ans += binomial(j, r) * (aminusat
                                         **(j - r)) * (p**r) * onDa.moment(r)
            #print "\tr =", r, " ans =", ans
        #print " "
        return (~ap) * ans

    @cached_method
    def _compute_nth_coeff(self, n, twist=None):
        r"""
        Computes the coefficient of T^n.
        """
        #TODO: Check that n is not too big
        #TODO implement twist
        Phis = self._Phis
        p = Phis.parent().prime()
        if n == 0:
            return sum(
                [self._basic_integral(a, 0, twist) for a in range(1, p)])
        p_prec, var_prec = Phis.precision_absolute()
        max_j = Phis.parent().coefficient_module().length_of_moments(p_prec)
        ans_prec = max_j - (n / (p - 1)).floor() - min(
            max_j, n) - (max_j / p).floor()
        if ans_prec == 0:
            return self._coefficient_ring(0)
        #prec = self._Phis.parent()#precision_absolute()[0] #Not quite right, probably
        #print "@@@@n =", n, "prec =", prec
        cjns = list(logp_binom(n, p, max_j + 1))
        #print cjns
        teich = Phis.parent().base_ring().base_ring().teichmuller
        #Next line should work but loses precision!!!
        ans = sum([
            cjns[j] *
            sum([((~teich(a))**j) * self._basic_integral(a, j, twist)
                 for a in range(1, p)])
            for j in range(1, min(max_j, len(cjns)))
        ])
        #Instead do this messed up thing
        w = ans.parent().gen()
        #ans = 0*w
        #for j in range(1,min(max_j, len(cjns))):
        #    ans_term = [0*w] * var_prec
        #    for a in range(1,p):
        #        term = (((~teich(a)) ** j) * self._basic_integral(a, j, twist)).list()
        #        for i in range(min(var_prec, len(term))):
        #            ans_term[i] += term[i]
        #    ans += cjns[j] * sum([ans_term[i] * w**i for i in range(var_prec)])
        #print ans_prec
        ans_prec = O(p**ans_prec)
        #print ans_prec
        #print ans
        for i in range(ans.degree() + 1):
            ans += ans_prec * w**i
        return ans

    def coefficient(self, index, twist=None):
        r"""
        index should be some sort of pair (i,j) corresponding to T^i w^j. Maybe if
        index is just one number, i, it can return the coefficient of T^i to biggest
        possible precision in w.
        
        Should also make it so that one can pass some monomial in the variables.
        """
        pass

    def power_series(self, twist=None, prec=None):
        r"""
        returns a power series in base_ring, up to given precision, or max prec if prec is None
        """
        p = self._Phis.parent().prime()
        if prec is None:
            prec = self._max_coeff(
            )  #Phis.precision_absolute()[0] #Not quite right, probably
        else:
            pass  #do some checks on inputted prec
        return self._base_ring(
            [self._compute_nth_coeff(n, twist) for n in range(prec + 1)])