Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 41c9c1a

Browse files
author
Edgar Costa
committed
initial implementation of padic polylogarithms
1 parent b63a0d2 commit 41c9c1a

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

src/sage/rings/padics/padic_generic_element.pyx

+125
Original file line numberDiff line numberDiff line change
@@ -2661,3 +2661,128 @@ cdef class pAdicGenericElement(LocalGenericElement):
26612661

26622662
"""
26632663
raise NotImplementedError
2664+
2665+
def polylog(self, n):
2666+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
2667+
from sage.rings.power_series_ring import PowerSeriesRing
2668+
from sage.rings.padics.factory import Qp
2669+
from sage.misc.all import verbose
2670+
from sage.functions.log import log
2671+
from sage.functions.other import ceil
2672+
2673+
def _polylog_c(n,p):
2674+
return p/(p-1) - (n-1)/log(p) + (n-1)*log(n*(p-1)/log(p),p) + log(2*p*(p-1)*n/log(p), p)
2675+
2676+
def _compute_g(p, n, prec, terms):
2677+
# Compute the sequence of power series g
2678+
R = PowerSeriesRing(Qp(p, ceil(prec)), default_prec=terms, names='v')
2679+
v = R.gen()
2680+
g = (n+1)*[0]
2681+
g[0] = v-1 - ((v-1)**p)/(v**p-(v-1)**p)
2682+
for i in range(n):
2683+
g[i+1] = -(g[i]/(v-v**2)).integral()
2684+
return [x.truncate(terms) for x in g]
2685+
2686+
def _findprec(c_1,c_2,c_3,p):
2687+
k = ceil(c_1/c_2)
2688+
while True:
2689+
if c_1*k - c_2*k.log(p) > c_3:
2690+
return k
2691+
k += 1
2692+
2693+
def _Li_n_res_1(p, n, z0, prec):
2694+
"""
2695+
compute Li_n for z0 = 1 mod p
2696+
"""
2697+
if z0 == 1:
2698+
raise ValueError('z0 cannot be 1!')
2699+
elif p == 2:
2700+
raise ValueError('p cannot be 2!')
2701+
else:
2702+
hsl = _findprec((z0-1).valuation(p), n, prec, p) # TODO increase if p = 2
2703+
K = Qp(p,ceil(prec + n*log(hsl-1,p)))
2704+
gsl = max([_findprec(1/(p-1), 1, prec - m + _polylog_c(m,p)+ K(1-2**(m-1)).valuation() + (n-m)*(hsl-1).log(p), p) for m in range(2,n+1)])
2705+
g = _compute_g(p, n, prec, gsl)
2706+
S = PowerSeriesRing(K, default_prec=hsl,names='t')
2707+
t = S.gen()
2708+
G = [((1+t).log())**i/Integer(i).factorial() for i in range(n+4)]
2709+
2710+
H = (n+1)*[0]
2711+
H[2] = sum((-1)**i*t**i/(i+1) for i in range(hsl+1)).integral()
2712+
for i in range(2,n):
2713+
H0 = 0
2714+
if (i + 1) % 2 == 1:
2715+
H0 = 2**i*p**(i+1)*g[i+1](1/2)/((1-2**i)*(p**(i+1) - 1))
2716+
H[i+1] = (H[i]/(1+t) + G[i]/t).integral() + H0
2717+
2718+
return Qp(p,prec)(H[n](K(z0-1)) - (K(z0).log(0))**(n-1)*K(1-z0).log(0)/Integer(n-1).factorial())
2719+
2720+
def _Li_n(p = 7, n = 3, z0 = 1/2, prec = 20):
2721+
"""
2722+
Return Li_n(z0) , the p-adic polylogarithm of ``z0`` to precision prec.
2723+
2724+
z0 not infinity or 1 mod p
2725+
2726+
INPUT:
2727+
2728+
- ``p`` -- (default: 7) a positive prime integer
2729+
- ``n`` -- (default: 2) a positive integer
2730+
- prec -- (default: 15) a positive integer
2731+
2732+
OUTPUT:
2733+
2734+
- Li_n(z0)
2735+
2736+
EXAMPLES:
2737+
::
2738+
2739+
sage: Li_n(13, 6, -1) == 0
2740+
True
2741+
2742+
"""
2743+
K = Qp(p,prec)
2744+
res = 'infty' # Assume residue disk around oo
2745+
if K(z0).valuation() >= 0:
2746+
res = K(z0).residue()
2747+
2748+
# Which residue disk are we in
2749+
if res == 0:
2750+
verbose("residue 0, using series. %d %s"%(n,str(z0)), level=2)
2751+
return sum(K(z0)**k/k**n for k in range(1,p*prec))
2752+
if res == 1 and K(z0) == 1:
2753+
raise ValueError
2754+
# Residue disk around 1
2755+
if res == 1 and K(z0) != 1:
2756+
verbose("residue 1, using Li_n_res_1. %d %s"%(n,str(z0)), level=2)
2757+
return _Li_n_res_1(p, n, z0, prec)
2758+
if res == 'infty':
2759+
verbose("residue oo, using functional equation for reciprocal. %d %s"%(n,str(z0)), level=2)
2760+
return (-1)**(n+1)*_Li_n(p,n,1/z0,prec)-(K(z0).log(0)**n)/K(n.factorial())
2761+
2762+
P = PolynomialRing(K, 'x')
2763+
x = P.gen()
2764+
f = x**(p-1)-1
2765+
roots = f.roots(multiplicities=False) # TODO use K.zeta here?
2766+
for x in roots:
2767+
if (z0 - x).valuation() > 0:
2768+
zeta = x
2769+
2770+
# Set up precision bounds
2771+
tsl = _findprec((z0-zeta).valuation(), n, prec, p)
2772+
gsl = max([_findprec(1/(p-1), 1, prec - m + _polylog_c(m,p) + (n-m)*(tsl-1).log(p), p) for m in range(1,n+1)])
2773+
2774+
gtr = _compute_g(p, n, prec + n*(tsl -1).log(p) + n*(gsl-1).log(p), gsl)
2775+
2776+
# Residue disk around zeta
2777+
verbose("general case. %d %s"%(n,str(z0)), level=2)
2778+
Li_i_zeta = [0] + [p**i/(p**i-1)*gtr[i](1/(1-zeta)) for i in range(1,n+1)]
2779+
2780+
T = PowerSeriesRing(K, default_prec=tsl, names='t')
2781+
t = T.gen()
2782+
F = (n+1)*[0]
2783+
F[0] = (zeta+t)/(1-zeta-t)
2784+
for i in range(n):
2785+
F[i+1] = Li_i_zeta[i+1] + (F[i]/(zeta+t)).integral()
2786+
return Qp(p, prec)(F[n](z0-zeta))
2787+
2788+
return _Li_n(self.parent().prime(), n, self, self.precision_absolute())

0 commit comments

Comments
 (0)