def createAGGNodeObj(self, aggNodeStr): if isinstance(aggNodeStr, str): return ParserUtil.parseRelVar(aggNodeStr) else: return RelationalVariableIntersection( ParserUtil.parseRelVar(aggNodeStr[0]), ParserUtil.parseRelVar(aggNodeStr[1]))
def testInvalidSetOfRelationalVariables(self): # all relvars must have the same perspective schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') TestUtil.assertRaisesMessage( self, Exception, "Perspective is not consistent across all relational variables", RelationalValidity.checkValidityOfRelationalVariableSet, schema, 0, [ ParserUtil.parseRelVar(relVarStr) for relVarStr in ['[A].X', '[B].Y'] ]) TestUtil.assertRaisesMessage( self, Exception, "Perspective is not consistent across all relational variables", RelationalValidity.checkValidityOfRelationalVariableSet, schema, 0, [ ParserUtil.parseRelVar(relVarStr) for relVarStr in ['[B].Y', '[A].X'] ]) # all relvars must be consistent with hop threshold TestUtil.assertRaisesMessage( self, Exception, "Relational variable '[A, AB, B].Y' is longer than the hop threshold", RelationalValidity.checkValidityOfRelationalVariableSet, schema, 0, [ ParserUtil.parseRelVar(relVarStr) for relVarStr in ['[A].X', '[A, AB, B].Y'] ]) TestUtil.assertRaisesMessage( self, Exception, "Relational variable '[A, AB, B].Y' is longer than the hop threshold", RelationalValidity.checkValidityOfRelationalVariableSet, schema, 1, [ ParserUtil.parseRelVar(relVarStr) for relVarStr in ['[A, AB, B].Y', '[A].X'] ]) # enforce that the relational variables are checked for consistency against the schema # using RelationalValidity.checkRelationalVariableValidity mockRelVarChecker = MagicMock( wraps=RelationalValidity.checkRelationalVariableValidity) RelationalValidity.checkValidityOfRelationalVariableSet( schema, 2, [ ParserUtil.parseRelVar(relVarStr) for relVarStr in ['[A, AB, B].Y', '[A].X'] ], relationalVariableChecker=mockRelVarChecker) self.assertEqual(2, mockRelVarChecker.call_count)
def testRemoveEdgesForDependency(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'A') schema.addAttribute('A', 'B') schema.addAttribute('A', 'C') schema.addAttribute('A', 'D') schema.addAttribute('A', 'E') schema.addAttribute('A', 'F') schema.addAttribute('A', 'G') schema.addAttribute('A', 'H') dependencies = [ '[A].A -> [A].B', '[A].A -> [A].C', '[A].B -> [A].D', '[A].C -> [A].D', '[A].E -> [A].F', '[A].E -> [A].G', '[A].F -> [A].H', '[A].G -> [A].H' ] model = Model(schema, dependencies) agg = AbstractGroundGraph(model, 'A', 0) agg.removeEdgesForDependency(ParserUtil.parseRelDep('[A].B -> [A].A')) self.assertEqual(8, len(agg.edges())) agg.removeEdgesForDependency(ParserUtil.parseRelDep('[A].A -> [A].B')) self.assertEqual(7, len(agg.edges())) self.assertNotIn( (ParserUtil.parseRelVar('[A].A'), ParserUtil.parseRelVar('[A].B')), agg.edges()) agg.removeEdgesForDependency(ParserUtil.parseRelDep('[A].F -> [A].H')) self.assertEqual(6, len(agg.edges())) self.assertNotIn( (ParserUtil.parseRelVar('[A].F'), ParserUtil.parseRelVar('[A].H')), agg.edges()) schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addEntity('C') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('C', 'Z') schema.addAttribute('AB', 'XY') schema.addAttribute('BC', 'YZ') model = Model(schema, [ '[BC, B, AB, A].X -> [BC].YZ', '[AB, B, BC, C].Z -> [AB].XY', '[AB, B, AB, A, AB, B].Y -> [AB].XY' ]) aAGG = AbstractGroundGraph(model, 'A', 6) self.assertEqual(9, len(aAGG.edges())) aAGG.removeEdgesForDependency( ParserUtil.parseRelDep('[BC, B, AB, A].X -> [BC].YZ')) self.assertEqual(7, len(aAGG.edges())) aAGG.removeEdgesForDependency( ParserUtil.parseRelDep('[AB, B, AB, A, AB, B].Y -> [AB].XY')) self.assertEqual(2, len(aAGG.edges()))
def isConditionallyIndependent(self, relVar1Str, relVar2Str, condRelVarStrs): logger.debug("testing %s _||_ %s | { %s }", relVar1Str, relVar2Str, condRelVarStrs) if not isinstance(relVar1Str, str) and not isinstance(relVar1Str, RelationalVariable) or not relVar1Str: raise Exception("relVar1Str must be a parseable RelationalVariable string") if not isinstance(relVar2Str, str) and not isinstance(relVar2Str, RelationalVariable) or not relVar2Str: raise Exception("relVar2Str must be a parseable RelationalVariable string") if not isinstance(condRelVarStrs, collections.Iterable) or isinstance(condRelVarStrs, str): raise Exception("condRelVarStrs must be a sequence of parseable RelationalVariable strings") relVar1 = ParserUtil.parseRelVar(relVar1Str) relVar2 = ParserUtil.parseRelVar(relVar2Str) if len(relVar2.path) > 1: raise Exception("relVar2Str must have a singleton path") baseItemName = relVar1.getBaseItemName() relVarAggrs = [AverageAggregator(relVar1Str), IdentityAggregator(relVar2Str)] relVarAggrs.extend([AverageAggregator(condRelVarStr) for condRelVarStr in condRelVarStrs]) relVar1Data = [] relVar2Data = [] condVarsData = [] for i in range(len(condRelVarStrs)): condVarsData.append([]) for idVal, row in self.dataStore.getValuesForRelVarAggrs(self.schema, baseItemName, relVarAggrs): if None in row: continue relVar1Data.append(float(row[0])) relVar2Data.append(float(row[1])) for i, value in enumerate(row[2:]): condVarsData[i].append(float(value)) robjects.baseenv['treatment'] = robjects.FloatVector(relVar1Data) robjects.baseenv['outcome'] = robjects.FloatVector(relVar2Data) for i, condVarData in enumerate(condVarsData): robjects.baseenv['cond{}'.format(i)] = robjects.FloatVector(condVarData) if not condVarsData: # marginal linearModel = r.lm('outcome ~ treatment') effectSize = r('cor(treatment, outcome)^2')[0] summary = r.summary(linearModel) else: condVarIndexes = range(len(condVarsData)) linearModel = r.lm('outcome ~ treatment + cond{}'.format(' + cond'.join(map(str, condVarIndexes)))) effectSize = r('cor(residuals(lm(outcome ~ cond{condVarStrs})), ' 'residuals(lm(treatment ~ cond{condVarStrs})))^2'.format( condVarStrs=(' + cond'.join(map(str, condVarIndexes)))))[0] summary = r.summary(linearModel) pval = summary.rx2('coefficients').rx(2,4)[0] logger.debug('soe: {}, pval: {}'.format(effectSize, pval)) return pval > self.alpha or effectSize < self.soeThreshold
def setSepsets(self, sepsets, relationalVariableSetChecker=RelationalValidity.checkValidityOfRelationalVariableSet): """ Sets the sepsets internally. Accepts string representation of the relational variables in the sepsets. """ if not isinstance(sepsets, dict): raise Exception("Sepsets must be a dictionary: found {}".format(sepsets)) self.sepsets = {(ParserUtil.parseRelVar(relVar1Str), ParserUtil.parseRelVar(relVar2Str)): {ParserUtil.parseRelVar(condVarStr) for condVarStr in sepsetStr} for (relVar1Str, relVar2Str), sepsetStr in sepsets.items()} for (relVar1, relVar2), condRelVars in self.sepsets.items(): relationalVariableSetChecker(self.schema, self.hopThreshold, {relVar1, relVar2} | condRelVars)
def relVarStrPairsToRelVarPairs(self, relVarStrPairs): edges = [] for relVarStrPair in relVarStrPairs: if isinstance(relVarStrPair[0], str) and isinstance( relVarStrPair[1], str): # relVar -> relVar edges.append((ParserUtil.parseRelVar(relVarStrPair[0]), ParserUtil.parseRelVar(relVarStrPair[1]))) elif isinstance(relVarStrPair[0], str) and not isinstance(relVarStrPair[1], str): # relVar -> relVarInt edges.append( (ParserUtil.parseRelVar(relVarStrPair[0]), RelationalVariableIntersection( ParserUtil.parseRelVar(relVarStrPair[1][0]), ParserUtil.parseRelVar(relVarStrPair[1][1])))) elif not isinstance(relVarStrPair[0], str) and isinstance( relVarStrPair[1], str): # relVarInt -> relVar edges.append((RelationalVariableIntersection( ParserUtil.parseRelVar(relVarStrPair[0][0]), ParserUtil.parseRelVar(relVarStrPair[0][1])), ParserUtil.parseRelVar(relVarStrPair[1]))) else: raise Exception("Unknown pairing in relVarStrPairs: {}".format( relVarStrPair)) return edges
def testSetUndirectedSkeleton(self): schema = Schema() model = Model(schema, []) pc = PC(schema, Oracle(model)) undirectedSkeleton = nx.DiGraph() pc.setUndirectedSkeleton(undirectedSkeleton) self.assertEqual(undirectedSkeleton, pc.undirectedSkeleton) TestUtil.assertRaisesMessage(self, Exception, "Undirected skeleton must be a networkx DiGraph: found None", pc.setUndirectedSkeleton, None) # nodes must match the attributes of the schema undirectedSkeleton = nx.DiGraph() undirectedSkeleton.add_node(ParserUtil.parseRelVar('[A].X')) TestUtil.assertRaisesMessage(self, Exception, "Undirected skeleton's nodes must match schema attributes", pc.setUndirectedSkeleton, undirectedSkeleton) schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') model = Model(schema, []) pc = PC(schema, Oracle(model)) undirectedSkeleton = nx.DiGraph() TestUtil.assertRaisesMessage(self, Exception, "Undirected skeleton's nodes must match schema attributes", pc.setUndirectedSkeleton, undirectedSkeleton)
def dSeparated(self, hopThreshold, relVar1Strs, relVar2Strs, condRelVarStrs, relationalVariableSetChecker=RelationalValidity.checkValidityOfRelationalVariableSet): """ relVar1Strs, relVar2Strs, and condRelVarStrs are sequences of parseable RelationalVariable strings Method checks if, in model, are relVars1 and relVars2 d-separated? Constructs the abstract ground graph (AGG) for the model, and checks to see if all paths are d-separated. """ if not isinstance(relVar1Strs, collections.Iterable) or not relVar1Strs: raise Exception("relVars1 must be a non-empty sequence of parseable RelationalVariable strings") relVars1 = {ParserUtil.parseRelVar(relVarStr) for relVarStr in relVar1Strs} if not isinstance(relVar2Strs, collections.Iterable) or not relVar2Strs: raise Exception("relVars2 must be a non-empty sequence of parseable RelationalVariable strings") relVars2 = {ParserUtil.parseRelVar(relVarStr) for relVarStr in relVar2Strs} if not isinstance(condRelVarStrs, collections.Iterable): raise Exception("condRelVars must be a sequence of parseable RelationalVariable strings") condRelVars = {ParserUtil.parseRelVar(condRelVar) for condRelVar in condRelVarStrs} # check consistency of all three relational variable sets (perspectives, hop threshold, against schema) relationalVariableSetChecker(self.model.schema, hopThreshold, relVars1 | relVars2 | condRelVars) perspective = list(relVars1)[0].getBaseItemName() if (perspective, hopThreshold) not in self.perspectiveHopThresholdToAgg: agg = AbstractGroundGraph(self.model, perspective, hopThreshold) ug = agg2ug(agg) self.perspectiveHopThresholdToAgg[(perspective, hopThreshold)] = agg self.ugs[(perspective, hopThreshold)] = ug else: agg = self.perspectiveHopThresholdToAgg[(perspective, hopThreshold)] ug = self.ugs[(perspective, hopThreshold)] # expand relVars1, relVars2, condRelVars with all intersection variables they subsume relVars1 = {relVar for relVar1 in relVars1 for relVar in agg.getSubsumedVariables(relVar1)} relVars2 = {relVar for relVar2 in relVars2 for relVar in agg.getSubsumedVariables(relVar2)} condRelVars = {relVar for condRelVar in condRelVars for relVar in agg.getSubsumedVariables(condRelVar)} relVars1 -= condRelVars relVars2 -= condRelVars if relVars1 & relVars2 != set(): return False if not relVars1 or not relVars2: return True return bfsReachability(relVars1, relVars2, condRelVars, agg, ug)
def testSetPhaseIPattern(self): # edges in skeleton and sepsets should be useful for Phase II schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') schema.addAttribute('A', 'Y') schema.addAttribute('A', 'Z') model = Model(schema, ['[A].X -> [A].Z', '[A].Y -> [A].Z']) pc = PC(schema, Oracle(model)) undirectedSkeleton = nx.DiGraph() relVarX = ParserUtil.parseRelVar('[A].X') relVarY = ParserUtil.parseRelVar('[A].Y') relVarZ = ParserUtil.parseRelVar('[A].Z') undirectedSkeleton.add_edges_from([(relVarX, relVarZ), (relVarZ, relVarX), (relVarY, relVarZ), (relVarZ, relVarY)]) pc.setUndirectedSkeleton(undirectedSkeleton) pc.setSepsets({(relVarX, relVarY): set(), (relVarY, relVarX): set()}) pc.pcPhaseII() self.assertPCOutputEqual(['[A].X', '[A].Y', '[A].Z'], [('[A].X', '[A].Z'), ('[A].Y', '[A].Z')], None, None, pc.partiallyDirectedGraph, None, None)
def testInvalidRelationalVariables(self): schema = Schema() schema.addEntity('A') TestUtil.assertRaisesMessage( self, Exception, "Schema item 'A' has no attribute 'X' in relationalVariable '[A].X'", RelationalValidity.checkRelationalVariableValidity, schema, ParserUtil.parseRelVar('[A].X')) schema.addAttribute('A', 'X') TestUtil.assertRaisesMessage( self, Exception, "Schema item 'A' has no attribute 'Y' in relationalVariable '[A].Y'", RelationalValidity.checkRelationalVariableValidity, schema, ParserUtil.parseRelVar('[A].Y')) self.assertIsNone( RelationalValidity.checkRelationalVariableValidity( schema, ParserUtil.parseRelVar('[A].exists'))) schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) TestUtil.assertRaisesMessage( self, Exception, "Schema item 'AB' has no attribute 'XY' in relationalVariable '[A, AB].XY'", RelationalValidity.checkRelationalVariableValidity, schema, ParserUtil.parseRelVar('[A, AB].XY')) self.assertIsNone( RelationalValidity.checkRelationalVariableValidity( schema, ParserUtil.parseRelVar('[A, AB].exists'))) TestUtil.assertRaisesMessage( self, Exception, "Schema item 'B' has no attribute 'Y' in relationalVariable '[A, AB, B].Y'", RelationalValidity.checkRelationalVariableValidity, schema, ParserUtil.parseRelVar('[A, AB, B].Y')) schema.addAttribute('B', 'Y') # enforce that the relational paths are checked for consistency against the schema # using RelationalValidity.checkRelationalPathValidity mockRelPathChecker = MagicMock( wraps=RelationalValidity.checkRelationalPathValidity) RelationalValidity.checkRelationalVariableValidity( schema, ParserUtil.parseRelVar('[A, AB, B].Y'), relationalPathChecker=mockRelPathChecker) self.assertEqual(1, mockRelPathChecker.call_count)
def assertPCOutputEqual(self, expectedNodeStrs, expectedEdgeStrs, expectedSepsetStrs, expectedNumDSepCalls, dag, sepset, mockOracle): # test nodes are equal expectedNodes = [ParserUtil.parseRelVar(nodeStr) for nodeStr in expectedNodeStrs] TestUtil.assertUnorderedListEqual(self, expectedNodes, dag.nodes()) # test edges are equal self.assertEqual(len(expectedEdgeStrs), len(dag.edges())) for expectedEdgeStr in expectedEdgeStrs: expectedEdge = (ParserUtil.parseRelVar(expectedEdgeStr[0]), ParserUtil.parseRelVar(expectedEdgeStr[1])) self.assertIn(expectedEdge, dag.edges()) # test sepsets are equal, if passed in if expectedSepsetStrs and sepset: expectedSepset = {(ParserUtil.parseRelVar(relVar1Str), ParserUtil.parseRelVar(relVar2Str)): {ParserUtil.parseRelVar(condVarStr) for condVarStr in sepsetStr} for (relVar1Str, relVar2Str), sepsetStr in expectedSepsetStrs.items()} self.assertDictEqual(expectedSepset, sepset) # test the number of d-separation calls, if passed in if expectedNumDSepCalls and mockOracle: self.assertEqual(expectedNumDSepCalls, mockOracle.isConditionallyIndependent.call_count)
def testRelVarCheckerUsed(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') schema.addEntity('B') schema.addAttribute('B', 'Y') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addEntity('C') schema.addAttribute('C', 'Z') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) model = Model(schema, ['[B, AB, A].X -> [B].Y', '[C, BC, B].Y -> [C].Z']) dsep = DSeparation(model) mockRelVarSetChecker = MagicMock( wraps=RelationalValidity.checkValidityOfRelationalVariableSet) dsep.dSeparated(8, ['[A].X'], ['[A, AB, B, BC, C].Z'], [], relationalVariableSetChecker=mockRelVarSetChecker) self.assertEqual(1, mockRelVarSetChecker.call_count) relVarsPassed = { ParserUtil.parseRelVar('[A].X'), ParserUtil.parseRelVar('[A, AB, B, BC, C].Z') } mockRelVarSetChecker.assert_called_with(model.schema, 8, relVarsPassed) mockRelVarSetChecker = MagicMock( wraps=RelationalValidity.checkValidityOfRelationalVariableSet) dsep.dSeparated(8, ['[A].X'], ['[A, AB, B, BC, C].Z'], ['[A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y'], relationalVariableSetChecker=mockRelVarSetChecker) self.assertEqual(1, mockRelVarSetChecker.call_count) relVarsPassed = { ParserUtil.parseRelVar('[A].X'), ParserUtil.parseRelVar('[A, AB, B, BC, C].Z'), ParserUtil.parseRelVar('[A, AB, B].Y'), ParserUtil.parseRelVar('[A, AB, B, BC, C, BC, B].Y') } mockRelVarSetChecker.assert_called_with(model.schema, 8, relVarsPassed)
def dictStrsToRelVars(self, attrToParents): return { ParserUtil.parseRelVar(attr): [ParserUtil.parseRelVar(parent) for parent in parents] for attr, parents in attrToParents.items() }
def relVarStrPairsToRelVarInts(self, relVarStrPairs): return [ RelationalVariableIntersection(ParserUtil.parseRelVar(relVarStr1), ParserUtil.parseRelVar(relVarStr2)) for relVarStr1, relVarStr2 in relVarStrPairs ]
def testParseRelationalVariable(self): relVarStr = '[A].X' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A'], actualRelVar.path) self.assertEqual('X', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) relVarStr = '[A].exists' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A'], actualRelVar.path) self.assertEqual('exists', actualRelVar.attrName) self.assertTrue(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) relVarStr = '[B].Y' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['B'], actualRelVar.path) self.assertEqual('Y', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) relVarStr = '[AB].XY' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['AB'], actualRelVar.path) self.assertEqual('XY', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) relVarStr = '[A, AB].XY' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A', 'AB'], actualRelVar.path) self.assertEqual('XY', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) relVarStr = '[A, AB, B].Y' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A', 'AB', 'B'], actualRelVar.path) self.assertEqual('Y', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) relVarStr = '[A, AB, B].exists' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A', 'AB', 'B'], actualRelVar.path) self.assertEqual('exists', actualRelVar.attrName) self.assertTrue(actualRelVar.isExistence()) self.assertEqual(relVarStr, str(actualRelVar)) # testing that spaces are ignored after commas between item names relVarStr = '[A,AB,B].Y' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A', 'AB', 'B'], actualRelVar.path) self.assertEqual('Y', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual('[A, AB, B].Y', str(actualRelVar)) # testing that spaces are ignored in attribute names relVarStr = '[A,AB,B].Y ' actualRelVar = ParserUtil.parseRelVar(relVarStr) self.assertTrue(isinstance(actualRelVar, RelationalVariable)) self.assertEqual(['A', 'AB', 'B'], actualRelVar.path) self.assertEqual('Y', actualRelVar.attrName) self.assertFalse(actualRelVar.isExistence()) self.assertEqual('[A, AB, B].Y', str(actualRelVar))
def testThreeEntityTwoRelationshipsAGG(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addEntity('C') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('C', 'Z') schema.addAttribute('AB', 'XY') schema.addAttribute('BC', 'YZ') model = Model(schema, []) aAGG = AbstractGroundGraph(model, 'A', 6) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in [ '[A].X', '[A, AB].XY', '[A, AB, B].Y', '[A, AB, B, AB].XY', '[A, AB, B, BC].YZ', '[A, AB, B, AB, A].X', '[A, AB, B, BC, C].Z', '[A, AB, B, AB, A, AB].XY', '[A, AB, B, BC, C, BC].YZ', '[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y' ] ] TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, aAGG.getRelationalVariableNodes()) expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y') ]) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, aAGG.getRelationalVariableIntersectionNodes()) self.assertAGGEdgesEqual([], aAGG) bcAGG = AbstractGroundGraph(model, 'BC', 4) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in [ '[BC].YZ', '[BC, B].Y', '[BC, C].Z', '[BC, B, AB].XY', '[BC, C, BC].YZ', '[BC, B, AB, A].X', '[BC, C, BC, B].Y', '[BC, B, AB, A, AB].XY', '[BC, C, BC, B, AB].XY' ] ] TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, bcAGG.getRelationalVariableNodes()) expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[BC, B].Y', '[BC, C, BC, B].Y'), ('[BC, B, AB].XY', '[BC, C, BC, B, AB].XY'), ('[BC, B, AB, A, AB].XY', '[BC, C, BC, B, AB].XY') ]) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, bcAGG.getRelationalVariableIntersectionNodes()) self.assertAGGEdgesEqual([], bcAGG) model = Model(schema, [ '[BC, B, AB, A].X -> [BC].YZ', '[AB, B, BC, C].Z -> [AB].XY', '[AB, B, AB, A, AB, B].Y -> [AB].XY' ]) aAGG = AbstractGroundGraph(model, 'A', 6) expectedEdges = self.relVarStrPairsToRelVarPairs([ ('[A].X', '[A, AB, B, BC].YZ'), ('[A, AB, B, AB, A].X', '[A, AB, B, BC].YZ'), ('[A, AB, B, BC, C].Z', '[A, AB].XY'), ('[A, AB, B, BC, C].Z', '[A, AB, B, AB].XY'), ('[A, AB, B, AB, A, AB, B].Y', '[A, AB].XY'), ('[A, AB, B].Y', '[A, AB, B, AB].XY'), ('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, AB].XY'), (('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y'), '[A, AB].XY'), (('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y'), '[A, AB, B, AB].XY') ]) self.assertAGGEdgesEqual(expectedEdges, aAGG)
def testManyToManyTwoEntityTwoRelationshipsAGGNodes(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB1', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addRelationship('AB2', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('AB1', 'XY1') schema.addAttribute('AB2', 'XY2') model = Model(schema, []) aAGG = AbstractGroundGraph(model, 'A', 4) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in [ '[A].X', '[A, AB1].XY1', '[A, AB2].XY2', '[A, AB1, B].Y', '[A, AB2, B].Y', '[A, AB1, B, AB1].XY1', '[A, AB1, B, AB2].XY2', '[A, AB2, B, AB1].XY1', '[A, AB2, B, AB2].XY2', '[A, AB1, B, AB1, A].X', '[A, AB1, B, AB2, A].X', '[A, AB2, B, AB1, A].X', '[A, AB2, B, AB2, A].X' ] ] expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[A, AB1].XY1', '[A, AB2, B, AB1].XY1'), ('[A, AB2].XY2', '[A, AB1, B, AB2].XY2'), ('[A, AB1, B].Y', '[A, AB2, B].Y'), ('[A, AB1, B, AB1].XY1', '[A, AB2, B, AB1].XY1'), ('[A, AB2, B, AB2].XY2', '[A, AB1, B, AB2].XY2'), ('[A, AB1, B, AB1, A].X', '[A, AB1, B, AB2, A].X'), ('[A, AB1, B, AB1, A].X', '[A, AB2, B, AB1, A].X'), ('[A, AB1, B, AB1, A].X', '[A, AB2, B, AB2, A].X'), ('[A, AB2, B, AB2, A].X', '[A, AB1, B, AB2, A].X'), ('[A, AB2, B, AB2, A].X', '[A, AB2, B, AB1, A].X'), ('[A, AB1, B, AB2, A].X', '[A, AB2, B, AB1, A].X') ]) TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, aAGG.getRelationalVariableNodes()) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, aAGG.getRelationalVariableIntersectionNodes()) self.assertAGGEdgesEqual([], aAGG) ab1AGG = AbstractGroundGraph(model, 'AB1', 4) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in [ '[AB1].XY1', '[AB1, A].X', '[AB1, B].Y', '[AB1, A, AB1].XY1', '[AB1, A, AB2].XY2', '[AB1, B, AB1].XY1', '[AB1, B, AB2].XY2', '[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y', '[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X', '[AB1, A, AB1, B, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1', '[AB1, A, AB1, B, AB2].XY2', '[AB1, A, AB2, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2' ] ] TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, ab1AGG.getRelationalVariableNodes()) expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[AB1, A].X', '[AB1, B, AB1, A].X'), ('[AB1, A].X', '[AB1, B, AB2, A].X'), ('[AB1, B].Y', '[AB1, A, AB1, B].Y'), ('[AB1, B].Y', '[AB1, A, AB2, B].Y'), ('[AB1, A, AB1].XY1', '[AB1, B, AB1].XY1'), ('[AB1, A, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1'), ('[AB1, A, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1'), ('[AB1, A, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'), ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'), ('[AB1, A, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'), ('[AB1, A, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'), ('[AB1, A, AB2].XY2', '[AB1, A, AB1, B, AB2].XY2'), ('[AB1, B, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'), ('[AB1, B, AB1].XY1', '[AB1, A, AB1, B, AB1].XY1'), ('[AB1, B, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1'), ('[AB1, B, AB2].XY2', '[AB1, A, AB2, B, AB2].XY2'), ('[AB1, B, AB2].XY2', '[AB1, A, AB1, B, AB2].XY2'), ('[AB1, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'), ('[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y'), ('[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X'), ('[AB1, A, AB1, B, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1'), ('[AB1, A, AB1, B, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1'), ('[AB1, A, AB1, B, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'), ('[AB1, A, AB2, B, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1'), ('[AB1, A, AB2, B, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'), ('[AB1, B, AB1, A, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'), ('[AB1, A, AB1, B, AB2].XY2', '[AB1, A, AB2, B, AB2].XY2'), ('[AB1, A, AB1, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'), ('[AB1, A, AB1, B, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'), ('[AB1, A, AB2, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'), ('[AB1, A, AB2, B, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'), ('[AB1, B, AB1, A, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2') ]) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, ab1AGG.getRelationalVariableIntersectionNodes()) self.assertAGGEdgesEqual([], aAGG) # test multiple relationships with two dependencies model = Model(schema, [ '[AB2, B, AB1, A].X -> [AB2].XY2', '[AB1, B, AB2].XY2 -> [AB1].XY1' ]) ab1AGG = AbstractGroundGraph(model, 'AB1', 3) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in [ '[AB1].XY1', '[AB1, A].X', '[AB1, B].Y', '[AB1, A, AB1].XY1', '[AB1, A, AB2].XY2', '[AB1, B, AB1].XY1', '[AB1, B, AB2].XY2', '[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y', '[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X' ] ] TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, ab1AGG.getRelationalVariableNodes()) expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[AB1, A].X', '[AB1, B, AB1, A].X'), ('[AB1, A].X', '[AB1, B, AB2, A].X'), ('[AB1, B].Y', '[AB1, A, AB1, B].Y'), ('[AB1, B].Y', '[AB1, A, AB2, B].Y'), ('[AB1, A, AB1].XY1', '[AB1, B, AB1].XY1'), ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'), ('[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y'), ('[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X') ]) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, ab1AGG.getRelationalVariableIntersectionNodes()) expectedEdges = self.relVarStrPairsToRelVarPairs([ ('[AB1, B, AB2].XY2', '[AB1].XY1'), ('[AB1, B, AB2].XY2', '[AB1, B, AB1].XY1'), ('[AB1, A].X', '[AB1, B, AB2].XY2'), ('[AB1, B, AB1, A].X', '[AB1, B, AB2].XY2'), (('[AB1, A].X', '[AB1, B, AB1, A].X'), '[AB1, B, AB2].XY2'), (('[AB1, A].X', '[AB1, B, AB2, A].X'), '[AB1, B, AB2].XY2'), ('[AB1, B, AB2].XY2', ('[AB1, A, AB1].XY1', '[AB1, B, AB1].XY1')), ('[AB1, A].X', ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2')), ('[AB1, B, AB1, A].X', ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2')), (('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'), '[AB1].XY1'), (('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'), '[AB1, B, AB1].XY1'), (('[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X'), '[AB1, B, AB2].XY2') ]) self.assertAGGEdgesEqual(expectedEdges, ab1AGG)
def testOneToManyTwoEntityAGG(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.ONE)) model = Model(schema, []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'A', 0), []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'B', 0), []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'AB', 0), []) schema.addAttribute('A', 'X') model = Model(schema, []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'A', 2), []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'B', 2), []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'AB', 2), []) schema.addAttribute('B', 'Y') model = Model(schema, []) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'A', 2), []) # putting in max hop threshold self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'B', 4), []) abAGG = AbstractGroundGraph(model, 'AB', 3) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in ['[AB, A].X', '[AB, B].Y', '[AB, A, AB, B].Y'] ] expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[AB, B].Y', '[AB, A, AB, B].Y') ]) TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, abAGG.getRelationalVariableNodes()) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, abAGG.getRelationalVariableIntersectionNodes()) self.assertAGGEdgesEqual([], abAGG) # test that order of relVar1, relVar2 for RelationalVariableIntersection doesn't matter expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[AB, A, AB, B].Y', '[AB, B].Y') ]) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, abAGG.getRelationalVariableIntersectionNodes()) model = Model(schema, ['[A, AB, B].Y -> [A].X']) aAGG = AbstractGroundGraph(model, 'A', 2) expectedEdges = self.relVarStrPairsToRelVarPairs([('[A, AB, B].Y', '[A].X')]) self.assertAGGEdgesEqual(expectedEdges, aAGG) # test that extended dependencies are only added among nodes that exist in the AGG (have an appropriate number of hops) bAGG = AbstractGroundGraph(model, 'B', 2) expectedEdges = self.relVarStrPairsToRelVarPairs([('[B].Y', '[B, AB, A].X')]) self.assertAGGEdgesEqual(expectedEdges, bAGG) bAGG = AbstractGroundGraph(model, 'B', 4) expectedEdges = self.relVarStrPairsToRelVarPairs([ ('[B].Y', '[B, AB, A].X'), ('[B, AB, A, AB, B].Y', '[B, AB, A].X') ]) self.assertAGGEdgesEqual(expectedEdges, bAGG) # test dependencies get inherited for intersection nodes abAGG = AbstractGroundGraph(model, 'AB', 3) expectedEdges = self.relVarStrPairsToRelVarPairs([ ('[AB, B].Y', '[AB, A].X'), ('[AB, A, AB, B].Y', '[AB, A].X'), (('[AB, A, AB, B].Y', '[AB, B].Y'), '[AB, A].X') ]) self.assertAGGEdgesEqual(expectedEdges, abAGG) schema.addAttribute('B', 'Z') model = Model(schema, []) abAGG = AbstractGroundGraph(model, 'AB', 3) expectedRelVarNodes = [ ParserUtil.parseRelVar(relVarStr) for relVarStr in [ '[AB, A].X', '[AB, B].Y', '[AB, A, AB, B].Y', '[AB, B].Z', '[AB, A, AB, B].Z' ] ] expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([ ('[AB, B].Y', '[AB, A, AB, B].Y'), ('[AB, B].Z', '[AB, A, AB, B].Z') ]) TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes, abAGG.getRelationalVariableNodes()) TestUtil.assertUnorderedListEqual( self, expectedRelVarIntNodes, abAGG.getRelationalVariableIntersectionNodes()) self.assertAGGEdgesEqual([], abAGG) model = Model(schema, [ '[A, AB, B].Y -> [A].X', '[A, AB, B].Z -> [A].X', '[B].Y -> [B].Z' ]) aAGG = AbstractGroundGraph(model, 'A', 2) expectedEdges = self.relVarStrPairsToRelVarPairs([ ('[A, AB, B].Y', '[A].X'), ('[A, AB, B].Z', '[A].X'), ('[A, AB, B].Y', '[A, AB, B].Z') ]) self.assertAGGEdgesEqual(expectedEdges, aAGG) abAGG = AbstractGroundGraph(model, 'AB', 3) expectedEdges = self.relVarStrPairsToRelVarPairs([ ('[AB, A, AB, B].Y', '[AB, A, AB, B].Z'), ('[AB, A, AB, B].Y', '[AB, A].X'), ('[AB, B].Y', '[AB, B].Z'), ('[AB, A, AB, B].Z', '[AB, A].X'), ('[AB, B].Y', '[AB, A].X'), ('[AB, B].Z', '[AB, A].X'), (('[AB, B].Y', '[AB, A, AB, B].Y'), '[AB, A].X'), (('[AB, B].Y', '[AB, A, AB, B].Y'), '[AB, B].Z'), (('[AB, B].Y', '[AB, A, AB, B].Y'), '[AB, A, AB, B].Z'), (('[AB, B].Z', '[AB, A, AB, B].Z'), '[AB, A].X'), ('[AB, A, AB, B].Y', ('[AB, B].Z', '[AB, A, AB, B].Z')), ('[AB, B].Y', ('[AB, B].Z', '[AB, A, AB, B].Z')) ]) self.assertAGGEdgesEqual(expectedEdges, abAGG)