def testCardinalities(self): schema = SchemaGenerator.generateSchema( 2, 1, entityAttrDistribution=ConstantDistribution(0), relationshipAttrDistribution=ConstantDistribution(0), cardinalityDistribution=ConstantDistribution(Schema.ONE)) expectedSchema = Schema() expectedSchema.addEntity('A') expectedSchema.addEntity('B') expectedSchema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) self.assertEqual(schema, expectedSchema) schema = SchemaGenerator.generateSchema( 2, 1, entityAttrDistribution=ConstantDistribution(0), relationshipAttrDistribution=ConstantDistribution(0), cardinalityDistribution=ConstantDistribution(Schema.MANY)) expectedSchema = Schema() expectedSchema.addEntity('A') expectedSchema.addEntity('B') expectedSchema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) self.assertEqual(schema, expectedSchema)
def testGenerateRelationshipAttributes(self): schema = SchemaGenerator.generateSchema( 2, 1, entityAttrDistribution=ConstantDistribution(0), relationshipAttrDistribution=ConstantDistribution(1), cardinalityDistribution=ConstantDistribution(Schema.ONE)) expectedSchema = Schema() expectedSchema.addEntity('A') expectedSchema.addEntity('B') expectedSchema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) expectedSchema.addAttribute('AB', 'XY1') self.assertEqual(schema, expectedSchema) schema = SchemaGenerator.generateSchema( 2, 2, entityAttrDistribution=ConstantDistribution(0), relationshipAttrDistribution=ConstantDistribution(2), cardinalityDistribution=ConstantDistribution(Schema.ONE)) expectedSchema.addRelationship('AB2', ('A', Schema.ONE), ('B', Schema.ONE)) expectedSchema.addAttribute('AB', 'XY2') expectedSchema.addAttribute('AB2', 'XY2_1') expectedSchema.addAttribute('AB2', 'XY2_2') self.assertEqual(schema, expectedSchema)
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 testIntersectingInputRelVars(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') model = Model(schema, []) dsep = DSeparation(model) self.assertFalse(dsep.dSeparated(0, ['[A].X1'], ['[A].X1'], [])) self.assertFalse( dsep.dSeparated(0, ['[A].X2', '[A].X1'], ['[A].X1', '[A].X2'], [])) self.assertFalse( dsep.dSeparated(0, ['[A].X2', '[A].X1'], ['[A].X1'], [])) 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, []) dsep = DSeparation(model) self.assertFalse( dsep.dSeparated(6, ['[A, AB, B, AB, A, AB, B].Y'], ['[A, AB, B, BC, C, BC, B].Y'], []))
def testDuplicateAttrNames(self): schemaWithEntityA = Schema() schemaWithEntityA.addEntity('A') schemaWithEntityA.addAttribute('A', 'X', Attribute.INTEGER) TestUtil.assertRaisesMessage( self, Exception, "Schema already has attribute named 'X' for item 'A'", schemaWithEntityA.addAttribute, 'A', 'X', Attribute.INTEGER) schemaWithEntityA.addEntity('B') schemaWithEntityA.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) schemaWithEntityA.addAttribute('AB', 'XY', Attribute.INTEGER) TestUtil.assertRaisesMessage( self, Exception, "Schema already has attribute named 'XY' for item 'AB'", schemaWithEntityA.addAttribute, 'AB', 'XY', Attribute.INTEGER) a = schemaWithEntityA.getEntity('A') TestUtil.assertRaisesMessage( self, Exception, "Schema already has attribute named 'X' for item 'A'", a.addAttribute, 'X', Attribute.INTEGER) ab = schemaWithEntityA.getRelationship('AB') TestUtil.assertRaisesMessage( self, Exception, "Schema already has attribute named 'XY' for item 'AB'", ab.addAttribute, 'XY', Attribute.INTEGER)
def testBadInput(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') schema.addAttribute('A', 'X2') dataStore = InMemoryDataStore() linearCITest = LinearCITest(schema, dataStore) TestUtil.assertRaisesMessage( self, Exception, "relVar1Str must be a parseable RelationalVariable string", linearCITest.isConditionallyIndependent, None, '[A].X2', []) TestUtil.assertRaisesMessage( self, Exception, "relVar2Str must be a parseable RelationalVariable string", linearCITest.isConditionallyIndependent, '[A].X1', None, []) TestUtil.assertRaisesMessage( self, Exception, "condRelVarStrs must be a sequence of parseable RelationalVariable strings", linearCITest.isConditionallyIndependent, '[A].X1', '[A].X2', None) TestUtil.assertRaisesMessage( self, Exception, "condRelVarStrs must be a sequence of parseable RelationalVariable strings", linearCITest.isConditionallyIndependent, '[A].X1', '[A].X2', '[A].X2') # relVar2Str MUST be singleton schema.addEntity('B') schema.addAttribute('B', 'Y', Attribute.FLOAT) schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) TestUtil.assertRaisesMessage(self, Exception, "relVar2Str must have a singleton path", linearCITest.isConditionallyIndependent, '[A].X1', '[A, AB, B].Y', [])
def testNoExistenceVariables(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)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('C', 'Z') schema.addAttribute('AB', 'XY') schema.addAttribute('BC', 'YZ') hop0 = ['[A].X', '[B].Y', '[C].Z', '[AB].XY', '[BC].YZ'] hop1 = ['[A, AB].XY', '[B, AB].XY', '[B, BC].YZ', '[C, BC].YZ', '[AB, A].X', '[AB, B].Y', '[BC, C].Z', '[BC, B].Y'] hop2 = ['[A, AB, B].Y', '[B, AB, A].X', '[B, BC, C].Z', '[C, BC, B].Y', '[AB, A, AB].XY', '[AB, B, BC].YZ', '[BC, C, BC].YZ', '[BC, B, AB].XY'] hop3 = ['[A, AB, B, BC].YZ', '[B, AB, A, AB].XY', '[B, BC, C, BC].YZ', '[C, BC, B, AB].XY', '[AB, A, AB, B].Y', '[AB, B, BC, C].Z', '[BC, C, BC, B].Y', '[BC, B, AB, A].X'] relVars = RelationalSpace.getRelationalVariables(schema, 3) self.assertTrue(all([isinstance(relVar, RelationalVariable) for relVar in relVars])) TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3, [str(relVar) for relVar in relVars])
def testDependencyValidity(self): # Model needs to pass in mock for dependencyChecker, make sure gets called exactly once per dependency mockRelDepChecker = MagicMock( wraps=RelationalValidity.checkRelationalDependencyValidity) schema = Schema() dependencies = [] Model(schema, dependencies, relationalDependencyChecker=mockRelDepChecker) self.assertEqual(0, mockRelDepChecker.call_count) schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') schema.addAttribute('A', 'V') schema.addEntity('B') schema.addAttribute('B', 'Y') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addEntity('C') schema.addAttribute('C', 'Z') schema.addAttribute('C', 'W') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) dependencies = [ '[B, AB, A].X -> [B].Y', '[C, BC, B].Y -> [C].Z', '[C].Z -> [C].W', '[A].X -> [A].V', '[A, AB, B, BC, C].W -> [A].V' ] mockRelDepChecker = MagicMock( wraps=RelationalValidity.checkRelationalDependencyValidity) Model(schema, dependencies, relationalDependencyChecker=mockRelDepChecker) self.assertEqual(5, mockRelDepChecker.call_count)
def testModelFileIO(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addEntity('C') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.MANY)) schema.addRelationship('BC', ('B', Schema.MANY), ('C', Schema.MANY)) schema.addAttribute('A', 'X', Attribute.INTEGER) schema.addAttribute('B', 'Y', Attribute.INTEGER) schema.addAttribute('C', 'Z', Attribute.INTEGER) schema.addAttribute('AB', 'XY1', Attribute.INTEGER) schema.addAttribute('AB', 'XY2', Attribute.INTEGER) schema.addAttribute('BC', 'YZ', Attribute.INTEGER) schema.toFile('schema.json') model = Model(schema, []) model.toFile('model.json') loadedModel = Model.fromFile('schema.json', 'model.json') self.assertEqual(model, loadedModel) model = Model(schema, ['[A, AB, B].Y -> [A].X']) model.toFile('model.json') loadedModel = Model.fromFile('schema.json', 'model.json') self.assertEqual(model, loadedModel) model = Model( schema, ['[A, AB, B].Y -> [A].X', '[AB, B, BC, C].Z -> [AB].exists']) model.toFile('model.json') loadedModel = Model.fromFile('schema.json', 'model.json') self.assertEqual(model, loadedModel)
def testCardinalities(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') TestUtil.assertRaisesMessage( self, Exception, "Bad cardinality for entity1 or entity2: xxxx one. Should be either Schema.ONE or Schema.MANY", schema.addRelationship, 'AB', ('A', 'xxxx'), ('B', Schema.ONE)) TestUtil.assertRaisesMessage( self, Exception, "Bad cardinality for entity1 or entity2: many xxxx. Should be either Schema.ONE or Schema.MANY", schema.addRelationship, 'AB', ('A', Schema.MANY), ('B', 'xxxx')) TestUtil.assertRaisesMessage( self, Exception, "Bad cardinality for entity1 or entity2: xxxx many. Should be either Schema.ONE or Schema.MANY", schema.addRelationship, 'AB', ('A', 'xxxx'), ('B', Schema.MANY)) TestUtil.assertRaisesMessage( self, Exception, "Bad cardinality for entity1 or entity2: one xxxx. Should be either Schema.ONE or Schema.MANY", schema.addRelationship, 'AB', ('A', Schema.ONE), ('B', 'xxxx')) schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) ab = schema.getRelationship('AB') self.assertEqual(Schema.ONE, ab.getCardinality('A')) self.assertEqual(Schema.ONE, ab.getCardinality('B')) schema.addEntity('C') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) bc = schema.getRelationship('BC') self.assertEqual(Schema.ONE, bc.getCardinality('B')) self.assertEqual(Schema.MANY, bc.getCardinality('C')) TestUtil.assertRaisesMessage( self, Exception, "Entity 'A' does not exist for relationship 'BC'", bc.getCardinality, 'A')
def testOneRelationshipOneToOne(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('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) schema = Schema() schema.addEntity('B') schema.addEntity('C') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.ONE)) relPaths = RelationalSpace.getRelationalPaths(schema, 0) hop0 = [['B'], ['C'], ['BC']] TestUtil.assertUnorderedListEqual(self, hop0, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 1) hop1 = [['B', 'BC'], ['BC', 'B'], ['BC', 'C'], ['C', 'BC']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 2) hop2 = [['B', 'BC', 'C'], ['C', 'BC', 'B']] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2, relPaths) relPaths = RelationalSpace.getRelationalPaths(schema, 3) hop3 = [] TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3, relPaths)
def testGetRelationshipsForEntity(self): schema = Schema() schema.addEntity('A') TestUtil.assertUnorderedListEqual( self, [], schema.getRelationshipsForEntity('A')) schema.addEntity('B') TestUtil.assertUnorderedListEqual( self, [], schema.getRelationshipsForEntity('B')) schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) ab = schema.getRelationship('AB') TestUtil.assertUnorderedListEqual( self, [ab], schema.getRelationshipsForEntity('A')) TestUtil.assertUnorderedListEqual( self, [ab], schema.getRelationshipsForEntity('B')) schema.addEntity('C') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.ONE)) bc = schema.getRelationship('BC') TestUtil.assertUnorderedListEqual( self, [ab], schema.getRelationshipsForEntity('A')) TestUtil.assertUnorderedListEqual( self, [ab, bc], schema.getRelationshipsForEntity('B')) TestUtil.assertUnorderedListEqual( self, [bc], schema.getRelationshipsForEntity('C')) # test for bad entity names TestUtil.assertRaisesMessage(self, Exception, "Entity 'XX' does not exist", schema.getRelationshipsForEntity, 'XX')
def testGetSchemaItems(self): schema = Schema() schema.addEntity('A') actualItems = schema.getSchemaItems() TestUtil.assertUnorderedListEqual(self, ['A'], [item.name for item in actualItems]) actualItem = schema.getSchemaItem('A') self.assertEqual('A', actualItem.name) self.assertTrue(schema.hasSchemaItem('A')) schema.addEntity('B') actualItems = schema.getSchemaItems() TestUtil.assertUnorderedListEqual(self, ['A', 'B'], [item.name for item in actualItems]) actualItem = schema.getSchemaItem('B') self.assertEqual('B', actualItem.name) self.assertTrue(schema.hasSchemaItem('B')) schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) actualItems = schema.getSchemaItems() TestUtil.assertUnorderedListEqual(self, ['A', 'B', 'AB'], [item.name for item in actualItems]) actualItem = schema.getSchemaItem('AB') self.assertEqual('AB', actualItem.name) self.assertTrue(schema.hasSchemaItem('AB')) TestUtil.assertRaisesMessage(self, Exception, "Schema item 'XX' does not exist", schema.getSchemaItem, 'XX') self.assertFalse(schema.hasSchemaItem('XX'))
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 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 testGetAncestors(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X') model = Model(schema, []) agg = AbstractGroundGraph(model, 'A', 0) self.assertGetAncestorsEquals(['[A].X'], agg, '[A].X') 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].C', '[A].A -> [A].D', '[A].B -> [A].D', '[A].C -> [A].E', '[A].D -> [A].E', '[A].E -> [A].G', '[A].E -> [A].H', '[A].F -> [A].H' ] model = Model(schema, dependencies) agg = AbstractGroundGraph(model, 'A', 0) self.assertGetAncestorsEquals( ['[A].G', '[A].A', '[A].B', '[A].C', '[A].D', '[A].E'], agg, '[A].G') self.assertGetAncestorsEquals( ['[A].F', '[A].A', '[A].B', '[A].C', '[A].D', '[A].E', '[A].H'], agg, '[A].H') 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' ]) agg = AbstractGroundGraph(model, 'A', 6) self.assertGetAncestorsEquals([ '[A, AB].XY', '[A, AB, B, BC, C].Z', '[A, AB, B, AB, A, AB, B].Y', ('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y') ], agg, '[A, AB].XY') self.assertGetAncestorsEquals( [('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y')], agg, ('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y'))
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)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') schema.addAttribute('C', 'Z') schema.addAttribute('AB', 'XY') schema.addAttribute('BC', 'YZ') hop0 = [] hop1 = [ '[A, AB].exists -> [A].X', '[B, AB].exists -> [B].Y', '[B, BC].exists -> [B].Y', '[C, BC].exists -> [C].Z', '[A, AB].XY -> [A].X', '[B, AB].XY -> [B].Y', '[B, BC].YZ -> [B].Y', '[C, BC].YZ -> [C].Z', '[AB, A].X -> [AB].exists', '[AB, A].X -> [AB].XY', '[AB, B].Y -> [AB].exists', '[AB, B].Y -> [AB].XY', '[BC, C].Z -> [BC].exists', '[BC, C].Z -> [BC].YZ', '[BC, B].Y -> [BC].exists', '[BC, B].Y -> [BC].YZ' ] hop2 = [ '[AB, A, AB].exists -> [AB].XY', '[AB, B, BC].exists -> [AB].exists', '[AB, B, BC].exists -> [AB].XY', '[BC, C, BC].exists -> [BC].YZ', '[BC, B, AB].exists -> [BC].exists', '[BC, B, AB].exists -> [BC].YZ', '[A, AB, B].Y -> [A].X', '[B, AB, A].X -> [B].Y', '[B, BC, C].Z -> [B].Y', '[C, BC, B].Y -> [C].Z', '[AB, B, BC].YZ -> [AB].exists', '[AB, B, BC].YZ -> [AB].XY', '[BC, B, AB].XY -> [BC].exists', '[BC, B, AB].XY -> [BC].YZ' ] hop3 = [ '[A, AB, B, BC].exists -> [A].X', '[B, AB, A, AB].exists -> [B].Y', '[B, BC, C, BC].exists -> [B].Y', '[C, BC, B, AB].exists -> [C].Z', '[A, AB, B, BC].YZ -> [A].X', '[B, AB, A, AB].XY -> [B].Y', '[B, BC, C, BC].YZ -> [B].Y', '[C, BC, B, AB].XY -> [C].Z', '[AB, A, AB, B].Y -> [AB].XY', '[AB, B, BC, C].Z -> [AB].exists', '[AB, B, BC, C].Z -> [AB].XY', '[BC, C, BC, B].Y -> [BC].YZ', '[BC, B, AB, A].X -> [BC].exists', '[BC, B, AB, A].X -> [BC].YZ' ] relDeps = RelationalSpace.getRelationalDependencies( schema, 3, includeExistence=True) self.assertTrue( all([ isinstance(relDep, RelationalDependency) for relDep in relDeps ])) TestUtil.assertUnorderedListEqual(self, hop0 + hop1 + hop2 + hop3, [str(relDep) for relDep in relDeps])
def testGetSubsumedRelVarInts(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.ONE)) schema.addAttribute('A', 'X') schema.addAttribute('B', 'Y') model = Model(schema, []) abAGG = AbstractGroundGraph(model, 'AB', 3) self.assertSameSubsumedVariables(['[AB, A].X'], abAGG, '[AB, A].X') self.assertSameSubsumedVariables( ['[AB, B].Y', ('[AB, B].Y', '[AB, A, AB, B].Y')], abAGG, '[AB, B].Y') self.assertSameSubsumedVariables( ['[AB, A, AB, B].Y', ('[AB, B].Y', '[AB, A, AB, B].Y')], abAGG, '[AB, A, AB, B].Y') 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) self.assertSameSubsumedVariables([ '[A, AB1, B, AB1, A].X', ('[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') ], aAGG, '[A, AB1, B, AB1, A].X') # test bad relVar input to getSubsumedVariables schema = Schema() schema.addEntity('A') model = Model(schema, []) agg = AbstractGroundGraph(model, 'A', 0) TestUtil.assertRaisesMessage( self, Exception, "relVar must be a RelationalVariable: found 'None'", agg.getSubsumedVariables, None) schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X1') model = Model(schema, []) agg = AbstractGroundGraph(model, 'A', 0) TestUtil.assertRaisesMessage( self, Exception, "relVar '[A].X2' is not a node in the abstract ground graph", agg.getSubsumedVariables, RelationalVariable(['A'], 'X2'))
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 testLinearCITestWithThreeEntityRDSJMLRExample(self): schema = Schema() schema.addEntity('A') schema.addAttribute('A', 'X', Attribute.FLOAT) schema.addEntity('B') schema.addAttribute('B', 'Y', Attribute.FLOAT) schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY)) schema.addEntity('C') schema.addAttribute('C', 'Z', Attribute.FLOAT) schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY)) dataStore = Sqlite3DataStore() dataStore.addTable(schema, 'A') dataStore.addTable(schema, 'B') dataStore.addTable(schema, 'C') dataStore.addTable(schema, 'AB') dataStore.addTable(schema, 'BC') aFile = open('citest/relational-data-a.csv', 'r') dataStore.loadCsvFile('A', ['id', 'X'], 'citest/relational-data-a.csv', aFile, ',', 2) bFile = open('citest/relational-data-b.csv', 'r') dataStore.loadCsvFile('B', ['id', 'Y'], 'citest/relational-data-b.csv', bFile, ',', 2) cFile = open('citest/relational-data-c.csv', 'r') dataStore.loadCsvFile('C', ['id', 'Z'], 'citest/relational-data-c.csv', cFile, ',', 2) abFile = open('citest/relational-data-ab.csv', 'r') dataStore.loadCsvFile('AB', ['id', 'a_id', 'b_id'], 'citest/relational-data-ab.csv', abFile, ',', 3) bcFile = open('citest/relational-data-bc.csv', 'r') dataStore.loadCsvFile('BC', ['id', 'b_id', 'c_id'], 'citest/relational-data-bc.csv', bcFile, ',', 3) linearCITest = LinearCITest(schema, dataStore) self.assertFalse( linearCITest.isConditionallyIndependent('[A, AB, B, BC, C].Z', '[A].X', [])) self.assertTrue( linearCITest.isConditionallyIndependent('[A, AB, B, BC, C].Z', '[A].X', ['[A, AB, B].Y'])) self.assertTrue( linearCITest.isConditionallyIndependent( '[A, AB, B, BC, C].Z', '[A].X', ['[A, AB, B].Y', '[A, AB, B, AB, A].X'])) linearCITest = LinearCITest(schema, dataStore, alpha=0.4, soeThreshold=0.001) self.assertFalse( linearCITest.isConditionallyIndependent('[A, AB, B, BC, C].Z', '[A].X', ['[A, AB, B].Y']))
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 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 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 testOneToManyRDS(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.ONE)) model = Model(schema, ['[B, AB, A].X -> [B].Y']) dsep = DSeparation(model) self.assertFalse(dsep.dSeparated(4, ['[B].Y'], ['[B, AB, A].X'], [])) self.assertFalse(dsep.dSeparated(4, ['[B, AB, A].X'], ['[B].Y'], [])) self.assertFalse(dsep.dSeparated(2, ['[A, AB, B].Y'], ['[A].X'], [])) self.assertFalse(dsep.dSeparated(2, ['[A].X'], ['[A, AB, B].Y'], [])) self.assertFalse(dsep.dSeparated(3, ['[AB, B].Y'], ['[AB, A].X'], [])) self.assertFalse(dsep.dSeparated(3, ['[AB, A].X'], ['[AB, B].Y'], [])) self.assertFalse( dsep.dSeparated(3, ['[AB, A].X'], ['[AB, A, AB, B].Y'], [])) schema.addAttribute('A', 'Z') model = Model(schema, ['[B, AB, A].X -> [B].Y', '[A, AB, B].Y -> [A].Z']) dsep = DSeparation(model) self.assertFalse( dsep.dSeparated(4, ['[B, AB, A].X'], ['[B, AB, A].Z'], [])) self.assertFalse(dsep.dSeparated(2, ['[A].Z'], ['[A].X'], [])) self.assertFalse(dsep.dSeparated(3, ['[AB, A].X'], ['[AB, A].Z'], [])) self.assertTrue( dsep.dSeparated(2, ['[A].X'], ['[A].Z'], ['[A, AB, B].Y'])) self.assertFalse( dsep.dSeparated(4, ['[B, AB, A].X'], ['[B, AB, A].Z'], ['[B].Y'])) self.assertFalse( dsep.dSeparated(4, ['[B, AB, A].X'], ['[B, AB, A].Z'], ['[B, AB, A, AB, B].Y'])) self.assertTrue( dsep.dSeparated(4, ['[B, AB, A].X'], ['[B, AB, A].Z'], ['[B].Y', '[B, AB, A, AB, B].Y'])) self.assertFalse( dsep.dSeparated(3, ['[AB, A].X'], ['[AB, A].Z'], ['[AB, B].Y'])) self.assertFalse( dsep.dSeparated(3, ['[AB, A].X'], ['[AB, A].Z'], ['[AB, A, AB, B].Y'])) # true with both, forces intersection between '[AB, B].Y', '[AB, A, AB, B].Y' to be included automatically self.assertTrue( dsep.dSeparated(3, ['[AB, A].X'], ['[AB, A].Z'], ['[AB, B].Y', '[AB, A, AB, B].Y']))
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 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 testSchemaFileIO(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addEntity('C') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.MANY)) schema.addRelationship('BC', ('B', Schema.MANY), ('C', Schema.MANY)) schema.addAttribute('A', 'X', Attribute.INTEGER) schema.addAttribute('B', 'Y', Attribute.INTEGER) schema.addAttribute('C', 'Z', Attribute.INTEGER) schema.addAttribute('AB', 'XY1', Attribute.INTEGER) schema.addAttribute('AB', 'XY2', Attribute.INTEGER) schema.addAttribute('BC', 'YZ', Attribute.INTEGER) schema.toFile('schema.json') loadedSchema = Schema.fromFile('schema.json') self.assertEqual(schema, loadedSchema)
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
def testOneRelationshipPerPairFlag(self): schema = SchemaGenerator.generateSchema( 2, 1, relationshipAttrDistribution=ConstantDistribution(0), cardinalityDistribution=ConstantDistribution(Schema.ONE), oneRelationshipPerPair=True) expectedSchema = Schema() expectedSchema.addEntity('A') expectedSchema.addEntity('B') expectedSchema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) self.assertEqual([expectedSchema.getRelationship('AB')], schema.getRelationshipsBetweenEntities('A', 'B')) schema = SchemaGenerator.generateSchema( 3, 2, relationshipAttrDistribution=ConstantDistribution(0), entityPairPicker=makePairPickerWithList([('A', 'B'), ('A', 'B'), ('A', 'C')]), cardinalityDistribution=ConstantDistribution(Schema.ONE), oneRelationshipPerPair=True) expectedSchema.addEntity('C') expectedSchema.addRelationship('AC', ('A', Schema.ONE), ('C', Schema.ONE)) self.assertEqual([expectedSchema.getRelationship('AB')], schema.getRelationshipsBetweenEntities('A', 'B')) self.assertEqual([expectedSchema.getRelationship('AC')], schema.getRelationshipsBetweenEntities('A', 'C')) schema = SchemaGenerator.generateSchema( 4, 4, relationshipAttrDistribution=ConstantDistribution(0), entityPairPicker=makePairPickerWithList([('A', 'B'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'D'), ('B', 'C')]), cardinalityDistribution=ConstantDistribution(Schema.ONE), oneRelationshipPerPair=True) expectedSchema.addEntity('D') expectedSchema.addRelationship('AD', ('A', Schema.ONE), ('D', Schema.ONE)) expectedSchema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.ONE)) self.assertEqual([expectedSchema.getRelationship('AB')], schema.getRelationshipsBetweenEntities('A', 'B')) self.assertEqual([expectedSchema.getRelationship('AC')], schema.getRelationshipsBetweenEntities('A', 'C')) self.assertEqual([expectedSchema.getRelationship('AD')], schema.getRelationshipsBetweenEntities('A', 'D')) self.assertEqual([expectedSchema.getRelationship('BC')], schema.getRelationshipsBetweenEntities('B', 'C'))
def testGetRelationship(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) actualRelationship = schema.getRelationship('AB') self.assertEqual('AB', actualRelationship.name) self.assertTrue(schema.hasRelationship('AB')) schema.addEntity('C') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.ONE)) actualRelationship = schema.getRelationship('BC') self.assertEqual('BC', actualRelationship.name) self.assertTrue(schema.hasRelationship('BC')) TestUtil.assertRaisesMessage(self, Exception, "Relationship 'XX' does not exist", schema.getRelationship, 'XX') self.assertFalse(schema.hasRelationship('XX'))
def testSchemaRelationships(self): schema = Schema() schema.addEntity('A') schema.addEntity('B') schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE)) actualRelationships = schema.getRelationships() actualNames = [rel.name for rel in actualRelationships] TestUtil.assertUnorderedListEqual(self, ['AB'], actualNames) schema.addEntity('C') schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.ONE)) actualRelationships = schema.getRelationships() actualNames = [rel.name for rel in actualRelationships] TestUtil.assertUnorderedListEqual(self, ['AB', 'BC'], actualNames) # verify that entity names for relationships actually exist TestUtil.assertRaisesMessage( self, Exception, "One of entity1Name or entity2Name not listed in entityNames: 'C', 'D'", schema.addRelationship, 'CD', ('C', Schema.ONE), ('D', Schema.ONE))