In this course, we shall interact in three ways with Python:
spyder: is an Interactive Development Environment (IDE) for Python
that provides edition and debugging features in a simple and light-weighted software. We use it for almost all the work related to coding exercises.
terminal: is the essential interaction with Python. We will use it for some simple examples in class.
jupyter notebook: is an interactive computational environment, in which you can combine code execution, rich text, mathematics, plots and rich media. We use it mainly to write these labs. These notebooks are used in Google Colab. For example, this notebook.
Running the code (assuming that the paths are correctly set),
spyder: There should be some icon linking to Spyder execution in your Desktop or in your Applications menu. In any case, you always can run spyder from command line just by running (writing) spyder.
terminal: Just open a console and run python. Then, you enter to python command line. Another use of the console is to run a specific program. In this case you run in console python myscript.py.
jupyter notebook: open a terminal, go tot the folder that contains the code and run jupyter notebook. The file extension is ipynb
.
We will use Anaconda distribution with Python 3 for these labs.
Python is a very versatile language that can perform very different tasks. In this course we shall focus in some numerical algorithms you can implement through Python.
Python is modular. A module is a script containing definitions of variables and functions, among others. Very often, modules are gathered into packages attending to some specific application. For instance, we shall make an extensive use of
A standard python script starts importing modules from packages. For instance
import numpy as np
Here we have imported all the numpy
contents, to which we shall refer to with the prefix np
:
print(np.pi)
There are variations of the import
command. For instance, if we want to load just the definition of $\pi$, we use
from numpy import pi as PI
print(PI)
The numpy package (module) is used in almost all numerical computation using Python. It is a package that provides high-performance vector, matrix and higher-dimensional data structures for Python. It is implemented in C and Fortran so when calculations are vectorized (formulated with vectors and matrices), performance is very good.
There are many ways of creating a numpy array. For instance,
a = np.array([1, 2, 3, 4])
b = np.array([(1.5, 2, 3), (4, 5, 6)])
c = np.zeros((3, 4))
d = np.ones((2, 3))
e = np.arange(1, 10, 2)
f = np.arange(1., 10, 2)
g = np.linspace(1, 9, 5)
print('a\n',a,'\n')
print('b\n',b,'\n')
print('c\n',c,'\n')
print('d\n',d,'\n')
print('e\n',e,'\n')
print('f\n',f,'\n')
print('g\n',g)
Indexes begin with zero. -1
index is for the last element of the array.
In arange
, the values are generated within the half-open interval [1, 10), that is 1 is included but 10 is not. The last index is the step. It is similar to range
but this last generates a list while arange
generates a numpy array.
print('a[0] = ', a[0], '\nb[0,0] = ',b[0,0], '\nb[0][0] = ',b[0][0])
print('e[-1] = ',e[-1])
len
: number of elements in a one-dimension numpy array (vector), number of rows in a two-dimension numpy array (matrix).
ndim
: dimension number of an array (one for a vector, two for a matrix, at least three for a multidimensional matrix)
shape
: number of elements in every dimension, (number rows, number columns) for a two-dimension matrix.
print('len a = ', len(a),'; dim b = ', b.ndim, '; shape b = ', b.shape)
Arithmetic operators on arrays apply element-wise. This is different than for Python lists!
a = np.array([1, 2, 3, 4])
b = np.array([(1.5, 2, 3, 5)])
a1 = [1, 2, 3, 4]
b1 = [1.5, 2, 3, 5]
print('a+b numpy array ')
print(a+b)
print('\na1+b1 list')
print(a1+b1)
On the other hand
print('a = \n', a)
print('\n3+a = \n', 3+a)
print('\n3*a = \n', 3*a)
print('\n\n3/a = \n', 3/a)
print('\na/2 = \n', a/2)
Unlike in many matrix languages, the product operator *
operates element-wise in numpy arrays. The matrix product can be performed using the dot
function or method:
A = np.array( [[1, 1], [0, 1]] )
B = np.array( [[2, 3], [1, 4]] )
print('A')
print(A)
print('\nB')
print(B)
print('\nA*B')
print(A*B)
print('\nAB')
print(np.dot(A,B))
a = np.arange(10)
print('a\n', a)
print('\na[1]\n', a[1])
print('\na[1:8]\n', a[1:8])
print('\na[1:8:2]\n', a[1:8:2])
print('\na[1:]\n', a[1:])
print('\na[:8]\n', a[:8])
print('\na[::2]\n', a[::2])
print('\na[-1]\n', a[-1])
print('\na[:-1]\n', a[:-1])
print('\na[0]\n', a[0])
print('\na[1:]\n', a[1:])
print('\na[::-1]\n', a[::-1])
print('\na[::-2]\n', a[::-2])
print('\na[7:1:-2]\n', a[7:1:-2])
%run slicing1
b = np.array([0, 1, 5, -1])
print('\na[b]\n',a[b])
Also, for two-dimensional numpy arrays
n = 6
s = n*n
a = np.arange(s)
a = np.reshape(a,(n,n))
print('a = \n', a)
print('\033[91m \na[1,3] = \n', a[1,3])
print('\033[92m \na[:,5] = \n', a[:,5])
print('\033[94m \na[4,:] = \n', a[4,:])
print('\033[95m \na[1:3, 0:2] = \n', a[1:3, 0:2])
%run slicing2
print('\033[91m \na[0,1:5] = \n', a[0,1:5])
print('\033[92m \na[4:,4:] = \n', a[4:,4:])
print('\033[94m \na[2::2,::2] = \n', a[2::2,::2])
%run slicing3
To achieve high performance, assignments in Python usually do not copy the underlaying objects. This is important, for example, when objects are passed between functions, to avoid an excessive amount of memory copying when it is not necessary (technical term: pass by reference).
No Copy at All: Simple assignments make no copy of array objects or their data.
a = np.arange(12)
b = a
print('a[0] = ', a[0], '\nb[0] = ',b[0])
b[0] = 10
print('a[0] = ', a[0], '\nb[0] = ',b[0])
Deep copy: The copy
method makes a complete copy of the array and its data.
b = a.copy()
print('a[0] = ', a[0], '\nb[0] = ',b[0])
b[0] = 0
print('a[0] = ', a[0], '\nb[0] = ',b[0])
print(np.sin(PI/2))
print(np.exp(-1))
print(np.arctan(np.inf))
print(np.sqrt(4))
If they are applied to a numpy array, the result is a numpy array
a = np.linspace(2,4,5)
print('a =\n', a)
print('\nnp.sqrt(a) =\n', np.sqrt(a))
f1 = lambda x: x ** 3
f2 = lambda x,y: x + y
print('f1(2) = ', f1(2))
print('f2(1,1) = ', f2(1,1))
def f3(x):
if x > 2:
return 0
else:
return 1
print('f3(-1) = ', f3(-1))
print('f3(3) = ', f3(3))
For more information, see Numpy Quickstart tutorial
For basic plotting, we use the package matplotlib
import matplotlib.pyplot as plt
x = np.linspace(-1,2) # Define the grid
f = lambda x : x**3 - 2*x**2 + 1 # Define the function
OX = 0*x
plt.figure()
plt.plot(x,f(x)) # Plot the function
plt.plot(x,OX,'k-') # Plot X axis
plt.xlabel('x')
plt.ylabel('y')
plt.title('function')
plt.show()
We create a grid for $x$ and another for $y$. Twenty equispaced points for each one.
xgrid = np.linspace(-1,1,20)
ygrid = np.linspace(-1,1,20)
We construct a bidimensional grid
X, Y = np.meshgrid(xgrid,ygrid)
We define a two-variable function
g = lambda x,y: x**2 + y**2
We represent the function with colors
plt.figure()
plt.contourf(X,Y,g(X,Y), cmap='jet')
plt.colorbar()
plt.show()
We represent the function as a surface
from mpl_toolkits.mplot3d import Axes3D
fig1 = plt.figure(figsize=(10,5))
ax1 = plt.axes(projection ='3d')
ax1.plot_surface(X, Y, g(X,Y), cmap='jet')
plt.show()
Or as a wireframe
fig2 = plt.figure(figsize=(10,5))
ax2 = plt.axes(projection ='3d')
ax2.plot_wireframe(X, Y, g(X,Y))
plt.show()
Create and print the following numpy vectors and matrices:
$$a = (1, \;3, \;7)\qquad b = \left( \begin{array}{rrr} 2&4&3 \\ 0&1&6 \\ \end{array} \right)\qquad c = (1, \;1, \;1) \qquad d = (0, \;0, \;0, \;0) $$$$e= \left(\begin{array}{rr} 0&0 \\ 0&0 \\ 0&0 \end{array} \right) \qquad f= \left( \begin{array}{rrrr} 1&1&1&1 \\ 1&1&1&1 \\ 1&1&1&1 \\ \end{array}\right)$$
%run Exercise1
Using the arange
command and then linspace
command, create the vectors:
Use
np.set_printoptions(precision=2,suppress=True)
%run Exercise2
arange
, create the vector%run Exercise3
Starting with the vector $a=(1,2,3)$ create a vector $b=(0,1,2,3,0)$
%run Exercise4
Given the matrix
$$ A= \left( \begin{array}{rrrr} 2&1&3&4 \\ 9&8&5&7 \\ 6&-1&-2&-8 \\ -5&-7&-9&-6 \\ \end{array}\right) $$From $A$, get the following matrices:
$$a=\left( \begin{array}{r} 2 \\ 9 \\ 6 \\ -5 \end{array}\right) \qquad b=\left( \begin{array}{rrrr} 6&-1&-2&-8 \end{array}\right) \qquad c=\left( \begin{array}{rr} 2&1\\ 9&8 \\ \end{array}\right) $$$$ d=\left( \begin{array}{rr} -2&-8\\ -9&-6 \\ \end{array}\right) \qquad e=\left( \begin{array}{rr} 8&5\\ -1&-2 \\ \end{array}\right) \qquad f=\left( \begin{array}{rrr} 1&3&4 \\ 8&5&7 \\ -1&-2&-8 \\ -7&-9&-6 \\ \end{array}\right) \qquad g=\left( \begin{array}{rr} 8&5 \\ -1&-2 \\ -7&-9 \\ \end{array}\right)$$%run Exercise5
%run Exercise6
%run Exercise7