{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"from graphics import GraphWin, Point, Circle, Rectangle, Text\n",
"from random import randrange\n",
"from math import pi, sqrt"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"height, width = 1044, 1044"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def intro():\n",
" s = \"\"\"\n",
" Calculating π using a Monte Carlo method\n",
"\n",
" Source: https://en.wikipedia.org/wiki/Monte_Carlo_method#Introduction\n",
"\n",
" For example, consider a circle inscribed in a unit square. Given that the\n",
" circle and the square have a ratio of areas that is π/4, the value of π can\n",
" be approximated using a Monte Carlo method:\n",
"\n",
" Draw a square on the ground, then inscribe a circle within it. Uniformly\n",
" scatter some objects of uniform size (grains of rice or sand) over the\n",
" square. Count the number of objects inside the circle and the total number\n",
" of objects. The ratio of the two counts is an estimate of the ratio of the\n",
" two areas, which is π/4. Multiply the result by 4 to estimate π.\n",
"\n",
" In this procedure the domain of inputs is the square that circumscribes our\n",
" circle. We generate random inputs by scattering grains over the square then\n",
" perform a computation on each input (test whether it falls within the\n",
" circle). Finally, we aggregate the results to obtain our final result, the\n",
" approximation of π.\n",
"\n",
" There are two important points to consider here: Firstly, if the grains are\n",
" not uniformly distributed, then our approximation will be poor. Secondly,\n",
" there should be a large number of inputs. The approximation is generally\n",
" poor if only a few grains are randomly dropped into the whole square. On\n",
" average, the approximation improves as more grains are dropped.\n",
"\n",
"\n",
" \"\"\"\n",
"\n",
" print(s)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def prepare_window():\n",
" global height, width\n",
"\n",
" # Set our window dimensions and display it.\n",
" win = GraphWin(\"Monte Carlo Calculation of π\", height, height)\n",
"\n",
" # Prepare our circle for drawing.\n",
" center = Point(height/2, width/2)\n",
" unit_circle = Circle(center,\n",
" (height - 20)/2 if height < width else (width - 20)/2)\n",
" unit_circle.setFill(\"red1\")\n",
" unit_circle.setOutline(\"red1\")\n",
"\n",
" p1, p2 = Point((height - 10), 10), Point(10, (width - 10))\n",
" unit_square = Rectangle(p1, p2)\n",
" unit_square.setFill(\"blue\")\n",
" unit_square.setOutline(\"blue\")\n",
"\n",
" # The order of drawing matters, the square first, then the circle.\n",
" # Otherwise, the circle may be obscured.\n",
" unit_square.draw(win)\n",
" unit_circle.draw(win)\n",
"\n",
" return unit_circle, unit_square, win"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def get_input():\n",
" num_points = int(float(input(\"How many points to draw? \")))\n",
" return num_points"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def in_circle(point, circ):\n",
"\n",
" # get the distance between pt1 and circ using the\n",
" # distance formula\n",
" dx = point.getX() - circ.getCenter().getX()\n",
" dy = point.getY() - circ.getCenter().getY()\n",
" dist = sqrt(dx*dx + dy*dy)\n",
"\n",
" # check whether the distance is less than the radius\n",
" return dist <= circ.getRadius()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def calc_pi(points, circle):\n",
" global height, width\n",
" total = len(points)\n",
" total_in_circle = 0\n",
"\n",
" for p in points:\n",
" if in_circle(p, circle):\n",
" total_in_circle += 1\n",
"\n",
" return (total_in_circle/total) * 4"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def scatter(win, circle, n):\n",
" global height, width\n",
" points = []\n",
"\n",
" # White backing for stats\n",
" white_box = Rectangle(Point(10,10), Point(190, 90))\n",
" white_box.setFill(\"white\")\n",
" white_box.draw(win)\n",
" \n",
" # Create Text object to show us current stats.\n",
" status = Text(Point(80, 50), \"\")\n",
" status.setSize(16)\n",
" status.draw(win)\n",
"\n",
" for i in range(n):\n",
" # Random position in side square\n",
" x = randrange(10, width - 10 + 1)\n",
" y = randrange(10, height - 10 + 1)\n",
"\n",
" # Create and save point in a list\n",
" point = Point(x, y)\n",
" points.append(point)\n",
"\n",
" # Set the points properties, including drawing.\n",
" point.setFill(\"white\")\n",
" point.setOutline(\"white\")\n",
" point.draw(win)\n",
"\n",
" # Update the stats text label with new info.\n",
" pi_sim = calc_pi(points, circle)\n",
" status.setText(\"Points drawn: {0}\\n\\\n",
" π = {1:0.6f}\\n\\\n",
" π_sim = {2:0.6f}\\n\\\n",
" diff = {3:0.6f}%\".format(len(points),\n",
" pi,\n",
" pi_sim,\n",
" (1 - (pi_sim/pi))*100))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [],
"source": [
"def main():\n",
" # Print an introduction\n",
" intro()\n",
"\n",
" # Get input from user on how many points to draw.\n",
" n = get_input()\n",
"\n",
" # Prepare our window for simulation\n",
" u_circle, u_square, window = prepare_window()\n",
"\n",
" # Scatter points all over the unit square.\n",
" scatter(window, u_circle, n)\n",
"\n",
" # Get mouse click to exit (useful when run from a command line terminal)\n",
" window.getMouse()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
" Calculating π using a Monte Carlo method\n",
"\n",
" Source: https://en.wikipedia.org/wiki/Monte_Carlo_method#Introduction\n",
"\n",
" For example, consider a circle inscribed in a unit square. Given that the\n",
" circle and the square have a ratio of areas that is π/4, the value of π can\n",
" be approximated using a Monte Carlo method:\n",
"\n",
" Draw a square on the ground, then inscribe a circle within it. Uniformly\n",
" scatter some objects of uniform size (grains of rice or sand) over the\n",
" square. Count the number of objects inside the circle and the total number\n",
" of objects. The ratio of the two counts is an estimate of the ratio of the\n",
" two areas, which is π/4. Multiply the result by 4 to estimate π.\n",
"\n",
" In this procedure the domain of inputs is the square that circumscribes our\n",
" circle. We generate random inputs by scattering grains over the square then\n",
" perform a computation on each input (test whether it falls within the\n",
" circle). Finally, we aggregate the results to obtain our final result, the\n",
" approximation of π.\n",
"\n",
" There are two important points to consider here: Firstly, if the grains are\n",
" not uniformly distributed, then our approximation will be poor. Secondly,\n",
" there should be a large number of inputs. The approximation is generally\n",
" poor if only a few grains are randomly dropped into the whole square. On\n",
" average, the approximation improves as more grains are dropped.\n",
"\n",
"\n",
" \n",
"How many points to draw? 10000\n"
]
},
{
"ename": "GraphicsError",
"evalue": "Can't draw to closed window",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mGraphicsError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m\u001b[0m in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;31m# Scatter points all over the unit square.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mscatter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwindow\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mu_circle\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;31m# Get mouse click to exit (useful when run from a command line terminal)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m\u001b[0m in \u001b[0;36mscatter\u001b[0;34m(win, circle, n)\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0mpoint\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetFill\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"white\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0mpoint\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetOutline\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"white\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 27\u001b[0;31m \u001b[0mpoint\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdraw\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwin\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 28\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;31m# Update the stats text label with new info.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/Library/Python/3.8/lib/python/site-packages/graphics.py\u001b[0m in \u001b[0;36mdraw\u001b[0;34m(self, graphwin)\u001b[0m\n\u001b[1;32m 480\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 481\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcanvas\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcanvas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misClosed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mGraphicsError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mOBJ_ALREADY_DRAWN\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 482\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mgraphwin\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misClosed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mGraphicsError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Can't draw to closed window\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 483\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcanvas\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgraphwin\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 484\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_draw\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgraphwin\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mGraphicsError\u001b[0m: Can't draw to closed window"
]
}
],
"source": [
"main()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.11"
}
},
"nbformat": 4,
"nbformat_minor": 1
}