Let's say you have the grid:
list = [[-,O,-,-,O,-,],
[O,-,-,-,-,O],
[O,O,-,-,X,-],
[-,-,O,-,-,-]]
How would you get the coordinates of all O's that are within a distance of 3 from X?
From what I saw in other answers, using scipy.spatial.KDTree.query_ball_point seemed like a common approach but I was unable to figure out how to adapt it to my use case. One possible idea I had was to store every coordinate of the list such as
coords=[[0,0],[0,1]...] and then use the scipy method and pass in the coordinate of the X and the searching distance. And then once I received the list of possible coordinates, I then iterate through the list and check which ones are equal to O. I was wondering, however, if there was a more efficient or more optimized solution I could use. Any help would be greatly appreciated.
You don't need to make it too complicate by using Scipy. This problem can easily done by help of mathematics.
Equation of coordinate inside circle is x^2 + y^2 <= Radius^2, so just check coordinate that inside the circle.
list = [[-,O,-,-,O,-,],
[O,-,-,-,-,O],
[O,O,-,-,X,-],
[-,-,O,-,-,-]]
X_coor = #Coordinate of X, in this case y = 2, x = 4
d = #Maximum distance from X in this case d = 3
total = 0
O_coor = [] #Store coordinate of all O near X
for y in range(max(0, X_coor.y - d), min(list.length - 1, X_coor.y + d)):
for x in range(max(0, X_coor.x - sqrt(d**2 - (y - X_coor.y)**2)), min(list.length - 1, X_coor.x + sqrt(d**2 - (y - X_coor.y)**2))):
if list[y][x] == "O":
total++
O_coor.append([x, y])
print(total)
print(O_coor)
It a long code, but you can ask me parts that you don't understand.
Note: This solution check only coordinate in circle area not entire list, so even if you have large list this still very fast.
Related
I have been looking for the solution for the closest pair problem in Python, but all the solutions were completely different from mine.
Here is the code that finds the closest pair of points on a 2D dimension.
def closest_pair_two_axes(xarr, yarr):
pairs = []
# doesn't really depend if xarr or yarr because the lengths are the same
for i in range(len(xarr)):
pairs.append([xarr[i], yarr[i]])
# Finds the difference between each point
dist_arr = []
for i in range(1, len(pairs)-1):
for j in range(i, len(pairs)):
diff_x = pairs[j][0] - pairs[j - i][0]
diff_y = pairs[j][1] - pairs[j - i][1]
diff = (diff_x ** 2 + diff_y ** 2) ** 0.5
dist_arr.append(round(diff, 2))
index = dist_arr.index(min(dist_arr))
closest_distance = dist_arr[index]
return closest_distance
xarr and yarr are just the names of arrays for the x and y coordinates. In the function, I combine both arrays into a dictionary containing sets of coordinates. After that, I iterate through every possible combination of the coordinates and find the distance between each one of them. In the end, I find the minimum distance, trace it back to the pair it belongs to, and then return it to the user.
This code works but I am not sure if it works correctly and if the result really is the closest pair. Is the code correct?
EDIT:
I changed [j-1] to [j-i] so that it will iterate through every pair possible. Also, I solved the problem using another person's algorithm(the right algorithm) and got the same answer as I did with my algorithm. It might not be the fastest and cleanest code, but it works!
I am trying to write program that print maximal points of the input but it is not giving correct output.
Definition of maximal-
Given a set of points P = {p1,p2,...,pn} in 2-space, each represented by its x and y integer coordinates, output the set of the maximal points of P, that is, those points pi, such that pi is not dominated by any other point of P (not both coordinate are dominated)
Example input:
p1(5,7),p2(47,84),p3(89,4),(46,54),(100,1)
Example outut:
p2(47,84),(89,4),(100,1)
The idea of my program is to first sort the point according to x axis then compare the y coordinate.
a=[[5,7],[47,84],[89,4][46,54],[100,1]]
#sort according to x axis
mylist.sort(key=lambda x: x[0])
#compare y coordinate of i to all element right to i
for i in reversed(range(len(a)):
j=i+1
while (j<len(a)):
if(mylist[i][1]>mylist[j][1]):
j+=1
if(j==len(a)):
print(mylist[i])
That's really not how you'd do that in Python. Use language elements that help you express what's going on, that way the code gets more understandable and, as a bonus, more concise. You want to find all elements of a for which no other element of a is greater in both coordinates:
a=[[5,7],[47,84],[89,4],[46,54],[100,1]]
for point in a:
if not any(map(lambda p: p[0] > point[0] and p[1] > point[1], a)):
print(point)
You could also use a list comprehension instead of map, which might be a bit more efficient:
a=[[5,7],[47,84],[89,4],[46,54],[100,1]]
for point in a:
if not any([p[0] > point[0] and p[1] > point[1] for p in a]):
print(point)
I have an N-body simulation that generates a list of particle positions, for multiple timesteps in the simulation. For a given frame, I want to generate a list of the pairs of particles' indices (i, j) such that dist(p[i], p[j]) < masking_radius. Essentially I'm creating a list of "interaction" pairs, where the pairs are within a certain distance of each other. My current implementation looks something like this:
interaction_pairs = []
# going through each unique pair (order doesn't matter)
for i in range(num_particles):
for j in range(i + 1, num_particles):
if dist(p[i], p[j]) < masking_radius:
interaction_pairs.append((i,j))
Because of the large number of particles, this process takes a long time (>1 hr per test), and it is severely limiting to what I need to do with the data. I was wondering if there was any more efficient way to structure the data such that calculating these pairs would be more efficient instead of comparing every possible combination of particles. I was looking into KDTrees, but I couldn't figure out a way to utilize them to compute this more efficiently. Any help is appreciated, thank you!
Since you are using python, sklearn has multiple implementations for nearest neighbours finding:
http://scikit-learn.org/stable/modules/neighbors.html
There is KDTree and Balltree provided.
As for KDTree the main point is to push all the particles you have into KDTree, and then for each particle ask query: "give me all particles in range X". KDtree usually do this faster than bruteforce search.
You can read more for example here: https://www.cs.cmu.edu/~ckingsf/bioinfo-lectures/kdtrees.pdf
If you are using 2D or 3D space, then other option is to just cut the space into big grid (which cell size of masking radius) and assign each particle into one grid cell. Then you can find possible candidates for interaction just by checking neighboring cells (but you also have to do a distance check, but for much fewer particle pairs).
Here's a fairly simple technique using plain Python that can reduce the number of comparisons required.
We first sort the points along either the X, Y, or Z axis (selected by axis in the code below). Let's say we choose the X axis. Then we loop over point pairs like your code does, but when we find a pair whose distance is greater than the masking_radius we test whether the difference in their X coordinates is also greater than the masking_radius. If it is, then we can bail out of the inner j loop because all points with a greater j have a greater X coordinate.
My dist2 function calculates the squared distance. This is faster than calculating the actual distance because computing the square root is relatively slow.
I've also included code that behaves similar to your code, i.e., it tests every pair of points, for speed comparison purposes; it also serves to check that the fast code is correct. ;)
from random import seed, uniform
from operator import itemgetter
seed(42)
# Make some fake data
def make_point(hi=10.0):
return [uniform(-hi, hi) for _ in range(3)]
psize = 1000
points = [make_point() for _ in range(psize)]
masking_radius = 4.0
masking_radius2 = masking_radius ** 2
def dist2(p, q):
return (p[0] - q[0])**2 + (p[1] - q[1])**2 + (p[2] - q[2])**2
pair_count = 0
test_count = 0
do_fast = 1
if do_fast:
# Sort the points on one axis
axis = 0
points.sort(key=itemgetter(axis))
# Fast
for i, p in enumerate(points):
left, right = i - 1, i + 1
for j in range(i + 1, psize):
test_count += 1
q = points[j]
if dist2(p, q) < masking_radius2:
#interaction_pairs.append((i, j))
pair_count += 1
elif q[axis] - p[axis] >= masking_radius:
break
if i % 100 == 0:
print('\r {:3} '.format(i), flush=True, end='')
total_pairs = psize * (psize - 1) // 2
print('\r {} / {} tests'.format(test_count, total_pairs))
else:
# Slow
for i, p in enumerate(points):
for j in range(i+1, psize):
q = points[j]
if dist2(p, q) < masking_radius2:
#interaction_pairs.append((i, j))
pair_count += 1
if i % 100 == 0:
print('\r {:3} '.format(i), flush=True, end='')
print('\n', pair_count, 'pairs')
output with do_fast = 1
181937 / 499500 tests
13295 pairs
output with do_fast = 0
13295 pairs
Of course, if most of the point pairs are within masking_radius of each other, there won't be much benefit in using this technique. And sorting the points adds a little bit of time, but Python's TimSort is rather efficient, especially if the data is already partially sorted, so if the masking_radius is sufficiently small you should see a noticeable improvement in the speed.
Here is my code:
# point of intersection between opposite and hypotenuse
x,y = pygame.mouse.get_pos()
# using formula for length of line
lenline1 = (x-x)**2 + (300-y)**2
lenline2 = (x-700)**2 + (y-300)**2
opposite = math.sqrt(lenline1)
adjacent = math.sqrt(lenline2)
# Converting length of lines to angle
PQ = opposite/adjacent
k = math.sin(PQ)
j = math.asin(k)
print(j)
I'm not getting the results I expected, although after messing around with it I got close but it wasn't quite right. Could someone please tell me what I'm doin wrong. I have two lines:
opposite and adjacent
And I wish to get the angle using the inverse of sin. What am I doing wrong. I'm only a beginner so don't give too detailed info. I can't imagine this is hard to do.
Thanks.
To find the angle between two lines, use the following relation:
cos(angle) = (l1 dot l2) / (|l1| |l2|)
That is,
dotproduct = l1x * l2x + l1y * l2y
lenproduct = |l1| * |l2|
angle = acos(dotproduct / lenproduct)
where l1x, l1y are the x,y components of the line l1.
Don't bother with the k computation, its meaningless.
j = math.asin(PQ)
However, this only works for right-angled triangles and you have to appropriate side lengths in the right places. In general this will not work and you need to use the dot product method.
Looks like you're trying to find the angle of the triangle (700,300), (x,300), (x,y). You're making it much more complicated than it needs to be. the length of the hypotenuse is math.hypot((700-x),(300-y)) and the angle is math.atan2((700-x), (300-y)).
How can I check if a point is below a line or not ?
I've the following data:
Line [ {x1,y1}, {x2,y2} ]
Points {xA,yA}, {xB,yB} ...
I need to write a small algorithm in python to detect points on one side and the other side of the line.
thanks
You could try using a cross product -- http://en.wikipedia.org/wiki/Cross_product.
v1 = (x2-x1, y2-y1) # Vector 1
v2 = (x2-xA, y2-yA) # Vector 2
xp = v1[0]*v2[1] - v1[1]*v2[0] # Cross product
if xp > 0:
print('on one side')
elif xp < 0:
print('on the other')
else:
print('on the same line!')
You'd need to calibrate what each side is. If you want it to be "below" or "above" you need to ensure the points on the line are sorted horizontally.
I haven't tested this.
Edit I initially put in the dot product formula. :o
Edit 2 D'oh, I was putting the coordinates into a set instead of a tuple. Using namedtuple('point', 'x y') for the vectors is nice if you're running a reasonably modern version of Python.
Luckily I found Calculating a 2D Vector's Cross Product.
You could try using a cross product, but the trick is how to choose the point to form a vector, here I choose the closest point from points, assume I got pointA(you can fairly loop points to calculate to distance from loop point to Line):
v1 = {x2-x1, y2-y1} # Vector 1
v2 = {xA-x1, yA-y1} # Vector 2
cross_product = v1.x*v2.y - v1.y*v2.x
if cross_product > 0:
print 'pointA is on the counter-clockwise side of line'
elif cross_product < 0:
print 'pointA is on the clockwise side of line'
else:
print 'pointA is exactly on the line'
Lets say you've given 2 points A, B and you want to know in which halfplane a third point C lies. The terms "below" and "above" as criteria are very vague, so you need a reference point, for example the origin. Just be sure this reference point is not collinear with A and B.
What you have now is a triangle (A, B, C). Using the determinant you can calculate the signed area (see here, or here). The only interesting thing here is to remember the sign.
Next step: for a given point D calculate the signed area of the triangle (A, B, D). If the result has the same sign as the area of your reference triangle -> C and D are on the same side of (A, B). If the sign differs -> C and D lie on opposite sides of the line. If the area of (A, B, D) is 0 then A, B and D are collinear. Note: use the Python builtin cmp to compare the triangle areas.