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