Sage lecture

877 days ago by kkovacs

Mathematical softwares – sage (Software for Arithmetic Geometry Experimentation)

Misson: a free alternative of Magma, Maple, Mathematica and Matlab.

 

Long term goals

  • Useful: Sage’s intended audience is mathematics students (from high school to graduate school), teachers, and research mathematicians. The aim is to provide software that can be used to explore and experiment with mathematical constructions in algebra, geometry, number theory, calculus, numerical computation, etc. Sage helps make it easier to interactively experiment with mathematical objects.
  • Efficient: Be fast. Sage uses highly-optimized mature software like GMP, PARI, GAP, and NTL, and so is very fast at certain operations.
  • Free and open source: The source code must be freely available and readable, so users can understand what the system is really doing and more easily extend it. Just as mathematicians gain a deeper understanding of a theorem by carefully reading or at least skimming the proof, people who do computations should be able to understand how the calculations work by reading documented source code. If you use Sage to do computations in a paper you publish, you can rest assured that your readers will always have free access to Sage and all its source code, and you are even allowed to archive and re-distribute the version of Sage you used.
  • Easy to compile: Sage should be easy to compile from source for Linux, OS X and Windows users. This provides more flexibility for users to modify the system.
  • Cooperation: Provide robust interfaces to most other computer algebra systems, including PARI, GAP, Singular, Maxima, KASH, Magma, Maple, and Mathematica. Sage is meant to unify and extend existing math software.
  • Well documented: Tutorial, programming guide, reference manual, and how-to, with numerous examples and discussion of background mathematics.
  • Extensible: Be able to define new data types or derive from built-in types, and use code written in a range of languages.
  • User friendly: It should be easy to understand what functionality is provided for a given object and to view documentation and source code. Also attain a high level of user support.

 Source

  • Homepage: sagemath.org. Can be downloaded here, documentation is found here.
  • Sage cloud: sagecloud.com. Can be accessed from any browser, free.
restart 
       

 

 

 

Sage, numerical calculator

Arithmetic operations, elementry functions

1 + 1 
       
2
2

Sage can caluclate with rational numbers. It switches to floating point numbers with the n() method.

13/5 
       
13/5
13/5
n(13/5) 
       
2.60000000000000
2.60000000000000
sin(1), sqrt(2) 
       
(sin(1), sqrt(2))
(sin(1), sqrt(2))
sqrt(2).n(), sqrt(2).n(200) # n() can be used as a method 
       
(1.41421356237310,
 1.4142135623730950488016887242096980785696718753769480731767)
(1.41421356237310,
 1.4142135623730950488016887242096980785696718753769480731767)
sin(1.0) 
       
0.841470984807897
0.841470984807897
sin(pi/3) 
       
1/2*sqrt(3)
1/2*sqrt(3)
show(sin(pi/3)) 
       

                                
                            

                                
_.n(1000) # _ the previous result 
       
0.8660254037844386467637231707529361834714026269051903140279034897259665\
084544000185405730933786242878378130707077033515149849725474994762394058\
277560471868242640466159511527910339874100505423374616325076561716334516\
614433253361273344609189856135235658301839307940095249932686899296947338\
25173753288025
0.866025403784438646763723170752936183471402626905190314027903489725966508454400018540573093378624287837813070707703351514984972547499476239405827756047186824264046615951152791033987410050542337461632507656171633451661443325336127334460918985613523565830183930794009524993268689929694733825173753288025
111^111 
       
107362012888474225801214565046695501959850723994224804804775911175625076\
195783347022491226170093634621466103743092986967777786330067310159463303\
558666910091026017785587295539622142057315437069730229375357546494103400\
699864397711
107362012888474225801214565046695501959850723994224804804775911175625076195783347022491226170093634621466103743092986967777786330067310159463303558666910091026017785587295539622142057315437069730229375357546494103400699864397711
13//5, 13%5 
       
(2, 3)
(2, 3)
64^(1/6) # root 
       
2
2
factor(24) # text completeion with TAB, try it with writing only fact and pressing TAB 
       
2^3 * 3
2^3 * 3
exp(2), e^2 
       
(e^2, e^2)
(e^2, e^2)
e^2.n() 
       
7.38905609893065
7.38905609893065
log(e), log(100), log(100.), log(100,10), log(1024,2) 
       
(1, log(100), 4.60517018598809, 2, 10)
(1, log(100), 4.60517018598809, 2, 10)
arcsin(1/2) 
       
1/6*pi
1/6*pi
a = 10^10 # creating a variable a%3 
       
1
1

A question symbol ? after a command shows detailed help.

x.abs? 
       

File: /usr/local/SageMath/src/sage/symbolic/expression.pyx

Type: <type ‘builtin_function_or_method’>

Definition: x.abs(hold=False)

Docstring:

Return the absolute value of this expression.

EXAMPLES:

sage: var('x, y')
(x, y)
sage: (x+y).abs()
abs(x + y)

Using the hold parameter it is possible to prevent automatic evaluation:

sage: SR(-5).abs(hold=True)
abs(-5)

To then evaluate again, we use unhold():

sage: a = SR(-5).abs(hold=True); a.unhold()
5

File: /usr/local/SageMath/src/sage/symbolic/expression.pyx

Type: <type ‘builtin_function_or_method’>

Definition: x.abs(hold=False)

Docstring:

Return the absolute value of this expression.

EXAMPLES:

sage: var('x, y')
(x, y)
sage: (x+y).abs()
abs(x + y)

Using the hold parameter it is possible to prevent automatic evaluation:

sage: SR(-5).abs(hold=True)
abs(-5)

To then evaluate again, we use unhold():

sage: a = SR(-5).abs(hold=True); a.unhold()
5

 

Lists, indices

Indexing starts from 0.

  • series (1,2,3)
  • list: [1,2,3]
(3 + 3*I)^4, (sqrt(3) + i)^6 # a series with 2 elements, normal parenthesis can omitted 
       
(-324, (sqrt(3) + I)^6)
(-324, (sqrt(3) + I)^6)
expand(_[1]) # this expands the second expression 
       
-64
-64
l = [1, 3, 2, 4] l[1:2] 
       
[3]
[3]
l = range(7); l # with ; we can write multiple commands in a line 
       
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]

list[c:d]   from element c to d, d is not included

list[c:d:e]   from element c to d with e steps

l[1], l[-1], l[:2], l[4:], l[3:1], l[0:-1], l[0:-1:2] 
       
(1, 6, [0, 1], [4, 5, 6], [], [0, 1, 2, 3, 4, 5], [0, 2, 4])
(1, 6, [0, 1], [4, 5, 6], [], [0, 1, 2, 3, 4, 5], [0, 2, 4])

List comprehension

[expression for variable in something]

Similar to how we define sets in mathematics. Example: $\{ f(x) \mid x\in H\}$.

(In sage lists and sets are different, in a set the order of its elements aren't given.)

L = [factor(n) for n in range(10000, 10025)] 
       
print L 
       
[2^4 * 5^4, 73 * 137, 2 * 3 * 1667, 7 * 1429, 2^2 * 41 * 61, 3 * 5 * 23
* 29, 2 * 5003, 10007, 2^3 * 3^2 * 139, 10009, 2 * 5 * 7 * 11 * 13, 3 *
47 * 71, 2^2 * 2503, 17 * 19 * 31, 2 * 3 * 1669, 5 * 2003, 2^5 * 313,
3^3 * 7 * 53, 2 * 5009, 43 * 233, 2^2 * 3 * 5 * 167, 11 * 911, 2 * 5011,
3 * 13 * 257, 2^3 * 7 * 179]
[2^4 * 5^4, 73 * 137, 2 * 3 * 1667, 7 * 1429, 2^2 * 41 * 61, 3 * 5 * 23 * 29, 2 * 5003, 10007, 2^3 * 3^2 * 139, 10009, 2 * 5 * 7 * 11 * 13, 3 * 47 * 71, 2^2 * 2503, 17 * 19 * 31, 2 * 3 * 1669, 5 * 2003, 2^5 * 313, 3^3 * 7 * 53, 2 * 5009, 43 * 233, 2^2 * 3 * 5 * 167, 11 * 911, 2 * 5011, 3 * 13 * 257, 2^3 * 7 * 179]

List comprehension with a condition

[expression for variable in something if condition]


P = [n for n in range(10000,10100) if is_prime(n)] 
       
       
[10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093,
10099]
[10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099]

 

Logic values

3 == 4 
       
False
False
3 <> 4, 3 != 4 
       
(True, True)
(True, True)
3 < 4 
       
True
True

 

Functions defined by a mathematical expression

f(x) = x^3 
       
f(5) 
       
125
125
var('c') f(c) 
       
c^3
c^3
a = f(c^2-3) 
       
expand(a) 
       
c^6 - 9*c^4 + 27*c^2 - 27
c^6 - 9*c^4 + 27*c^2 - 27

 

 

Sage, as a programming language

The basis of sage is the pythong programming language.

 

Variables

Variable types are dynamic (as opposed to static: we do not need to define the type of the variables, their types can freely change).

a = 3 a = a+1 a = a^2 a 
       
16
16
a = "this is a text" 
       
       
'this is a text'
'this is a text'

 

 

Symbolic variables, sage, as a symbolic calculator

As opposed to usual programming languages (C, Python, Fortran,...), but similar to other CAS (computer algebra system) a variable can be symbolic in sage. By default the variable x is symbolic, using the var function any variable can be made symbolic.

diff(x^2*exp(x), x) 
       
x^2*e^x + 2*x*e^x
x^2*e^x + 2*x*e^x
diff(x^2*exp(x), x, 10) 
       
x^2*e^x + 20*x*e^x + 90*e^x
x^2*e^x + 20*x*e^x + 90*e^x
integral(9*x^2*exp(3*x^3), x) 
       
e^(3*x^3)
e^(3*x^3)
diff(y^2*exp(y), y) 
       
Traceback (click to the left of this block for traceback)
...
NameError: name 'y' is not defined
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_44.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("ZGlmZih5XjIqZXhwKHkpLCB5KQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
  File "", line 1, in <module>
    
  File "/tmp/tmp6yiHg3/___code___.py", line 3, in <module>
    exec compile(u'diff(y**_sage_const_2 *exp(y), y)
  File "", line 1, in <module>
    
NameError: name 'y' is not defined
var('y') 
       
y
y
diff(y^2*exp(y), y) 
       
y^2*e^y + 2*y*e^y
y^2*e^y + 2*y*e^y
solve([x+y==3, x-y-4], x, y) 
       
[[x == (7/2), y == (-1/2)]]
[[x == (7/2), y == (-1/2)]]
var('x y z p q') eq1 = p+q==5 eq2 = p*x+q*y==-5 eq3 = p*x^2+q*y^2==10 solve([eq1,eq2,eq3], q, x, y) 
       
[[q == -p + 5, x == -(p - sqrt(-p^2 + 5*p))/p, y == -(p -
sqrt(p)*sqrt(-p + 5) - 5)/(p - 5)], [q == -p + 5, x == -(p + sqrt(-p^2 +
5*p))/p, y == -(p + sqrt(p)*sqrt(-p + 5) - 5)/(p - 5)]]
[[q == -p + 5, x == -(p - sqrt(-p^2 + 5*p))/p, y == -(p - sqrt(p)*sqrt(-p + 5) - 5)/(p - 5)], [q == -p + 5, x == -(p + sqrt(-p^2 + 5*p))/p, y == -(p + sqrt(p)*sqrt(-p + 5) - 5)/(p - 5)]]
solve( [2*x + 3*y + 2*z == -1, x + y + z == 0], x, y ) 
       
[[x == -z + 1, y == -1]]
[[x == -z + 1, y == -1]]
solve( [2*x + 3*y + 2*z == -1, x + y + z == 0], x, y, z ) 
       
[[x == -r1 + 1, y == -1, z == r1]]
[[x == -r1 + 1, y == -1, z == r1]]
solve(cos(x)==sin(x), x) 
       
[sin(x) == cos(x)]
[sin(x) == cos(x)]
find_root(cos(x)==sin(x), 0, 1) 
       
0.7853981633974483
0.7853981633974483
limit(arctan(-x) + exp(-x)*x^1000, x=oo) 
       
-1/2*pi
-1/2*pi

 

Conditional command: if

a = 12 if a%2 == 0: print "even" else: print "odd" 
       
even
even

 

Functions and methods

f(x,y) = x^3*exp(x^2)*y^3 
       
f.diff(y) 
       
(x, y) |--> 3*x^3*y^2*e^(x^2)
(x, y) |--> 3*x^3*y^2*e^(x^2)
f.integral(x) 
       
(x, y) |--> 1/2*(x^2 - 1)*y^3*e^(x^2)
(x, y) |--> 1/2*(x^2 - 1)*y^3*e^(x^2)

 

Writing a function (programming function)

def gcd(a,b): if b==0: return abs(a) else: return gcd(b,a%b) 
       
gcd(1111,1111111111) 
       
11
11

 

Sets

Colors = ["Spades", "Diamond", "Hearts", "Clubs"] Values = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"] Cards = Set(Colors).cartesian_product(Set(Values)) #.map(tuple) 
       
Cards.random_element() 
       
('Diamond', 'Jack')
('Diamond', 'Jack')
Cards.cardinality() 
       
52
52
Hands = Subsets(Cards, 5) 
       
Hands.random_element() 
       
{('Hearts', 5), ('Diamond', 'Jack'), ('Diamond', 'King'), ('Diamond',
10), ('Spades', 8)}
{('Hearts', 5), ('Diamond', 'Jack'), ('Diamond', 'King'), ('Diamond', 10), ('Spades', 8)}
Hands.cardinality() 
       
2598960
2598960
binomial(52,5) 
       
2598960
2598960
def is_it_a_pair(hand): return len(set(value for (color, value) in hand)) == 4 
       
hand = Hands.random_element(); hand 
       
{('Hearts', 10), ('Diamond', 8), ('Diamond', 2), ('Diamond', 'Queen'),
('Spades', 6)}
{('Hearts', 10), ('Diamond', 8), ('Diamond', 2), ('Diamond', 'Queen'), ('Spades', 6)}
is_it_a_pair(hand) 
       
False
False

 

 

 

Abstract mathematical structures

Polynomial rings over a given field

n = -1.1 
       
n.is_unit() 
       
True
True
type(n) 
       
<type 'sage.rings.real_mpfr.RealLiteral'>
<type 'sage.rings.real_mpfr.RealLiteral'>
polinomQ.<q> = PolynomialRing(QQ) polinomR.<x> = PolynomialRing(RR) polinomC.<z> = PolynomialRing(CC) 
       
factor(q^4 + 2*q^2 + 2) 
       
q^4 + 2*q^2 + 2
q^4 + 2*q^2 + 2
factor(x^4 + 2*x^2 + 2) 
       
(x^2 - 0.910179721124455*x + 1.41421356237310) * (x^2 +
0.910179721124455*x + 1.41421356237310)
(x^2 - 0.910179721124455*x + 1.41421356237310) * (x^2 + 0.910179721124455*x + 1.41421356237310)
factor(z^4 + 2*z^2 + 2) 
       
(z - 0.455089860562227 - 1.09868411346781*I) * (z - 0.455089860562227 +
1.09868411346781*I) * (z + 0.455089860562227 - 1.09868411346781*I) * (z
+ 0.455089860562227 + 1.09868411346781*I)
(z - 0.455089860562227 - 1.09868411346781*I) * (z - 0.455089860562227 + 1.09868411346781*I) * (z + 0.455089860562227 - 1.09868411346781*I) * (z + 0.455089860562227 + 1.09868411346781*I)
factor(x^2 - 2) 
       
(x - 1.41421356237310) * (x + 1.41421356237310)
(x - 1.41421356237310) * (x + 1.41421356237310)
(q^4 - 3*q^3 + 2*q^2 - q + 1) // (q^2 - 1) 
       
q^2 - 3*q + 3
q^2 - 3*q + 3
(q^4 - 3*q^3 + 2*q^2 - q + 1) % (q^2 - 1) 
       
-4*q + 4
-4*q + 4
(q^2 - 1)*(q^2 - 3*q + 3) - 4*q + 4 
       
q^4 - 3*q^3 + 2*q^2 - q + 1
q^4 - 3*q^3 + 2*q^2 - q + 1
p = q^4 - 3*q^3 + 2*q^2 - q + 1 
       
p.is_irreducible() 
       
False
False
p.xgcd(q^2-1) 
       
(q - 1, -1/4, 1/4*q^2 - 3/4*q + 3/4)
(q - 1, -1/4, 1/4*q^2 - 3/4*q + 3/4)
-1/4*p + (1/4*q^2 - 3/4*q + 3/4) * (q^2 - 1) 
       
q - 1
q - 1

 

Vector spaces, matrices

A = Matrix([[1,2,3],[3,2,1],[1,1,1]]); A 
       
[1 2 3]
[3 2 1]
[1 1 1]
[1 2 3]
[3 2 1]
[1 1 1]
A.LU() 
       
(
[0 1 0]  [  1   0   0]  [  3   2   1]
[1 0 0]  [1/3   1   0]  [  0 4/3 8/3]
[0 0 1], [1/3 1/4   1], [  0   0   0]
)
(
[0 1 0]  [  1   0   0]  [  3   2   1]
[1 0 0]  [1/3   1   0]  [  0 4/3 8/3]
[0 0 1], [1/3 1/4   1], [  0   0   0]
)
P, L, U = A.LU() 
       
P*L*U 
       
[1 2 3]
[3 2 1]
[1 1 1]
[1 2 3]
[3 2 1]
[1 1 1]
A.rank() 
       
2
2
A.nullity() 
       
1
1
A.left_kernel() # left zerospace: xA=0 
       
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[ 1  1 -4]
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[ 1  1 -4]
A.right_kernel() # right zerospace: Ax=0 
       
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[ 1 -2  1]
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[ 1 -2  1]
A.row_space() 
       
Free module of degree 3 and rank 2 over Integer Ring
Echelon basis matrix:
[ 1  0 -1]
[ 0  1  2]
Free module of degree 3 and rank 2 over Integer Ring
Echelon basis matrix:
[ 1  0 -1]
[ 0  1  2]
A.echelon_form() 
       
[ 1  0 -1]
[ 0  1  2]
[ 0  0  0]
[ 1  0 -1]
[ 0  1  2]
[ 0  0  0]
A.column_space() 
       
Free module of degree 3 and rank 2 over Integer Ring
Echelon basis matrix:
[1 3 1]
[0 4 1]
Free module of degree 3 and rank 2 over Integer Ring
Echelon basis matrix:
[1 3 1]
[0 4 1]
B = A.transpose() B.echelon_form() 
       
[1 3 1]
[0 4 1]
[0 0 0]
[1 3 1]
[0 4 1]
[0 0 0]
B.rref() 
       
[  1   0 1/4]
[  0   1 1/4]
[  0   0   0]
[  1   0 1/4]
[  0   1 1/4]
[  0   0   0]
v = vector([1,1,-4]) v 
       
(1, 1, -4)
(1, 1, -4)
A, v*A, A*v 
       
(
[1 2 3]                        
[3 2 1]                        
[1 1 1], (0, 0, 0), (-9, 1, -2)
)
(
[1 2 3]                        
[3 2 1]                        
[1 1 1], (0, 0, 0), (-9, 1, -2)
)
w = vector([3,5,2]) 
       
A.solve_right(w) 
       
(1, 1, 0)
(1, 1, 0)
A \ w 
       
(1, 1, 0)
(1, 1, 0)
A.solve_left(w) 
       
Traceback (click to the left of this block for traceback)
...
ValueError: matrix equation has no solutions
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_121.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("QS5zb2x2ZV9sZWZ0KHcp"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
  File "", line 1, in <module>
    
  File "/tmp/tmpruhl0q/___code___.py", line 2, in <module>
    exec compile(u'A.solve_left(w)
  File "", line 1, in <module>
    
  File "sage/matrix/matrix2.pyx", line 175, in sage.matrix.matrix2.Matrix.solve_left (/usr/local/SageMath/src/build/cythonized/sage/matrix/matrix2.c:5238)
  File "sage/matrix/matrix2.pyx", line 404, in sage.matrix.matrix2.Matrix.solve_right (/usr/local/SageMath/src/build/cythonized/sage/matrix/matrix2.c:7000)
  File "sage/matrix/matrix2.pyx", line 522, in sage.matrix.matrix2.Matrix._solve_right_general (/usr/local/SageMath/src/build/cythonized/sage/matrix/matrix2.c:8147)
ValueError: matrix equation has no solutions
B = A.change_ring(GF(2)) 
       
B.echelon_form() 
       
[1 0 1]
[0 1 0]
[0 0 0]
[1 0 1]
[0 1 0]
[0 0 0]
B.base_ring() 
       
Finite Field of size 2
Finite Field of size 2

 

 

 

Graphics

2d graphics

plot(cos, (-5,5)) 
       
plot([cos,sin], (-5,5), aspect_ratio=1) 
       
parametric_plot((cos(x),sin(x)^3),(x,0,2*pi),color='red') 
       
var('x') p = plot(2*x^4-2*x^3+3*x^2-3*x+4, (x,-1,1), color = 'cyan', thickness=3) p += plot(2*x^4, (x,-1,1), color = 'magenta', thickness=3) p.show() 
       
%hide @interact(layout=[['x0'], ['eps']]) def _(x0=slider(0, 5, default=1.9, label="x<sub>0</sub>"), eps=slider(0.01, 0.6, default=0.5, label="ε")): f=sin(x) + x/2 pont = point2d((x0,f(x=x0)), rgbcolor=(0.5,0,0), size=60) p = plot(f, (0,5)) maxx = 5 d = diff(f)(x=x0) saveps = polygon2d([[x0,f(x=x0)], [maxx,f(x=x0)+(d+eps)*(maxx-x0)], [maxx,f(x=x0)+(d-eps)*(maxx-x0)]], rgbcolor=(0,1,0), alpha=0.2)+polygon2d([[x0,f(x=x0)], [0,f(x=x0)-(d+eps)*(x0)], [0,f(x=x0)-(d-eps)*(x0)]], rgbcolor=(0,1,0), alpha=0.2) delta = min(5-x0, x0) var('z') while True: try: delta = find_root(f(x=x0)+(z-x0)*(d-eps)==f(x=z), x0+0.001, x0+delta-0.001) - x0 except: break while True: try: delta = find_root(f(x=x0)+(z-x0)*(d+eps)==f(x=z), x0+0.001, x0+delta-0.001) - x0 except: break while True: try: delta = x0 - find_root(f(x=x0)+(z-x0)*(d-eps)==f(x=z), x0-delta+0.001, x0-0.001) except: break while True: try: delta = x0 - find_root(f(x=x0)+(z-x0)*(d+eps)==f(x=z), x0-delta+0.001, x0-0.001) except: break savdel = polygon2d([[x0-delta,-0.2],[x0-delta,3],[x0+delta,3],[x0+delta,-0.2]], rgbcolor=(1,0,0), alpha=0.2) # t = text('x0+delta',(x0+delta,-0.1),rgbcolor=(0,0,0)) # t2 = text('x0-delta',(x0-delta,-0.2),rgbcolor=(0,0,0)) l = line([[x0,-0.2],[x0,3]], rgbcolor=(1,0,0), alpha=0.2, thickness=2) l2 = line([[0,f(x=x0)-x0*d], [maxx,f(x=x0)+(maxx-x0)*d]], rgbcolor=(0,1,0), alpha=0.2, thickness=2) show(pont+p+saveps+savdel+l+l2, aspect_ratio=1, xmin=-0.2, ymin=-0.2, ymax=3) 
       
x0 
ε 

Click to the left again to hide and once more to show the dynamic interactive window

var('x,y') plot3d(x^2-y^2, (x,-4,4), (y,-4,4)) 
       
u, v = var('u,v') fx = cos(v) * (3 + cos(u)) fy = sin(v) * (3 + cos(u)) fz = sin(u) parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, aspect_ratio=1, color="red")