<jupyter_start><jupyter_text>Lab 1 IntroductionIn this lab, we will begin to learn how to use Python to solve mathematical problems.The goal of this lab is to teach you how to write basic, everyday mathematical expressions in Python. This will give you the basic tools you’ll need for future labs, covering quiver plots, Euler’s method and the numerical solution of differential equations, and for subsequent topics in second- and third-year Mathematics.  Executing simple mathematical expressionsIn Jupyter notebooks like this one you can execute Python in cells by pressing Ctrl-Enter (or Shift-Enter).Let's start simple! Execute the cell below and observe the output.<jupyter_code>1 + 1<jupyter_output><empty_output><jupyter_text>Python uses standard symbols for the basic algebraic operations of addition, subtraction, multiplication and division. Here are some examples to try.<jupyter_code>17 - 2.5
7 * 4
1 / 9<jupyter_output><empty_output><jupyter_text>Exponents are represents in Python by double-star `**`. For example, to compute the number googol, which is ten raised to the one-hundredth power, do the following.<jupyter_code>10**100<jupyter_output><empty_output><jupyter_text>Note that in Jupyter, only the output of the final line will be displayed. To suppress that output, terminate the final line with `;`.<jupyter_code>1 + 1
2 + 3
1 + 1
2 + 3;<jupyter_output><empty_output><jupyter_text>If you would like to view a result from a line that is not the final line, use the `print` function.<jupyter_code>print('one plus one is', 1 + 1)
2 + 3<jupyter_output>one plus one is 2<jupyter_text>Using numpy mathematical functionsYou are already familiar with a wide array of mathematical functions, such as trig functions, logs and square roots. Here, we see how to use these functions in Python.Python is a general-purpose programming language, so you have to `import` the mathematical functions that you want from a _module_ called `numpy` (aka NumPy).<jupyter_code>from numpy import log, log10, sqrt, sin, cos, tan<jupyter_output><empty_output><jupyter_text>Names of the functions in NumPy are all more or less the same as the names you use when writing them down or on your graphics calculator. For example, NumPy’s sine function is sin, its cosine function cos and its tangent function tan. Therefore, to compute the cosine of 3.1415926, you proceed as follows.<jupyter_code>cos(3.1415926)<jupyter_output><empty_output><jupyter_text>Note that arguments passed to functions are always enclosed in brackets. Note also that numpy assumes that all angles are in radians.Some function names in NumPy are a little surprising. For instance, the natural logarithm function is `log`, not `ln`.<jupyter_code>log(2.7182818)<jupyter_output><empty_output><jupyter_text>You can compute the base-10 logarithm using `log10`.<jupyter_code>log10(100)<jupyter_output><empty_output><jupyter_text>Other functions that you would usually write with symbols require functions calls. For instance $\sqrt{4}$ becomes<jupyter_code>sqrt(4)<jupyter_output><empty_output><jupyter_text>Exercise 1Calculate `tan(3.14159)` in the cell below.<jupyter_code>tan(3.14159)<jupyter_output><empty_output><jupyter_text>You can execute the same cell as many times as you like. Go back and change your answer above to calculate `tan(3.14159/4)`. You can also copy and paste like you ordinarily would, and by tapping or click next a cell you can select the whole cell. You can move, copy, or paste cells. Exactly how you do this depends on your browser, so experiment a little bit.  Names for common constants in NumPyThree constants that are ubiquitous in mathematics are $\pi$, $\mathrm{e}$, and the imaginary number $i$. We can import the first two from NumPy.<jupyter_code>from numpy import pi, e
tan(pi)<jupyter_output><empty_output><jupyter_text>We know that $\pi$ and $\mathrm{e}$ are constants, but the objects we have just imported from NumPy are _variables_, not functions like we imported from NumPy last time. That means we don't put brackets after them.<jupyter_code>cos(pi/4)<jupyter_output><empty_output><jupyter_text>We don't import $i$ because Python already knows about it. Electrical engineers use $j$ instead of $i$ (because $i$ is current), and so does python.<jupyter_code>1j * 1j<jupyter_output><empty_output><jupyter_text>Note that `1j` is a complex number, so the output of the above multiplication is also a complex number (whose imaginary part is zero). If you really want $\mathrm{e}$ you can use the constant imported above, but most of the time we will use NumPy's `exp` function (which calculates $\mathrm{e}^x$).<jupyter_code>from numpy import exp
exp(1)<jupyter_output><empty_output><jupyter_text>Exercise 2Calculate $\mathrm{e}^{i\pi}$.Unless you import another specialised module, all arithmetic in Python will be _floating point_ arithmetic, where irrational numbers are truncated to have finite precision. For that reason, you may observe a very small _floating point error_ in your results.<jupyter_code>exp(1j*pi)<jupyter_output><empty_output><jupyter_text>Plotting functionsWhen we plot a function given by a formula, say $f(x) = \sin(x)$, we first must define the range of $x$ values we want to use, the domain of the plot. Example 1Plot the curve $y = \sin(x)$ in the range $−5 \leq x \leq 5$. We define the range of $x$ by typing the following command.<jupyter_code>from numpy import linspace
x = linspace(-5, 5, 101)
x<jupyter_output><empty_output><jupyter_text>Note that if you don't know what a function does (or can't remember the order of its arguments), help is only a question mark away.<jupyter_code>linspace?<jupyter_output><empty_output><jupyter_text>The above call to `linspace` creates a $1\times 101$ NumPy array whose elements are from -5 to 5. We chose the steps to be small enough to make the plot smooth. First calculate the $y$ values that correspond to our $x$ values.<jupyter_code>y = sin(x)
y<jupyter_output><empty_output><jupyter_text>There are several good visualisation modules available in Python. We will use Seaborn. We will also use the pandas library to create a table of the data.<jupyter_code>import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd<jupyter_output><empty_output><jupyter_text>This may be the first time that you have encountered object-oriented programming. The `.` in `pd.DataFrame` means that `DataFrame` belongs to `pd`. `pd.DataFrame(...)` creates a new pandas `DataFrame` object, which is a type of data table.This may also be the first time that you have encountered a Python dictionary (`{'x': x, 'y': y}`). Dictionaries are extremely useful, but we will mostly just use them to create pandas DataFrames.<jupyter_code>data = pd.DataFrame({'x': x, 'y': y})
data<jupyter_output><empty_output><jupyter_text>Now draw a line through the points defined by the $x$ and $y$ arrays.The semicolon is more of a Jupyter thing than a Python thing. It supresses the value that is returned from `sns.lineplot` so that it isn't displayed in our notebook.<jupyter_code>sns.lineplot(data=data, x='x', y='y');<jupyter_output><empty_output><jupyter_text>Steps for basic plotting1. define the range: `x = linspace(`start`,`stop`, `num points`)`2. define the function you want to plot: `y = `function`(x)`3. copy-and-paste the plot command:```data = pd.DataFrame({'x': x, 'y': y})sns.lineplot(data=data, x='x', y='y');``` Example 2Plot the function$$y = x^2 - x\sin(3x) - x\mathrm{e}^x,\qquad -3\leq x \leq 3$$<jupyter_code>x = linspace(-3, 3, 61)
y = x**2 - x*sin(3*x) - x*exp(x)
data = pd.DataFrame({'x': x, 'y': y})
sns.lineplot(data=data, x='x', y='y');<jupyter_output><empty_output><jupyter_text>Example 3Sometimes we have a set of measurements that we want to plot. Essentially we do what we did above, but the variables now contain the data, rather than values of an independent variable $x$ and the corresponding function values $y$.Here are some actual data on influenza cases collected during the 2003-2004 flu season.<jupyter_code>data = {'Week':
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
         14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26],
        '% patients with flu-like symptoms':
        [0.9, 1.0, 1.3, 1.3, 1.8, 2.4, 2.7, 3.7, 4.5,
         5.4, 7.4, 7.5, 7.6, 5.2, 2.9, 2.1, 1.9, 1.8,
         1.5, 1.4, 1.3, 1.1, 1.0, 1.0, 1.1, 0.9]}
data['Week']<jupyter_output><empty_output><jupyter_text>As usual, insert the data into a DataFrame<jupyter_code>data = pd.DataFrame(data)
data<jupyter_output><empty_output><jupyter_text>Week 1 is the first full week of October 2003. _% Flu Cases_ is the percentage of all patients seen by doctors in that week who had flu-like symptoms.Let's plot them. Instead of suppressing the output of `sns.lineplot`, we can use it to give the plot a title. Note that the `.` operator means that `set_title` belongs to the `ax` object. Calling it alters the `ax` object (it adds the title to the plot).<jupyter_code>ax = sns.lineplot(data=data, x='Week', y='% patients with flu-like symptoms')
ax.set_title('The 2003-2004 Flu Season')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09539003190670041, 'fraction_numerical': 0.026185498954780503, 'mean_word_length': 5.316886726893676, 'pattern_counts': {'":': 0, '<': 104, '<?xml version=': 0, '>': 104, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '548301', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 3005, 'n_tokens_neox': 2773, 'n_words': 1181, 'path': 'notebooks/lab-01.ipynb', 'repo_name': 'BenKaehler/mm-labs', 'size': '9089'}