{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "sampling.ipynb\n", "\n", "Discussion: This Jupyter notebook investigates sampling squares, triangles, polygons and circles\n", "\n", "Licensing: This code is distributed under the GNU LGPL license.\n", " \n", "Modified: 23 October 2016\n", "\n", "Author: John Burkardt, Lukas Bystricky" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using matplotlib backend: agg\n" ] } ], "source": [ "# Import necessary libraries and set plot option\n", "%matplotlib \n", "%config InlineBackend.figure_format = 'svg'\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import math\n", "import scipy.spatial as spatial" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sampling\n", "\n", "In this module we will investigate sampling various geometric regions.\n", "\n", "We will concentrate on 2D regions, starting with the easiest case and working \n", "our way up.\n", "\n", "Sampling a geometric region allows us to make estimates of geometric\n", "quantities for which an exact calculation might be difficult.\n", "\n", "For our Voronoi project, the calculations we are interested in are\n", "the area, centroid, and \"energy\" of each of the Voronoi subregions." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " I G[I] Left[I] Right[I] Centroid[I] Length[I] Energy[I]\n", " 0 0.200000 0.000000 0.300000 0.143759 0.307000 0.003462\n", " 1 0.400000 0.300000 0.500000 0.396705 0.188000 0.000614\n", " 2 0.600000 0.500000 0.700000 0.600319 0.197000 0.000558\n", " 3 0.800000 0.700000 1.000000 0.855896 0.308000 0.003313\n" ] } ], "source": [ "# Estimating Information in a 1D interval\n", "#\n", "# As in the voronoi notebook, consider 4 generator points in the interval [0,1].\n", "#\n", "# If we can generate n uniform random samples of the interval, and neari is the number of\n", "# those samples xj closest to generator gi, and l is the length of our region, then:\n", "#\n", "# estimated length of subregion i: li = l * ( neari / n )\n", "# estimated centroid: ci = sum ( xj ) / neari\n", "# estimated energy: ei = li * sum ( xj - gi )**2 / neari\n", "#\n", "# We do these estimates n= 1000.\n", "#\n", "g = np.array ( [ 1.0/5.0, 2.0/5.0, 3.0/5.0, 4.0/5.0] )\n", "\n", "right = np.zeros ( 4 )\n", "left = np.zeros ( 4 )\n", "for i in range ( 0, 4 ):\n", " if ( i == 0 ):\n", " left[i] = 0.0\n", " else:\n", " left[i] = ( g[i-1] + g[i] ) / 2.0\n", " if ( i < 3 ):\n", " right[i] = ( g[i] + g[i+1] ) / 2.0\n", " else:\n", " right[i] = 1.0\n", " \n", "n = 1000\n", "x = np.random.random ( n )\n", "\n", "centroid = np.zeros ( 4 )\n", "length = np.zeros ( 4 )\n", "energy = np.zeros ( 4 )\n", "near = np.zeros ( 4 )\n", "\n", "for j in range ( 0, n ):\n", " i = ( np.abs ( g - x[j] ) ).argmin ( )\n", " near[i] = near[i] + 1\n", " centroid[i] = centroid[i] + x[j]\n", " energy[i] = energy[i] + ( g[i] - x[j] ) ** 2\n", "\n", "for i in range ( 0, 4 ):\n", " length[i] = 1.0 * float ( near[i] ) / float ( n )\n", " centroid[i] = centroid[i] / float ( near[i] )\n", " energy[i] = length[i] * energy[i] / float ( near[i] )\n", "# \n", "# Print i, g[i], left[i], right[i], centroid[i], length[i], energy[i]\n", "#\n", "print ( '' )\n", "print ( ' I G[I] Left[I] Right[I] Centroid[I] Length[I] Energy[I]' )\n", "for i in range ( 0, 4 ):\n", " print ( '%2d %14.6f %14.6f %14.6f %14.6f %14.6f %14.6f' \\\n", " % ( i, g[i], left[i], right[i], centroid[i], length[i], energy[i] ) )" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " I G[I,0] G[I,1] Centroid[I,0] Centroid[I,1] Area[I] Energy[I]\n", " 0 0.200000 0.200000 0.152912 0.150355 0.088200 0.001749\n", " 1 0.400000 0.200000 0.400769 0.146156 0.061300 0.000858\n", " 2 0.600000 0.200000 0.599287 0.157362 0.058600 0.000753\n", " 3 0.800000 0.200000 0.850003 0.146927 0.086800 0.001759\n", " 4 0.200000 0.400000 0.157440 0.396774 0.062000 0.000761\n", " 5 0.400000 0.400000 0.399457 0.403016 0.039200 0.000256\n", " 6 0.600000 0.400000 0.599368 0.403641 0.044100 0.000293\n", " 7 0.800000 0.400000 0.851058 0.402232 0.057000 0.000757\n", " 8 0.200000 0.600000 0.149949 0.596359 0.056700 0.000786\n", " 9 0.400000 0.600000 0.402168 0.604616 0.039100 0.000252\n", "10 0.600000 0.600000 0.596494 0.600649 0.041400 0.000285\n", "11 0.800000 0.600000 0.848929 0.598082 0.059700 0.000765\n", "12 0.200000 0.800000 0.152368 0.852970 0.091000 0.001802\n", "13 0.400000 0.800000 0.401451 0.850852 0.061600 0.000841\n", "14 0.600000 0.800000 0.601293 0.849003 0.065600 0.000883\n", "15 0.800000 0.800000 0.852675 0.850888 0.087700 0.001762\n" ] } ], "source": [ "## Approximate 2D Voronoi diagrams by sampling\n", "#\n", "# As in the Voronoi notebook, let's consider a region which is the unit square,\n", "# and use 16 generators, simply a tensor product (or \"mesh grid\") of our\n", "# original set of 1D values. (It takes a little bit of trouble to take the\n", "# 2 (4,4) arrays output from meshgrid and pack them into a single (16,2) \n", "# array as \n", "#\n", "# In the unit square, it is easy to compute n uniform random samples.\n", "# We call np.random.rand ( n, 2 )\n", "#\n", "g = np.array ( [ 1.0/5.0, 2.0/5.0, 3.0/5.0, 4.0/5.0] )\n", "\n", "GX, GY = np.meshgrid ( g, g )\n", "G = np.zeros ( [ 16, 2 ] )\n", "G[:,0] = np.ndarray.flatten ( GX )\n", "G[:,1] = np.ndarray.flatten ( GY )\n", "\n", "centroid = np.zeros ( [ 16, 2 ] )\n", "area = np.zeros ( 16 )\n", "energy = np.zeros ( 16 )\n", "near = np.zeros ( 16 )\n", "\n", "n = 10000\n", "XY = np.random.rand ( n, 2 )\n", "\n", "def nearest ( G, xy ):\n", " idx = -1\n", " dmin = np.Inf\n", " for i in range ( 0, 16 ):\n", " d = np.linalg.norm ( G[i,:] - xy[:] ) \n", " if ( d < dmin ):\n", " idx = i\n", " dmin = d\n", " return idx \n", "\n", "for j in range ( 0, n ):\n", " i = nearest ( G, XY[j,:] )\n", " near[i] = near[i] + 1\n", " centroid[i,:] = centroid[i,:] + XY[j,:]\n", " energy[i] = energy[i] + ( G[i,0] - XY[j,0] ) ** 2 + ( G[i,1] - XY[j,1] ) ** 2\n", " \n", "for i in range ( 0, 16 ):\n", " area[i] = 1.0 * float ( near[i] ) / float ( n )\n", " centroid[i,:] = centroid[i,:] / float ( near[i] )\n", " energy[i] = area[i] * energy[i] / float ( near[i] )\n", "# \n", "# Print i, g[i], centroid[i,:], area[i], energy[i]\n", "#\n", "print ( '' )\n", "print ( ' I G[I,0] G[I,1] Centroid[I,0] Centroid[I,1] Area[I] Energy[I]' )\n", "for i in range ( 0, 16 ):\n", " print ( '%2d %14.6f %14.6f %14.6f %14.6f %14.6f %14.6f' \\\n", " % ( i, G[i,0], G[i,1], centroid[i,0], centroid[i,1], area[i], energy[i] ) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sampling General Rectangles; Cubes; Hypercubes #\n", "\n", "In our example, the x and y coordinates of our region ran from 0 to 1.\n", "Therefore, we felt comfortable with calling the random number generator\n", "to return random numbers r1 and r2 to create a random point (r1,r2) \n", "in the square.\n", "\n", "Suppose our region is not the unit square, but instead, some rectangular\n", "region, with sides still parallel to the coordinate axes, such as:\n", " (X1,Y2)-----(X2,Y2)\n", " | |\n", " (X1,Y2)-----(X2,Y1)\n", "It turns out that we just need a linear transformation so that r1\n", "becomes a number between X1 and X2, while r2 is between Y1 and Y2:\n", " s1 = X1 + (X2-X1)*r1\n", " s2 = Y1 + (Y2-Y1)*r2\n", " \n", "What happens in 3D, if our region is a 3D block with sides parallel to\n", "coordinate axes, and extents (X1,X2), (Y1,Y2) and (Z1,Z2)? We just add\n", " s3 = Z1 + (Z2-Z1)*r3.\n", "\n", "It should be obvious that we can slso do this for a rectangular hypercube\n", "in any higher dimension." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Uniform sampling in a triangle #\n", "\n", "To generate uniform random values in a triangle with vertices (A,B,C) \n", "we have to get two random numbers and then modify the second one:\n", " \n", "r1 =random\n", "r2 = sqrt ( random )\n", "\n", "Now we can compute our blending coefficients:\n", " \n", "i = 1 - r2\n", "j = ( 1 - r1 ) * r2\n", "k = r1 * r2\n", "\n", "And compute a sample point:\n", " \n", "s = ( i * a + j * b + k * c )\n" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " I G[I,0] G[I,1] Centroid[I,0] Centroid[I,1] Area[I] Energy[I]\n", " 0 2.000000 2.000000 1.528826 1.647866 0.414000 0.394782\n", " 1 3.000000 1.000000 2.935244 0.823659 0.305000 0.146931\n", " 2 3.000000 2.000000 3.020501 1.974266 0.133000 0.023667\n", " 3 3.000000 3.000000 2.753789 3.077630 0.148000 0.042581\n" ] }, { "data": { "text/plain": [ "[]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Let our triangle have the vertices (4,0), (3,4) and (0,1)\n", "#\n", "# Consider 4 generator points (2,2), (3,1), (3,2), (3,3)\n", "#\n", "# Using n=1000 samples, estimate the area, centroid, and energy of each subregion.\n", "#\n", "a = np.array ( [4,0] )\n", "b = np.array ( [3,4] )\n", "c = np.array ( [0,1] )\n", "\n", "g = np.array ( [ [ 2,2], [3,1], [3,2], [3,3] ] )\n", "\n", "triangle_area = 0.5 * ( a[0] * ( b[1] - c[1] ) + b[0] * ( c[1] - a[1] ) + c[0] * ( a[1] - b[1] ) )\n", "\n", "\n", "\n", "area = np.zeros ( 4 )\n", "centroid = np.zeros ( [4,2] )\n", "energy = np.zeros ( 4 )\n", "near = np.zeros ( 4 )\n", "\n", "for l in range ( 0, 1000 ):\n", " r1 = np.random.random ( )\n", " r2 = np.sqrt ( np.random.random ( ) )\n", " i = 1 - r2\n", " j = ( 1 - r1 ) * r2\n", " k = r1 * r2\n", " s = ( i * a + j * b + k * c )\n", "\n", "def nearest ( G, s ):\n", " idx = -1\n", " dmin = np.Inf\n", " for i in range ( 0, 4 ):\n", " d = np.linalg.norm ( g[i,:] - s[:] ) \n", " if ( d < dmin ):\n", " idx = i\n", " dmin = d\n", " return idx \n", "\n", "n = 1000\n", "\n", "for l in range ( 0, n ):\n", " \n", " r1 = np.random.random ( )\n", " r2 = np.sqrt ( np.random.random ( ) )\n", " i = 1 - r2\n", " j = ( 1 - r1 ) * r2\n", " k = r1 * r2\n", " s = ( i * a + j * b + k * c )\n", "\n", " i = nearest ( g, s )\n", " near[i] = near[i] + 1\n", " centroid[i,:] = centroid[i,:] + s[:]\n", " energy[i] = energy[i] + ( g[i,0] - s[0] ) ** 2 + ( g[i,1] - s[1] ) ** 2\n", "\n", "for i in range ( 0, 4 ):\n", " area[i] = 1.0 * float ( near[i] ) / float ( n )\n", " centroid[i,:] = centroid[i,:] / float ( near[i] )\n", " energy[i] = area[i] * energy[i] / float ( near[i] )\n", "# \n", "# Print i, g[i], centroid[i,:], area[i], energy[i]\n", "#\n", "print ( '' )\n", "print ( ' I G[I,0] G[I,1] Centroid[I,0] Centroid[I,1] Area[I] Energy[I]' )\n", "for i in range ( 0, 4 ):\n", " print ( '%2d %14.6f %14.6f %14.6f %14.6f %14.6f %14.6f' \\\n", " % ( i, g[i,0], g[i,1], centroid[i,0], centroid[i,1], area[i], energy[i] ) )\n", "#\n", "# Plot the triangle (blue lines), the generators (red dots)\n", "# and the centroids (black dots). \n", "#\n", "# Do the estimated positions of the centroids seem reasonable?\n", "#\n", "plt.plot ( [ a[0], b[0], c[0], a[0] ], [ a[1], b[1], c[1], a[1] ], 'b-' )\n", "plt.plot ( g[:,0], g[:,1], 'ro' )\n", "plt.plot ( centroid[:,0], centroid[:,1], 'k.' )\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Uniform sampling of a line divided into unequal lengths #\n", "\n", "Before we can consider uniform sampling of polygons, it will be helpful\n", "to consider how to handle the following problem:\n", " \n", "Suppose a line is divided up into N intervals I1, I2, ..., IN of \n", "lengths L1, L2, ..., LN. Then consider the partial sums of the\n", "lengths, S0 = 0, S1 = S0 + L1, S2 = S1 + L2, ..., SN = SN-1+LN.\n", "\n", "Normalize by dividing by SN: P0 = 0, P1 = S1/SN, P2 = S2/SN, ..., PN=SN/SN=1.\n", " \n", "One way to sample the line is to choose an interval and then choose a\n", "point in the interval. If the intervals are of different lengths,\n", "then we need to choose longer intervals more often, and in proportion\n", "to their lengths. To do that, choose a random number r1 between 0 and 1, and then \n", " choose I1 if S0 <= r1 < S1\n", " I2 if S1 <= r1 < S2\n", " ...\n", " IN if SN-1 <= r1 <= SN \n", "Once we have decided on the interval uniformly, we then have to pick a \n", "point inside the interval uniformly. But that just means that if we\n", "have decided to sample interval I7, we need a random value r2\n", "which we then have to linearly transform between S6 and S7.\n", " s = S6 + (S7-S6)*r2 = S6 + L7 * r2." ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[5 1 4]\n", "[ 0. 5. 6. 10.]\n", "[ 0. 0.5 0.6 1. ]\n", "[ 503. 115. 382.]\n" ] } ], "source": [ "# Uniform sampling of a line divided into unequal lengths\n", "#\n", "# Consider the line segment from 10 to 20, divided into the \n", "# subintervals [10,15], [15,16], [16,20].\n", "#\n", "# If we choose 100 points uniformly, we expect about 50 to be in\n", "# the first segment, about 10 in the second, and about 40 in the third.\n", "#\n", "# Put together a code to compute 1000 sample points from this line segment,\n", "# using the two step process in which you first choose which subinterval\n", "# to sample, and then choose a point in that subinterval.\n", "#\n", "# Normally, we'd be interested in the final X values, but for this example,\n", "# we mainly want to show that we can sample uniformly from unevenly sized\n", "# intervals if we know how big they are.\n", "#\n", "l = np.array ( [ 5, 1, 4 ] )\n", "print ( l )\n", "\n", "s = np.zeros ( 4 )\n", "for i in range ( 1, 4 ):\n", " s[i] = s[i-1] + l[i-1]\n", "print ( s )\n", "\n", "p = np.zeros ( 4 )\n", "p = s / s[3]\n", "print ( p )\n", "\n", "count = np.zeros ( 3 )\n", "n = 1000\n", "for j in range ( 0, n ):\n", " r1 = np.random.random ( )\n", " for i in range ( 1, 4 ):\n", " if ( r1 <= p[i] ):\n", " interval = i - 1\n", " break\n", " r2 = np.random.random ( )\n", " x = s[interval] + l[interval] * r2\n", " count[interval] = count[interval] + 1\n", "#\n", "# Print count to verify roughly 500 / 100 / 400 split in interval choice.\n", "#\n", "print ( count )\n", " " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Uniform sampling of a polygon #\n", "\n", "Suppose our region is a polygon. As discussed in the polygon notebook,\n", "any polygon can be represented as a collection of triangles.\n", "\n", "Therefore, if we wish to sample uniformly from a polygon P, we could \n", "use a two step process:\n", "* decide which triangle Ti to sample;\n", "* decide which point xj in Ti to sample.\n", "\n", "We know how to choose x in T uniformly, because T is a triangle\n", "and we did that in the triangle notebook.\n", "\n", "So how do we do step 1 so that the process is uniform?\n", "All we have to do is choose triangles with a frequency proportional\n", "to their area, since that \"counts\" how many points are in that triangle.\n", "But that is the same as the problem of sampling unequal line segments uniformly.\n", "\n", "In other words, we prepare for step 1 by computing the area Ai \n", "of each triangle Ti, creating an increasing sequence of numbers P \n", "which are spaced proportionally to the triangle areas, select a random\n", "number r1, and use that to select triangle Ti." ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0.33333333 1. ]\n", "\n", " IT Hits Area CentroidX CentroidY\n", "\n", " 0 342 0.513000 0.359181 0.329075\n", " 1 658 0.987000 1.011538 0.672720\n" ] } ], "source": [ "# Uniform sampling of a polygon #\n", "#\n", "# We'll use a simple quadrilateral made up of two triangles, \n", "# one having twice the area of the other.\n", "#\n", "# 1 (3)---*---(2)\n", "# | | \\ T1 / \n", "# Y | \\ /\n", "# | |T0 \\ /\n", "# 0 (0)--(1)\n", "# \n", "# 0----1-----2---X\n", "#\n", "# Prepare:\n", "#\n", "# Define a list XY of 4 point coordinates.\n", "# Define the polygon P as two triangles, that is, 2 rows of 3 indices into XY.\n", "# Compute the areas of T0, T1 and P.\n", "# Compute the array of S values.\n", "#\n", "# Sample:\n", "#\n", "# Compute 1000 random samples of the polygon.\n", "# Estimate the area and centroid of each triangle.\n", "# (We can't compute the energy, because we didn't \n", "# pick generator points in each triangle)\n", "#\n", "xy = np.array ( [ [0.0,0.0], [1.0,0.0], [2.0,1.0], [0.0,1.0] ] )\n", "\n", "p = np.array ( [ [ 0, 1, 3 ], [ 1, 2, 3 ] ] )\n", "\n", "a0 = 0.5 * ( xy[p[0,0],0] * ( xy[p[0,1],1] - xy[p[0,2],1])\\\n", " + xy[p[0,1],0] * ( xy[p[0,2],1] - xy[p[0,0],1])\\\n", " + xy[p[0,2],0] * ( xy[p[0,0],1] - xy[p[0,1],1]) )\n", " \n", "a1 = 0.5 * ( xy[p[1,0],0] * ( xy[p[1,1],1] - xy[p[1,2],1])\\\n", " + xy[p[1,1],0] * ( xy[p[1,2],1] - xy[p[1,0],1])\\\n", " + xy[p[1,2],0] * ( xy[p[1,0],1] - xy[p[1,1],1]) )\n", "\n", "ap = a0 + a1\n", "\n", "s = np.array ( [ a0 / ( a0 + a1 ), ( a0 + a1 ) / ( a0 + a1 ) ] )\n", "\n", "hit = np.zeros ( 2 )\n", "centroid = np.zeros ( [ 2, 2 ] )\n", "\n", "n = 1000\n", "\n", "for j in range ( 0, n ):\n", "#\n", "# Select triangle IT.\n", "#\n", " r0 = np.random.random ( )\n", " if ( r0 < s[0] ):\n", " it = 0\n", " else:\n", " it = 1\n", " \n", " hit[it] = hit[it] + 1\n", "#\n", "# Select point S in triangle IT.\n", "#\n", " r1 = np.random.random ( )\n", " r2 = np.sqrt ( np.random.random ( ) )\n", "\n", " i = 1 - r2\n", " j = ( 1 - r1 ) * r2\n", " k = r1 * r2\n", " sample = i * xy[p[it,0],:] + j * xy[p[it,1],:] + k * xy[p[it,2],:]\n", " \n", " centroid[it,:] = centroid[it,:] + sample\n", "\n", "print ( '' )\n", "print ( ' IT Hits Area CentroidX CentroidY' )\n", "print ( '' )\n", "for it in range ( 0, 2 ):\n", " centroid[it,:] = centroid[it,:] / float ( hit[it] )\n", " area_est = ap * float ( hit[it] )/ float ( n )\n", " print ( ' %2d %4d %14.6f %14.6f %14.6f' % ( it, hit[it], area_est, centroid[it,0], centroid[it,1] ) )\n", "#\n", "# The correct areas are 0.5 and 1.0\n", "#" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Uniform Sampling of a Circle #\n", "\n", "Another region we often want to sample is a circle.\n", "\n", "One way to sample from a circle is to sample from the square that surrounds\n", "the circle, and discard points that are not actually in the circle. This \n", "means that sometimes you have to try more than once just to get a single\n", "acceptable point.\n", "\n", "Another way is more direct. Here we sample the unit circle (center (0,0), radius 1):\n", "\n", "r1 = random number\n", "r2 = random number\n", "\n", "r = sqrt ( r1 )\n", "t = 2.0 * pi * r2\n", "\n", "x = r * cos ( t )\n", "y = r * sin ( t )" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0 5062 0.000000 -0.500000 1.590274 -0.005251 -0.425194 0.517778\n", " 1 3649 0.000000 0.500000 1.146367 0.006751 0.302887 0.415091\n", " 2 1289 0.000000 0.750000 0.404951 0.013395 0.780412 0.054550\n" ] } ], "source": [ "# Uniform sampling of a circle\n", "#\n", "# So we will work with the unit circle.\n", "#\n", "# We will do an approximate Voronoi analysis for the generator points\n", "# g = { [0,-0.5], [0,0.5], [0.0,0.75] }\n", "# If you plot these points, you can see the the Voronoi \"polygon\" for the\n", "# first point will be the lower half of the circle, while the second point\n", "# will have more area associated with it than the third point will.\n", "#\n", "# We will sample with 1000 points and estimate the area, centroids, and energy.\n", "#\n", "g = np.array ( [ [0.0,-0.5], [0.0, 0.5], [0.0,0.75] ] )\n", "\n", "hits = np.zeros ( 3 )\n", "area = np.zeros ( 3 )\n", "centroid = np.zeros ( [ 3, 2 ] )\n", "energy = np.zeros ( 3 )\n", "area_circle = np.pi\n", " \n", "n = 10000\n", " \n", "for j in range ( 0, n ):\n", " r1 = np.random.random ( )\n", " r2 = np.random.random ( )\n", " r = np.sqrt ( r1 )\n", " t = 2.0 * np.pi * r2\n", " xy = np.array ( [ r * np.cos ( t ), r * np.sin ( t ) ] )\n", " nearest = -1\n", " dist = np.Inf\n", " for i in range ( 0, 3 ):\n", " d = np.linalg.norm ( xy - g[i,:])\n", " if ( d < dist ):\n", " nearest = i\n", " dist = d\n", " hits[nearest] = hits[nearest] + 1\n", " centroid[nearest,:] = centroid[nearest,:] + xy[:]\n", " energy[nearest] = energy[nearest] + ( xy[0] - g[nearest,0] )**2 + ( xy[1] - g[nearest,1] )**2\n", " \n", "for i in range ( 0, 3 ):\n", " centroid[i,:] = centroid[i,:] / float ( hits[i] )\n", " area[i] = area_circle * float ( hits[i] ) / float ( n )\n", " energy[i] = area[i] * energy[i] / float ( hits[i] ) \n", "\n", "for i in range ( 0, 3 ):\n", " print ( '%2d %3d %14.6f %14.6f %14.6f %14.6f %14.6f %14.6f' \\\n", " % ( i, hits[i], g[i,0], g[i,1], area[i], centroid[i,0], centroid[i,1], energy[i] ))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.8" } }, "nbformat": 4, "nbformat_minor": 0 }