| import numpy as np |
| from pyDOE2.doe_lhs import lhs |
| import matplotlib.pyplot as plt |
| import streamlit as st |
| import mpmath |
|
|
| |
| mpmath.mp.dps = 50 |
|
|
| |
| 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}$. |
| """ |
| ) |
|
|
|
|
| |
| def draw_the_plot(): |
| fig, ax = plt.subplots() |
| ax.set_aspect("equal") |
| |
| square = plt.Rectangle( |
| (-1, -1), 2, 2, facecolor="lightblue", edgecolor="r", linewidth=2 |
| ) |
| ax.add_artist(square) |
| |
| 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, |
| ) |
| |
| 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) |
| |
| ax.arrow(0, 0, 1, 0, head_width=0.05, color="k", length_includes_head=True) |
| |
| 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([]) |
| |
| 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) |
|
|
| |
| distances = np.linalg.norm(samples, axis=1) |
|
|
| |
| 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) |
|
|