<jupyter_start><jupyter_text>Monte Carlo approximation of pi In this session you will be practicing a number of things you've learned over the last two days and seeing how you can combine those seemingly distinct concepts to solve a problem. First let's discuss the problem we intend to solve.Suppose we need to calculate the value of $\pi$ (it's readily available in several libraries, but let's assume for the purposes of this excercise that you need to calculate it anyway). The approach we'll use for this is called a [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method). For those unfamiliar with the term, Monte Carlo methods are a way to approximate values using random numbers which have some particular statistical properties relevant to the problem at hand.This method consists of the following steps:- Consider a unit square (x = [0, 1], y = [0, 1]) containing a quarter of a unit circle ($r = 1$)- Randomly select a point within the square- Determine whether the selected point is within the circle- As you select more points, the ratio of the number of points within the circle to the total number of points will converge towards $\pi / 4$, so     $$    \pi = 4 \frac{\text{number of points in circle}}{\text{total number of points}}    $$![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Pi_30K.gif/220px-Pi_30K.gif)  ChallengeHere in the notebook, write a function that implements the algorithm described above and returns a value for $\pi$If it helps you to conceptualise the problem, loop over the number of points you want to use and do your calculations on each iterationOnce you're happy with that, refactor your function so that it uses numpy operations and considers all the points at once, instead of looping over them<jupyter_code>import numpy as np

tot_num = 1000000 #total number of test points points

def find_y_on_circle(x):
    
        y = np.sqrt(1 - x**2) #circle equation
        return y
    
def est_pi(tot_num):
    """
    This function will estimate pi using the Monte Carlo method in a unit circle.
    """

    inside = 0 
    res = 0 #counter for test points

    while res < tot_num:
        x = np.random.uniform(0,1)
        y = np.random.uniform(0,1)
        if find_y_on_circle(x) >= y: #inside the circle
            inside += 1
        res += 1

    return 4*inside/tot_num #prints pi estimate
print(est_pi(tot_num))<jupyter_output>3.141876<jupyter_text>ChallengeOutside the notebook, in whatever text editor you're most comfortable using, make a Python script containing your $\pi$-calculation function, and save it in the same directory as this notebook. Import that function into the notebook and test it a bit. Make sure it still gives the correct answer and that you're happy using it as an imported function.Write some tests for your function, in a separate test script. Run your tests and make sure that your function is definitely doing what you expect it to be doing.<jupyter_code>import piscript<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0626865671641791, 'fraction_numerical': 0.013930348258706468, 'mean_word_length': 3.9768976897689767, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '626860', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 812, 'n_tokens_neox': 763, 'n_words': 419, 'path': '06-approximating-pi/01-calculating-pi.ipynb', 'repo_name': 'Krimofthecrop/rcsc18_lessons', 'size': '3015'}