Esempio n. 1
0
    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)
Esempio n. 2
0
    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'], []))
Esempio n. 3
0
    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)
Esempio n. 4
0
    def testPropositionalAGG(self):
        schema = Schema()
        schema.addEntity('A')
        model = Model(schema, [])
        agg = AbstractGroundGraph(model, 'A', 0)
        self.assertAGGEqualNoIntersection(schema, agg, [])

        schema.addAttribute('A', 'A')
        schema.addAttribute('A', 'B')
        schema.addAttribute('A', 'C')
        model = Model(schema, [])
        agg = AbstractGroundGraph(model, 'A', 0)
        self.assertAGGEqualNoIntersection(schema, agg, [])

        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)
        self.assertAGGEqualNoIntersection(schema, agg, dependencies)
Esempio n. 5
0
    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)
Esempio n. 6
0
    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'))
Esempio n. 7
0
    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'))
Esempio n. 8
0
    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()))
Esempio n. 9
0
    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'], []))
Esempio n. 10
0
    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']))
Esempio n. 11
0
    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)
Esempio n. 12
0
 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)
Esempio n. 13
0
    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'], [], [])
Esempio n. 14
0
    def testCondRelVarsSameAsOneRelVar(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].X1 -> [A].X3'])
        dsep = DSeparation(model)
        self.assertTrue(dsep.dSeparated(0, ['[A].X1'], ['[A].X2'], ['[A].X2']))
        self.assertTrue(dsep.dSeparated(0, ['[A].X1'], ['[A].X2'], ['[A].X1']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].X1'], ['[A].X2'], ['[A].X1', '[A].X2']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].X1'], ['[A].X2', '[A].X3'],
                            ['[A].X1', '[A].X2']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].X1'], ['[A].X2', '[A].X3'],
                            ['[A].X2', '[A].X3']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].X2', '[A].X3'], ['[A].X1'],
                            ['[A].X2', '[A].X3']))

        # test for sequences of length > 1
        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)
        dsep = DSeparation(model)
        self.assertTrue(
            dsep.dSeparated(0, ['[A].A', '[A].E'], ['[A].D', '[A].H'],
                            ['[A].B', '[A].C', '[A].E', '[A].H']))
        self.assertFalse(
            dsep.dSeparated(0, ['[A].A', '[A].E', '[A].F'],
                            ['[A].D', '[A].H', '[A].G'],
                            ['[A].B', '[A].C', '[A].E', '[A].H']))
Esempio n. 15
0
    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']))
Esempio n. 16
0
    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)
Esempio n. 17
0
    def testBadPerspective(self):
        schema = Schema()
        model = Model(schema, [])
        # non-string
        TestUtil.assertRaisesMessage(
            self, Exception, "Perspective must be a valid schema item name",
            AbstractGroundGraph, model, None, 0)

        # string, but bad item name
        TestUtil.assertRaisesMessage(
            self, Exception, "Perspective must be a valid schema item name",
            AbstractGroundGraph, model, 'A', 0)

        schema = Schema()
        schema.addEntity('A')
        model = Model(schema, [])
        TestUtil.assertRaisesMessage(
            self, Exception, "Perspective must be a valid schema item name",
            AbstractGroundGraph, model, 'B', 0)
Esempio n. 18
0
    def testOneToOneRDS(self):
        schema = Schema()
        schema.addEntity('A')
        schema.addAttribute('A', 'X')
        schema.addEntity('B')
        schema.addAttribute('B', 'Y')
        schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE))
        model = Model(schema, [])
        dsep = DSeparation(model)
        self.assertTrue(dsep.dSeparated(2, ['[A, AB, B].Y'], ['[A].X'], []))
        self.assertTrue(dsep.dSeparated(2, ['[A].X'], ['[A, AB, B].Y'], []))
        self.assertTrue(dsep.dSeparated(2, ['[B].Y'], ['[B, AB, A].X'], []))
        self.assertTrue(dsep.dSeparated(2, ['[B, AB, A].X'], ['[B].Y'], []))
        self.assertTrue(dsep.dSeparated(1, ['[AB, B].Y'], ['[AB, A].X'], []))
        self.assertTrue(dsep.dSeparated(1, ['[AB, A].X'], ['[AB, B].Y'], []))

        model = Model(schema, ['[B, AB, A].X -> [B].Y'])
        dsep = DSeparation(model)
        self.assertFalse(dsep.dSeparated(2, ['[B].Y'], ['[B, AB, A].X'], []))
        self.assertFalse(dsep.dSeparated(2, ['[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(1, ['[AB, B].Y'], ['[AB, A].X'], []))
        self.assertFalse(dsep.dSeparated(1, ['[AB, A].X'], ['[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(2, ['[B, AB, A].X'], ['[B, AB, A].Z'], []))
        self.assertFalse(dsep.dSeparated(2, ['[A].Z'], ['[A].X'], []))
        self.assertFalse(dsep.dSeparated(1, ['[AB, A].X'], ['[AB, A].Z'], []))

        self.assertTrue(
            dsep.dSeparated(2, ['[A].X'], ['[A].Z'], ['[A, AB, B].Y']))
        self.assertTrue(
            dsep.dSeparated(1, ['[AB, A].X'], ['[AB, A].Z'], ['[AB, B].Y']))
        self.assertTrue(
            dsep.dSeparated(2, ['[B, AB, A].X'], ['[B, AB, A].Z'], ['[B].Y']))
Esempio n. 19
0
 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),
                                       [])
Esempio n. 20
0
 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']))
Esempio n. 21
0
 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)
Esempio n. 22
0
 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)
Esempio n. 23
0
    def testFourVariableModels(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'])
        dsep = DSeparation(model)
        self.assertTrue(dsep.dSeparated(0, ['[A].X1'], ['[A].X2'], []))
        self.assertFalse(dsep.dSeparated(0, ['[A].X1'], ['[A].X2'],
                                         ['[A].X3']))
        self.assertFalse(dsep.dSeparated(
            0, ['[A].X1'], ['[A].X2'],
            ['[A].X4']))  # tests conditioning on descendant of a collider
        self.assertFalse(
            dsep.dSeparated(0, ['[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'
        ])
        dsep = DSeparation(model)
        self.assertFalse(dsep.dSeparated(0, ['[A].X1'], ['[A].X4'], []))
        self.assertTrue(dsep.dSeparated(0, ['[A].X1'], ['[A].X4'], ['[A].X2']))
        self.assertFalse(
            dsep.dSeparated(0, ['[A].X1'], ['[A].X4'], ['[A].X2', '[A].X3']))
        self.assertFalse(dsep.dSeparated(0, ['[A].X2'], ['[A].X3'], []))
        self.assertFalse(dsep.dSeparated(0, ['[A].X2'], ['[A].X3'],
                                         ['[A].X1']))
        self.assertFalse(dsep.dSeparated(0, ['[A].X2'], ['[A].X3'],
                                         ['[A].X4']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].X2'], ['[A].X3'], ['[A].X1', '[A].X4']))
Esempio n. 24
0
    def testMakeModel(self):
        model = Model(self.schema, [])
        self.assertEqual([], model.dag.nodes())

        self.schema.addEntity('A')
        self.schema.addAttribute('A', 'X')
        self.schema.addEntity('B')
        self.schema.addRelationship('AB', ('A', Schema.ONE), ('B', Schema.ONE))
        model = Model(self.schema, [])
        TestUtil.assertUnorderedListEqual(
            self, ['[A].exists', '[B].exists', '[AB].exists', '[A].X'],
            [str(attr) for attr in model.dag.nodes()])
        TestUtil.assertUnorderedListEqual(self, [('[A].exists', '[AB].exists'),
                                                 ('[B].exists', '[AB].exists'),
                                                 ('[A].exists', '[A].X')],
                                          [(str(edge[0]), str(edge[1]))
                                           for edge in model.dag.edges()])
        self.assertEqual([], model.dependencies)

        self.schema.addAttribute('B', 'Y')
        dependencies = ['[A, AB, B].Y -> [A].X']
        model = Model(self.schema, dependencies)
        TestUtil.assertUnorderedListEqual(
            self,
            ['[A].exists', '[B].exists', '[AB].exists', '[B].Y', '[A].X'],
            [str(attr) for attr in model.dag.nodes()])
        TestUtil.assertUnorderedListEqual(self, [('[A].exists', '[AB].exists'),
                                                 ('[B].exists', '[AB].exists'),
                                                 ('[A].exists', '[A].X'),
                                                 ('[AB].exists', '[A].X'),
                                                 ('[B].exists', '[A].X'),
                                                 ('[B].exists', '[B].Y'),
                                                 ('[B].Y', '[A].X')],
                                          [(str(edge[0]), str(edge[1]))
                                           for edge in model.dag.edges()])
        self.assertEqual(dependencies,
                         [str(relDep) for relDep in model.dependencies])
Esempio n. 25
0
 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)
Esempio n. 26
0
    def testBadInput(self):
        model = Model(Schema(), [])
        for method in [
                ModelEvaluation.skeletonPrecision,
                ModelEvaluation.skeletonRecall,
                ModelEvaluation.orientedPrecision,
                ModelEvaluation.orientedRecall
        ]:

            TestUtil.assertRaisesMessage(
                self, Exception,
                "learnedDependencies must be a list of RelationalDependencies "
                "or parseable RelationalDependency strings", method, model,
                None)

            TestUtil.assertRaisesMessage(
                self, Exception,
                "learnedDependencies must be a list of RelationalDependencies "
                "or parseable RelationalDependency strings", method, model,
                'dependency')
Esempio n. 27
0
 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)
Esempio n. 28
0
    def testEightVariableModel(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].C', '[A].A -> [A].D', '[A].B -> [A].D',
            '[A].B -> [A].F', '[A].C -> [A].E', '[A].D -> [A].E',
            '[A].E -> [A].G', '[A].E -> [A].H', '[A].F -> [A].H'
        ]
        model = Model(schema, dependencies)
        dsep = DSeparation(model)
        self.assertFalse(dsep.dSeparated(0, ['[A].A'], ['[A].E'], []))
        self.assertFalse(dsep.dSeparated(0, ['[A].A'], ['[A].E'], ['[A].C']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].A'], ['[A].E'], ['[A].C', '[A].D']))
        self.assertFalse(dsep.dSeparated(0, ['[A].B'], ['[A].E'], []))
        self.assertFalse(dsep.dSeparated(0, ['[A].B'], ['[A].E'], ['[A].D']))
        self.assertTrue(
            dsep.dSeparated(0, ['[A].B'], ['[A].E'], ['[A].C', '[A].D']))
        self.assertFalse(
            dsep.dSeparated(0, ['[A].B'], ['[A].E'],
                            ['[A].C', '[A].D', '[A].H']))

        # testing d-separation with sets of relVars
        self.assertFalse(
            dsep.dSeparated(0, ['[A].A', '[A].C'], {'[A].F', '[A].H'}, []))
        self.assertFalse(
            dsep.dSeparated(0, ('[A].A', '[A].C'), {'[A].F', '[A].H'},
                            ['[A].E']))
        self.assertTrue(
            dsep.dSeparated(0, ('[A].A', '[A].C'), {'[A].F', '[A].H'},
                            {'[A].B', '[A].E'}))
Esempio n. 29
0
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
Esempio n. 30
0
    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)