Lab 2: Thrown for a Loop: Monte Carlo Methods
This labs explores iteration and how it can be used to abstract away repetitive tasks in a clean and consise way. In addition it highlights a monte carlo method for estimating π and, for extra credit, a monte carlo method for estimating e.
Source Code
This week we will use the sanbox method for code deployment and collection. You should find a repository in the williams-cs organization called <git-username>-lab2. This repo is accessible only to you, the instructor, and the teaching assistants. Because of this, you will not need to fork it, only clone it to your local disk.
      Clone your private repo: git clone
      git@github.com:williams-cs/<git-username>-lab2.git
      You can always get the repo address by using the ssh
      copy-to-clipboard link on github.
    
There is no need to use virtualenv or pip this week because we aren't using any external libraries.
Monte Carlo Methods
    Here's a cool way to estimate π:  throw a bunch darts at dartboard with radius 
 
    The dartboard has area π × r2=π and the case has area 4, so if your throws are uniformly distributed inside the case, then the ratio of darts hitting the dart board to the dart case should be π/4. Multiplying this ratio by 4 gives you an estimate of π.
    Use the random
    module (and specifically the
    function random.uniform(a,b)) to simulate the dart
    throwing.
    
      Implement the following functions (hint: calculate_pi
      should call both rand() and distance) and
      test your code with increasing sample sizes (you should see more
      accurate estimates of π)
    
 
    def rand(): 
        """return a number uniformly at random in the range [-1,1]"""
    
     
     def distance(x,y):
	 """return the euclidean distance between (0,0) and (x,y)"""
    
     
     def calculate_pi(n):
	 """
	 Calculate PI by comparing the ratio of points landing
	 in the circle with radius 1 to those landing outside
	 """
    
    
    $ python3 pi.py 10
    2.8
    $ python3 pi.py 100
    3.28
    $ python3 pi.py 1000
    3.232
    $ python3 pi.py 10000
    3.1524
    $ python3 pi.py 100000
    3.13804
    $ python3 pi.py 1000000
    3.14012
    
    Practice Looping
Consider the following python program calledpattern_a.py (it's provided in the source
    code) that accepts an integer argument and produces the following
    output.
    
    pattern_a.py <num>
    
    
    $ python3 pattern_a.py 3
    1 1 1
    2 2 2
    3 3 3
    
    $ python3 pattern_a.py 4
    1 1 1 1
    2 2 2 2
    3 3 3 3
    4 4 4 4
    
    $ python3 pattern_a.py 5
    1 1 1 1 1
    2 2 2 2 2
    3 3 3 3 3
    4 4 4 4 4
    5 5 5 5 5
    
    
    Write four different python programs called pattern_b.py, pattern_c.py, 
    pattern_n.py, and pattern_z.py respectively.
    Each program takes a single positive integer assignment and
    produces the correctly formatted output, examples of which are
    given below.  Remember that you can surpress
    the newline character at the end of the print
    function by using the optional final 
    argument end.  Here is an example: print("some string",end="").
    
Pattern B
    pattern_b.py <num>
          
    produces the following output when called with appropriate integer argument.
    $ python3 pattern_b.py 3
    1 2 3
    2 3
    3 
    $ python3 pattern_b.py 4    
    1 2 3 4
    2 3 4
    3 4
    4
    $ python3 pattern_b.py 5
    
    1 2 3 4 5
    2 3 4 5
    3 4 5 
    4 5
    5
    
    Pattern C
    pattern_c.py <num>
          
    produces the following output when called with appropriate integer argument.
    $ python3 pattern_c.py 3
    1 
    1 2 2 
    1 2 2 3 3 3
    $ python3 pattern_c.py 4
    
    1 
    1 2 2 
    1 2 2 3 3 3
    1 2 2 3 3 3 4 4 4 4
    $ python3 pattern_c.py 5
    
    1 
    1 2 2 
    1 2 2 3 3 3
    1 2 2 3 3 3 4 4 4 4
    1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
    
    Pattern N
    pattern_n.py <num>
          
    produces the following output when called with appropriate integer argument.
    $ python3 pattern_n.py 2
    *  *
    ** *
    * **
    *  *
    
    $ python3 pattern_n.py 3
    *   *
    **  *
    * * *
    *  **
    *   *
    $ python3 pattern_n.py 4    
    *    *
    **   *
    * *  *
    *  * *
    *   **
    *    *
    
    Pattern Z
    pattern_z.py <num>
          
    produces the following output when called with appropriate integer argument.
    $ python3 pattern_z.py 2
    ****
      *
     *
    ****
 
    $ python3 pattern_z.py 3
    *****
       *
      *
     *
    *****
    $ python3 pattern_z.py 4
    ******
        *
       *
      *
     *
    ******
    
    Extra-Credit: Estimating e
      The mathematical constant e
      plays a pivotal role in
      mathematics.  It is approximately
      2.718.  One way to approximate the
      number is to use computer-intensive
      monte carlo methods, like we did
      with estimating π.  Here's how,
      imagine you have an infinite list
      of random numbers 
      The file e.py contains headers for two
      functions estimate and sample.
      Implement these functions.
    
 
     import random
     import sys
     
     def estimate():
        """
        One estimate of the constant 'e' involves generaing an infinite sequence
        of random numbers in the range (0,1). Call these values X1, X2, X3, ...
        The smallest value n such that the sum of X1 + X2 + ... + Xn > 1 gives
        an estimate for 'e'.  This function returns one such estimate.  In other
        words, it repeatedly generates numbers in the range (0,1), adding them to
        a total, and returns the number of iterations after which the total first 
        exceeds 1"""
     def sample(n):
        """
        Return the average estimate() value over n samples.
        As n increases, this gives an increasingly more accurate estimate
        of the constant 'e'"""
     print(sample(int(sys.argv[1])))
     
    
      $ python3 e.py 10
      2.8
      $ python3 e.py 100
      2.6
      $ python3 e.py 1000
      2.704
      $ python3 e.py 10000
      2.7244
      $ python3 e.py 100000
      2.72335
      $ python3 e.py 1000000
      2.718798
      $ python3 e.py 10000000
      2.7180784
    
    Submission
- When you cloned your private repo locally, it contained the following four files:
	  - README.md
- e.py
- pattern_a.py
- pi.py
 
- Begin by adding your new files to the repo index: 
	  $ git add pattern_b.py pattern_c.py pattern_n.py pattern_z.py
- Now commit those additions to the repository: $ git commit -a -m "some log message"
- Finally, push your changes back to github repo: $ git push
- With the sandbox method, there is not need to issue a pull request. This is because you started with your own private repo---no fork means no pull request
Credit
The looping problems come from Tom Wexler and the dartboard example for the monte carlo problem for estimating π comes from Alexa Sharp