Computational Mathematics With SageMath 1
Computational Mathematics With SageMath 1
Mathematics
with SageMath
P. Zimmermann
A. Casamayou
N. Cohen
G. Connan
T. Dumont
L. Fousse
F. Maltey
M. Meulien
M. Mezzarobba
C. Pernet
N. M. Thiéry
E. Bray
J. Cremona
M. Forets
A. Ghitza
H. Thomas
Computational Mathematics with SageMath
Parts of this book are inherited from the book Calcul formel : mode d’emploi.
Exemples en Maple from Philippe Dumas, Claude Gomez, Bruno Salvy and Paul
Zimmermann, distributed under cc-by-sa 2.0 fr, in particular Sections 2.1.5, 2.3.5
and 5.3.
Parts of the Sage examples from Chapter 15 are inherited from the tutorials
of MuPAD-Combinat [HT04] and Sage-combinat. The enumeration of complete
binary trees in §15.1.2 is partly inspired from a classroom problem designed by
Florent Hivert.
Exercise 9 on Gauss problem is inspired from a problem designed by François
Pantigny, and Exercise 17 on the Magnus effect is extracted from a classroom
problem designed by Jean-Guy Stoliaroff.
Graphs from Figure 4.9 and their interpretation reproduce part of paragraph
III.4 from the “Que sais-je ?” book Les nombres premiers from Gérald Tenenbaum
and Michel Mendès France.
Preface
This book was written for those who want to efficiently use a computer algebra
system, and Sage in particular. Symbolic computation systems offer plenty of
functionality, and finding the right approach or command to solve a given problem
is sometimes difficult. A reference manual provides a detailed analytic description
of each function of the system; however, this is not very useful since usually we
do not know in advance the name of the function we are looking for! This book
provides another approach, by giving a global and synthetic point of view, while
insisting on the underlying mathematics, the classes of problems we can solve
and the corresponding algorithms.
The first part, more specific to Sage, will help getting to grips with this
system. This part is written to be understood by undergraduate students, and
partly by high school students. The other parts cover more specialised topics
encountered in undergraduate and graduate studies. Unlike in a reference manual,
the mathematical concepts are clearly explained before illustrating them with
Sage. This book is thus in the first place a book about mathematics.
To illustrate this book, Sage was a natural choice, since it is an open-source
system, that anybody can use, modify and redistribute at will. In particular
the student who learns Sage in high school will be able to continue to use it at
undergraduate or graduate levels, in a company, etc. Sage is still a relatively
young system, and despite its already extensive capacities, it does contain some
bugs. However, thanks to its very active community of developers, Sage evolves
very quickly. Every Sage user can report a bug — maybe together with its solution
— on trac.sagemath.org or via the sage-support list.
In writing this book, we have used version 8.2 of Sage. Nevertheless, the
examples should still work with later versions. However, some of the explanations
may no longer hold, for example the fact that Sage relies on Maxima for numerical
integrals.
When in December 2009 I asked Alexandre Casamayou, Guillaume Connan,
Thierry Dumont, Laurent Fousse, François Maltey, Matthias Meulien, Marc
Mezzarobba, Clément Pernet and Nicolas Thiéry to write the first version (in
French) of this book, all agreed with enthusiasm — including Nathann Cohen
who joined us later on. Given the success of the French version, it was clear
that an English version would be welcome. In March 2017, I decided to start
working on the English version; I want to thank once again those of the “dream
team” who helped me translating the text into English, updating the examples
to the new version of Sage, and moreover improving the content of the book
iv
Nancy, France
Paul Zimmermann
May 2018
Contents
1 First Steps 3
1.1 The Sage Program . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1 A Tool for Mathematics . . . . . . . . . . . . . . . . . . 3
1.2 Sage as a Calculator . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1 First Computations . . . . . . . . . . . . . . . . . . . . 7
1.2.2 Elementary Functions and Usual Constants . . . . . . . 10
1.2.3 On-Line Help and Automatic Completion . . . . . . . . . 11
1.2.4 Python Variables . . . . . . . . . . . . . . . . . . . . . . 12
1.2.5 Symbolic Variables . . . . . . . . . . . . . . . . . . . . . 13
1.2.6 First Graphics . . . . . . . . . . . . . . . . . . . . . . . 15
4 Graphics 75
4.1 2D Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.1 Graphical Representation of a Function . . . . . . . . . 75
4.1.2 Parametric Curve . . . . . . . . . . . . . . . . . . . . . 78
4.1.3 Curve in Polar Coordinates . . . . . . . . . . . . . . . . 78
4.1.4 Curve Defined by an Implicit Equation . . . . . . . . . 79
4.1.5 Data Plot . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.1.6 Displaying Solutions of Differential Equations . . . . . . 82
4.1.7 Evolute of a Curve . . . . . . . . . . . . . . . . . . . . . 88
4.2 3D Curves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5 Computational Domains 95
5.1 Sage is Object-Oriented . . . . . . . . . . . . . . . . . . . . . . . 95
5.1.1 Objects, Classes and Methods . . . . . . . . . . . . . . . 95
5.1.2 Objects and Polymorphism . . . . . . . . . . . . . . . . 97
5.1.3 Introspection . . . . . . . . . . . . . . . . . . . . . . . . 98
5.2 Elements, Parents, Categories . . . . . . . . . . . . . . . . . . . 99
5.2.1 Elements and Parents . . . . . . . . . . . . . . . . . . . 99
5.2.2 Constructions . . . . . . . . . . . . . . . . . . . . . . . . 100
5.2.3 Further Reading: Categories . . . . . . . . . . . . . . . . 101
5.3 Domains with a Normal Form . . . . . . . . . . . . . . . . . . . . 101
5.3.1 Elementary Domains . . . . . . . . . . . . . . . . . . . . 103
5.3.2 Compound Domains . . . . . . . . . . . . . . . . . . . . 107
CONTENTS vii
7 Polynomials 127
7.1 Polynomial Rings . . . . . . . . . . . . . . . . . . . . . . . . . . 128
7.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . 128
7.1.2 Building Polynomial Rings . . . . . . . . . . . . . . . . 128
7.1.3 Polynomials . . . . . . . . . . . . . . . . . . . . . . . . . 130
7.2 Euclidean Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . 134
7.2.1 Divisibility . . . . . . . . . . . . . . . . . . . . . . . . . 134
7.2.2 Ideals and Quotients . . . . . . . . . . . . . . . . . . . . 136
7.3 Factorisation and Roots . . . . . . . . . . . . . . . . . . . . . . . 137
7.3.1 Factorisation . . . . . . . . . . . . . . . . . . . . . . . . 137
7.3.2 Root Finding . . . . . . . . . . . . . . . . . . . . . . . . 139
7.3.3 Resultant . . . . . . . . . . . . . . . . . . . . . . . . . . 140
7.3.4 Galois Group . . . . . . . . . . . . . . . . . . . . . . . . 142
7.4 Rational Functions . . . . . . . . . . . . . . . . . . . . . . . . . 142
7.4.1 Construction and Basic Properties . . . . . . . . . . . . 142
7.4.2 Partial Fraction Decomposition . . . . . . . . . . . . . . 143
7.4.3 Rational Reconstruction . . . . . . . . . . . . . . . . . . 144
7.5 Formal Power Series . . . . . . . . . . . . . . . . . . . . . . . . . 147
7.5.1 Operations on Truncated Power Series . . . . . . . . . . 148
7.5.2 Solutions of an Equation: Series Expansions . . . . . . . 149
7.5.3 Lazy Power Series . . . . . . . . . . . . . . . . . . . . . 150
7.6 Computer Representation of Polynomials . . . . . . . . . . . . . . 151
IV Combinatorics 325
Annexes 405
B Bibliography 451
C Index 455
xii CONTENTS
Part I
This introductory chapter presents the way the Sage mathematical system thinks.
The next chapters of this first part develop the basic notions: how to make symbolic
or numerical computations in analysis, how to work with vectors or matrices,
write programs, deal with data lists, produce graphics, etc. The following parts
of this book treat in more detail some branches of mathematics where computers
are very helpful.
Access to Sage
To use Sage, all that is needed is a web browser. As a starter, the ser-
vice http://sagecell.sagemath.org/ allows for testing commands. To
go further, one can use one of the online services. For example, CoCalc
(http://cocalc.com, formerly known as SageMathCloud) gives access to a
lot of computational software and collaborative tools, together with course
management features. Developed and hosted by SageMathInc, an indepen-
dent company founded by William Stein, its access is free for casual use, and
most of its code is free. Other similar services are hosted by universities and
institutions. Ask around to find out what is available near you.
For regular usage, it is recommended to use Sage on one’s own machine,
installing it if this has not yet been done by the system administrator. Sage
is available for most operating systems: Linux, Windows, MacOS; see the
Download section on http://sagemath.org.
How to start Sage depends on the environment; therefore we do not go
into details here. On CoCalc one needs to create an account, a project, and
finally a Jupyter worksheet. On a desktop, the system may provide a startup
icon. Under Linux or MacOS, one typically would launch the command sage
––notebook jupyter in a terminal.
Resources
However Sage is accessed, one can use it via a web application enabling the
edition and sharing of notebooks which mix code, interactive computations,
equations, visualisations and text:
Figure 1.1 – The first occurrence of the name Sage, on a handwritten note of
W. Stein.
At first, Sage was both an acronym and a reference to the “sage” medicinal
plant. When the system later expanded to cover much of mathematics, the
acronym part was dropped. As Sage came to be known in larger circles,
and to avoid confusion with, for example, the business management software
of the same name, the official name was changed to SageMath. When the
context is unambiguous, for example in this book, it is traditional to just
use Sage.
sage: ( 1 + 2 * (3 + 5) ) * 2
34
The * character above stands for multiplication, which should not be omitted,
even in expressions like 2x. The power operation is written ˆ or **:
sage: 2^3
8
sage: 2**3
8
Please note the exact computation: the result of the above division, after sim-
plification, is the rational number 10/3 and not an approximation like 3.33333.
There is no limit1 to the size of integers or rational numbers:
sage: 2^10
1024
sage: 2^100
1267650600228229401496703205376
sage: 2^1000
1071508607186267320948425049060001810561404811705533607443750\
3883703510511249361224931983788156958581275946729175531468251\
8714528569231404359845775746985748039345677748242309854210746\
0506237114187795418215304647498358194126739876755916554394607\
7062914571196477686542167660429831652624386837205668069376
Integer operations
integer division a // b
remainder a % b
quotient and remainder divmod(a,b)
factorial n! factorial(n)
binomial coefficient nk
binomial(n,k)
sage: arccos(sin(pi/3))
arccos(1/2*sqrt(3))
sage: sqrt(2)
sqrt(2)
sage: exp(I*pi/7)
e^(1/7*I*pi)
One does not always get the expected results. Indeed, only few simplifications
are done automatically. If needed, it is possible to explicitly call a simplification
function:
sage: simplify(arccos(sin(pi/3)))
1/6*pi
We will see in §2.1 how to tune the simplification of expressions. Of course, it
is also possible to compute numerical approximations of the results, with an
accuracy as large as desired:
sage: numerical_approx(6*arccos(sin(pi/3)), digits=60)
3.14159265358979323846264338327950288419716939937510582097494
sage: numerical_approx(sqrt(2), digits=60)
1.41421356237309504880168872420969807856967187537694807317668
sage: arc<tab>
Possible completions are:
arc arccos arccosh arccot arccoth arccsc arccsch
arcsec arcsech arcsin arcsinh arctan arctan2 arctanh
e
To restore the original value, one can type for example:
sage: from sage.all import pi
or alternatively
sage: restore()
which restores to their default value all predefined variables and functions. The
reset() function performs an even more complete reset, in particular it clears all
user-defined variables.
2*z + 3
How can we give a value to a symbolic variable appearing in an expression? One
uses the substitution operation, as in:
sage: x = SR.var('x')
sage: expr = sin(x); expr
sin(x)
sage: expr(x=1)
sin(1)
The substitution in symbolic expressions is discussed in detail in the next chapter.
Exercise 1. Explain step by step what happens during the following instructions:
sage: u = SR.var('u')
sage: u = u+1
sage: u = u+1
sage: u
u + 2
3 In this book, we will often write x = var(’x’) instead of the better but cumbersome form
arctan(sqrt(2)) and pi/2-arctan(1/sqrt(2)) are considered equal. In fact, when one compares
two expressions with bool(x==y), Sage tries to prove that their difference is zero, and returns
True if that succeeds.
18 CHAP. 2. ANALYSIS AND ALGEBRA
+ *
^ * 2 + +
x 2 3 x x 1 x 2
Figure 2.1 – Two symbolic expressions representing the same mathematical object.
Symbolic Functions
sage: p = (x+y)*(x+1)^2
sage: p2 = p.expand(); p2
x^3 + x^2*y + 2*x^2 + 2*x*y + x + y
whereas the collect method groups terms together according to the powers of a
given variable:
sage: p2.collect(x)
x^3 + x^2*(y + 2) + x*(2*y + 1) + y
Those methods do not only apply to polynomials in symbolic variables, but also
to polynomials in more complex sub-expressions like sin x:
sage: ((x+y+sin(x))^2).expand().collect(sin(x))
x^2 + 2*x*y + y^2 + 2*(x + y)*sin(x) + sin(x)^2
For rational functions, the combine method enables us to group together terms
with common denominator; the partial_fraction method performs the partial
fraction decomposition over Q. (To specify a different decomposition field, we
refer the reader to §7.4.)
The more useful representations are the expanded form for a polynomial, and
the reduced form P/Q with P and Q expanded in the case of a fraction. When
20 CHAP. 2. ANALYSIS AND ALGEBRA
(x−1)x y2 b c 1
Fraction r= x2 −7
+ x2 −7
+ a
+ a
+ x+1
(x−1)x+y 2 b+c 1
r.combine() x2 −7
+ a
+ x+1
1
Fraction r=
(x3 +1)y2
−(x−2) 1
r.partial_fraction(x) +
3 (x2 −x+1)y 2 3 (x+1)y 2
two polynomials or fractions are written in this form, it suffices to compare their
coefficients to decide if they are equal: we say they are in normal form.
2.1.4 Assumptions
During a computation, the symbolic variables appearing in expressions are in
general considered as taking potentially any value in the complex plane. This
22 CHAP. 2. ANALYSIS AND ALGEBRA
2.2 Equations
We now deal with equations and how to solve them; the main functions are
summarised in Table 2.3.
Scalar equations
Symbolic solution solve
Roots (with multiplicities) roots
Numerical solving find_root
sage: eq.rhs()
0
then solve it for z with solve:
sage: solve(eq,
√
z)
√
2
2 cos(ϕ) −1−1 2 cos(ϕ)2 −1+1
z=− cos(ϕ) , z = cos(ϕ)
" ( 31 ) √
√ √ √ − I 3−1
− 1 I 3 + 1 1
3 59 −
1
+
2 18 2 √ √ ( 1 ) , 1 ,
3 18 3 59 − 12 3
1
√
( 31 )
√ √ √ − −I 3 − 1
− 1 −I 3 + 1 1
3 59 −
1
+
2 18 2 √ √ ( 1 ) , 1 ,
1
3 18 3 59 − 21 3
( 31 )
√ √
1 3 59 − 1 +
−2
18 2 √ √ ( 1 ) , 1
3 18 3 59 − 21 3
1
sage: solve(x^(1/x)==(1/x)^x, x)
[(1/x)^x == x^(1/x)]
sage: y = function('y')(x)
sage: desolve(diff(y,x,x) + x*diff(y,x) + y == 0, y, [0,0,1])
-1/2*I*sqrt(2)*sqrt(pi)*erf(1/2*I*sqrt(2)*x)*e^(-1/2*x^2)
2.3 Analysis
This section is a quick introduction of useful functions in real analysis. For more
advanced usage or more details, we refer to the following chapters, in particular
about numerical integration (Chapter 14), non-linear equations (Chapter 12), and
differential equations (Chapter 10).
2.3.1 Sums
The sum function computes symbolic sums. Let us obtain for example the sum of
the n first positive integers:
sage: k, n = var('k, n')
sage: sum(k, k, 1, n).factor()
1
2 (n + 1)n
To compute the corresponding power series, we should tell Sage that the
modulus2 of q is less than 1:
sage: assume(abs(q) < 1)
sage: sum(a*q^k, k, 0, infinity)
a
− q−1
This recurrence
P is easily obtained when computing by two different methods the telescopic
sum (k + 1)p+1 − kp+1 .
0≤k≤n
2.3.2 Limits
To determine a limit, we use the limit command or its alias lim. Let us compute
the following limits:
√3
x−2
a) lim √ ;
x→8 3
x + 19 − 3
cos π4 − x − tan x
b) limπ .
x→ 4 1 − sin π4 + x
2.3.3 Sequences
The above functions enable us to study sequences of numbers. We illustrate this
by comparing the growth of an exponential sequence and a geometric sequence.
100
n
Example. (A sequence study) Let us consider the sequence un = 100 n.
1.6e90
1.4e90
1.2e90
1e90
8e89
6e89
4e89
2e89
0
5 10 15 20 25 30 35 40
The sequence is thus increasing up to index 21, then decreasing after index
22.
30 CHAP. 2. ANALYSIS AND ALGEBRA
sage: ((1+arctan(x))^(1/x)).series(x==0, 3)
(e) + (− 21 e)x + ( 18 e)x2 + O x3
sage: (ln(2*sin(x))).series(x==pi/6, 3)
√
2 3
( 3)(− 61 π + x) + (−2)(− 61 π + x) + O − 216
1
(π − 6 x)
sage: k = var('k')
sage: sum(1/k^2, k, 1, infinity),\
....: sum(1/k^4, k, 1, infinity),\
....: sum(1/k^5, k, 1, infinity)
1 2 1 4
6 π , 90 π , ζ(5)
We notice that the partial sum of the first 12 terms already yields 95 significant
digits of π!
Example. (Convergence of a series) Let us study the convergence of the
series p
X
sin π 4 n2 + 1 .
n≥0
We can then apply the taylor function to this new expression of the general
term:
2.3.6 Derivatives
The derivative function (with alias diff) computes the derivative of a symbolic
expression or function.
sage: diff(sin(x^2), x)
2*x*cos(x^2)
sage: function('f')(x); function('g')(x); diff(f(g(x)), x)
f(x)
g(x)
D[0](f)(g(x))*diff(g(x), x)
sage: diff(ln(f(x)), x)
diff(f(x), x)/f(x)
2.3.8 Integrals
To compute an indefinite or definite integral, we use integrate as a function or
method (or its alias integral):
sage: sin(x).integral(x, 0, pi/2)
1
sage: integrate(1/(1+x^2), x)
arctan(x)
3A function f is said harmonic when its Laplacian ∆f = ∂12 f + ∂22 f is zero.
34 CHAP. 2. ANALYSIS AND ALGEBRA
Z √
1/ 2
f (t)
2. For N ∈ N, let us define J = dt. Prove lim SN = J.
0
1 − t8 N →+∞
This fabulous formula was found on September 19, 1995 by Simon Plouffe, in
collaboration with David Bailey and Peter Borwein. Thanks to computation
derived from the BBP formula, the 4 000 000 000 000 000-th digit of π in radix 2
was computed in 2001.
−ı ∧ →
1. Show that →
− →
−
D = − 1e S and deduce the ellipse eccentricity.
−ı is colinear with the vector →
2. Show that →
− → −
S ∧ D.
→
− →
−
3. Show that →
−ı ∧ N = − p S and deduce the ellipse parameter p.
e
4. Compute the half major axis a of the ellipse in term of the parameter p and the
eccentricity e.
5. Numerical application: in the plane with a Cartesian coordinate system, we
consider the following points:
A1 ( 01 ) , A2 ( 22 ) , A3 ( 3.5
0 ), O ( 00 ) .
Matrix reduction
Eigenvalues of a matrix eigenvalues
Eigenvectors of a matrix eigenvectors_right
Jordan normal form reduction jordan_form
Minimal polynomial minimal_polynomial
Characteristic polynomial characteristic_polynomial
Exercise 11 (A matrix equation). Let us recall the factorisation lemma for linear
maps. Let E, F, G be K-vector spaces of finite dimension. Let u ∈ L(E, F ) and
v ∈ L(E, G). Then the following assertions are equivalent:
i) there exists w ∈ L(F, G) such that v = w ◦ u,
ii) Ker(u) ⊂ Ker(v).
We search all solutions to this problem in a concrete case. Let
−2 1 1
1 2 −1
A= 8 1 −5 and C= 2 −1 −1 .
4 3 −3 −5 0 3
The minimal polynomial of A admits a simple root and a double root; thus A
is not diagonalisable. However, its minimal polynomial being split into linear
factors, A is triangularisable.
sage: A.eigenvectors_right()
[(1, [(1, −1, 1)] , 1) , (−2, [(1, −1, 0)] , 2)]
sage: A.jordan_form(transformation=True)
1 0 0 1 1 1
0 −2 1 , −1 −1 0
0 0 −2 1 0 −1
1 −1/2
Example. Let us diagonalise the matrix A = −1/2 −1
. We first try the
jordan_form function:
sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]])
sage: A.jordan_form()
Traceback (most recent call last):
...
RuntimeError: Some eigenvalue does not exist in Rational Field.
A small difficulty appears here: the eigenvalues are not all rational.
sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]])
sage: A.minimal_polynomial()
x^2 - 5/4
We therefore have to change the base field.
sage: R = QQ[sqrt(5)]
sage: A = A.change_ring(R)
sage: A.jordan_form(transformation=True, subdivide=False)
1
sqrt 5 0
2 , 1 1
1 −sqrt + 2 sqrt + 2
0 − sqrt 5 5 5
2
This is to be interpreted as:
1 √
2 5 √ 0 √ 1 √ 1
,
0 − 12 5 − 5+2 5+2
√ √
√2 6 √2
Example. Let us diagonalise the matrix A = √6 √3 3 .
2 3 1
Here, we have to work in an extension of degree 4 of the field Q, for example
as follows.
sage: K.<sqrt2> = NumberField(x^2 - 2)
sage: L.<sqrt3> = K.extension(x^2 - 3)
sage: A = matrix(L, [[2, sqrt2*sqrt3, sqrt2], \
....: [sqrt2*sqrt3, 3, sqrt3], \
....: [sqrt2, sqrt3, 1]])
2.4. BASIC LINEAR ALGEBRA 39
sage: A.jordan_form(transformation=True)
6 0 0 √ √ 1 1 0
0 0 0 , 1 2 3
2
1
√ √0 √1
0 0 0 2 2 − 2 − 3
40 CHAP. 2. ANALYSIS AND ALGEBRA
Programming and Data Structures
3
The two preceding chapters introduced mathematical computations using one-line
commands, but Sage also allows programs with sequences of instructions.
The Sage computer algebra system is in fact an extension of the Python1 com-
puter language, and allows, with a few exceptions, to use the Python programming
constructs.
The commands described in the previous chapters show that it is not necessary
to know the Python language to use Sage; this chapter explains how to use
the Python programming structures within Sage. Since we only present basic
programming, this chapter can be skipped by the reader fluent in Python; the
examples are chosen among the most classical ones encountered in mathematics,
so that the reader can quickly grasp the Python programming constructs, by
analogy with known programming languages.
This chapter presents in particular the paradigm of structured programming
with loops and tests, then describes functions dealing with lists and other data
structures.
3.1 Syntax
3.1.1 General Syntax
The instructions are generally processed line by line. Python considers the
sharp symbol “#” as the beginning of a comment, until the end of the line.
The semi-colon “;” separates several instructions written on the same line:
1 The Sage version considered here uses Python 2.7, which slightly differs from Python 3.
42 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
In addition to these keywords, we have the constants None (empty value, named
NULL in other languages), True and False, and several functions predefined by
Python or Sage like len, cos and integrate. It is better not to use these as
variable names, otherwise some functionalities might no longer be available. The
interpreter knows some additional commands, like quit to exit the Sage session.
We will discover other commands like time or timeit later in this book.
Some symbols have a special meaning in Sage. They are explained in Table 3.2.
3.1. SYNTAX 43
sage: a, b = b, a
sage: a, b
(20, 10)
The assignment a, b = b, a is equivalent to swapping the values of a and b
using an auxiliary variable:
sage: temp = a; a = b; b = temp # equivalent to: a, b = b, a
The following trick swaps the values of a and b without any auxiliary variable,
using additions and subtractions:
sage: x, y = var('x, y'); a = x ; b = y
sage: a, b
(x, y)
sage: a = a + b ; b = a - b ; a = a - b
sage: a, b
(y, x)
The instruction a = b = c = 0 assigns the same value, here 0, to several
variables; the instructions x += 5 and n *= 2 are respectively equivalent to x =
x+5 and n = n*2.
The comparison between two objects is performed by the double equal sign
“==”:
sage: 2 + 2 == 2^2, 3 * 3 == 3^3
(True, False)
3.2 Algorithmics
The paradigm of structured programming consists in designing a computer program
as a finite sequence of instructions, which are executed in order. Those instructions
can be atomic or composed:
3.2.1 Loops
Enumeration Loops. An enumeration loop performs the same computation
for all integer values of an index k ∈ {a, . . . , b}: the following example3 outputs
the beginning of the multiplication table by 7:
3 When using Sage in a terminal, such a block of instructions must be ended by an additional
empty line, which will be implicit in the whole book. This is not necessary when using Sage
through a web browser.
3.2. ALGORITHMICS 45
sage: S = 0 sage: S = 0
sage: for k in [1..3]: sage: for k in [1..3]:
... S = S+k ... S = S+k
sage: S = 2*S ... S = 2*S
sage: S sage: S
On the left the instruction S = 2*S is executed only once at the end of the loop,
while on the right it is executed at every iteration, which explains the different
results:
S = (0 + 1 + 2 + 3) · 2 = 12 S = ((((0 + 1) · 2) + 2) · 2 + 3) · 2 = 22.
This kind of loop will be useful to compute a given term of a recurrence, cf. the
examples at the end of this section.
The syntax for k in [a..b] for an enumeration loop is the simplest one
and can be used without any problem for 104 or 105 iterations; its drawback
is that it explicitly constructs the list of all possible values of the loop variable
before executing the iteration block, however it manipulates Sage integers of type
Integer (see §5.3.1). Several ..range functions allow iterations with two possible
choices. The first choice is: either construct the list of possible values before
starting the loop, or determine those values along with the loop iterations. The
second choice is between Sage integers4 (Integer) and Python integers (int),
those two integer types having slightly different properties. In case of doubt, the
[a..b] form should be preferred.
While Loops. The other kind of loops are the while loops. Like the enumeration
loops, they execute a certain number of times the same sequence of instructions;
4 The commands srange, sxrange and [...] also work on rational and floating-point numbers:
however, here the number of repetitions is not known a priori, but depends on a
condition.
The while loop, as its name says, executes instructions while a given condition
is fulfilled. The following example computes the sum of the squares of non-negative
integers whose exponential is less or equal to 106 , i.e., 12 + 22 + · · · + 132 :
sage: S = 0 ; k = 0 # The sum S starts to 0
sage: while e^k <= 10^6: # e^13 <= 10^6 < e^14
....: S = S + k^2 # accumulates the squares k^2
....: k = k + 1
sage: S
819
The last instruction returns the value of the variable S and outputs the result:
X 13
X
S= k2 = k 2 = 819, e13 ≈ 442413 ≤ 106 < e14 ≈ 1202604.
k∈N k=0
ek ≤106
The above instruction block contains two assignments: the first one accumulates
the new term, and the second one moves to the next index. Those two instructions
are indented in the same way inside the while loop structure.
The following example is another typical example of while loop. For a given
number x ≥ 1, it seeks the unique integer n ∈ N satisfying 2n−1 ≤ x < 2n , i.e.,
the smallest integer with x < 2n . The program below compares x to 2n , whose
value is successively 1, 2, 4, 8, etc.; it performs this computation for x = 104 :
sage: x = 10^4; u = 1; n = 0 # invariant: u = 2^n
sage: while u <= x: n = n+1; u = 2*u # or n += 1; u *= 2
sage: n
14
As long as the condition 2n ≤ x is satisfied, this program computes the new values
n + 1 and 2n+1 = 2 · 2n of the two variables n and u, and stores them in place
of n and 2n . The loop ends when the condition is no longer fulfilled, i.e., when
3.2. ALGORITHMICS 47
x < 2n :
Note that the body of a while loop is never executed when the condition is false
at the first test.
As seen above, small command blocks can be typed on a single line after the
colon “:”, without creating a new indented block starting at the next line.
The for and while loops repeat a given number of times the same
instructions. The break command inside a loop interrupts it before its
end, and the continue command goes directly to the next iteration. Those
commands thus allow — among other things — to check the terminating
condition at every place in the loop.
The four examples below determine the smallest positive integer x satis-
fying log(x + 1) ≤ x/10. The first program (top left) uses a for loop with at
most 100 tries which terminates once the first solution is found; the second
program (top right) looks for the smallest solution and might not terminate
if the condition is never fulfilled; the third (bottom left) is equivalent to the
first one with a more complex loop condition; finally the fourth (bottom
right) has an unnecessarily complex structure, whose unique goal is to exhibit
the continue command. In all cases the final value x is 37.0.
for x in [1.0..100.0]: x=1.0
if log(x+1)<=x/10: break while log(x+1)>x/10:
x=x+1
x=1.0 x=1.0
while log(x+1)>x/10 and x<100: while True:
x=x+1 if log(x+1)>x/10:
x=x+1
continue
break
The return command (which ends the execution of a function and defines
its result, cf. §3.2.3) offers yet another way to abort early from an instruction
block.
to the recurrence relation. The first iteration computes u1 from u0 for n = 1, the
second one likewise from u1 to u2 when n = 2, and the last of the n iterations
updates U from un−1 to un :
sage: U = 1.0 # or U = 1. or U = 1.000
sage: for n in [1..20]:
....: U = 1 / (1 + U^2)
sage: U
0.682360434761105
The same program with the integer U = 1 instead of the floating-point number
U = 1.0 on the first line will perform exact computations on rational numbers;
then u10 becomes a rational number with several hundreds digits, and u20 has
hundreds of thousands digits. Exact computations are useful when rounding
errors accumulate in numerical approximations. Otherwise, by hand or with the
computer, the computations on numerical approximations of a dozen digits are
faster than those on integers or rational numbers of thousand digits or more.
The sums or products admitting recurrence formulas are computed the same
way:
Xn
Sn = (2k)(2k + 1) = 2 · 3 + 4 · 5 + · · · + (2n)(2n + 1),
k=1
S0 = 0, Sn = Sn−1 + (2n)(2n + 1) for n ∈ N − {0}.
The following programming method follows that of recurrent sequences; starting
from 0, we add successive terms for k = 1, k = 2, ..., until k = n:
sage: S = 0 ; n = 10
sage: for k in [1..n]:
....: S = S + (2*k) * (2*k+1)
sage: S
1650
This example highlights a general method to compute a sum; however, in this
simple case, a symbolic computation yields the general answer:
sage: n, k = var('n, k') ; res = sum(2*k*(2*k+1), k, 1, n)
sage: res, factor(res) # result expanded, factorised
(4/3*n^3 + 3*n^2 + 5/3*n, 1/3*(4*n + 5)*(n + 1)*n)
Those results might also be obtained with the pen and pencil method from
well-known sums:
n
X n
X
n(n + 1) n(n + 1)(2n + 1)
k= , k2 = ,
2 6
k=1 k=1
n
X n
X n
X 2 n (n + 1)(2n + 1)
2k (2k + 1) = 4 k2 + 2 k= + n(n + 1)
3
k=1 k=1 k=1
n(n + 1) (4n + 2) + 3 n(n + 1)(4n + 5)
= = .
3 3
3.2. ALGORITHMICS 49
In this case,
the two sequences converge to the same limit ℓ,
∀p ∈ N up ≤ lim un = ℓ = lim vn ≤ vp ,
n→+∞ n→+∞
u +v v −u
ℓ − p2 p ≤ p 2 p .
(S2n )n∈N and (S2n+1 )n∈N satisfy Eq. (3.1), with common limit say ℓ. Hence the
sequence (Sn )n∈N also converges to ℓ and we have S2p+1 ≤ ℓ = limn→+∞ Sn ≤
S2p .
The following program illustrates this result for the sequence ak = 1/k 3 from
k = 1, by storing in two variables U and V the partial sums S2n and S2n+1
enclosing the limit:
sage: U = 0.0 # the sum S0 is empty, of value zero
sage: V = -1.0 # S1 = -1/1^3
sage: n = 0 # U and V contain S(2n) and S(2n+1)
sage: while U-V >= 1.0e-6:
....: n = n+1 # n += 1 is equivalent
....: U = V + 1/(2*n)^3 # going from S(2n-1) to S(2n)
....: V = U - 1/(2*n+1)^3 # going from S(2n) to S(2n+1)
sage: V, U
(-0.901543155458595, -0.901542184868447)
The main loop increases the value of n until the two terms S2n and S2n+1 are
close enough. The two variables U and V contain two consecutive terms; the loop
body computes S2n from S2n−1 , and then S2n+1 from S2n , whence the crossed
assignments to U and V.
The program halts when two consecutive terms S2n+1 and S2n surrounding
the limit are close enough, the approximation error — without taking into account
rounding errors — satisfies then 0 ≤ a2n+1 = S2n − S2n+1 ≤ 10−6 .
Programming these five alternating series is similar:
X (−1)n X (−1)n X (−1)n
, , ,
log n n n2
n≥2 n≥1 n≥1
X (−1)n X X (−1)n
, (−1)n e−n ln n = .
n4 nn
n≥1 n≥1 n≥1
The terms of those series converge more or less rapidly to 0, thus the limit
approximations require more or fewer computations.
Looking for a precision of 3, 10, 20 or 100 digits on the limits of these series
consists in solving the following inequalities:
3
1/ log n ≤ 10−3 ⇐⇒ n ≥ e(10 ) ≈ 1.97 · 10434
1/n ≤ 10−3 103
⇐⇒ n ≥ √ 1/n ≤ 10−10 ⇐⇒ n ≥ 1010
1/n2 ≤ 10−3 ⇐⇒ n ≥ 103 ≈ 32 1/n2 ≤ 10−10 ⇐⇒ n ≥ 105
1/n4 ≤ 10−3 ⇐⇒ n ≥ (103 )1/4 ≈ 6 1/n4 ≤ 10−10 ⇐⇒ n ≥ 317
−n log n
e ≤ 10−3 ⇐⇒ n ≥ 5 e−n log n
≤ 10−10 ⇐⇒ n ≥ 10
1/n2 ≤ 10−20 ⇐⇒ n ≥ 1010 1/n2 ≤ 10−100 ⇐⇒ n ≥ 1050
1/n4 ≤ 10−20 ⇐⇒ n ≥ 105 1/n4 ≤ 10−100 ⇐⇒ n ≥ 1025
−n log n
e ≤ 10−20 ⇐⇒ n ≥ 17 e−n log n
≤ 10−100 ⇐⇒ n ≥ 57
In the simplest cases solving these inequalities yields an index n from which
the value Sn is close enough to the limit ℓ, and then a for enumeration loop is
3.2. ALGORITHMICS 51
3.2.2 Conditionals
Another important instruction is the conditional (or test), which enables us to
execute some instructions depending on the result of a boolean condition. The
structure of the conditional and two possible syntaxes are:
if a condition: if a condition:
an instruction sequence an instruction sequence
else:
another instruction sequence
The Syracuse sequence is defined using a parity condition:
(
un /2 if un is even
u0 ∈ N − {0}, un+1 =
3un + 1 if un is odd.
52 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
The Collatz conjecture says — with no known proof in 2017 — that for all initial
values u0 ∈ N − {0}, there exists a rank n for which un = 1. The next terms are
then 4, 2, 1, 4, 2, etc. The computation of each term of this sequence requires a
parity test. This condition is checked within a while loop, which determines the
smallest n ∈ N satisfying un = 1:
sage: u = 6 ; n = 0
sage: while u != 1: # the test u <> 1 is also possible
....: if u % 2 == 0: # the operator % yields the remainder
....: u = u//2 # //: Euclidean division quotient
....: else:
....: u = 3*u+1
....: n = n+1
sage: n
8
Checking whether un is even is done by comparing to 0 the remainder of the
Euclidean division of un by 2. The variable n at the end of the block is the
number of iterations. The loop ends as soon as un = 1; for example if u0 = 6
then u8 = 1 and 8 = min{p ∈ N|up = 1}:
p = 0 1 2 3 4 5 6 7 8 9 10 ···
up = 6 3 10 5 16 8 4 2 1 4 2 ···
Verifying step-by-step the correct behaviour of the loop can be done using a
spy-instruction print(u, n) inside the loop body.
The if instruction also allows nested tests in the else branch using the elif
keyword. The two following structures are thus equivalent:
Like for loops, small instruction sequences may be put after the colon on the
same line, rather than in an indented block below.
with zero, one or several arguments, which returns (resp. does not return) a result.
Let us define the function (x, y) 7→ x2 + y 2 :
sage: def fct2 (x, y):
....: return x^2 + y^2
sage: a = var('a')
sage: fct2 (a, 2*a)
5*a^2
The function evaluation ends with the return command, whose argument, here
x2 + y 2 , is the result of the function.
A procedure is like a function, but does not return any value, and without
any return instruction the instruction body of the procedure is evaluated until
its end. In fact a procedure returns the None value, which means “nothing”.
By default, all variables appearing in a function are considered local variables.
Local variables are created at each function call, destroyed at the end of the
function, and do not interact with other variables of the same name. In particular,
global variables are not modified by the evaluation of a function having local
variables of the same name:
sage: def foo (u):
....: t = u^2
....: return t*(t+1)
sage: t = 1 ; u = 2
sage: foo(3), t, u
(90, 1, 2)
It is possible to modify a global variable from within a function, with the global
keyword:
sage: a = b = 1
sage: def f(): global a; a = b = 2
sage: f(); a, b
(2, 1)
The AHmean function has two parameters u and v which are local variables, whose
initial values are those of the function arguments; for example with AHmean (1.,
2.) the function body begins with u = 1.0 and v = 2.0.
The structured programming paradigm recommends to have the return
statement at the very end of the function body. However, it is possible to put it
in the middle of the instruction block, then the following instructions will not be
executed. And the function body might contain several return occurrences.
Translating the mathematician’s viewpoint into the computer suggests the
use of functions that return results from their arguments, instead of procedures
that output those results with a print command. The Sage computer algebra
system is itself built on numerous functions like exp or solve, which return a
result, for example a number, an expression, a list of solutions, etc.
The two following functions yield the same result for a nonnegative integer
argument n; the first function uses the iterative method with a for loop, while
the second one is a word-by-word translation of the above recursive definition:
sage: def fact1 (n):
....: res = 1
....: for k in [1..n]: res = res*k
....: return res
The function fib1 below applies an iterative scheme to compute terms of the
Fibonacci sequence: the variables U and V store the two previous values before
computing the next one:
sage: def fib1 (n):
....: if n == 0 or n == 1: return n
....: else:
....: U = 0 ; V = 1 # the initial terms u0 and u1
....: for k in [2..n]: W = U+V ; U = V ; V = W
....: return V
sage: fib1(8)
3.2. ALGORITHMICS 55
21
The for loop applies the relation un = un−1 + un−2 from n = 2. Note: a parallel
assignment U,V = V,U+V in place of W=U+V ; U=V ; V=W would avoid the need
of an auxiliary variable W, and would translate the order-1 vectorial recurrence
Xn+1 = f (Xn ) with f (a, b) = (b, a + b), for Xn = (un , un+1 ). Those iterative
methods are efficient, however programming them requires to manually deal with
variables corresponding to different terms of the sequence.
On the contrary, the recursive function fib2 follows more closely the mathe-
matical definition of the Fibonacci sequence, which makes its programming and
understanding easier:
sage: def fib2 (n):
....: if 0 <= n <= 1: return n # for n = 0 or n = 1
....: else: return fib2(n-1) + fib2(n-2)
The result of this function is the value returned by the conditional statement: either
0 or 1 respectively for n = 0 and n = 1, otherwise the sum fib2(n-1)+fib2(n-2);
each branch of the test consists of a return instruction.
This method is however less efficient since several computations are duplicated.
For example fib2(5) evaluates fib2(3) and fib2(4), which are in turn evaluated
in the same manner. Therefore, Sage computes twice fib2(3) and three times
fib2(2). This recursive process ends by the evaluation of either fib2(0) or
fib2(1), of value 0 or 1, and the evaluation of fib2(n) eventually consists in
computing un by adding un ones, and un−1 zeroes. The total number of additions
performed to compute un is thus un+1 − 1. This number grows very quickly, and
no computer is able to compute u100 this way.
Other methods are also possible, for example remembering the intermediate
terms using the decorator @cached_function, or using properties of matrix
powers: the following paragraph shows how to compute the millionth term of this
sequence. For example, compare the efficiency of the function fib2 defined above
with the following one, for example on n = 30:
sage: @cached_function
sage: def fib2a (n):
....: if 0 <= n <= 1: return n
....: else: return fib2a(n-1) + fib2a(n-2)
Integer powers often arise in mathematics and computer science; this paragraph
discusses a general method to compute an in a much faster way than the naive
method. The sequence (un )n∈N below satisfies un = an ; this follows by induction
2
from the equalities a2k = (ak ) and ak+1 = a ak :
1
if n = 0,
2
un = un/2 if n is even positive, (3.2)
a un−1 if n is odd.
therefore:
u2 = a2 , u4 = u22 = a4 , u5 = a a4 = a5 ,
u10 = u25 = a10 , u11 = a a10 = a11 .
The computation of un only involves terms uk with k ∈ {0, ..., n − 1}, and is thus
well performed in a finite number of operations.
This example also shows that u11 is obtained after the evaluation of 6 terms u10 ,
u5 , u4 , u2 , u1 and u0 , which performs 6 multiplications only. In general, the
computation of un requires between log n/ log 2 and 2 log n/ log 2 multiplications.
Indeed, un is obtained from uk , k ≤ n/2, with one or two additional steps,
according to the parity of n. This method is thus much faster than the naive one
when n is large: about twenty products for n = 104 instead of 104 products:
However, this method is not always the best one; the following operations using
b, c, d and f perform 5 products to compute a15 , whereas the above method —
using u, v, w, x and y — requires 6 products, without counting the initial product
a · 1:
b = a2 c = ab = a3 d = c2 = a6 f = cd = a9 df = a15 : 5 products;
u = a2 v = au = a3 w = v 2 = a6
x = aw = a7 y = x2 = a14 ay = a15 : 6 products.
The recursive function pow1 uses the recurrent sequence (3.2) to compute an :
sage: def pow1 (a, n):
....: if n == 0: return 1
....: elif n % 2 == 0: b = pow1 (a, n//2); return b*b
....: else: return a * pow1(a, n-1)
2048
The fact that pow2(a, n) returns an is shown by verifying that after each iteration
the values of the variables u, v and k satisfy v uk = an , for whatever parity of k.
Before the first iteration v = 1, u = a and k = n; after the last one k = 0, thus
v = an .
The successive values of the integer variable k are nonnegative, and they form
a decreasing sequence. Hence this variable can only take a finite number of values
before being zero and terminating the loop.
Despite their apparent differences — pow1 is recursive, while pow2 is iterative
— those two functions express almost the same algorithm: the only difference is
2 k
that a2k is evaluated as (ak ) in pow1, and as (a2 ) in pow2, through the update
of the variable u.
The method presented here is not limited to the computation of an where
a is a number and n a positive integer, it applies to any associative law (which
is needed to preserve usual properties of iterated products). For instance, by
replacing the integer 1 by the m × m unit matrix 1m , the two above functions
would evaluate powers of square matrices. Those functions show how to efficiently
implement the power operator “ˆ” upon multiplication, and are similar to the
method implemented within Sage.
For example, using powers of matrices enables us to compute much larger
terms of the Fibonacci sequence:
0 1 un
A= , Xn = , AXn = Xn+1 , An X0 = Xn .
1 1 un+1
58 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
The corresponding Sage program fits in two lines, and the wanted result is the
first coordinate of the matrix product An X0 , which effectively works for n = 107 ;
the fib3 and fib4 programs are equivalent, and their efficiency comes from the
fact that Sage implements a fast exponentiation method:
sage: def fib3 (n):
....: A = matrix ([[0, 1], [1, 1]]) ; X0 = vector ([0, 1])
....: return (A^n*X0)[0]
The % operator replaces the expressions to its right in the character string to its
left, in place of the placeholders like %2d or %.4f. In the above example the %4d
specifier adds some left padding spaces to the string representing k 4 , to get at
least four characters. Likewise, the %.4f placeholder in ’pi = %.4f’ % n(pi)
outputs pi = 3.1416 with four digits after the decimal point.
In a terminal, the raw_input(’message’) command prints the text message,
waits a keyboard input validated by the hEnteri key, and returns the user-given
character string.
5 The output of len is a Python integer of type int, to get a Sage integer we write
Integer(len(..)).
60 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
The command L[p:q] extracts the sub-list [L[p], L[p+1], ..., L[q-1]],
which is empty if q ≤ p. Negative indices allow to reference the last terms of the
list; finally L[p:] is equivalent to L[p:len(L)], and L[:q] to L[0:q]:
Similarly to the L[n] = ... command which modifies an element of the list, the
assignment L[p:q] = [...] substitutes all elements between index p included
and index q excluded:
Therefore, L[:1] = [] and L[-1:] = [] delete respectively the first and last
term of a list, and likewise L[:0] = [a] and L[len(L):] = [a] insert the
element a respectively in front and in tail of the list. More generally the following
equalities hold:
The operator in checks whether a list contains a given element, while “==”
compares two lists elementwise. The two sub-lists below with positive or negative
indices are equal:
While we have considered so far lists with integer elements, list elements can be
any Sage object: numbers, expressions, other lists, etc.
3.3. LISTS AND OTHER DATA STRUCTURES 61
The map command builds this “map”: the following example applies the trigono-
metric function cos to a list of usual angles:
sage: map (cos, [0, pi/6, pi/4, pi/3, pi/2])
[1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0]
A user-defined function — with def — or a lambda-expression might also be used
as first argument of map; the following command is equivalent to the above, using
the function t 7→ cos t:
sage: map (lambda t: cos(t), [0, pi/6, pi/4, pi/3, pi/2])
[1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0]
The lambda command is followed by the parameters separated by commas,
and the colon must be followed by exactly one expression, which is the function
result (without the return keyword).
62 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
A lambda expression may contain a test, whence the following functions are
equivalent:
sage: map (N, map (cos, [0, pi/6, pi/4, pi/3, pi/2]))
[1.00000000000000, 0.866025403784439, 0.707106781186548,
0.500000000000000, 0.000000000000000]
In the two following examples, we combine the if and filter tests with the
comprehension for to determine a list of primes congruent to 1 modulo 4, then a
list of squares of prime numbers:
sage: filter (is_prime, [4*n+1 for n in [0..20]])
[5, 13, 17, 29, 37, 41, 53, 61, 73]
sage: [n^2 for n in [1..20] if is_prime(n)]
[4, 9, 25, 49, 121, 169, 289, 361]
In the first case the is_prime test is performed after the computation of 4n + 1,
while in the second one the primality test is done before the computation of the
square n2 .
The reduce function operates by associativity from left to right on the elements
of a list. Let us define the following operation, say ⋆:
The first argument of reduce is a two-parameter function, the second one is the
list of its arguments:
sage: reduce (lambda x, y: 10*x+y, [1, 2, 3, 4])
1234
A third optional argument gives the image of an empty list:
sage: reduce (lambda x, y: 10*x+y, [9, 8, 7, 6], 1)
19876
This third argument usually corresponds to the neutral element of the operation
that is applied. The following example computes a product of odd integers:
sage: L = [2*n+1 for n in [0..9]]
sage: reduce (lambda x, y: x*y, L, 1)
654729075
The Sage functions add6 and prod apply directly the reduce operator to compute
sums and products; the three examples below yield the same result. The list
form enables us to add an optional second argument which stands for the neutral
element, 1 for the product and 0 for the sum, or a unit matrix for a matrix
product:
sage: prod ([2*n+1 for n in [0..9]], 1) # a list with for
654729075
sage: prod ( 2*n+1 for n in [0..9]) # without a list
654729075
sage: prod (n for n in [0..19] if n%2 == 1)
654729075
The function any associated to the or operator, and the function all to the and
operator, have similar syntax. Their evaluation terminates as soon as the result
True or False obtained for one term avoids the evaluation of the next terms:
6 Do not confuse add with sum, which looks for a symbolic expression of a sum.
64 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
The commands L.pop(i) and L.pop() remove the element of index i, or the
last one, and return the removed element; their behaviour is described by these
two functions:
def pop1 (L, i): def pop2 (L):
a = L[i] return pop1 (L, len(L)-1)
L[i:i+1] = []
return a
3.3. LISTS AND OTHER DATA STRUCTURES 67
In addition, L.index(x) returns the index of the first element equal to x, and
L.remove(x) removes the first element equal to x. These commands raise an
error when x is not in the list. Finally, the command del L[p:q] is equivalent
to L[p:q] = [], and del L[i] removes the ith element.
Contrary to what happens in several other computer languages, these functions
modify in-place the list L, without creating a new list.
sage: fct1([1..10])
[[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]]
The second function below goes only once through the list, and constructs the
two result lists element by element:
sage: def fct2 (L):
....: res0 = [] ; res1 = []
....: for k in L:
....: if k%2 == 0: res0.append(k) # or res0[len(res0):] = [k]
....: else: res1.append(k) # or res1[len(res1):] = [k]
....: return [res0, res1]
This program replaces the for loop and the auxiliary variables by a recursive call
and an additional parameter:
sage: def fct3a (L, res0, res1):
....: if L == []: return [res0, res1]
....: elif L[0]%2 == 0: return fct3a(L[1:], res0+[L[0]], res1)
....: else: return fct3a (L[1:], res0, res1+[L[0]])
The very extensive Python library re may also be used to search sub-strings,
words and regular expressions.
Checking for shared data structures can be done in Sage using the is binary
operator; if the answer is true, all modifications will have a side effect on both
variables:
sage: L1 = [11, 22, 33] ; L2 = L1 ; L3 = L1[:]
sage: [L1 is L2, L2 is L1, L1 is L3, L1 == L3]
[True, True, False, True]
Copy operations on lists operate on one level only. As a consequence, modifying
an element in a list of lists has a side effect despite the list copy at the outer
level:
sage: La = [1, 2, 3] ; L1 = [1, La] ; L2 = copy(L1)
sage: L1[1][0] = 5 # [1, [5, 2, 3]] for L1 and L2
sage: [L1 == L2, L1 is L2, L1[1] is L2[1]]
[True, False, True]
The following instruction duplicates a list on two levels:
70 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
3.3.9 Dictionaries
Last but not least, Python, and thus Sage, provides the notion of dictionary. Like
a phone book, a dictionary associates a value to a given key.
The keys of a dictionary might be of any immutable type: numbers, characters
strings, tuples, etc. The syntax is like lists, using assignments from the empty
dictionary dict() which can be written {} too:
sage: D={}; D['one']=1; D['two']=2; D['three']=3; D['ten']=10
sage: D['two'] + D['three']
5
The above example shows how to add an entry (key,value) to a dictionary, and
how to access the value associated to a given key via D[...].
The operator in checks whether a key is in a dictionary, and the commands
del D[x] or D.pop(x) erase the entry of key x in this dictionary.
The following example demonstrates how a dictionary can be used to represent
a function on a finite set:
E = {a0 , a1 , a2 , a3 , a4 , a5 }, f (a0 ) = b0 , f (a1 ) = b1 , f (a2 ) = b2 ,
f (a3 ) = b0 , f (a4 ) = b3 , f (a5 ) = b3 .
3.3. LISTS AND OTHER DATA STRUCTURES 73
The two following commands, applied to the keys or to the dictionary itself
are, by construction, equivalent to D.values():
The following test on the number of distinct values determines if the function
represented by D is injective, len(D) being the number of dictionary entries:
sage: def injective(D):
....: return len(D) == len (Set(D.values()))
The first two commands below build the image f (F ) and the preimage f −1 (G)
of subsets F and G of a function defined by the dictionary D; the last one
constructs the dictionary DR corresponding to the inverse function f −1 of f ,
assumed to be bijective:
sage: Set([D[t] for t in F])
sage: Set([t for t in D if D[t] in G])
sage: DR = dict((D[t], t) for t in D)
74 CHAP. 3. PROGRAMMING AND DATA STRUCTURES
4
Graphics
4.1 2D Graphics
Several definitions of a plane curve are possible: as the graph of a function, from
a parametric system, using polar coordinates, or by an implicit equation. We
detail these four cases, and give some examples of data visualisation.
0.8
0.6
0.4
0.2
-0.2
1
Figure 4.1 – Graph of x 7→ x sin x
.
• linestyle: style of the line, either dotted with ’:’, dash-dotted with ’-.’,
or solid with the default value ’-’.
2 4
1.5 3
1 2
0.5 1
-0.5 -1
-1 -2
-1.5 -3
-2 -4
0.5
-8 -6 -4 -2 2 4 6 8
-0.5
-1
In the code above, f is a piecewise function on [−π; π], defined with the piecewise
instruction. To extend f by 2π-periodicity, the simplest solution is to give an
expression valid for any real number, such as saw(x)/abs(saw(x)). The sum of
the 20 first terms of the Fourier series is:
4 sin(3x) sin(5x) sin(19π)
S= sin(x) + + + ··· + .
π 3 5 19
78 CHAP. 4. GRAPHICS
sage: t = var('t')
sage: x = cos(t) + cos(7*t)/2 + sin(17*t)/3
sage: y = sin(t) + sin(7*t)/2 + cos(17*t)/3
sage: g = parametric_plot((x, y), (t, 0, 2*pi))
sage: g.show(aspect_ratio=1)
1.5
0.5
-0.5
-1
-1.5
1 1
Figure 4.4 – Parametric curve of equation x(t) = cos(t) + 2
cos(7t) + 3
sin(17t), y(t) =
sin(t) + 21 sin(7t) + 13 cos(17t).
1
2
0.5
1
-3 -2 -1 1 2 3 -1 -0.5 0.5 1
-1
-0.5
-2
-1
-3
Exercise 12. Draw the family of Pascal conchoids of polar equation ρ(θ) = a + cos θ
when the parameter a varies from 0 to 2 by steps of 0.1.
-3 -2 -1 1 2 3
-1
-2
-3
Figure 4.6 – Curve g2 defined by the equation cos(z 4 ) = 1.
9 350
8
300
7
6 250
5 200
4 150
3
100
2
1 50
2 4 6 8 10 5 10 15
option bins whose default value is 50), the height of each bar being proportional
to the number of corresponding values.
sage: liste = [10 + floor(10*sin(i)) for i in range(100)]
sage: bar_chart(liste)
sage: finance.TimeSeries(liste).plot_histogram(bins=20)
0.16
0.14
15
0.12
0.1
10
0.08
0.06
5 0.04
0.02
10 20 30 40 50 5 10 15
It often arises that the list of data values we want to study is stored in a
spreadsheet format. The Python csv package enables us to import such data
4.1. 2D GRAPHICS 81
stored in the csv format. For example, let us assume that we want to plot the
histogram of grades of a school class, which are in column 3 of the file exam01.csv.
To extract the grades from this column, we will use the following instructions (in
general, the first lines of such a file contain text, therefore we deal with potential
non-matching lines with the try keyword):
sage: import csv
sage: reader = csv.reader(open("exam01.csv"))
sage: grades = []; list = []
sage: for line in reader: 0.25
....: f = float(i)
0.05
....: pass 2 4 6 8 10 12 14
....: else:
....: list.append(f)
sage: finance.TimeSeries(list).plot_histogram(bins=20)
To draw a list of linked points (resp. non-linked), we use the line(p)
(resp. point(p) or points(p)) command, p being a list of 2-element lists (or
tuples) giving abscissa and ordinate of the points.
Example. (Random walk) Starting from the origin O, a particle moves a
distance ℓ every t seconds, in a random direction, independently of the preceding
moves. Let us draw an example of particle trajectory. The red line goes from the
initial to the final position.
sage: n, l, x, y = 10000, 1, 0, 0; p = [[0, 0]]
sage: for k in range(n):
....: theta = (2 * pi * random()).n(digits=5)
....: x, y = x + l * cos(theta), y + l * sin(theta)
....: p.append([x, y])
sage: g1 = line([p[n], [0, 0]], color='red', thickness=2)
sage: g1 += line(p, thickness=.4); g1.show(aspect_ratio=1)
Example. (Uniformly distributed sequences) Given a real sequence (un )n∈N∗ ,
we construct the polygonal line whose successive vertices are the points in the
complex plane X
zN = e2iπun .
n≤N
50
40
30
20
10
-10
-20
-30
√
• un = ⌊n ln(n)⌋ 2 and N = 10000,
√
• un = pn 2 and N = 10000 (here pn is the n-th prime).
√
Figure 4.9 is obtained as follows (here for un = n 2):
sage: length = 200; n = var('n')
sage: u = lambda n: n * sqrt(2)
sage: z = lambda n: exp(2 * I * pi * u(n)).n()
sage: vertices = [CC(0, 0)]
sage: for n in range(1, length):
....: vertices.append(vertices[n - 1] + CC(z(n)))
sage: line(vertices).show(aspect_ratio=1)
We see that the curve√4.9a is amazingly regular, which suggests that the
uniform√ distribution of n 2 modulo 1 is deterministic. In the case of un =
n ln(n) 2, the values apparently seem random modulo 1. However, the associated
curve 4.9b is remarkably well structured. The curve 4.9c has the same kind
of structure as the second one. Finally,
√ the curve 4.9d shows the completely
different nature of primes modulo 1/ 2: the spirals have disappeared and the
aspect looks very similar to a random walk un (Figure 4.8). It thus looks as
though “prime numbers make use of all the randomness they are given...”
For a detailed interpretation of these curves, we refer the reader to the book
(in French) Les nombres premiers of Gérald Tenenbaum and Michel Mendès
France [TMF00].
Exercise 13 (Drawing terms of a recurrent sequence). We consider the sequence
(un )n∈N defined by: nu0 = a,
∀n ∈ N, un+1 = u2n − 14 .
60
0.6
40
0.4
0.2 20
-0.2
-20
-0.4
√ √
(a) Case un = n 2. (b) Case un = n ln(n) 2.
50
40
40
30 30
20
20
10
10
-80 -60 -40 -20 20
-10
-30
-10
-40
√ √
(c) Case un = ⌊n ln(n)⌋ 2. (d) Case un = pn 2.
the desolve function, which is studied in more detail in Chapter 10. To solve
a differential equation numerically, Sage provides several tools: desolve_rk4
(which uses the same syntax as desolve, and which is enough to solve differential
equations at undergraduate level), odeint (which calls the SciPy package), and
finally ode_solver (which calls the GSL library, and whose use is detailed in
Section 14.2). The functions desolve_rk4 and odeint return a list of points,
which is easy to draw using the line command; we will use them in this section
to draw numerical solutions.
Example. (First-order linear differential equation) Let us draw the integral
curves of the differential equation xy ′ − 2y = x3 .
sage: x = var('x'); y = function('y')
sage: DE = x*diff(y(x), x) == 2*y(x) + x^3
sage: desolve(DE, [y(x),x])
(_C + x)*x^2
sage: sol = []
sage: for i in srange(-2, 2, 0.2):
....: sol.append(desolve(DE, [y(x), x], ics=[1, i]))
....: sol.append(desolve(DE, [y(x), x], ics=[-1, i]))
sage: g = plot(sol, x, -2, 2)
sage: y = var('y')
sage: g += plot_vector_field((x, 2*y+x^3), (x,-2,2), (y,-1,1))
sage: g.show(ymin=-1, ymax=1)
To decrease the computation time, it would be better here to define “by hand”
the general solution of the equation, and to create a list of particular solutions (as
done in the solution of Exercise 14), instead of solving the differential equation
several times with different initial conditions. We could also compute a numerical
solution of this equation (with the desolve_rk4 function) to draw its integral
curves:
sage: x = var('x'); y = function('y')
sage: DE = x*diff(y(x), x) == 2*y(x) + x^3
sage: g = Graphics() # creates an empty graph
sage: for i in srange(-2, 2, 0.2):
....: g += line(desolve_rk4(DE, y(x), ics=[1, i],\
1 1
0.5 0.5
-0.5 -0.5
-1 -1
10
-4 -2 2 4
-2
population 35
40
Rabbits 30
35
25
30
20
25
foxes
20 15
15 10
10 5
Foxes
5 0
0 2 4 6 8 10 12 14
time 0 10 20 30
rabbits
40 50 60
The flow lines (which are identical to trajectories, since the flow is stationary) are parallel
to the velocity. We search a parametric expression of the flow lines; we have thus to
solve the differential system:
dr dθ vθ
= vr and = .
dt dt r
By using coordinates scaled by the radius a of the cylinder, we may assume a = 1. Draw
the flow lines for α ∈ {0.1, 0.5, 1, 1.25}.
88 CHAP. 4. GRAPHICS
The Magnus effect was proposed to build propulsion systems made from large vertical
rotating cylinders able to produce a longitudinal thrust when the wind is perpendicular
to the ship (this was the case of the Baden-Baden rotor ship built by Anton Flettner,
which crossed the Atlantic in 1926).
The derivative of Equation (4.1), combined with (4.2), yields the system:
12
10
-8 -6 -4 -2 2 4 6 8
As recalled above, the evolute of a curve is also the locus of its centres of curvature.
Using the circle function, let us draw some osculating circles of the parabola.
The centre of curvature Ω at a point Mt = (x(t), y(t)) of the curve has coordinates:
x′2 + y ′2 x′2 + y ′2
xΩ = x + −y ′ , and yΩ = y + x′ ,
x′ y ′′− x′′ y ′ x′ y ′′
− x′′ y ′
sage: t = var('t'); p = 2
sage: x(t) = t; y(t) = t^2 / (2 * p); f(t) = [x(t), y(t)]
sage: df(t) = [x(t).diff(t), y(t).diff(t)]
sage: d2f(t) = [x(t).diff(t, 2), y(t).diff(t, 2)]
2 We consider here the algebraic radius of curvature, which can be negative.
90 CHAP. 4. GRAPHICS
Type of drawing
Graph of a function plot
Parametric curve parametric_plot
Curve defined by a polar equation polar_plot
Curve defined by an implicit equation implicit_plot
Level set of a complex function complex_plot
Empty graphical object Graphics()
Integral curves of a differential equation odeint, desolve_rk4
Bar graph, bar chart bar_chart
Histogram of a statistical sequence plot_histogram
Polygonal chain line
Cloud of points points
Circle circle
Polygon polygon
Text text
12
10
-10 -5 5
-2
Table 4.1 gives a summary of the functions detailed in this section. It also
contains the text command which enables us to add a character string in a graph,
and the polygon command to plot polygons.
4.2 3D Curves
Sage provides the plot3d(f(x,y),(x,a,b),(y,c,d)) command to display sur-
faces in 3-dimensions. The surface obtained may then be visualised via the Jmol
application; the Tachyon 3D Ray Tracer or three.js can be used alternatively
with the option viewer=’tachyon’ or viewer=’threejs’ of the show command.
Here is a first example of parametric surface (Figure 4.15):
sage: u, v = var('u, v')
sage: h = lambda u,v: u^2 + 2*v^2
sage: plot3d(h, (u,-1,1), (v,-1,1), aspect_ratio=[1,1,1])
Hence f has well-defined directional derivatives in any direction at the point (0, 0).
To better visualise the surface corresponding to f , we can first look for some level
sets; for example the level set of value 12 :
sage: solve(f(x,y) == 1/2, y)
[y == x^2]
sage: a = var('a'); h = f(x, a*x^2).simplify_rational(); h
a/(a^2 + 1)
Along the parabola of equation y = ax2 , except at the origin, f has thus a
a a
constant value f (x, ax2 ) = 1+a2 . We then display the function h : a −
7 → 1+a2:
0.4
0.2
-4 -3 -2 -1 1 2 3 4
-0.2
-0.4
The function h has its maximum at a = 1 and its minimum at a = −1. The
restriction of f to the parabola of equation y = x2 corresponds to the level set
at “height” 12 ; conversely, the restriction to the parabola of equation y = −x2
corresponds to the bottom of the “thalweg” at height − 21 . In conclusion, arbitrarily
close to the point (0, 0), we can find points where f takes as value 12 , or respectively
− 12 . As a consequence, f is not continuous at the origin.
sage: p = plot3d(f(x,y),(x,-2,2),(y,-2,2),plot_points=[150,150])
We might also draw horizontal planes to display the level sets of this function
with:
sage: for i in range(1,4):
....: p += plot3d(-0.5 + i / 4, (x, -2, 2), (y, -2, 2),\
....: color=hue(i / 10), opacity=.1)
Among the other 3D graphical commands, implicit_plot3d allows us to
display surfaces defined by an implicit equation of the form f (x, y, z) = 0. Let
us display for example the Cassini surface (Figure 4.18a) defined by the implicit
2
equation: a2 + x2 + y 2 = 4 a2 x2 + z 4 .
sage: x, y, z = var('x, y, z'); a = 1
sage: h = lambda x, y, z:(a^2 + x^2 + y^2)^2 - 4*a^2*x^2-z^4
sage: implicit_plot3d(h, (x,-3,3), (y,-3,3), (z,-2,2),\
....: plot_points=100)
4.2. 3D CURVES 93
x2 y
Figure 4.17 – The surface corresponding to f : (x, y) 7→ x4 +y 2
.
Finally, let us give an example of 3-dimensional curve (Figure 4.18b) with the
line3d command:
sage: line3d([(-10*cos(t)-2*cos(5*t)+15*sin(2*t),\
....: -15*cos(2*t)+10*sin(t)-2*sin(5*t),\
....: 10*cos(3*t)) for t in srange(0,6.4,.1)],radius=.5)
sage: type(12/35)
<type 'sage.rings.rational.Rational'>
sage: fourth_power(2)
16
sage: fourth_power(3/2)
81/16
1 For a binary operation like the product, the selection of the appropriate method is slightly
more complex than what was described above. Indeed, we might deal with mixed operations
like the sum 2 + 3/4 of an integer and of a rational number. In this case, 2 will be converted in
the rational 2/1, and the addition of two rationals will be called. The rules that describe which
operand must be converted, and how it should be converted, are part of the coercion model.
98 CHAP. 5. COMPUTATIONAL DOMAINS
sage: fourth_power(I)
1
sage: fourth_power(x+1)
(x + 1)^4
sage: M = matrix([[0,-1],[1,0]]); M
[ 0 -1]
[ 1 0]
sage: fourth_power(M)
[1 0]
[0 1]
5.1.3 Introspection
Python objects, and therefore Sage objects, have some introspection features. This
means that, during execution, we can “ask” an object for its class, its methods,
etc., and manipulate the obtained informations using the usual constructions
of the programming language. For instance, the class of an object o is itself a
Python object, and we can obtain it using type(o):
sage: t = type(5/1); t
<type 'sage.rings.rational.Rational'>
sage: t == type(5)
False
We see here that the expression 5/1 constructs the rational number 5, which
differs — as Python object — from the integer 5!
The introspection tools also give access to the factorisation on-line help from
an object of integer type:
sage: o = 720
sage: o.factor?
Docstring:
Return the prime factorization of this integer as a formal
Factorization object.
...
and even to the source code of that function:
sage: o.factor??
...
def factor(self, algorithm='pari', proof=None, ...)
...
if algorithm == 'pari':
...
elif algorithm in ['kash', 'magma']:
...
Avoiding some technical details, we see here that Sage delegates the integer
factorisation to other tools (PARI/GP, Kash, or Magma).
5.2. ELEMENTS, PARENTS, CATEGORIES 99
sage: QQ
Rational Field
and use them to easily convert an element from one set to the other, when it
makes sense:
sage: QQ(5).parent()
Rational Field
sage: ZZ(5/1).parent()
Integer Ring
sage: ZZ(1/5)
Traceback (most recent call last):
...
TypeError: no conversion of this rational to integer
More generally, the P(x) syntax — where P is a parent — tries to convert
the object x into an element of P. We show four different instances of 1: as
integer 1 ∈ Z, as rational number 1 ∈ Q, as real floating-point 1.0 ∈ R or complex
floating-point 1.0 + 0.0i ∈ C:
sage: ZZ(1), QQ(1), RR(1), CC(1)
(1, 1, 1.00000000000000, 1.00000000000000)
Exercise 19. Find two Sage objects having the same type and different parents.
Then find two Sage objects having the same parent and different types.
5.2.2 Constructions
The parents being themselves first-class objects, we can apply operations to them.
For example, one can construct the cartesian product Q2 :
sage: cartesian_product([QQ, QQ])
The Cartesian product of (Rational Field, Rational Field)
find Q as the fraction field of Z:
sage: ZZ.fraction_field()
Rational Field
construct the ring of polynomials in x with coefficients in Z:
sage: ZZ['x']
Univariate Polynomial Ring in x over Integer Ring
Using an incremental approach, we can construct complex algebraic structures
like the 3 × 3 matrix space with polynomial coefficients on a finite field:
sage: Z5 = GF(5); Z5
Finite Field of size 5
sage: P = Z5['x']; P
Univariate Polynomial Ring in x over Finite Field of size 5
sage: M = MatrixSpace(P, 3, 3); M
5.3. DOMAINS WITH A NORMAL FORM 101
mathematically identical if their canonical (or normal) forms are equal. Sometimes normal form
is meant as a weaker notion, where only zero is assumed to have a unique representation.
3 Most of the other parents available in Sage correspond to domains with a normal form, but
not all of them. It also happens that, for efficiency reasons, Sage represents elements in normal
form only when explicitly requested.
102 CHAP. 5. COMPUTATIONAL DOMAINS
fields
euclidean domains
gcd domains
integral domains
rings
rngs semirings
sets
objects
Algebraic numbers
Algebraic numbers Q̄ QQbar or AlgebraicField()
Real algebraic numbers AA or AlgebraicRealField()
Number fields Q[x]/hpi NumberField(p)
Symbolic computation
Matrices m × n with coefficients in A MatrixSpace(A, m, n)
Polynomials A[x, y] A['x,y'] or PolynomialRing(A, 'x,y')
Series A[[x]] A[['x']] or PowerSeriesRing(A, 'x')
Symbolic expressions SR
Integers. The integers are represented in radix two internally, and printed by
default in radix ten. As seen above, the Sage integers are objects of the class
Integer. Their parent is the ring Z:
sage: 5.parent()
Integer Ring
The integers are always in normal form; their equality is thus easy to check. As
a consequence, to be able to represent integers in factorised form, the factor
command needs a specific class:
sage: type(factor(4))
<class 'sage.structure.factorization_integer.IntegerFactorization'>
104 CHAP. 5. COMPUTATIONAL DOMAINS
or conversely
sage: Integer(5)
5
sage: type(Integer(5))
<type 'sage.rings.integer.Integer'>
In tests and loops, the conditions built from the operators or and and are evaluated
lazily from left to right. This means that the evaluation of a condition or ends
as soon as the first True value is encountered, without evaluating the rightmost
terms; similarly with and and False. Hence the following divisibility test of b by
a does not produce any error even if a = 0:
sage: a = 0; b = 12; (a == 0 and b == 0) or (a != 0 and b % a == 0)
The operator not takes precedence over and, which in turn takes precedence
over or, the equality and comparison tests having precedence over all boolean
operators. The two following tests are thus equivalent to the above one:
sage: ((a == 0) and (b == 0)) or ((a != 0) and (b % a == 0))
sage: a == 0 and b == 0 or not a == 0 and b % a == 0
In the simple cases, these tests are automatically performed; otherwise we call
the bool command to force the evaluation:
sage: x, y = var('x, y')
sage: bool( (x-y)*(x+y) == x^2-y^2 )
True
Both IntegerModRing(n) and GF(p) are domains with a normal form: the
reduction modulo n or p are done automatically. The computations in rings and
finite fields are detailed in Chapter 6.
5.3. DOMAINS WITH A NORMAL FORM 107
Matrices. The normal form4 of a matrix is obtained when all its coefficients
are themselves in normal form. As a consequence, a matrix defined over a field or
ring with normal form is automatically in normal form:
sage: a = matrix(QQ, [[1,2,3],[2,4,8],[3,9,27]])
sage: (a^2 + 1) * a^(-1)
[ -5 13/2 7/3]
[ 7 1 25/3]
[ 2 19/2 27]
The matrix function call is a shortcut. Internally, Sage builds the corresponding
parent, here the space of 3 × 3 matrices with coefficients in Q (which has normal
form), then uses it to construct the matrix:
sage: M = MatrixSpace(QQ,3,3); M
Full MatrixSpace of 3 by 3 dense matrices over Rational Field
sage: a = M([[1,2,3],[2,4,8],[3,9,27]])
sage: (a^2 + 1) * a^(-1)
[ -5 13/2 7/3]
[ 7 1 25/3]
[ 2 19/2 27]
The operations on symbolic matrices are described in Chapter 8, and on numerical
matrices in Chapter 13.
a0 + a1 x + a2 x2 + · · · + an xn + O(xn+1 )
used for example to represent Taylor expansions, and whose usage in Sage is
described in §7.5. The parent of series in x, truncated at order n, and with
coefficients in A, is the ring A[[x]], build with PowerSeriesRing(A, ’x’, n).
Like polynomials, truncated power series have an analogue in the world SR of
symbolic expressions. The corresponding command to reduce to normal form is
series.
sage: f = cos(x).series(x == 0, 6); 1 / f
1
1+(− 12 )x2 + 24
1 4
x +O(x6 )
sage: (1 / f).series(x == 0, 6)
1 + 21 x2 + 5 4
24 x + O x6
This book does not describe in detail how to play with algebraic numbers in Sage,
however several examples can be found in Chapters 7 and 9.
5.4. EXPRESSIONS VS COMPUTATIONAL DOMAINS 109
5.4.4 Synthesis
In the preceding examples, we have shown how the user might control the level
of rigour in her/his computations.
On the one hand, she/he can use symbolic expressions. These expressions
live in the ring SR. They offer several methods (presented in Chapter 2) which
apply well to some sub-classes of expressions, like polynomial expressions. When
we recognise to which classes a given expression belongs to, this helps to know
which functions could be applied. The simplification of expressions is a particular
problem where this recognition is crucial. The main classes of expression are
defined to take into account this simplification issue, and we will prefer this
approach in the rest of this book.
On the other hand, the user can construct a parent which will explicitly define
the computational domain. It is especially interesting when this parent has a
normal form: i.e., when two objects are mathematically equal if and only if they
have the same representation.
As a summary, the main advantage of symbolic expressions (SR) is their ease
of use: no explicit declaration of the computational domain, easy addition of new
variables or functions, easy change of the computational domain (for example
when one takes the sine of a polynomial expression), use of all possible calculus
tools (integration, etc.). The advantages of explicitly defining the computational
domain are in the first place pedagogical, more rigorous computations6 , the
automatic normal form transformation (which can also be a drawback!), and
the easy access to advanced constructions that would be difficult with symbolic
expressions (computations in a finite field or an algebraic extension of Q, in a
non-commutative ring, etc.).
6 Sage is not a certified computer algebra system: a bug is thus always possible; however,
This chapter describes the use of Sage for elementary number theory, for working
with objects related to finite fields (§6.1), for primality testing (§6.2) and integer
factorisation (§6.3); we will also discuss some applications (§6.4).
using a % n. Note that the modulus n does not appear explicitly in the displayed
value:
sage: a = IntegerModRing(15)(3); b = IntegerModRing(17)(3); a, b
(3, 3)
sage: a == b
False
One consequence of this is that when one uses “cut-and-paste” to copy integers
modulo n, one loses information about n. Given a variable whose value is
an integer modulo n, one can recover information about n using the methods
base_ring or parent, and the value of n using the method characteristic:
sage: R = a.parent(); R
Ring of integers modulo 15
sage: R.characteristic()
15
The basic operations (addition, subtraction and multiplication) are overloaded for
integers modulo n, and call the appropriate functions; also, integers are converted
automatically when one of the operands is an integer modulo n:
sage: a + a, a - 17, a * a + 1, a^3
(6, 1, 10, 12)
For inversion, 1/a mod n, or division, b/a mod n, Sage carries out the operation
if possible; otherwise, i.e., when a and n have a nontrivial common factor, a
ZeroDivisionError is raised:
sage: 1/(a+1)
4
sage: 1/a
Traceback (most recent call last):
...
ZeroDivisionError: Inverse does not exist.
To obtain the value of a as an integer from its residue a mod n, one can use
the method lift or even ZZ:
sage: z = a.lift(); y = ZZ(a); y, type(y), y == z
(3, <type 'sage.rings.integer.Integer'>, True)
The additive order of a modulo n is the smallest integer k > 0 such that
ka = 0 mod n. It is equal to k = n/g, where g = gcd(a, n), and is given by the
method additive_order (we will see later that one can also use Mod or mod to
define integers modulo n):
sage: [Mod(x,15).additive_order() for x in range(0,15)]
[1, 15, 15, 5, 15, 3, 5, 15, 15, 5, 3, 15, 5, 15, 15]
The multiplicative order of a modulo n, for a coprime1 to n, is the smallest
integer k > 0 such that ak = 1 mod n. (If a had a common divisor p with n, then
1 “coprime” and “relatively prime” are synonymous.
6.1. FINITE FIELDS AND RINGS 117
ak mod n would be a multiple of p for all k.) If this multiplicative order equals
ϕ(n), which is the order of the multiplicative group modulo n, one says that a
is a generator of this group. Thus for n = 15, there is no generator, since the
maximal order is 4 < 8 = ϕ(15):
sage: [[x, Mod(x,15).multiplicative_order()]
....: for x in range(1,15) if gcd(x,15) == 1]
[[1, 1], [2, 4], [4, 2], [7, 4], [8, 4], [11, 2], [13, 4], [14, 2]]
Here is an example with n = p prime, where 3 is a generator:
sage: p = 10^20 + 39; mod(2,p).multiplicative_order()
50000000000000000019
sage: mod(3,p).multiplicative_order()
100000000000000000038
An important operation on Z/nZ is modular exponentiation, which means
to calculate ae mod n. The RSA crypto-system relies on this operation. To
calculate ae mod n, the most efficient algorithms require of the order of log e
multiplications or squarings modulo n. It is crucial to reduce all calculations
modulo n systematically, and not compute ae first as an integer, as the following
example shows:
sage: n = 3^100000; a = n-1; e = 100
sage: %timeit (a^e) % n
5 loops, best of 3: 387 ms per loop
sage: %timeit power_mod(a,e,n)
125 loops, best of 3: 3.46 ms per loop
2 The finite field with q elements is either denoted F , or GF(q) (where “GF” stands for
q
“Galois Field”). Here we will use the notation Fq for the mathematical object, and the notation
GF(q) in Sage code.
118 CHAP. 6. FINITE FIELDS AND NUMBER THEORY
sage: R = GF(9,name='x'); R
Finite Field in x of size 3^2
Here, Sage has automatically chosen the polynomial f :
sage: R.polynomial()
x^2 + 2*x + 2
Field elements are thus represented by polynomials in the generator x, ak−1 xk−1 +
· · · + a1 x + a0 , with coefficients ai which are elements of Fp :
sage: Set([r for r in R])
{0, 1, 2, x, x + 1, x + 2, 2*x, 2*x + 1, 2*x + 2}
One can also make Sage use a specific irreducible polynomial f :
sage: Q.<x> = PolynomialRing(GF(3))
sage: R2 = GF(9, name='x', modulus=x^2+1); R2
Finite Field in x of size 3^2
Be careful: even though the two fields R and R2 created above are both
isomorphic to F9 , Sage provides no isomorphism between them automatically:
sage: p = R(x+1); R2(p)
Traceback (most recent call last):
...
TypeError: unable to coerce from a finite field other than the prime
subfield
-13/17
sage: rational_reconstruction(409,1000)
Traceback (most recent call last):
...
ArithmeticError: rational reconstruction of 409 (mod 1000) does not
exist
Now we know that Hn can be written in the form pn /qn with integers pn , qn ,
where qn = lcm(1, 2, . . . , n). We also know that Hn ≤ log n + 1, which allows us
to bound pn . This leads to the following function, which finds Hn using modular
arithmetic and rational reconstruction:
sage: def harmonic_mod(n,m):
....: return add([1/x % m for x in range(1,n+1)])
sage: def harmonic2(n):
....: q = lcm(range(1,n+1))
....: pmax = RR(q*(log(n)+1))
....: m = ZZ(2*pmax^2)
....: m = ceil(m/q)*q + 1
....: a = harmonic_mod(n,m)
....: return rational_reconstruction(a,m)
In this example, the function harmonic2 is no more efficient than the original
function harmonic, but it illustrates the method. It is not always necessary to
know a rigorous bound for x and y, as a rough estimate “by eye” will suffice,
provided that one is able to verify easily that x/y is the correct solution.
One can generalise the method of rational reconstruction to handle numerators
x and denominators y of different sizes; see for example Section 5.10 of the book
[vzGG03].
Here we have presented the simplest variant of the Chinese Remainder Theorem.
One can also consider the case of several moduli m1 , m2 , . . . , mk . The Sage
command for finding x0 , given a, b, m, n, is crt(a,b,m,n):
sage: a = 2; b = 3; m = 5; n = 7; lambda0 = (b-a)/m % n; a + lambda0 * m
17
sage: crt(2,3,5,7)
17
The Sage function crt may also be used when the moduli m and n are not
coprime. If g = gcd(m, n), then a solution exists if and only if a ≡ b mod g:
sage: crt(15,1,30,4)
45
sage: crt(15,2,30,4)
Traceback (most recent call last):
...
ValueError: No solution to crt problem since gcd(30,4) does not divide
15-2
6.2 Primality
Testing whether an integer is prime is a fundamental operation for a symbolic
computer software package. Even if the user is not aware of it, such tests are
carried out thousands of times per second by the software. For example, to factor
a polynomial in Z[x], one starts by factoring it in Fp [x] for some prime number p,
and one must therefore find a suitable prime.
6.2. PRIMALITY 121
Useful commands
Ring of integers modulo n IntegerModRing(n)
Finite field with q elements GF(q)
Pseudo-primality test is_pseudoprime(n)
Primality test is_prime(n)
There are two main classes of primality test. The most efficient are pseudo-
primality tests, and are in general based on forms of Fermat’s Little Theorem,
which says that if p is prime, then every integer a with 0 < a < p is an element
of the multiplicative group (Z/pZ)∗ , and hence ap−1 ≡ 1 mod p. One uses
small values of a (2, 3, . . .) to speed up the computation of ap−1 mod p. If
ap−1 6≡ 1 mod p, then p is certainly not prime. If ap−1 ≡ 1 mod p, one cannot
conclude either that p is or is not prime; we say that p is a (Fermat) pseudo-prime
to base a. The intuition is that an integer p which is a pseudo-prime to many
bases has a greater chance of being prime (but see below). Pseudo-primality
tests share the property that when they return the verdict False, the number
is certainly composite, whereas when they return True, no definite conclusion is
possible.
The second class consists of true primality tests. These tests always return a
correct answer, but can be less efficient than pseudo-primality tests, especially
for numbers that are pseudo-primes to many bases, and in particular for actual
primes. Many software packages only provide pseudo-primality tests, despite the
name of the corresponding function (isprime, for example) sometimes leading
the user to believe that a true primality test is provided. Sage provides two
different functions: is_pseudoprime for pseudo-primality, and is_prime for true
primality:
sage: p = previous_prime(2^400)
sage: %timeit is_pseudoprime(p)
625 loops, best of 3: 1.07 ms per loop
sage: %timeit is_prime(p)
5 loops, best of 3: 485 ms per loop
We see in this example that the primality test is more costly; when possible,
therefore, one prefers to use is_pseudoprime.
Some primality testing algorithms provide a certificate, which allows an
independent subsequent verification of the result, often more efficiently than the
test itself. Sage does not provide such a certificate in the current release, but one
can construct one using Pocklington’s Theorem:
√
Theorem. Let n > 1 be an odd integer such that n − 1 = F R, with F ≥ n.
n−1
If for each prime factor p of F , there exists a such that a ≡ 1 mod n and
a(n−1)/p − 1 is coprime to n, then n is prime.
Consider for example n = 231 − 1. The factorisation of n − 1 is 2 · 32 · 7 · 11 · 31 ·
151 · 331. One can take F = 151 · 331, and a = 3 satisfies the condition for both
122 CHAP. 6. FINITE FIELDS AND NUMBER THEORY
factors p = 151 and p = 331. Hence it suffices to prove the primality of 151 and
331 in order to deduce that n is prime. This test uses modular exponentiation in
an important way.
Carmichael numbers
Exercise 20. Write a Sage function to count the Carmichael numbers n = pqr ≤ N ,
with p, q, r distinct odd primes. How many do you find for N = 104 , 105 , 106 , 107 ?
(Richard Pinch has counted 20138200 Carmichael numbers less than 1021 .)
Finally, in order to repeat an operation on all prime numbers in an interval, it
is better to employ the construction prime_range, which constructs a table of
primes using a sieve, than to simply use a loop with next_probable_prime or
next_prime:
sage: def count_primes1(n):
....: return add([1 for p in range(n+1) if is_prime(p)])
sage: %timeit count_primes1(10^5)
5 loops, best of 3: 674 ms per loop
The function is faster if one uses is_pseudoprime instead of is_prime:
sage: def count_primes2(n):
....: return add([1 for p in range(n+1) if is_pseudoprime(p)])
sage: %timeit count_primes2(10^5)
5 loops, best of 3: 256 ms per loop
In this example, it is worth using a loop rather than constructing a list of 105
elements, and again is_pseudoprime is faster than is_prime:
sage: def count_primes3(n):
....: s = 0; p = 2
6.3. FACTORISATION AND DISCRETE LOGARITHMS 123
Aliquot sequences
30, 42, 54, 66, 78, 90, 144, 259, 45, 33, 15, 9, 4, 3, 1.
When the cycle has length one, we say that the starting integer is perfect, for
example 6 = 1 + 2 + 3 and 28 = 1 + 2 + 4 + 7 + 14 are perfect. When the
cycle has length two, the two integers in the cycle are called amicable and
form an amicable pair, for example 220 and 284. When the cycle has length
three or more, the integers in the cycle are called sociable.
Exercise 21. Calculate the aliquot sequence starting with 840, take the 5 first and
5 last terms, and draw the graph of log10 sk as a function of k (you can use the function
sigma).
6.4 Applications
6.4.1 The Constant δ
The constant δ is a two-dimensional generalisation of Euler’s constant γ. It is
defined as follows: !
X n
1
δ = lim − log n , (6.1)
n→∞ πrk2
k=2
6.4. APPLICATIONS 125
√ plane R containing
2
where rk is the radius of the smallest closed disc in the affine √ at
least k points of Z . For √
2
example, r2 = 1/2, r3 = r4 = 2/2, r5 = 1, r6 = 5/2,
r7 = 5/4, and r8 = r9 = 2:
Exercise 23. Given that I is a rational number, develop an algorithm using rational
reconstruction and/or the Chinese Remainder Theorem to calculate I. Implement the
algorithm in Sage, and apply it to the case [n1 , . . . , n31 ] =
This chapter will discuss univariate polynomials and related objects, mainly
rational functions and formal power series. We will first see how to perform with
Sage some transformations like the Euclidean division of polynomials, factorisation
into irreducible polynomials, root isolation, or partial fraction decomposition. All
these transformations will take into account the ring or field where the polynomial
coefficients live: Sage enables us to compute in polynomial rings A[x], in their
quotient A[x]/hP (x)i, in fraction fields K(x) or in formal power series rings A[[x]]
for a whole set of base rings.
Operations on polynomials also have some unexpected applications. How
would you automatically guess the next term of the sequence
1, 1, 2, 3, 8, 11, 39...?
For example, you could use the Padé approximation of rational functions, presented
in Section 7.4.3! How could you get a series expansion of the solutions of the
equation exf (x) = f (x)? An answer can be found in Section 7.5.3.
We assume in general that the reader is used to playing with polynomials and
rational functions at the first year university level. However, we will discuss more
advanced subjects. How to prove that the solutions of the equation x5 − x − 1
cannot be expressed by radicals? It suffices to compute its Galois group, as
explained in Section 7.3.4. The corresponding parts are not used elsewhere in this
book, and the reader may skip them. Finally, this chapter gives a few examples
with algebraic and p-adic numbers.
Here we will focus on polynomials with one variable, called univariate polyno-
mials. Multivariate polynomials are discussed in Chapter 9.
128 CHAP. 7. POLYNOMIALS
polygen(QQ, ’x’) alone does not change the value of the Python variable x.
7.1. POLYNOMIAL RINGS 129
the examples will have coefficients in a field. In the whole chapter, the letters A
and K respectively correspond to a commutative ring and to a field.
The first step to perform a computation in an algebraic structure R is often
to build R itself. We build Q[x] with
The ’x’ on the first line is a character string, which is the name of the indeter-
minate, or generator of the ring. The x on the second line is a Python variable
in which one stores the generator; using the same name makes the code easier
to read. The object stored in the variable x represents the polynomial x ∈ Q[x].
Its parent (the parent of a Sage object is the algebraic structure “from which it
comes”, see §5.1) is the ring QQ[’x’]:
sage: x.parent()
Univariate Polynomial Ring in x over Rational Field
The polynomial x ∈ Q[x] is considered different from x ∈ A[x] for a base ring
A 6= Q, and also different from those, like t ∈ Q[t], whose indeterminate has a
different name.
The expression PolynomialRing(QQ, ’t’) might also be written QQ[’t’].
We often combine this abbreviation with the construction S.<g> = ..., which
simultaneously assigns a structure to the variable S and its generator to the
variable g. The construction of the ring Q[x] and of its indeterminate then reduces
to R.<x> = QQ[]. The form x = polygen(QQ, ’x’) seen above is equivalent to
sage: x^2 + 1
y^2 + 1
sage: (y^2 + 1).parent()
Univariate Polynomial Ring in x over Rational Field
7.1.3 Polynomials
Creation and Basic Arithmetic. After the instruction R.<x> = QQ[], the
expressions constructed from x and rational constants with operations + and *
are elements of Q[x]. For example, in p = x + 2, Sage automatically determines
that the values of the variable x and the integer 2 can both be seen as elements
of Q[x]. The addition routine of polynomials in Q[x] is thus called; it builds and
returns the polynomial x + 2 ∈ Q[x].
Another way to build a polynomial is to enumerate its coefficients:
sage: def rook_polynomial(n, var='x'):
....: return ZZ[var]([binomial(n, k)^2 * factorial(k)
....: for k in (0..n) ])
The above function constructs polynomials whose coefficient of xk is the number
of ways to put k rooks on an n × n chessboard, so that two rooks cannot
capture each other; this explains the name of the function. The parentheses after
ZZ[var] force the conversion of a given object into an element of this ring. The
7.1. POLYNOMIAL RINGS 131
Basic arithmetic
operations p + q, p − q, p × q, pk p + q, p - q, p * q, p^k
substitution x := a p(a) or p.subs(a)
derivative p.derivative() or p.diff()
Transformations
transformation of coefficients p.map_coefficients(f)
change of base ring A[x] → B[x] p.change_ring(B) or B['x'](p)
reciprocal polynomial p.reverse()
some specialised variants of methods we mention, and numerous methods common to all ring
elements, and even to all Sage objects, which have no particular interest on polynomials. Note
however that some specialised methods (for example p.rescale(a), equivalent to p(a*x)) are
often more efficient than more general methods that could replace them.
132 CHAP. 7. POLYNOMIALS
Change of Ring. The exact list of available operations, their meaning and
their efficiency heavily depend on the base ring. For example, the polynomials in
GF(p)[’x’] have a method small_roots which returns their small roots with
respect to the characteristic p; those in QQ[’x’] do not have such a method, since
it makes no sense. The factor method exists for all polynomials, but raises an
exception NotImplementedError for polynomials with coefficients in SR or in
Z/4Z. This exception means that this operation is not available in Sage for this
kind of object, despite having a mathematical meaning.
It is very useful to be able to juggle the different rings of coefficients on
which we might consider a given polynomial. Applied to a polynomial in A[x],
the method change_ring(B) returns its image in B[x], when a natural method
to convert the coefficients exists. The conversion is often given by a canonical
morphism from A to B: in particular, change_ring might be used to extend
the base ring to gain additional algebraic properties. Here for example, the
polynomial p is irreducible over the rationals, but it factors on R:
sage: x = polygen(QQ)
sage: p = x^2 - 16*x + 3
sage: p.factor()
x^2 - 16*x + 3
sage: p.change_ring(RDF).factor()
(x - 15.810249675906654) * (x - 0.18975032409334563)
The RDF domain is that of “machine floating-point numbers”, and is discussed in
Chapter 11. The obtained factorisation is approximate; it is not enough to recover
the original polynomial. To represent real roots of polynomials with integer
coefficients in a way that enables exact computations, we use the domain AA of
real algebraic numbers. We will see some examples in the following sections.
The same method change_ring allows to reduce a polynomial in Z[x] modulo
a prime number:
sage: p.change_ring(GF(3))
x^2 + 2*x
Conversely, if B ⊂ A and if the coefficients of p are in fact in B, we also call
change_ring to recover p in B[x].
The parents of polynomial objects, i.e., the rings A[x], are themselves
first class Sage objects. Let us briefly see how to use them.
A first family of methods enables us to construct particular polynomials,
to draw random ones, or to enumerate families, here those of degree exactly 2
over F2 :
sage: list(GF(2)['x'].polynomials(of_degree=2))
[x^2, x^2 + 1, x^2 + x, x^2 + x + 1]
We will call some of these methods in the examples of the next sections, to
build objects on which we will work. Chapter 15 explains more generally
how to enumerate finite sets with Sage.
Secondly, the system “knows” some basic facts for each polynomial ring.
We can check whether a given object is a ring, if it is noetherian:
sage: A = QQ['x']
sage: A.is_ring() and A.is_noetherian()
True
or if Z is a sub-ring of Q[x], and for which values of n the ring Z/nZ is
integral:
sage: ZZ.is_subring(A)
True
sage: [n for n in range(20)
....: if Integers(n)['x'].is_integral_domain()]
[0, 2, 3, 5, 7, 11, 13, 17, 19]
These capabilities largely rely on the Sage category system (see also §5.2.3).
Polynomial rings belong to a number of “categories”, like the category of
sets, that of Euclidean rings, and many more:
sage: R.categories()
[Category of euclidean domains,
Category of principal ideal domains,
...
Category of sets with partial maps, Category of objects]
This reflects that any polynomial ring is also a set, a Euclidean domain, and
so on. The system can thus automatically transfer to polynomial rings the
general properties of objects from these different categories.
134 CHAP. 7. POLYNOMIALS
Miscellaneous
interpolation p(xi ) = yi p = R.lagrange_polynomial([(x1,y1), ...])
content of p ∈ Z[x] p.content()
7.2.1 Divisibility
Divisions. The Euclidean division works in a field, and more generally in a
commutative ring when the leading coefficient of the divisor is invertible, since this
coefficient is the only one from the base ring by which it is required to divide:
sage: R.<t> = Integers(42)[]; (t^20-1) % (t^5+8*t+7)
22*t^4 + 14*t^3 + 14*t + 6
When the leading coefficient is not invertible, we can still define a pseudo Euclidean
division (pseudo-division for short): let A be a commutative ring, p, d ∈ A[x], and
a the leading coefficient of d. Then there exists two polynomials q, r ∈ A[x], with
deg r < deg d, and an integer k ≤ deg p − deg d + 1 such that
ak p = qd + r.
Exercise 25. Usually, in Sage, polynomials in Q[x] are represented on the monomial
basis (xn )n∈N . Chebyshev polynomials Tn , defined by Tn (cos θ) = cos(nθ), form a family
of orthogonal polynomials and thus a basis of Q[x]. The first Chebyshev polynomials
are
Write a function taking as input an element of Q[x] and returning the coefficients of its
decomposition in the basis (Tn )n∈N .
GCD. Sage is able to compute the gcd of polynomials over a field, thanks
to the Euclidean structure of K[x], but also on some other rings, including the
integers:
sage: S.<x> = ZZ[]; p = 2*(x^10-1)*(x^8-1)
sage: p.gcd(p.derivative())
2*x^2 - 2
We can prefer the more symmetric expression gcd(p,q), which yields the same
result as p.gcd(q). It is though slightly less natural in Sage since it is not a
general mechanism: gcd(p,q) calls a function of two arguments, defined manually
in the source code of Sage, and which calls in turn p.gcd. Only some usual
methods have such an associated function.
The extended gcd, i.e., the computation of a Bézout relation
is given by p.xgcd(q):
sage: R.<x> = QQ[]; p = x^5-1; q = x^3-1
sage: print("the gcd is %s = (%s)*p + (%s)*q" % p.xgcd(q))
the gcd is x - 1 = (-x)*p + (x^3 + 1)*q
The xgcd method also exists for polynomials in ZZ[’x’], but beware: since Z[x]
is not a principal ideal ring, the result is in general not a Bézout relation (ap + bq
might be an integer multiple of the gcd)!
136 CHAP. 7. POLYNOMIALS
sage: J2 = R.ideal(x^5 + 2)
sage: ((3*x+5)*J1*J2).reduce(x^10)
421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81
If K is a field, then the ring K[x] is principal: the ideals are represented
during computations by a generator, all this being an algebraic language for the
operations seen in §7.2.1. Its principal advantage is that quotient
rings can be
easily used in new constructions, here that of F5 [t]/ht2 + 3i [x]:
Sage also allows building non principal ideals like in Z[x], however the available
operations are then limited — except in case of multivariate polynomials over a
field, which are the subject of Chapter 9.
Exercise 27. We define the sequence (un )n∈N with the initial conditions un = n + 7
for 0 ≤ n < 1000, and the linear recurrence relation
Compute the last five digits of u1010000 . Hint: we might look at the algorithm from §3.2.4.
However, this algorithm is too expensive when the order of the recurrence is large.
Introduce a clever quotient of polynomial rings to avoid this issue.
7.3. FACTORISATION AND ROOTS 137
Elements of K[x]/hpi
lift (section of R ։ R/J) u.lift()
minimal polynomial u.minpoly()
characteristic polynomial u.charpoly()
matrix u.matrix()
trace u.trace()
7.3.1 Factorisation
Irreducibility Test. On the algebraic side, the simplest question about the
factorisation of a polynomial is whether it is irreducible. Naturally, the answer
depends on the base ring. The method is_irreducible tells if a polynomial is
irreducible in its parent ring. For example, the polynomial 3x2 − 6 is irreducible
over Q, but not over Z (why?):
sage: R.<x> = QQ[]; p = 3*x^2 - 6
sage: p.is_irreducible(), p.change_ring(ZZ).is_irreducible()
(True, False)
Factorisation
irreducibility test p.is_irreducible()
factorisation p.factor()
square-free factorisation p.squarefree_decomposition()
square-free part p/ gcd(p, p′ ) p.radical()
Roots
roots in A, in D p.roots(), p.roots(D)
real roots p.roots(RR), p.real_roots()
complex roots p.roots(CC), p.complex_roots()
isolation of real roots p.roots(RIF), p.real_root_intervals()
isolation of complex roots p.roots(CIF)
resultant p.resultant(q)
discriminant p.discriminant()
Galois group (p irreducible) p.galois_group()
This works for a large number of domains, with more or less efficiency.
In particular, selecting for D the field of algebraic numbers QQbar or that
of real algebraic numbers AA enables us to compute exactly the complex or real
roots of a polynomial with rational coefficients:
Sage plays transparently for the user with different representations of algebraic
numbers. One encodes each α ∈ Q̄ by its minimal polynomial together with a
sufficiently accurate interval to distinguish α from the other roots. Therefore,
despite their output, the returned roots are not just approximate values. They
can be reused in exact computations:
Here, we have raised the first root found to the fourth power, then forced Sage to
simplify the result to make it clear it equals the integer 7.
A variant of the exact resolution is to simply isolate the roots, i.e., determine
intervals containing exactly one root each, by giving as domain D that of the
real intervals RIF or complex intervals CIF. Among the other useful domains in
the case of a polynomial with rational coefficients, let us mention RR, CC, RDF,
CDF, which all correspond to approximate numerical roots, and the number fields
QQ[alpha].The specific methods real_roots, complex_roots and (for some base
rings) real_root_intervals offer additional options or give slightly different
results from the roots method. The numerical approximation and isolation of
roots is discussed in more detail in §12.2.
7.3.3 Resultant
modulo n shows that they have a common factor in Z/nZ if and only if n divides 8.
Pm Pn
Let p = i=0 pi xi and q = i=0 qi xi be two non constant polynomials in
7.3. FACTORISATION AND ROOTS 141
pm ··· ··· p0
.. ..
. .
pm · · · · · · p0
Res(p, q) = qn ··· q0 . (7.1)
.. ..
. .
.. ..
. .
qn ··· q0
The specialisation property mentioned above follows from the definition (7.1):
if ϕ : A → A′ is a ring morphism, the application of which to p and q keeps their
degrees unchanged, i.e., such that ϕ(pm ) 6= 0 and ϕ(qn ) 6= 0, then we have
As a consequence, ϕ(Res(p, q)) vanishes when ϕ(p) and ϕ(q) share a common
factor. We have seen above an example of this phenomenon, with ϕ the canonical
projection from Z to Z/nZ.
The most common usage of the resultant concerns the case where the base
ring itself is a polynomial ring: p, q ∈ A[x] with A = K[a1 , . . . , ak ]. In particular,
given α1 , . . . , αk ∈ K, let us consider the specialisation
ϕ : B[a1 , . . . , ak ] → K
q(a1 , . . . , ak ) 7→ q(α1 , . . . , αk ).
We see that the resultant Res(p, q) vanishes at (α1 , . . . , αk ) if and only if the
specialisations ϕ(p), ϕ(q) ∈ K[x] share a common factor, assuming that one of
the leading terms of p and q does not vanish in (α1 , . . . , αk ).
For example, the discriminant of p ∈ Q[x] of degree m is defined by
This definition generalises the classical discriminants of degree two and three
polynomials:
142 CHAP. 7. POLYNOMIALS
Sage, but we can upload and automatically install it with the command sage -i database_gap
(it might be needed to restart Sage after the installation).
7.4. RATIONAL FUNCTIONS 143
Rational functions
fraction field K(x) Frac(K['x'])
numerator r.numerator()
denominator r.denominator()
simplification (modifies r) r.reduce()
partial fraction decomposition r.partial_fraction_decomposition()
rational reconstruction of s mod m s.rational_reconstruct(m)
-6 -4 -2 2 4 6 type (4, 2)
-1 ···········
type (8, 4)
-2 ·− ·− ·−
type (12, 6)
-3
−−−−−
Figure 7.1 – The tangent function and some Padé approximants on [−2π, 2π].
then to lift the solution found. The following function lifts an element a from
Z/pZ into an integer of absolute value at most p/2.
sage: def lift_sym(a):
....: m = a.parent().defining_ideal().gen()
....: n = a.lift()
....: if n <= m // 2: return n
....: else: return n - m
We then get:
sage: Qx(map(lift_sym, num))/Qx(map(lift_sym, den))
(-10*x^3 + 105*x)/(x^4 - 45*x^2 + 105)
When the wanted coefficients are too large for this technique, we can perform the
computation modulo several primes, and apply the “Chinese Remainder Theorem”
to obtain a solution with integer coefficients, as explained in §6.1.4. Another
possibility is to compute a recurrence relation with constant coefficients which
is satisfied by the series coefficients. This computation is almost equivalent to a
Padé approximant (see Exercise 28), but the Sage function berlekamp_massey is
able to perform it on any field.
Let us make the preceding computation more automatic, by writing a func-
tion which directly computes the approximant with rational coefficients, under
favorable assumptions:
sage: def mypade(pol, n, k):
....: x = ZpZx.gen();
....: n,d = ZpZx(pol).rational_reconstruct(x^n, k-1, n-k)
....: return Qx(map(lift_sym, n))/Qx(map(lift_sym, d))
It then suffices to call plot on the results of this function (converted into elements
of SR, since plot is not able to draw directly the graph of an “algebraic” rational
function) to obtain the graph of Figure 7.1: