예제 #1
0
def _prec_for_solve_diff_eqn(M, p):
    r"""
    A helper function for determining the (absolute) precision of the input
    to solve_diff_eqn required in order obtain an answer with (absolute)
    precision ``M``. The parameter ``p`` is the prime.
    
    Given input (absolute) precision `M_\text{in}`, the output of
    solve_diff_eqn has (absolute) precision
    
    .. MATH::
        
        M = M_\text{in} - \lfloor\log_p(M_\text{in})\rfloor - 1.
    
    ::EXAMPLES:
    
        sage: from sage.modular.pollack_stevens.modsym_OMS_space import _prec_for_solve_diff_eqn
        sage: [_prec_for_solve_diff_eqn(M, p) for p in [3,7,11,29] for M in [1,3,10,20]]
        [2, 5, 13, 23, 2, 4, 12, 22, 2, 4, 12, 22, 2, 4, 11, 21]
    """
    if M < 1:
        raise ValueError("Desired precision M(=%s) must be at least 1." % (M))
    # A good guess to begin:
    M_in = ZZ(1 + M + ZZ(M).exact_log(p))
    # It looks like usually there are no iterations
    while M > M_in - M_in.exact_log(p) - 1:
        M_in += 1
        #print("An iteration in _prec_solve_diff_eqn")
    return M_in
예제 #2
0
 def dirichlet_coefficients(self, ncoeffs=20):
     from sage.rings.power_series_ring import PowerSeriesRing
     from sage.misc.misc import srange
     #from sage.misc.mrange import mrange
     ncoeffs = ZZ(ncoeffs)
     ps = prime_range(ncoeffs + 1)
     num_ps = len(ps)
     exps = [ncoeffs.exact_log(p) + 1 for p in ps]
     M = ncoeffs.exact_log(2) + 1
     #print ps, exps, M
     PS = PowerSeriesRing(QQ, 'x', M)
     euler_factors = dict([[ps[i], ~PS(self.euler_factor(ps[i]), exps[i] + 1)] for i in range(num_ps)])
     ans = []
     for n in srange(1, ncoeffs + 1):
         ans.append(prod([euler_factors[p][e] for p, e in n.factor()]))
     #ans = [0] * ncoeffs
     #is_zeroes = True
     #for e in mrange(exps):
     #    if is_zeroes:
     #        is_zeroes = False
     #        ans[0] = QQ.one()
     #        continue
     #    n = 1
     #    an = QQ.one()
     #    breaker = False
     #    for i in range(num_ps):
     #        if exps[i] == 0:
     #            continue
     #        n *= ps[i] ** e[i]
     #        if n > ncoeffs:
     #            breaker = True
     #            break
     #        an *= euler_factors[i][e[i]]
     #    #print n, an, e
     #    if breaker:
     #        continue
     #    ans[n-1] = an
     return ans
예제 #3
0
 def solve_diff_eqn(self):
     r"""
     Solves the difference equation.
     
     See Theorem 4.5 and Lemma 4.4 of [PS].
     
     INPUT:
     
     - ``self`` - an overconvergent distribution `\mu` of absolute
         precision `M`
     
     OUTPUT:
     
     - an overconvergent distribution `\nu` of absolute precision
         `M - \lfloor\log_p(M)\rfloor - 1` such that
     
     .. math::
     
         \nu|\Delta = \mu,\text{ where }\Delta=\begin{pmatrix}1&1\\0&1
         \end{pmatrix} - 1.
     
     EXAMPLES::
     
         sage: D = OverconvergentDistributions(0,7,base=ZpCA(7,5))
         sage: D10 = D.change_precision(10)
         sage: mu10 = D10((O(7^10), 4 + 6*7 + 5*7^3 + 2*7^4 + 5*7^5 + O(7^9), 5 + 7^3 + 5*7^4 + 6*7^5 + 7^6 + 6*7^7 + O(7^8), 2 + 7 + 6*7^2 + 6*7^4 + 7^5 + 7^6 + O(7^7), 3*7 + 4*7^2 + 4*7^3 + 3*7^4 + 3*7^5 + O(7^6), 5 + 3*7 + 2*7^2 + 7^3 + 3*7^4 + O(7^5), 1 + 7^2 + 7^3 + O(7^4), 6*7 + 6*7^2 + O(7^3), 2 + 3*7 + O(7^2), 1 + O(7)))
         sage: nu10 = mu10.solve_diff_eqn()
         sage: MS = OverconvergentModularSymbols(14, coefficients=D)
         sage: MR = MS.source()
         sage: Id = MR.gens()[0]
         sage: nu10 * MR.gammas[Id] - nu10 - mu10
         7^8 * ()
         sage: D = OverconvergentDistributions(0,7,base=Qp(7,5))
         sage: D10 = D.change_precision(10)
         sage: mu10 = D10((O(7^10), 4 + 6*7 + 5*7^3 + 2*7^4 + 5*7^5 + O(7^9), 5 + 7^3 + 5*7^4 + 6*7^5 + 7^6 + 6*7^7 + O(7^8), 2 + 7 + 6*7^2 + 6*7^4 + 7^5 + 7^6 + O(7^7), 3*7 + 4*7^2 + 4*7^3 + 3*7^4 + 3*7^5 + O(7^6), 5 + 3*7 + 2*7^2 + 7^3 + 3*7^4 + O(7^5), 1 + 7^2 + 7^3 + O(7^4), 6*7 + 6*7^2 + O(7^3), 2 + 3*7 + O(7^2), 1 + O(7)))
         sage: nu10 = mu10.solve_diff_eqn()
         sage: MS = OverconvergentModularSymbols(14, coefficients=D);
         sage: MR = MS.source();
         sage: Id = MR.gens()[0]
         sage: nu10 * MR.gammas[Id] - nu10 - mu10
         7^8 * ()
         sage: R = ZpCA(5, 5); D = OverconvergentDistributions(0,base=R);
         sage: nu = D((R(O(5^5)), R(5 + 3*5^2 + 4*5^3 + O(5^4)), R(5 + O(5^3)), R(2*5 + O(5^2), 2 + O(5))));
         sage: nu.solve_diff_eqn()
         5 * (1 + 3*5 + O(5^2), O(5))
         
     Check input of relative precision 2::
     
         sage: from sage.modular.pollack_stevens.coeffmod_OMS_element import CoeffMod_OMS_element
         sage: R = ZpCA(3, 9)
         sage: D = OverconvergentDistributions(0, base=R, prec_cap=4)
         sage: V = D.approx_module(2)
         sage: nu = CoeffMod_OMS_element(V([R(0, 9), R(2*3^2 + 2*3^4 + 2*3^7 + 3^8 + O(3^9))]), D, ordp=0, check=False)
         sage: mu = nu.solve_diff_eqn()
         sage: mu
         3 * ()
     """
     #RH: see tests.sage for randomized verification that this function works correctly
     p = self.parent().prime()
     abs_prec = ZZ(self.precision_absolute())
     if self.is_zero():
         mu = self.parent()(0)
         mu.ordp = abs_prec - abs_prec.exact_log(p) - 1
         return mu
     if self._unscaled_moment(0) != 0:
         raise ValueError("Distribution must have total measure 0 to be in image of difference operator.")
     M = ZZ(len(self._moments))
     ## RP: This should never happen -- the distribution must be 0 at this point if M==1
     if M == 1:
         return self.parent()(0)
     if M == 2:
         if p == 2:
             raise ValueError("Not enough accuracy to return anything")
         else:
             out_prec = abs_prec - abs_prec.exact_log(p) - 1
             if self.ordp >= out_prec:
                 mu = self.parent()(0)
                 mu.ordp = out_prec
                 return mu
             mu = self.parent()(self._unscaled_moment(1))
             mu.ordp = self.ordp
             return mu
     R = self.parent().base_ring()
     K = R.fraction_field()
     bern = [bernoulli(i) for i in range(0,M-1,2)]
     minhalf = ~K(-2)    #bernoulli(1)
     # bernoulli(1) = -1/2; the only nonzero odd bernoulli number
     v = [minhalf * self.moment(m) for m in range(M-1)] #(m choose m-1) * B_1 * mu[m]/m            
     for m in range(1,M):
         scalar = K(self.moment(m)) * (~K(m))
         for j in range(m-1,M-1,2):
             v[j] += binomial(j,m-1) * bern[(j-m+1)//2] * scalar
     ordp = min(a.valuation() for a in v)
     #Is this correct in ramified extensions of QQp?
     verbose("abs_prec: %s, ordp: %s"%(abs_prec, ordp), level=2)
     if ordp != 0:
         new_M = abs_prec - 1 - (abs_prec).exact_log(p) - ordp
         verbose("new_M: %s"%(new_M), level=2)
         V = self.parent().approx_module(new_M)
         v = V([R(v[i] >> ordp) for i in range(new_M)])
     else:
         new_M = abs_prec - abs_prec.exact_log(p) - 1
         verbose("new_M: %s"%(new_M), level=2)
         V = self.parent().approx_module(new_M)
         v = V([R(v[i]) for i in range(new_M)])
     v[new_M-1] = v[new_M-1].add_bigoh(1)  #To force normalize to deal with this properly. May not be necessary any more.
     mu = CoeffMod_OMS_element(v, self.parent(), ordp=ordp, check=False)
     verbose("mu.ordp: %s, mu._moments: %s"%(mu.ordp, mu._moments), level=2)
     return mu.normalize()