def testUpdateState(self): matches = {} u = Vertex('u1') v = Vertex('v1') g = Graph() g._updateState(u, v, matches) self.assertEquals(len(g._matchHistory), 1) self.assertEquals(len(matches), 1) self.assertEquals(matches[u.id], 'v1')
def testSubgraphSearchSolutionNoCandidates(self): # Test when an umatched query vertex doesn't have any candidates, we # don't find any solutions. g = Graph() g.addVertex(Vertex('v1', 'A')) q = Graph() q.addVertex(Vertex('u1', 'B')) matches = {} self.assertEqual(len(g._solutions), 0) g._subgraphSearch(matches, q) self.assertEqual(len(g._solutions), 0)
def testSearchNoCandidates(self): # If there are no suitable candidate data vertices for every # query vertex, then the returned solutions list should be empty. g = Graph() g.addEdge(Vertex('v1', 'A'), Vertex('v2', 'B')) q = Graph() q.addEdge(Vertex('u1', 'Z'), Vertex('u2', 'Y')) solutions = g.search(q) self.assertEquals(len(solutions), 0)
def testSubgraphSearchSimpleSolution(self): # One simple solution. g = Graph() g.addVertex(Vertex('v1', 'A')) v1 = g._vertices['v1'] q = Graph() q.addVertex(Vertex('u1', 'A')) q._vertices['u1'].candidates = [v1] self.assertEqual(len(g._solutions), 0) g._subgraphSearch({}, q) self.assertEqual(len(g._solutions), 1) self.assertIn('u1', g._solutions[0]) self.assertEquals(g._solutions[0]['u1'], 'v1')
def testSubgraphSearchSolutionFound(self): # Test that when the length of query=>data vertex matches is the # same as the number of query vertices, then the solution is stored. g = Graph() q = Graph() q.addVertex(Vertex('u1', 'A')) # one query vertex matches = {'u1': 'v1'} # one match g._subgraphSearch(matches, q) self.assertEqual(len(g._solutions), 1)
def testSubgraphSearchOneCandidateNotJoinable(self): # The query vertex has a candidate data vertex, but they aren't # "joinable" -- no solution. g = Graph() g.addVertex(Vertex('v1', 'A')) g.addVertex(Vertex('v2', 'B')) v1 = g._vertices['v1'] q = Graph() q.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) q._vertices['u1'].candidates = [v1] # u2 and v2 are already matched. There's an edge between u1 and # u2, but no edge between v1 and v2 so u1 and v1 cannot be matched. matches = {'u2': 'v2'} self.assertEqual(len(g._solutions), 0) g._subgraphSearch(matches, q) self.assertEqual(len(g._solutions), 0)
def testFilterCandidates(self): # Filtering an empty graph should return an empty array. g = Graph() c = g._filterCandidates(None) self.assertEquals(len(c), 0) # Build a little graph with two 'A' labeled vertices. g.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) g.addEdge('u1', Vertex('u3', 'A')) # Search the graph for all 'X' vertices (should return an empty array.) u = Vertex('x', 'X') c = g._filterCandidates(u) self.assertTrue(len(c) == 0) # Search for 'A' vertices. Should return two of them. u = Vertex('x', 'A') c = g._filterCandidates(u) self.assertTrue(len(c) == 2) self.assertTrue(c[0].label == 'A') self.assertTrue(c[1].label == 'A')
def testNextUnmamtchedVertex(self): matches = {} # Build a little graph with three nodes. q = Graph() q.addEdge(Vertex('u1'), Vertex('u2')) q.addEdge('u1', Vertex('u3')) # Call _nextUnmatchedVertex three times. Each time it returns a # vertex, add it to matches. for i in range(3): v = q._nextUnmatchedVertex(matches) self.assertTrue(v.id in ['u1', 'u2', 'u3']) matches[v.id] = 'XYZ' # Now that all of the vertices are labeled, _nextUnmatchedVertex() # should return None. self.assertIsNone(q._nextUnmatchedVertex(matches))
def _parseGraph(self): """ graph -> edgeList | edgeList ',' graph An edgeList represents a connected path of vertices. A "graph" is a comma-separated list of such paths. This method builds a graph from the given representation. Input: none Output: Graph build from the incoming list of edgeLists """ #logging.debug('parsing new graph') g = Graph() self._parseEdgeList(g) while self.lookahead.type == TokenTypes.COMMA: self._match(TokenTypes.COMMA) self._parseEdgeList(g) return g
def testMapRHSToGraph(self): # No vertices in rhs. Mapping returned is empty. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs, rhs) gen = Generator() rhsMapping = gen._mapRHSToGraph(g, p, {}) self.assertEqual(len(rhsMapping), 0) # rhs has vertex r1, but it doesn't appear in the lhs. Mapping returned # is empty. rhs.addVertex(Vertex('r1', 'A', '1')) rhsMapping = gen._mapRHSToGraph(g, p, {}) self.assertEqual(len(rhsMapping), 0) # rhs vertex r1 also appears in lhs as l1, which is mapped to g1. # r1 should appear in rhsMapping mapped to g1. lhs.addVertex(Vertex('l1', 'A', '1')) rhsMapping = gen._mapRHSToGraph(g, p, {'l1':'g1'}) self.assertEqual(len(rhsMapping), 1) self.assertIn('r1', rhsMapping) self.assertEqual(rhsMapping['r1'], 'g1')
def testFindMatchedNeighbors(self): q = Graph() # No data should return an empty list. mn = q._findMatchedNeighbors(None, None) self.assertEquals(len(mn), 0) # No matching neighbors should return an empty list. q.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) u2 = q._vertices['u2'] mn = q._findMatchedNeighbors(u2, []) self.assertEquals(len(mn), 0) # Make a matching neighbor and make sure it is returned. matches = {'u1': 'v1', 'v1': 'u1'} mn = q._findMatchedNeighbors(u2, matches) self.assertEquals(len(mn), 1) self.assertEquals(mn[0].id, 'u1')
def testRestoreState(self): # Save state with a couple calls to updateState() and then see that # they are undone. g = Graph() matches = {} u1 = Vertex('u1') v1 = Vertex('v1') g._updateState(u1, v1, matches) # u1 matched with v1 u2 = Vertex('u2') v2 = Vertex('v2') g._updateState(u2, v2, matches) # u2 matched with v2 # Now we should get the dictionary with only the original set of # matches. matches = g._restoreState(matches) self.assertEquals(len(matches), 1) self.assertTrue('u1' in matches) self.assertTrue(matches['u1'], 'v1') # Now we should have an empty dictionary. matches = g._restoreState(matches) self.assertEquals(len(matches), 0)
def testRefineCandidates(self): # An empty candidate list should return an empty list. g = Graph() c = g._refineCandidates([], None, {}) self.assertEquals(len(c), 0) # Build a graph and some vertices for use later. u = Vertex('g0') # query vertex v = Vertex('g0') # data vertex # Test with unmatched candidate with the v.degree >= u.degree. This # should return the id of v. u.degree = 1 v.degree = 1 c = [v] c = g._refineCandidates(c, u, {}) self.assertEqual(len(c), 1) self.assertEqual(c[0].id, 'g0') # Test with matched candidate with v.degree >= u.degree. This should # return no candidates. u.degree = 1 v.degree = 1 m = {'g0': 'g0'} c = g._refineCandidates(c, u, m) self.assertEqual(len(c), 0) # Test with unmatched candidate with v.degree < u.degree. This should # return no candidates. u.degree = 1 v.degree = 0 c = g._refineCandidates(c, u, {}) self.assertEqual(len(c), 0) # Test with matched candidate with v.degree < u.degree. This should # return no candidates. u.degree = 1 v.degree = 0 m = {'g0': 'g0'} c = g._refineCandidates(c, u, m) self.assertEqual(len(c), 0)
def testApplyProduction_Blackbox2(self): # Another black-box test of _applyProduction this time with # numbered vertices. # Graph is A0->A1,A0->D g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'A')) g.addEdge('g0', Vertex('g2', 'D')) # Production is A1->A2 ==> A1->A->A2. # This production adds a new vertex "A" between the existing As, # leaving the first A still pointing to D. # Resulting graph: A1->A3->A2; A1->D lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'A', 2)) rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'A')) rhs.addEdge('r1', Vertex('r2', 'A', 2)) p = Production(lhs, rhs) gen = Generator() gen._applyProduction(g, p, {'l0':'g0','l1':'g1'}) # Result has 4 vertices. self.assertEqual(len(g._vertices), 4) # <g0,A> is still in the graph. self.assertIn('g0', g._vertices) self.assertEqual(g._vertices['g0'].label, 'A') # <v3,A> has been added. self.assertIn('v3', g._vertices) self.assertEqual(g._vertices['v3'].label, 'A') # g0->v3 self.assertIn(g._vertices['v3'], g._edges['g0']) # <g1,A> is still in the graph. self.assertIn('g1', g._vertices) self.assertEqual(g._vertices['g1'].label, 'A') # <g2,D> is still in the graph. self.assertIn('g2', g._vertices) self.assertEqual(g._vertices['g2'].label, 'D') # <g0,A>-><g2,D> self.assertIn(g._vertices['g2'], g._edges['g0']) # g0->v3 self.assertIn(g._vertices['v3'], g._edges['g0']) # Output looks fine: A1->A->A, A1->D self.assertEqual(str(g), 'digraph {\nA_v3->A_g1;\nA_g0->D_g2;\nA_g0->A_v3;\n\n}')
def testApplyProductions(self): # Start graph already has the minimum number of vertices. Nothing done. g = Graph() c = {'min_vertices':0} gen = Generator() gen.applyProductions(g, None, c) self.assertEqual(len(g._vertices), 0) # No matching productions raises an error. c = {'min_vertices':1} self.assertRaises(RuntimeError, gen.applyProductions, g, [], c) # When we're done, g has more at least min_vertices. g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'A')) c = {'min_vertices':10} # Production is A1->A2 ==> A1->A->A2 lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'A', 2)) rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'A')) rhs.addEdge('r1', Vertex('r2', 'A', 2)) p = Production(lhs, rhs) gen.applyProductions(g, [p], c) logging.debug(g) self.assertEqual(len(g._vertices), 10)
def testDeleteMissingEdges(self): # If lhs has no edges, then there's nothing missing from the rhs. # Nothing is done to the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() rhs = Graph() p = Production(lhs,rhs) lhsMapping = {} rhsMapping = {} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) # lhs has an edge, but it also appears on the rhs. Nothing done. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'B', 1)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) # lhs has an edge, but the starting vertex doesn't appear in the RHS. # The edge should be deleted from the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addVertex(Vertex('r0', 'A', 2)) rhs.addVertex(Vertex('r1', 'B', 1)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 0) # lhs has an edge, but the ending vertex doesn't appear in the RHS. # The edge should be deleted from the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addVertex(Vertex('r0', 'A', 1)) rhs.addVertex(Vertex('r1', 'B', 2)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r0':'g0'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 0) # lhs has an edge, but it's gone from the rhs. It should be deleted # from the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addVertex(Vertex('r0', 'A', 1)) rhs.addVertex(Vertex('r1', 'B', 1)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 0)
def testFindCandidates(self): # Create empty data and query graphs. g = Graph() q = Graph() # Searching finds no candidates. self.assertFalse(g._findCandidates(q)) # Add some data vertices. g.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) # Empty query graph still finds no candidates. self.assertFalse(g._findCandidates(q)) # Add some query vertices. q.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) q.addEdge('u1', Vertex('u3', 'C')) # Data graph has no 'C', so still returns false. self.assertFalse(g._findCandidates(q)) # Add a vertex for C, and now the test should succeeed. g.addEdge('u1', Vertex('u3', 'C')) u1 = q._vertices['u1'] self.assertTrue(g._findCandidates(q)) self.assertEquals(len(u1.candidates), 1)
def testApplyProduction(self): # A basic test that tests all four cases: add and remove vertex, # and add and remove edge. # Graph starts with A->B g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) g1 = g._vertices['g1'] # Production lhs matches A->B lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) # Production rhs transforms that to A->C rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'C')) p = Production(lhs,rhs) gen = Generator() gen._applyProduction(g, p, {'l0':'g0','l1':'g1'}) # g has a new vertex, <v2,C>. self.assertEqual(len(g._vertices), 2) self.assertEqual(g._vertices['v1'].label, 'C') # <g0,A> points to <v2,C> self.assertEqual(len(g._edges['g0']), 1) self.assertEqual(g._edges['g0'][0].id, 'v1') self.assertEqual(g._vertices['v1'].label, 'C') # <g0,A> no longer points to <g1,B> self.assertNotIn(g1, g._edges['g0']) # Vertex <g1,B> has been deleted. self.assertNotIn('g1', g._vertices)
def testParseEdgeList(self): # edgeList -> ID | ID '->' edgeList # Left off first required ID. p = Parser(Lexer('')) g = Graph() self.assertRaises(SyntaxError, p._parseEdgeList, g) # Using non-existing label should create a new vertex. g = Graph() p = Parser(Lexer('A')) p._parseEdgeList(g) self.assertEqual(g._vertices['v0'].label, 'A') # Using an existing label should not create a new vertex. g = Graph() g.addVertex(Vertex('u0', 'A')) p = Parser(Lexer('A')) p._parseEdgeList(g) self.assertEqual(g._vertices['u0'].label, 'A') # Left off second ID. p = Parser(Lexer('A ->')) g = Graph() self.assertRaises(SyntaxError, p._parseEdgeList, g) # Simple transition should create two vertices and connect them. g = Graph() p = Parser(Lexer('A -> B')) p._parseEdgeList(g) self.assertEquals(len(g._vertices), 2) self.assertEquals(g._vertices['v0'].label, 'A') self.assertEquals(g._vertices['v1'].label, 'B') self.assertEquals(g._edges['v0'][0].label, 'B')
def testSearchTwoSolutions(self): # A1_g0->B_g1->C_g2, A2_g3->B_g1 g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) g.addEdge('g1', Vertex('g2', 'C')) g.addEdge(Vertex('g3', 'A'), 'g1') #g.addEdge('g3', 'g2') # A_g0->B_g1->C_g2 q = Graph() q.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) q.addEdge('g1', Vertex('g2', 'C')) solutions = g.search(q) self.assertEquals(len(solutions), 2) # First A->B,C is found. self.assertEquals(solutions[0]['g0'], 'g3') self.assertEquals(solutions[0]['g1'], 'g1') self.assertEquals(solutions[0]['g2'], 'g2') # Second A->B,C is found. self.assertEquals(solutions[1]['g0'], 'g0') self.assertEquals(solutions[1]['g1'], 'g1') self.assertEquals(solutions[1]['g2'], 'g2')
def testApplyProduction_Blackbox(self): # Black-box test of _applyProduction. # Graph is A->C,D g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'C')) g.addVertex(Vertex('g2', 'D')) # Production is A->C,D ==> A->B,C. # This adds vertex B, adds edge from A->B, deletes edge from A->C, # and deletes vertex D. lhs = Graph() lhs.addEdge(Vertex('l0', 'A'), Vertex('l1', 'C')) lhs.addVertex(Vertex('l2', 'D')) rhs = Graph() rhs.addEdge(Vertex('r0', 'A'), Vertex('r1', 'B')) rhs.addVertex(Vertex('r2', 'C')) p = Production(lhs, rhs) gen = Generator() gen._applyProduction(g, p, {'l0':'g0','l1':'g1','l2':'g2'}) self.assertEqual(len(g._vertices), 3) # <g0,A> is still in the graph. self.assertIn('g0', g._vertices) self.assertEqual(g._vertices['g0'].label, 'A') # <v3,B> has been added. self.assertIn('v2', g._vertices) self.assertEqual(g._vertices['v2'].label, 'B') # A->B self.assertIn(g._vertices['v2'], g._edges['g0']) # <g1,C> is still in the graph. self.assertIn('g1', g._vertices) self.assertEqual(g._vertices['g1'].label, 'C') # A->C has been removed. self.assertNotIn(g._vertices['g1'], g._edges['g0']) # <g2,D> has been removed. self.assertNotIn('g2', g._vertices) # Output looks fine. self.assertEqual(str(g), 'digraph {\nA_g0->B_v2;\n\n}')
class TestGraphClass(unittest.TestCase): def setUp(self): self.g = Graph() def testConstructor(self): # New graphs should be empty. self.assertTrue(len(self.g._vertices) == 0) self.assertTrue(len(self.g._edges) == 0) self.assertTrue(len(self.g._neighbors) == 0) def testAddVertex(self): # Correct add. v = self.g.addVertex(Vertex('u1')) self.assertTrue('u1' in self.g._vertices) # Adding an existing vertex should return the existing vertex. self.assertEquals(self.g.addVertex(v), v) def testAddEdge(self): # Add edge with two vid's a = self.g.addVertex(Vertex('u1', 'A')) b = self.g.addVertex(Vertex('u2', 'B')) self.g.addEdge('u1', 'u2') # Add edge with one vid and one Vertex. self.g.addEdge('u1', Vertex('u3', 'C')) c = self.g._vertices['u3'] # Add edge with one Vertex and one vid. self.g.addEdge(Vertex('u4', 'D'), 'u1') d = self.g._vertices['u4'] # Add edge with two Vertics. self.g.addEdge(Vertex('u5', 'E'), Vertex('u6', 'F')) e = self.g._vertices['u5'] f = self.g._vertices['u6'] # Make sure A points to B and C. self.assertTrue(b in self.g._edges['u1']) self.assertTrue(c in self.g._edges['u1']) self.assertTrue(a in self.g._edges['u4']) self.assertTrue(f in self.g._edges['u5']) # Make sure neighbors all reference each other. self.assertTrue(b in self.g._neighbors['u1']) self.assertTrue(c in self.g._neighbors['u1']) self.assertTrue(d in self.g._neighbors['u1']) self.assertTrue(a in self.g._neighbors['u2']) self.assertTrue(a in self.g._neighbors['u3']) self.assertTrue(a in self.g._neighbors['u4']) self.assertTrue(e in self.g._neighbors['u6']) self.assertTrue(f in self.g._neighbors['u5']) # Make sure the vertex degrees were updated. self.assertEquals(self.g._vertices['u1'].degree, 3) self.assertEquals(self.g._vertices['u2'].degree, 1) self.assertEquals(self.g._vertices['u3'].degree, 1) self.assertEquals(self.g._vertices['u4'].degree, 1) self.assertEquals(self.g._vertices['u5'].degree, 1) self.assertEquals(self.g._vertices['u6'].degree, 1) def testDeleteEdge(self): # Referencing non-existing vertices should return False self.assertFalse(self.g.deleteEdge('aaa', 'bbb')) # Build A->B self.g.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) u1 = self.g._vertices['u1'] u2 = self.g._vertices['u2'] # Deleting a non-existant edge should return False. self.assertFalse(self.g.deleteEdge('u1', 'bbb')) # Deleting an existing edge should return True. self.assertTrue(self.g.deleteEdge('u1', 'u2')) # u2 should not appear in the list of edges from u1. self.assertTrue(u2 not in self.g._edges['u1']) # u2 should not appear in the list of neighbors of u1. self.assertTrue(u2 not in self.g._neighbors['u1']) # Both vertex degress should be decremented. self.assertEquals(u1.degree, 0) self.assertEquals(u2.degree, 0) def testDeleteVertex(self): # Deleting a non-existing vertex raises an exception. self.assertIsNone(self.g.deleteVertex('X')) # Build A->B, B->A self.g.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) self.g.addEdge('u2', 'u1') u1 = self.g._vertices['u1'] u2 = self.g._vertices['u2'] self.g.deleteVertex('u1') # u1 shouldn't appear anywhere as an edge or neighbor. self.assertTrue('u1' not in self.g._edges) self.assertTrue('u1' not in self.g._neighbors) self.assertTrue('u1' not in self.g._edges['u2']) self.assertTrue('u1' not in self.g._neighbors['u2']) # u1 isn't a vertex anymore. self.assertTrue('u1' not in self.g._vertices) def testEdgesProperty(self): # Build A->B, B->C self.g.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) self.g.addEdge('u2', Vertex('u3', 'C')) for e in self.g.edges: if e[0].id == 'u1': self.assertEquals(e[1].id, 'u2') elif e[0].id == 'u2': self.assertEquals(e[1].id, 'u3') else: self.assertFalse(True) def testFindVertex(self): u1 = self.g.addVertex(Vertex('u1', 'A', 1)) self.assertIsNone(self.g.findVertex('X')) self.assertIsNone(self.g.findVertex('A2')) self.assertEqual(self.g.findVertex('A1'), u1) def testHasEdgeBetweenVertices(self): self.g.addEdge(Vertex('u0', 'A'), Vertex('u1', 'B')) self.g.addEdge('u1', Vertex('u2', 'C')) self.assertTrue(self.g.hasEdgeBetweenVertices('u0', 'u1')) self.assertFalse(self.g.hasEdgeBetweenVertices('u0', 'u2')) self.assertFalse(self.g.hasEdgeBetweenVertices('XX', 'XX')) self.assertFalse(self.g.hasEdgeBetweenVertices('u0', 'XX')) def testLabelsProperty(self): self.g.addVertex(Vertex('u1', 'A')) self.g.addVertex(Vertex('u2', 'B')) self.g.addVertex(Vertex('u3', 'C')) labels = self.g.labels self.assertEquals(len(labels), 3) self.assertTrue('A' in labels) self.assertTrue('B' in labels) self.assertTrue('C' in labels) def testNamesProperty(self): self.g.addVertex(Vertex('u1', 'A', 1)) self.g.addVertex(Vertex('u2', 'B', 2)) self.g.addVertex(Vertex('u3', 'C', 3)) names = self.g.names self.assertEquals(len(names), 3) self.assertTrue('A1' in names) self.assertTrue('B2' in names) self.assertTrue('C3' in names) def testNumVertices(self): # Empty graph. self.assertEquals(self.g.numVertices, 0) # One vertex. a = self.g.addVertex(Vertex('u1')) self.assertEquals(self.g.numVertices, 1) def testRepr(self): # Test of the output function (__repr__). # No vertices. self.assertEquals(self.g.__repr__(), "digraph {\n\n}") # A self.g.addVertex(Vertex('u1', 'A')) self.assertEquals(self.g.__repr__(), "digraph {\nA_u1\n}") # A->B self.g.addEdge('u1', Vertex('u2', 'B')) self.assertEquals(self.g.__repr__(), "digraph {\nA_u1->B_u2;\n\n}") # A->B->C self.g.addEdge('u2', Vertex('u3', 'C')) self.assertEquals(self.g.__repr__(), "digraph {\nA_u1->B_u2;\nB_u2->C_u3;\n\n}") # A->B->C, A->D self.g.addEdge('u1', Vertex('u4', 'D')) self.assertEquals( self.g.__repr__(), "digraph {\nA_u1->B_u2;\nA_u1->D_u4;\nB_u2->C_u3;\n\n}")
def testAddNewEdges(self): # rhs has no edges, so nothing changes. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs,rhs) rhsMapping = {} gen = Generator() self.assertEqual(len(g._edges), 0) gen._addNewEdges(g, p, rhsMapping) self.assertEqual(len(g._edges), 0) # rhs has an edge, but it already exists in the graph. g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'B', 1)) p = Production(lhs,rhs) rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._addNewEdges(g, p, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) # rhs has a new edge not in graph. g = Graph() g.addVertex(Vertex('g0', 'A')) g.addVertex(Vertex('g1', 'B')) lhs = Graph() rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'B', 1)) p = Production(lhs,rhs) rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 0) gen._addNewEdges(g, p, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) self.assertEqual(g._edges['g0'][0].id, 'g1')
def testFindMatchingProductions(self): # Providing no productions should result in no matches. gen = Generator() g = Graph() self.assertEquals( len(gen._findMatchingProductions(g, [])), 0) # We have a production, but the LHS can't be found in the graph. # No solutions. g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() lhs.addEdge(Vertex('g0', 'C'), Vertex('g1', 'D')) rhs = Graph() p1 = Production(lhs, rhs) gen = Generator() self.assertEquals( len(gen._findMatchingProductions(g, [p1])), 0) # One matching production, a simple vertex "A". g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() lhs.addVertex(Vertex('g0', 'A', '1')) rhs = Graph() p1 = Production(lhs, rhs) self.assertEquals( len(gen._findMatchingProductions(g, [p1])), 1) # Two matching productions. g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() lhs.addVertex(Vertex('g0', 'A', '2')) rhs = Graph() p1 = Production(lhs, rhs) p2 = Production(lhs, rhs) self.assertEquals( len(gen._findMatchingProductions(g, [p1, p2])), 2)
def testIsJoinable(self): # If there are no matched vertices yet (we just started the matching # process), then should return True. g = Graph() self.assertTrue(g._isJoinable(None, None, None, {})) # If there are matches, but none adjacent to u, then should # return False. g = Graph() g.addEdge(Vertex('v1'), Vertex('v2')) v = g._vertices['v1'] q = Graph() q.addEdge(Vertex('u1'), Vertex('u2')) u = q._vertices['u1'] self.assertFalse(g._isJoinable(u, v, q, {'u3': 'v3', 'v3': 'u3'})) # If an edge exists between u and n, but the other direction between # v and m, should return False g = Graph() g.addEdge(Vertex('v1'), Vertex('v2')) v = g._vertices['v1'] q = Graph() q.addEdge(Vertex('u2'), Vertex('u1')) u = q._vertices['u1'] self.assertFalse(g._isJoinable(u, v, q, {'u2': 'v2', 'v2': 'u2'})) # If an edge exists between n and u, but the other direction between # m and v, should return False g = Graph() g.addEdge(Vertex('v2'), Vertex('v1')) v = g._vertices['v1'] q = Graph() q.addEdge(Vertex('u1'), Vertex('u2')) u = q._vertices['u1'] self.assertFalse(g._isJoinable(u, v, q, {'u2': 'v2', 'v2': 'u2'})) # Correct case 1. Edge between u and n, and between v and m. g = Graph() g.addEdge(Vertex('v1'), Vertex('v2')) v = g._vertices['v1'] q = Graph() q.addEdge(Vertex('u1'), Vertex('u2')) u = q._vertices['u1'] self.assertTrue(g._isJoinable(u, v, q, {'u2': 'v2', 'v2': 'u2'})) # Correct case 2. Edge between n and u, and between m and v. g = Graph() g.addEdge(Vertex('v2'), Vertex('v1')) v = g._vertices['v1'] q = Graph() q.addEdge(Vertex('u2'), Vertex('u1')) u = q._vertices['u1'] self.assertTrue(g._isJoinable(u, v, q, {'u2': 'v2', 'v2': 'u2'}))
def testDeleteMissingVertices(self): # lhs has no vertices(!). Nothing done. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs, rhs) gen = Generator() gen._deleteMissingVertices(g, p, {}) self.assertEqual(len(g._vertices), 0) # lhs has vertices, but they all appear in the rhs. Nothing done. g.addVertex(Vertex('g0', 'A', 1)) lhs.addVertex(Vertex('l0', 'A', 1)) rhs.addVertex(Vertex('r0', 'A', 1)) p = Production(lhs, rhs) gen._deleteMissingVertices(g, p, {'l0':'g0'}) self.assertEqual(len(g._vertices), 1) # lhs has a vertex (A2) that don't appear in the rhs. It should be # deleted from g. g.addVertex(Vertex('g1', 'A', 2)) lhs.addVertex(Vertex('l1', 'A', 2)) p = Production(lhs, rhs) self.assertEqual(len(g._vertices), 2) gen._deleteMissingVertices(g, p, {'l0':'g0', 'l1':'g1'}) self.assertEqual(len(g._vertices), 1)
def testParseVertexID(self): p = Parser(Lexer('')) # No text label raises an error. g = Graph() t = Token(0, '123') self.assertRaises(AttributeError, p._parseVertexID, t, g) # Only a label - doesn't exist in the graph. g = Graph() t = Token(0, 'A') v = p._parseVertexID(t, g) self.assertEqual(v.label, 'A') self.assertIsNone(v.number) # Label and a number - not in the graph. g = Graph() t = Token(0, 'A1') v = p._parseVertexID(t, g) self.assertEqual(v.label, 'A') self.assertEqual(v.number, '1') # Only a label - already in the graph. g = Graph() u = Vertex('v1', 'A') g.addVertex(u) t = Token(0, 'A') v = p._parseVertexID(t, g) self.assertEqual(v, u) # Label and a number - already in the graph. g = Graph() u = Vertex('v1', 'A', '1') g.addVertex(u) t = Token(0, 'A1') v = p._parseVertexID(t, g) self.assertEqual(v, u)
def testAddNewVertices(self): # Production rhs has no vertices, so nothing done. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs, rhs) gen = Generator() self.assertEqual(len(g._vertices), 0) gen._addNewVertices(g, p, {}) self.assertEqual(len(g._vertices), 0) # Production rhs has vertices, but they all appear in the LHS. Hence # they aren't new and nothing is done. lhs.addVertex(Vertex('l1', 'A', 1)) rhs.addVertex(Vertex('r1', 'A', 1)) self.assertEqual(len(g._vertices), 0) gen._addNewVertices(g, p, {}) self.assertEqual(len(g._vertices), 0) # rhs has one new vertex not in the lhs. rhsMapping = {} rhs.addVertex(Vertex('r2', 'B', 2)) self.assertEqual(len(g._vertices), 0) gen._addNewVertices(g, p, rhsMapping) self.assertEqual(len(g._vertices), 1) self.assertIn('v0', g._vertices) # new vertex is v0 self.assertEqual(g._vertices['v0'].label, 'B') # with label B self.assertEqual(g._vertices['v0'].number, 2) # with number 2 self.assertIn('r2', rhsMapping) # now appears in rhsMapping self.assertEqual(rhsMapping['r2'], 'v0') # r2 mapped to v0 (the newly added vertex) in graph
def setUp(self): self.g = Graph()
def testSearchOneSimpleSolution(self): g = Graph() g.addEdge(Vertex('v1', 'A'), Vertex('v2', 'B')) g.addEdge('v1', Vertex('v3', 'C')) # Query graph is exact replica. q = Graph() q.addEdge(Vertex('u1', 'A'), Vertex('u2', 'B')) q.addEdge('u1', Vertex('u3', 'C')) solutions = g.search(q) self.assertEquals(len(solutions), 1) self.assertEquals(solutions[0]['u1'], 'v1') self.assertEquals(solutions[0]['u2'], 'v2') self.assertEquals(solutions[0]['u3'], 'v3')