Pi / app.py
Zeel's picture
pi with monte carlo
0437308
raw
history blame contribute delete
No virus
3.68 kB
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)