# Python: Our first program ([home](https://github.com/alexhkurz/introduction-to-numbers/blob/master/README.md) ... [previous](https://hackmd.io/@alexhkurz/r1Gdg_EoU) ... [next Python](https://hackmd.io/@alexhkurz/SkABF8ajI) ... [next maths](https://hackmd.io/@alexhkurz/B1w9oSPiL)) The beginnings of Python are easy to understand. Let us have a look. In the [previous session](https://hackmd.io/@alexhkurz/r1Gdg_EoU) we used the program [`check_group`](https://github.com/alexhkurz/introduction-to-numbers/blob/master/src/check_group.py) to check whether a given table represents an operation that is associative. Now we take this opportunity to learn a bit more about programming and Python. The first line of the program is carrier = [0,1,2,3] that is, we give the name `carrier` to the list `[0,1,2,3]`. This is the list of elements of the system of numbers we want to verify as a group. In mathematics, it is common to call the set of elements of a structure the "carrier" of the structure. By the way, you can ask a question to a program by inserting print statements. For example: **Exercise:** If you add the lines print(carrier[0]) print(carrier[1]) print(carrier[2]) print(carrier[3]) print(carrier[4]) and then run the program, what happens? Each time you ask Python a question you should update your mental model of Python. And it is always good to try to refine your model of a programming language. For example, according to the experiments above, the meaning of `carrier[0]` could be both just `0` or also the `0`th element in the list `carrier`. **Exercise:** Devise an experiment that allows you to learn which of the two models of computations is implemented in Python. To summarise what we learned so far: **Computational model:** The first element of a list is indexed by `0`. Indexing an element that does not exist causes a run-time error called `list index out of range`. After you updated your mental model you should be able to predict the outcome of further experiments. For example: **Exercise:** Extend the carrier to contain 5 elements. What does the command `print(carrier[4])` output now? Is this a different error than before? In which line of the program does it happen. Can you guess why it might happen? Can you guess how to change the table to avoid the error? Don't worry if not, we will come back to this below. A great way to learn programming is to ask your own questions. **Activity:** Think of a question of your own. How could you ask this question to Python by inserting a print statement into the program? What happens if you run your modified program? Or just take some of the print statements above and modify them and/or move them around to other places in the program. What happens? After doing this for while, are you able to predict what will happen? (After you are done asking these questions, remove the print statements again. Don't let them pollute the code. And take the additional element 4 out of the carrier.) The program continues with table = [ [0,1,2,3], [1,2,3,0], [2,3,0,1], [3,0,1,2] ] This is the structure, namely the operation of which we want to confirm that it has the properties of a group (identity, inverses, associativity). Again, it is a good idea to ask some questions: **Exercise:** What does the program output if you add the statements print(table[0][0]) print(table[1][2]) print(table[2][1]) print(table[4][4]) **Exercise:** Can you change the table so that the commands `print(table[1][2])` and `print(table[2][1])` print different output? To continue reading our program, # print a 2d table in matrix form without commas, brackets and quotes is just a comment to increase readability for human readers. Comments are ignored by the computer. To the human reader, the comment tells us what the function `print_table()`, defined next, is supposed to do. def print_table(table): for row in table: print(" ".join(map(str,row))) To explain this in a bit more detail, for Python, the `table` [[0,1,2,3], [1,2,3,0], [2,3,0,1], [3,0,1,2]] is a list of lists of elements, with lots of `,` and `[` and `]`. We don't need to know how the function `print_table()` works internally, just that it removes these symbols to make the table look nicer: 0 1 2 3 1 2 3 0 2 3 0 1 3 0 1 2 Now we come to the interesting part of the program, namely how to verify whether `table` is associative. Mathematically, we would write associativity as $$ x(yz)= (xy)z$$ for all $x,y,z$. Here, we decided to not give a particular name such as $+$ or $\cdot$ to the operation and just write $xy$ instead of $x+y$ or $x\cdot y$. In Python, $xy$ becomes simply `table[x][y]`. **Activity:** In which line of the program do you find $x(yz)=(xy)z$? Now we are almost there. We just need to know how to translate the "for all $x,y,z$". This is done using the `for`. So the checking associativity looks in Python as follows. def is_associative(): for x in carrier: for y in carrier: for z in carrier: if not table[x][table[y][z]] == table[table[x][y]][z]: print('') print_table(table) print('not associative for',x,y,z) return False return True If you want to write your own Python code it is important to know that the indentation is part of the language. This is called "layout syntax". For example, it is important that the `return False` is "inside" the `if` and that the `return True` is "outside" of the `for`s. In other words, we print "not associative" only in case that a violation of associativity was found and we return True only if no violation was found. To understand that the latter is true, you need to know that the "return False" terminates the function `is_associative()` immediately. The code above only *defines* the function `is_associative()`. To run the function we still need to *call* it. This is what happens next: if is_associative(): print('') print_table(table) print('is associative') In words, if the table is associative, we print the table and a message confirming associativity. **Homework:** Use the program to test for associativity various tables you define yourself. You may also want to experiment with larger carriers. **Homework for the Couragous:** Define other functions such as `is_commutative()` or `inverse(x)` or `has_inverses()` or `has_neutral_element()`.