The most interesting functions to be exported here are matrix_of_frobenius() and adjusted_prec().
Currently this code is limited to the case (no
for
), and only handles the
elliptic curve case (not more general hyperelliptic curves).
REFERENCES:
AUTHORS:
Bases: sage.structure.element.ModuleElement
Create an element of the Monsky-Washnitzer ring of differentials, of
the form .
INPUT:
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5 - 4*x + 4)
sage: x,y = C.monsky_washnitzer_gens()
sage: MW = C.invariant_differential().parent()
sage: sage.schemes.elliptic_curves.monsky_washnitzer.MonskyWashnitzerDifferential(MW, x)
x dx/2y
sage: sage.schemes.elliptic_curves.monsky_washnitzer.MonskyWashnitzerDifferential(MW, y)
y*1 dx/2y
sage: sage.schemes.elliptic_curves.monsky_washnitzer.MonskyWashnitzerDifferential(MW, x, 10)
y^10*x dx/2y
Returns , where this element is
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: x,y = C.monsky_washnitzer_gens()
sage: w = C.invariant_differential()
sage: w
1 dx/2y
sage: w.coeff()
1
sage: (x*y*w).coeff()
y*x
Used to obtain the raw coefficients of a differential, see SpecialHyperellipticQuotientElement.coeffs()
INPUT:
OUTPUT:
The raw coefficients of where self is
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: x,y = C.monsky_washnitzer_gens()
sage: w = C.invariant_differential()
sage: w.coeffs()
([(1, 0, 0, 0, 0)], 0)
sage: (x*w).coeffs()
([(0, 1, 0, 0, 0)], 0)
sage: (y*w).coeffs()
([(0, 0, 0, 0, 0), (1, 0, 0, 0, 0)], 0)
sage: (y^-2*w).coeffs()
([(1, 0, 0, 0, 0), (0, 0, 0, 0, 0), (0, 0, 0, 0, 0)], -2)
Computes the definite integral of self from to
.
INPUT:
OUTPUT:
EXAMPLES:
sage: K = pAdicField(5,7)
sage: E = EllipticCurve(K,[-31/3,-2501/108]) #11a
sage: P = E(K(14/3), K(11/2))
sage: w = E.invariant_differential()
sage: w.coleman_integral(P,2*P)
O(5^6)
sage: Q = E.lift_x(3)
sage: w.coleman_integral(P,Q)
2*5 + 4*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + O(5^6)
sage: w.coleman_integral(2*P,Q)
2*5 + 4*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + O(5^6)
sage: (2*w).coleman_integral(P, Q) == 2*(w.coleman_integral(P, Q))
True
Returns the power of in
where self is
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-3*x+1)
sage: x,y = C.monsky_washnitzer_gens()
sage: A = y^5 - x*y^3
sage: A.extract_pow_y(5)
[1, 0, 0, 0, 0]
sage: (A * C.invariant_differential()).extract_pow_y(5)
[1, 0, 0, 0, 0]
Computes the definite integral of self from to
.
INPUT:
OUTPUT:
EXAMPLES:
sage: K = pAdicField(5,7)
sage: E = EllipticCurve(K,[-31/3,-2501/108]) #11a
sage: P = E(K(14/3), K(11/2))
sage: w = E.invariant_differential()
sage: w.coleman_integral(P,2*P)
O(5^6)
sage: Q = E.lift_x(3)
sage: w.coleman_integral(P,Q)
2*5 + 4*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + O(5^6)
sage: w.coleman_integral(2*P,Q)
2*5 + 4*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + O(5^6)
sage: (2*w).coleman_integral(P, Q) == 2*(w.coleman_integral(P, Q))
True
Returns the maximum power of in
where self is
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-3*x+1)
sage: x,y = C.monsky_washnitzer_gens()
sage: w = y^5 * C.invariant_differential()
sage: w.max_pow_y()
5
sage: w = (x^2*y^4 + y^5) * C.invariant_differential()
sage: w.max_pow_y()
5
Returns the minimum power of in
where self is
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-3*x+1)
sage: x,y = C.monsky_washnitzer_gens()
sage: w = y^5 * C.invariant_differential()
sage: w.min_pow_y()
5
sage: w = (x^2*y^4 + y^5) * C.invariant_differential()
sage: w.min_pow_y()
4
Use homology relations to find and
such that this element is
equal to
, where
is given in terms of the
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: x,y = C.monsky_washnitzer_gens()
sage: w = (y*x).diff()
sage: w.reduce()
(y*x, 0 dx/2y)
sage: w = x^4 * C.invariant_differential()
sage: w.reduce()
(1/5*y*1, 4/5*1 dx/2y)
sage: w = sum(QQ.random_element() * x^i * y^j for i in [0..4] for j in [-3..3]) * C.invariant_differential()
sage: f, a = w.reduce()
sage: f.diff() + a - w
0 dx/2y
Use homology relations to find and
such that this element is
equal to
, where
is given in terms of the
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: E = HyperellipticCurve(x^3-4*x+4)
sage: x, y = E.monsky_washnitzer_gens()
sage: x.diff().reduce_fast()
(x, (0, 0))
sage: y.diff().reduce_fast()
(y*1, (0, 0))
sage: (y^-1).diff().reduce_fast()
((y^-1)*1, (0, 0))
sage: (y^-11).diff().reduce_fast()
((y^-11)*1, (0, 0))
sage: (x*y^2).diff().reduce_fast()
(y^2*x, (0, 0))
Use homology relations to eliminate negative powers of .
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-3*x+1)
sage: x,y = C.monsky_washnitzer_gens()
sage: (y^-1).diff().reduce_neg_y()
((y^-1)*1, 0 dx/2y)
sage: (y^-5*x^2+y^-1*x).diff().reduce_neg_y()
((y^-1)*x + (y^-5)*x^2, 0 dx/2y)
Use homology relations to eliminate negative powers of .
EXAMPLES:
sage: R.<x> = QQ['x']
sage: E = HyperellipticCurve(x^5-3*x+1)
sage: x, y = E.monsky_washnitzer_gens()
sage: (y^-1).diff().reduce_neg_y_fast()
((y^-1)*1, 0 dx/2y)
sage: (y^-5*x^2+y^-1*x).diff().reduce_neg_y_fast()
((y^-1)*x + (y^-5)*x^2, 0 dx/2y)
It leaves non-negative powers of alone:
sage: y.diff()
(-3*1 + 5*x^4) dx/2y
sage: y.diff().reduce_neg_y_fast()
(0, (-3*1 + 5*x^4) dx/2y)
Use homology relations to eliminate negative powers of .
Use homology relations to eliminate positive powers of .
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^3-4*x+4)
sage: x,y = C.monsky_washnitzer_gens()
sage: (y^2).diff().reduce_pos_y()
(y^2*1, 0 dx/2y)
sage: (y^2*x).diff().reduce_pos_y()
(y^2*x, 0 dx/2y)
sage: (y^92*x).diff().reduce_pos_y()
(y^92*x, 0 dx/2y)
sage: w = (y^3 + x).diff()
sage: w += w.parent()(x)
sage: w.reduce_pos_y_fast()
(y^3*1 + x, x dx/2y)
Use homology relations to eliminate positive powers of .
EXAMPLES:
sage: R.<x> = QQ['x']
sage: E = HyperellipticCurve(x^3-4*x+4)
sage: x, y = E.monsky_washnitzer_gens()
sage: y.diff().reduce_pos_y_fast()
(y*1, 0 dx/2y)
sage: (y^2).diff().reduce_pos_y_fast()
(y^2*1, 0 dx/2y)
sage: (y^2*x).diff().reduce_pos_y_fast()
(y^2*x, 0 dx/2y)
sage: (y^92*x).diff().reduce_pos_y_fast()
(y^92*x, 0 dx/2y)
sage: w = (y^3 + x).diff()
sage: w += w.parent()(x)
sage: w.reduce_pos_y_fast()
(y^3*1 + x, x dx/2y)
x.__init__(...) initializes x; see help(type(x)) for signature
Bases: sage.modules.module.Module
Class for the ring of Monsky–Washnitzer differentials over a given base ring.
Returns where the model of the underlying hyperelliptic curve
of self is given by
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.Q()
x^5 - 4*x + 4
Return a new differential ring which is self base-extended to
INPUT:
OUTPUT:
Self, base-extended to .
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.base_ring()
SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 4*x + 4) over Rational Field
sage: MW.base_extend(Qp(5,5)).base_ring()
SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = (1 + O(5^5))*x^5 + (1 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x + (4 + O(5^5))) over 5-adic Field with capped relative precision 5
Returns a new differential ring which is self with the coefficient
ring changed to .
INPUT:
OUTPUT:
Self, with the coefficient ring changed to .
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.base_ring()
SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 4*x + 4) over Rational Field
sage: MW.change_ring(Qp(5,5)).base_ring()
SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = (1 + O(5^5))*x^5 + (1 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x + (4 + O(5^5))) over 5-adic Field with capped relative precision 5
Returns the degree of , where the model of the underlying
hyperelliptic curve of self is given by
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.Q()
x^5 - 4*x + 4
sage: MW.degree()
5
Returns the dimension of self.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: K = Qp(7,5)
sage: CK = C.change_ring(K)
sage: MW = CK.invariant_differential().parent()
sage: MW.dimension()
4
Returns and caches , which is used in computing the image of
under a
-power lift of Frobenius to
.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.frob_Q(3)
-(60-48*y^2+12*y^4-y^6)*1 + (192-96*y^2+12*y^4)*x - (192-48*y^2)*x^2 + 60*x^3
sage: MW.Q()(MW.x_to_p(3))
-(60-48*y^2+12*y^4-y^6)*1 + (192-96*y^2+12*y^4)*x - (192-48*y^2)*x^2 + 60*x^3
sage: MW.frob_Q(11) is MW.frob_Q(11)
True
Returns the action of a -power lift of Frobenius on the basis
where is the degree of the underlying hyperelliptic curve.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: prec = 1
sage: p = 5
sage: MW = C.invariant_differential().parent()
sage: MW.frob_basis_elements(prec,p)
[((92000*y^-14-74200*y^-12+32000*y^-10-8000*y^-8+1000*y^-6-50*y^-4)*1 - (194400*y^-14-153600*y^-12+57600*y^-10-9600*y^-8+600*y^-6)*x + (204800*y^-14-153600*y^-12+38400*y^-10-3200*y^-8)*x^2 - (153600*y^-14-76800*y^-12+9600*y^-10)*x^3 + (63950*y^-14-18550*y^-12+1600*y^-10-400*y^-8+50*y^-6+5*y^-4)*x^4) dx/2y, (-(1391200*y^-14-941400*y^-12+302000*y^-10-76800*y^-8+14400*y^-6-1320*y^-4+30*y^-2)*1 + (2168800*y^-14-1402400*y^-12+537600*y^-10-134400*y^-8+16800*y^-6-720*y^-4)*x - (1596800*y^-14-1433600*y^-12+537600*y^-10-89600*y^-8+5600*y^-6)*x^2 + (1433600*y^-14-1075200*y^-12+268800*y^-10-22400*y^-8)*x^3 - (870200*y^-14-445350*y^-12+63350*y^-10-3200*y^-8+600*y^-6-30*y^-4-5*y^-2)*x^4) dx/2y, ((19488000*y^-14-15763200*y^-12+4944400*y^-10-913800*y^-8+156800*y^-6-22560*y^-4+1480*y^-2-10)*1 - (28163200*y^-14-18669600*y^-12+5774400*y^-10-1433600*y^-8+268800*y^-6-25440*y^-4+760*y^-2)*x + (15062400*y^-14-12940800*y^-12+5734400*y^-10-1433600*y^-8+179200*y^-6-8480*y^-4)*x^2 - (12121600*y^-14-11468800*y^-12+4300800*y^-10-716800*y^-8+44800*y^-6)*x^3 + (9215200*y^-14-6952400*y^-12+1773950*y^-10-165750*y^-8+5600*y^-6-720*y^-4+10*y^-2+5)*x^4) dx/2y, (-(225395200*y^-14-230640000*y^-12+91733600*y^-10-18347400*y^-8+2293600*y^-6-280960*y^-4+31520*y^-2-1480-10*y^2)*1 + (338048000*y^-14-277132800*y^-12+89928000*y^-10-17816000*y^-8+3225600*y^-6-472320*y^-4+34560*y^-2-720)*x - (172902400*y^-14-141504000*y^-12+58976000*y^-10-17203200*y^-8+3225600*y^-6-314880*y^-4+11520*y^-2)*x^2 + (108736000*y^-14-109760000*y^-12+51609600*y^-10-12902400*y^-8+1612800*y^-6-78720*y^-4)*x^3 - (85347200*y^-14-82900000*y^-12+31251400*y^-10-5304150*y^-8+367350*y^-6-8480*y^-4+760*y^-2+10-5*y^2)*x^4) dx/2y]
Kedlaya’s algorithm allows us to calculate the action of Frobenius on
the Monsky-Washnitzer cohomology. First we lift to
by setting
Pulling back the differential , we get
Use Newton’s method to calculate the square root.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: prec = 2
sage: p = 7
sage: MW = C.invariant_differential().parent()
sage: MW.frob_invariant_differential(prec,p)
((67894400*y^-20-81198880*y^-18+40140800*y^-16-10035200*y^-14+1254400*y^-12-62720*y^-10)*1 - (119503944*y^-20-116064242*y^-18+43753472*y^-16-7426048*y^-14+514304*y^-12-12544*y^-10+1568*y^-8-70*y^-6-7*y^-4)*x + (78905288*y^-20-61014016*y^-18+16859136*y^-16-2207744*y^-14+250880*y^-12-37632*y^-10+3136*y^-8-70*y^-6)*x^2 - (39452448*y^-20-26148752*y^-18+8085490*y^-16-2007040*y^-14+376320*y^-12-37632*y^-10+1568*y^-8)*x^3 + (21102144*y^-20-18120592*y^-18+8028160*y^-16-2007040*y^-14+250880*y^-12-12544*y^-10)*x^4) dx/2y
We use this to solve for the linear combination of
needed to clear all terms with
.
Returns as an element of self.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.invariant_differential()
1 dx/2y
Returns and caches , reduced via the relations coming from the
defining polynomial of the hyperelliptic curve.
EXAMPLES:
sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5-4*x+4)
sage: MW = C.invariant_differential().parent()
sage: MW.x_to_p(3)
x^3
sage: MW.x_to_p(5)
-(4-y^2)*1 + 4*x
sage: MW.x_to_p(101) is MW.x_to_p(101)
True
Bases: sage.rings.ring.CommutativeAlgebra
Specialised class for representing the quotient ring
, where
is an
arbitrary commutative base ring (in which 2 and 3 are invertible),
and
are elements of that ring.
Polynomials are represented internally in the form
where the
are
polynomials in
. Multiplication of polynomials always
reduces high powers of
(i.e. beyond
) to
powers of
.
Hopefully this ring is faster than a general quotient ring because it uses the special structure of this ring to speed multiplication (which is the dominant operation in the frobenius matrix calculation). I haven’t actually tested this theory though...
TODO: - Eventually we will want to run this in characteristic 3, so
we need to: (a) Allow to contain an
term, and
(b) Remove the requirement that 3 be invertible. Currently this is
used in the Toom-Cook algorithm to speed multiplication.
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: R
SpecialCubicQuotientRing over Ring of integers modulo 125 with polynomial T = x^3 + 124*x + 94
Get generators:
sage: x, T = R.gens()
sage: x
(0) + (1)*x + (0)*x^2
sage: T
(T) + (0)*x + (0)*x^2
Coercions:
sage: R(7)
(7) + (0)*x + (0)*x^2
Create elements directly from polynomials:
sage: A, z = R.poly_ring().objgen()
sage: A
Univariate Polynomial Ring in T over Ring of integers modulo 125
sage: R.create_element(z^2, z+1, 3)
(T^2) + (T + 1)*x + (3)*x^2
Some arithmetic:
sage: x^3
(T + 31) + (1)*x + (0)*x^2
sage: 3 * x**15 * T**2 + x - T
(3*T^7 + 90*T^6 + 110*T^5 + 20*T^4 + 58*T^3 + 26*T^2 + 124*T) + (15*T^6 + 110*T^5 + 35*T^4 + 63*T^2 + 1)*x + (30*T^5 + 40*T^4 + 8*T^3 + 38*T^2)*x^2
Retrieve coefficients (output is zero-padded):
sage: x^10
(3*T^2 + 61*T + 8) + (T^3 + 93*T^2 + 12*T + 40)*x + (3*T^2 + 61*T + 9)*x^2
sage: (x^10).coeffs()
[[8, 61, 3, 0], [40, 12, 93, 1], [9, 61, 3, 0]]
TODO: write an example checking multiplication of these polynomials against Sage’s ordinary quotient ring arithmetic. I can’t seem to get the quotient ring stuff happening right now...
Creates the element , where the
are polynomials in
.
INPUT:
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: A, z = R.poly_ring().objgen()
sage: R.create_element(z^2, z+1, 3)
(T^2) + (T + 1)*x + (3)*x^2
Return a list [x, T] where x and T are the generators of the ring (as element of this ring).
Note
I have no idea if this is compatible with the usual Sage ‘gens’ interface.
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: x, T = R.gens()
sage: x
(0) + (1)*x + (0)*x^2
sage: T
(T) + (0)*x + (0)*x^2
Return the underlying polynomial ring in .
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: R.poly_ring()
Univariate Polynomial Ring in T over Ring of integers modulo 125
Bases: sage.structure.element.CommutativeAlgebraElement
An element of a SpecialCubicQuotientRing.
Returns list of three lists of coefficients, corresponding to the
,
,
coefficients. The lists
are zero padded to the same length. The list entries belong to the
base ring.
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: p = R.create_element(t, t^2 - 2, 3)
sage: p.coeffs()
[[0, 1, 0], [123, 0, 1], [3, 0, 0]]
Multiplies this element by a scalar, i.e. just multiply each
coefficient of by the scalar.
INPUT:
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: x, T = R.gens()
sage: f = R.create_element(2, t, t^2 - 3)
sage: f
(2) + (T)*x + (T^2 + 122)*x^2
sage: f.scalar_multiply(2)
(4) + (2*T)*x + (2*T^2 + 119)*x^2
sage: f.scalar_multiply(t)
(2*T) + (T^2)*x + (T^3 + 122*T)*x^2
Returns this element multiplied by .
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: f = R.create_element(2, t, t^2 - 3)
sage: f
(2) + (T)*x + (T^2 + 122)*x^2
sage: f.shift(1)
(2*T) + (T^2)*x + (T^3 + 122*T)*x^2
sage: f.shift(2)
(2*T^2) + (T^3)*x + (T^4 + 122*T^2)*x^2
EXAMPLES:
sage: B.<t> = PolynomialRing(Integers(125))
sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
sage: x, T = R.gens()
sage: f = R.create_element(1 + 2*t + 3*t^2, 4 + 7*t + 9*t^2, 3 + 5*t + 11*t^2)
sage: f.square()
(73*T^5 + 16*T^4 + 38*T^3 + 39*T^2 + 70*T + 120) + (121*T^5 + 113*T^4 + 73*T^3 + 8*T^2 + 51*T + 61)*x + (18*T^4 + 60*T^3 + 22*T^2 + 108*T + 31)*x^2
Bases: sage.structure.element.CommutativeAlgebraElement
x.__init__(...) initializes x; see help(type(x)) for signature
Returns the raw coefficients of this element.
INPUT:
- R - an (optional) base-ring in which to cast the coefficients
OUTPUT:
- coeffs - a list of coefficients of powers of
for each power of
- n - an offset indicating the power of
of the first list element
EXAMPLES:
sage: R.<x> = QQ['x']
sage: E = HyperellipticCurve(x^5-3*x+1)
sage: x,y = E.monsky_washnitzer_gens()
sage: x.coeffs()
([(0, 1, 0, 0, 0)], 0)
sage: y.coeffs()
([(0, 0, 0, 0, 0), (1, 0, 0, 0, 0)], 0)
sage: a = sum(n*x^n for n in range(5)); a
x + 2*x^2 + 3*x^3 + 4*x^4
sage: a.coeffs()
([(0, 1, 2, 3, 4)], 0)
sage: a.coeffs(Qp(7))
([(0, 1 + O(7^20), 2 + O(7^20), 3 + O(7^20), 4 + O(7^20))], 0)
sage: (a*y).coeffs()
([(0, 0, 0, 0, 0), (0, 1, 2, 3, 4)], 0)
sage: (a*y^-2).coeffs()
([(0, 1, 2, 3, 4), (0, 0, 0, 0, 0), (0, 0, 0, 0, 0)], -2)
Note that the coefficient list is transposed compared to how they are stored and printed:
sage: a*y^-2
(y^-2)*x + (2*y^-2)*x^2 + (3*y^-2)*x^3 + (4*y^-2)*x^4
A more complicated example:
sage: a = x^20*y^-3 - x^11*y^2; a
(y^-3-4*y^-1+6*y-4*y^3+y^5)*1 - (12*y^-3-36*y^-1+36*y+y^2-12*y^3-2*y^4+y^6)*x + (54*y^-3-108*y^-1+54*y+6*y^2-6*y^4)*x^2 - (108*y^-3-108*y^-1+9*y^2)*x^3 + (81*y^-3)*x^4
sage: raw, offset = a.coeffs()
sage: a.min_pow_y()
-3
sage: offset
-3
sage: raw
[(1, -12, 54, -108, 81),
(0, 0, 0, 0, 0),
(-4, 36, -108, 108, 0),
(0, 0, 0, 0, 0),
(6, -36, 54, 0, 0),
(0, -1, 6, -9, 0),
(-4, 12, 0, 0, 0),
(0, 2, -6, 0, 0),
(1, 0, 0, 0, 0),
(0, -1, 0, 0, 0)]
sage: sum(c * x^i * y^(j+offset) for j, L in enumerate(raw) for i, c in enumerate(L)) == a
True
Can also be used to construct elements:
sage: a.parent()(raw, offset) == a
True
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
Bases: sage.rings.ring.CommutativeAlgebra
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
Returns , computed quickly.
The key here is that the formula for is messy
in terms of
, but varies nicely with
.
Where have degree at most
for each
. Pre-compute
for each
the “hard” way, and the rest are easy.
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
x.__init__(...) initializes x; see help(type(x)) for signature
Computes how much precision is required in matrix_of_frobenius to
get an answer correct to prec -adic digits.
The issue is that the algorithm used in matrix_of_frobenius
sometimes performs divisions by , so precision is lost
during the algorithm.
The estimate returned by this function is based on Kedlaya’s result
(Lemmas 2 and 3 of “Counting Points on Hyperelliptic Curves...”),
which implies that if we start with
-adic
digits, the total precision loss is at most
-adic
digits. (This estimate is somewhat less than the amount you would
expect by naively counting the number of divisions by
.)
INPUT:
OUTPUT: adjusted precision (usually slightly more than prec)
Computes the action of Frobenius on and on
, using Newton’s method (as suggested in Kedlaya’s
paper).
(This function does not yet use the cohomology relations - that happens afterwards in the “reduction” step.)
More specifically, it finds and
in
the quotient ring
, such that
where
(Here is
, and
is the
coefficient ring of
.)
and
are computed in the
SpecialCubicQuotientRing associated to
, so all powers
of
for
are reduced to powers of
.
INPUT:
OUTPUT:
Computes the action of Frobenius on and on
, using a
series expansion.
(This function computes the same thing as frobenius_expansion_by_newton(), using a different method. Theoretically the Newton method should be asymptotically faster, when the precision gets large. However, in practice, this functions seems to be marginally faster for moderate precision, so I’m keeping it here until I figure out exactly why it’s faster.)
(This function does not yet use the cohomology relations - that happens afterwards in the “reduction” step.)
More specifically, it finds F0 and F1 in the quotient ring
, such that
, and
where
. (Here
is
,
and
is the coefficient ring of
.)
and
are computed in the
SpecialCubicQuotientRing associated to
, so all powers
of
for
are reduced to powers of
.
It uses the sum
and
INPUT:
OUTPUT:
Computes the (constant) matrix used to calculate the linear
combinations of the needed to eliminate the
negative powers of
in the cohomology (i.e. in
reduce_negative()).
INPUT:
Tries to call x.lift(), presumably from the -adics to ZZ.
If this fails, it assumes the input is a power series, and tries to lift it to a power series over QQ.
This function is just a very kludgy solution to the problem of trying to make the reduction code (below) work over both Zp and Zp[[t]].
Computes the matrix of Frobenius on Monsky-Washnitzer cohomology,
with respect to the basis .
INPUT:
Q - cubic polynomial
defining an elliptic curve
by
. The coefficient ring of
should be a
-algebra in which the matrix of
frobenius will be constructed.
p - prime = 5 for which E has good reduction
M - integer = 2; -adic precision of
the coefficient ring
trace - (optional) the trace of the matrix, if
known in advance. This is easy to compute because it’s just the
of the curve. If the trace is supplied,
matrix_of_frobenius will use it to speed the computation (i.e. we
know the determinant is
, so we have two conditions, so
really only column of the matrix needs to be computed. It’s
actually a little more complicated than that, but that’s the basic
idea.) If trace=None, then both columns will be computed
independently, and you can get a strong indication of correctness
by verifying the trace afterwards.
Warning
THE RESULT WILL NOT NECESSARILY BE CORRECT TO M p-ADIC
DIGITS. If you want prec digits of precision, you need to use
the function adjusted_prec(), and then you need to reduce the
answer mod at the end.
OUTPUT:
2x2 matrix of frobenius on Monsky-Washnitzer cohomology, with entries in the coefficient ring of Q.
EXAMPLES:
A simple example:
sage: p = 5
sage: prec = 3
sage: M = monsky_washnitzer.adjusted_prec(p, prec)
sage: M
5
sage: R.<x> = PolynomialRing(Integers(p**M))
sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
sage: A
[3090 187]
[2945 408]
But the result is only accurate to prec digits:
sage: B = A.change_ring(Integers(p**prec))
sage: B
[90 62]
[70 33]
Check trace (123 = -2 mod 125) and determinant:
sage: B.det()
5
sage: B.trace()
123
sage: EllipticCurve([-1, 1/4]).ap(5)
-2
Try using the trace to speed up the calculation:
sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4),
... p, M, -2)
sage: A
[2715 187]
[1445 408]
Hmmm... it looks different, but that’s because the trace of our
first answer was only -2 modulo , not -2 modulo
. So the right answer is:
sage: A.change_ring(Integers(p**prec))
[90 62]
[70 33]
Check it works with only one digit of precision:
sage: p = 5
sage: prec = 1
sage: M = monsky_washnitzer.adjusted_prec(p, prec)
sage: R.<x> = PolynomialRing(Integers(p**M))
sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
sage: A.change_ring(Integers(p))
[0 2]
[0 3]
Here’s an example that’s particularly badly conditioned for using the trace trick:
sage: p = 11
sage: prec = 3
sage: M = monsky_washnitzer.adjusted_prec(p, prec)
sage: R.<x> = PolynomialRing(Integers(p**M))
sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 + 7*x + 8, p, M)
sage: A.change_ring(Integers(p**prec))
[1144 176]
[ 847 185]
The problem here is that the top-right entry is divisible by 11,
and the bottom-left entry is divisible by . So when
you apply the trace trick, neither
nor
is enough to compute the whole matrix to the
desired precision, even if you try increasing the target precision
by one. Nevertheless, matrix_of_frobenius knows
how to get the right answer by evaluating
instead:
sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 + 7*x + 8, p, M, -2)
sage: A.change_ring(Integers(p**prec))
[1144 176]
[ 847 185]
The running time is about O(p*prec**2) (times some logarithmic factors), so it’s feasible to run on fairly large primes, or precision (or both?!?!):
sage: p = 10007
sage: prec = 2
sage: M = monsky_washnitzer.adjusted_prec(p, prec)
sage: R.<x> = PolynomialRing(Integers(p**M))
sage: A = monsky_washnitzer.matrix_of_frobenius( # long time
... x^3 - x + R(1/4), p, M) # long time
sage: B = A.change_ring(Integers(p**prec)); B # long time
[74311982 57996908]
[95877067 25828133]
sage: B.det() # long time
10007
sage: B.trace() # long time
66
sage: EllipticCurve([-1, 1/4]).ap(10007) # long time
66
sage: p = 5
sage: prec = 300
sage: M = monsky_washnitzer.adjusted_prec(p, prec)
sage: R.<x> = PolynomialRing(Integers(p**M))
sage: A = monsky_washnitzer.matrix_of_frobenius( # long time
... x^3 - x + R(1/4), p, M) # long time
sage: B = A.change_ring(Integers(p**prec)) # long time
sage: B.det() # long time
5
sage: -B.trace() # long time
2
sage: EllipticCurve([-1, 1/4]).ap(5) # long time
-2
Let’s check consistency of the results for a range of precisions:
sage: p = 5
sage: max_prec = 60
sage: M = monsky_washnitzer.adjusted_prec(p, max_prec)
sage: R.<x> = PolynomialRing(Integers(p**M))
sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M) # long time
sage: A = A.change_ring(Integers(p**max_prec)) # long time
sage: result = [] # long time
sage: for prec in range(1, max_prec): # long time
... M = monsky_washnitzer.adjusted_prec(p, prec) # long time
... R.<x> = PolynomialRing(Integers(p^M),'x') # long time
... B = monsky_washnitzer.matrix_of_frobenius( # long time
... x^3 - x + R(1/4), p, M) # long time
... B = B.change_ring(Integers(p**prec)) # long time
... result.append(B == A.change_ring( # long time
... Integers(p**prec))) # long time
sage: result == [True] * (max_prec - 1) # long time
True
The remaining examples discuss what happens when you take the coefficient ring to be a power series ring; i.e. in effect you’re looking at a family of curves.
The code does in fact work...
sage: p = 11
sage: prec = 3
sage: M = monsky_washnitzer.adjusted_prec(p, prec)
sage: S.<t> = PowerSeriesRing(Integers(p**M), default_prec=4)
sage: a = 7 + t + 3*t^2
sage: b = 8 - 6*t + 17*t^2
sage: R.<x> = PolynomialRing(S)
sage: Q = x**3 + a*x + b
sage: A = monsky_washnitzer.matrix_of_frobenius(Q, p, M) # long time
sage: B = A.change_ring(PowerSeriesRing(Integers(p**prec), 't', default_prec=4)) # long time
sage: B # long time
[1144 + 264*t + 841*t^2 + 1025*t^3 + O(t^4) 176 + 1052*t + 216*t^2 + 523*t^3 + O(t^4)]
[ 847 + 668*t + 81*t^2 + 424*t^3 + O(t^4) 185 + 341*t + 171*t^2 + 642*t^3 + O(t^4)]
The trace trick should work for power series rings too, even in the badly- conditioned case. Unfortunately I don’t know how to compute the trace in advance, so I’m not sure exactly how this would help. Also, I suspect the running time will be dominated by the expansion, so the trace trick won’t really speed things up anyway. Another problem is that the determinant is not always p:
sage: B.det() # long time
11 + 484*t^2 + 451*t^3 + O(t^4)
However, it appears that the determinant always has the property that if you substitute t - 11t, you do get the constant series p (mod p**prec). Similarly for the trace. And since the parameter only really makes sense when it’s divisible by p anyway, perhaps this isn’t a problem after all.
Computes the matrix of Frobenius on Monsky-Washnitzer cohomology,
with respect to the basis , where
is the degree of
.
INPUT:
OUTPUT:
x
matrix
of Frobenius on Monsky-Washnitzer cohomology,
and list of differentials {f_i } such that
EXAMPLES:
sage: p = 5
sage: prec = 3
sage: R.<x> = QQ['x']
sage: A,f = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(x^5 - 2*x + 3, p, prec)
sage: A
[ 4*5 + O(5^3) 5 + 2*5^2 + O(5^3) 2 + 3*5 + 2*5^2 + O(5^3) 2 + 5 + 5^2 + O(5^3)]
[ 3*5 + 5^2 + O(5^3) 3*5 + O(5^3) 4*5 + O(5^3) 2 + 5^2 + O(5^3)]
[ 4*5 + 4*5^2 + O(5^3) 3*5 + 2*5^2 + O(5^3) 5 + 3*5^2 + O(5^3) 2*5 + 2*5^2 + O(5^3)]
[ 5^2 + O(5^3) 5 + 4*5^2 + O(5^3) 4*5 + 3*5^2 + O(5^3) 2*5 + O(5^3)]
Applies cohomology relations to reduce all terms to a linear
combination of and
.
INPUT:
OUTPUT:
Note
The algorithm operates in-place, so the data in coeffs is destroyed.
EXAMPLE:
sage: R.<x> = Integers(5^3)['x']
sage: Q = x^3 - x + R(1/4)
sage: coeffs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
sage: monsky_washnitzer.reduce_all(Q, 5, coeffs, 1)
(21, 106)
Applies cohomology relations to incorporate negative powers of
into the
term.
INPUT:
OUTPUT: The reduction is performed in-place. The output is placed in coeffs[offset]. Note that coeffs[i] will be meaningless for i offset after this function is finished.
EXAMPLE:
sage: R.<x> = Integers(5^3)['x']
sage: Q = x^3 - x + R(1/4)
sage: coeffs = [[10, 15, 20], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
sage: monsky_washnitzer.reduce_negative(Q, 5, coeffs, 3)
sage: coeffs[3]
[28, 52, 9]
sage: R.<x> = Integers(7^3)['x']
sage: Q = x^3 - x + R(1/4)
sage: coeffs = [[7, 14, 21], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
sage: monsky_washnitzer.reduce_negative(Q, 7, coeffs, 3)
sage: coeffs[3]
[245, 332, 9]
Applies cohomology relations to incorporate positive powers of
into the
term.
INPUT:
OUTPUT: The reduction is performed in-place. The output is placed in coeffs[offset]. Note that coeffs[i] will be meaningless for i offset after this function is finished.
EXAMPLE:
sage: R.<x> = Integers(5^3)['x']
sage: Q = x^3 - x + R(1/4)
sage: coeffs = [[1, 2, 3], [10, 15, 20]]
sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
sage: monsky_washnitzer.reduce_positive(Q, 5, coeffs, 0)
sage: coeffs[0]
[16, 102, 88]
sage: coeffs = [[9, 8, 7], [10, 15, 20]]
sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
sage: monsky_washnitzer.reduce_positive(Q, 5, coeffs, 0)
sage: coeffs[0]
[24, 108, 92]
Applies cohomology relation to incorporate term
into
and
terms.
INPUT:
OUTPUT: The reduction is performed in-place. The output is placed in coeffs[offset]. This method completely ignores coeffs[i] for i != offset.
EXAMPLE:
sage: R.<x> = Integers(5^3)['x']
sage: Q = x^3 - x + R(1/4)
sage: coeffs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
sage: monsky_washnitzer.reduce_zero(Q, coeffs, 1)
sage: coeffs[1]
[6, 5, 0]
INPUT:
OUTPUT:
EXAMPLES:
sage: from sage.schemes.elliptic_curves.monsky_washnitzer import transpose_list
sage: L = [[1, 2], [3, 4], [5, 6]]
sage: transpose_list(L)
[[1, 3, 5], [2, 4, 6]]