I am trying to adapt this code here: https://github.com/nachonavarro/gabes/blob/master/gabes/circuit.py (line 136)
but am coming across an issue because several times the attribute .chosen_label is used but I can find no mention of it anywhere in the code. The objects left_gate, right_gate and gate are Gate objects (https://github.com/nachonavarro/gabes/blob/master/gabes/gate.py)
def reconstruct(self, labels):
levels = [[node for node in children]
for children in anytree.LevelOrderGroupIter(self.tree)][::-1]
for level in levels:
for node in level:
gate = node.name
if node.is_leaf:
garblers_label = labels.pop(0)
evaluators_label = labels.pop(0)
else:
left_gate = node.children[0].name
right_gate = node.children[1].name
garblers_label = left_gate.chosen_label
evaluators_label = right_gate.chosen_label
output_label = gate.ungarble(garblers_label, evaluators_label)
gate.chosen_label = output_label
return self.tree.name.chosen_label
The code runs without error and the .chosen_label is a Label object (https://github.com/nachonavarro/gabes/blob/master/gabes/label.py)
Any help would be much appreciated
The attribute is set in the same method:
for level in levels:
for node in level:
gate = node.name
if node.is_leaf:
# set `garblers_label` and `evaluators_label` from
# the next two elements of the `labels` argument
else:
# use the child nodes of this node to use their gates, and
# set `garblers_label` and `evaluators_label` to the left and
# right `chosen_label` values, respectively.
# generate the `Label()` instance based on `garblers_label` and `evaluators_label`
output_label = gate.ungarble(garblers_label, evaluators_label)
gate.chosen_label = output_label
I'm not familiar with the anytree library, so I had to look up the documentation: the anytree.LevelOrderGroupIter(...) function orders the nodes in a tree from root to leaves, grouped by level. The tree here appears to be a balanced binary tree (each node has either 0 or 2 child nodes), so you get a list with [(rootnode,), (level1_left, level1_right), (level2_left_left, level2_left_right, level2_right_left, level2_right_right), ...]. The function loops over these levels in reverse order. This means that leaves are processed first.
Once all node.is_leaf nodes have their chosen_label set, the other non-leaf nodes can reference the chosen_label value on the leaf nodes on the level already processed before them.
So, assuming that labels is a list with at least twice the number of leaf nodes in the tree, you end up with those label values aggregated at every level via the gate.ungarble() function, and the final value is found at the root node via self.tree.name.chosen_label.
Related
I'm working with a networkx graph graph in which each node is converted to an object with specified attributes such node_x.colour where x in range(0, len(graph)). All node objects are stored in self.nodes = [...]. Each node also has an associated neighbors list adjacent_nodes = [...] which contains the indices of the graph nodes it is connected to and is accessed via node_x.adjacent_nodes.
I have a separate list voting_nodes = [...] which stores all the nodes in graph that have an attribute of 'opinion' equal to 1 i.e. if node_x.opinion = 1, append it to voting_nodes
I want to get the node i in the graph such that node_i in voting_nodes and has the most neighbors in voting_nodes out of all other nodes in voting_nodes.
My attempt was:
max_vote_count = 0
# Voting node with the most voting neighbors. Will be type object.
best_voting_node = 0
for node in voting_nodes:
vote_count = 0
if node.adjacent_nodes:
for neigh_node in node.adjacent_nodes:
# self.nodes[neigh_node] gets the corresponding node object of index neigh_node
if self.nodes[neigh_node] in voting_nodes:
vote_count += 1
if vote_count > max_vote_count:
max_vote_count = vote_count
best_voting_node = node
However, the code returns 0 as the max_vote_count and best_voting_node everytime, even if nearly all nodes in graph are connected. What is the error and is there a better approach?
from link import Link
from node import Node
from path import Path
from od import OD
import sys
import traceback
import utils
class BadNetworkOperationException(Exception):
"""
You can raise this exception if you try a network action which is invalid
(e.g., trying to find a topological order on a network with cycles.)
"""
pass
class Network:
"""
This is the class used for transportation networks. It uses the following
dictionaries to store the network; the keys are IDs for the network elements,
and the values are objects of the relevant type:
node -- network nodes; see node.py for description of this class
link -- network links; see link.py for description of this class
ODpair -- origin-destination pairs; see od.py
path -- network paths; see path.py. Paths are NOT automatically generated
when the network is initialized (you probably wouldn't want this,
the number of paths is exponential in network size.)
The network topology is expressed both in links (through the tail and head
nodes) and in nodes (forwardStar and reverseStar are Node attributes storing
the IDs of entering and leaving links in a list).
numNodes, numLinks, numZones -- self-explanatory
firstThroughNode -- in the TNTP data format, transiting through nodes with
low IDs can be prohibited (typically for centroids; you
may not want vehicles to use these as "shortcuts").
When implementing shortest path or other routefinding,
you should prevent trips from using nodes with lower
IDs than firstThroughNode, unless it is the destination.
"""
def init(self, networkFile="", demandFile=""):
"""
Class initializer; if both a network file and demand file are specified,
will read these files to fill the network data structure.
"""
self.numNodes = 0
self.numLinks = 0
self.numZones = 0
self.firstThroughNode = 0
self.node = dict()
self.link = dict()
self.ODpair = dict()
self.path = dict()
if len(networkFile) > 0 and len(demandFile) > 0:
self.readFromFiles(networkFile, demandFile)
def findLeastEnteringLinks(self):
"""
This method should return the ID of the node with the least number
of links entering the node. Ties can be broken arbitrarily.
"""
# *** YOUR CODE HERE ***
# Replace the following statement with your code.
# raise utils.NotYetAttemptedException
minvalue = 1000
for i in self.node:
if (minvalue > len(self.node[i].reverseStar)):
minvalue = len(self.node[i].reverseStar)
idnode= i
return idnode
def formAdjacencyMatrix(self):
"""
This method should produce an adjacency matrix, with rows and columns
corresponding to each node, and entries of 1 if there is a link connecting
the row node to the column node, and 0 otherwise. This matrix should
be stored in self.adjacencyMatrix, which is a dictionary of dictionaries:
the first key is the "row" (tail) node, and the second key is the "column"
(head) node.
"""
self.adjacencyMatrix = dict()
for i in self.node:
self.adjacencyMatrix[i] = dict()
# *** YOUR CODE HERE ***
# Replace the following statement with your code.
# raise utils.NotYetAttemptedException
for i in self.node:
for j in self.node:
self.adjacencyMatrix[i][j]=0
for ij in self.link:
self.adjacencyMatrix[self.link[ij].tail][self.link[ij].head]=1
return self.adjacencyMatrix
def findTopologicalOrder(self):
"""
This method should find a topological order for the network, storing
the order in the 'order' attribute of the nodes, i.e.:
self.node[5].order
should store the topological label for node 5.
The topological order is generally not unique, this method can return any
valid order. The nodes should be labeled 1, 2, 3, ... up through numNodes.
If the network has cycles, a topological order does not exist. The presence
of cycles can be detected in the algorithm for finding a topological order,
and you should raise an exception if this is detected.
"""
# *** YOUR CODE HERE ***
# Replace the following statement with your code.
# raise utils.NotYetAttemptedException
for i in self.node:
self.node[i].order = []
node_list= list()
for i in self.node:
if len(self.node[i].reverseStar) == 0:
node_list.append(i)
break
if len(node_list)== 0:
raise BadNetworkOperationException()
while (len(node_list)!=self.numNodes):
for i in [x for x in self.node if x not in node_list]:
incoming_nodes = [int(j[1]) for j in self.node[i].reverseStar if j not in node_list]
if (len(incoming_nodes)== 0):
node_list.append(i)
break
for k in range(len(node_list)):
self.node[node_list[k]].order = k+1
return self.node[i].order
I have an interesting python "network" challenge. Not sure what data construct to use and am hoping to learn something new from the experts!
The following is a snippet from an ordered table (see SORT column) with a FROM NODE and TO NODE. This table represents a hydrologic network (watershed sequencing) from upstream to downstream. TO NODE = 0 indicates the bottom of the network.
Given there can be many branches, how does one traverse a network from any given FROM NODE to TO NODE = 0 and store the list of nodes that are sequenced over?
For example, starting at:
HYBAS_ID (this is same as FROM NODE)= 2120523430
see <---- about 2/3rd way down, the sequence of Nodes would include the following:
[2120523430, 2120523020, 2120523290, 2120523280,2120523270,2120020790, 0]
Table:
SORT FROM NODE TO NODE
30534 2121173490 2120522070
30533 2120521930 2120521630
30532 2120522070 2120521630
30531 2120521620 2120522930
30530 2120521630 2120522930
30529 2121172200 2121173080
30528 2120522930 2120523360
30527 2120522940 2120523360
30526 2120519380 2120523170
30525 2120519520 2120523170
30524 2120523440 2120523350
30523 2120523360 2120523350
30522 2120525750 2120523430
30521 2120525490 2120523430
30520 2121173080 2120522820
30519 2120523430 2120523020 <------- if you start network here
30518 2120523350 2120523020
30517 2120522820 2120523290
30516 2120523020 2120523290 <------ the second node is here
30515 2120523170 2120523280
30514 2120523290 2120523280 <------ third node here
30513 2120523160 2120523270
30512 2120523280 2120523270 <------ fourth
30511 2120523150 2120020790
30510 2120523270 2120020790 <------ fifth
30509 2120020790 0 <------ End.
Would a dictionary and some kind of graph structure work to traverse this network? The code may be fed a list of thousands or millions of FROM NODES to calculate the routing so efficiency is important.
The standard way to do this is with an unordered dictionary representing a directed graph, and then to iterate through it. First you have to populate the dictionary (which let's say is a csv for the sake of argument), and then iterate through the values. so
my_graph = {}
with open("myfile.csv") as f:
for l in f:
split_lines = l.split(",")
my_graph[int(split_lines[1])] = int(split_lines[2])
HYBAS_ID = 2120523430
current_hybas = my_graph[HYBAS_ID]
return_value = [HYBAS_ID]
while current_hybas != 0:
return_value.append(current_hybas)
current_hybas = my_graph[current_hybas]
print return_value
Should approximately get you what you want.
I am trying to prune decision trees, using some procedure.
After i do sorts of manipulations on the current tree, i get different values from the function validate() (inside prune_helper, by print(self.validate(validation_data))) - before and after manipulating the tree, which is great (It means that something does happen to the tree for a given node).
def prune_helper(self, curr_node):
all_err = []
# The current tree.
tree_1 = self
all_err.append((tree_1._generalization_error(), tree_1))
# Replace node with leaf 1.
tree_2 = self._replace_leaf(curr_node, DEMOCRAT)
all_err.append((tree_2._generalization_error(), tree_2))
# Replace node with leaf 0.
tree_3 = self._replace_leaf(curr_node, REPUBLICAN)
all_err.append((tree_3._generalization_error(), tree_3))
# Replace node with left subtree.
test_4 = self._replace_subtree(curr_node, LEFT)
all_err.append((test_4._generalization_error(), test_4))
# Replace node with middle subtree.
test_5 = self._replace_subtree(curr_node, MIDDLE)
all_err.append((test_5._generalization_error(), test_5))
# Replace node with right subtree.
test_6 = self._replace_subtree(curr_node, RIGHT)
all_err.append((test_6._generalization_error(), test_6))
all_err.sort(key=lambda tup: tup[0])
min_tree = all_err[0][1]
# print(self.validate(validation_data)) <-- This
self = copy.deepcopy(min_tree)
# print(self.validate(validation_data)) <-- Mostly different than this
curr_node.pruned = True
def prune(self, curr_node=None):
if curr_node is None:
curr_node = self._root
# Node is leaf.
if curr_node.leaf:
self.prune_helper(curr_node=curr_node)
return
# Node is not a leaf, we may assume that he has all three children.
if curr_node.left.pruned is False:
self.prune(curr_node=curr_node.left)
if curr_node.middle.pruned is False:
self.prune(curr_node=curr_node.middle)
if curr_node.right.pruned is False:
self.prune(curr_node=curr_node.right)
# We'll prune the current node, only if we checked all of its children.
self.prune_helper(curr_node=curr_node)
But the problem is, when i want to calculate some value for the tree after prunning it "completely", i get the same value returned by validate(), which means that maybe the tree wasnt changed afterall, and the effect on the tree only took place in prune_tree-
def prune_tree(tree):
# print(tree.validate(validation_data)) <- This
tree.prune()
# print(tree.validate(validation_data)) <- Same as this
tree.print_tree('after')
I think that maybe the problem is with the way i try to change the self object or something. Is there anything obvious that i've done wrong implementing the whole thing that may lead to this results?
I'm not quite sure where the problem is in this script. What I've done is this....
I have a scene with 2 curves. Each curve has three spheres linked to it.
I select the curves and run the script. It craps out and says I've got objects with matching names?
import maya.cmds as cmds
selection = cmds.ls(selection=True, type='dagNode')
# groups of ![enter image description here][1]nodes to be exported out
nodeBundles = []
for n in selection:
# list the children nodes
children = cmds.listRelatives(n, allDescendents=True, noIntermediate=True, fullPath=True, type="dagNode", path=True)
# list the transform nodes to each child node
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True)
# append each set of children to a unique array and then append to main array
nodeBundles.append(childrenTransforms)
# select the transform nodes
# cmds.select(childrenTransforms)
# MXS cache out each bundle of nodes
for n in nodeBundles:
cmds.select(clear=True)
cmds.xform(n, absolute=True, t=[0,0,10])
print n
FIXED CODE:
import maya.cmds as cmds
selection = cmds.ls(selection=True, type='dagNode')
# groups of ![enter image description here][1]nodes to be exported out
nodeBundles = []
for n in selection:
# list the children nodes
children = cmds.listRelatives(n, allDescendents=True, noIntermediate=True, fullPath=True, type="dagNode", path=True)
# list the transform nodes to each child node
# childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True)
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True, fullPath=True)
# append each set of children to a unique array and then append to main array
nodeBundles.append(childrenTransforms)
# select the transform nodes
# cmds.select(childrenTransforms)
# MXS cache out each bundle of nodes
for n in nodeBundles:
cmds.select(clear=True)
cmds.xform(n, r=True, t=[0,0,10])
print n
By adding a list inside of a list I can then iterated based on groups of children. is this the correct method of doing so then?
nodes = []
for item in cmds.ls(sl=True, type = 'transform'):
descendants = cmds.listRelatives(ad=True, ni=True, f=True) or []
# nodes += descendants # append the list, not insert it
nodes.append(descendants)
val = 1
for grp in nodes:
for n in grp:
cmds.select(clear=True)
offset = val * 10
print offset
cmds.xform(n, r=True, t=[0,0,offset])
val += 1
Without seeing your scene or error message, my assumption is you have multiple nodes of the same name. Because Maya uses strings, it can't tell the difference between pSphere1 and... pSphere1
From the documentation on listRelatives, use the argument fullPath:
Return full pathnames instead of object names.
Like this:
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True, fullPath=True)
Assuming the error was in the last cmds.xform, this should make those transforms unambiguous (i.e. |group1|pSphere1)
listRelatives will work on selected objects if nothing is specified, so you can get the subnodes (with full paths) like this:
descendants = cmds.listRelatives(ad=True, ni=True, f=True) # f=True = long paths
If you were trying to use 'dagNode' to filter between shapes and geometry, it wont' work: dagNode will return both transforms and shapes. You can use 'geometryShape' to get only shapes:
descendant_shapes = cmds.listRelatives(ad=True, ni = True, f=True)
but in your case that would return the curveShape as well. You could filter out the curve with:
descendants = cmds.ls(descendants, type= surfaceShape, l=True) # l=True keeps long paths
Also: in you code you are passing lists-of-lists into nodeBundles, which Maya won't like. You should flatten the list by adding items one at a time:
nodes = []
for item in cmds.ls(sl=True, type = 'transform'):
descendants = cmds.listRelatives(ad=True, ni=True, f=True) or []
nodes += descendants # append the list, not insert it
for n in nodes:
cmds.select(clear=True)
cmds.xform(n, r=True, t=[0,0,10])