Introduction to the -adics¶
This tutorial outlines what you need to know in order to use
Our goal is to create a rich structure of different options that
will reflect the mathematical structures of the
Our design philosophy has been to create a robust, usable interface
working first, with simple-minded implementations underneath. We
want this interface to stabilize rapidly, so that users’ code does
not have to change. Once we get the framework in place, we can go
back and work on the algorithms and implementations underneath. All
of the current
If you do find bugs, have feature requests or general comments, please email sage-support@groups.google.com or roed@math.harvard.edu.
Terminology and types of -adics¶
To write down a general
We can think of
Secondly, as Cauchy sequences of rationals (or integers, in the
case of
Both of these representations give a natural way of thinking about
finite approximations to a
The absolute precision of a finite approximation
In the second representation, we can achieve the same thing by truncating a series
at
As above, we call this
Given any
There are three different representations of
the fixed modulus ring
the capped absolute precision ring
the capped relative precision ring, and
the capped relative precision field.
Fixed Modulus Rings¶
The first, and simplest, type of
The fixed modulus ring provides the lowest level of convenience, but it is also the one that has the lowest computational overhead. Once we have ironed out some bugs, the fixed modulus elements will be those most optimized for speed.
As with all of the implementations of Zp
, and passing in
'fixed-mod'
for the type
parameter. For example,
sage: R = Zp(5, prec = 10, type = 'fixed-mod', print_mode = 'series')
sage: R
5-adic Ring of fixed modulus 5^10
>>> from sage.all import *
>>> R = Zp(Integer(5), prec = Integer(10), type = 'fixed-mod', print_mode = 'series')
>>> R
5-adic Ring of fixed modulus 5^10
R = Zp(5, prec = 10, type = 'fixed-mod', print_mode = 'series') R
One can create elements as follows:
sage: a = R(375)
sage: a
3*5^3
sage: b = R(105)
sage: b
5 + 4*5^2
>>> from sage.all import *
>>> a = R(Integer(375))
>>> a
3*5^3
>>> b = R(Integer(105))
>>> b
5 + 4*5^2
a = R(375) a b = R(105) b
Now that we have some elements, we can do arithmetic in the ring.
sage: a + b
5 + 4*5^2 + 3*5^3
sage: a * b
3*5^4 + 2*5^5 + 2*5^6
>>> from sage.all import *
>>> a + b
5 + 4*5^2 + 3*5^3
>>> a * b
3*5^4 + 2*5^5 + 2*5^6
a + b a * b
Floor division (//) divides even though the result isn’t really known to the claimed precision; note that division isn’t defined:
sage: a // 5
3*5^2
>>> from sage.all import *
>>> a // Integer(5)
3*5^2
a // 5
sage: a / 5
Traceback (most recent call last):
...
ValueError: cannot invert non-unit
>>> from sage.all import *
>>> a / Integer(5)
Traceback (most recent call last):
...
ValueError: cannot invert non-unit
a / 5
Since elements don’t actually store their actual precision, one can only divide by units:
sage: a / 2
4*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 2*5^8 + 2*5^9
sage: a / b
Traceback (most recent call last):
...
ValueError: cannot invert non-unit
>>> from sage.all import *
>>> a / Integer(2)
4*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 2*5^8 + 2*5^9
>>> a / b
Traceback (most recent call last):
...
ValueError: cannot invert non-unit
a / 2 a / b
If you want to divide by a non-unit, do it using the //
operator:
sage: a // b
3*5^2 + 3*5^3 + 2*5^5 + 5^6 + 4*5^7 + 2*5^8 + 3*5^9
>>> from sage.all import *
>>> a // b
3*5^2 + 3*5^3 + 2*5^5 + 5^6 + 4*5^7 + 2*5^8 + 3*5^9
a // b
Capped Absolute Rings¶
The second type of implementation of
Once again, use Zp
to create a capped absolute
sage: R = Zp(5, prec = 10, type = 'capped-abs', print_mode = 'series')
sage: R
5-adic Ring with capped absolute precision 10
>>> from sage.all import *
>>> R = Zp(Integer(5), prec = Integer(10), type = 'capped-abs', print_mode = 'series')
>>> R
5-adic Ring with capped absolute precision 10
R = Zp(5, prec = 10, type = 'capped-abs', print_mode = 'series') R
We can do similar things as in the fixed modulus case:
sage: a = R(375)
sage: a
3*5^3 + O(5^10)
sage: b = R(105)
sage: b
5 + 4*5^2 + O(5^10)
sage: a + b
5 + 4*5^2 + 3*5^3 + O(5^10)
sage: a * b
3*5^4 + 2*5^5 + 2*5^6 + O(5^10)
sage: c = a // 5
sage: c
3*5^2 + O(5^9)
>>> from sage.all import *
>>> a = R(Integer(375))
>>> a
3*5^3 + O(5^10)
>>> b = R(Integer(105))
>>> b
5 + 4*5^2 + O(5^10)
>>> a + b
5 + 4*5^2 + 3*5^3 + O(5^10)
>>> a * b
3*5^4 + 2*5^5 + 2*5^6 + O(5^10)
>>> c = a // Integer(5)
>>> c
3*5^2 + O(5^9)
a = R(375) a b = R(105) b a + b a * b c = a // 5 c
Note that when we divided by 5, the precision of c
dropped.
This lower precision is now reflected in arithmetic.
sage: c + b
5 + 2*5^2 + 5^3 + O(5^9)
>>> from sage.all import *
>>> c + b
5 + 2*5^2 + 5^3 + O(5^9)
c + b
Division is allowed: the element that results is a capped relative field element, which is discussed in the next section:
sage: 1 / (c + b)
5^-1 + 3 + 2*5 + 5^2 + 4*5^3 + 4*5^4 + 3*5^6 + O(5^7)
>>> from sage.all import *
>>> Integer(1) / (c + b)
5^-1 + 3 + 2*5 + 5^2 + 4*5^3 + 4*5^4 + 3*5^6 + O(5^7)
1 / (c + b)
Capped Relative Rings and Fields¶
Instead of restricting the absolute precision of elements (which doesn’t make much sense when elements have negative valuations), one can cap the relative precision of elements. This is analogous to floating point representations of real numbers. As in the reals, multiplication works very well: the valuations add and the relative precision of the product is the minimum of the relative precisions of the inputs. Addition, however, faces similar issues as floating point addition: relative precision is lost when lower order terms cancel.
To create a capped relative precision ring, use Zp
as before.
To create capped relative precision fields, use Qp
.
sage: R = Zp(5, prec = 10, type = 'capped-rel', print_mode = 'series')
sage: R
5-adic Ring with capped relative precision 10
sage: K = Qp(5, prec = 10, type = 'capped-rel', print_mode = 'series')
sage: K
5-adic Field with capped relative precision 10
>>> from sage.all import *
>>> R = Zp(Integer(5), prec = Integer(10), type = 'capped-rel', print_mode = 'series')
>>> R
5-adic Ring with capped relative precision 10
>>> K = Qp(Integer(5), prec = Integer(10), type = 'capped-rel', print_mode = 'series')
>>> K
5-adic Field with capped relative precision 10
R = Zp(5, prec = 10, type = 'capped-rel', print_mode = 'series') R K = Qp(5, prec = 10, type = 'capped-rel', print_mode = 'series') K
We can do all of the same operations as in the other two cases, but precision works a bit differently: the maximum precision of an element is limited by the precision cap of the ring.
sage: a = R(375)
sage: a
3*5^3 + O(5^13)
sage: b = K(105)
sage: b
5 + 4*5^2 + O(5^11)
sage: a + b
5 + 4*5^2 + 3*5^3 + O(5^11)
sage: a * b
3*5^4 + 2*5^5 + 2*5^6 + O(5^14)
sage: c = a // 5
sage: c
3*5^2 + O(5^12)
sage: c + 1
1 + 3*5^2 + O(5^10)
>>> from sage.all import *
>>> a = R(Integer(375))
>>> a
3*5^3 + O(5^13)
>>> b = K(Integer(105))
>>> b
5 + 4*5^2 + O(5^11)
>>> a + b
5 + 4*5^2 + 3*5^3 + O(5^11)
>>> a * b
3*5^4 + 2*5^5 + 2*5^6 + O(5^14)
>>> c = a // Integer(5)
>>> c
3*5^2 + O(5^12)
>>> c + Integer(1)
1 + 3*5^2 + O(5^10)
a = R(375) a b = K(105) b a + b a * b c = a // 5 c c + 1
As with the capped absolute precision rings, we can divide, yielding a capped relative precision field element.
sage: 1 / (c + b)
5^-1 + 3 + 2*5 + 5^2 + 4*5^3 + 4*5^4 + 3*5^6 + 2*5^7 + 5^8 + O(5^9)
>>> from sage.all import *
>>> Integer(1) / (c + b)
5^-1 + 3 + 2*5 + 5^2 + 4*5^3 + 4*5^4 + 3*5^6 + 2*5^7 + 5^8 + O(5^9)
1 / (c + b)
Unramified Extensions¶
One can create unramified extensions of Zq
and Qq
.
In addition to requiring a prime power as the first argument,
Zq
also requires a name for the generator of the residue field.
One can specify this name as follows:
sage: R.<c> = Zq(125, prec=20); R # needs sage.libs.ntl
5-adic Unramified Extension Ring in c defined by x^3 + 3*x + 3
>>> from sage.all import *
>>> R = Zq(Integer(125), prec=Integer(20), names=('c',)); (c,) = R._first_ngens(1); R # needs sage.libs.ntl
5-adic Unramified Extension Ring in c defined by x^3 + 3*x + 3
R.<c> = Zq(125, prec=20); R # needs sage.libs.ntl
Eisenstein Extensions¶
It is also possible to create Eisenstein extensions of
sage: R = Zp(5, 2)
>>> from sage.all import *
>>> R = Zp(Integer(5), Integer(2))
R = Zp(5, 2)
Then define the polynomial yielding the desired extension.:
sage: S.<x> = ZZ[]
sage: f = x^5 - 25*x^3 + 15*x - 5
>>> from sage.all import *
>>> S = ZZ['x']; (x,) = S._first_ngens(1)
>>> f = x**Integer(5) - Integer(25)*x**Integer(3) + Integer(15)*x - Integer(5)
S.<x> = ZZ[] f = x^5 - 25*x^3 + 15*x - 5
Finally, use the ext
function on the ground field to create the
desired extension.:
sage: W.<w> = R.ext(f) # needs sage.libs.ntl sage.rings.padics
>>> from sage.all import *
>>> W = R.ext(f, names=('w',)); (w,) = W._first_ngens(1)# needs sage.libs.ntl sage.rings.padics
W.<w> = R.ext(f) # needs sage.libs.ntl sage.rings.padics
You can do arithmetic in this Eisenstein extension:
sage: (1 + w)^7 # needs sage.libs.ntl sage.rings.padics
1 + 2*w + w^2 + w^5 + 3*w^6 + 3*w^7 + 3*w^8 + w^9 + O(w^10)
>>> from sage.all import *
>>> (Integer(1) + w)**Integer(7) # needs sage.libs.ntl sage.rings.padics
1 + 2*w + w^2 + w^5 + 3*w^6 + 3*w^7 + 3*w^8 + w^9 + O(w^10)
(1 + w)^7 # needs sage.libs.ntl sage.rings.padics
Note that the precision cap increased by a factor of 5, since the
ramification index of this extension over