Modify a binary tree in python - python

I have a binary tree with 7 elements which currently looks like this:
1
5 2
7 6 4 3
I am trying to traverse it in postorder and relable the elements as I go, so that it looks like this:
7
3 6
1 2 4 5
using the following function, which is part of my Tree class:
def relable(self, h):
if self.root is not None:
self._relable(self.root, h)
def _relable(self, node, h):
if node is not None:
self._relable(node.l, h-2)
self._relable(node.r, h-1)
node = Node(h)
The rest of my Tree class is more or less the same as the one here.
I populated the tree by adding the numbers 1-7 in a loop.
However, when I call tree.relable(7), and then print the tree, the tree is the same.
I'm guessing this has something to do with how Python passes arguments (I'm a C++ programmer) but I don't know how to fix this.
The entirety of my code can be fount here.

node = Node(h) is just assigning a local variable, it doesn't have any effect on the node parameter that was passed to the function. You need to actually modify the node, i.e. node.v = h.

Related

Implementing multiple branching rules in the same branch and bound tree in PySCIPOpt

I would like to implement a custom branching rule initially (for a few nodes in the top of the tree), and then use Scip's implementation of vanilla full strong branching rule (or some other rule like pseudocost). Is this possible to do using/by extending
PySCIPOpt?
import pyscipopt as scip
import random
class oddevenbranch(scip.Branchrule):
def branchexeclp(self, allowaddcons):
'''
This rule uses the branching rule I have defined if the node number is odd,
and should use strong branching otherwise.
'''
node_ = self.model.getCurrentNode()
num = node_.getNumber()
if num % 2 == 1:
candidate_vars, *_ = self.model.getLPBranchCands()
branch_var_idx = random.randint(0,len(candidate_vars)-1)
branch_var = candidate_vars[branch_var_idx]
self.model.branchVar(branch_var)
result = scip.SCIP_RESULT.BRANCHED
return {"result": result}
else:
print(num, ': Did not branch')
result = scip.SCIP_RESULT.DIDNOTRUN
return {"result": result}
if __name__ == "__main__":
m1 = scip.Model()
m1.readProblem('xyz.mps') # Used to read the instance
m1.setIntParam('branching/fullstrong/priority', 11000)
branchrule = oddevenbranch()
m1.includeBranchrule(branchrule=branchrule,
name="CustomRand", # name of the branching rule
desc="", # description of the branching rule
priority=100000, # priority: set to this to make it default
maxdepth=-1, # maximum depth up to which it will be used, or -1 for no restriction
maxbounddist=1) # maximal relative distance from current node's dual bound to primal
m1.optimize()
I wonder what is causing this behavior. Does it need to call branching multiple times to perform strong branching?
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
2 : Did not branch
I believe you can achieve this effect. SCIP has several branching rules and executes them one by one according to their priorities until one of them produces a result.
The default rule "relpscost" has a priority of 10000, so you should create a custom rule with a higher priority.
If you do not want to use your own rule at a node (deeper in the tree), you can
decide in the branchexeclp(allowedcons) callback of your rule to return a dict
{'result': pyscipopt.SCIP_RESULT.DIDNOTRUN}
which should inform SCIP that your rule did not execute and should be skipped, in which case the "relpscost" rule should take over (see here).
Edit: It is not quite obvious to me how your instance looks like so I am guessing a bit here: I think you are right in assuming that the multiple calls at node 2 are due to the strong branching. You can check by switching to another backup strategy, such as "mostinf".
Additionally, it is really helpful to check out the statistics by calling model.printStatistics() after the optimization has finished. I tried your code on the "cod105" instance of the MIPlIB benchmarks and similarly found a set of "Did not branch" outputs. The (abbreviated) statistics regarding branching rules are the following:
Branching Rules : ExecTime SetupTime BranchLP BranchExt BranchPS Cutoffs DomReds Cuts Conss Children
CustomRand : 0.00 0.00 1 0 0 0 0 0 0 2
fullstrong : 5.32 0.00 7 0 0 0 7 0 3 0
So the fallback rule is in fact called several times. Apparently, the "fullstrong" rule calls "CustomRand" internally, though this is not reflected in the actual statistics...

NetworkX find root_node for a particular node in a directed graph

Suppose I have a directed graph G in Network X such that:
G has multiple trees in it
Every node N in G has exactly 1 or 0
parent's.
For a particular node N1, I want to find the root node of the tree it resides in (its ancestor that has a degree of 0). Is there an easy way to do this in network x?
I looked at:
Getting the root (head) of a DiGraph in networkx (Python)
But there are multiple root nodes in my graph. Just only one root node that happens to be in the same tree as N1.
edit Nov 2017 note that this was written before networkx 2.0 was released. There is a migration guide for updating 1.x code into 2.0 code (and in particular making it compatible for both)
Here's a simple recursive algorithm. It assumes there is at most a single parent. If something doesn't have a parent, it's the root. Otherwise, it returns the root of its parent.
def find_root(G,node):
if G.predecessors(node): #True if there is a predecessor, False otherwise
root = find_root(G,G.predecessors(node)[0])
else:
root = node
return root
If the graph is a directed acyclic graph, this will still find a root, though it might not be the only root, or even the only root ancestor of a given node.
I took the liberty of updating #Joel's script. His original post did not work for me.
def find_root(G,child):
parent = list(G.predecessors(child))
if len(parent) == 0:
print(f"found root: {child}")
return child
else:
return find_root(G, parent[0])
Here's a test:
G = nx.DiGraph(data = [('glu', 'skin'), ('glu', 'bmi'), ('glu', 'bp'), ('glu', 'age'), ('npreg', 'glu')])
test = find_root(G, "age")
age
glu
npreg
found root: npreg
Networkx - 2.5.1
The root/leaf node can be found using the edges.
for node_id in graph.nodes:
if len(graph.in_edges(node_id)) == 0:
print("root node")
if len(graph.out_edges(node_id)) == 0:
print("leaf node")
In case of multiple roots, we can do something like this:
def find_multiple_roots(G, nodes):
list_roots = []
for node in nodes:
predecessors = list(G.predecessors(node))
if len(predecessors)>0:
for predecessor in predecessors:
list_roots.extend(find_root(G, [predecessor]))
else:
list_roots.append(node)
return list_roots
Usage:
# node need to be passed as a list
find_multiple_roots(G, [node])
Warning: This recursive function can explode pretty quick (the number of recursive functions called could be exponentially proportional to the number of nodes exist between the current node and the root), so use it with care.

How do I build a tree dynamically in Python

A beginner Python/programming question... I'd like to build a tree structure in Python, preferably based on dictionaries. I found code that does this neatly:
Tree = lambda: collections.defaultdict(Tree)
root = Tree()
This can easily be populated like:
root['toplevel']['secondlevel']['thirdlevel'] = 1
root['toplevel']['anotherLevel'] = 2
...etc.
I'd like to populate the levels/leaves dynamically so that I can add as many levels as needed, and where the leaves can be at any level. How do I do that?
Any help is greatly appreciated.
You can simply do it with a utility function, like this
def add_element(root, path, data):
reduce(lambda x, y: x[y], path[:-1], root)[path[-1]] = data
You can use it, like this
import collections
tree = lambda: collections.defaultdict(tree)
root = tree()
add_element(root, ['toplevel', 'secondlevel', 'thirdlevel'], 1)
add_element(root, ['toplevel', 'anotherlevel'], 2)
print root
Output
defaultdict(<function <lambda> at 0x7f1145eac7d0>,
{'toplevel': defaultdict(<function <lambda> at 0x7f1145eac7d0>,
{'secondlevel': defaultdict(<function <lambda> at 0x7f1145eac7d0>,
{'thirdlevel': 1}),
'anotherlevel': 2
})
})
If you want to implement this in recursive manner, you can take the first element and get the child object from current root and strip the first element from the path, for the next iteration.
def add_element(root, path, data):
if len(path) == 1:
root[path[0]] = data
else:
add_element(root[path[0]], path[1:], data)
aah! this was a problem for me when I started coding as well, but the best of us come across this early.
Note; this is for when your tree is going N levels deep. where N is between 0 and infinite, ie; you don't know how deep it can go; it may only have a first level, or it may go up to a 20th level
your problem is a general programming problem; reading in a tree that could be any number of levels deep and the solution to that is; Recursion.
whenever reading in a tree structure, you have to;
1 - build up an object
2 - check whether the object has children
2a - if the object has children, do steps 1 and 2 for each child.
here's a code template in python for doing this;
def buildTree(treeObject):
currObject = Hierarchy()
currObject.name = treeObject.getName()
currObject.age = treeObject.getAge()
#as well as any other calculations and values you have to set for that object
for child in treeObject.children:
currChild = buildTree(child)
currObject.addChild(currChild)
#end loop
return currObject
This
root['toplevel']['secondlevel']['thirdlevel'] = 1
can also be done like this:
node = root
for key in ('toplevel', 'secondlevel'):
node = node[key]
node['thirdlevel'] = 1
I hope that gives you an idea.

Finding the (guaranteed unique) path between two nodes in a tree

I have a (likely) simple graph traversal question. I'm a graph newbie using networkx as my graph data structures. My graphs always look like this:
0
1 8
2 3 9 10
4 5 6 7 11 12 13 14
I need to return the path from the root node to a given node (eg., path(0, 11) should return [0, 8, 9, 11]).
I have a solution that works by passing along a list which grows and shrinks to keep track of what the path looks like as you traverse the tree, ultimately getting returned when the target node is found:
def VisitNode(self, node, target, path):
path.append(node)
# Base case. If we found the target, then notify the stack that we're done.
if node == target:
return True
else:
# If we're at a leaf and it isn't the target, then pop the leaf off
# our path (backtrack) and notify the stack that we're still looking
if len(self.neighbors(node)) == 0:
path.pop()
return False
else:
# Sniff down the next available neighboring node
for i in self.neighbors_iter(node):
# If this next node is the target, then return the path
# we've constructed so far
if self.VisitNode(i, target, path):
return path
# If we've gotten this far without finding the target,
# then this whole branch is a dud. Backtrack
path.pop()
I feel in my bones that there is no need for passing around this "path" list... I should be able to keep track of that information using the call stack, but I can't figure out how... Could someone enlighten me on how you would solve this problem recursively using the stack to keep track of the path?
You could avoid passing around the path by returning None on failure, and a partial path on success. In this way, you do not keep some sort of 'breadcrumb trail' from the root to the current node, but you only construct a path from the target back to the root if you find it. Untested code:
def VisitNode(self, node, target):
# Base case. If we found the target, return target in a list
if node == target:
return [node]
# If we're at a leaf and it isn't the target, return None
if len(self.neighbors(node)) == 0:
return None
# recursively iterate over children
for i in self.neighbors_iter(node):
tail = self.VisitNode(i, target)
if tail: # is not None
return [node] + tail # prepend node to path back from target
return None #none of the children contains target
I don't know the graph library you are using, but I assume that even leafs contain a neighbours_iter method, which obviously shouldn't yield any children for a leaf. In this case, you can leave out the explicit check for a leaf, making it a bit shorter:
def VisitNode(self, node, target):
# Base case. If we found the target, return target in a list
if node == target:
return [node]
# recursively iterate over children
for i in self.neighbors_iter(node):
tail = self.VisitNode(i, target)
if tail: # is not None
return [node] + tail # prepend node to path back from target
return None # leaf node or none of the child contains target
I also removed some of the else statements, since inside the true-part of the if you are returning from the function. This is common refactering pattern (which some old-school people don't like). This removes some unnecessary indentation.
You can avoid your path argument at all having path initialized in the method's body. If method returns before finding a full path, it may return an empty list.
But your question is also about using a stack instead of a list in Depth-First-search implementation, right? You get a flavor here: http://en.literateprograms.org/Depth-first_search_%28Python%29.
In a nutshell, you
def depthFirstSearch(start, isGoal, result):
###ensure we're not stuck in a cycle
result.append(start)
###check if we've found the goal
###expand each child node in order, returning if we find the goal
# No path was found
result.pop()
return False
with
###<<expand each child node in order, returning if we find the goal>>=
for v in start.successors:
if depthFirstSearch(v, isGoal, result):
return True
and
###<<check if we've found the goal>>=
if isGoal(start):
return True
Use networkx directly:
all_simple_paths(G, source, target, cutoff=None)

python and fast lookups of a tree where nodes have multiple attrubutes and values

I need a tree object in python that is very fast. Speed of the lookup is more important than memory. The leaf node is the value that I want.
So, if given state=NY, postion=3, hourOfDay=2 and dayOfWeek=3 I need to get the value =100 with speed. The nodes with a * are a leaf node.
0) root
1) {state: [NY,LA]}
2) {howOfDay:[1,2,3,4,5], postion:[1,2,3]}
*3) {dayOfWeek:[234]} => value:100
4) {state: [FL,NV,……rest of the states]}
5) {howOfDay:[1,6,7,8,9….23]}
*6) {dayOfWeek:[1,5,6,7]} => value:120
In my database my data looks like this with the attributes as json objects.
parent child attribute value
0 1 state NY,LA
1 2 {howOfDay:[1,2,3,4,5], postion:[1,2,3]}
2 3 dayOfWeek dayOfWeek [2,3,4] 100
0 3 state [FL,NV,……rest of the states]
4 5 howOfDay:[1,6,7,8,9….23]
5 6 dayOfWeek:[1,5,6,7] 120
So, what python library and tree structure should i use to best find a value? How do a convert the data to best do a fast lookup?
If you value speed over memory you can put all you data into a dictionaly, using a tuple(state, position, hourOfDay, dayOfWeed) as key.
data = dict()
Now, for each leave node, insert the data into the dictionary:
data[state, position, hourOfDay, dayOfWeed] = value
You then access data using
value = data[state, position, hourOfDay, dayOfWeed]
This is faster than any tree traversal as it uses the underlying optimized CPython implementation of a hashed dictionary.

Categories