In ACN 903, we will often benchmark theoretical results against numerical values. Note that there are two popular, non-compatible, Python branches (2.x and 3.x). We will use here Python 3. No strong developing skill is required besides defining a function. If you don't know anything about Python, you can use one of the numerous online tutorials. These should bring you up to speed within an hour or less.
Just in case, a small survival kit is provided below.
There are multiple IDEs to write code in Python: VI, Emacs, Eclipse... In this course, we will use Jupyter Notebooks (formerly known as IPython Notebooks). One of the main advantages of Jupyter over other IDEs is that you can write code in Python and text in Markdown in the same file.
Usage. In a terminal, go to your working directory and write jupyter notebook. If you are using a computer at Télécom, you may need to specify the path, like /cal/softs/anaconda/anaconda3/jupyter notebook. This command should launch a Jupyter window in your browser, which should display the files of your current directory.
You can use Jupyter to edit an existing Notebook (a file with the extension ipynb) or create a new one by clicking the button New in the upper right corner.
To learn how to use Jupyter, use the Help! Just in case, a very few tips:
In [X]: on the left-hand side of the window. You can use a large range of symbols, such as greek letters. For instance, you can write the letter $\mu$ by typing \mu and then pressing Tab on the keyboard.You are free to use any interface you are comfortable with. If you just begin with Python, Spyder is a nice IDE to start. Spyder has three main ways of evaluating Python expressions.
In most languages, the keyword end is used to tell that a loop/condition/definition ends. In Python, there is no end. Instead, the ranges are defined according to indentation.
For example, compare
In [ ]:
x = 0
for i in range(5):
x = x + i
print("x is "+str(x))
with
In [ ]:
x = 0
for i in range(5):
x = x + i
print("x is "+str(x))
Function definitions start with the keyword def. You can assign default values to parameters, which allows for highly flexible function calls. For example, look at the following:
In [ ]:
def my_division(x = 10, y = 3):
return x/y
In [ ]:
print(my_division(12,4))
In [ ]:
print(my_division())
In [ ]:
print(my_division(12))
In [ ]:
print(my_division(y = 5))
In [ ]:
print(my_division(y = 2, x = 10))
Be careful, arguments without a default value must (always!) precede those with a default value in order to avoir ambiguity.
One of the strength of Python is the vast amount of available modules.
The following modules are highly recommended: numpy (for a minimum of maths primitives) and matplotlib (for conveniently displaying the results).
A convenient way to load them in Jupyter Notebooks is to use %pylab inline, a magic command that loads both modules under the names np and plt and displays the figures inside the Notebook (otherwise, they may pop-up in a separate window). Once this magic is evaluated, its effect lasts for the whole session.
A minimal example:
In [ ]:
%pylab inline
In [ ]:
x = np.arange(0, 5, .1)
plt.plot(x, np.sqrt(x), 'r', label = '$\sqrt{x}$')
plt.plot(x, np.log(x+1), 'g', label = '$\ln (x+1)$')
plt.xlabel('$x$')
plt.ylabel('$f(x)$')
plt.legend(loc = 4)
plt.show()
Remark. The command %pylab inline also loads numpy and matplotlib into the main namespace, so that you don't need to write the prefixes np and plt if you want (just try to remember that you are actually calling functions from modules).
In [ ]:
x = arange(0, 5, .1)
plot(x, sqrt(x), 'r', label = '$\sqrt{x}$')
plot(x, log(x+1), 'g', label = '$\ln (x+1)$')
xlabel('$x$')
ylabel('$f(x)$')
legend(loc = 4)
show()
Whatever you want to implement, there is probably a module that does all the heavy lifting for you. Must you re-invent the wheel? This is actually a very tricky question. We won't forbid you to use extra modules, but there are things you should ask yourself before making a decision:
Additionally, most of the modules you actually need are given in the Notebooks of the practicals, along with explanations.
Python is interpreted, not compiled. As a consequence, for loops can rapidly become your main bottleneck. Always try to rely on numpy arrays if it can avoid loops.
In [ ]:
import time
n = 10000000
t = time.time()
x = zeros(n)
for i in range(n):
x[i] = sqrt(i)
print("FOR loops: "+str(time.time()-t)+" s")
t = time.time()
y = sqrt(arange(n))
print("Numpy: "+str(time.time()-t)+" s")
Remark: if you cannot avoid loop, there are other ways to accelerate your code that will be explained during the course. Teaser:
In [ ]:
from numba import jit
@jit()
def my_loops(n):
x = zeros(n)
for i in range(n):
x[i] = sqrt(i)
return x
my_loops(1) # trigger compilation
t = time.time()
my_loops(n)
print("FOR loops with jit: "+str(time.time()-t)+" s")
Reference passing can be tricky.
In [ ]:
A = [1, 2, 3, 4]
B = A
A[0] = 0
print(A==B)
In [ ]:
A = [1, 2, 3, 4]
B = A.copy()
A[0] = 0
print(A==B)