I am trying to implement the Hopcroft Karp algorithm in Python using networkx as graph representation.
Currently I am as far as this:
#Algorithms for bipartite graphs
import networkx as nx
import collections
class HopcroftKarp(object):
INFINITY = -1
def __init__(self, G):
self.G = G
def match(self):
self.N1, self.N2 = self.partition()
self.pair = {}
self.dist = {}
self.q = collections.deque()
#init
for v in self.G:
self.pair[v] = None
self.dist[v] = HopcroftKarp.INFINITY
matching = 0
while self.bfs():
for v in self.N1:
if self.pair[v] and self.dfs(v):
matching = matching + 1
return matching
def dfs(self, v):
if v != None:
for u in self.G.neighbors_iter(v):
if self.dist[ self.pair[u] ] == self.dist[v] + 1 and self.dfs(self.pair[u]):
self.pair[u] = v
self.pair[v] = u
return True
self.dist[v] = HopcroftKarp.INFINITY
return False
return True
def bfs(self):
for v in self.N1:
if self.pair[v] == None:
self.dist[v] = 0
self.q.append(v)
else:
self.dist[v] = HopcroftKarp.INFINITY
self.dist[None] = HopcroftKarp.INFINITY
while len(self.q) > 0:
v = self.q.pop()
if v != None:
for u in self.G.neighbors_iter(v):
if self.dist[ self.pair[u] ] == HopcroftKarp.INFINITY:
self.dist[ self.pair[u] ] = self.dist[v] + 1
self.q.append(self.pair[u])
return self.dist[None] != HopcroftKarp.INFINITY
def partition(self):
return nx.bipartite_sets(self.G)
The algorithm is taken from http://en.wikipedia.org/wiki/Hopcroft%E2%80%93Karp_algorithm
However it does not work. I use the following test code
G = nx.Graph([
(1,"a"), (1,"c"),
(2,"a"), (2,"b"),
(3,"a"), (3,"c"),
(4,"d"), (4,"e"),(4,"f"),(4,"g"),
(5,"b"), (5,"c"),
(6,"c"), (6,"d")
])
matching = HopcroftKarp(G).match()
print matching
Unfortunately this does not work, I end up in an endless loop :(. Can someone spot the error, I am out of ideas and I must admit that I have not yet fully understand the algorithm, so it is mostly an implementation of the pseudo code on wikipedia
The line
if self.pair[v] and self.dfs(v):
should be
if self.pair[v] is None and self.dfs(v):
as per the pseudo-code on the Wikipedia page. The only other problem I see is that you are using the deque as a stack and you want to use it as a queue. To remedy that, you just need to popleft rather than pop (which pops right). So the line
v = self.q.pop()
should be
v = self.q.popleft()
Hopefully everything else works. I was just checking that your Python code works in the same manner as the pseudocode on Wikipedia so hopefully that pseudocode is correct.
In python there is a package for this algorithm.
HopcroftKarp, you can directly use that package for your implementation.
Related
So I am trying to map all the rotation angles present into the range of 0<angle<360, at every key points for all the mesh objects present in the selected group, this is the approach i took to get all the objects but i am struggling at the keypoint partBY KEYPOINT I MEANT THE MARKED PART IN THE IMAGE
import maya.cmds as cmds
grps = []
subgroups = []
objs = []
rotation_keys = set()
attributes = ['rotateX','rotateY','rotateZ']
for i in cmds.ls():
if "_SET" in i:
grps.append(i)
for g in grps:
subgroups.append(cmds.listRelatives(g))
for sg in subgroups:
objs.extend(cmds.listRelatives(sg))
for attrib in attributes:
for key in cmds.keyframe(obj, attribute = attrib, q=True, tc=True):
rotation_keys.append(key)
print(rotation_keys)
But after this i am kinda lost, i have already created the function to map the angles tho so i don't have any issue regarding that, but how should i access all of they keys and change rotation values on each of them.
Thanks & Regards
Kartikey
I don't have maya anymore but here is how I was saving animated attributes, you will have to adapt the code as it is used inside my set of coding :
def getAnimatedAttr(node=list):
"""
:param node: object list
:return: list of animated channels
"""
myAttrAnimated = []
for n in node:
testT = cmds.listConnections(n.transform, type='animCurve', d=True)
testS = cmds.listConnections(n.shape, type='animCurve', d=True)
if testT:
myAttrAnimated += cmds.listConnections(testT, p=True)
if testS:
myAttrAnimated += cmds.listConnections(testS, p=True)
return myAttrAnimated
def saveAnimatedAttr(node=list, presetName='', path=''):
"""
:param node: list of python object
:param presetName: string
:param path: if no path, it go for ncache
:return: True
"""
# add a loop if there is a list ?
attrs = getAnimatedAttr(node)
tmpDic = {}
for i in attrs:
myTicks = cmds.keyframe(node, q=1, at= i.split('.')[-1])
myValues = cmds.keyframe(node, q=1, at= i.split('.')[-1], valueChange=True)
tmpDic[i] = zip(myTicks, myValues)
if path == '':
path = make_dir()
path = path + '/{0}.json'.format(presetName)
else:
path = path + '/{0}.json'.format(presetName)
output = path.replace('/', '//')
js.saveJson(output, tmpDic)
return True
So hey everyone , actually I kind of succeeded in writing the program for it , I guess it can be more optimized and we can eliminate few of the loops, but yeah here it is
def angleMapper():
subgroups = []
objs = []
grps = cmds.ls('*_SET')
for g in grps:
subgroups.extend(cmds.listRelatives(g))
for sg in subgroups:
objs.extend(cmds.listRelatives(sg))
data = {obj:[] for obj in objs}
for obj in data.keys():
keyframeValue = cmds.keyframe(obj+".rotateX", q=True)
if keyframeValue is not None:
data[obj].extend(keyframeValue)
for obj in data.keys():
keyframeValue = cmds.keyframe(obj+".rotateY", q=True)
if keyframeValue is not None:
data[obj].extend(keyframeValue)
for obj in data.keys():
keyframeValue = cmds.keyframe(obj+".rotateZ", q=True)
if keyframeValue is not None:
data[obj].extend(keyframeValue)
for k,v in data.items():
data[k] = list(set(data[k]))
for k,v in data.items():
if len(v)>=1:
for t in v:
rotateX = cmds.getAttr(k+'.rotateX', time = t)
cmds.setKeyframe(k, attribute='rotateX', v= rotateX%360, t=t)
for k,v in data.items():
if len(v)>=1:
for t in v:
rotateY = cmds.getAttr(k+'.rotateY', time = t)
cmds.setKeyframe(k, attribute='rotateY', v= rotateY%360, t=t)
for k,v in data.items():
if len(v)>=1:
for t in v:
rotateZ = cmds.getAttr(k+'.rotateZ', time = t)
cmds.setKeyframe(k, attribute='rotateZ', v= rotateZ%360, t=t)
Hope it will give you a rough idea, and any help in optimizing it will be great
Thanks
Kartikey
Sudoku is a well known CSP and, in this case, LC problem. I don't need the solution, which follows.
My question is why does self.DOMAIN = "123456789" (line #4) work, whereas self.DOMAIN = map(str, range(1, 10)) (line #5) does not? Are they not equivalent?
class Solution:
def __init__(self):
self.SIZE = 9
# self.DOMAIN = map(str, range(1, self.SIZE + 1)) # THIS DES NOT WORK NOT WORK
self.DOMAIN = "123456789" # THIS WORKS
self.EMPTY = "."
from collections import defaultdict
self.rows = defaultdict(set) # {row:set}
self.cols = defaultdict(set) # {col:set}
self.boxs = defaultdict(set) # {box:set}
self.row_idx = lambda cell: cell // self.SIZE # determines row from cell num
self.col_idx = lambda cell: cell % self.SIZE # determins col from cell num
self.box_idx = lambda r, c: (r // 3) * 3 + c // 3 # determines box from row, col
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
assert(len(board) == self.SIZE and len(board[0]) == self.SIZE), \
"Sudoku board must be 9x9 in dimensions"
# Initialize board state
self.board = board
for r in range(self.SIZE):
for c in range(self.SIZE):
val = self.board[r][c]
if val != self.EMPTY:
self.rows[r].add(val)
self.cols[c].add(val)
self.boxs[self.box_idx(r, c)].add(val)
# Begin backtracking search from the first cell
self.backtrack(0)
def backtrack(self, cell):
if cell == 81:
# all values have been set and we are outside the board range
return True
r, c = self.row_idx(cell), self.col_idx(cell)
if self.board[r][c] != self.EMPTY:
# nothing to do, continue search
return self.backtrack(cell + 1)
# explore values in the domain for this cell
for candidate_val in self.DOMAIN:
if self.is_valid(r, c, candidate_val):
# place candidate
self.board[r][c] = candidate_val
self.rows[r].add(candidate_val)
self.cols[c].add(candidate_val)
self.boxs[self.box_idx(r, c)].add(candidate_val)
# continue search
if self.backtrack(cell + 1):
return True
# remove candidate and backtrack
self.board[r][c] = self.EMPTY
self.rows[r].remove(candidate_val)
self.cols[c].remove(candidate_val)
self.boxs[self.box_idx(r, c)].remove(candidate_val)
# no solution found for all values in the domain for this cell
return False
def is_valid(self, r, c, val):
""" Returns whether a value can be placed in board[r][c] in the current game state """
if val in self.rows[r]:
return False
if val in self.cols[c]:
return False
if val in self.boxs[self.box_idx(r, c)]:
return False
return True
You are suffering confusion between "generator" and "container".
Consult type( ... ) to tell the difference between them.
Python generators are "lazy", for excellent technical reasons.
Sometimes we can get away with just evaluating
the first K items of an infinite generator.
In your method you want everything greedily pulled out,
and then stored in a container.
The conventional way to phrase this is to wrap map with list:
self.DOMAIN = list(map(str, range(1, 10)))
or perhaps in your case you would prefer that .join pull them out:
self.DOMAIN = ''.join(map(str, range(1, 10)))
I need to add values to my Binary Tree (Node).
Here is my class:
class Node:
def __init__(self, key):
self.left = None
self.right = None
self.val = key
def __str__(self):
return "{}".format(self.val)
file = open("/home/dzierzen/Downloads/text.txt", "r")
lines = []
for line in file:
cleaned_line = re.sub(r"\s+", "", line)
#
I have txt file with something like this. L means Left, Right mean Right on the tree. Of course the real txt file contains much more records. My questions is: how to deal with that? How to add this values to the tree?
G RR
A
C L
F LLR
X LLL
F R
X RL
H LLG RR
C L
F LLR
X LLL
F R
X RL
H LL
I'm building the tree by going through the list and deciding on the L/R characters which way to go. When I found a non existing leaf, I create a Node there with the value of None. Multiple visits to the same leaf will overwrite the value, but you can easily change that. If the splitted text has only one value, that will be the root Node's value.
I added a printing method that will traverse the tree and print the root of the subtree, then the left and right leaves. It also indents it according to it's level.
class Node:
def __init__(self, key):
self.left = None
self.right = None
self.val = key
def __str__(self):
return "{}".format(self.val)
def _printTree(self, node, level=0):
if node != None:
print(f"{'-'*level}{node}")
self._printTree(node.left,level+1)
self._printTree(node.right,level+1)
def printTree(self):
self._printTree(self)
p = s.split('\n')
root = Node(None)
for k in p:
v = k.split()
if len(v) == 1:
root.val = v[0]
else:
r = root
for c in v[1]:
if c == 'L':
if r.left is None:
r.left = Node(None)
r = r.left
elif c == 'R':
if r.right is None:
r.right = Node(None)
r = r.right
r.val = v[0]
root.printTree()
Using the input text you wrote this is what gets generated:
A
-C
--H
---X
---F
-F
--X
--G
I am trying to build a iterable graph class with python 2.7. I want to be able to iterate though a dictionary containing the vertexes.
Cutting and pasting from https://github.com/joeyajames has got me so far but now I am confused as to how to make this work so that
I can test vertices dict for the presence of an vertice and add if not present. This part is maybe unneeded.
"if (a not in gra ):" because the validation is done in the Graph class itself.
The expected output is a dictionary with the vertices as keys. Actualy im not even sure a list is not better object to use.
class Vertex(object):
def __init__(self, n):
self.name = n
self.neighbors = list()
self.discovery = 0
self.finish = 0
self.color = 'black'
def add_neighbor(self, v):
if v not in self.neighbors:
self.neighbors.append(v)
self.neighbors.sort()
class Graph(object):
def __init__(self,size):
self.vertices = {}
self.hops = 0
self.count = 0
self.limit = size
def __iter__(self):
return self
def next(self):
self.count += 1
if self.count > self.limit:
raise StopIteration
def add_vertex(self,vertex):
if isinstance(vertex, Vertex) and vertex.name not in self.vertices:
self.vertices[vertex.name] = vertex
return True
else:
return False
def add_edge(u,v):
if u in self.vertices and v in self.vertices:
for key, value in self.vertices.items():
if key == u:
value.add_neighbor(v)
if key == v:
value.add_neighbor(u)
return True
else:
return False
def _dfs(self, vertex):
global hops
vertex.color = 'red'
vertex.discovery = hops
hops += 1
for v in vertex.neighbors:
if self.vertices[v].color == 'black':
self._dfs(self.vertices[v])
vertex.color = 'blue'
vertex.finish = hops
time += 1
input = ((5,3),(4 ,2),(0,1),(2 3),(0 4))
N,l = input[0]
print "N is " + str(N)
print "l is " + str(l)
gra = Graph(N)
for i in xrange(1,l):
a,b = input[i]
# Store a and b as vertices in graph object
print "a is " + str(a) + " b is " + str(b)
if (a not in gra ):
print "adding a"
gra.add_vertex(Vertex(chr(a)))
if (b not in gra ):
print "adding b"
gra.add_vertex(Vertex(chr(b)))
You are trying to use not in, which tests for containment; implement the __contains__ hook to facilitate that:
def __contains__(self, vertex):
return vertex.name in self.vertices
I've assumed you wanted to test for vertices, so create one before testing for containment:
a = Vertex(chr(a))
if a not in gra:
print "adding a"
gra.add_vertex(a)
For iteration, I'd not make Graph itself the iterator; that limits you to iterating just once. Your next() method also lacks a return statement, so all you are doing is produce a sequence of None objects.
Make it an iterable instead, so return a new iterator object each time __iter__ is called. You can most simply achieve this by making __iter__ a generator:
def __iter__(self):
for vertex in self.vertices.itervalues():
yield vertex
Note the yield. I've assumed you wanted to iterate over the vertices.
I am practicing problems on Graphs on Hacker Rank. Below is the link for the problem
https://www.hackerrank.com/challenges/tripartite-matching
I wrote a piece of code and the code seems to run on the test case that is being given. I created some test cases of my own and manually calculated the output and then ran my program and it works. However, for most of the other test cases on Hacker Rank. I get a Run Time Error. I am not sure which Run Time Error it is.
I think my logic is breaking for large input sizes. But I am not sure how.
Below is my code.
'''
Input Sequence
3
2
1 2
2 3
3
1 2
1 3
2 3
2
1 3
2 3
'''
#Stores the data of the graph
class Graph:
def __init__(self,parent_node,child_node):
self.node_map = {}
self.node_map[parent_node] = [child_node]
self.node_map[child_node] = [parent_node]
def getNodeMap(self):
return self.node_map
def deleteKey(self, parent_node):
del self.node_map[parent_node]
def printGraph(self):
print self.node_map
def getChildren(self, parent_node):
return self.node_map[parent_node]
def getAllParents(self):
return self.node_map.keys()
def add(self,parent_node,child_node):
#Adding the Node and Edge Details
# Adding Parent and Child
if (parent_node in self.node_map):
child_list = []
child_list = self.node_map[parent_node]
child_list.append(child_node)
self.node_map[parent_node] = child_list
else:
self.node_map[parent_node] = [child_node]
if (child_node in self.node_map):
parent_list = self.node_map[child_node]
parent_list.append(parent_node)
self.node_map[child_node] = parent_list
else:
self.node_map[child_node] = [parent_node]
def runDFS(parent,seq,graph_num):
#print seq
if(graph_num == len(all_graphs)):
all_sequences.append(seq)
return
else:
if(parent not in all_graphs[graph_num].getAllParents()):
return
children = all_graphs[graph_num].getChildren(parent)
for child in children:
new_set = copy.deepcopy(s)
new_seq = copy.deepcopy(seq)
new_seq.append(child)
runDFS(child,new_seq,graph_num+1)
import sys
import fileinput
import copy
import sys
all_graphs = []
all_sequences = []
list_sequences = []
graphs = raw_input()
#print 'Graphs are', graphs
g = [Graph for i in range(int(graphs))]
for i in range(0,int(graphs)):
g[i] = Graph(-999*i,-999*i)
#print 'Read no. of Edges'
edges = raw_input()
#print edges
for j in range(0,int(edges)):
#print 'Read Edge Info'
edge_info = raw_input()
parent_node = edge_info[0]
child_node = edge_info[2]
g[i].add(parent_node, child_node)
g[i].deleteKey(-999*i)
all_graphs.append(g[i])
#for i in range(0,len(all_graphs)):
# print all_graphs[i].getNodeMap()
graph_num = 0
all_sequences = []
sys.setrecursionlimit(20000)
for item in all_graphs[graph_num].getAllParents():
s = set()
s.add(item)
seq = list()
seq.append(item)
runDFS(item,seq,graph_num)
#print all_sequences
counter = 0
for item in all_sequences:
#print item
end_node = item[len(item)-1]
start_node = item[0]
if(end_node == start_node):
counter = counter + 1
print counter
Would really appreciate some help. Is there a bug in my logic or is my assumption right?
If the code is not working for larger input sizes than what is the best way to optimize it?
Instead of running DFS, I used the following approach. But the same thing happens here as well. I think there is some problem with my IO. I am not able to figure out what... :(
for itemA in all_graphs[0].getAllParents():
for itemB in all_graphs[0].getChildren(itemA):
for itemC in all_graphs[1].getChildren(itemB):
if(itemA in all_graphs[2].getChildren(itemC)):
counter = counter + 1
print counter