Getting Started with Python#

Installing Python#

There are multiple ways to get a working python installation on your computer, depending on whether you’re using Windows, Mac, or Linux.

The first option is to install standard python, which you can download here.

The second option is to install Anaconda, which comes with a bunch of extra packages and tools that can be useful for scientific computing.

Personally, I don’t use Anaconda as I prefer to have more control over what I install, but both options are popular.

Resources#

Installing an IDE#

An IDE is basically a text editor combined with some additional tools that allow you to run and debug your code. My IDE of choice is VSCode. Two other popular IDEs are PyCharm and Spyder, both of these are more specifically designed for python programming.

Tip

Whatever IDE you choose, make sure you learn how to use it’s python debugger. A debugger will allow you to pause the program at a specific point and then step through the code line by line and inspect the values of variables. Debugging this way is much more efficient than using print statements.

Tip

You should also learn to use some of the keyboard shortcuts for your IDE. Different IDEs have different shortcuts that will make your editing experience easier by allowing you to quickly do things like rename a variable everywhere it appears in your code, comment and uncomment large blocks of code, and create multiple cursors to edit multiple lines at once.

VSCode has some walkthroughs of these features that should show up the first time you open it.

Resources#

Installing Packages#

Most python packages are installed through pip the default python package manager. You can install packages by running pip install <package name> in the terminal. If you installed python using anaconda/conda, you can also install packages using conda install <package name>, but not everything you can install with pip is available through conda. You can also pip install things if you use conda, but make sure you have run conda install pip in the relevant environment first.

tl;dr#

To install the primary packages you’ll need for this course, run the following in the terminal:

pip install --upgrade pip
pip install numpy scipy jaxlib jax[cpu] matplotlib niceplots

NumPy#

NumPy is THE standard package for doing math in python, especially things involving vectors, matrices, and multidimensional arrays.

import numpy as np

# Create a random linear system (Ax=b) and solve it
N = 5
A = np.random.rand(N, N)
b = np.random.rand(N)
x = np.linalg.solve(A, b)

print(f"{A=}\n")
print(f"{b=}\n")
print(f"{x=}\n")

# Check that the solution is correct
diff = A @ x - b  # @ is the matrix multiplication operator, A @ x is equivalent to np.dot(A, x)
print(f"Linear system solution error norm = {np.linalg.norm(diff)}")
A=array([[0.50122711, 0.39307474, 0.11744351, 0.79573245, 0.4883522 ],
       [0.38451448, 0.55358049, 0.3721361 , 0.66031229, 0.92817422],
       [0.14355362, 0.00541981, 0.82590157, 0.85126053, 0.00932226],
       [0.28220734, 0.37200741, 0.74670183, 0.44570255, 0.84131498],
       [0.50448022, 0.39729077, 0.51426973, 0.30586818, 0.87372884]])

b=array([0.37239017, 0.77499391, 0.64194949, 0.63495222, 0.88070258])

x=array([  7.68177298,  99.03330702,  23.67937126, -23.55278952,
       -54.150844  ])

Linear system solution error norm = 1.3613819831636986e-14

JAX#

JAX is a library that does many things useful for machine learning. Most importantly for this course, it has a module that allows you to compute derivatives through NumPy-like code. In theory, this means you can take code written using numpy, replace import numpy as np with import jax.numpy as np, and then differentiate through the code using jax.grad.

Support for JAX on windows is apparently “experimental”, but it should still be installable through pip, see the instructions here. If you run into problems, please let us know on Piazza.

import jax.numpy as jnp
from jax import grad


# Define a function that does some stuff with arrays
def func(x):
    return jnp.sum(jnp.exp(x) * (jnp.sin(x) + jnp.cos(2 * x))) / jnp.sum(x**2)


# Create another function that computes the gradient of the first function using JAX's AD
funcGradient = grad(func)

# Evaluate the function and it's gradient
x = jnp.linspace(0, 2 * jnp.pi, 10)
y = func(x)
dydx = funcGradient(x)

print(f"{x=}\n")
print(f"{y=}\n")
print(f"{dydx=}\n")
x=Array([0.        , 0.69813174, 1.3962635 , 2.0943952 , 2.792527  ,
       3.4906588 , 4.1887903 , 4.8869224 , 5.585054  , 6.2831855 ],      dtype=float32)

y=Array(0.742495, dtype=float32)

dydx=Array([ 0.01439827, -0.01306541, -0.02845956,  0.07103436,  0.1409933 ,
       -0.46274623, -1.7529042 , -1.070204  ,  4.2873783 ,  7.642982  ],      dtype=float32)

SciPy#

SciPy contains a bunch of more complex scientific computing algorithms for things like root finding, optimization, solving ODE’s, and sparse linear algebra.

from scipy.optimize import root_scalar


# Use scipy to find the root of e^x - 1
def anotherFunc(x):
    f = np.exp(x) - 1
    print(f"{x=}, f(x) = {f}")
    return f


root = root_scalar(anotherFunc, method="bisect", bracket=[-2, 4], xtol=1e-6)
x=-2.0, f(x) = -0.8646647167633873
x=4.0, f(x) = 53.598150033144236
x=1.0, f(x) = 1.718281828459045
x=-0.5, f(x) = -0.3934693402873666
x=0.25, f(x) = 0.2840254166877414
x=-0.125, f(x) = -0.11750309741540454
x=0.0625, f(x) = 0.06449445891785932
x=-0.03125, f(x) = -0.03076676552365587
x=0.015625, f(x) = 0.015747708586685727
x=-0.0078125, f(x) = -0.007782061739756485
x=0.00390625, f(x) = 0.003913889338347465
x=-0.001953125, f(x) = -0.0019512188925244756
x=0.0009765625, f(x) = 0.0009770394924164538
x=-0.00048828125, f(x) = -0.0004881620601105974
x=0.000244140625, f(x) = 0.0002441704297477809
x=-0.0001220703125, f(x) = -0.00012206286222260498
x=6.103515625e-05, f(x) = 6.103701893311886e-05
x=-3.0517578125e-05, f(x) = -3.051711246848665e-05
x=1.52587890625e-05, f(x) = 1.525890547848796e-05
x=-7.62939453125e-06, f(x) = -7.6293654275305656e-06
x=3.814697265625e-06, f(x) = 3.814704541582614e-06
x=-1.9073486328125e-06, f(x) = -1.9073468138230965e-06
x=9.5367431640625e-07, f(x) = 9.536747711536009e-07
x=-4.76837158203125e-07, f(x) = -4.768370445162873e-07
x=2.384185791015625e-07, f(x) = 2.3841860752327193e-07

Matplotlib#

The standard plotting library for python. It has a lot of functionality and excellent documentation.

Tip

If you’re a Matlab user, you may be used to plotting simply by calling the plot function, and switching between different figures using the figure function. It is possible to use a similar approach in Matplotlib, but I’d recommend that you instead use the approach used in the matplotlib examples where you first create figure and axis objects and then call the plot methods of the axis. This makes it much clearer in your code which data is being plotted on which figure.

import matplotlib.pyplot as plt

# Create a figure with two subplots on top of each other
fig, axes = plt.subplots(nrows=2, sharex=True)

# Set the axis labels and tick marks
axes[0].set_ylabel("$y_1$")
axes[1].set_ylabel("$y_2$")
axes[1].set_xlabel("t (s)")
axes[0].set_title("Experimental data")

# Create some data to plot
x = np.linspace(0, 8 * np.pi, 100)

y1 = np.exp(-x / 8) * np.sin(x)
y1_experiment = y1 + np.random.normal(0, 0.05, size=y1.shape)

y2 = np.exp(-x / 8) * np.cos(x)
y2_experiment = y2 + np.random.normal(0, 0.05, size=y2.shape)

# Plot the smooth function as a line and the "experimental data" as points
axes[0].plot(x, y1_experiment, "o", label="Data")
axes[0].plot(x, y1, "-", label="Fit")

axes[1].plot(x, y2_experiment, "o", label="Data")
axes[1].plot(x, y2, "-", label="Fit")

# Loop through the subplots and add legends to each using the labels we set above
for axis in axes:
    axis.legend()
../_images/5ca0d0ec848189f2113df31df77ae268c537214a222d03e392bc1fcc2cf45e6d.png

NicePlots#

NicePlots is a little package I helped write with my labmates that we use to make our Matplotlib plots look nicer. It is not at all necessary for the course, but if you do want to use it you can pip install it just like all the other packages mentioned already. You can also check out some example uses of it here.

import niceplots

plt.style.use(niceplots.get_style())

# Repeat the same plot as above, but now with the niceplots style
fig, axes = plt.subplots(nrows=2, sharex=True, figsize=(6, 6))

# Set the axis labels and tick marks
axes[0].set_ylabel("$y_1$", rotation="horizontal", ha="right")
axes[1].set_ylabel("$y_2$", rotation="horizontal", ha="right")
axes[1].set_xlabel("t (s)")
axes[0].set_title("Experimental data")

axes[0].plot(x, y1_experiment, "o", label="Data", clip_on=False)
axes[0].plot(x, y1, "-", label="Fit", clip_on=False)

axes[1].plot(x, y2_experiment, "o", label="Data", clip_on=False)
axes[1].plot(x, y2, "-", label="Fit", clip_on=False)

for axis in axes:
    axis.legend(labelcolor="linecolor")
    niceplots.adjust_spines(axis)
../_images/079ed4b4abe1d7feaebed687a8b14fe1aa18ec69c678a856219fde76a7c500cb.png

Learning python#

Python for everybody is a very extensive and popular course for learning python for complete beginners, it was even developed by a professor at the University of Michigan. The most important basic concepts you’ll probably need for this course are covered in sections 3-11.

Software carpentry also has a good introduction to python.

Below are some more resources on learning to use NumPy, especially for people used to programming in Matlab: