Changing iteration order during nested iteration - python

Given two associative arrays, one array contains pointers to 3d point coordinates, the other array contains a hash/dictionary of surfaces. For every point in the first array, there will be only one matching surface found in the second array (where the point lay on the surface.)
We need to iterate through the points to find the matching surface (to then get the unit vector [ijk points] normal to the surface at that point.)
Brute force could iterate through every item in each list, breaking the iteration once each surface data point is found. Though I’ve already found in writing earlier versions of this program, astronomically numerous calculations will be performed, and I need to be efficient.
There will always be more points than surfaces, and the surfaces will be adjacent, meaning as I iteration through the points in a certain order, it’s more likely than not that the next point will be on the same surface as the last.
I’m wondering if I can run a loop which, for example,
for point n:
for surface i:
does the point lay on the surface? if so, break
…and if the last ‘i’ value was 5, begin the next iteration at i=5 (and if the point wasn’t on surface 5, continue iterating through each surface.) It would be better if I could have it iterate in a order like: not 5? try 6; not 6? try 4——
Expanding on that idea, imagine that ‘i’ were organized in an 2d array. I.e:
[1,2,3]
[4,5,6]
[7,8,9]
And for n points:
For i surfaces: (continuing where I left off,) not 4? try 2; not 2? try 8.
I’m wondering if a ‘for’ loop won’t give me the versatility I need. (By the way, the program will likely be written in either Python or .NET) I’m thinking that I can make a while loop and write some sort of logic that will iterate the way I want. Am I trying to reinvent the wheel? Am I on the right track?

This is only a partial answer, because your question doesn't have a lot of specifics on what your actual code is. But, that said, one thing to note is that the variable from a for loop retains its value even after the loop has ended. So this will print 5:
for i in range(1000):
if i == 5:
break
print(i)
So you can easily check after the inner loop what value it ended on. And then you can do whatever you want with that value. For instance, you could look at it on the next run through the outer loop and fix things up so that the inner loop starts at some other place.
A for loop will almost surely give you the versatility you need, because you can use a for loop to iterate over many kinds of things, including some custom iterator that you create. So for instance you could do something like this:
def best_order_to_loop(all_surfaces, previous_stopping_point):
# some logic here
yield next_value
previous_stopping_point = None
for point in points:
surfaces_in_order = best_order_to_loop(all_surfaces, previous_stopping_point)
for surface in surfaces_in_order:
# do whatever
previous_stopping_point = surface
Again, this is just a sketch and I'm not sure I'm 100% understanding your setup. But it seems like you're saying "if the previous loop stopped at X, then based on that I want the next loop to loop in such-and-such order". If that is the case you can write a function like best_order_to_loop that determines how the next inner loop will go, based on the previous stopping point.

Related

I set 3 arrays to the same thing, changing a single entry in one of them also changes the other two arrays. How can I make the three arrays separate?

I am making a puzzle game in a command terminal. I have three arrays for the level, originlevel, which is the unaltered level that the game will return to if you restart the level. Emptylevel is the level without the player. Level is just the level. I need all 3, because I will be changing the space around the player.
def Player(matrix,width):
originlevel = matrix
emptylevel = matrix
emptylevel[PlayerPositionFind(matrix)]="#"
level = matrix
The expected result is that it would set one entry to "#" in the emptylevel array, but it actually sets all 3 arrays to the same thing! My theory is that the arrays are somehow linked because they are originally said to the same thing, but this ruins my code entirely! How can I make the arrays separate, so changing one would not change the other?
I should not that matrix is an array, it is not an actual matrix.
I tried a function which would take the array matrix, and then just return it, thinking that this layer would unlink the arrays. It did not. (I called the function IHATEPYTHON).
I've also read that setting them to the same array is supposed to do this, but I didn't actually find an answer how to make them NOT do that. Do I make a function which is just something like
for i in range(0,len(array)):
newarray.append(array[i])
return newarray
I feel like that would solve the issue but that's so stupid, can I not do it in another way?
This issue is caused by the way variables work in Python. If you want more background on why this is happening, you should look up 'pass by value versus pass by reference'.
In order for each of these arrays to be independent, you need to create a copy each time you assign it. The easiest way to do that is to use an array slice. This means you will get a new copy of the array each time.
def Player(matrix,width):
originlevel = matrix[:]
emptylevel = matrix[:]
emptylevel[PlayerPositionFind(matrix)]="#"
level = matrix[:]

How is math.copysign(x, y) in Python useful?

I was going over the functions of the math module in Python and found the math.copysign (x,y) function. I want to know when someone would use this function. I check many websites and they show how to use the function. I understand how to use it, but I would like to know in which cases it will be useful to get the absolute value of the first argument and the sign of the second.
math.copysign(x, y)
Here's one easy example. Suppose I'm writing a game, and I want the enemy to move toward the player at a given speed. The speed is determined by one variable and the direction is determined by where the player is
enemy.velocity = math.copysign(enemy.base_speed, player.xposition - enemy.xposition)
This sort of vector math (here, it's really just directional math, since we're dealing in one dimension) becomes second nature when you've used it awhile.
Could be useful when trying to find positive or negative floats.
I just stumbled on error in my code, which was solved by copysign:
#Error:
#a is a float value:
a=-0.0004
if int(a) < 0:
#do something
Won't work, because int(-0.004) will be 0, which has no sign.
So had to change to:
a=-0.0004
if math.copysign(1,a) < 0:
#do something

Exploring linked point with recursing "for" function in python

I have a set of points in the space, each of them is linked to some other: http://molview.org/?q=Decane
For each point I need to find three other points:
One to form a bond: first neighbors
Second to form an angle: second neighbors
Third to form a dihedral angle: third neighbors is best but second if not existing
I have a working algorithm:
def search_and_build(index, neighbor):
#index is the currently selected point, neighbor is a list containing all the connected point...
#if the index is already done return directly
if is_done(index):
return
set_done(index)
for i, j in enumerate(neighbor):
#add function are adding data in dictionaries and search function are searching in the bonding dict for second and third neighbors
add_bond(j, index)
add_angle(j, search_angle(j))
add_dihedral(j, search_dihedral(j))
search_and_build(j, get_sorted_neighbors(j))
This algorithm is using recursivity in a for loop. I use it because I thought recursivity is cool and also because it instantly worked. I assumed that python would finish the for first and then run another function, but after some debugging I realized that it's not working like that. Sometimes the for is running multiples times before another function sometimes not
I googled and it's apparently a bad practice to use such algorithms, would someone be able to explain?
Each time your for loop gets to the last line it calls the function again, starting the for loop again and so on.
The issue is that the for loop in all of those functions calls has not finished executing, it has executed once, and put a new function call on the stack for search_and_build and each search_and_build execution will do the same while there's still something in your dict.
By the time you get back to the first For loops the dict that's getting iterated on doesn't exist or has shrunk a lot, but there was supposed to be something/more of something to iterate over when it first started.
Basicly recursion is cool, but it makes thing pretty hard to get your head around or debug, even more if you invole other loops inside each steps of your recursion.
TLDR : Mutating and iterable while looping over it is very bad.

Is it possible to (quickly) find only the first cycle in a networkx graph?

I have a directed network that may or may not have cycles in it. I need to find them and remove the cyclicity. If I have a networkx DiGraph (G), I can find all the cycles with
cycle_nodes = nx.simple_cycles(G)
which creates a cycle-returning generator.
However, I don't want to return all cycles a la list(cycle_nodes) because many of the cycles are subsets of each other, and fixing one will fix others. Instead, I would like to only find the first instance of a cycle. As cycle_nodes is a generator, I tried
next(cycle_nodes)
to return only the first instance. However, I found that the time required to return the first instance not much smaller compared to the time required to return all instances:
list(cycle_nodes) : 58s
next(cycle_nodes) : 44s
Is this just due to the nature of my graph (i.e. the first cycle is far along the search order), or is there a more efficient way to return any cycle (doesn't necessarily need to be the first)?
The reason I suspect there may be a faster way is because when I run nx.is_directed_acyclic_graph(G), it takes only a second or two and returns False, so it's obviously finding at least one cycle in just a second or so.
The answer was sort of obvious. The algorithm nx.find_cycle() with no starting node provided will return the first cycle it finds, and rapidly. I was under the impression that a starting node needed to be provided, RTFM!

Loop until steady-state of a complex data structure in Python

I have a more-or-less complex data structure (list of dictionaries of sets) on which I perform a bunch of operations in a loop until the data structure reaches a steady-state, ie. doesn't change anymore. The number of iterations it takes to perform the calculation varies wildly depending on the input.
I'd like to know if there's an established way for forming a halting condition in this case. The best I could come up with is pickling the data structure, storing its md5 and checking if it has changed from the previous iteration. Since this is more expensive than my operations I only do this every 20 iterations but still, it feels wrong.
Is there a nicer or cheaper way to check for deep equality so that I know when to halt?
Thanks!
Take a look at python-deep. It should do what you want, and if it's not fast enough you can modify it yourself.
It also very much depends on how expensive the compare operation and how expensive one calculation iteration is. Say, one calculation iteration takes c time and one test takes t time and the chance of termination is p then the optimal testing frequency is:
(t * p) / c
That is assuming c < t, if that's not true then you should obviously check every loop.
So, since you can dynamically can track c and t and estimate p (with possible adaptions in the code if the code suspects the calculation is going to end) you can set your test frequency to an optimal value.
I think your only choices are:
Have every update mark a "dirty flag" when it alters a value from its starting state.
Doing a whole structure analysis (like the pickle/md5 combination you suggested).
Just run a fixed number of iterations known to reach a steady state (possibly running too many times but not having the overhead of checking the termination condition).
Option 1 is analogous to what Python itself does with ref-counting. Option 2 is analogous to what Python does with its garbage collector. Option 3 is common in numerical analysis (i.e. run divide-and-average 20 times to compute a square root).
Checking for equality to me doesn't seem the right way to go. Provided that you have full control over the operations you perform, I would introduce a "modified" flag (boolean variable) that is set to false at the beginning of each iteration. Whenever one of your operation modifies (part of) your data structure, it is set to true, and repetition is performed until modified remained "false" throughout a complete iteration.
I would trust the python equality operator to be reasonably efficient for comparing compositions of built-in objects.
I expect it would be faster than pickling+hashing, provided python tests for list equality something like this:
def __eq__(a,b):
if type(a) == list and type(b) == list:
if len(a) != len(b):
return False
for i in range(len(a)):
if a[i] != b[i]:
return False
return True
#testing for other types goes here
Since the function returns as soon as it finds two elements that don't match, in the average case it won't need to iterate through the whole thing. Compare to hashing, which does need to iterate through the whole data structure, even in the best case.
Here's how I would do it:
import copy
def perform_a_bunch_of_operations(data):
#take care to not modify the original data, as we will be using it later
my_shiny_new_data = copy.deepcopy(data)
#do lots of math here...
return my_shiny_new_data
data = get_initial_data()
while(True):
nextData = perform_a_bunch_of_operations(data)
if data == nextData: #steady state reached
break
data = nextData
This has the disadvantage of having to make a deep copy of your data each iteration, but it may still be faster than hashing - you can only know for sure by profiling your particular case.

Categories

Resources