# Second Sage Lecture¶

## Lists¶

range(from=0, to, step=1)


• [ ) interval notation
• inclusive from the left and exclusive from the right
• Also 0-based indexing!
In :
range(5, 10)

Out:
[5, 6, 7, 8, 9]
In :
[1, 2, 3] == 1

Out:
True

## List comprehension¶

[ f(x) for x in ___ ]
In :
[n for n in range(10)]

Out:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In :
[n^2 for n in range(1,11)]

Out:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

### Selection¶

[ f(x) for x in ___ if g(x) ]


• f(x) is the result
• g(x) is a boolean function (condition) ### either/or values
[ f1(x) if g(x) else f2(x) for x in ___ ]

Every element will appear in the list, but some with f1(x) values, others with f2(x) values (depending in g(x))

In :
print range(1,21)
[ 3*x+1 if x%2==1 else x//2 for x in range(1,21) ]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Out:
[4, 1, 10, 2, 16, 3, 22, 4, 28, 5, 34, 6, 40, 7, 46, 8, 52, 9, 58, 10]

### multiple for¶

Means cross product or Descartes product.

[(i,j) for i in ___ for j in ___ ]



Goes through (i, j) pairs in the cross product.

Not the same as:

[[(i,j) for i in ___ ] for j in ___ ]



Because that is a list-of-lists!

In :
print([ (i, j) for i in range(5) for j in range(5) ] )
print
print([[ (i, j) for i in range(5)] for j in range(5) ] )

[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]

[[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)], [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)], [(0, 2), (1, 2), (2, 2), (3, 2), (4, 2)], [(0, 3), (1, 3), (2, 3), (3, 3), (4, 3)], [(0, 4), (1, 4), (2, 4), (3, 4), (4, 4)]]


## Functions¶

inline:

f(x) = x^2



declaration:

def f(x):
return x^2


• Mind the colon and the identation!
• The identation decides where to end the function.
• The return is not necessarily the last line, but nothing is executed after that!
In :
x=var('x')
f(x)=x^2
def g(x):
return x^2
def h(x):
return x^2
print('ooh!')

print(f(3), g(3))
print(diff(f,x,1))
print(diff(g(x),x,1))

(9, 9)
x |--> 2*x
2*x


There is a difference between inline and declared functions.

• inline functions can contain only one expression
• inline functions are mathematically funcitions
• declared functions are functions in the programming sense
In :
f?


## Condition¶

inline:

f1(x) if g(x) else f2(x)



programming:

if g(x):
f1(x)
else:
f2(x)



Mind the colon and the identation! The else part is optional.

In :
def parity(a):
if a%2 == 0:
return "even"
else:
return "odd"
return 0
print(parity(6))

even


If you miss the return then the result is a unique None value. You cannot miss the return in inline functions.

In :
def parity2(a):
if a%2 == 0:
return "even"
else:
print "odd"
'ooh'
print(parity2(5))

odd
None

In :
def gcd(a,b):
if (b == 0):
return a
return gcd(b, a%b)
print(gcd(50,15))

5

In :
def factorial(n):
if n==0:
return 1
return n*factorial(n-1)
factorial(10)

Out:
3628800
In :
def factorial2(x):
return x*factorial2(x-1)
factorial2(10)

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-13-35a00d34a177> in <module>()
1 def factorial2(x):
2     return x*factorial2(x-Integer(1))
----> 3 factorial2(Integer(10))

<ipython-input-13-35a00d34a177> in factorial2(x)
1 def factorial2(x):
----> 2     return x*factorial2(x-Integer(1))
3 factorial2(Integer(10))

... last 1 frames repeated, from the frame below ...

<ipython-input-13-35a00d34a177> in factorial2(x)
1 def factorial2(x):
----> 2     return x*factorial2(x-Integer(1))
3 factorial2(Integer(10))

RuntimeError: maximum recursion depth exceeded while calling a Python object

## Tower of Hanoi¶ The puzzle was invented by the French mathematician Édouard Lucas in 1883. There is a story about an Indian temple in Kashi Vishwanath which contains a large room with three time-worn posts in it, surrounded by 64 golden disks. Brahmin priests, acting out the command of an ancient prophecy, have been moving these disks in accordance with the immutable rules of Brahma since that time. The puzzle is therefore also known as the Tower of Brahma puzzle. According to the legend, when the last move of the puzzle is completed, the world will end.

https://en.wikipedia.org/wiki/Tower_of_Hanoi

In :
A = [5, 4, 3, 2, 1]
B = []
C = []
def move(n, source, target, auxiliary):
if n > 0:
# move n - 1 disks from source to auxiliary, so they are out of the way
move(n - 1, source, auxiliary, target)
# move the nth disk from source to target
target.append(source.pop())
# Display our progress
print(A, B, C)
# move the n - 1 disks that we left on auxiliary onto target
move(n - 1, auxiliary, target, source)
# initiate call from source A to target C with auxiliary B
move(5, A, C, B)

([5, 4, 3, 2], [], )
([5, 4, 3], , )
([5, 4, 3], [2, 1], [])
([5, 4], [2, 1], )
([5, 4, 1], , )
([5, 4, 1], [], [3, 2])
([5, 4], [], [3, 2, 1])
(, , [3, 2, 1])
(, [4, 1], [3, 2])
([5, 2], [4, 1], )
([5, 2, 1], , )
([5, 2, 1], [4, 3], [])
([5, 2], [4, 3], )
(, [4, 3, 2], )
(, [4, 3, 2, 1], [])
([], [4, 3, 2, 1], )
(, [4, 3, 2], )
(, [4, 3], [5, 2])
([], [4, 3], [5, 2, 1])
(, , [5, 2, 1])
(, [4, 1], [5, 2])
([3, 2], [4, 1], )
([3, 2, 1], , )
([3, 2, 1], [], [5, 4])
([3, 2], [], [5, 4, 1])
(, , [5, 4, 1])
(, [2, 1], [5, 4])
([], [2, 1], [5, 4, 3])
(, , [5, 4, 3])
(, [], [5, 4, 3, 2])
([], [], [5, 4, 3, 2, 1])