The below code generates set of random x,y coordinates and uses the equation of an ellipse to compare how many of those points lie inside ellipse centered at (1,1) and a rectangle of area 2a*2b constructed around the ellipse whose semimajor and semiminor axis are a and b but b is variable and takes a value from the list b every single time. I want to have all the values of b for which the ratio of all the points lying inside the ellipse to the points lying inside the rectangle is greater than 0.5.
The problem I'm facing is If I check for a single value of b = 0.63. the condition ellipse_points/rectangle_points is approximately equal to 0.5 but when I loop throught the list b and use the If statement to get all the points for which ellipse_points/rectangle_points > 0.5, I do not see any value close to 0.63 instead I see values from 1.2 till 1.9, I do not understand why when I loop through a list of values for b the if statement seems to give faulty values. please refer to the next set of code where I set value of b = 0.63 and find ratio ellipse_points/rectangle_points
import numpy as np
x = np.random.uniform(0, 2, 10000) #generates random x coordinates
y = np.random.uniform(0, 2, 10000) #generates random y coordinates
ellipse_points, rectangle_points = 0, 0
a = 1
b = []
for i in range(1, 200):
b.append(i/100)
#print(b)
for p in b:
for i, j in zip(x, y):
if (((i - 1) ** 2) / a ** 2 + ((j - 1) ** 2) / p ** 2) < 1:
ellipse_points += 1
rectangle_points += 1
if ellipse_points/rectangle_point > 0.5:
print(p)
OUTPUT: 1.2, 1.21.............1.9
#
x = np.random.uniform(0, 2, 10000) #generates random x coordinates
y = np.random.uniform(0, 2, 10000) #generates random y coordinates
ellipse_points, rectangle_points = 0, 0
a = 1
b = 0.63
for i, j in zip(x, y):
if (((i - 1) ** 2) / a ** 2 + ((j - 1) ** 2) / b ** 2) < 1:
ellipse_points += 1
rectangle_points += 1
print(ellipse_points/rectangle_points)
OUTPUT 0.5001
If I understood your problem correctly, here's a vectorized solution.
It creates a binary mask for points inside the ellipse, counts where the mask is True and divides it by the total number of points.
# np.random.seed(42)
N = 10000
x = np.random.uniform(0, 2, N) #generates random x coordinates
y = np.random.uniform(0, 2, N) #generates random y coordinates
a = 1
b = 0.63
ratio = ((((x - 1)/a)**2 + ((y - 1)/b)**2) < 1).sum()/N
>>> print(ratio)
0.4954
Related
#Program that will load 2 arrays. ELements of the first array are coordinates X. and#the elements of the second array are coordinates Y of a point on a plane.# find the point and print the index of coordinates of the point which is the closest to the#starting point, coordinate 0,0.
import math
i = 0
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min = math.sqrt(X[0])**2 + math.sqrt(Y[0])**2
while i < len(X):
U = math.sqrt(X[i])**2 + math.sqrt(Y[i])**2
if U < min:
min = U
else:
min = min
i = i + 1
mindex = X.index(min)
print(min)
print(mindex)
so basically the coordinates should be 1,1 since that is the shortest distance from the nul-point with the distance D = 2.But how do I also print the index of that element 1. With the index being 7
Edit: in python
Here you go:
import math
X = [3, 32, 15, 43, 5, 22, 90, 1]
Y = [3, 32, 15, 43, 5, 22, 90, 1]
# calculate distances using list comprehension
distances = [math.sqrt(x) ** 2 + math.sqrt(y) ** 2 for x, y in zip(X, Y)]
# find minimal distance
min_distance = min(distances)
# find index of minimal index
min_distance_index = distances.index(min_distance)
print(min_distance, min_distance_index) # Output: 2.0 7
Just a heads up, you got the wrong formula for euclidean distance. Your formula comes down to x + y if they're both positive, otherwise you get an error. The actual formula is math.sqrt(x ** 2 + y ** 2)
From the phrasing of your question it sounds like you only want to print the index, in which case the following is enough
import math
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min_index = min(range(len(X)), key=lambda i: math.sqrt(X[i] ** 2 + Y[i] ** 2))
print(min_index)
Super easy, barely an inconvenience.
>>> min(range(len(X)), key=lambda i: X[i] + Y[i])
7
(No idea what you think squaring square roots achieves, so I removed that.)
check this:
import math
i = 0
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min = math.sqrt(X[0])**2 + math.sqrt(Y[0])**2
idx = 0
while i < len(X):
U = math.sqrt(X[i])**2 + math.sqrt(Y[i])**2
if U < min:
min = U
idx = i
i = i + 1
print(min)
print(idx)
I'm trying to make a function that generates a 2D dataset. The steps I want the code to do are as such:
Make a list of 100 lists, with coordinates and class 0 (for uninitialised) in each list
Generate n random coordinates and set their classes, update list
Calculate distance between points with class 0 and points with assigned classes. Take sum of 1/distance to points with class 1, sum of 1/distance to points with class 2... etc and the class of that point will be the class that has the largest sum
However, the code below does not work, when the list points is printed, almost all the points still have class 0.
import random
def dataset_maker(n): # 2D plane with 0 through 9 for x and y axis
points = []
for i in range(0,10):
for j in range(0,10):
points.append([i, j, "0"]) # 0 = class not initialised, 1 = class 1, 2 = class 2 etc
centriods = []
for i in range(n):
centriods.append((random.randint(0,9), random.randint(0,9)))
for i in range(0,len(points)):
for j in range(0,len(centriods)):
if points[i][0] == centriods[j][0] and points[i][1] == centriods[j][1]:
points[i][2] = str(j+1)
# All neighbours NN to determine classes of other points
distances = [0] * n
for i in range(0,len(points)):
if points[i][2] == "0":
for j in range(0,len(points)):
if points[j][2] != "0":
if((points[i][0] - points[j][0]) ** 2 + (points[i][1] - points[j][1]) ** 2) != 0: # prevent division of 0
tmp = 1 / ((points[i][0] - points[j][0]) ** 2 + (points[i][1] - points[j][1]) ** 2)
tmp2 = int(points[j][2]) - 1
distances[tmp2] += tmp
tmp3 = distances[0]
for i in range(0,len(distances)):
if distances[i] > tmp3:
tmp3 = distances[i]
points[i][2] = str(distances.index(tmp3) + 1)
distances = [0] * n
print(points)
dataset_maker(5)
I am new in Python and I have a sphere of radius (R) and centred at (x0,y0,z0). Now, I need to find those points which are either on the surface of the sphere or inside the sphere e.g. points (x1,y1,z1) which satisfy ((x1-x0)**2+(y1-y0)**2+(z1-x0)*82)**1/2 <= R. I would like to print only those point's coordinates in a form of numpy array. Output would be something like this-[[x11,y11,z11],[x12,y12,z12],...]. I have the following code so far-
import numpy as np
import math
def create_points_around_atom(number,atom_coordinates):
n= number
x0 = atom_coordinates[0]
y0 = atom_coordinates[1]
z0 = atom_coordinates[2]
R = 1.2
for i in range(n):
phi = np.random.uniform(0,2*np.pi,size=(n,))
costheta = np.random.uniform(-1,1,size=(n,))
u = np.random.uniform(0,1,size=(n,))
theta = np.arccos(costheta)
r = R * np.cbrt(u)
x1 = r*np.sin(theta)*np.cos(phi)
y1 = r*np.sin(theta)*np.sin(phi)
z1 = r*np.cos(theta)
dist = np.sqrt((x1-x0)**2+(y1-y0)**2+(z1-z0)**2)
distance = list(dist)
point_on_inside_sphere = []
for j in distance:
if j <= R:
point_on_inside_sphere.append(j)
print('j:',j,'\tR:',R)
print('The list is:', point_on_inside_sphere)
print(len(point_on_inside_sphere))
kk =0
for kk in range(len(point_on_inside_sphere)):
for jj in point_on_inside_sphere:
xx = np.sqrt(jj**2-y1**2-z1**2)
yy = np.sqrt(jj**2-x1**2-z1**2)
zz = np.sqrt(jj**2-y1**2-x1**2)
print("x:", xx, "y:", yy,"z:", zz)
kk +=1
And I am running it-
create_points_around_atom(n=2,structure[1].coords)
where, structure[1].coords is a numpy array of three coordinates.
To sum up what has been discussed in the comments, and some other points:
There is no need to filter the points because u <= 1, which means np.cbrt(u) <= 1 and hence r = R * np.cbrt(u) <= R, i.e. all points will already be inside or on the surface of the sphere.
Calling np.random.uniform with size=(n,) creates an array of n elements, so there's no need to do this n times in a loop.
You are filtering distances from the atom_coordinate, but the points you are generating are centered on [0, 0, 0], because you are not adding this offset.
Passing R as an argument seems more sensible than hard-coding it.
There's no need to "pre-load" arguments in Python like one would sometimes do in C.
Since sin(theta) is non-negative over the sphere, you can directly calculate it from the costheta array using the identity cosĀ²(x) + sinĀ²(x) = 1.
Sample implementation:
# pass radius as an argument
def create_points_around_atom(number, center, radius):
# generate the random quantities
phi = np.random.uniform( 0, 2*np.pi, size=(number,))
theta_cos = np.random.uniform(-1, 1, size=(number,))
u = np.random.uniform( 0, 1, size=(number,))
# calculate sin(theta) from cos(theta)
theta_sin = np.sqrt(1 - theta_cos**2)
r = radius * np.cbrt(u)
# use list comprehension to generate the coordinate array without a loop
# don't forget to offset by the atom's position (center)
return np.array([
np.array([
center[0] + r[i] * theta_sin[i] * np.cos(phi[i]),
center[1] + r[i] * theta_sin[i] * np.sin(phi[i]),
center[2] + r[i] * theta_cos[i]
]) for i in range(number)
])
I'm writing a script to subtract the inside cylinder from the outside cylinder for multiple cylinders.
for example: x = pi*[n+1]**2 - pi*[n]**2
However I'm not sure how to get n to change each time from for example 1 - 4, i want to be able to change n and have the code run through the new values without having to change everything.
x = pi*[1]**2 - pi*[0]**2
x = pi*[2]**2 - pi*[1]**2
x = pi*[3]**2 - pi*[2]**2
x = pi*[4]**2 - pi*[3]**2
I was trying to get a while loop to work but i cant figure out how to reference n without specifically stating which number in the array i want to reference.
Any help would be greatly appreciated.
rs = 0.2 # Radius of first cylinder
rc = 0.4 # Radius of each cylinder (concrete)
rg = 1 # Radius of each cylinder (soil)
BW = 3 # No. cylinders (concrete)
BG = 2 # No. cylinders (soil)
v1 = np.linspace(rs, rc, num=BW) # Cylinders (concrete)
v2 = np.linspace(rc * 1.5, rg, num=BG) # Cylinders (soil)
n = np.concatenate((v1, v2)) # Combined cylinders
for i in range(BW + BG):
x = np.pi * (n[i + 1] ** 2) - np.pi * (n[i] ** 2)
Try this:
for n in range(4): # 0 to 3
x = pi*[n+1]**2 - pi*[n]**2 #[1] - [0], [2] - [1] and so on...
# doSomething
If [n] is an index of an array with name num, replace [n] with
num[n] like so:
for n in range(4): # 0 to 3
x = pi*(num[n+1]**2) - pi*(num[n]**2) #[1] - [0], [2] - [1] and so on...
# doSomething
If instead it was simply n, replace [n] with n like so:
for n in range(4): # 0 to 3
x = pi*((n+1)**2) - pi*(n**2) #[1] - [0], [2] - [1] and so on...
# doSomething
Since your numbers are in a numpy array, it's much more efficient to use broadcast operations across the array (or slices of it), rather than writing a explicit loop and operating on individual items. This is the main reason to use numpy!
Try something like this:
# compute your `n` array as before
areas = pi * n**2 # this will be a new array with the area of each cylinder
area_differences = areas[1:] - areas[:-1] # differences in area between adjacent cylinders
How about this:
for i, value in enumerate(n[:-1]):
print(np.pi * (n[i + 1] ** 2) - np.pi * (value ** 2))
For me it prints:
0.157079632679
0.219911485751
0.628318530718
2.0106192983
Perhaps you want this:
>>> values = [np.pi * (n[i + 1] ** 2) - np.pi * (value ** 2)
for i, value in enumerate(n[:-1])]
>>> values
[0.15707963267948971, 0.2199114857512855, 0.62831853071795885, 2.0106192982974673]
Lets explain it:
we must get all elements in the list but the last, because n[i + 1] fails for the last item, so we use n[0:-1] (we are allowed omit the start of the slice if it is 0 or the end if it is equal or greater than len(n)).
enumerate(a_list) returns something resembling a list of pairs in the form
[(0, a_list[0]), (1, a_list[1]), ..., (n, a_list[n)]
for i, value in ... unpacks each pair into variables named i and value
[something for something in a_list] returns a new list. You may do calculations, and filter the values. For example, if you want a list of the square of the even integers bellow 10:
>>> [x * x for x in range(10) if x % 2 == 1]
[1, 9, 25, 49, 81]
I think this should provide the results you are looking for:
rs = 0.2 # Radius of first cylinder
rc = 0.4 # Radius of each cylinder (concrete)
rg = 1 # Radius of each cylinder (soil)
BW = 3 # No. cylinders (concrete)
BG = 2 # No. cylinders (soil)
v1 = np.linspace(rs, rc, num=BW) # Cylinders (concrete)
v2 = np.linspace(rc * 1.5, rg, num=BG) # Cylinders (soil)
n = np.concatenate((v1, v2))
results = []
for i, v in enumerate(n):
if i+1 < len(n):
results.append(pi * n[i+1] ** 2 - pi * v ** 2)
else:
break
Beginner in python here.
300 points are randomly generated where x and y are between 0 and 1.
I need to count the number of points that are generated inside the unit circle and to also estimate pi using these points. I typically want the code to be similar to this (what I have so far):
import math
import random
points = 300
x = [random.random() for jj in range(points)]
y = [random.random() for xx in x]
count = 0
for xx, yy in zip(x,y) :
if xx**2 + yy**2 < 1:
do_not_count_it
else:
count_it
sum = all_points_in_unit_circle
Any suggestions on how to complete the code?
You were close
You just need a condition when the point is inside (no need for else:).
You inverted the condition (you count when < 1)
Variables sum and count are the same.
This was not a mistake, but use multiplication instead of exponentiation when possible.
Library math is unused. You could have used sqrt(), but since sqrt(1)==1, it would be useless.
Which gives:
import random
points = 300
x = [random.random() for jj in range(points)]
y = [random.random() for xx in x]
count = 0
for xx, yy in zip(x,y) :
if xx * xx + yy * yy < 1:
count += 1
print (count)
BTW, it works for pyhton2 and python3.
I'm not too familiar with Monte Carlo methods, but a quick read tells me that you should simply do
for xx, yy in zip(x,y) :
if xx**2 + yy**2 <= 1:
count+=1
And then just approximate pi like so
approxPi = 4.0 * count / points
you can also do it like this:
from random import random
num_of_points = 300
points = [(random(), random()) for _ in range(num_of_points)]
points_inside = sum(x**2 + y**2 < 1 for x, y in points)
Here the radius of circle is 0.5 and the area of circle is Pi*0.5^2 = Pi*0.25; and the square is 1x1 and the area of square is 1x1 = 1.
The #point_in_circle / #point_in_square = area_of_circle / area_of_square,
so we have circle_count / all_count = Pi*0.25 / 1
we get Pi = circle_count / all_count * 1 / 0.25
This code will print out the PI value:
import math
import random
points = 300
x = [random.random() for jj in range(points)]
y = [random.random() for xx in x]
count_circle = 0
for xx, yy in zip(x,y) :
if xx**2 + yy**2 <= 1:
count_circle += 1
pi = count_circle/points/0.25
print (pi)