%display latex
SageMath knows about $\pi$, $e$ and $i$ (well, it's mathematical software, isn't it ?):
e^(i*pi) + 1
--- It's nice, but I thought SageMath was based on Python: shouldn't the above be written e**(i*pi) + 1
,
given that ^
is the bitwise XOR operator in Python?
Actually, the input cells are preparsed by SageMath before being sent to the Python interpreter. The action of the preparser is revealed by the function preparse
:
preparse("e^(i*pi) + 1")
We see that indeed, the character ^
has been changed to **
.
Another noticable change is 1
$\to$ Integer(1)
. This means that the preparser is turning integers into SageMath integers, which belong to the class Integer
:
type(1)
This type of integer is much more sophisticated than a mere Python integer (int
). In particular, it knows to which mathematical set it belongs. The latter is returned by the function parent
:
parent(1)
To have more information than just the symbol of the parent, one can use the print
function:
print(parent(1))
Integer Ring
Let us denote this object by the Python variable Z
:
Z = parent(1)
Z
Z
is endowed with many methods, which can be discovered via the TAB key:
Z.<TAB>
Once a method has been selected, one can get some documentation about it via ?
:
Z.cardinality?
A double question mark leads directly to the source code (recall that SageMath is a free software!):
Z.cardinality??
More documentation is available in the online reference manual as well as in various tutorials and guides.
Z.cardinality()
Other methods:
Z.is_ring()
Z.is_field()
Z.zero(), Z.one() # the ring zero and unit elements
Expressing $1\in \mathbb{Z}$ in SageMath:
1 in Z
1 is actually the unit element of the ring $\mathbb{Z}$:
1 == Z.one()
Note that there exits a predefined variable, ZZ
, for $\mathbb{Z}$:
Z is ZZ
SageMath integers can be arbitrarily large (up to the limit of the computer memory):
m = 2^127 - 1
m
m.is_prime()
Note that one has still access to the Python integers, via int
:
int(1)
type(_) # the underscore stands for the latest output
They are automatically converted (coerced) into SageMath integers if necessary, for instance if they are added to some SageMath integer:
int(1) + 2
type(_)
Of course, SageMath also knows about rational numbers:
2/3
Python would have returned 0.6666666666666666. This is not the case here because
preparse('2/3')
and the division of the (Sage) integer 2 by the (Sage) integer 3 is the (Sage) rational number $2/3$:
parent(2/3)
print(_)
Rational Field
As the above examples illustrate, SageMath is based on a Parent/Element scheme: parent(a)
is the algebraic or topological/differential structure to which a
belongs.
SageMath has also the concept of mathematical categories:
print(category(Z))
Join of Category of euclidean domains and Category of infinite enumerated sets and Category of metric spaces
SageMath can compute numerical values with an arbitrary number of digits:
n(pi, digits=1000)
n
is the shortcut alias for numerical_approx
.
Another interesting computation regards the Hermite-Ramanujan constant:
a = exp(pi*sqrt(163))
a
Actually, this number is very close to an integer, as announced by Charles Hermite in 1859 (probably without using SageMath...):
n(a, digits=50)
That's clear if we turn off scientific notation:
n(a, digits=50).str(no_sci=2)
Beside numerical computations, SageMath can perform symbolic ones. For instance, it can compute a derivative:
f = diff(sin(x^2), x)
f
Due to the command %display latex
in the first cell of this notebook, SageMath displays all results, such as the one above, in LaTeX format. To get them in console mode, use the function print
:
print(f)
2*x*cos(x^2)
The explicit LaTeX code can be obtained:
print(latex(f))
2 \, x \cos\left(x^{2}\right)
A pdf file with the LaTeX typeset formula is generated by the function view
:
view(f)
x
is the only generic symbolic variable predefined in a SageMath session. All other symbolic variables must be declared explicitly, via the function var
:
y = var('y')
alp = var('alp', latex_name=r'\alpha')
f = alp*y + x
f
diff(f, alp)
SageMath can also compute a primitive:
integrate(x^5/(x^3 - 2*x +1), x, hold=True)
integrate(x^5/(x^3 - 2*x + 1), x)
and of course definite integrals: it suffices to provide the two boundaries after the argument x
. A first attempt with 0 and 1 fails:
# integrate(x^5/(x^3 - 2*x + 1), x, 0, 1)
Don't panic: error messages are usually long because they display the whole call stack. The important information lies at the end:
ValueError: Integral is divergent
Choosing the boundaries to be 2 and 3 yields a convergent integral:
integrate(x^5/(x^3 - 2*x + 1), x, 2, 3)
n(_) # numerical approximation of the above result
SageMath proposes various symbolic engines to evaluate a primitive. The default one is Maxima:
integrate(x^5/(x^3 - 2*x + 1), x, algorithm='maxima') # same result as above
but SymPy is also available:
integrate(x^5/(x^3 - 2*x + 1), x, algorithm='sympy')
as well as Giac:
integrate(x^5/(x^3-2*x+1), x, algorithm='giac')
One can even use WolframAlpha via some internet connection:
integrate(x^5/(x^3-2*x+1), x, algorithm='mathematica_free')
Actually SageMath has some interface to Mathematica:
cos(x^2)._mathematica_init_()
as well as to SymPy, Maxima and Giac:
cos(x^2)._sympy_()
print(cos(x^2)._maxima_())
2 cos(_SAGE_VAR_x )
cos(x^2)._giac_()
Let us check the primitive computation:
f = integrate(x^5/(x^3-2*x+1), x)
f
diff(f, x)
_.simplify_full()
Indefinite integrals can also be computed:
integrate(exp(-x^2), x, -oo, +oo)
exp(x).taylor(x, 0, 8)
lim(sin(x)/x, x=0)
n = var('n') # declaring n as a symbolic variable
sum(1/n^2, n, 1, +oo, hold=True) == sum(1/n^2, n, 1, +oo)
sum(1/n^3, n, 1, +oo)
numerical_approx(_)
Of course, as many standard functions, Riemann's zeta function is already implemented in SageMath:
zeta(2)
solve(x^2 == x + 1, x)
y = function('y')
eq = diff(y(x), x) - y(x) == x*y(x)^4
eq
desolve(eq, y(x))
Finally, to illustrate the advantage of being built atop of Python, here is a loop for displaying Pascal's triangle with only two instruction lines:
for n in range(10):
print([binomial(n, p) for p in range(n+1)])
[1] [1, 1] [1, 2, 1] [1, 3, 3, 1] [1, 4, 6, 4, 1] [1, 5, 10, 10, 5, 1] [1, 6, 15, 20, 15, 6, 1] [1, 7, 21, 35, 35, 21, 7, 1] [1, 8, 28, 56, 70, 56, 28, 8, 1] [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
plot(sin(x^2), (x, 0, 4), axes_labels=['$x$', '$y$'])
See the dedicated notebook.