The course

We are here to work out how to teach coding in the context of the MATH1058 (Operational Research with Mathematical Computing) which is new in 2017/18. The motivations for the computational component were outlined in these slides, which led to this much more detailed Python for Mathematicians tutorial.

The crucial point is not the Python (and LaTeX, and Excel) content that the students will see, but the attitude and approach towards computing that we want to instill.

The students

We can expect many different backgrounds within the student cohort. Some example profiles would be

  1. The student with a computing background, maybe doing Maths with CS, who already knows more Python than any of the instructors ("How can I overload these Python operators in my derived classes?").
  2. The student who's wary of computing or doesn't see its relevance to the pure, abstract mathematical approach they aspire to ("If I wanted to do programming I wouldn't be taking Mathematics").
  3. The student who sees computing as a pragmatic necessity for future employers but doesn't connect it to their mathematical studies ("I'm just doing this for the CV points").

The mental model

We want all the students to construct a mental model that links key mathematical concepts to their practical expression in code, and understands when using code to explore mathematics is useful. To do this we want to

  • link to mathematical examples - in this case, the Operational Research part of the course, or other examples;
  • link to mathematical concepts - constructive proof, iteration, etc - whenever introducing new programming concepts;
  • emphasize the communication aspects - through documentation, and in the use of LaTeX - at all stages, to demonstrate understanding;
  • present computing as a standard tool of mathematicians.

Remember: it doesn't matter if the instructor knows less computing than the student. The point is to get across your mathematical mindset.

Python

Notation

When writing computer commands that you can type, the font will change to command. For example, x=2**3.4/5 is a command that can be typed in.

When we talk about a general command, or some piece of missing data that you should complete, we will use angle brackets as in <command> or <variable>. For example, <location> could mean "Southampton".

When showing actual commands as typed into Python, they will start with In [<number>]:. This is the notation used by the IPython console. The <number> allows you to refer to previous commands more easily. The output associated with that command will start with Out [<number>]:.

When displaying code, certain commands will appear in different colours. The colours are not necessary. They highlight different types of command or variable. When using the spyder editor you may find the colours match up and are useful: if not, either ignore them or switch them off.

The console - Python as calculator

Start with using Python as a calculator. This is similar to typing commands directly into an Excel worksheet. Look at the console in the bottom right part of spyder. Here we can type commands and see a result. Simple arithmetic gives the expected results:


In [1]:
2+2


Out[1]:
4

In [2]:
(13.5*2.6-1.4)/10.2


Out[2]:
3.3039215686274517

If we want to raise a number to a power, say $2^4$, the notation is **:


In [3]:
2**4


Out[3]:
16

There is an issue with division. If we divide an integer by an integer, Python 3.X will do real (floating point) division, so that:


In [4]:
5/2


Out[4]:
2.5

However, Python 2.X will do division in the integers:

In []: 5/2
Out []: 2

If you really want to do integer division, the command is //:


In [5]:
5//2


Out[5]:
2

Variables

A variable is an object with a name and a value:


In [6]:
x = 2

Teaching note

If students are familiar with some other scripting language this should be clear. If they're used to R (and remember they'll be doing R through MATH1024) then that uses the notation

x <- 2

Some languages (particularly compiled languages, but Visual Basic is another that they may have seen) want the type of the variable declared first. So in VBA this would be

DIM x AS INTEGER
x = 2

It is worth showing that the same variable can be assigned variables of different types without any problem:


In [7]:
x = 2.3
x = "hello"

We see that there's no output when you define a variable. To get output, use the print function:


In [8]:
print(x)
x = 3.4
print("x =", x)
x = 7
print("x = {}".format(x))


hello
x = 3.4
x = 7

It is worth emphasizing that the "equals" sign is not mathematical equality, but an assignment operation that has an order. So we've seen that x=2 works, but:


In [9]:
2=x


  File "<ipython-input-9-18df7434ef40>", line 1
    2=x
       ^
SyntaxError: can't assign to literal

Variable names have certain rules and conventions, which are very similar to VBA.

Variables must

  • not contain spaces
  • not start with a number
  • not contain a special character (such as !@#$%^&*()\|)

Variables should

  • be descriptive, ie say what their purpose is in the code
  • be written entirely in lower case
  • separate different words in the variable name using underscores

More detail can be found in PEP8.

It is strongly recommended that variables do not use any extended characters, but only the basic latin characters, numbers, and underscores.

Check that you are happy manipulating variables in the console. For example,


In [10]:
x = 3
y = 17.5

In [11]:
x+y


Out[11]:
20.5

In [12]:
x/y


Out[12]:
0.17142857142857143

In [13]:
x**(-2/y)


Out[13]:
0.8820066439915335

Assigning a value to one variable does not change the value of other variables. Let's set the value of variable y to be a function of the variable x.


In [14]:
x = 1.5

y = x**2

print('x: {}, y: {}'.format(x, y))


x: 1.5, y: 2.25

If we change x by assigning it a new value, we see that y is not automatically updated. Once a value is assigned to a variable, it does not 'remember' where this value came from. This is different from how spreadsheets work.


In [15]:
x = 3

print('x: {}, y: {}'.format(x, y))


x: 3, y: 2.25

Also try doing some things that you expect to break, so you understand the error messages:


In [16]:
x / 0


---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-16-91e0c8b67771> in <module>()
----> 1 x / 0

ZeroDivisionError: division by zero

In [ ]:
z = "hello"
y * z

Programs and scripts

We will want to repeatedly execute commands, and store work for later use. The Python console is no use for this. Instead we must save the commands to a file, sometimes called a script. This will be a plain text file, containing Python commands. The name of the file follows the same rules as the names of Python variables.

Note that most programming languages work this way. The key difference between languages is how multiple files are used together to make something happen.

The editor in spyder is a good way of creating Python files, as it has additional tools to make it easier.

As a simple example, we will use the three lines


In [17]:
x = 3
y = 11.5
x+y


Out[17]:
14.5

Go to the editor and type in the three lines:

x = 3
y = 11.5
x+y

Save the file in a suitable location with the name script1.py. Make certain that your working directory in spyder matches the location you've save the file (not always needed, but always worth doing to avoid issues).

To run this program, either

  • press the green "play" button in the toolbar;
  • press the function key F5;
  • select "Run" from the "Run" menu.

In the console you should see a line like

runfile('/Users/ih3/msc-or-python/script1.py', wdir='/Users/ih3/msc-or-python')

appear, and nothing else. To check that the program has worked, check the value of y. In the console just type y:


In [18]:
y


Out[18]:
11.5

Also, in the top right of the spyder window, select the "Variable explorer" tab. It shows the variables that it currently knows, which should include y, its type (float) and its value.

Why did running the script not produce output? By default, output is only produced in the console. If you want a script to really produce output, use the print function.

Edit your script to read

x = 3
y = 11.5
print(x+y)

Save it and run it again: you should now see output in the console.

The import statement

One single file containing Python commands isn't much help. Being able to re-use previous files (and their variables and functions) is what we really want to do. To do this we need to get the information from a file.

In the console type


In [19]:
import script1


14.5

This finds the file script1.py and runs all the commands in it. As the file has been edited to explicitly print the result of x+y, we see output.

What we're really interested in is the values defined in the file. Type


In [20]:
script1.y


Out[20]:
11.5

We see the value in the file has been stored in <filename>.value. This means we never have to worry about the value in the file over-writing the value we currently have, as they have different names. Check this by typing:


In [21]:
y = 17.2
print(y)
print(script1.y)


17.2
11.5

We can import the variables (and functions, and everything) from one file into another file. Create a new file (to be saved as script2.py which reads

import script1

z = 4.3
print(script1.y - z)

We see that it directly uses the variables from script1:


In [22]:
import script2


7.2

Teaching note

There is a persistent annoying issue with Python and spyder that it will not import a script (or module, or package) that has already been imported. This is usually what you want. However, when modifying scripts or working in the console we see that this can lead to confusion. In the example above, script1 contains a print call, as does script2. When importing script2 it in principle executes all commands in script1, so you would expect to see two lines printed. But above we only see one.

This is because script1 has already been imported into the console, so the commands in it will not be executed again. If you open a new console and import script2 in that before importing script1 then you will see two lines printed.


We can use import to get access to a huge range of in-built Python packages. For example, the numpy package gives us access to more useful mathematical and numerical functions:


In [23]:
import numpy
print("pi is", numpy.pi)
print("log(y) is", numpy.log(y))


pi is 3.141592653589793
log(y) is 2.84490938382
Exercise

Check that you are happy with tab completion and/or using the help to work out how to compute $\tanh(e)$ using numpy commands.


In [24]:
numpy.tanh(numpy.e)


Out[24]:
0.99132891580059979