CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

| Download

Chapter 1 - An introduction in SageMath

Views: 315
Visibility: Unlisted (only visible to those who know the link)
Image: ubuntu2004-eol
Kernel: SageMath 9.7

A course in script languages


Introduction

This is an introductory course on computing and programming with SageMath, designed primarily for students in mathematics, informatics, and engineering, though it is also suitable for those from other disciplines such as physics, biology, and economics.

The course assumes no prior programming experience and is tailored to students with limited exposure to programming. However, we have also included topics to help more experienced programmers enhance their skills, particularly in SageMath.

We hope this material will also be useful for teachers and instructors covering similar subjects.

It's important to note that this course (and the descriptions below) does not aim to cover the mathematical theories related to the tasks and applications discussed. All relevant mathematical topics are thoroughly explained in the primary reference, the BG book, especially in the first seven chapters.

Broadly speaking, these chapters cover topics from linear algebra and its applications, complex numbers, analytic geometry, basic probability, combinatorics, and foundational concepts in calculus and analysis (mainly concerning single-variable functions), such as functions, series, limits, derivatives, integrals, Taylor series, Fourier series, numerical methods, and other.

While we do not provide formal mathematical proofs, we focus on implementing ideas using the aforementioned programming package. However, in some cases, we include the relevant mathematical details for the reader's convenience.

Use of Sage

Sage is a free, open-source software for mathematics and informatics.

It is built on Python, which serves as its foundational language—a point that will become clearer as we progress.

One key advantage of Sage is its accessibility: anyone can easily access it via the official website: http://Sagemath.org{\tt{http://Sagemath.org}}.

Note: Throughout this course, we will use the terms "Sage" and "SageMath" interchangeably. We hope this does not cause confusion.

Let's start with a few practical details about Sage itself. We encourage the readers to follow the links provided for further instructions.

Sage Cells

You can access and use SageMath through a free online editor via any web browser:

https://sagecell.sagemath.org{\tt{https://sagecell.sagemath.org}}

In this way you do not need to have the latest version of SageMath installed on our computer.

However, online editors have some limitations.

Another way to use SageMath is to install it on your own computer.

Then you do not need an Internet connection and you can also save your own work.

CoCalc

Another flavor of Sage Math is using CoCalc, where one should create first an account in CoCalc.com.

In this case there is no longer the need to install and maintain SageMath in your machine.

The same time using the editors that CoCalc offers (Sage Worksheet, Jupiter Notebook, Latex document, etc), one can create projects, save them, and return for editing at any time.

For instance, this document is written in the editors that CoCalc offers.


Chapter 1 - An introduction in SageMath


1.1. Preliminaries (Sage as a Calculator )
1.2. Division of integers and prime numbers via Sage
1.3. Some standard functions in Sage
1.4. Python variables in Sage and other technicalities
1.5. Symbolic variables in Sage
1.6. Applications of symbolic variables
1.7. Booleans
1.8. Subsets of real numbers
1.9. Complex numbers
1.10. Functions in Sage
1.11. Preliminaries on programming with Sage

The first chapter serves as an introduction and warmly welcomes you to SageMath.

We'll explore commands for basic computations, working with numbers, and handling functions. Our goal is to give you a first glimpse of how SageMath handles mathematical expressions and performs essential mathematical tasks.

1.1. Preliminaries (Sage as a Calculator)

With a few minor exceptions, SageMath is based on the Python programming language, meaning it uses Python-like syntax. Therefore, users familiar with Python will quickly adapt to SageMath’s tasks. This also means that much of the introductory material on Python can be useful when learning or teaching SageMath.

However, SageMath’s syntax extends beyond Python’s. For instance, while Python uses **  for exponentiation, SageMath accepts both  and ** and ^. We’ll encounter more examples like this as we go along.

Like Python, SageMath uses = for assignment and ==, <=, >=, <, > for comparisons. These operators work in SageMath just as they do in Python.

Additionally, common operations such as addition, abstraction, multiplication and division (corresponding to +, -, *, /, respectively), work as expected. The same applies for the use of parentheses. More details on these will follow.


Rings and fields of numbers (universes)

Before moving on the description of the main material and explain how Sage can be used to study mathematical tasks or mathematical structures, we discuss some basic syntax.

This appears in many different Sage tasks, and it is easy to master with it.

In particular, we begin with details about numbers, as integers, rationals, etc.

So, let us type the following:

ZZ
Integer Ring
QQ
Rational Field
RR
Real Field with 53 bits of precision
CC
Complex Field with 53 bits of precision

Therefore, ZZ{\tt{ZZ}} represents the ring of integers, QQ{\tt{QQ}} is the field of rational numbers, RR{\tt{RR}} is the field of real numbers and CC{\tt{CC}} is the field of complex numbers.

To check if a given number is an integer, rational, real or complex, we can proceed as described in the following examples.

1/2 in ZZ
False
1/2 in QQ
True
pi in QQ
False
pi in RR # pi = the greek π = the ratio of a circle's circumference to its diameter. #It is an irrational number, approximately equal to 3.14.
True
pi in QQ
False

The imaginary number i satisfies i2=1i^2=-1.

i in RR
False
i in CC
True

In sage we may denote the imaginary number i also by capital I.

I in CC
True
I^2==-1
True
pi in CC
True
bool(pi == pi + 0* i)
True
5 in ZZ
True
-1/2 in QQ
True
e in QQ #the Euler number e: it is defined as the base of the natural logarithm. # The Euler is also an irrational number, approximately equal to 2.71828.
False
e in RR
True
ln(2) in QQ
False
sqrt(3) in QQ #sqrt() is the square-root function--see also below
False
sqrt(4) in QQ
True
2+3*I in CC #The letter I or i is the square root of -1, an imaginary number. We mainly suggest the use of I
True
1+pi*i in RR
False

We see that in Sage, everything that follows the character # is a comment and Sage ignores it. This feature comes from Python.

Comments are very useful, and we'll frequently rely on them—especially in longer Sage cells or when we want to explain something directly within the code. We highly recommend using comments, particularly when sharing your code with others, as they make your work clearer and easier to understand.


The parent function

Another way to check the field, is based on the command parent(){\tt{parent()}} function. For instance we may type

parent(7)
Integer Ring
parent(10.22356)
Real Field with 53 bits of precision
parent(e)
Symbolic Ring
parent(1.254)
Real Field with 53 bits of precision
parent(1/3)
Rational Field
parent(1+I)
Number Field in I with defining polynomial x^2 + 1 with I = 1*I

One can also determine the bits of precision (see also below)

R = RealField(16) R
Real Field with 16 bits of precision

For instance, with this precision Sage computes

R(golden_ratio) #Sage knows all famous numbers, e.g., the golden ratio=(1+sqrt(5))/2
1.618

There is the option of fixing the precision with more bits, e.g.,

R = RealField(50) R(golden_ratio)
1.6180339887499

Sage as a Calculator

Obviously, Sage can be used as a calculator and so basic arithmetics can be done very easily.

Later we will see that Sage can be used also as a graphing calculator\textit{graphing calculator}.

Let us describe some easy examples.


4*2 #it returns the product between 2 and 4
8
4**2 #it returns the 2nd power of 4
16
bool(4**2==16)
True
4**2==16
True
8^2 == (4*2)**2 #Sage checks if it is true that 8^2 is equal to (4x2)x(4x2)
True
16/4 #it returns the ratio of 16 by 4 which equals to 4.
4
(3+4)*2/6 # this returns the ratio of 14 by 6.
7/3

Note that one could use paranethesis to get the same result

((3+4)*2)/6
7/3

This means that the use of parenthesis in Sage is the usual one.

For example, observe the difference between the following two expressions:

7**2-sqrt(16)*5/4
44
(7**2-sqrt(16)*5)/4
29/4

Useful technicalities in Sage to remember

  1. In SageMath it is common to use the print{\tt{print}} command to display intermediate steps. For example:

print((3+4)/3)
7/3

While Sage will always print the output of the last line, printing any other output requires a print command.

Let us illustrate this situation by an example:

7+4 8+2 9/2
9/2

while we can type:

print(7+4) print(8+2) 9/2
11 10
9/2

Note that the values "-", ", "--", "---" (using one, two, and three underscores) are the last three output values.

For instance, type

print(_)
9/2

Or type:

1/(2*10)
1/20
1/(4*10)
1/40

and then

print(_)
1/40
print(__)
1/20
  1. In SageMath the show{\tt{show}} command supports a Latex-like pretty output. Let us compare two expressions:

7/10 + 2/pi
2/pi + 7/10
show(7/10+2/pi)

2π+710\displaystyle \frac{2}{\pi} + \frac{7}{10}

Or as another example, type

exp(I*2*pi/101)
e^(2/101*I*pi)
show(exp(I*2*pi/101))

e(2101iπ)\displaystyle e^{\left(\frac{2}{101} i \, \pi\right)}

Square roots, n-th roots & floating point functions

In the previous commands, we met a first example of a function in SageMath, namely the square-root function sqrt(){\tt{sqrt()}}.

sqrt(49)
7

When the positive integer pp given inside the function sqrt(){\tt{sqrt()}} is a perfect square, i.e., p=q2p=q^2 for some integer qZq\in\mathbb{Z}, then typing the command sqrt(p){\tt{sqrt(p)}} Sage will return the integer qq.

However, when pp is not a perfect square the following cases may appear:

sqrt(8)
2*sqrt(2)
sqrt(17)
sqrt(17)
sqrt(pi)
sqrt(pi)

In many cases we may need to know a decimal presentation of certain expressions, as sqrt(17){\tt{sqrt(17)}}.

In Sage, to arrive to a decimal number (or floating point number) there are many alternatives. For example, we may proceed as below:

sqrt(8.0)
2.82842712474619
sqrt(17.0)
4.12310562561766
sqrt(8.1)
2.84604989415154
sqrt(3.14159)
1.77245310234150

To arrive to a decimal numbe presentations we can also type:

N(sqrt(17))
4.12310562561766

or

n(sqrt(17))
4.12310562561766

As another example, consider the case

29/4
29/4
n(29/4)
7.25000000000000

However, as we saw above, we may also type:

29/4.0
7.25000000000000

Summary:

Both the commands N(p)N(p) and n(p)n(p) return the inserted number pp in a floating point format.

Thus, the functions N()N() or n()n(), they both try to convert what is inside the parentheses to a real number.

These functions come with options, e.g., we can specify the number of digits that we want to contain a floating point number.

n(29/4, digits = 5)
7.2500

Finally, another alternative to get a decimal approximation of a given number goes as follows:

numerical_approx(sqrt(2), digits=200)
1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605715

Of course, one gets the same result via the code

n(sqrt(2), digits = 200)
1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605715

We mention that one can type x.n(p)x.n(p), where inside the parentheses we specify by a positive integer pp how many bits\mathbb{bits} of precission we want. For example:

(29/4).n(25)
7.250000
pi.n(100)
3.1415926535897932384626433833

Note that the default bits are 53 bits of precision. For example, for the irrational number π\pi we get

pi.n()
3.14159265358979

Another classical example:

golden_ratio.n()
1.61803398874989

As another typical example, let us use the number ee, i.e., the base of the natural logarithm.

n(e)
2.71828182845905
e.n()
2.71828182845905

Let us also mention that for the nnth root of a number aa we type a1/n{\tt{a^{1/n}}}. For example:

8^(1/3)
2

Or we can type a(1/n)a**(1/n), that is

8**(1/3)
2
4^(1/2)
2
4**(1/2)
2
27**(1/3)
3
64^(1/4)
2*4^(1/4)

However, notice that

15^(1/3)
15^(1/3)
15**(1/3)
15^(1/3)

In this case to get an answer we can type

n(15^(1/3))
2.46621207433047

In some cases we may need to find how many digits has a number, and the command ndigits{\tt{ndigits}} is appropriate for this. Also we may need to count hom many times a certain digit appears isnside a given number. Let us describe an example:

Example

Compute the digits of the number p=2200p=2^{200}. Then count how many times appears the digit 22 in the expression of pp.

Solution:

p=2**200 show(p) p.ndigits()

1606938044258990275541962092341162602522202993782792835301376\displaystyle 1606938044258990275541962092341162602522202993782792835301376

61

Thus pp consists of 61 digits. For the second task we type:

p.digits().count(2)
12

Thus Sage counts twelve times the digit 2 in the expression of p.


1.2. Division of integers and prime numbers via Sage

Above we saw that when dividing two integers a subtlety may appear: SageMath will return either a fraction or its decimal approximation.

Let us describe such an example:

7/4
7/4
7/4.0
1.75000000000000
10.512/3
3.50400000000000

In general, SageMath will attempt to be as precise as possible and will return the fraction unless told otherwise.

As we saw above, one way to tell to SageMath that we want the decimal approximation, is to include a decimal in the expression itself.

7/4.0
1.75000000000000

Otherwise we can use some of the functions N{\tt{N}} or n{\tt{n}}, introduced above.

Now, during the procedure of division of integers in many cases we may need to know the integer quotient and also the remainder of the division.

To calculate the quotient we use the // operator. On the other hand, the % operator is used for the remainder.

11//4 # for integer arguments, // returns the integer quotient
2
11 % 4 #for integer arguments, % means mod, i.e., it returns the remainder
3
14//4
3
14 % 4
2

We can take both the quotient and the remainder, all at once, via the command divmod(){\tt{divmod()}}. For instance

divmod(14,4)
(3, 2)

In Sage there is also a built-in command available to check whether one integer divides another. This goes as follows:

4.divides(14)
False
4.divides(16)
True

We can also find all positive divisors of a fixed integer. We can do this via the command divisors(){\tt{divisors()}}:

14.divisors()
[1, 2, 7, 14]
16.divisors()
[1, 2, 4, 8, 16]
5.divisors()
[1, 5]

Hence from the above we conclude for example that between the numbers 14, 16, and 5 only 5 is a prime number.

To check if an integer is prime, we can also use the command .is_prime(){\tt{.is\_prime()}}.

5.is_prime()
True
167.is_prime()
True
(4^2-3).is_prime()
True
10.is_prime()
False
(3^29-1).is_prime()
False
163.is_prime()
True
(163-6).is_prime()
True

Finally, let us mention the syntax .factor(){\tt{.factor()}} which is about the prime factorization of an integer.

51.factor()
3 * 17
52.factor()
2^2 * 13

In case we need to locate the prime numbers dividing an integer, SageMaths provides the command .prime_divisors(){\tt{.prime\_divisors()}}.

Another available command is .prime_factors(){\tt{.prime\_factors()}}.

23.prime_divisors()
[23]
24.prime_divisors()
[2, 3]
163.prime_divisors()
[163]
164.prime_divisors()
[2, 41]
30.prime_factors()
[2, 3, 5]

There is also the command gcd(){\tt{gcd}()} which returns the largest between the common divisors of two given integers.

gcd(10, 5)
5
gcd(100, 200)
100

Exercise

  1. Compute a decimal approximation of 22\frac{\sqrt{2}}{2} with five digits.

  2. Compute a decimal approximation of 22\frac{\sqrt{2}}{2} with seven bits of precision.

  3. Compute the integer quotient of 25 by 4, and find the remainder.

  4. Is the number 163 prime?

  5. Provide the prime factorization of the integers 120, 121, 1020 and 1021.

  6. Find the prime divisors of the integers 165 and 169.

  7. Find the greatest common divisor for the integers (18, 76).

Solution:

N(sqrt(3), digits=10)
1.732050808
N(sqrt(2)/2, digits=5)
0.70711
(sqrt(2)/2).n(7)
0.71
25 //4
6
25 % 4
1
120.factor()
2^3 * 3 * 5
121.factor()
11^2
1021.factor()
1021
1020.factor()
2^2 * 3 * 5 * 17
165.prime_divisors()
[3, 5, 11]
gcd(18, 76)
2

1.3. Some standard functions in Sage

SageMath becomes very attractive and useful since it includes most of the standard functions that we encounter studying basic mathematical structures.

Above we already met the square-root function sqrt(){\tt{sqrt()}}.

Below we will refresh some other very commonly used functions, as the absolute value, the maximum, minimum, floor, ceiling, trigonometric, exponential, and logarithm functions.


A summary of standard functions in Sage

  1. The abs(){\tt{abs()}} function returns the absolute value of a real number.

  2. The max(){\tt{max()}} and min(){\tt{min()}} functions return the largest and smallest of a set of numbers.

  3. The floor(){\tt{floor()}} function rounds a number down to the nearest integer, while the function ceil(){\tt{ceil()}} rounds up (see also below).

  4. The trigonometric functions sin(){\tt{sin()}}, cos(){\tt{cos()}}, tan(){\tt{tan()}}. These functions, during evaluation, have the same behavior as sqrt(){\tt{sqrt()}}.

  5. The inverse trigonometric functions are built-in, for instance the inverse of tan\tan corresponds to arctan(){\tt{arctan()}}.

  6. Most of the hyperbolic functions are also built-in, as sinh(){\tt{sinh()}}.

  7. In SageMath exponentiation base ee, can be done using the exp(){\tt{exp()}} function (or simply by using e and raising to the appropriate power).

  8. In SageMath for the logarithm (the inverse function to exponentiation) we can use the functions log(){\tt{log()}} or ln(){\tt{ln()}}, which both represent the logarithm in base ee.

    We may also specify a different base as a second argument to the command. Therefore, to compute logb(x)\log_{b}(x) in SageMath, use the command log(x,b){\tt{log(x,b)}}.

Exercise

Compute in SageMath the following:

  1. The absolute value (length) of the complex number πi\pi i (see below for complex numbers)

  2. The absolute value of log(1/3)\log(1/3).

  3. The value of sin(2π/3)\sin(2\pi/3) as a fraction.

  4. The values cos0\cos 0, sinπ\sin\pi.

  5. The value sin2\sin 2 with accuracy of 10 digits.

  6. Construct further examples yourself.

Solution:

abs(-1)
1
sin(pi/2)
1
log(1)
0
N(ln(2))
0.693147180559945
abs(pi*I)
pi
abs(log(1/3))
-log(1/3)
sin(2*pi/3)
1/2*sqrt(3)
cos(0)
1
sin(pi)
0
N(sin(2),digits=10)
0.9092974268
ln(e)
1
log(e)
1
ln(2.4)==log(2.4)
True
exp(0)
1
exp(1)
e
log(1)
0
e^(log(1/2))
1/2
exp(pi)+2*sqrt(6)
2*sqrt(6) + e^pi
log(pi/4)+4*sin(e)
log(1/4*pi) + 4*sin(e)
show(log(pi/4)+4*sin(e))

log(14π)+4sin(e)\displaystyle \log\left(\frac{1}{4} \, \pi\right) + 4 \, \sin\left(e\right)

log(1.4567)+4*sin(0.1223)
0.864154997470704

We will return on functions and how we can treat them in Sage a few below.


Tip:

To access the help page for a function in SageMath, type the name of the function and then add a question mark.

After running such a command, a new window area will open where are given the details for the corresponding function.

Finally, using two question marks will show the source code of the function under question.

For instance, ask yourself Sage for the cos function.

cos?
cos??

1.4. Python variables in Sage and other technicalities

In SageMath variables are defined using the "=" operator.

Often, such variables are called Python variables\textbf{Python variables}, and should be distinguished from the symbolic variables\textbf{symbolic variables} in Sage, that we will introduce below.

Note that some operations (such as variable assignment) do not have an output and we add another line to print the value of our variable.

For instance:

mul = 11 * 12 mul
132

In this way we have assigned a value to the variable mul\text{mul}, namely the value 11×12=13211\times 12=132.

Thus mul\text{mul} is a Python variable, which we can use to implement further operations:

mul+4
136
mul/2+4
70
mul/11
12

Another example: We introduce a python variable that we call ``example''

example=pi/2; example
1/2*pi
N(example)
1.57079632679490
N(example+1)
2.57079632679490

We can now combine both Python variable, ``mul'' and ''example'' introduced above to construct a new variable:

exa2=(example*mul)**2; exa2
4356*pi^2
bool(exa2/(mul^2)==example^2)
True

As another example, entering z=3z=3 means that zz will be assigned the value 33:

z=3; z
3

If we then evaluate for example the expression 6+3z 6 + 3z, Sage will return 15:

6+3*z
15

Or type

3/(2*z^3)
1/18
(1/4)*z**2
9/4

Or you can combine both the variables mul\text{mul} and zz:

(1/4)*z**2+mul/11
57/4
z=3; print(z)
3
Tip

To restore all predefined variables and functions instead, the command restore(){\tt{restore()}} is the appropriate one.

When, in addition, all user-defined Python variables should be deleted, we type reset(){\tt{reset()}}.

Try some examples yourselves.

On the other hand, a double-equal sign (==) is a test of equality between two expressions.

Since we previously set z=3z = 3, then evaluating z==3z == 3 returns True{\tt{True}}, whereas evaluating z==2z ==2 return False{\tt{False}}:

z==4
False
z==2
False

Note that variables can be useful for many reasons, and especially in computations. E.g.:

y=sin(5)+cot(4); y
cot(4) + sin(5)
show(y)

cot(4)+sin(5)\displaystyle \cot\left(4\right) + \sin\left(5\right)

show(y/2)

12cot(4)+12sin(5)\displaystyle \frac{1}{2} \, \cot\left(4\right) + \frac{1}{2} \, \sin\left(5\right)

show(N((y/2)^10))

5.99211556964472×1014\displaystyle 5.99211556964472 \times 10^{-14}

show(ln(y)^(1/4)/16)

116log(cot(4)+sin(5))14\displaystyle \frac{1}{16} \, \log\left(\cot\left(4\right) + \sin\left(5\right)\right)^{\frac{1}{4}}

Remark

We mention that in SageMath mathematical objects and variables can be inserted in print commands using commas, or using carefully empty curly braces {} and .format(math1,math2,...){\tt{.format(math1,math2,...)}}.

Let us present an example:

Consider the function f(x)=x4+5x2.f(x)=\displaystyle x^{4} + 5 \, x - 2.

f(x)=x^4+5*x-2; show(f); show(f(x)); show("The function that we treat has the form {}".format(f(x)))

x  x4+5x2\displaystyle x \ {\mapsto}\ x^{4} + 5 \, x - 2

x4+5x2\displaystyle x^{4} + 5 \, x - 2

The function that we treat has the form x^4 + 5*x - 2\displaystyle \verb|The|\verb| |\verb|function|\verb| |\verb|that|\verb| |\verb|we|\verb| |\verb|treat|\verb| |\verb|has|\verb| |\verb|the|\verb| |\verb|form|\verb| |\verb|x^4|\verb| |\verb|+|\verb| |\verb|5*x|\verb| |\verb|-|\verb| |\verb|2|

print("The area of a circle of radius 1 is approximately",pi.n())
The area of a circle of radius 1 is approximately 3.14159265358979
print("The square-root of {} is approximately {}".format(log(2),sqrt(log(2)).n()))
The square-root of log(2) is approximately 0.832554611157698

Now, as we said, SageMath is essentially built on Python, and hence uses much of the same syntax.

Hence, for example, indentation is extremely important.

To understand better what we mean, the description of an example is helpful:

a=4-pi if a<0: print("Negative") elif a==0: print("Zero") else: print("Positive")
Positive

We will meet further examples how to use the statements if{\tt{if}}, elif{\tt{elif}} and else{\tt{else}} in the final section of this introductory chapter.

Tip

Useful to know that an if{\tt{if}} statement can be written in one line, as follows:

a = 2 if a>0: print("Positive")
Positive

1.5. Symbolic variables in Sage

In Sage you can declare your own variables, no matter what the application is.

These ``Sage variables'' are often called symbolic variables{\textbf{symbolic variables}}.

Roughly speaking the symbolic variables play the role of “indeterminates{\mathit indeterminates}” that we often use in mathematical solving.

There are several ways to establish or introduce a symbolic variable in Sage, as we will see below via examples.


x = var("x"); x #recall that we use ; to type in the same line more than one commands
x
var("z a b c")
(z, a, b, c)

or

x = SR.var("x"); x
x

In both cases Sage returns a symbolic variable named xx. Or you can simply type var("x"){\tt{var("x")}}.

A variable can also given by yy, or zz, or tt, etc.

y=SR.var("y"); y
y

Moreover, one can introduce many variables together in a row:

x, y, z=var("x, y,z") x+y+z
x + y + z

Sage now treats the expression x+y+z as a function on the variables x, y, z. For instance

t=var('t') f(t)=t^3+4*t+5 show(f(3))

44\displaystyle 44

var("theta")
theta
g(theta)=sin(theta)+theta/2 -ln(theta); g
theta |--> 1/2*theta - log(theta) + sin(theta)
N(g(pi/3))
1.34350658220145
plot(g(theta), theta, (1, pi))
Image in a Jupyter notebook
show(solve([g(theta)==0], theta))

[θ=2log(θ)2sin(θ)]\displaystyle \left[\theta = 2 \, \log\left(\theta\right) - 2 \, \sin\left(\theta\right)\right]

x, y, z=var("x, y,z") f(x, y, z)=2*x-(1/2)*y+z^2 f(2, 2, 1)
4

Remark

\bullet As we will explain also below, SageMath realizes automatically{\textit{automatically}} xx as a symbolic variable, which is not the case for other variables.

Hence working only with the symbolic variable x{\tt{x}}, it is general unnecessary to declare it as a symbilic variable (especially in https://sagecell.sagemath.org).

\bullet Often, dealing with mathematical expressions we need to be sure that our symbolic variables live in the right domain.

For that, we can use the command assume{\tt{assume}} (or we can make Sage to ``forgot'' assumptions, via the command forget{\tt{forget}}). For instance:

x = var("x") assume(x >= 0) bool(abs(x) == x)
True
forget(x >= 0) bool(abs(x) == x)
False

Another example of this type:

assume(x>0); bool(sqrt(x**2)==x)
True
forget(x>0); bool(sqrt(x**2)==x)
False

We can also create symbolic variables by using the syntax

x=SR.var("x", n)

This returns the symbolic variables for x0,x1,,xnx_{0}, x_{1}, \ldots, x_{n} for some positive integer nn. For example:

x=SR.var("x") a=SR.var("a", 4) a[0]+a[1]*x+a[2]*x**2+a[3]*x**3
a3*x^3 + a2*x^2 + a1*x + a0

In the previous result we may fix the parameters a3,a2,a1,a0a_3, a_2, a_1, a_0 to obtain a polynomial of degree three.

For such substitutions one may use the command .subs(){\tt{.subs()}}, in a cell as follows:

x=SR.var("x") a=SR.var("a", 4) a[0]+a[1]*x+a[2]*x**2+a[3]*x**3 f=a[0]+a[1]*x+a[2]*x**2+a[3]*x**3 f.subs(a[0] == 8,a[1] == 6, a[2] == 1, a[3] == 1/8)
1/8*x^3 + x^2 + 6*x + 8

If we want to plot the resulting polynomial we may type

plot(1/8*x**3+x**2+6*x+8, (x, -50, 50))
Image in a Jupyter notebook

We will discuss more details on 2D-ploting in SageMath in Chapter 2.

Now, let us mention that using the function coefficient(){\tt{coefficient()}} we can take the coefficients of any term in a given polynomials.

For instance the following cell returns the coefficient of x3x^3 in the previous expression:

x=SR.var("x") a=SR.var("a", 4) f=a[0]+a[1]*x+a[2]*x**2+a[3]*x**3 f.coefficient(x^3)
a3

1.6. Applications of symbolic variables

Let us present now some very basic applications of symbolic variables\textbf{symbolic variables}, in terms of exercises.

We will treat equations (and in particular polynomial equations) and also plots (graphs) of functions, although these topics will be analyzed in more details in Chapter 2.

Exercise

Let a,b,cRa, b, c\in\R be three real numbers. Assuming that a>0a> 0, solve the equations ax+b=0ax+b=0, and ax2+bx+c=0ax^2+bx+c=0 with respect to xx.

Solution:

x, a, b=var("x, a, b") assume(a>0) solve(a*x+b==0, x)
[x == -b/a]

Notice that the solve{\tt{solve}} command returns a list of solutions. Sage uses brackets to indicate a list.

In our case, there is only one solution so the list contains only one element.

We will learn more on lists in Sage a few below.

For the second equation, type the following:

x, a, b, c=var("x, a, b, c") assume(a>0) solve(a*x**2+b*x+c==0, x)
[x == -1/2*(b + sqrt(b^2 - 4*a*c))/a, x == -1/2*(b - sqrt(b^2 - 4*a*c))/a]

Remark

  1. To get the 2nd entry of the list presented by Sage in the previous example, there are many methods. One of them goes as follows:

x, a, b, c=var("x, a, b, c") assume(a>0) sol=solve(a*x**2+b*x+c==0, x) sol[1]
x == -1/2*(b - sqrt(b^2 - 4*a*c))/a

Notice here that Sage, as Python, starts all lists (and array) indices with element zero. Hence the second element of our list corresponds to 1.

Lists are important in Sage, and hence below we will analyze more their implementation, by further applications.

  1. Notice that above we used the command assume{\tt{assume}} to assume that a>0a>0.

Keep in mind that this command applies to many cases and we will meet it again.

Finally, you may want to plot a polynomial of degree two to arrive to a certain parabola.

Let us present an example (with discriminant Δ=0\Delta=0, and thus a double root).

x, a, b, c=var("x, a, b, c") assume(a>0); solve(a*x**2+b*x+c==0, x) f(x)=a*x**2+b*x+c plot(f.subs(a==1, b==2, c==1), (x, -5, 5))
Image in a Jupyter notebook

Exercise for practice

Indicate in the previous plot the point on R2\R^2 induced by the double root x=b2ax=-\frac{b}{2a} of the equation f(x)=0f(x)=0.

Hint: in case you find difficulties see the first section in Chapter 2.

Exercise

Let a1,a2,.a6a_1, a_2, \ldots. a_6 positive real numbers. Show that A6A5>0\frac{A_{6}}{A_{5}}>0 where An=a1++annA_{n}=\frac{a_1+\cdots+a_n}{n}.

Solution:

Of course the statement is obvious. We pose this task to improve our understanding on the use of symbolic variables, and also of the command bool{\tt{bool}}.

a1, a2, a3, a4, a5, a6=var("a1, a2, a3, a4, a5, a6") assume(a1>0, a2>0, a3>0, a4>0, a5>0, a6>0) A6=(a1+a2+a3+a4+a5+a6)/6 A5=(a1+a2+a3+a4+a5)/5 bool(A6/A5>0)
True
Exercise

Present the graph of the function f(x)=4x5+32x2+3x+4f(x)=4x^5+32x^2+3x+4 with 2x2-2\leq x\leq 2.

Solution:

Note that we dont need to setup xx as a symbolic variable, although we want to treat a function of xx and find its plot. Indeed, we may just type:

# as above, we plot a function using the "plot" function in SAGE # we specify range of x as -2 to 2 plot(4*x**5+32*x**2+3*x+4, x, -2, 2)
Image in a Jupyter notebook

However, one will arrive to the same figure, if instead use the following Sage cell:

x=var("x") plot(4*x**5+32*x**2+3*x+4, x, -2, 2)
Image in a Jupyter notebook

This simple example verifies that SageMath understands x{\tt{x}} automatically as a symbolic variable.

In other words, Sage initializes the Symbolic Ring to have one symbolic variable, namely x{\tt{x}}, and this obeys the arithmetical rules that one may expect.

However, note that this is not the case for other variables as y,zy, z, etc.

For instance running the command plot(4y5+32y2+3y+4,y,2,2){\tt{plot(4*y**5+32*y**2+3*y+4, y, -2, 2)}} we will get an error (make the experiment in your editor).

We will analyze further the importance of symbolic variable in Sage in the sequel.

Although we will meet more details on polynomials in Chapter 2, let us list some commands useful when treating such kind of functions.

Try yourself to explore them, and realize their implementation by making some tests.

factor{\tt{factor}}, expand{\tt{expand}}, combine{\tt{combine}}, collect{\tt{collect}}.

floor?
Signature: floor(x, **kwds) Type: Function_floor String form: floor File: /ext/sage/9.7/src/sage/functions/other.py Docstring: The floor function. The floor of x is computed in the following manner. 1. The "x.floor()" method is called and returned if it is there. If it is not, then Sage checks if x is one of Python's native numeric data types. If so, then it calls and returns "Integer(math.floor(x))". 2. Sage tries to convert x into a "RealIntervalField" with 53 bits of precision. Next, the floors of the endpoints are computed. If they are the same, then that value is returned. Otherwise, the precision of the "RealIntervalField" is increased until they do match up or it reaches "bits" of precision. 3. If none of the above work, Sage returns a symbolic "Expression" object. EXAMPLES: sage: floor(5.4) 5 sage: type(floor(5.4)) <class 'sage.rings.integer.Integer'> sage: var('x') x sage: a = floor(5.4 + x); a floor(x + 5.40000000000000) sage: a.simplify() floor(x + 0.4000000000000004) + 5 sage: a(x=2) 7 sage: floor(cos(8) / cos(2)) 0 sage: floor(log(4) / log(2)) 2 sage: a = floor(5.4 + x); a floor(x + 5.40000000000000) sage: a.subs(x==2) 7 sage: floor(log(2^(3/2)) / log(2) + 1/2) 2 sage: floor(log(2^(-3/2)) / log(2) + 1/2) -1 sage: floor(factorial(50)/exp(1)) 11188719610782480504630258070757734324011354208865721592720336800 sage: floor(SR(10^50 + 10^(-50))) 100000000000000000000000000000000000000000000000000 sage: floor(SR(10^50 - 10^(-50))) 99999999999999999999999999999999999999999999999999 sage: floor(int(10^50)) 100000000000000000000000000000000000000000000000000 Small numbers which are extremely close to an integer are hard to deal with: sage: floor((33^100 + 1)^(1/100)) Traceback (most recent call last): ... ValueError: cannot compute floor(...) using 256 bits of precision This can be fixed by giving a sufficiently large "bits" argument: sage: floor((33^100 + 1)^(1/100), bits=500) Traceback (most recent call last): ... ValueError: cannot compute floor(...) using 512 bits of precision sage: floor((33^100 + 1)^(1/100), bits=1000) 33 sage: import numpy sage: a = numpy.linspace(0,2,6) sage: floor(a) array([0., 0., 0., 1., 1., 2.]) sage: floor(x)._sympy_() floor(x) Test pickling: sage: loads(dumps(floor)) floor Init docstring: The floor function. The floor of x is computed in the following manner. 1. The "x.floor()" method is called and returned if it is there. If it is not, then Sage checks if x is one of Python's native numeric data types. If so, then it calls and returns "Integer(math.floor(x))". 2. Sage tries to convert x into a "RealIntervalField" with 53 bits of precision. Next, the floors of the endpoints are computed. If they are the same, then that value is returned. Otherwise, the precision of the "RealIntervalField" is increased until they do match up or it reaches "bits" of precision. 3. If none of the above work, Sage returns a symbolic "Expression" object. EXAMPLES: sage: floor(5.4) 5 sage: type(floor(5.4)) <class 'sage.rings.integer.Integer'> sage: var('x') x sage: a = floor(5.4 + x); a floor(x + 5.40000000000000) sage: a.simplify() floor(x + 0.4000000000000004) + 5 sage: a(x=2) 7 sage: floor(cos(8) / cos(2)) 0 sage: floor(log(4) / log(2)) 2 sage: a = floor(5.4 + x); a floor(x + 5.40000000000000) sage: a.subs(x==2) 7 sage: floor(log(2^(3/2)) / log(2) + 1/2) 2 sage: floor(log(2^(-3/2)) / log(2) + 1/2) -1 sage: floor(factorial(50)/exp(1)) 11188719610782480504630258070757734324011354208865721592720336800 sage: floor(SR(10^50 + 10^(-50))) 100000000000000000000000000000000000000000000000000 sage: floor(SR(10^50 - 10^(-50))) 99999999999999999999999999999999999999999999999999 sage: floor(int(10^50)) 100000000000000000000000000000000000000000000000000 Small numbers which are extremely close to an integer are hard to deal with: sage: floor((33^100 + 1)^(1/100)) Traceback (most recent call last): ... ValueError: cannot compute floor(...) using 256 bits of precision This can be fixed by giving a sufficiently large "bits" argument: sage: floor((33^100 + 1)^(1/100), bits=500) Traceback (most recent call last): ... ValueError: cannot compute floor(...) using 512 bits of precision sage: floor((33^100 + 1)^(1/100), bits=1000) 33 sage: import numpy sage: a = numpy.linspace(0,2,6) sage: floor(a) array([0., 0., 0., 1., 1., 2.]) sage: floor(x)._sympy_() floor(x) Test pickling: sage: loads(dumps(floor)) floor Call docstring: Allows an object of this class to behave like a function. If "floor" is an instance of this class, we can do "floor(n)" to obtain the floor of "n".

Exercise

Recall from above that the floor of a real number xRx\in\mathbb{R} (also called the integer part of xx), is the greatest integer which is less than or equal to xx.

This is usually denoted by x\lfloor x\rfloor or simply by [x][x].

The floor function is then defined by f(x)=xf(x)=\lfloor x\rfloor, for all xRx\in\mathbb{R}.

Plot in Sage the floor function. Hint: Use the command floor{\tt{floor}}.

Solution:

Let us try to use the command floor{\tt{floor}}, as it is suggested, and sketch the graph of the floor function for 5x5-5\leq x\leq 5. We type:

var("x") fl_function(x)=floor(x) plot(fl_function(x), x, -5, 5)
Image in a Jupyter notebook

Of course, the vertical lines are not part of the graph. Moreover, the floor functions has discontinuities at any integer nZn\in\mathbb{Z}.

To sketch in a better way the graph of the floor function we may use inside the plot function the option exlude{\tt{exlude}}, to exlude these discontinuities.

The result is a the same figure as above, but without the vertical lines, see here:

plot(fl_function(x), x, -5, 5, exclude=[-5..5])
Image in a Jupyter notebook

Finally, one can plot the floor function in a more manual way and present the discontinuities by a small circle.

Our method for this relies on the logical for{\tt{for}} and goes as follows:

var("x") f=floor(x) p=plot(f, x, -5, 5, color="steelblue",ticks=[1,1]) for x in [-5..5] : p+=point([x,x], size=30, color="black") p+=circle((x,x-1),0.08,color="black") show(p)
Image in a Jupyter notebook

Exercise

Plot in Sage via the command implicit_plot{\tt{implicit\_plot}} the function f(x,y)=xn+yn1f(x, y)=x^n+y^n-1, for different values of nn.

Solution:

For n=1n=1 the implicit plotting of ff will give a line. For n=2n=2 we get a circle:

var("x") n=2 f(x, y)=x^n+y^n-1 implicit_plot(f, (x, -2, 2), (y, -2, 2), color="green")
Image in a Jupyter notebook
n=3 implicit_plot(x^n+y^n-1, (x, -2, 2), (y, -2, 2), color="green")
Image in a Jupyter notebook
n=4 implicit_plot(x^n+y^n-1, (x, -2, 2), (y, -2, 2), color="green")
Image in a Jupyter notebook
n=50 implicit_plot(x^n+y^n-1, (x, -2, 2), (y, -2, 2), color="green")
Image in a Jupyter notebook
n=51 implicit_plot(x^n+y^n-1, (x, -2, 2), (y, -2, 2), color="green")
Image in a Jupyter notebook

Further details on plotting with Sage will be covered in the forthcoming chapters. Additionally, examples of working with symbolic variables often involve computing sums, both finite and infinite, which are of particular importance in mathematics. Thus, it is useful to know how to compute a given sum using a mathematical package. Let us present such an example.

Exercise

It is well-known that using the principle of mathematics induction over the natural number N={1,2,}\mathbb{N}=\{1, 2, \cdots\} one can show that Δn:=1+2++n=n(n+1)2.\Delta_{n}:=1+2+\cdots+n=\frac{n(n+1)}{2}\,. Such integers Δn\Delta_n are called triangular numbers. Verify In Sage this result.

Solution:

We use the command sum(){\tt{sum()}}, which we will meet again in Chapter 2 when we will study series. For out task, its implementation goes as follows

n, k = var("n, k") f=k sum1 = sum(f, k, 1, n, hold = True) show(sum1 == sum1.unhold().factor())

k=1nk=12(n+1)n\displaystyle {\sum_{k=1}^{n} k} = \frac{1}{2} \, {\left(n + 1\right)} n

Exercise

Compute the sum m=1n(n2+m)2\sum_{m=1}^{n}(n^2+m)^2.

Solution:

var("m, n") sum1 = sum((m+n**2)**2, m, 1, n, hold=True) show(sum1) show(sum1.unhold())

m=1n(n2+m)2\displaystyle {\sum_{m=1}^{n} {\left(n^{2} + m\right)}^{2}}

n5+n4+43n3+12n2+16n\displaystyle n^{5} + n^{4} + \frac{4}{3} \, n^{3} + \frac{1}{2} \, n^{2} + \frac{1}{6} \, n

Exercise

Compute the sum k=1nk2\sum_{k=1}^nk^2.

Solution:

k, n = var("k n") sum(k^2, k, 1, n)
1/3*n^3 + 1/2*n^2 + 1/6*n
Further examples on symbolic variables
var("course") assume(course>0) f(course)=4*course^2+2*course+1; print(f) show(f(course))
course |--> 4*course^2 + 2*course + 1

4course2+2course+1\displaystyle 4 \, \mathit{course}^{2} + 2 \, \mathit{course} + 1

g(t)=t^4 diff(g, t)(t=2)
32

1.7. Booleans

Next, we will explore how to evaluate set operations. This can be done using the bool(){\tt{bool( )}} function. The  bool(){\tt{bool( )}} function in Python and SageMath is used to convert a given value or expression into a Boolean value, either True or False. It can be used in conditions involving sets or other collections, where it helps to determine if the collection is empty or contains elements, etc. For example:

# Logical condition example x = 12 bool(x > 5 and x < 20)
True

Let us now work with sets that contain strings, where you asked to test various properties of these sets. In SageMath (and in Python), sets are defined by using the curly braces { }\{ \ \}.


Exercise

For the sets given below (consisting of words (strings)), use SageMath to test membership using the bool() function. fruits={"apple","banana","cherry","date"},   colors={"red","green","blue","yellow","cherry"}\text{fruits}= \{"apple", "banana", "cherry", "date"\},\ \ \ \text{colors} = \{"red", "green", "blue", "yellow", "cherry"\} In particular, do the following:

  1. Test if "cherry" is in both sets.

  2. Test if "apple" is in the colors set.

  3. Check if the intersection of the sets is non-empty.

  4. Check if the fruits set is a subset of the colors set.

  5. Perform a union of the two sets.

  6. Test if "banana" is in the combined set and "blue" is in the colors set.

  7. Test if "date" is not in the colors set or "green" is in the fruits set.

Solution:

# Define two sets of strings fruits = {"apple", "banana", "cherry", "date", "Art"} colors = {"red", "green", "blue", "yellow", "cherry", "cherry"} print(fruits) colors
{'cherry', 'Art', 'date', 'banana', 'apple'}
{'blue', 'cherry', 'green', 'red', 'yellow'}
colors.intersection(fruits)
{'cherry'}

months={"June", "August", "September", "January"} days={"Monday", "Friday", "Saturday", "Sunday", "January"} print(bool("Friday" in months))
False
dM=days.union(months); print(dM)
{'January', 'Saturday', 'Monday', 'Friday', 'June', 'September', 'Sunday', 'August'}
is_not_empty=days.intersection(months); is_not_empty
{'January'}

Next, we have:

# Check if the intersection of the sets is non-empty non_empty_intersection = bool(fruits.intersection(colors)) # Check if the fruits set is a subset of the colors set fruits_subset_of_colors = bool(fruits.issubset(colors)) # Print the results non_empty_intersection, fruits_subset_of_colors
(True, False)

Moreover:

# Perform a union of the two sets combined_set = fruits.union(colors) # Test if "banana" is in the combined set and "blue" is in the colors set test_combined = bool("banana" in combined_set and "blue" in colors) # Test if "date" is not in the colors set or "green" is in the fruits set test_negation = bool("date" not in colors or "green" in fruits) # Print the results test_combined, test_negation
(True, True)

Exercise for practice

Consider the sets:

set1={1,2,"apple","banana"},   set2={3,4,"apple","cherry"}.\text{set1}=\{1, 2, "apple", "banana"\}, \ \ \ \text{set2}= \{3, 4, "apple", "cherry"\}.

Use the bool() function to test the following:

  1. Check if the string "apple" is in both sets.

  2. Check if the number 2 is in set1 but not in set2.

  3. Check if the string "apple" is in both sets.

  4. Check if the number 2 is in set1 but not in set2.

  5. Check if the intersection of set1 and set2 is non-empty.

  6. Check if the union of set1 and set2 is non-empty.

  7. Check if "banana" is in set1 or set2.

  8. Check if the number 3 is in set2 and the string "cherry" is in set2.

We will return to Boolean operations on general sets in Chapter 2.


1.8. Subsets of real numbers

Many of the given tasks in this course require the use of real numbers only.

Hence it can be useful to pose already in this place some commands in SageMath appropriate to treat subsets of the real line.


Remark

The known mathematical notation for open (or closed) intervals of R\mathbb{R} applies in Sage too. However, there are alternatives:

For instance, one can type RealSet(a,b){\tt{RealSet(a, b)}}, for some a,bRa, b\in\mathbb{R}, which gives the open interval (a,b)(a, b).

Let us present some examples.

(0, 1)
(0, 1)
RealSet((0,1)) # this will give the open set from two numbers
(0, 1)
[0, 1]
[0, 1]
RealSet([0, 2])
[0, 2]

Or, to get a closed subset we may type:

[0, 1]
[0, 1]
RealSet([0,1])
[0, 1]
RealSet.closed(1, 0)
[0, 1]

However, since brackets must be balanced in Python, we see that typing (0,1]{\tt{(0, 1]}}, for example, we will get an error:

(0, 1]
Input In [47] (Integer(0), Integer(1)] ^ SyntaxError: closing parenthesis ']' does not match opening parenthesis '('

The naive notation for half-open intervals works only as follows:

RealSet.open_closed(0,4)
(0, 4]
RealSet.closed_open(0,4)
[0, 4)

We may also define single sets, as follows:

RealSet.point(4) RealSet.point(pi)
{pi}

Or we may type

RealSet(x == 4)
{4}
RealSet(x == pi)
{pi}

Here are some further options that we can use to define subsets of the real line:

RealSet.unbounded_below_open(0)
(-oo, 0)
RealSet.unbounded_below_open(10)
(-oo, 10)
RealSet.unbounded_below_closed(1.234)
(-oo, 1.23400000000000]
RealSet.unbounded_above_open(0)
(0, +oo)
RealSet.unbounded_above_closed(0)
[0, +oo)
RealSet(x < 2)
(-oo, 2)
RealSet(2 < x)
(2, +oo)
RealSet(2 <= x)
[2, +oo)
RealSet(-oo, oo)
(-oo, +oo)

The real line forms a very basic example of a (smoth) manifold, and Sage knows about manifolds - a notion that unfortunatelly we will not discuss further in these notes.

However, lets us present the real line as a manifold in Sage, which provides an alternative interpretation of the outpout given for the previous case.

R = manifolds.RealLine(); R
Real number line ℝ
RealSet(R)
(-oo, +oo)

Let us now discuss some methods, which all return as a result the union of subsets of the real line:

RealSet(x != 0)
(-oo, 0) ∪ (0, +oo)
RealSet(x != 2)
(-oo, 2) ∪ (2, +oo)
RealSet((0,1), [2,3])
(0, 1) ∪ [2, 3]
RealSet((0,1), [2,3], (3, 5))
(0, 1) ∪ [2, 5)
RealSet((1,4), (0,2))
(0, 4)
RealSet(x >= 0, x <-1)
(-oo, -1) ∪ [0, +oo)

We will meet some (topological) characteristics of subsets of the real line, as upper/lower bounds, interior, closure, etc, in Chapter 2.

Let us now present additional syntax referring to subsets of R\mathbb{R}.


Basic Boolean tasks using subsets of the real line

A = RealSet(0, 1)[0] A.is_empty() False
False
S1 = RealSet((0, 2), (4, 5)) S2 = RealSet((1, 2)) S3 = RealSet.point(3) RealSet.are_pairwise_disjoint(S1, S2, S3)
False
RealSet.are_pairwise_disjoint(S1, S3, [6,6])
True
A = RealSet((1,4)) B = RealSet((1,2)) C = RealSet((2,3)) B.is_subset(A)
True
A.is_subset(B)
False
C.is_subset(A)
True
C.is_subset(B)
False

Union of subsets - a further perspective

S1 = RealSet(-1,2) S2 = RealSet(1,3) S1.union(S2)
(-1, 3)

We may also type:

S1 + S2
(-1, 3)

Example

S2.union(0, 1)
(0, 1) ∪ (1, 3)
s = RealSet().union([1, 3], (2, 6)); s
[1, 6)

1.9. Complex numbers

There are many ways to introduce a complex number in SageMath.

For instance for the complex number z=2+3iz=2+3i we can type CC(2,3){\tt{CC(2, 3)}}, or simple z=2+I3{\tt{z=2+I*3}} (or z=2+i3{\tt{z=2+i*3}}).


Exercise

For the complex number z1=7+(1/2)iz_1=7+(1/2)i and z2=2+2iz_2=-2+\sqrt2 i compute the following:

  1. The real/imaginary part of z1z_1;

  2. z1+z2z_1+z_2, z1z2z_1z_2, z1/z2z_1/z_2;

  3. The argument of z1z_1, and of z1z2z_1z_2;

  4. The complex conjugate of z2z_2 and z1+z2z_1+z_2;

  5. Plot the complex numbers z1z_1, z2z_2, z1+z2z_1+z_2.

Solution:

z1=CC(7, (1/2)) z2=CC(-2, sqrt(2))
show(z1)

7.00000000000000+0.500000000000000i\displaystyle 7.00000000000000 + 0.500000000000000i

z1=7+i*(1/2); z1
1/2*I + 7
a=real(z1); b=imag(z1) #the functions real(z), imag(z) return the real/imaginary part of z show(a); show(b)

7.00000000000000\displaystyle 7.00000000000000

0.500000000000000\displaystyle 0.500000000000000

real(8+(1/2)*I)
8
imag(8+(1/2)*i)
1/2
z1+z2
5.00000000000000 + 1.91421356237310*I
z1*z2
-14.7071067811865 + 8.89949493661167*I
z1/z2
-2.21548220313558 - 1.81658248943528*I
arg(z1) #the function arg(z) returns the argument of the given complex number z
0.0713074647852903
arg(z1*z2)
2.59742040970470
conjugate(z2) #the function conjugate(z) returns the complex conjugate of z
-2.00000000000000 - 1.41421356237310*I
conjugate(z1+z2)
5.00000000000000 - 1.91421356237310*I
a = arrow((0,0),(real(z1),imag(z1))) a b = arrow((0,0),(real(z2),imag(z2))) b c = arrow((0,0),(real(z1+z2),imag(z1+z2))) c plot(a+b+c)
Image in a Jupyter notebook

Exercise

Express the complex nmber 4+8i84i\frac{4+8i}{-8-4i} in the form x+iyx+iy with x,yRx, y\in\mathbb{R}. Next, find its real and imaginary part.

Solution:

z=(4+8*I)/(-8-4*I); simplify(z)
-3/5*I - 4/5

Thus x=4/5x=-4/5 and y=3/5y=-3/5, that is (z)=4/5\Re(z)=-4/5 and (z)=3/5\Im(z)=-3/5. In Sage we may type:

z=(4+8*I)/(-8-4*I) print([real(z), imag(z)])
[-4/5, -3/5]

Exercise

Sketch the following sets of points in C\mathbb{C} via Sage: V1={zC:z1=z+1},V2={zC:1zi2},V3={zC:(z2)=1},V4={zC:(1/z)<1/2}.\begin{darray}{rcl} {\mathsf V}_1&=&\{z\in\mathbb{C} : \left|z-1\right|=\left|z+1\right|\}\,, \\ {\mathsf V}_2&=&\{z \in\mathbb{C} : 1\le\left|z-i\right|\le2\}\,,\\ {\mathsf V}_3&=&\{z\in\mathbb{C} : \Re(z^2)=1\}\,, \\ {\mathsf V}_4&=&\{z\in\mathbb{C} : \Re(1/z)<1/2\}\,. \end{darray}

Solution:

We first introduce x,yx, y as variables and then define the complex number z=x+iyz=x+iy.

Then we use the the command implicit_plot{\tt{implicit\_plot}} or the command region_plot{\tt{region\_plot}}, appropriatelly:

var('x y') z = x + y*I implicit_plot(abs(z - 1) == abs(z + 1), (-3, 3), (-3, 3))
Image in a Jupyter notebook

So, V1\mathsf{V}_1 represents the imaginary line. For the second set of points we get the annulus around ii:

region_plot([abs(z - I) >= 1, abs(z - I) <= 2] , (-3, 3), (-3, 3))
Image in a Jupyter notebook

The third set V3\mathsf{V}_3 is the hyperbola a2b2=1a^2-b^2=1:

implicit_plot((z*z).real() == 1 , (-3, 3), (-3, 3))
Image in a Jupyter notebook

The last set V4\mathsf{V}_4 is the exterior of the unit disc centered at~11.

region_plot((1/z).real() < 1/2 , (-3, 3), (-3, 3))
Image in a Jupyter notebook

1.10. Functions with Sage

Next we will introduce some examples which will help us to understand better how to use Sage when studying basic objects in mathematics, as functions, etc.

This section can be read briefly, since we will return on functions in details in Chapters 2 and 3.

We have already been familiar with the method introducing functions in Sage using symbolic variables. Let us recall such an example.


Exercise

Present in Sage the code for defining the following function: f(x)=4sin2(x)+1ln(x)+exf(x)=4\sin^2(x)+\frac{1}{\ln(x)}+e^x. Next, find its value at the points x=π/2x=\pi/2 and x=0x=0.

Solution:

f(x)=4*sin(x)**2+(1/ln(x))+e^x ; f; print(f)
x |--> 4*sin(x)^2 + 1/log(x) + e^x
ln(0)
-Infinity
f(0)
1
N(f(pi/2))
11.0249111674830
f(0)
1

Or we may type

g(x)=4*(sin(x))^2+1/ln(x)+e**x show(g(x))

4sin(x)2+1log(x)+ex\displaystyle 4 \, \sin\left(x\right)^{2} + \frac{1}{\log\left(x\right)} + e^{x}

print("g(pi/2)=", N(g(pi/2)))
g(pi/2)= 11.0249111674830
g(0)
1

Another method - The def{\tt{def}} command

Another way to introduce functions in SageMath follows the standard way to create a function in Python.

This is based on the def{\tt{def}} keyword (usually, a Python function ends with the return{\tt{return}} command, which returns the result).

The related syntax is as follows:

def ’name’(’arguments’):

’instructions’

return ’result’

Notice however that the block positioning is important, something that we will see better via examples.


Exercise

Type in Sage a short routine to define the function h(x)=xex2/2h(x)=xe^{x^2/2}. Then compute the values h(0)h(0), h(1/2)h(1/2), h(1)h(1) and h(2)h(2).

Solution:

def h(x) : return x*e**(x^2/2)
show(h(x))

xe(12x2)\displaystyle x e^{\left(\frac{1}{2} \, x^{2}\right)}

h(0)
0
h(0.5)
0.566574226533413
h(1)
e^(1/2)

Or we can type

h(0.5) print("h(0, 5) is equal to", h(0.5))
h(0, 5) is equal to 0.566574226533413
show(h(1))

e12\displaystyle e^{\frac{1}{2}}

show(h(2))

2e2\displaystyle 2 \, e^{2}

Tip

For computing all the given values together, we can proceed as follows (we use the commands map{\tt{map}} and list{\tt{list}}).

A=[0, 0.5, 1, 2] list(map(h, A)) #the list command is used to return the result in the form of a list !
[0, 0.566574226533413, e^(1/2), 2*e^2]

Finally recall that typing the given values in decimal way, we can obtain a decimal presentation of h(0.5)h(0.5), h(1)h(1) and h(2)h(2):

A=[0, 0.5, 1.0, 2.0] list(map(h, A))
[0, 0.566574226533413, 1.64872127070013, 14.7781121978613]

1.11. Preliminaries on programming with Sage

Lists

As we saw before, like Python, Sage uses (squared) brackets to indicate a list.

Recall also that Sage starts all lists (and array) indices with element zero.

The entries of a list are are separated with commas and are included inside " " or ' ' .

When we want to create a list of numbers, we should avoid to include them inside " " or ' ' (in the latter case, the numbers will be treated only as strings).

Moreover, list of numbers can be also written using round brackets (parenthesis) (), instead of brackets (as the vectors in linear algebra).

In the latter case we can still extract any entry, but one cannot perform operations as changing the inputs of entries, etc.

Hence in general we will create list using square brackets.


Exercise

  1. Create in Sage a list consisting of the countries India, Germany, Brazil, Japan, Ukraine, Italy, Czech Republic, Thailand, Spain, Greece. Next print the list, find its length and extract the third and sixth member of this list.

  2. Create in Sage a list consisting of the population of the above countries, according to the following link: https://www.worldometers.info/world-population/population-by-country/ Next print the list and extract the third, fifth, sixth and tenth member of this list.

  3. Add the populations of the countries appearing in the previous list.

  4. Use the command bar_chart{\tt{bar\_chart}} to plot the numerical values of the populations given in 2) in a bar graph.

  5. Create a table which will assing the countries from the list in 1) with the populations in list 2). Hint: Use appropriatelly the command table{\tt{table}}.

  6. Add in the first list the country Mexico and in the second list its populations. Next construct the new table (as in case 5) and the new bar graph. Hint: Use appropriatelly the command append{\tt{append}}.

Solution:

  1. Let us call the first list ``countries''

countries=["Usa", "India", "Brazil", "Japan", "Ukraine", "Italy", "Czech Republic", "Thailand", "Spain", "Greece"] print(countries)
['Usa', 'India', 'Brazil', 'Japan', 'Ukraine', 'Italy', 'Czech Republic', 'Thailand', 'Spain', 'Greece']
countries.
len(countries)
10
countries[0]
'Usa'
countries[-1]
'Greece'
countries[-2]
'Spain'
countries[9]==countries[-1]
True

To find the 3rd and 6th member of the list we type countries[2]{\tt{countries[2]}} and countries[5]{\tt{countries[5]}}, respectively (recall that the list indices start from 0).

countries[2]
'Brazil'
countries[5]
'Italy'
  1. For the second list one can work similarly (here we post the populations based on the mentioned link, as it was on April 2024).

pop_per_country=[339996563,1428627663,216422446,123294513,36744634,58870762,10495295,71801279,47519628,10341277] print(pop_per_country)
[339996563, 1428627663, 216422446, 123294513, 36744634, 58870762, 10495295, 71801279, 47519628, 10341277]
pop_per_country[2]
216422446
pop_per_country[4]
36744634
pop_per_country[5]
58870762
pop_per_country[9]
10341277
  1. To add the populations inclued in the list ``pop_per_country'' one can use the sum{\tt{sum}} command and type sum(pop_per_county){\tt{sum(pop\_per\_county)}}.

sum(pop_per_country)
2344114060
  1. To produce the required bar graph (also known as a ``bar chart") we can use the command bar_chart{\tt{bar\_chart}} as follows:

bar_chart(pop_per_country)
Image in a Jupyter notebook
  1. To create this table we can use the command table{\tt{table}} as follows:

table([countries, pop_per_country])
  1. For this, give the following cells:

#countries.remove("Mexico") #print(countries) countries.append("Mexico") print(countries) #countries.append("Mexico")
['Usa', 'India', 'Brazil', 'Japan', 'Ukraine', 'Italy', 'Czech Republic', 'Thailand', 'Spain', 'Greece', 'Mexico']
pop_per_country.append(128455567) print(pop_per_country)
[339996563, 1428627663, 216422446, 123294513, 36744634, 58870762, 10495295, 71801279, 47519628, 10341277, 128455567]
table([countries, pop_per_country])
bar_chart(pop_per_country)
Image in a Jupyter notebook

Exercise for practice

Repeat the previous task, for the same countries, but with respect to the total deaths by Covid (according to the link of wikipedia: https://en.wikipedia.org/wiki/COVID-19_pandemic_by_country_and_territory)

Dictionaries

Dictionaries are also very useful to encode data. Let us describe their implementation via an example.

Exercise

  1. Create (and print) a dictionary assigning to each country appearing in 1) of the previous problem, the corresponding population.

--according to the link: https://www.worldometers.info/world-population/population-by-country/

  1. Locate the keys and the values of the dictionary.

Solution:

  1. The solution goes as follows:

population_dict={"USA":339996563, "India":1428627663, "Brazil":216422446,"Japan":123294513, "Ukraine":36744634, "Italy":58870762, "Czech Republic":10495295, "Thailand":71801279, "Spain":47519628, "Greece":10341277} population_dict
{'USA': 339996563, 'India': 1428627663, 'Brazil': 216422446, 'Japan': 123294513, 'Ukraine': 36744634, 'Italy': 58870762, 'Czech Republic': 10495295, 'Thailand': 71801279, 'Spain': 47519628, 'Greece': 10341277}
population_dict.
  1. Sage has built-in functions to perform these `operations', which can be done via the commands keys{\tt{keys}} and values{\tt{values}}, respectively.

population_dict.keys()
dict_keys(['USA', 'India', 'Brazil', 'Japan', 'Ukraine', 'Italy', 'Czech Republic', 'Thailand', 'Spain', 'Greece'])
population_dict.values()
dict_values([339996563, 1428627663, 216422446, 123294513, 36744634, 58870762, 10495295, 71801279, 47519628, 10341277])

Conditionals

In SageMath an important instruction is the conditional (or test), which enables us to execute some instructions depending on the result of a boolean condition.

Exercise

Present a syntax in Sage printing passed\mathit{passed} when some given number c is bigger than 5, and failed\mathit{failed} in the opposite way.

Solution:

c=5.5 if(c>5): print("passed") else : print("failed")
passed
c=4.8 if(c>5): print("passed") else : print("failed")
failed

Example

c=6.7 if(c>=8.5): print("excelent") else: if (6.5<c<8.5): print("very good") else: if (5<c<6.4): print("bad")
very good
c=5.2 if(c>=8.5): print("excelent") else: if (6.5<c<8.5): print("very good") else: if (5<c<6.4): print("bad")
bad
c=9.2 if(c>=8.5): print("excelent") else: if (6.5<c<8.5): print("very good") else: if (5<c<6.4): print("bad")
excelent

Exercise

Introduce the function F(x)=4esin(4x)16x4\displaystyle F(x)=\frac{4e^{\sin(4x)}}{\sqrt[4]{16x}} for x>0x>0 and F(x)=0F(x)=0 for x=0x=0 in Sage. Next evaluate F(1)F(1).

Solution:

In this case we need to add conditions, so we may type:

def F(x): if x >0 : return 4*e**(sin(4*x))/(16*x)**(1/4) else : return 0
F(1)
2*e^sin(4)
N(F(1))
0.938328371748002

Note that:

F(0)
0

However, we also obtain

F(-1)
0

Hence we may type:

def G(x): if x >0 : return 4*e**(sin(4*x))/(16*x)**(1/4) elif x == 0 : #elif is an alis of else if statement return 0
G(1)
2*e^sin(4)
G(-1) #this will not return something!
(For) Loops

In Sage (enumeration) loops perform the same computation for all integer values of an index kk running in specific set of indices, say k{a,,b}k\in\{a, \ldots, b\}.

In other words, loops are statements that allow us to repeat a set of instructions either for a number of times, or until an expression (condition) becomes false.

For this reason loops become very important in programming and as such they often appear in coding with Sage.

Therefore, it can be useful to describe a few details, useful for applications in forthcoming chapters.


Exercise

Type a code in Sage that will output the multiplication 2k22k^2 for k{1,2,3,4,5,6}k\in\{1, 2, 3, 4, 5, 6\}.

Solution:

for k in [1..6]: #The colon symbol “:” at the end of the first line starts the instruction block print (2*k^2) #a block containing a single instruction
2 8 18 32 50 72

Exercise

Type a code in Sage that will output the multiplication k2/2k^2/2 for k{0,1,,19}k\in\{0, 1, \ldots, 19\}.

Solution:

for k in [0..19]: print (k^2/2)
0 1/2 2 9/2 8 25/2 18 49/2 32 81/2 50 121/2 72 169/2 98 225/2 128 289/2 162 361/2

Or we can equivalently type:

for number in range(20): #The code range(20) returns the set of values 0, 1, 2,...,19. print(number^2/2)
0 1/2 2 9/2 8 25/2 18 49/2 32 81/2 50 121/2 72 169/2 98 225/2 128 289/2 162 361/2

Example

This example provides a way to ask from Sage to return to our screen terms of a given sequence ana_n (when nn is running in for some certain range).

Here. we also use the command subs{\tt{subs}}which is about substitutions (see also Capter 2).

n = var('n') a(n)=3*n/(n-2) # we assume that n>=3 show([a(n).subs(n=k) for k in range(3, 20)])

[9,6,5,92,215,4,277,154,113,185,3911,72,4513,247,175,278,5717]\displaystyle \left[9, 6, 5, \frac{9}{2}, \frac{21}{5}, 4, \frac{27}{7}, \frac{15}{4}, \frac{11}{3}, \frac{18}{5}, \frac{39}{11}, \frac{7}{2}, \frac{45}{13}, \frac{24}{7}, \frac{17}{5}, \frac{27}{8}, \frac{57}{17}\right]

Often, it maybe be useful to illustrate these terms (and so part of the seqence). We can do this in many different ways, one of them given below.

P=Graphics() for n in srange (3, 20): P=P+points((n, a(n))) show(P)
Image in a Jupyter notebook

For the command srange{\tt{srange}} type the following syntax below to read details for its use. Note that we will examine many details on sequences and how we can treat them (even graphically) via Sage, in Chapter 2.

srange?

Exercise

Program Sage with the aim to print the expression

kAlice(1+k2)Bob,k{0,1,,9}\frac{k\cdot\text{Alice}}{\sqrt{(1+k^2)\cdot\text{Bob}}}, \quad\quad\quad k\in\{0, 1, \ldots, 9\}

where Alice\text{Alice} and Bob\text{Bob} represent positive numbers.

Solution:

var("Alice, Bob") assume(Alice>0, Bob>0) for number in range(10): show(number*Alice/sqrt((1+number^2)*Bob))

0\displaystyle 0

2Alice2Bob\displaystyle \frac{\sqrt{2} \mathit{Alice}}{2 \, \sqrt{\mathit{Bob}}}

25Alice5Bob\displaystyle \frac{2 \, \sqrt{5} \mathit{Alice}}{5 \, \sqrt{\mathit{Bob}}}

310Alice10Bob\displaystyle \frac{3 \, \sqrt{10} \mathit{Alice}}{10 \, \sqrt{\mathit{Bob}}}

417Alice17Bob\displaystyle \frac{4 \, \sqrt{17} \mathit{Alice}}{17 \, \sqrt{\mathit{Bob}}}

526Alice26Bob\displaystyle \frac{5 \, \sqrt{26} \mathit{Alice}}{26 \, \sqrt{\mathit{Bob}}}

637Alice37Bob\displaystyle \frac{6 \, \sqrt{37} \mathit{Alice}}{37 \, \sqrt{\mathit{Bob}}}

72Alice10Bob\displaystyle \frac{7 \, \sqrt{2} \mathit{Alice}}{10 \, \sqrt{\mathit{Bob}}}

865Alice65Bob\displaystyle \frac{8 \, \sqrt{65} \mathit{Alice}}{65 \, \sqrt{\mathit{Bob}}}

982Alice82Bob\displaystyle \frac{9 \, \sqrt{82} \mathit{Alice}}{82 \, \sqrt{\mathit{Bob}}}

Exercise

Type a code in Sage that will simultaneously return the prime factorization of the integers 20, 21, 22, 23, and 24. The code should print each one of these numbers, together with it’s factorization.

Solution:

for x in range(20, 25): print (x, "=", factor(x))
20 = 2^2 * 5 21 = 3 * 7 22 = 2 * 11 23 = 23 24 = 2^3 * 3

As we saw above, the elif{\tt{elif}} statement (which is a short for else if{\tt{else \ if}}), can be used when we want to specify/check whether our expression satisfies more than one condition. As another example:

r=12 if 2.divides(r): print("ok") elif r==12: print(12)
ok
r=13 if 2.divides(r): print("ok") elif r==13: print(13)
13

Also, we saw that the else{\tt{else}} operator can be used if we need to execute some code. For example, we can use this to establish another way to introduce piecewise functions. Let us present an example.

Exercise

Define in Sage the function

g(x)={tan(3πx2)if x<1,1+xif x1.g(x)= \left\{ \begin{matrix} \tan(\frac{3\pi x}{2}) & if \ |x|<1, \\ 1+x & if \ |x|\geq 1. \end{matrix} \right.

Solution:

def g(x): if abs(x)<1: return tan(3*pi*x/4) else: return 1+x
g(1/2)
-1
g(1.3)
2.30000000000000
g(5)
6
g(-4)
-3
g(10/10)
2
g(9/10)
-tan(13/40*pi)
g(0)
0