def testOneRelationship(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.MANY)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('AB', 'XY') relDeps = RelationalSpace.getRelationalDependencies( schema, 0, includeExistence=True) hop0 = [] self.assertTrue( all([ isinstance(relDep, RelationalDependency) for relDep in relDeps ])) TestUtil.assertUnorderedListEqual(self, hop0, [str(relDep) for relDep in relDeps]) relDeps = RelationalSpace.getRelationalDependencies( schema, 1, includeExistence=True) hop1 = [ '[A, AB].XY -> [A].X', '[A, AB].exists -> [A].X', '[AB, A].X -> [AB].XY', '[AB, A].X -> [AB].exists', '[AB, B].Y -> [AB].XY', '[AB, B].Y -> [AB].exists', '[B, AB].XY -> [B].Y', '[B, AB].exists -> [B].Y' ] self.assertTrue( all([ isinstance(relDep, RelationalDependency) for relDep in relDeps ])) TestUtil.assertUnorderedListEqual(self, hop0 + hop1, [str(relDep) for relDep in relDeps]) relDeps = RelationalSpace.getRelationalDependencies( schema, 2, includeExistence=True) hop2 = [ '[A, AB, B].Y -> [A].X', '[AB, B, AB].exists -> [AB].XY', '[B, AB, A].X -> [B].Y' ] self.assertTrue( all([ isinstance(relDep, RelationalDependency) for relDep in relDeps ])) TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2, [str(relDep) for relDep in relDeps]) relDeps = RelationalSpace.getRelationalDependencies( schema, 3, includeExistence=True) hop3 = [ '[A, AB, B, AB].XY -> [A].X', '[A, AB, B, AB].exists -> [A].X', '[AB, B, AB, A].X -> [AB].XY' ] self.assertTrue( all([ isinstance(relDep, RelationalDependency) for relDep in relDeps ])) TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3, [str(relDep) for relDep in relDeps])
def testPhaseI(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') model = Model(schema, []) mockOracle = MagicMock(wraps=Oracle(model)) mockModelProperty = PropertyMock() type(mockOracle).model = mockModelProperty pc = PC(schema, mockOracle) pc.pcPhaseI() self.assertEqual(0, mockModelProperty.call_count) # forces us not to cheat by simply returning the model self.assertPCOutputEqual(['[A].X'], [], {}, 0, pc.undirectedSkeleton, pc.sepsets, mockOracle) schema.addAttribute('A', 'Y') model = Model(schema, []) mockOracle = MagicMock(wraps=Oracle(model)) mockModelProperty = PropertyMock() type(mockOracle).model = mockModelProperty pc = PC(schema, mockOracle) pc.pcPhaseI() self.assertEqual(0, mockModelProperty.call_count) # forces us not to cheat by simply returning the model expectedSepset = {('[A].X', '[A].Y'): set(), ('[A].Y', '[A].X'): set()} self.assertPCOutputEqual(['[A].X', '[A].Y'], [], expectedSepset, 1, pc.undirectedSkeleton, pc.sepsets, mockOracle) model = Model(schema, ['[A].X -> [A].Y']) mockOracle = MagicMock(wraps=Oracle(model)) pc = PC(schema, mockOracle) pc.pcPhaseI() expectedNodes = ['[A].X', '[A].Y'] expectedEdges = [('[A].X', '[A].Y'), ('[A].Y', '[A].X')] self.assertPCOutputEqual(expectedNodes, expectedEdges, {}, 2, pc.undirectedSkeleton, pc.sepsets, mockOracle) schema.addAttribute('A', 'Z') model = Model(schema, ['[A].X -> [A].Y']) mockOracle = MagicMock(wraps=Oracle(model)) pc = PC(schema, mockOracle) pc.pcPhaseI() expectedNodes = ['[A].X', '[A].Y', '[A].Z'] expectedEdges = [('[A].X', '[A].Y'), ('[A].Y', '[A].X')] expectedSepset = {('[A].X', '[A].Z'): set(), ('[A].Z', '[A].X'): set(), ('[A].Y', '[A].Z'): set(), ('[A].Z', '[A].Y'): set()} self.assertPCOutputEqual(expectedNodes, expectedEdges, expectedSepset, 4, pc.undirectedSkeleton, pc.sepsets, mockOracle) model = Model(schema, ['[A].X -> [A].Z', '[A].Z -> [A].Y']) mockOracle = MagicMock(wraps=Oracle(model)) pc = PC(schema, mockOracle) pc.pcPhaseI() expectedNodes = ['[A].X', '[A].Y', '[A].Z'] expectedEdges = [('[A].X', '[A].Z'), ('[A].Z', '[A].X'), ('[A].Z', '[A].Y'), ('[A].Y', '[A].Z')] expectedSepset = {('[A].X', '[A].Y'): {'[A].Z'}, ('[A].Y', '[A].X'): {'[A].Z'}} expectedDSepCount = 9 self.assertPCOutputEqual(expectedNodes, expectedEdges, expectedSepset, expectedDSepCount, pc.undirectedSkeleton, pc.sepsets, mockOracle)
def testExtendPaths(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addAttribute('AB', 'XY1') schema.addAttribute('AB', 'XY2') schema.addAttribute('AB', 'XY3') from causality.dseparation import AbstractGroundGraph as AGG_module self.assertEqual([['AB', 'B', 'AB', 'A', 'AB', 'B', 'AB']], AGG_module.extendPath(schema, ['AB', 'B', 'AB'], ['AB', 'A', 'AB', 'B', 'AB']))
def testInvalidRelationalDependencies(self): 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') # Check that entire dependency is canonical (relVar2 has a singleton path) TestUtil.assertRaisesMessage( self, Exception, "Dependency '[B].Y -> [B, AB, A].X' is not canonical", RelationalValidity.checkRelationalDependencyValidity, schema, ParserUtil.parseRelDep('[B].Y -> [B, AB, A].X')) # Check that base items are the same in both paths TestUtil.assertRaisesMessage( self, Exception, "Dependency '[B].Y -> [A].X' has inconsistent base items", RelationalValidity.checkRelationalDependencyValidity, schema, ParserUtil.parseRelDep('[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.checkRelationalDependencyValidity( schema, ParserUtil.parseRelDep('[A, AB, B].Y -> [A].X'), relationalVariableChecker=mockRelVarChecker) self.assertEqual(2, mockRelVarChecker.call_count)
def testMaximumNumParentsArgument(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') schema.addAttribute('A', 'X3') dependencies = ['[A].X1 -> [A].X3', '[A].X2 -> [A].X3'] TestUtil.assertRaisesMessage(self, Exception, "Could not generate a model: failed to find a model with 2 dependenc[y|ies]", ModelGenerator.generateModel, schema, 0, 2, maxNumParents=1, dependencies=dependencies) schema.addAttribute('A', 'X4') dependencies = ['[A].X1 -> [A].X3', '[A].X2 -> [A].X3', '[A].X4 -> [A].X3'] TestUtil.assertRaisesMessage(self, Exception, "Could not generate a model: failed to find a model with 3 dependenc[y|ies]", ModelGenerator.generateModel, schema, 0, 3, maxNumParents=2, dependencies=dependencies)
def testTwoRelationships(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addEntity('C') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.ONE)) schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) relPaths = RelationalSpace.getRelationalPaths(schema, 0) hop0 = [['A'], ['B'], ['C'], ['AB'], ['BC']] TestUtil.assertUnorderedListEqual(self, hop0, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 1) hop1 = [['A', 'AB'], ['B', 'AB'], ['B', 'BC'], ['C', 'BC'], ['AB', 'A'], ['AB', 'B'], ['BC', 'C'], ['BC', 'B']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 2) hop2 = [['A', 'AB', 'B'], ['B', 'AB', 'A'], ['B', 'BC', 'C'], ['C', 'BC', 'B'], ['AB', 'A', 'AB'], ['AB', 'B', 'BC'], ['BC', 'C', 'BC'], ['BC', 'B', 'AB']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 3) hop3 = [['A', 'AB', 'B', 'BC'], ['B', 'AB', 'A', 'AB'], ['B', 'BC', 'C', 'BC'], ['C', 'BC', 'B', 'AB'], ['AB', 'A', 'AB', 'B'], ['AB', 'B', 'BC', 'C'], ['BC', 'C', 'BC', 'B'], ['BC', 'B', 'AB', 'A']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3, relPaths)
def testOneEntity(self): schema = Schema() schema.addEntity('A') relPaths = RelationalSpace.getRelationalPaths(schema, 0) TestUtil.assertUnorderedListEqual(self, [['A']], relPaths) schema = Schema() schema.addEntity('B') relPaths = RelationalSpace.getRelationalPaths(schema, 0) TestUtil.assertUnorderedListEqual(self, [['B']], relPaths) schema.addEntity('A') relPaths = RelationalSpace.getRelationalPaths(schema, 0) TestUtil.assertUnorderedListEqual(self, [['A'], ['B']], relPaths)
def testBadHopThresholdInput(self): # hop thresholds must be non-negative integers schema = Schema() schema.addEntity('A') model = Model(schema, []) TestUtil.assertRaisesMessage( self, Exception, "hopThreshold must be a non-negative integer", AbstractGroundGraph, model, 'A', None) TestUtil.assertRaisesMessage( self, Exception, "hopThreshold must be a non-negative integer", AbstractGroundGraph, model, 'A', 1.5) TestUtil.assertRaisesMessage( self, Exception, "hopThreshold must be a non-negative integer", AbstractGroundGraph, model, 'A', -1)
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 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 testPCObj(self): schema = Schema() model = Model(schema, []) oracle = Oracle(model) pc = PC(schema, oracle) self.assertEqual(schema, pc.schema) self.assertEqual(oracle.model, pc.oracle.model)
def testNoSkeletonBeforePhaseII(self): # must have an undirected skeleton and sepsets before running Phase II schema = Schema() model = Model(schema, []) pc = PC(schema, Oracle(model)) TestUtil.assertRaisesMessage(self, Exception, "No undirected skeleton found. Try running Phase I first.", pc.pcPhaseII) # what if we set the skeleton to None? pc = PC(schema, Oracle(model)) pc.undirectedSkeleton = None TestUtil.assertRaisesMessage(self, Exception, "No undirected skeleton found. Try running Phase I first.", pc.pcPhaseII) # what if we don't set the sepset? pc = PC(schema, Oracle(model)) pc.setUndirectedSkeleton(nx.DiGraph()) TestUtil.assertRaisesMessage(self, Exception, "No sepsets found. Try running Phase I first.", pc.pcPhaseII) # what if we set the sepsets to None? pc = PC(schema, Oracle(model)) pc.setUndirectedSkeleton(nx.DiGraph()) pc.sepsets = None TestUtil.assertRaisesMessage(self, Exception, "No sepsets found. Try running Phase I first.", pc.pcPhaseII)
def testTwoEntities(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.MANY)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('AB', 'XY') dependencies = ['[A, AB].XY -> [A].X', '[A, AB].exists -> [A].X', '[AB, A].X -> [AB].XY', '[AB, A].X -> [AB].exists', '[AB, B].Y -> [AB].XY', '[AB, B].Y -> [AB].exists', '[B, AB].XY -> [B].Y', '[B, AB].exists -> [B].Y', '[A, AB, B].Y -> [A].X', '[AB, B, AB].exists -> [AB].XY', '[B, AB, A].X -> [B].Y'] model = ModelGenerator.generateModel(schema, 2, 3, dependencies=dependencies, randomPicker=lambda depsList, _: [depsList[0]]) self.assertIsInstance(model, Model) TestUtil.assertUnorderedListEqual(self, ['[A, AB].XY -> [A].X', '[A, AB].exists -> [A].X', '[AB, B].Y -> [AB].XY'], [str(dep) for dep in model.dependencies])
def testSetSepsets(self): schema = Schema() model = Model(schema, []) pc = PC(schema, Oracle(model)) pc.setSepsets({}) self.assertEqual({}, pc.sepsets) TestUtil.assertRaisesMessage(self, Exception, "Sepsets must be a dictionary: found None", pc.setSepsets, None)
def testSchemaEntities(self): schemaWithEntityA = Schema() schemaWithEntityA.addEntity('A') actualEntities = schemaWithEntityA.getEntities() TestUtil.assertUnorderedListEqual(self, ['A'], [ent.name for ent in actualEntities]) schemaWithEntityA.addEntity('B') actualEntities = schemaWithEntityA.getEntities() TestUtil.assertUnorderedListEqual(self, ['A', 'B'], [ent.name for ent in actualEntities])
def testChoseTooFewDependencies(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') schema.addAttribute('A', 'X3') dependencies = ['[A].X3 -> [A].X1', '[A].X1 -> [A].X2', '[A].X2 -> [A].X3', '[A].X2 -> [A].X1', '[A].X1 -> [A].X3', '[A].X3 -> [A].X2'] TestUtil.assertRaisesMessage(self, Exception, "Could not generate a model: failed to find a model with 4 dependenc[y|ies]", ModelGenerator.generateModel, schema, 0, 4, dependencies=dependencies, randomPicker=lambda depsList, _: [depsList[0]])
def testBadHopThreshold(self): schema = Schema() TestUtil.assertRaisesMessage( self, Exception, "Hop threshold must be a number: found 'XX'", RelationalSpace.getRelationalPaths, schema, 'XX') TestUtil.assertRaisesMessage(self, Exception, "Hop threshold must be >= 0: found -1", RelationalSpace.getRelationalPaths, schema, -1)
def testGetEntity(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') actualEntity = schema.getEntity('A') self.assertEqual('A', actualEntity.name) self.assertTrue(schema.hasEntity('A')) actualEntity = schema.getEntity('B') self.assertEqual('B', actualEntity.name) self.assertTrue(schema.hasEntity('B')) TestUtil.assertRaisesMessage(self, Exception, "Entity 'XX' does not exist", schema.getEntity, 'XX') self.assertFalse(schema.hasEntity('XX'))
def testLongRangeDependencyIsIgnored(self): # Build AGG with model with a dependency that is longer than hop threshold # the long-range dependence is not (B,h)-reachable for the AGG from perspective B schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.ONE)) schema.addAttribute('B', 'Y1') schema.addAttribute('B', 'Y2') model = Model(schema, ['[B, AB, A, AB, B].Y1 -> [B].Y2']) self.assertAGGEqualNoIntersection(schema, AbstractGroundGraph(model, 'B', 2), [])
def testRemoveCommonCondRelVarOnlyFromRelVars(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') schema.addAttribute('A', 'X3') model = Model(schema, ['[A].X1 -> [A].X2', '[A].X2 -> [A].X3']) dsep = DSeparation(model) self.assertTrue( dsep.dSeparated(0, ['[A].X1', '[A].X2'], ['[A].X3'], ['[A].X2'])) self.assertTrue( dsep.dSeparated(0, ['[A].X1', '[A].X2'], ['[A].X2', '[A].X3'], ['[A].X2']))
def testAddEntityAttribute(self): a = Entity('A') a.addAttribute('X', Attribute.INTEGER) TestUtil.assertUnorderedListEqual(self, ['X'], [attr.name for attr in a.attributes]) a.addAttribute('Y', Attribute.INTEGER) TestUtil.assertUnorderedListEqual(self, ['X', 'Y'], [attr.name for attr in a.attributes]) schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X', Attribute.INTEGER) TestUtil.assertUnorderedListEqual( self, ['X'], [attr.name for attr in schema.getEntity('A').attributes]) schema.addAttribute('A', 'Y', Attribute.INTEGER) TestUtil.assertUnorderedListEqual( self, ['X', 'Y'], [attr.name for attr in schema.getEntity('A').attributes])
def testOneRelationshipOneToMany(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.ONE)) relPaths = RelationalSpace.getRelationalPaths(schema, 0) hop0 = [['A'], ['B'], ['AB']] TestUtil.assertUnorderedListEqual(self, hop0, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 1) hop1 = [['A', 'AB'], ['AB', 'A'], ['AB', 'B'], ['B', 'AB']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 2) hop2 = [['A', 'AB', 'B'], ['AB', 'A', 'AB'], ['B', 'AB', 'A']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 3) hop3 = [['AB', 'A', 'AB', 'B'], ['B', 'AB', 'A', 'AB']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 4) hop4 = [['B', 'AB', 'A', 'AB', 'B']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3 + hop4, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 5) hop5 = [] TestUtil.assertUnorderedListEqual( self, hop0 + hop1 + hop2 + hop3 + hop4 + hop5, relPaths)
def testBadRelVarInput(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') model = Model(schema, []) dsep = DSeparation(model) TestUtil.assertRaisesMessage( self, Exception, "relVars1 must be a non-empty sequence of parseable RelationalVariable strings", dsep.dSeparated, 0, None, ['[A].X2'], []) TestUtil.assertRaisesMessage( self, Exception, "relVars2 must be a non-empty sequence of parseable RelationalVariable strings", dsep.dSeparated, 0, ['[A].X1'], None, []) TestUtil.assertRaisesMessage( self, Exception, "condRelVars must be a sequence of parseable RelationalVariable strings", dsep.dSeparated, 0, ['[A].X1'], ['[A].X2'], None) TestUtil.assertRaisesMessage( self, Exception, "relVars1 must be a non-empty sequence of parseable RelationalVariable strings", dsep.dSeparated, 0, [], ['[A].X2'], []) TestUtil.assertRaisesMessage( self, Exception, "relVars2 must be a non-empty sequence of parseable RelationalVariable strings", DSeparation.dSeparated, model, 0, ['[A].X1'], [], [])
def testPCLearnModel(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') schema.addAttribute('A', 'Y') schema.addAttribute('A', 'Z') schema.addAttribute('A', 'W') model = Model(schema, ['[A].X -> [A].Y', '[A].X -> [A].W', '[A].X -> [A].Z', '[A].Y -> [A].Z', '[A].W -> [A].Z']) pc = PC(schema, Oracle(model)) pc.learnModel() expectedNodes = ['[A].X', '[A].Y', '[A].Z', '[A].W'] expectedEdges = [('[A].X', '[A].Z'), ('[A].Y', '[A].Z'), ('[A].W', '[A].Z'), ('[A].X', '[A].Y'), ('[A].Y', '[A].X'), ('[A].W', '[A].X'), ('[A].X', '[A].W')] self.assertPCOutputEqual(expectedNodes, expectedEdges, None, None, pc.partiallyDirectedGraph, None, None)
def testOracle(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') schema.addAttribute('A', 'X3') schema.addAttribute('A', 'X4') model = Model( schema, ['[A].X1 -> [A].X3', '[A].X2 -> [A].X3', '[A].X3 -> [A].X4']) oracle = Oracle(model) self.assertTrue(isinstance(oracle, CITest)) self.assertTrue( oracle.isConditionallyIndependent('[A].X1', '[A].X2', [])) self.assertFalse( oracle.isConditionallyIndependent('[A].X1', '[A].X2', ['[A].X3'])) self.assertFalse( oracle.isConditionallyIndependent( '[A].X1', '[A].X2', ['[A].X4'])) # tests conditioning on descendant of a collider self.assertFalse( oracle.isConditionallyIndependent('[A].X1', '[A].X2', ['[A].X3', '[A].X4'])) # model has multiple paths model = Model(schema, [ '[A].X1 -> [A].X3', '[A].X1 -> [A].X2', '[A].X2 -> [A].X4', '[A].X4 -> [A].X3' ]) oracle = Oracle(model) self.assertFalse( oracle.isConditionallyIndependent('[A].X1', '[A].X4', [])) self.assertTrue( oracle.isConditionallyIndependent('[A].X1', '[A].X4', ['[A].X2'])) self.assertFalse( oracle.isConditionallyIndependent('[A].X1', '[A].X4', ['[A].X2', '[A].X3'])) self.assertFalse( oracle.isConditionallyIndependent('[A].X2', '[A].X3', [])) self.assertFalse( oracle.isConditionallyIndependent('[A].X2', '[A].X3', ['[A].X1'])) self.assertFalse( oracle.isConditionallyIndependent('[A].X2', '[A].X3', ['[A].X4'])) self.assertTrue( oracle.isConditionallyIndependent('[A].X2', '[A].X3', ['[A].X1', '[A].X4']))
def testPhaseIBiggerConditionalSets(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') schema.addAttribute('A', 'Y') schema.addAttribute('A', 'Z') schema.addAttribute('A', 'W') model = Model(schema, ['[A].X -> [A].Y', '[A].X -> [A].Z', '[A].Y -> [A].W', '[A].Z -> [A].W']) pc = PC(schema, Oracle(model)) pc.pcPhaseI() expectedNodes = ['[A].X', '[A].Y', '[A].Z', '[A].W'] expectedEdges = [('[A].X', '[A].Y'), ('[A].Y', '[A].X'), ('[A].X', '[A].Z'), ('[A].Z', '[A].X'), ('[A].W', '[A].Y'), ('[A].Y', '[A].W'), ('[A].W', '[A].Z'), ('[A].Z', '[A].W')] expectedSepset = {('[A].X', '[A].W'): {'[A].Y', '[A].Z'}, ('[A].W', '[A].X'): {'[A].Y', '[A].Z'}, ('[A].Y', '[A].Z'): {'[A].X'}, ('[A].Z', '[A].Y'): {'[A].X'}} self.assertPCOutputEqual(expectedNodes, expectedEdges, expectedSepset, None, pc.undirectedSkeleton, pc.sepsets, None)
def testOneRelationshipManyToOne(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.MANY)) relPaths = RelationalSpace.getRelationalPaths(schema, 3) hopUpTo3 = [['A'], ['B'], ['AB'], ['A', 'AB'], ['AB', 'A'], ['AB', 'B'], ['B', 'AB'], ['A', 'AB', 'B'], ['AB', 'B', 'AB'], ['B', 'AB', 'A'], ['A', 'AB', 'B', 'AB'], ['AB', 'B', 'AB', 'A']] TestUtil.assertUnorderedListEqual(self, hopUpTo3, relPaths)
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 testTwoVariableModels(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') model = Model(schema, []) dsep = DSeparation(model) self.assertTrue(dsep.dSeparated(0, ['[A].X1'], ['[A].X2'], [])) self.assertTrue(dsep.dSeparated(0, ['[A].X2'], ['[A].X1'], [])) model = Model(schema, ['[A].X1 -> [A].X2']) dsep = DSeparation(model) self.assertFalse(dsep.dSeparated(0, ['[A].X1'], ['[A].X2'], [])) self.assertFalse(dsep.dSeparated(0, ['[A].X2'], ['[A].X1'], []))
def testGenerateEntities(self): schema = SchemaGenerator.generateSchema(0, 0) expectedSchema = Schema() self.assertEqual(schema, expectedSchema) schema = SchemaGenerator.generateSchema( 1, 0, entityAttrDistribution=ConstantDistribution(0)) expectedSchema.addEntity('A') self.assertEqual(schema, expectedSchema) schema = SchemaGenerator.generateSchema( 2, 0, entityAttrDistribution=ConstantDistribution(0)) expectedSchema.addEntity('B') self.assertEqual(schema, expectedSchema)
def incompleteness_example(): schema = Schema() schema.addEntity("E1") schema.addEntity("E2") schema.addEntity("E3") schema.addRelationship("R1", ("E1", Schema.ONE), ("E2", Schema.ONE)) schema.addRelationship("R2", ("E2", Schema.ONE), ("E3", Schema.ONE)) schema.addRelationship("R3", ("E2", Schema.ONE), ("E3", Schema.ONE)) schema.addAttribute("R1", "X") schema.addAttribute("R2", "Y") schema.addAttribute("E2", "Z") d1 = RelationalDependency(RelationalVariable(["R2", "E2", "R1"], "X"), RelationalVariable(["R2"], "Y")) d2 = RelationalDependency(RelationalVariable(["R2", "E3", "R3", "E2"], "Z"), RelationalVariable(["R2"], "Y")) d3 = RelationalDependency(RelationalVariable(["R1", "E2", "R2", "E3", "R3", "E2"], "Z"), RelationalVariable(["R1"], "X")) model = Model(schema, [d1, d2, d3]) return schema, model