How can I generalize Jump Point Search to a 3D search volume?
So far, I have defined pruning rules for a 3D cube involving each of the three movements- straight (0,0,1), first-order diagonal (0,1,1) and second-order (1,1,1).
What I'm mostly concerned about is the optimal turning points defined in the paper. I've been unable to ascertain exactly how they were derived, and therefore how to derive my own for three dimensions.
Any suggestions as to how this can be done?
Rather than attempting to derive turning points, it helps to use an intuitive understanding of the algorithm in 2D.
Because the shortest distance between two locations is a straight line, we know that moving diagonally is fastest because it's equivalent to two steps in 1D. In 3D, this means a diagonal is equivalent to three steps. (in reality, these values are sqrt(2) and sqrt(3)). With this, we choose to optimize by moving across as many axis as possible... Turning to move along a 2D axis is worse than turning to move along a 3D axis. Likewise, moving along 1D (straight) is even worse than 2D movement. This is the core assumption jump-point makes.
There is, in the culling algorithm, the assumption that if you are jumping on the least optimal axis (1D), then there are no optimal turns of a higher axis order (turning onto a 2D axis) until there is a parallel wall on the same axis order. For example, look at figure 2(d), where the code sees a parallel wall in 1D and adds a 2D movement back into the list.
As a Heuristic
Evaluate forward until one space is left open (and a wall is 2 spaces away), and add this point to the jumplist. For any point on the jumplist, jump in a new direction. goal > 2D movements forward > 1D movements forward > 1D movements backward > 2D movements backward. We can generalize this heuristic to any n dimension...
Evaluating the next direction, with + being towards the goal, and n being the amount of dimensions incremented gives us the equation...
+nD > +n-1 D > ... +1D > 0D > -1D > ... > -n-1 D > -nD
The order of best->worst turning points in 3D
3D+ = [1, 1, 1]
2D+ = [1, 1, 0], [1, 0, 1], [0, 1, 1]
1D+ = [1, 0, 0], [0, 1, 0], [0, 0, 1], [-1, 1, 1], [1, -1, 1], [1, 1, -1]
(suboptimals below; [0, 0, 0] is useless, so I didn't include it)
0D = [1, -1, 0], [1, 0, -1], [-1, 1, 0], [-1, 0, 1], [0, -1, 1], [0, 1, -1]
1D- = [-1, 0, 0], [0, -1, 0], [0, 0, -1], [-1, -1, 1], [1, -1, -1], [-1, 1, -1]
2D- = [-1, -1, 0], [-1, 0, -1], [0, -1, -1]
3D- = [-1, -1, -1]
phew typing that was a pain, but it should solve your problem.
Just remember that as you 'jump', keep track of which order of axis you are jumping; you need to find parallel walls in the same axis. Therefore, moving in the direction [1, 0, 1], you want to find walls that are at [1, 1, 0] and [0, 1, 1] in order to 'unlock' a jump point in the direction [1, 1, 1].
With the same logic, if you move in 1D [1, 0, 0], you check [0, 1, 0] for a wall to add [0, 1, 1] and [1, 1, 0]. You also check [0, 0, 1] in order to add [1, 0, 1] and [0, 1, 1] as jump points.
Hopefully you get what I mean, because it's really difficult to visualize and calculate, but easy to grasp once you have the mathematics of it.
Conclusion
Use the A* heuristics...
Dijkstra = distance from start
Greedy First = distance from goal
Then add our new heuristics!
+nD > +n-1 D > ... +1D > -1D > ... > -n-1 D > -nD
if any point nD has a parallel obstruction, you may add a jump point for each open n+1 D direction.
EDIT:
The definition of 'parallel' for your code
any point that is the same order as the direction you are moving
not the next point in that direction
has the same amount of positive and negative dimensional moves as the next point (e.g, [1, 1, -1] is parallel to [1, -1, 1] and [-1, 1, 1], but not to [1, 0, 0]
Related
scores = [[0,0]]*10
scores[1][1] += 1
print(scores)
>>[[0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1]]
I want to increment at a specific position in a nested list in python, but am incrementing the entire list instead. Can anyone explain this behavior?
This is because python is first creating the list, then is creating the reference ten times. In other words, using this method only one list is created. Try this:
scores = []
for i in range(10):
scores.append([0, 0])
scores[1][1] += 1
print(scores)
Output:
[[0, 0], [0, 1], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
scores = [[0,0]]*10 makes 10 copy of the same objects. If you examine the id() of the list's elements, for example by id(scores[3]), you can see their references are the same. If you want to have different objects in your list, you should use something like: scores = [[0,0] for i in range(10)]
I was trying to solve the 3Sum problem in leetcode. but I observed python lists behaving different during the end of loop statement.
def threeSum(nums):
n=len(nums)
sum = {}
result = []
for i in range(n):
for j in range(i+1,n):
if i != j:
key = nums[i]+nums[j]
if key not in sum:
sum[key] = [nums[i],nums[j]]
for i in range(n):
if -nums[i] in sum:
temp = sum[-nums[i]]
temp.append(nums[i])
if(len(temp)<=3):
result.append(temp)
print(result)
print("at the end of loop")
print(result)
return "result printed"
nums = [-1,0,1,2,-1,-4]
print(threeSum(nums))
For the above function I got the output as
[[-1, 2, -1]]
[[-1, 2, -1], [-1, 1, 0]]
[[-1, 2, -1], [-1, 1, 0], [-1, 0, 1]]
[[-1, 2, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]]
at the end of loop
[[-1, 2, -1, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]]
result printed
From the output you can see that during the last iteration of the loop the result List variable contains the value [[-1, 2, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]] but when I print the same result at the end of the loop it is printed as [[-1, 2, -1, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]] , the first element in List is changed.
How do you explain this? Am I missing something in the understanding of Python Lists?
P.S : Please ignore the solution of 3Sum problem, I already found another way to solve it, my question is regarding the Python List only
In Python, List is reference value. In your code, you refer to sum[1] 2 times. Both of 2 times return to the same List instance. That's why after the 2nd time, that List instance is appended 1 more number
This behavior is caused by two issues:
if(len(temp)<=3): will prevent printing the final result due to the length constraint
python lists are mutable and they can be modified from different places if the same object is referenced
In your case, at fourth iteration result[0] and temp will reference the same object. This is why result gets modified even it was not apparently touched. It was changed due to the change of temp variable. You can check this using additional prints to highlight current iteration, result and object ids.
for i in range(n):
print(i)
print(result)
if -nums[i] in sum:
temp = sum[-nums[i]]
temp.append(nums[i])
if(len(temp)<=3):
result.append(temp)
print(result)
print(id(result[0]))
print(id(temp))
print("at the end of loop")
print(result)
return "result printed"
in the pyrr.Matrix docs it states:
Matrices are laid out in row-major format and can be loaded directly into OpenGL. To convert to column-major format, transpose the array using the numpy.array.T method.
creating a transformation matrix gives me:
Matrix44.from_translation( np.array([1,2,3]))
Matrix44([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[1, 2, 3, 1]])
If the layout is row-major, I would expect the output to be the transpose:
Matrix44([[1, 0, 0, 1],
[0, 1, 0, 2],
[0, 0, 1, 3],
[0, 0, 0, 1]])
I'm most likely confused (I come from C/OpenGL background), but could anyone please enlighten me?
Jonathan
I was writing down a great answer. But I found this really interesting link I invite you to read it !
This is a small resume :
If it's row-major matrix, then the translation is stored in the 3, 7, and 11th indices.
If it's column-major, then the translation is stored in the 12, 13, and 14th indices.
The difference behind the scene is the way to store the data. As it is 16 float in memory, those floats are contiguous in the memory. So you have to define if you either store them in 4 float x 4 columns or 4 float x 4 rows. And then it change the way you access and use it.
You can look at this link too.
How does OpenGL calculate the new texture coordinate when wrapping with GL_MIRRORED_REPEAT? I mean given (x, y) what formula is applied? https://open.gl/textures
See OpenGL 4.6 API Core Profile Specification; 8.14.2 Coordinate Wrapping and Texel Selection; page 257, Table 8.20
MIRRORED_REPEAT : (size − 1) − mirror(coord mod (2 × size)) − size)
where mirror(a) returns a if a ≥ 0, and −(1 + a) otherwise.
This means if the texture is tiled then the even tiles are draw as the texture is and the odd tiles are drawn mirrored.
If the texture coordinate are in [0, 1], [2, 3], [4, 5], ..., then the wrap function returns a corresponding coordinate in range [0, 1].
If the texture coordinate are in [1, 2], [3, 4], [5, 6], ..., then the wrap function returns a corresponding mirrored coordinate in range [1, 0].
The wrap function is applied to each coordinate separately and for each coordinate a separate, different wrap function can be set.
I have a 2-dimensional array of ones and zeros called M where the g rows represent groups and the a columns represent articles. M maps groups and articles. If a given article "art" belongs to group "gr" then we have M[gr,art]=1; if not we have M[gr,art]=0.
Now, I would like to convert M into a square a x a matrix of ones and zeros (call it N) where if an article "art1" is in the same group as article "art2", we have N(art1,art2)=1 and N(art1,art2)=0 otherwise. N is clearly symmetric with 1's in the diagonal.
How do I construct N based on M?
Many thanks for your suggestions - and sorry if this is trivial (still new to python...)!
So you have a boolean matrix M like the following:
>>> M
array([[1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 0],
[1, 0, 1, 0, 0, 0]])
>>> ngroups, narticles = M.shape
and what you want is a matrix of shape (narticles, narticles) that represents co-occurrence. That's simply the square of the matrix:
>>> np.dot(M, M.T)
array([[1, 0, 0, 1],
[0, 2, 0, 0],
[0, 0, 1, 1],
[1, 0, 1, 2]])
... except that you don't want counts, so set entries > 0 to 1.
>>> N = np.dot(M, M.T)
>>> N[N > 0] = 1
>>> N
array([[1, 0, 0, 1],
[0, 1, 0, 0],
[0, 0, 1, 1],
[1, 0, 1, 1]])