File size: 3,683 Bytes
0437308
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import numpy as np
from pyDOE2.doe_lhs import lhs
import matplotlib.pyplot as plt
import streamlit as st
import mpmath

# Set the precision to 50 decimal places
mpmath.mp.dps = 50

# Compute the value of pi with 50 decimal places of precision
pi = mpmath.pi

st.title("Compute Pi with Monte Carlo")

st.markdown(
    r"""
    We know that area of a circle is $\pi r^2$. If we enclose the circle in a square of side $2r$, then the area of the square is $4r^2$. The ratio of the area of the circle to the area of the square is $\frac{\pi r^2}{4r^2} = \frac{\pi}{4}$. If we randomly sample points in the square, then the ratio of the number of points in the circle to the total number of points is also $\frac{\pi}{4}$.
            """
)


# draw a circle with matplotlib
def draw_the_plot():
    fig, ax = plt.subplots()
    ax.set_aspect("equal")
    # draw a square with matplotlib
    square = plt.Rectangle(
        (-1, -1), 2, 2, facecolor="lightblue", edgecolor="r", linewidth=2
    )
    ax.add_artist(square)
    # add a two sides arrow outside the square to indicate the length of the side
    upper_margin = 1.05
    ax.arrow(
        -1,
        upper_margin,
        2,
        0,
        head_width=0.05,
        color="k",
        length_includes_head=True,
        clip_on=False,
    )
    ax.arrow(
        1,
        upper_margin,
        -2,
        0,
        head_width=0.05,
        color="k",
        length_includes_head=True,
        clip_on=False,
    )
    # annotate the arrow
    ax.annotate(
        "$2r$",
        xy=(0, upper_margin),
        xytext=(0, upper_margin),
        horizontalalignment="center",
        verticalalignment="bottom",
    )
    circle = plt.Circle((0, 0), 1, facecolor="lightgreen", edgecolor="b", linewidth=2)
    ax.add_artist(circle)
    # draw a horizontal arrow from the center to the edge
    ax.arrow(0, 0, 1, 0, head_width=0.05, color="k", length_includes_head=True)
    # annotate the arrow
    ax.annotate(
        "$r$",
        xy=(0.5, 0),
        xytext=(0.5, -0.1),
        horizontalalignment="center",
        verticalalignment="bottom",
    )

    ax.set_xlim(-1.1, 1.1)
    ax.set_ylim(-1.1, 1.1)
    ax.set_xticks([])
    ax.set_yticks([])
    # remove the x and y axis
    ax.spines["left"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["top"].set_visible(False)
    ax.spines["bottom"].set_visible(False)

    return fig, ax


fig, ax = draw_the_plot()
st.pyplot(fig)

st.subheader("Monte Carlo Simulation")

seed = st.number_input("Random seed", min_value=0, max_value=10000000, value=0, step=1)
N = st.number_input(
    "Number of points", min_value=1, max_value=10000000, value=10000, step=1
)
type = st.selectbox("Type of sampling", ["Random", "Grid"])

if type == "Random":
    samples = lhs(2, samples=N, random_state=seed) * 2 - 1
else:
    samples = np.linspace(-1, 1, int(np.sqrt(N)))
    samples = np.array(np.meshgrid(samples, samples)).T.reshape(-1, 2)

# compute the distance of each point from the origin
distances = np.linalg.norm(samples, axis=1)

# compute the number of points inside the circle
inside = samples[distances < 1, :]
print(samples.shape, inside.shape)

st.markdown(
    f"""
    Points inside the circle: = {len(inside)}\n
    Ratio: = {len(inside)} / {len(samples)} = {len(inside) / len(samples)}\n
    $\pi$ = {len(inside) / len(samples)} * 4\n
    | $\pi$ | value |
    | --- | --- |
    | estimated $\pi$ | {len(inside) / len(samples) * 4:.50f} |
    | real $\pi$ | {pi} |
    """
)

fig, ax = draw_the_plot()
ax.scatter(samples[:, 0], samples[:, 1], s=0.1, color="r")
ax.scatter(inside[:, 0], inside[:, 1], s=0.1, color="b")
st.pyplot(fig)