Pyton for beginners

Zawartość:

Organizacja

OCENA

Materiały dodatkowe

Zestawy zadań

Set 1

…functions, numbers, tuples, and lists…
A
(3 points)

It’s \(3\) o’clock in the morning and you need to prepare some formula to feed your newborn baby. The instructions on the package are very specific: prepare a certain amount of water at a given temperature, add the correct amount of formula, mix and cool everything down before serving. In order to keep the baby safe from infections, all the water that you use needs to be pre-boiled. Here is your setup:

  1. You prepared a container of pre-boiled water cooled down to the temperature \(T_{\text{cool}}\).
  2. You prepared an empty, sterile feeding bottle.
  3. You have an electric kettle and measured that when the water comes out of the spout it has temperature \(T_{\text{hot}}\) (it’s slightly cooler then \(100^{\circ}C\)).
  4. You need to prepare \(V\) milliliters (or any other unit of volume) water at temperature \(T\) to mix up the formula for your little one. You do this by first pouring \(V_{\text{cool}}\) milliliters (or any other unit of volume) of the cooler water into the bottle and then filling the bottle up to \(V\) with the hot water from the kettle. How much cool water should you use?

The mathematics of this problem is very simple, see the APPENDIX. To make things more convenient implement the python function:

def calculateVcool(Tcool , Thot , V , T):
    #...
    return Vcool

that returns the volume of the cooler water \(V_{\text{cool}}\) you need to pour into the bottle before pouring the remainder of the water from the kettle. This volume is calculated in such a way that when mixed the water has temperature \(T\).

Tip: If you find yourself in this scenario a infrared thermometer is a fantastic tool.

B
(1 points)

Turn the V, T, and Thot arguments of function calculateVcool from exercise A into optional arguments with realistic default values for a \(3\) month old baby.

C
(2 points)

Write a python script that asks the user to input the arguments of calculateVcool from A, runs the function and prints the result.

D
(1 points)

Nobody has time to fiddle around with their laptop at \(3\) o’clock in the morning. Get the script from C to run on your phone (at your own risk :-) ).

E
(4 points)

Your significant other (SO) has the early morning shift with the baby and asked you to prepare a thermos with pre-boiled water. You have determined the temperature coefficient of the thermos (the mathematics of this is very simple, see the APPENDIX) and need to decide on the temperature of the water in the thermos so that in a couple of hours, when your SO needs to prepare the formula, the temperature of the water in the thermos is appropriate.

To help with this implement the python function:

def calculateTemperature(Tfinal , time , Troom , k , 
        search = (0.0 , 100.0 , 1000)):
    #...
    return T

where Tfinal is the desired temperature of the water after time time, Troom is the ambient room temperature and k is the temperature coefficient. The final optional argument search determines the parameters of a numerical simulation that will solve the problem. The returned value T is the desired temperature of water in the thermos.

Use a simple numerical simulation to solve the problem. In this simulation scan initial water temperature candidates in the range search[0] \(\ldots\) search[1]. The range is divided into search[2] temperature values. For each temperature candidate, the final temperature after time time is calculated (see APPENDIX). Finally, out of all the temperature candidates, the one whose final temperature is closest to the desired Tfinal is returned as T. In your implementation please use:

Tip: The exponent is available in the math library. There is no need to install anything, it comes built in. Simply use from math import exp

APPENDIX

When mixing water to arrive at a given temperature, approximately (the notation is the same as in the exercises): \[ V_{\text{cool}} = V \frac{T_{\text{hot}} - T}{T_{\text{hot}} - T_{\text{cool}}} \] Does it matter if we use \(^{\circ}C\) or \(^{\circ}K\)? Is the formula any different if you prefer to pour the hot water first?

When water in a container is left in a room with ambient temperature \(T_{\text{room}}\) it will gradually, over time change it’s temperature to match the ambient temperature. This process can be approximately modeled by the formula: \[ \tau(t) = T_{\text{room}} - (T_{\text{room}} - \tau(0)) e^{-t/k} \] where \(\tau(0)\) is the initial temperature of water in the thermos and \(\tau(t)\) is the temperature in the thermos after time \(t\). The remaining notation is the same as in the exercises. Please note that a non-standard definition of the temperature coefficient \(k\) is used. The value of this coefficient can be worked out by measuring the temperature of the water in the thermos at two points in time and doing a little algebra. Does it matter if we use \(^{\circ}C\) or \(^{\circ}K\)? Is the formula any different if you prefer to pour the hot water first?

ADDITONAL MATERIALS

Set 2

…to is or not to is, dictionaries, loops, flow control, modules and objects…
A
(2 points)

Implement a function that takes an arbitrary number of arguments, say floating point numbers, and returns a dictionary containing:

Use this function in a script.

B
(3 points)

Implement a simple text based game. The gameplay and objective is completely up to you.

Please base your implementation on the following function:

def updateGameState(state)
    # ...

that updates the dictionary state in every iteration of the main game loop:

while(!state["finished"]):
    # ...    

At each iteration of the game loop print the available moves / options available to the player and use the input function to decide on how to proceed with the game play. Use if, else, and elif statements to decide how the game state will evolve. When the game is finished, change the value of "finished" in state to True. This will cause the main loop of the game to terminate.

C
(3 points)

Add some elegant ASCI art to your game. To do this please import the sys module and use the sys.stdout.write method to implement the function:

def showGameState(state):
    # ...

that will print a beautiful graphical representation of the game state to “standard output”. Add this function to the main game loop. Please assume that we are working in a terminal that is \(80\) characters wide and \(40\) characters tall.

Tips:

D
(2 points)

Implement a “smart” function:

def smartFunction(a , b):
    # ...
    return c

that returns the result c = a + b. Since this operation is very laborious and time consuming, the function memorizes previous arguments a, b that were passed to it, it also memorizes the result. This is all in the hope that when we pass those arguments to the function again it won’t have to do all that work, it’ll just recall the result.

In order to achieve this introduce a global variable smartFunctionMemory that will contain a dictionary. The keys in this dictionary are related to the arguments a, b, and the values are related to the results c.

What types of arguments can we pass into smartFunction?

E
(2 points)

Implement the function:

def readState(path)
    # ...
    return state

that reads the state from a file located at path path. The contents of this file is processed to obtain the saved state of a previous game.

Implement the function:

def writeState(state , path)
    # ...

that writes the game state to a file located at path path.

Add readState before the start of the game loop and writeState after the loop to allow the user to save the game progress.

Tip: Don’t worry we’ll discuss the details during class :-)

ADDITONAL MATERIALS

Set 3

…literate programming, loops and lambdas, …
A
(2 points)

Replace the repeated if, elif, else statements from your game in Set 2 with match. If these statements don’t appear in the game, please add some.

B
(2 points)

End your scripts from Set 1 with an infinite while loop instead of a call similar to input("Hit enter to exit."). Please use pass in the infinite loop.

Import the time module and use the time.time() function to measure the time the program spends in the loop. If this time exceeds \(10\) seconds, ask the user if the program should exit. If the program is supposed to wait reset the timer and run the loop for another \(10\) seconds.

Tip: use continue, and break.

C
(4 points)

Using the Jupyter notebook please investigate the logistic map.

Create a function that calculates the logistic map and draw the map using the matplotlib library, we will discuss how this library works during class. Make sure the notebook has a detailed description of your approach, use literate programming.

D
(2 points)

Re-implement the function from C to accept a keyword argument drawFunction. If the value of this keyword argument is not the default None then drawFunction points to a function that draws the data and a plot of the logistic map is produced automatically.

Test if this works using a lambda expression.

Can you use is to check if drawFunction has the default value?

ADDITIONAL MATERIALS

Set 4

…modules, packages, first look at classes and objects, …
A
(3 points)

Implement a Reverse Polish Notation calculator. Base your program on a stack implemented as a python list. All operations of the calculator take the stack, modify it and return the modified stack. For example adding two numbers:

def add(stack):
    x = stack.pop()      # 1
    y = stack.pop()      # 2
    stack.append(x + y)  # 3
    return stack         # 4

At 1 a number is popped from the end of the list with pop resulting in a shorter stack. At 2 another number is popped from the stack. Finally in 3 the stack is modified by adding a number to the end of the list with append. The new stack, shorter by one number, is returned in 4.

Add more functions:

Refer to the functions from a dictionary whose keys are python strings - the names of the functions. The values in the dictionaries are the functions themselves.

Create a while loop that checks if None is in the stack using in, if it’s in the stack - exit. In the loop ask the user to enter the command name, run the appropriate command from the dictionary to modify the stack. If the command is not in the dictionary keys, assume that the user entered a floating point number and append it to the stack.

B
(1 points)

Make the code from A a little more bullet proof:

C
(2 points)

Add another module extra.py with additional functions. Modify A to look inside this module for additional functions (tip: use the __dict__ attribute, we will discuss this during class).

D
(2 points)

Implement a simple class that iterates over the Fibonacci numbers. The constructor takes one argument - the number of Fibonacci numbers to iterate over. We will discuss the details during class.

ADDITONAL MATERIALS

Set 5

…sets, ciphers, and more on files…
A
(2 points + 1 point)

Implement two functions. The first one encodes the plaintext … plaintext (string of characters):

def encode(key , plaintext):
    # ...
    # return ciphertext

and the second one decodes the ciphertext … ciphertext (string of characters):

def decode(key , ciphertext):
    # ...
    # return plaintext

Both functions take a string of characters, key, as the first argument.

Use any cipher you like. We will discuss options during class. The extra point is for interesting solutions.

B
(2 points)

Rewrite the functions from A. Implement encoder and decoder so that they can be used:

myEncoder = encoder("secret_key")
myDecoder = decoder("secret_key")

plaintext = "this is the plaintext"
ciphertext = myEncoder(plaintext)

print(myDecoder(ciphertext) == plaintext) # true

Use two different methods:

C
(3 points + 1 point)

Using the argparse library implement a simple note taking application. The application has only one positional argument:

and the following optional arguments:

In your implementation:

Extra point: replace the positional argument password with an appropriate function from the getpass modle. Is this safer? Why?

DISCLAMER: This note taking application is only as safe as our implmentation makes it. Use at your own risk!

D
(2 points)

Next time we will be talking about the numpy module. In preparation please write a script that multiplies two \(1024 \times 1024\) matrices. Use python lists and list comprehensions to implement the matrices. Measure how much time the script takes to execute.

ADDITONAL MATERIALS

Set 6

…life, numpy, matplotlib, more on classes and exceptions…
A
(2 points)

Using the numpy library please implement the game of life with periodic boundary conditions (the left half of the grid is glued to the right, the top part of the grid is glued to the bottom … essentially creating a torus). The implementation should be a single script. The grid of cells is represented by a numpy array with an integer dtype. When implementing a single iteration of the game, please stick to the numpy library as strictly as possible to boost performance. Test the performance using large grids (1920 by 1080 and larger).

Tip: Use the numpy.roll function to obtain the state of neighbouring cells. Visualization can be achieved using the matplotlib.pyplot library functions, imshow or matshow function. We will cover the basic usage of matplotlib during class.

B
(4 points)

Extend A to continuous values: the state of the cell can be dead (0), alive (1) or anything in between. There are many sensible ways of doing this. One way is “smooth life”, see the links:

Tip: The function convolve2d from the scipy might be helpful. It works with numpy arrays. Visualization can be achieved using the matplotlib.pyplot library functions, imshow or matshow function. We will cover the basic usage of matplotlib during class.

C
(2 points)

Add a simple interactive command line interface to A or B. The program should give the user at least the following options:

Be persistent, if the user types an incorrect value prompt him / her again. To do this use try, except.

D
(2 points)

Wrap everything (A + C or B + C) into a class. Place the class definition in a separate module and use this module in a script.

E
(2 points)

Write a wrapper for the numpy array representing a grid of cells in the game of life. Try to make this class immutable (is this really possible in python?). Add the __hash__ and __eq__ methods to the class.

ADDITIONAL MATERIALS

… Obtaining the number of neighbours for the basic game of life

Let’s assume that we start from random configuration of \(4 \times 4\) cells:

import numpy as np                                        # 1
s = 4                                                     # 2
state = np.random.randint(0 , high = 2 , size = (s , s))  # 3
print(state)                                              # 4

In 1 we import the numpy library, in 2 we set the size of the matrix containing cell states, in 3 we draw a random distribution of cells (0 meaning a dead cell 1 meaning a live cell, the integers are drawn from a uniform distribution between \(0\) and high - 1 \(= 1\)). Finally 4 prints our result:

[[0 0 0 0]
 [0 1 1 0]
 [1 1 0 1]
 [0 1 0 1]]

To get a table whose values at a specific row and column correspond the state if the eight neighbors (Up, Down , Right , Left , UpRight , DownLeft , UpLeft, DownRight) we first roll the arrays to obtain:

U = np.roll(state , 1 , axis = 0)
D = np.roll(state , -1 , axis = 0)
R = np.roll(state , -1 , axis = 1)
L = np.roll(state , 1 , axis = 1)
UR = np.roll(np.roll(state , 1 , axis = 0) , -1 , axis = 1)
DL = np.roll(np.roll(state , -1 , axis = 0) , 1 , axis = 1)
UL = np.roll(np.roll(state , 1 , axis = 0) , 1 , axis = 1)
DR = np.roll(np.roll(state , -1 , axis = 0) , -1 , axis = 1)

and then sum:

neighbors = U + D + R + L + UR + DL + UL + DR
print(neighbors)

as a result, each cell has the following number of neighbors:

[[3 3 4 2]
 [4 3 3 3]
 [5 4 6 3]
 [5 2 4 2]]

This should be correct if we assume periodic boundaries (the left edge is glued to the right edge and the top edge is glued to the bottom edge).

The next bit is tricky. There are many ways of implementing a single iteration of the game. Since we are looking to eliminate regular python loops to increase the speed of our program have a look at the following functions np.ones, np.zeros, np.where, np.logical_and, np.logical_or and then have a close look the following code:

allAlive = np.ones((s , s) , dtype = np.int64)
allDead = np.zeros((s , s) , dtype = np.int64)
np.where(np.logical_and(state == 0 , neighbors == 3) , allAlive , state)

This can be easily extended to include the whole set of rules of the game. Remember stick to numpy for performance.

… The same thing but this time with convolutions …

Let’s import the convolve2d function from the scipy.signal library. Note that we are not importing the whole package nut just one function:

from scipy.signal import convolve2d

Next let’s try this:

k = np.array([[1 , 1 , 1] , [1 , 0 , 1] , [1 , 1 , 1]])
neighborsWithConvolve2D = convolve2d(state , k , mode = "same" , boundary="wrap")
print(neighborsWithConvolve2D)

The result should be the same as neighbors:

[[3 3 4 2]
 [4 3 3 3]
 [5 4 6 3]
 [5 2 4 2]]

The result is the same but the method is more general. We can look at a wider neighborhood of a cell by modifying k.

… The user input is all wrong …

Tip: Saving a numpy array can be obtained by running np.save (or numpy.save if we used just import numpy). Loading a numpy array can be obtained by running np.load. Both these functions raise exceptions if they get a bad file path. This means that we can use them inside try: and except: blocks. The function int also raised exceptions when it’s string argument is not a correctly formatted integer.

… Hiding class members …

A nice article on name mangling at geeksforgeeks.

… Calculating the hash of a numpy array …

To calculate the hash of the data that is contained inside a numpy array a try hash(a.data.tobytes()).

… Implementation using pygame

See the pygame website for installation instructions. To implement the game of life, both the classic version and the smooth version, you can use the template. Please read the comments from the template carefully.

Set 7

…magic methods, class functions and the matrix…
A
(2 points)

Implement the smart function from exercise D in Set 2. Use a function decorator. This decorator is a class with a __call__ method. Objects of this class also have a field that contains a dictionary with previous arguments and return values.

B
(2 points)

Expand the decorator from the previous exercise to accept a function with an arbitrary number of arguments positional argument.

C
(1 points)

Expand the decorator from the previous exercise to accept a function that has an arbitrary number of positional and keyword arguments.

D
(2 points)

Define a class BadHash of mutable integer objects. Each time a new instance of the object is created, increment a class variable. Add with a __hash__ method to … CAREFULL THIS IS A BIG MISTAKE! But we will go with it to explore the consequences. Use this method with functions that use our decorator.

E
(4 points)

Define a class whose objects hold a numerical value. At minimum, the class should have the following methods apart from the constructor:

In addition to performing numerical operations __add__, __sub__, __mul__, __truediv__, and __neg__ should appropriately increase the four class counters that determine how many additions, multiplications, divisions and negations were executed. Add the following class methods:

Use this class to determine the computational complexity of matrix multiplication and calculating the application of a matrix to a vector.

ADDITIONAL MATERIALS

Set 8

…pretty strings…
A
(1 + 1 points)

In an era before electronic calculators, logarithms were king. Two usefull properties of the logarithm function: \[ \log{a b} = \log{a} + \log{b} \] \[ \log{a / b} = \log{a} - \log{b} \] make it possible to change multiplication and division into addition and subtraction which require much less effort. This observation lies at the heart two interesting old calculating methods: the slide rule, and tables of logarithms. We will be focusing on the latter.

Please read this section on fancier string formatting and create a string containing a table of logarithms:

-------------------
| x     |  Log(x) |
-------------------
| 1.00  |  0.0000 |
| 1.01  |  0.0043 |
| 1.02  |  0.0086 |
...
| 1.20  |  0.0792 |
...
| 2.00  |  0.3010 |
...
| 6.00  |  0.7782 |
...
| 10.0  |  1.0000 |
-------------------

the first column has numbers going from \(1\) to \(10\) (the step size is up to you). The second columns is a base \(10\) logarithm of the corresponding number in the first column.

How can we use this table in practice. Let’s say we want to multiply \(2\) by \(6\): \[ \log_{10}{2 \times 6} = \log_{10}{2} + \log_{10}{6} \approx 0.3010 + 0.7782 = 1.0792 = \log_{10}{x} \] where \(x\) is our approximate result (\(\approx 12\)). We can approximate the logarithms by looking at our table and addition is easy enough (a person equipped with only a book of logarithm tables and an abacus is a dangerous calculating machine). There is a problem though, if we look at the second column the value \(1.0792\) is out of range, how do we solve this? Simple, just subtract \(1\) (or divide by \(10\) depending on how you look at it): \[ \log_{10}(x / 10) = \log_{10}{x} - \log_{10}{10} = 1.0792 - 1.0 = 0.0792 \] The value \(0.0792\) is no longer out of range in the second column and corresponds to … \(1.20\) which is our apporximate (we are doing approximations here left and right, let’s not forget about this) result divided by \(10\). So to summarize logarithm tables, plus some extra tricks like dividing by ten or subtracting one, are a powerful calculating tool.

Save your table into a text file. Make sure that:

Hint: logarithms are available in the math library. To calculate the base \(10\) logarithm of \(2.0\) you can use math.log(2.0 , 10).

B
(3 points)

Change the formatting of your logarithm table to use \(\LaTeX\) syntax for tables. Make the table larger and split it into multiple separate tables. Each page should contain a single table. Add special values for \(\pi\), \(\e\) etc. Can we add more columns to perform calculations with square roots and trigonometric functions?

Save the string with your table into a file with a .tex extension. Compile it with \(\LaTeX\).