Python recursive call for list elements - python

I've tried to create a rough implementation of g-means to break a sample down into clusters where the clusters are gaussian using recursion, but my program seems to be going in only one direction (downward). The input values of this method were a data set, X, and a list of centers.
I'm having trouble figuring out how to solve the recursive bit of this method (the last for loop and beyond). After all of the recursive calls, I want to have a list of centers in C that can be returned to the main method.
So here's what happens in the last for loop. I'm iterating through a list of clusters (found using my cluster centers), clust, that contain all the values in each cluster. I run a test to see if there is significant evidence that the values in each cluster are gaussian. If there is evidence, then I want to remove that cluster center and add two new centers above and below. I then want to run through another recursive call and then evaluate these new center to see if the clusters they match to are gaussian or not.
The problem is my program is only evaluating the lower center bound. It seems to never reach the upper center as though the return statement means the program will stop the upper center from ever being reached.
Does anyone know how I can get my method to cover both the lower and upper sides of the cluster? (The for loop usually only makes 1 iteration ( for i in range(len(clust))) even when the length of clust = 2.
Another problem I'm having is that my method is simply overwriting the centers list instead of adding to it with each recursive call. Does anyone know how I can make recursive calls while appending to a list? I'm inserting items into the list and passing part of the list to a deeper level, but on return, I only get two values (both really low).
def gMean(X,C):
label=vq.kmeans2(X,np.array(C))
#take care of centers that do not match to clusters in kmeans2
while(len(set(range(len(C))))!=len(set((label[1])))):
emptyK=set(range(len(C)))- set(range(len(C))).intersection(set(label[1]))
emptyK=list(emptyK)
emptyK.reverse()
for i in range(len(emptyK)):
C.pop(emptyK[i])
label=vq.kmeans2(X,np.array(C))
#clust is a 2D list and holds all the values for given cluster
clust=[[] for x in range(max(label[1])+1)]
for i in range(len(label[1])):
for j in range(len(clust)):
if j==label[1][i]:
clust[j].append(X[i])
for i in range(len(clust)):
transClust=np.transpose(clust[i])
notGausFlag=False
for j in range(len(transClust)):
if stats.anderson(transClust[j])[1][2]<stats.anderson(transClust[j])[0]:
notGausFlag=True
if notGausFlag==True:
upper,lower=findCenter(clust[i],C[i])
C.pop(i)
C.insert(i,upper)
C.insert(i,lower)
for j in range(len(clust[i])):
clust[i][j]=clust[i][j].tolist()
clust[i]=np.array(clust[i])
return gMean(clust[i],C[i:i+2])
if notGausFlag==False:
return C

So I think I realize the error in my code I'm calling a recursive method and passing a cluster with two cluster centers, but when I go to step into the next level of the recursive loop, I only ever step in with the first center because the second one isn't reached in the for loop (for i in range(len(closet)):).
What I should have done was call the recursive method like this.
return gMean(clust[i],C[i])+gMean(clust[i],C[i+1])

Related

Returning list of different results that are created recursively in Python

Lately I've been working with some recursive problems in Python where I have to generate a list of possible configurations (i.e list of permutations of a given string, list of substrings, etc..) using recursion. I'm having a very hard time in finding the best practice and also in understanding how to manage this sort of variable in recursion.
I'll give the example of the generate binary trees problem. I more-or-less know what I have to implement in the recursion:
If n=1, return just one node.
If n=3, return the only possible binary tree.
For n>3, crate one node and then explore the possibilities: left node is childless, right node is childless, neither node is childless. Explore these possibilites recursively.
Now the thing I'm having the most trouble visualising is how exactly I am going to arrive to the list of trees. Currently the practice I do is pass along a list in the function call (as an argument) and the function would return this list, but then the problem is in case 3 when calling the recursive function to explore the possibilites for the nodes it would be returning a list and not appending nodes to a tree that I am building. When I picture the recursion tree in my head I imagine a "tree" variable that is unique to each of the tree leaves, and these trees are added to a list which is returned by the "root" (i.e first) call. But I don't know if that is possible. I thought of a global list and the recursive function not returning anything (just appending to it) but the problem I believe is that at each call the function would receive a copy of the variable.
How can I deal with generating combinations and returning lists of configurations in these cases in recursion? While I gave an example, the more general the answer the better. I would also like to know if there is a "best practice" when it comes to that.
Currently the practice I do is pass along a list in the function call (as an argument) and the function would return this list
This is not the purest way to attack a recursive problem. It would be better if you can make the recursive function such that it solves the sub problem without an extra parameter variable that it must use. So the recursive function should just return a result as if it was the only call that was ever made (by the testing framework). So in the example, that recursive call should return a list with trees.
Alternatively the recursive function could be a sub-function that doesn't return a list, but yields the individual values (in this case: trees). The caller can then decide whether to pack that into a list or not. This is more pythonic.
As to the example problem, it is also important to identify some invariants. For instance, it is clear that there are no solutions when n is even. As to recursive aspect: once you have decided to create a root, then both its left and right sided subtree will have an odd number of nodes. Of course, this is an observation that is specific to this problem, but it is important to look for such problem properties.
Finally, it is equally important to see if the same sub problems can reoccur multiple times. This surely is the case in the example problem: for instance, the left subtree may sometimes have the same number of nodes as the right subtree. In such cases memoization will improve efficiency (dynamic programming).
When the recursive function returns a list, the caller can then iterate that list to retrieve its elements (trees in the example), and use them to build an extended result that satisfies the caller's task. In the example case that means that the tree taken from the recursively retrieved list, is appended as a child to a new root. Then this new tree is appended to a new list (not related to the one returned from the recursive call). This new list will in many cases be longer, although this depends on the type of problem.
To further illustrate the way to tackle these problems, here is a solution for the example problem: one which uses the main function for the recursive calls, and using memoization:
class Solution:
memo = { 1: [TreeNode()] }
def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
# If we didn't solve this problem before...
if n not in self.memo:
# Create a list for storing the results (the trees)
results = []
# Before creating any root node,
# decide the size of the left subtree.
# It must be odd
for num_left in range(1, n, 2):
# Make the recursive call to get all shapes of the
# left subtree
left_shapes = self.allPossibleFBT(num_left)
# The remainder of the nodes must be in the right subtree
num_right = n - 1 - num_left # The root also counts as 1
right_shapes = self.allPossibleFBT(num_right)
# Now iterate the results we got from recursion and
# combine them in all possible ways to create new trees
for left in left_shapes:
for right in right_shapes:
# We have a combination. Now create a new tree from it
# by putting a root node on top of the two subtrees:
tree = TreeNode(0, left, right)
# Append this possible shape to our results
results.append(tree)
# All done. Save this for later re-use
self.memo[n] = results
return self.memo[n]
This code can be made more compact using list comprehension, but it may make the code less readable.
Don't pass information into the recursive calls, unless they need that information to compute their local result. It's much easier to reason about recursion when you write without side effects. So instead of having the recursive call put its own results into a list, write the code so that the results from the recursive calls are used to create the return value.
Let's take a trivial example, converting a simple loop to recursion, and using it to accumulate a sequence of increasing integers.
def recursive_range(n):
if n == 0:
return []
return recursive_range(n - 1) + [n]
We are using functions in the natural way: we put information in with the arguments, and get information out using the return value (rather than mutation of the parameters).
In your case:
Now the thing I'm having the most trouble visualising is how exactly I am going to arrive to the list of trees.
So you know that you want to return a list of trees at the end of the process. So the natural way to proceed, is that you expect each recursive call to do that, too.
How can I deal with generating combinations and returning lists of configurations in these cases in recursion? While I gave an example, the more general the answer the better.
The recursive calls return their lists of results for the sub-problems. You use those results to create the list of results for the current problem.
You don't need to think about how recursion is implemented in order to write recursive algorithms. You don't need to think about the call stack. You do need to think about two things:
What are the base cases?
How does the problem break down recursively? (Alternately: why is recursion a good fit for this problem?)
The thing is, recursion is not special. Making the recursive call is just like calling any other function that would happen to give you the correct answer for the sub-problem. So all you need to do is understand how solving the sub-problems helps you to solve the current one.

recursive backtracker algorithm - pseudo code for function that calls itself

I was looking for simple recursive algorithms for randomly generating a maze for a game and I came across an algorithm called recursive backtracking. Since my maze consists of 15 by 15 squares where each cell is either an empty space or a wall, I modified the algorithm slightly:
Fill the grid with walls
Pick a random direction
If the cell in that direction is a wall and doesn't have two empty neighbours, clear that cell
else pick another random direction
If there are no available neighbours remaining, backtrack to the previous cell and try again
My project requires me to use recursive algorithms (I'm using python). This means that I need to use a function that calls itself. Can anyone suggest to me some python/psuedo code that fulfills the above criteria using a function that calls itself?
Example of a recursive algorithm:
def factorial(number):
if number <= 1: #base case
return 1
else:
return number * factorial(number-1)

Generator comprehensions for look ahead algorithm in Python

I called for help yesterday on how to look ahead in Python. My problem was to iterate through all the possible edges to add to a network, and for each possible network with an edge added, look at all the possible edges to add, and so on (n depth). At the end, compare all networks produced at depth n with the root network, and actually add the best first step (best first edge to add to accomplish the best result at depth n). When that first edge is added, do the depth search again, and so on until a good network is found. Like a moving window, I may say (see lookahead algorithm in Python for a more thorough explanation of the problem).
Unfortunately for the clarity of the question, the code requires igraph, which is available here: http://igraph.org/python/#downloads
#Peter Gibson promptly answered, guiding me through the logic of Generator comprehensions, and helped me produce this code:
from igraph import * # http://igraph.org/python/
def delta(g,gOld): # evaluates the improvement of the graph from one generation to the next
print "delta"
return g.diameter()-gOld.diameter()
def possible_new_edges(G):
print "Possible new edges"
allPossibleNewEdges = []
for n1 in range(50):
for n2 in range(n1,50):
if G.are_connected(G.vs[n1],G.vs[n2]) == False and n1 != n2:
allPossibleNewEdges.append(G.vs[n1],G.vs[n2])
return allPossibleNewEdges
def add_optimal_edge(graph, n=3):
print "Add optimal edge"
paths = [[graph]] # start off with just one graph path, which contains a single graph
for generation in range(n):
print "Generation:", generation
# path[-1] is the latest graph for each generation
paths = (path + path[-1].add_edge(e) for path in paths for e in path[-1].possible_new_edges())
# select best path by comparison of final generation against original graph
best = max(paths, lambda path: comp_delta(path[-1],graph))
return best[1] # returns the first generation graph
graph = Graph.Erdos_Renyi(50, .15, directed=False, loops=False) # create a random root graph of density 0.15
add_optimal_edge(graph)
The generator is concise and elegant. Let's say a little too elegant for my unwieldy Python style, and there are a few things I need to understand to make it work. The code runs with this error:
return best[1] # returns the first generation graph
TypeError: 'generator' object has no attribute '__getitem__'
I think it's because of a wrong use of functions with the generator...
So, my question is: what's the proper way to use functions in such a generator? I need to call possible_new_edges() and delta(), what do I need to pass them (the graph?) and how to do so?
Thanks so much!
Trying the code from your gist, I found several fairly minor errors that were preventing the code from running. I've included fixed code below. However, this doesn't really solve the problem. That's because your algorithm needs to consider a truly vast number of potential graphs, which it cannot do in any sort of reasonable time.
In my testing, looking one step ahead works perfectly well, but looking two steps takes a very long time (10s of minutes, at least, I've never waited for it to finish) and three steps will probably take days. This is because your possible_new_edges function returns more than a thousand possible edges. Each one will be added to a copy of your initial graph. Then for each each succeeding step, the process will repeat on each of the expanded graphs from the previous step. This results in an exponential explosion of graphs, as you have to evaluate something on the order of 1000**n graphs to see which is the best.
So, to get a practical result you'll still need to change things. I don't know graph theory or your problem domain well enough to suggest what.
Anyway, here are the changed parts of the "working" code (with the original comments removed so that my notes on what I've changed are more clear):
def possible_new_edges(G):
print("Possible new edges")
allPossibleNewEdges = []
for n1 in range(50):
for n2 in range(n1,50):
if G.are_connected(G.vs[n1],G.vs[n2]) == False and n1 != n2:
allPossibleNewEdges.append((G.vs[n1],G.vs[n2])) # append a tuple
return allPossibleNewEdges
def add_optimal_edge(graph, n=3):
print("Add optimal edge")
paths = [[graph]]
for generation in range(n):
print("Generation:", generation)
paths = (path + [path[-1] + e] # use + to add an edge, and to extend the path
for path in paths
for e in possible_new_edges(path[-1])) # call this function properly
best = max(paths, key=lambda path: comp_delta(path[-1],graph))
return best[1]
If the generator expression in the loop confuses you, it might help to replace it with a list comprehension (by replacing the outermost parentheses with square brackets). You can then inspect the paths list inside the loop (and do things like print its len()). The logic of the code is the same either way, the generator expressions just put off computing the expanded results until the max function starts iterating over paths in order to find the best scoring one.
Using list comprehensions will work for n=1 certainly, but you may start running out of memory as you try n=2 (and you certainly will for n=3 or more). The version above won't you run out of memory (as the generator expression only expands O(n) graphs at a time), but that doesn't mean it runs fast enough to inspect billions of graphs in sensible amount of time.

How To Get A For Loop To Affect Each Individual Object

folks! My question deals with a Python exercise that I'm currently trying to work out (well, to be more specific, the program is Autodesk Maya, but I'm using Python coding). The exercise involves taking a number of objects (spheres) contained in an array/list, and then using an increment variable to have them move in an offset animation. In other words, I want the first sphere to move, then the next spheres to move in a delayed time, then the next sphere with a more delayed time, etc.
The code that I have is as follows:
spheres = mc.ls(selection=True)
count=0
for i in range(len(spheres)):
count+=2
mc.selectKey(spheres)
mc.keyframe(edit=True, relative=True, timeChange=count)
print spheres(i)
The spheres are my objects, and as I said, I want the first to move normally in the timeline, then the next sphere to move with a delayed time of two, then the next to move with a delayed time of four, so on and so forth.
Any help with this would be much appreciated.
Thanks,
E
You're not actually setting the keyframe on the individual sphere; it looks like you're setting it on all spheres
Your for loop is generally bad form, but also less useful. Try changing it to this:
spheres = mc.ls(selection=True)
count=0
for sphere in spheres:
count += 2
mc.selectKey(sphere) # only selecting the one sphere!
mc.keyframe(edit=True, relative=True, timeChange=count)
print sphere # no need to look up the element
# which by the way should have been [i] not (i)
Output:
The keyframes were all lined up originally, but now offset by two frames each from the previous.
You haven't told us what the problem is, but I have a guess. (If I've guessed wrong, please elaborate your question, and I'll delete my answer.)
Are you getting an exception like this?
TypeError Traceback (most recent call last)
----> 1 print spheres(i)
TypeError: 'list' object is not callable
You claim that you have an "array/list" of spheres. If spheres is a list (or array or almost any other kind of collection) you index it using the [] operator. The () operator is used for function calls, not indexing. You're trying to call that list as if it were a function, passing it i as an argument, instead of trying to access that list as a sequence, getting the ith element.
To fix it:
print spheres[i]

how to use python's yield statement

I have a list of items and would like to generate all possible subsets. Therefore I'm using a recursive function with the item number and a list of all selected items as parameters. The function is called with 0 as the first parameter and does the following:
It looks at the item described by the index parameter
It selects it
It calls itself with an incremented index parameter
It deselects the item
It calls itself with an incremented index parameter
I'm needing the possible subsets to optimise something but since the list will get very long, I can't look at all of them. At first I tried to use brute force to take all subsets into consideration but that was a naive idea. Now the new plan is to create a greedy algorithm that takes the first "useful" selection: I want to look at all subsets until I find one that suits my needs and figured that python's yield statement is exactly the right choice. Here's some code:
def bruteForceLeft(selected,index):
#left is the list of which i need subsets
#its a gobal variable. to test the code, just make sure that you have a
#list called left in scope
if index==len(left):
#print(selected)
yield selected
else:
#the algorithm stores the selection in a tuple of two lists
#that's necessary since there's a second list called right as well
#I think you can just ignore this. Think of selected as a list that
#contains the current selection, not a tuple that contains the current
#selection on the right as well as the left side.
selected[0].append(left[index])
bruteForceLeft(selected,index+1)
selected[0].pop()
bruteForceLeft(selected,index+1)
#as you can see I pass a tuple of two empty lists to the function.
#only the first one is used in this piece of code
for option in bruteForceLeft( ([],[]) ,0):
print(option)
#check if the option is "good"
#break
The output is: nothing
At first I thought that I had made an error in generating the subsets, but in the if condition you can see that I have a commented print statement. If I uncomment this print statement and instead comment out the yield statement all the possible choices are printed - and the for loop is broken
With the yield statement the code runs without error, but it doesn't do anything either.
The problem is that when you recursively call bruteForceLeft, the yielded values don't magically get yielded from the enclosing function. So, you need to re-yield them yourself:
def bruteForceLeft(selected,index):
#left is the list of which i need subsets
if index==len(left):
#print(selected)
yield selected
else:
#the algorithm stores the selection in a tuple of two lists
#that's necessary since there's a second list called right as well
#I think you can just ignore this. Think of selected as a list that
#contains the current selection, not a tuple that contains the current
#selection on the right as well as the left side.
selected[0].append(left[index])
for s in bruteForceLeft(selected,index+1):
yield s
selected[0].pop()
for s in bruteForceLeft(selected,index+1):
yield s
(Edit: I actually just tested this, and your code has errors, but I'm pretty sure not re-yielding is the problem)

Categories