pi with monte carlo
Browse files- app.py +126 -0
- requirements.txt +4 -0
app.py
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
from pyDOE2.doe_lhs import lhs
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import streamlit as st
|
5 |
+
import mpmath
|
6 |
+
|
7 |
+
# Set the precision to 50 decimal places
|
8 |
+
mpmath.mp.dps = 50
|
9 |
+
|
10 |
+
# Compute the value of pi with 50 decimal places of precision
|
11 |
+
pi = mpmath.pi
|
12 |
+
|
13 |
+
st.title("Compute Pi with Monte Carlo")
|
14 |
+
|
15 |
+
st.markdown(
|
16 |
+
r"""
|
17 |
+
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}$.
|
18 |
+
"""
|
19 |
+
)
|
20 |
+
|
21 |
+
|
22 |
+
# draw a circle with matplotlib
|
23 |
+
def draw_the_plot():
|
24 |
+
fig, ax = plt.subplots()
|
25 |
+
ax.set_aspect("equal")
|
26 |
+
# draw a square with matplotlib
|
27 |
+
square = plt.Rectangle(
|
28 |
+
(-1, -1), 2, 2, facecolor="lightblue", edgecolor="r", linewidth=2
|
29 |
+
)
|
30 |
+
ax.add_artist(square)
|
31 |
+
# add a two sides arrow outside the square to indicate the length of the side
|
32 |
+
upper_margin = 1.05
|
33 |
+
ax.arrow(
|
34 |
+
-1,
|
35 |
+
upper_margin,
|
36 |
+
2,
|
37 |
+
0,
|
38 |
+
head_width=0.05,
|
39 |
+
color="k",
|
40 |
+
length_includes_head=True,
|
41 |
+
clip_on=False,
|
42 |
+
)
|
43 |
+
ax.arrow(
|
44 |
+
1,
|
45 |
+
upper_margin,
|
46 |
+
-2,
|
47 |
+
0,
|
48 |
+
head_width=0.05,
|
49 |
+
color="k",
|
50 |
+
length_includes_head=True,
|
51 |
+
clip_on=False,
|
52 |
+
)
|
53 |
+
# annotate the arrow
|
54 |
+
ax.annotate(
|
55 |
+
"$2r$",
|
56 |
+
xy=(0, upper_margin),
|
57 |
+
xytext=(0, upper_margin),
|
58 |
+
horizontalalignment="center",
|
59 |
+
verticalalignment="bottom",
|
60 |
+
)
|
61 |
+
circle = plt.Circle((0, 0), 1, facecolor="lightgreen", edgecolor="b", linewidth=2)
|
62 |
+
ax.add_artist(circle)
|
63 |
+
# draw a horizontal arrow from the center to the edge
|
64 |
+
ax.arrow(0, 0, 1, 0, head_width=0.05, color="k", length_includes_head=True)
|
65 |
+
# annotate the arrow
|
66 |
+
ax.annotate(
|
67 |
+
"$r$",
|
68 |
+
xy=(0.5, 0),
|
69 |
+
xytext=(0.5, -0.1),
|
70 |
+
horizontalalignment="center",
|
71 |
+
verticalalignment="bottom",
|
72 |
+
)
|
73 |
+
|
74 |
+
ax.set_xlim(-1.1, 1.1)
|
75 |
+
ax.set_ylim(-1.1, 1.1)
|
76 |
+
ax.set_xticks([])
|
77 |
+
ax.set_yticks([])
|
78 |
+
# remove the x and y axis
|
79 |
+
ax.spines["left"].set_visible(False)
|
80 |
+
ax.spines["right"].set_visible(False)
|
81 |
+
ax.spines["top"].set_visible(False)
|
82 |
+
ax.spines["bottom"].set_visible(False)
|
83 |
+
|
84 |
+
return fig, ax
|
85 |
+
|
86 |
+
|
87 |
+
fig, ax = draw_the_plot()
|
88 |
+
st.pyplot(fig)
|
89 |
+
|
90 |
+
st.subheader("Monte Carlo Simulation")
|
91 |
+
|
92 |
+
seed = st.number_input("Random seed", min_value=0, max_value=10000000, value=0, step=1)
|
93 |
+
N = st.number_input(
|
94 |
+
"Number of points", min_value=1, max_value=10000000, value=10000, step=1
|
95 |
+
)
|
96 |
+
type = st.selectbox("Type of sampling", ["Random", "Grid"])
|
97 |
+
|
98 |
+
if type == "Random":
|
99 |
+
samples = lhs(2, samples=N, random_state=seed) * 2 - 1
|
100 |
+
else:
|
101 |
+
samples = np.linspace(-1, 1, int(np.sqrt(N)))
|
102 |
+
samples = np.array(np.meshgrid(samples, samples)).T.reshape(-1, 2)
|
103 |
+
|
104 |
+
# compute the distance of each point from the origin
|
105 |
+
distances = np.linalg.norm(samples, axis=1)
|
106 |
+
|
107 |
+
# compute the number of points inside the circle
|
108 |
+
inside = samples[distances < 1, :]
|
109 |
+
print(samples.shape, inside.shape)
|
110 |
+
|
111 |
+
st.markdown(
|
112 |
+
f"""
|
113 |
+
Points inside the circle: = {len(inside)}\n
|
114 |
+
Ratio: = {len(inside)} / {len(samples)} = {len(inside) / len(samples)}\n
|
115 |
+
$\pi$ = {len(inside) / len(samples)} * 4\n
|
116 |
+
| $\pi$ | value |
|
117 |
+
| --- | --- |
|
118 |
+
| estimated $\pi$ | {len(inside) / len(samples) * 4:.50f} |
|
119 |
+
| real $\pi$ | {pi} |
|
120 |
+
"""
|
121 |
+
)
|
122 |
+
|
123 |
+
fig, ax = draw_the_plot()
|
124 |
+
ax.scatter(samples[:, 0], samples[:, 1], s=0.1, color="r")
|
125 |
+
ax.scatter(inside[:, 0], inside[:, 1], s=0.1, color="b")
|
126 |
+
st.pyplot(fig)
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
numpy
|
2 |
+
matplotlib
|
3 |
+
mpmath
|
4 |
+
pyDOE2
|