In [6]:
import numpy as np
import matplotlib.pyplot as plt
from numpy import array, cos, sin
In [1]:
%matplotlib inline

For loop and break

In [47]:
for i in range(20):
    print(i)
    if i > 30:
        break
else:
    print("maximum number of iteration reached")
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
not broken

Multiple assignments, comparisons

assigment: a=b=c=0, a,b = b,a, a=0 does not return anything

In [48]:
a = b = 3
In [49]:
print(a,b)
3 3
In [50]:
a = b = []
In [51]:
a is b
Out[51]:
True
In [52]:
a,b = 3,4
In [53]:
print(a,b)
3 4
In [54]:
a,b = b,a
In [55]:
print(a,b)
4 3
In [58]:
a,b,c,d = 1,2,3,"asf"
In [57]:
((a,b),c) = ((2,3),4)
In [60]:
(a = 2) == 3 # illegal!
Out[60]:
False
In [61]:
1/0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-61-05c9758a9c21> in <module>()
----> 1 1/0

ZeroDivisionError: division by zero
In [62]:
$#
  File "<ipython-input-62-921cc23c5c50>", line 1
    $#
    ^
SyntaxError: invalid syntax
In [63]:
1/0
$#
  File "<ipython-input-63-1d81501595aa>", line 2
    $#
    ^
SyntaxError: invalid syntax
In [66]:
array(1)/array(0)
/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/ipykernel/__main__.py:1: RuntimeWarning: divide by zero encountered in true_divide
  if __name__ == '__main__':
Out[66]:
inf
In [65]:
1./0.
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-65-3543596c47ff> in <module>()
----> 1 1./0.

ZeroDivisionError: float division by zero

multiple comparison: 0 < x < 1

In [68]:
x = .5
print(0 < x < 1)
print( (0<x) < 1)
True
False

Lists

deep copying [[2,3]], L*3?

in, not in for belonging to a list

In [71]:
L = [1,2,3,3,4]
5 in L
L.index(3)
Out[71]:
2
In [72]:
7 not in L
Out[72]:
True

list comprehension: with guard, multiple for inside

In [73]:
L
Out[73]:
[1, 2, 3, 3, 4]
In [76]:
[x**2 for x in L]
Out[76]:
[1, 4, 9, 9, 16]
In [82]:
[(i,j) for i in range(3) for j in range(2)]
Out[82]:
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
In [81]:
array([i*j for i in range(3) for j in range(2)]).reshape((3,2))
Out[81]:
array([[0, 0],
       [0, 1],
       [0, 2]])
In [78]:
[x**2 for x in ["a", b] if type(x) == int]
Out[78]:
[4]

tuples

In [83]:
t = (2,3)
In [84]:
t[0]
Out[84]:
2
In [85]:
t[0] = 1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-85-0a69537257d5> in <module>()
----> 1 t[0] = 1

TypeError: 'tuple' object does not support item assignment

strides, negative strides

slicing like a butcher: meaning of L[n:], L[-n:], etc. L[::-n], L[100:200] empty, replace chunks in a list

In [86]:
L
Out[86]:
[1, 2, 3, 3, 4]
In [87]:
L[100:200]
Out[87]:
[]
In [88]:
L[100]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-88-78da2f882365> in <module>()
----> 1 L[100]

IndexError: list index out of range
In [89]:
a = array(L)
a[100:200]
Out[89]:
array([], dtype=int64)

zip

In [90]:
L
Out[90]:
[1, 2, 3, 3, 4]
In [91]:
L1 = [10,20,30]
In [99]:
z = list(zip(L,L1))
print(z)
[(1, 10), (2, 20), (3, 30)]
In [102]:
L = [1, 2, 3, 3, 4]
In [97]:
L.append(L1)
print(L)
[1, 2, 3, 3, 4, [10, 20, 30]]
In [100]:
[x for x,y in z]
Out[100]:
[1, 2, 3]
In [104]:
el = list(enumerate(L))
print(el)
[(0, 1), (1, 2), (2, 3), (3, 3), (4, 4)]
In [105]:
[i for i,x in el if x == 3]
Out[105]:
[2, 3]

Dictionaries

keys, items, values

In [106]:
d = {'a': 3, 'b': 4}
In [107]:
d['a']
Out[107]:
3
In [108]:
d['b']
Out[108]:
4
In [110]:
x = 'a'
d[x] = 100
In [109]:
person1 = {'surname': 'Verdier', 'name': "Olivier"}

Laziness of bool operators

For else

Iterative algorithms

In [70]:
x = 1
max_iter = 100
for i in range(max_iter):
    x = x**2
    if x > 100:
        break
else:
    print("Algorithm did not converge in %s steps" % max_iter)
Algorithm did not converge in 100 steps

Plotting

plot labels and legends

In [71]:
xs = linspace(0,1,200)
plot(xs, cos(xs), label='cos')
plot(xs, sin(xs), label='sin')
legend()
savefig('sincos.pdf')

Function

Docstrings! (triple quotes)

In [72]:
def my_function():
    """
    my_function is a super function
    more information here
    that's enough
    """
    print("Hi! How are you?")
In [73]:
my_function?

Return multiple values

Functions always return None

Function arguments: named, default, star operations (varargs)

In [113]:
def power_function(a,b):
    return a**b
In [114]:
power_function(2,3)
Out[114]:
8
In [115]:
param_list = [2,3]
In [116]:
power_function(*param_list)
Out[116]:
8
In [119]:
power_function(array([2,3]), array([3,4]))
Out[119]:
array([ 8, 81])
In [120]:
power_function(*[3,4])
Out[120]:
81
In [123]:
param_dict = { 'b': 3, 'c': 2}
In [124]:
power_function(**param_dict)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-124-4d23a083342e> in <module>()
----> 1 power_function(**param_dict)

TypeError: power_function() got an unexpected keyword argument 'c'
In [125]:
power_function??
In [126]:
power_function(b=3, a=2)
Out[126]:
8
In [127]:
b, a = 2, 3
In [ ]:
power_function(a=b, b=a)
In [128]:
def nice_function(a, b=3):
    return a**b
In [129]:
nice_function(2)
Out[129]:
8
In [130]:
nice_function(2, b=5)
Out[130]:
32
In [131]:
nice_function(2,5)
Out[131]:
32
In [141]:
def super_function(a,b,*args, **kwargs):
    print(args)
    print(kwargs)
In [139]:
super_function(2,3,"hello",c=4,d=10)
('hello',)
{'c': 4, 'd': 10}
In [134]:
super_function(2,a=4,4,b=10)
  File "<ipython-input-134-e84df2085f0a>", line 1
    super_function(2,a=4,4,b=10)
                        ^
SyntaxError: non-keyword arg after keyword arg
In [144]:
def append_function(a, b=[]):
    b.append(a)
    return b
In [145]:
append_function(3,[4,5,6])
Out[145]:
[4, 5, 6, 3]
In [146]:
append_function(3)
Out[146]:
[3]
In [147]:
append_function(4)
Out[147]:
[3, 4]

closure example

In [91]:
def sin_freq(freq, x):
    return sin(2*pi*freq*x)
In [92]:
def get_sin_with_freq(freq):
    def sin_freq(x):
        return sin(2*pi*freq*x)
    return sin_freq
In [93]:
sin10 = get_sin_with_freq(10)
In [94]:
xs = linspace(0,1,200)
plot(xs, sin10(xs))
Out[94]:
[<matplotlib.lines.Line2D at 0x106a74048>]

Generators

Generators: enumerate, range, reversed

Exceptions

In [148]:
def divide(a,b):
    if b == 0:
        raise Exception("Oops, b is zero")
    return a/b
In [149]:
divide(3,4)
Out[149]:
0.75
In [150]:
divide(3,0)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-150-24bf8d716600> in <module>()
----> 1 divide(3,0)

<ipython-input-148-11371656a320> in divide(a, b)
      1 def divide(a,b):
      2     if b == 0:
----> 3         raise Exception("Oops, b is zero")
      4     return a/b

Exception: Oops, b is zero

Namespaces, imports

Namespaces, import, %run, etc.

In [95]:
import example
In [96]:
example.J
Out[96]:
1j
In [97]:
example.imported_function(2.)
Out[97]:
200.0
In [98]:
%run example.py
In [99]:
imported_function(2.)
Out[99]:
200.0
In [156]:
from example import bisect as example_bisect
In [182]:
class Example:
    pass
example = Example()
In [159]:
example.bisect = example_bisect
In [101]:
from example import *
In [102]:
import example1
import example2
example1.imported_function
example2.imported_function
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-102-d85a77517064> in <module>()
----> 1 import example1
      2 import example2
      3 example1.imported_function
      4 example2.imported_function

ImportError: No module named 'example1'
In [103]:
a = 0
a = 1
In [104]:
example = 10
In [105]:
import example as ex
In [106]:
ex.imported_function
Out[106]:
<function example.imported_function>

Arrays

array length is fixed: v[:2] = array([1]), or v.append

flags?

Boolean arrays: mask, example with rand(10,10) and capping at .5

In [160]:
M = np.random.randn(5,5)
In [161]:
print(M)
[[-0.45771511 -0.44600716 -0.0963087   0.36646952 -0.35648425]
 [-0.532434    0.19209479  0.83525092 -0.24639756 -0.61241575]
 [-0.82984776 -1.21664042  0.89142928  0.47979501 -0.30452319]
 [ 0.48553935 -1.62094851  0.81100656  0.05521396 -0.74060706]
 [ 1.54060755 -0.07426069 -0.40557241 -1.25481997 -1.77014925]]
In [163]:
mask = M > 0
print(mask)
[[False False False  True False]
 [False  True  True False False]
 [False False  True  True False]
 [ True False  True  True False]
 [ True False False False False]]
In [165]:
M[mask] = 100
In [166]:
M
Out[166]:
array([[ -4.57715111e-01,  -4.46007163e-01,  -9.63087029e-02,
          1.00000000e+02,  -3.56484245e-01],
       [ -5.32434001e-01,   1.00000000e+02,   1.00000000e+02,
         -2.46397558e-01,  -6.12415752e-01],
       [ -8.29847762e-01,  -1.21664042e+00,   1.00000000e+02,
          1.00000000e+02,  -3.04523194e-01],
       [  1.00000000e+02,  -1.62094851e+00,   1.00000000e+02,
          1.00000000e+02,  -7.40607061e-01],
       [  1.00000000e+02,  -7.42606888e-02,  -4.05572411e-01,
         -1.25481997e+00,  -1.77014925e+00]])
In [167]:
M[M<0] = -100
print(M)
[[-100. -100. -100.  100. -100.]
 [-100.  100.  100. -100. -100.]
 [-100. -100.  100.  100. -100.]
 [ 100. -100.  100.  100. -100.]
 [ 100. -100. -100. -100. -100.]]

array comparison

In [168]:
M
Out[168]:
array([[-100., -100., -100.,  100., -100.],
       [-100.,  100.,  100., -100., -100.],
       [-100., -100.,  100.,  100., -100.],
       [ 100., -100.,  100.,  100., -100.],
       [ 100., -100., -100., -100., -100.]])
In [169]:
M == M
Out[169]:
array([[ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True]], dtype=bool)
In [171]:
if (M == M).all():
    print("M is equal to itself!")
M is equal to itself!

vectorize example with sign?

In [173]:
def sign(x):
    if x < 0:
        return -1
    else:
        return 1
In [174]:
data = np.arange(5)-2
In [175]:
data
Out[175]:
array([-2, -1,  0,  1,  2])
In [177]:
vsign = np.vectorize(sign)
In [178]:
vsign(data)
Out[178]:
array([-1, -1,  1,  1,  1])
In [176]:
sign(data)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-176-783031542db4> in <module>()
----> 1 sign(data)

<ipython-input-173-888533a22840> in sign(x)
      1 def sign(x):
----> 2     if x < 0:
      3         return -1
      4     else:
      5         return 1

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

reshape with -1

solve!!

In [110]:
M = array([[1.,2.], [3.,4.]])
V = array([2.,3.])
In [111]:
print(M, V)
[[ 1.  2.]
 [ 3.  4.]] [ 2.  3.]
In [116]:
x = solve(M, V) # solves dot(M,x) == V
In [117]:
allclose(dot(M,x), V)
Out[117]:
True

No direct array comparision, use all, A < .75 & A > .25

Views?

Broadcasting!

In [123]:
print(M, V)
[[ 1.  2.]
 [ 3.  4.]] [ 2.  3.]
In [124]:
M * V
Out[124]:
array([[  2.,   6.],
       [  6.,  12.]])

Exceptions

Object oriented programming

Objects: example with Complex, __init__, __add__.

In [217]:
class Complex:
    def __init__(self, x, y):
        print("init!")
        self.r = x
        self.i = y
    
    def abs(self):
        return np.sqrt(self.r**2 + self.i**2)
    
    def __add__(self, zz):
        return Complex(self.r + zz.r, self.i + zz.i)
        
    def __str__(self):
        return "%s + %s J" % (self.r, self.i)
    
    def __repr__(self):
        return "Complex({},{})".format(self.r, self.i)
In [218]:
z = Complex(1.,2.)
init!
In [219]:
z2 = Complex(10., 20.)
z.__add__(z2)
init!
init!
Out[219]:
Complex(11.0,22.0)
In [216]:
z + z2
init!
Out[216]:
11.0 + 22.0 J
In [202]:
z * z2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-202-a1db40b12982> in <module>()
----> 1 z * z2

TypeError: unsupported operand type(s) for *: 'Complex' and 'Complex'
In [193]:
z.abs()
Out[193]:
2.2360679774997898
In [192]:
z.r,z.i
Out[192]:
(1.0, 2.0)
In [186]:
z.__dict__
Out[186]:
{'i': 2.0, 'r': 1.0}

Performance

In [223]:
def big_loop():
    s = 0
    for i in range(10000):
        s = s + np.sqrt(i)
In [221]:
%prun big_loop()
 
In [224]:
%timeit big_loop()
100 loops, best of 3: 12.7 ms per loop
In [44]:
%prun?
In [227]:
import datetime
In [250]:
tic = datetime.datetime.now()
big_loop()
toc = datetime.datetime.now()
print(toc - tic)
0:00:00.013855

Numba

In [251]:
def get_grid(nh,nv):
    x = np.linspace(-2,.8,nh)
    y = np.linspace(-1.4,1.4,nv)
    return np.meshgrid(x,y,indexing='ij')
In [253]:
def mandel_py(w,h,maxit=20):
    # prepare initial points
    x, y = get_grid(w,h)
    c = x+y*1j
    # where to store output
    output = np.zeros(c.shape, dtype=int) + maxit
    for i in range(h): # loop 1
        for j in range(w): # loop 2
            z = 0.
            c0 = c[i,j]
            for k in range(maxit): # loop 3!!
                z = z**2 + c0
                if z*z.conjugate() > 4.0:
                    output[i, j] = k
                    break
    return output.T
In [264]:
nb.jit(nopython=True)(mandel_py)(200,200)
---------------------------------------------------------------------------
TypingError                               Traceback (most recent call last)
<ipython-input-264-f046d1b4de87> in <module>()
----> 1 nb.jit(nopython=True)(mandel_py)(200,200)

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
    169         assert not kws
    170         sig = tuple([self.typeof_pyval(a) for a in args])
--> 171         return self.compile(sig)
    172 
    173     def inspect_llvm(self, signature=None):

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/dispatcher.py in compile(self, sig)
    346                                           self.py_func,
    347                                           args=args, return_type=return_type,
--> 348                                           flags=flags, locals=self.locals)
    349 
    350             # Check typing error if object mode is used

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in compile_extra(typingctx, targetctx, func, args, return_type, flags, locals, library)
    635     pipeline = Pipeline(typingctx, targetctx, library,
    636                         args, return_type, flags, locals)
--> 637     return pipeline.compile_extra(func)
    638 
    639 

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in compile_extra(self, func)
    356                 raise e
    357 
--> 358         return self.compile_bytecode(bc, func_attr=self.func_attr)
    359 
    360     def compile_bytecode(self, bc, lifted=(), lifted_from=None,

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in compile_bytecode(self, bc, lifted, lifted_from, func_attr)
    365         self.lifted_from = lifted_from
    366         self.func_attr = func_attr
--> 367         return self._compile_bytecode()
    368 
    369     def compile_internal(self, bc, func_attr=DEFAULT_FUNCTION_ATTRIBUTES):

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in _compile_bytecode(self)
    622 
    623         pm.finalize()
--> 624         return pm.run(self.status)
    625 
    626 

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in run(self, status)
    248                     # No more fallback pipelines?
    249                     if is_final_pipeline:
--> 250                         raise patched_exception
    251                     # Go to next fallback pipeline
    252                     else:

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in run(self, status)
    240             for stage, stage_name in self.pipeline_stages[pipeline_name]:
    241                 try:
--> 242                     res = stage()
    243                 except _EarlyPipelineCompletion as e:
    244                     return e.result

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in stage_nopython_frontend(self)
    453                 self.args,
    454                 self.return_type,
--> 455                 self.locals)
    456 
    457         with self.fallback_context('Function "%s" has invalid return type'

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/compiler.py in type_inference_stage(typingctx, interp, args, return_type, locals)
    749         infer.seed_type(k, v)
    750 
--> 751     infer.build_constraint()
    752     infer.propagate()
    753     typemap, restype, calltypes = infer.unify()

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/typeinfer.py in build_constraint(self)
    492         for blk in utils.itervalues(self.blocks):
    493             for inst in blk.body:
--> 494                 self.constrain_statement(inst)
    495 
    496     def propagate(self):

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/typeinfer.py in constrain_statement(self, inst)
    649     def constrain_statement(self, inst):
    650         if isinstance(inst, ir.Assign):
--> 651             self.typeof_assign(inst)
    652         elif isinstance(inst, ir.SetItem):
    653             self.typeof_setitem(inst)

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/typeinfer.py in typeof_assign(self, inst)
    689                                               src=value.name, loc=inst.loc))
    690         elif isinstance(value, (ir.Global, ir.FreeVar)):
--> 691             self.typeof_global(inst, inst.target, value)
    692         elif isinstance(value, ir.Arg):
    693             self.typeof_arg(inst, inst.target, value)

/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/numba/typeinfer.py in typeof_global(self, inst, target, gvar)
    754         else:
    755             raise TypingError("Untyped global name '%s'" % gvar.name,
--> 756                               loc=inst.loc)
    757 
    758     def typeof_expr(self, inst, target, expr):

TypingError: Failed at nopython (nopython frontend)
Untyped global name 'get_grid'
File "<ipython-input-253-ff821fe7c6f4>", line 3
In [265]:
def mandel_np(w,h,maxit=20):
    # prepare initial points
    x, y = get_grid(w,h)
    c = x+y*1j
    # where to store output
    output = np.zeros_like(c, dtype=int) + maxit
    z = np.zeros_like(c)
    for k in range(maxit):
        z = z**2 + c
        mask = z*z.conjugate() <= 4.0
        output[mask] = k
    return output.T
In [266]:
plt.imshow(mandel_py(200,200))
Out[266]:
<matplotlib.image.AxesImage at 0x109c2bd30>
In [262]:
%timeit mandel_np(200,200)
100 loops, best of 3: 9.83 ms per loop
/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/ipykernel/__main__.py:10: RuntimeWarning: overflow encountered in multiply
/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/ipykernel/__main__.py:10: RuntimeWarning: invalid value encountered in multiply
/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/ipykernel/__main__.py:9: RuntimeWarning: overflow encountered in square
/Users/olivier/anaconda/envs/python3/lib/python3.4/site-packages/ipykernel/__main__.py:9: RuntimeWarning: invalid value encountered in square
In [147]:
zeros_like?
In [150]:
%timeit mandel_py(200,200)
1 loops, best of 3: 703 ms per loop
In [256]:
import numba as nb
In [257]:
def mandel_raw(grid, output,maxit):
    for i in range(grid.shape[0]): # loop 1
        for j in range(grid.shape[1]): # loop 2
            z = 0.+0j
            c0 = grid[i,j]
            for k in range(maxit): # loop 3!!
                z = z**2 + c0
                if z.real*z.real + z.imag*z.imag > 4.0:
                    output[i, j] = k
                    break
mandel_nb = nb.jit('void(c16[:,:],i8[:,:],i8)', nopython=True)(mandel_raw)

def mandel_opt(w,h,maxit=20):
    x, y = get_grid(w,h)
    grid = x+y*1j
    output = np.zeros_like(grid, dtype=int) + maxit
    mandel_nb(grid,output,maxit)
    return output.T
    
In [260]:
%timeit mandel_opt(200,200)
100 loops, best of 3: 2.13 ms per loop
In [259]:
plt.imshow(mandel_opt(200,200))
Out[259]:
<matplotlib.image.AxesImage at 0x1099f1208>
In [155]:
imshow(mandel_py(200,200))
Out[155]:
<matplotlib.image.AxesImage at 0x109df5160>
In [156]:
%prun mandel_py(200,200)
 

Testing?