In this tutorial, we'll focus on the two most important Python packages for scientific computing: **numpy** and **matplotlib**.

First, a word about IPython: IPython is a collection of tools for interactive programming in Python. Most importantly for us, IPython includes an interactive shell and a browser-based notebook. The notebook (which you are using now) allows you to run Python code in your web browser; just click on a cell with code and hit shift+enter.

Python includes a package for numerical computation called numpy, which will be an essential tool in this course. You may find the following links helpful:

If you want something really exhaustive, read either of the books by Hans Petter Langtangen (KAUST has access to the e-books).

To get started, we import the numpy module. Import statements like this are the typical way of getting access to functions in Python. Here we just import the numpy module and tell Python that we want to refer to numpy by the short abbreviation "np":

In [ ]:

```
import numpy as np
```

The most important Numpy class is the *ndarray*, which is similar to an array in Matlab.

Numpy includes basic utility functions for creating arrays that are similar to those in Matlab:

In [ ]:

```
x = np.linspace(0,1,5)
print x
```

**Try changing the inputs to the linspace function and see if you can determine exactly what it does.**

In [ ]:

```
y = np.arange(0,1,0.2)
print y
```

**Try changing the inputs to the arange function to determine exactly what it does.** Another way to find out what a function does is to type its name, followed by a question mark:

In [ ]:

```
np.arange?
```

You can resize the help window (to get it out of your way) by dragging the divider.

The syntax for creating a multidimensional array in numpy is also similar to Matlab:

In [ ]:

```
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
print A
print A.shape
```

It's easy to manipulate arrays in various useful ways:

In [ ]:

```
B = np.arange(1,10)
print B
print B.reshape((3,3))
```

Notice that there are two pairs of parentheses used when calling the reshape command, because we are passing as argument the Python tuple *(3,3)*, which is the shape of the resulting array.

You can slice numpy arrays just as in Fortran 90 or Matlab, but the indexing is a little different. Can you figure out how it differs? Try the examples below:

In [ ]:

```
print A[0,0]
print A[1:3,0:2]
```

You can index in some slightly fancier ways, too:

In [ ]:

```
print A[:,1:]
print A[-1,:]
```

How does multiplication of arrays work? Let's see:

In [ ]:

```
print M*M
```

By default, numpy just multiplies componentwise. If you want to do matrix-matrix (or matrix-vector) multiplication, use the *dot* function:

In [ ]:

```
np.dot(M,M)
```

What else can you do with ndarrays? Besides basic arithmetic, there is a nice linear algebra package:

In [ ]:

```
np.linalg?
```

In [ ]:

```
np.linalg.norm(x)
```

We can use this package to solve a linear system of equations: $Mx=b$

In [ ]:

```
M = np.array([[0,2],[8,0]])
b = np.array([1,2])
print M
print b
```

In [ ]:

```
x = np.linalg.solve(M,b)
print x
```

**Can you think of an easy way to check that $x$ is the correct solution? Program your check in the box below.**

In [ ]:

```
```

We can also solve eigenvalue problems:

In [ ]:

```
lamda,V = np.linalg.eig(M)
print lamda
print V
```

Notice how we have put two variables on the left of the equals sign, to assign the outputs of *eig()* to two different variables. What are the two outputs? **How can you check that these outputs are correct? Program it in the box below.**

In [ ]:

```
```

For plotting we will use the matplotlib package.

In [ ]:

```
%pylab inline
import matplotlib.pyplot as plt
```

The line beginning with a "%" is referred to as a magic function. It will make it so that our plots appear in the browser, rather than in a separate window. If you want to know about all of IPython's magic functions, just type "%magic".

Now for a very simple example. Suppose we want to plot the function $\sin(\exp(x))$ on the interval $x\in(0,4)$. We'll want to use the numpy versions of the sine and exponential functions, which operate on arrays (the math module versions operate only on scalars):

In [ ]:

```
x=np.linspace(0,4,1000)
f=np.sin(np.exp(x))
plt.plot(x,f)
```

We won't spend much time on matplotlib. It's straightforward to use and you will generally only get into its advanced functionality if you are customizing the look of a plot for a publication. There is a nice matplotlib tutorial here. The matplotlib documentation in general is excellent.

If you type the name of a Python variable or module, followed by a period, and press the Tab key, you'll get a list of many of the things you can do with that variable or module. Try it out:

In [ ]:

```
x.
```

In [ ]:

```
plt.
```

**Gotcha: copies and views**

See if you can figure out what's happening in the following code.

In [ ]:

```
a = np.arange(12)
print a
b=a
b[5]=0
print a
```

**Try playing around with some of the things you found in the box below. See if you can do the following:

- Create a 10x10 matrix whose $(i,j)$ entry is equal to $i\times j$ without using a loop. Hint: use
*np.fromfunction()*. - Split your 10x10 matrix into five $10 \times 2$ matrices with one line of code. Hint: use
*np.hsplit()***

In [ ]:

```
```

Like MATLAB, Python is **slow**! Like MATLAB, it is particularly slow when using **loops** with many iterations, nested loops, or deeply nested function calls. For the exercises in this course, Python will be sufficiently fast as long as you don't use loops excessively.

For large-scale computational problems, you shouldn't use Python for any code that needs to be fast. Instead, you can write/generate code in C or Fortran and use weave, cython, f2py, or other similar packages to automatically incorporate that code into your Python program.

Besides numpy and matplotlib, there are many other useful Python packages for scientific computing. Here is a short list:

- scipy - optimization, ODEs, sparse linear algebra, etc.
- sympy - symbolic computation
- pandas - data analysis
- mpi4py - parallel computing
- petsc4py, pytrilinos - Python bindings for the "big 2" parallel scientific libraries
- pyCUDA, pyOpenCL - GPGPU computing
- FENiCS, FiPy, PyClaw - solve complicated PDEs with very sophisticated numerical methods
- networkX, pygraphviz - graphs

In [ ]:

```
```