CS51A - Spring 2022 - Class 24
Example code in this lecture
higher_order_functions.py
montecarlo.py
Lecture notes
admin
- assignment 12
- final practice problems posted
higher order functions
- have you ever typed a function into the shell, but forgot the parentheses?
def my_function(x):
return x+1
>>> my_function(2)
3
>>> my_function
<function my_function at 0x108e962f0>
>>> abs
<built-in function abs>
- Notice that it does NOT give an error
- Instead, it echoes the value, just like any other expression, in this case, the value is a function!
>>> type(my_function)
<class 'function'>
- functions in python are values, just like everything else!
>>> y = my_function
>>> y
<function my_function at 0x108e962f0>
>>> y(2)
3
>>> my_abs = abs
>>> my_abs(-10)
10
- we can pass them as parameters
- we can return them from functions
- we can even create them on the fly!
- what do the first four function in
higher_order_functions.py code
do?
- take two arguments and do standard mathematical calculations
- what does apply_function do in
higher_order_functions.py code
?
- takes three arguments
- the first is a function!
- applies the function passed as the first argument to the second and third argument and returns the result
- We can call our apply_function function:
>>> apply_function(add, 2, 3)
5
>>> apply_function(subtract, 2, 3)
-1
- to pass a function as a parameter you just give the name of the function as the argument
- def
- what the keyword def actually does is
1) create a new function
2) assign that function to a variable with the name of the function
map
- what does the apply_function_to_list function do in
higher_order_functions.py code
?
- takes a function and a list as parameters
- you can tell that the parameter "function" is a function because we apply it in the line with the append in it
- iterates through each value in the list
- applies the function
- appends the result of the function to a list that is then returned
- High-level: applies the function to each element in the list and returns a new list containing the result from each of those applications
- For example:
>>> apply_function_to_list(double, [1, 2, 3, 4])
[2, 4, 6, 8]
- this function is actually built in to python, call map:
>>> help(map)
Help on class map in module builtins:
class map(object)
| map(func, *iterables) --> map object
|
| Make an iterator that computes the function using arguments from
| each of the iterables. Stops when the shortest iterable is exhausted.
- take as input a function and something that is iterable
- only difference is that it return a map object (not a list), which is also iterable.
>>> map(double, [1, 2, 3, 4])
<map object at 0x7f7ff809b128>
>>> for val in map(double, [1, 2, 3, 4]):
print(val)
2
4
6
8
- by itself, this may not seem useful, but we can do more complicated things. What would this print?
>>> for val in map(double, map(double, [1, 2, 3, 4])):
print(val)
- the first map doubles it and then we iterate of this result and double it again!
filter
- what does the filter_list function do in
higher_order_functions.py code
?
- also takes a function and a list as parameters
- are there any expectations on what the function should do/return?
- it's used in an if statement
- it should return a bool, i.e. True or False
- The filter function is like map in that it applies the function to every element in the list
- BUT, it only keeps those where the function returns True for that element
- For example,
>>> map(is_even, [1, 2, 3, 4])
[False, True, False, True]
>>> filter_list(is_even, [1, 2, 3, 4])
[2, 4]
lambda
- It can be a bit annoying writing having to write all of these simple functions to simply pass as an argument to another function
- Python allows you to create "anonymous" function, i.e., functions that don't have an explicit name, but are simply code
- The syntax is:
lambda <input>: <expression>
- <input> is the parameter to the function. One restriction: it can only be a single input
- if you need more, just make it a tuple
- <expression> is the body of the function, but it can only be a single expression (i.e., something that represents a value)
- An example:
>>> lambda x: x+1
<function <lambda> at 0x7f7ff80981e0>
- notice that it gives the same "function" type back, but it doesn't have a name!
>>> (lambda x: x+1)(2)
3
- we can call it
>>> f = lambda x: x+1
>>> f(2)
3
- we can also associate it with a variable and call it
- Makes life easier!
>>> filter_list(lambda num: num%2 == 0, [1, 2, 3, 4])
[2, 4]
monte carlo sampling
- monte carlo methods are a way of determining the answer to numerical problems via random sampling
- general idea:
- generate random samples
- look at the outcome of those random samples
- use the answer to the outcomes to estimate the answer
- An example: calculating the area
- we want to calculate the area of a shape, specifically, if I draw an arbitrary shape within a 1 by 1 box, can you tell me the area?
- kind of hard!
- what if I put a bunch of points uniformly in the box and could tell how many were inside the shape?
- e.g., if I put 1000 points in the box with a triangle shape, how many would you expect in the triangle?
- about 500
- what would be the area of the triangle?
- 500/1000 = 0.5
- key idea: use the proportion of points that fall inside the shape to estimate the area
- what are the areas of these two shapes:
- triangle
- quarter circle
- look at in_circle and in_triangle functions in
montecarlo.py code
- what do these functions do?
- write a function monte_carlo that takes two parameters: number of trials and a shape function
- generate "trials" random points (x, y points between 0 and 1)
- count how many are "inside" the shape
- return the proportion, i.e., count/trials
- Hint:
import random
random.random() # returns random value between 0 and 1
- look at monte_carlo function in
montecarlo.py code
- We can use this to estimate the area of different shapes:
>>> monte_carlo(1000, in_triangle)
0.484
>>> monte_carlo(10000, in_triangle)
0.5005
>>> monte_carlo(100000, in_triangle)
0.49756
>>> monte_carlo(100000, in_circle)
0.7854
>>> monte_carlo(100000, in_circle)*4
3.14896
>>> monte_carlo(1000000, in_circle)*4
3.141972
>>> monte_carlo(10000000, in_circle)*4
3.141894