Пример #1
0
    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)
Пример #2
0
 def createAGGNodeObj(self, aggNodeStr):
     if isinstance(aggNodeStr, str):
         return ParserUtil.parseRelVar(aggNodeStr)
     else:
         return RelationalVariableIntersection(
             ParserUtil.parseRelVar(aggNodeStr[0]),
             ParserUtil.parseRelVar(aggNodeStr[1]))
Пример #3
0
    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)
Пример #4
0
    def isConditionallyIndependent(self, relVar1Str, relVar2Str, condRelVarStrs):
        logger.debug("testing %s _||_ %s | { %s }", relVar1Str, relVar2Str, condRelVarStrs)
        if not isinstance(relVar1Str, str) and not isinstance(relVar1Str, RelationalVariable) or not relVar1Str:
            raise Exception("relVar1Str must be a parseable RelationalVariable string")
        if not isinstance(relVar2Str, str) and not isinstance(relVar2Str, RelationalVariable) or not relVar2Str:
            raise Exception("relVar2Str must be a parseable RelationalVariable string")
        if not isinstance(condRelVarStrs, collections.Iterable) or isinstance(condRelVarStrs, str):
            raise Exception("condRelVarStrs must be a sequence of parseable RelationalVariable strings")

        relVar1 = ParserUtil.parseRelVar(relVar1Str)
        relVar2 = ParserUtil.parseRelVar(relVar2Str)
        if len(relVar2.path) > 1:
            raise Exception("relVar2Str must have a singleton path")

        baseItemName = relVar1.getBaseItemName()
        relVarAggrs = [AverageAggregator(relVar1Str), IdentityAggregator(relVar2Str)]
        relVarAggrs.extend([AverageAggregator(condRelVarStr) for condRelVarStr in condRelVarStrs])

        relVar1Data = []
        relVar2Data = []
        condVarsData = []
        for i in range(len(condRelVarStrs)):
            condVarsData.append([])

        for idVal, row in self.dataStore.getValuesForRelVarAggrs(self.schema, baseItemName, relVarAggrs):
            if None in row:
                continue
            relVar1Data.append(float(row[0]))
            relVar2Data.append(float(row[1]))
            for i, value in enumerate(row[2:]):
                condVarsData[i].append(float(value))

        robjects.baseenv['treatment'] = robjects.FloatVector(relVar1Data)
        robjects.baseenv['outcome'] = robjects.FloatVector(relVar2Data)
        for i, condVarData in enumerate(condVarsData):
            robjects.baseenv['cond{}'.format(i)] = robjects.FloatVector(condVarData)

        if not condVarsData: # marginal
            linearModel = r.lm('outcome ~ treatment')
            effectSize = r('cor(treatment, outcome)^2')[0]
            summary = r.summary(linearModel)
        else:
            condVarIndexes = range(len(condVarsData))
            linearModel = r.lm('outcome ~ treatment + cond{}'.format(' + cond'.join(map(str, condVarIndexes))))
            effectSize = r('cor(residuals(lm(outcome ~ cond{condVarStrs})), '
                           'residuals(lm(treatment ~ cond{condVarStrs})))^2'.format(
                            condVarStrs=(' + cond'.join(map(str, condVarIndexes)))))[0]
            summary = r.summary(linearModel)

        pval =  summary.rx2('coefficients').rx(2,4)[0]
        logger.debug('soe: {}, pval: {}'.format(effectSize, pval))
        return pval > self.alpha or effectSize < self.soeThreshold
Пример #5
0
    def setSepsets(self, sepsets, relationalVariableSetChecker=RelationalValidity.checkValidityOfRelationalVariableSet):
        """
        Sets the sepsets internally.  Accepts string representation of the relational variables in the sepsets.
        """
        if not isinstance(sepsets, dict):
            raise Exception("Sepsets must be a dictionary: found {}".format(sepsets))

        self.sepsets = {(ParserUtil.parseRelVar(relVar1Str), ParserUtil.parseRelVar(relVar2Str)):
                         {ParserUtil.parseRelVar(condVarStr) for condVarStr in sepsetStr}
                         for (relVar1Str, relVar2Str), sepsetStr in sepsets.items()}

        for (relVar1, relVar2), condRelVars in self.sepsets.items():
            relationalVariableSetChecker(self.schema, self.hopThreshold, {relVar1, relVar2} | condRelVars)
Пример #6
0
 def assertAGGEqualNoIntersection(self, schema, actualAgg,
                                  expectedRelDepStrs):
     expectedNodes = [
         relVar for relVar in RelationalSpace.getRelationalVariables(
             schema, actualAgg.hopThreshold, includeExistence=False)
         if relVar.getBaseItemName() == actualAgg.perspective
     ]
     expectedEdges = [(ParserUtil.parseRelDep(depStr).relVar1,
                       ParserUtil.parseRelDep(depStr).relVar2)
                      for depStr in expectedRelDepStrs]
     TestUtil.assertUnorderedListEqual(self, expectedNodes,
                                       actualAgg.nodes())
     TestUtil.assertUnorderedListEqual(self, expectedEdges,
                                       actualAgg.edges())
Пример #7
0
 def relVarStrPairsToRelVarPairs(self, relVarStrPairs):
     edges = []
     for relVarStrPair in relVarStrPairs:
         if isinstance(relVarStrPair[0], str) and isinstance(
                 relVarStrPair[1], str):
             # relVar -> relVar
             edges.append((ParserUtil.parseRelVar(relVarStrPair[0]),
                           ParserUtil.parseRelVar(relVarStrPair[1])))
         elif isinstance(relVarStrPair[0],
                         str) and not isinstance(relVarStrPair[1], str):
             # relVar -> relVarInt
             edges.append(
                 (ParserUtil.parseRelVar(relVarStrPair[0]),
                  RelationalVariableIntersection(
                      ParserUtil.parseRelVar(relVarStrPair[1][0]),
                      ParserUtil.parseRelVar(relVarStrPair[1][1]))))
         elif not isinstance(relVarStrPair[0], str) and isinstance(
                 relVarStrPair[1], str):
             # relVarInt -> relVar
             edges.append((RelationalVariableIntersection(
                 ParserUtil.parseRelVar(relVarStrPair[0][0]),
                 ParserUtil.parseRelVar(relVarStrPair[0][1])),
                           ParserUtil.parseRelVar(relVarStrPair[1])))
         else:
             raise Exception("Unknown pairing in relVarStrPairs: {}".format(
                 relVarStrPair))
     return edges
Пример #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()))
Пример #9
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)
Пример #10
0
    def dSeparated(self, hopThreshold, relVar1Strs, relVar2Strs, condRelVarStrs,
                   relationalVariableSetChecker=RelationalValidity.checkValidityOfRelationalVariableSet):
        """
        relVar1Strs, relVar2Strs, and condRelVarStrs are sequences of parseable RelationalVariable strings
        Method checks if, in model, are relVars1 and relVars2 d-separated? Constructs the abstract ground graph (AGG) for
        the model, and checks to see if all paths are d-separated.
        """
        if not isinstance(relVar1Strs, collections.Iterable) or not relVar1Strs:
            raise Exception("relVars1 must be a non-empty sequence of parseable RelationalVariable strings")
        relVars1 = {ParserUtil.parseRelVar(relVarStr) for relVarStr in relVar1Strs}

        if not isinstance(relVar2Strs, collections.Iterable) or not relVar2Strs:
            raise Exception("relVars2 must be a non-empty sequence of parseable RelationalVariable strings")
        relVars2 = {ParserUtil.parseRelVar(relVarStr) for relVarStr in relVar2Strs}

        if not isinstance(condRelVarStrs, collections.Iterable):
            raise Exception("condRelVars must be a sequence of parseable RelationalVariable strings")
        condRelVars = {ParserUtil.parseRelVar(condRelVar) for condRelVar in condRelVarStrs}

        # check consistency of all three relational variable sets (perspectives, hop threshold, against schema)
        relationalVariableSetChecker(self.model.schema, hopThreshold, relVars1 | relVars2 | condRelVars)

        perspective = list(relVars1)[0].getBaseItemName()
        if (perspective, hopThreshold) not in self.perspectiveHopThresholdToAgg:
            agg = AbstractGroundGraph(self.model, perspective, hopThreshold)
            ug = agg2ug(agg)
            self.perspectiveHopThresholdToAgg[(perspective, hopThreshold)] = agg
            self.ugs[(perspective, hopThreshold)] = ug
        else:
            agg = self.perspectiveHopThresholdToAgg[(perspective, hopThreshold)]
            ug = self.ugs[(perspective, hopThreshold)]

        # expand relVars1, relVars2, condRelVars with all intersection variables they subsume
        relVars1 = {relVar for relVar1 in relVars1 for relVar in agg.getSubsumedVariables(relVar1)}
        relVars2 = {relVar for relVar2 in relVars2 for relVar in agg.getSubsumedVariables(relVar2)}
        condRelVars = {relVar for condRelVar in condRelVars for relVar in agg.getSubsumedVariables(condRelVar)}

        relVars1 -= condRelVars
        relVars2 -= condRelVars

        if relVars1 & relVars2 != set():
            return False

        if not relVars1 or not relVars2:
            return True

        return bfsReachability(relVars1, relVars2, condRelVars, agg, ug)
Пример #11
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)
Пример #12
0
    def setUndirectedDependencies(self, undirectedDependencyStrs, dependencyChecker=RelationalValidity.checkRelationalDependencyValidity):
        if not isinstance(undirectedDependencyStrs, collections.Iterable):
            raise Exception("Undirected dependencies must be an iterable sequence of parseable RelationalDependency "
                            "strings: found {}".format(undirectedDependencyStrs))

        undirectedDependencies = [ParserUtil.parseRelDep(depStr) for depStr in undirectedDependencyStrs]
        # check each undirected dependency for consistency against the schema
        for undirectedDependency in undirectedDependencies:
            dependencyChecker(self.schema, undirectedDependency)
        self.undirectedDependencies = undirectedDependencies
        self.constructAggsFromDependencies(self.undirectedDependencies, times)
Пример #13
0
    def testParseRelationalDependency(self):
        relDepStr = '[A].X -> [A].Y'
        actualRelDep = ParserUtil.parseRelDep(relDepStr)
        self.assertTrue(isinstance(actualRelDep, RelationalDependency))
        self.assertEqual('[A].X', str(actualRelDep.relVar1))
        self.assertEqual('[A].Y', str(actualRelDep.relVar2))
        self.assertEqual(relDepStr, str(actualRelDep))

        relDepStr = '[A, AB, B].Y -> [A, AB].XY'
        actualRelDep = ParserUtil.parseRelDep(relDepStr)
        self.assertTrue(isinstance(actualRelDep, RelationalDependency))
        self.assertEqual('[A, AB, B].Y', str(actualRelDep.relVar1))
        self.assertEqual('[A, AB].XY', str(actualRelDep.relVar2))
        self.assertEqual(relDepStr, str(actualRelDep))

        relDepStr = '[A, AB, B].Y -> [A, AB].XY'
        actualRelDepIn = ParserUtil.parseRelDep(relDepStr)
        actualRelDepOut = ParserUtil.parseRelDep(actualRelDepIn)
        self.assertEqual(actualRelDepIn, actualRelDepOut)

        TestUtil.assertRaisesMessage(
            self, Exception,
            "relDepStr is not a string or RelationalDependency object",
            ParserUtil.parseRelDep, None)
Пример #14
0
    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)
Пример #15
0
    def assertPCOutputEqual(self, expectedNodeStrs, expectedEdgeStrs, expectedSepsetStrs, expectedNumDSepCalls,
                                  dag, sepset, mockOracle):
        # test nodes are equal
        expectedNodes = [ParserUtil.parseRelVar(nodeStr) for nodeStr in expectedNodeStrs]
        TestUtil.assertUnorderedListEqual(self, expectedNodes, dag.nodes())

        # test edges are equal
        self.assertEqual(len(expectedEdgeStrs), len(dag.edges()))
        for expectedEdgeStr in expectedEdgeStrs:
            expectedEdge = (ParserUtil.parseRelVar(expectedEdgeStr[0]), ParserUtil.parseRelVar(expectedEdgeStr[1]))
            self.assertIn(expectedEdge, dag.edges())

        # test sepsets are equal, if passed in
        if expectedSepsetStrs and sepset:
            expectedSepset = {(ParserUtil.parseRelVar(relVar1Str), ParserUtil.parseRelVar(relVar2Str)):
                              {ParserUtil.parseRelVar(condVarStr) for condVarStr in sepsetStr}
                          for (relVar1Str, relVar2Str), sepsetStr in expectedSepsetStrs.items()}
            self.assertDictEqual(expectedSepset, sepset)

        # test the number of d-separation calls, if passed in
        if expectedNumDSepCalls and mockOracle:
            self.assertEqual(expectedNumDSepCalls, mockOracle.isConditionallyIndependent.call_count)
Пример #16
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)
Пример #17
0
 def relVarStrPairsToRelVarInts(self, relVarStrPairs):
     return [
         RelationalVariableIntersection(ParserUtil.parseRelVar(relVarStr1),
                                        ParserUtil.parseRelVar(relVarStr2))
         for relVarStr1, relVarStr2 in relVarStrPairs
     ]
Пример #18
0
    def testThreeEntityTwoRelationshipsAGG(self):
        schema = Schema()
        schema.addEntity('A')
        schema.addEntity('B')
        schema.addEntity('C')
        schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.MANY))
        schema.addRelationship('BC', ('B', Schema.ONE), ('C', Schema.MANY))
        schema.addAttribute('A', 'X')
        schema.addAttribute('B', 'Y')
        schema.addAttribute('C', 'Z')
        schema.addAttribute('AB', 'XY')
        schema.addAttribute('BC', 'YZ')
        model = Model(schema, [])
        aAGG = AbstractGroundGraph(model, 'A', 6)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr) for relVarStr in [
                '[A].X', '[A, AB].XY', '[A, AB, B].Y', '[A, AB, B, AB].XY',
                '[A, AB, B, BC].YZ', '[A, AB, B, AB, A].X',
                '[A, AB, B, BC, C].Z', '[A, AB, B, AB, A, AB].XY',
                '[A, AB, B, BC, C, BC].YZ', '[A, AB, B, AB, A, AB, B].Y',
                '[A, AB, B, BC, C, BC, B].Y'
            ]
        ]
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          aAGG.getRelationalVariableNodes())
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y')
        ])
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            aAGG.getRelationalVariableIntersectionNodes())
        self.assertAGGEdgesEqual([], aAGG)

        bcAGG = AbstractGroundGraph(model, 'BC', 4)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr) for relVarStr in [
                '[BC].YZ', '[BC, B].Y', '[BC, C].Z', '[BC, B, AB].XY',
                '[BC, C, BC].YZ', '[BC, B, AB, A].X', '[BC, C, BC, B].Y',
                '[BC, B, AB, A, AB].XY', '[BC, C, BC, B, AB].XY'
            ]
        ]
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          bcAGG.getRelationalVariableNodes())
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[BC, B].Y', '[BC, C, BC, B].Y'),
            ('[BC, B, AB].XY', '[BC, C, BC, B, AB].XY'),
            ('[BC, B, AB, A, AB].XY', '[BC, C, BC, B, AB].XY')
        ])
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            bcAGG.getRelationalVariableIntersectionNodes())
        self.assertAGGEdgesEqual([], bcAGG)

        model = Model(schema, [
            '[BC, B, AB, A].X -> [BC].YZ', '[AB, B, BC, C].Z -> [AB].XY',
            '[AB, B, AB, A, AB, B].Y -> [AB].XY'
        ])
        aAGG = AbstractGroundGraph(model, 'A', 6)
        expectedEdges = self.relVarStrPairsToRelVarPairs([
            ('[A].X', '[A, AB, B, BC].YZ'),
            ('[A, AB, B, AB, A].X', '[A, AB, B, BC].YZ'),
            ('[A, AB, B, BC, C].Z', '[A, AB].XY'),
            ('[A, AB, B, BC, C].Z', '[A, AB, B, AB].XY'),
            ('[A, AB, B, AB, A, AB, B].Y', '[A, AB].XY'),
            ('[A, AB, B].Y', '[A, AB, B, AB].XY'),
            ('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, AB].XY'),
            (('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y'),
             '[A, AB].XY'),
            (('[A, AB, B, AB, A, AB, B].Y', '[A, AB, B, BC, C, BC, B].Y'),
             '[A, AB, B, AB].XY')
        ])
        self.assertAGGEdgesEqual(expectedEdges, aAGG)
Пример #19
0
    def testManyToManyTwoEntityTwoRelationshipsAGGNodes(self):
        schema = Schema()
        schema.addEntity('A')
        schema.addEntity('B')
        schema.addRelationship('AB1', ('A', Schema.MANY), ('B', Schema.MANY))
        schema.addRelationship('AB2', ('A', Schema.MANY), ('B', Schema.MANY))
        schema.addAttribute('A', 'X')
        schema.addAttribute('B', 'Y')
        schema.addAttribute('AB1', 'XY1')
        schema.addAttribute('AB2', 'XY2')
        model = Model(schema, [])
        aAGG = AbstractGroundGraph(model, 'A', 4)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr) for relVarStr in [
                '[A].X', '[A, AB1].XY1', '[A, AB2].XY2', '[A, AB1, B].Y',
                '[A, AB2, B].Y', '[A, AB1, B, AB1].XY1',
                '[A, AB1, B, AB2].XY2', '[A, AB2, B, AB1].XY1',
                '[A, AB2, B, AB2].XY2', '[A, AB1, B, AB1, A].X',
                '[A, AB1, B, AB2, A].X', '[A, AB2, B, AB1, A].X',
                '[A, AB2, B, AB2, A].X'
            ]
        ]
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[A, AB1].XY1', '[A, AB2, B, AB1].XY1'),
            ('[A, AB2].XY2', '[A, AB1, B, AB2].XY2'),
            ('[A, AB1, B].Y', '[A, AB2, B].Y'),
            ('[A, AB1, B, AB1].XY1', '[A, AB2, B, AB1].XY1'),
            ('[A, AB2, B, AB2].XY2', '[A, AB1, B, AB2].XY2'),
            ('[A, AB1, B, AB1, A].X', '[A, AB1, B, AB2, A].X'),
            ('[A, AB1, B, AB1, A].X', '[A, AB2, B, AB1, A].X'),
            ('[A, AB1, B, AB1, A].X', '[A, AB2, B, AB2, A].X'),
            ('[A, AB2, B, AB2, A].X', '[A, AB1, B, AB2, A].X'),
            ('[A, AB2, B, AB2, A].X', '[A, AB2, B, AB1, A].X'),
            ('[A, AB1, B, AB2, A].X', '[A, AB2, B, AB1, A].X')
        ])
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          aAGG.getRelationalVariableNodes())
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            aAGG.getRelationalVariableIntersectionNodes())
        self.assertAGGEdgesEqual([], aAGG)

        ab1AGG = AbstractGroundGraph(model, 'AB1', 4)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr) for relVarStr in [
                '[AB1].XY1', '[AB1, A].X', '[AB1, B].Y', '[AB1, A, AB1].XY1',
                '[AB1, A, AB2].XY2', '[AB1, B, AB1].XY1', '[AB1, B, AB2].XY2',
                '[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y',
                '[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X',
                '[AB1, A, AB1, B, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1',
                '[AB1, B, AB1, A, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1',
                '[AB1, A, AB1, B, AB2].XY2', '[AB1, A, AB2, B, AB2].XY2',
                '[AB1, B, AB1, A, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'
            ]
        ]
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          ab1AGG.getRelationalVariableNodes())
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[AB1, A].X', '[AB1, B, AB1, A].X'),
            ('[AB1, A].X', '[AB1, B, AB2, A].X'),
            ('[AB1, B].Y', '[AB1, A, AB1, B].Y'),
            ('[AB1, B].Y', '[AB1, A, AB2, B].Y'),
            ('[AB1, A, AB1].XY1', '[AB1, B, AB1].XY1'),
            ('[AB1, A, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1'),
            ('[AB1, A, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1'),
            ('[AB1, A, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'),
            ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'),
            ('[AB1, A, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'),
            ('[AB1, A, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'),
            ('[AB1, A, AB2].XY2', '[AB1, A, AB1, B, AB2].XY2'),
            ('[AB1, B, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'),
            ('[AB1, B, AB1].XY1', '[AB1, A, AB1, B, AB1].XY1'),
            ('[AB1, B, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1'),
            ('[AB1, B, AB2].XY2', '[AB1, A, AB2, B, AB2].XY2'),
            ('[AB1, B, AB2].XY2', '[AB1, A, AB1, B, AB2].XY2'),
            ('[AB1, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'),
            ('[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y'),
            ('[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X'),
            ('[AB1, A, AB1, B, AB1].XY1', '[AB1, A, AB2, B, AB1].XY1'),
            ('[AB1, A, AB1, B, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1'),
            ('[AB1, A, AB1, B, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'),
            ('[AB1, A, AB2, B, AB1].XY1', '[AB1, B, AB1, A, AB1].XY1'),
            ('[AB1, A, AB2, B, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'),
            ('[AB1, B, AB1, A, AB1].XY1', '[AB1, B, AB2, A, AB1].XY1'),
            ('[AB1, A, AB1, B, AB2].XY2', '[AB1, A, AB2, B, AB2].XY2'),
            ('[AB1, A, AB1, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'),
            ('[AB1, A, AB1, B, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'),
            ('[AB1, A, AB2, B, AB2].XY2', '[AB1, B, AB1, A, AB2].XY2'),
            ('[AB1, A, AB2, B, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2'),
            ('[AB1, B, AB1, A, AB2].XY2', '[AB1, B, AB2, A, AB2].XY2')
        ])
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            ab1AGG.getRelationalVariableIntersectionNodes())
        self.assertAGGEdgesEqual([], aAGG)

        # test multiple relationships with two dependencies
        model = Model(schema, [
            '[AB2, B, AB1, A].X -> [AB2].XY2', '[AB1, B, AB2].XY2 -> [AB1].XY1'
        ])
        ab1AGG = AbstractGroundGraph(model, 'AB1', 3)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr) for relVarStr in [
                '[AB1].XY1', '[AB1, A].X', '[AB1, B].Y', '[AB1, A, AB1].XY1',
                '[AB1, A, AB2].XY2', '[AB1, B, AB1].XY1', '[AB1, B, AB2].XY2',
                '[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y',
                '[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X'
            ]
        ]
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          ab1AGG.getRelationalVariableNodes())
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[AB1, A].X', '[AB1, B, AB1, A].X'),
            ('[AB1, A].X', '[AB1, B, AB2, A].X'),
            ('[AB1, B].Y', '[AB1, A, AB1, B].Y'),
            ('[AB1, B].Y', '[AB1, A, AB2, B].Y'),
            ('[AB1, A, AB1].XY1', '[AB1, B, AB1].XY1'),
            ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'),
            ('[AB1, A, AB1, B].Y', '[AB1, A, AB2, B].Y'),
            ('[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X')
        ])
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            ab1AGG.getRelationalVariableIntersectionNodes())
        expectedEdges = self.relVarStrPairsToRelVarPairs([
            ('[AB1, B, AB2].XY2', '[AB1].XY1'),
            ('[AB1, B, AB2].XY2', '[AB1, B, AB1].XY1'),
            ('[AB1, A].X', '[AB1, B, AB2].XY2'),
            ('[AB1, B, AB1, A].X', '[AB1, B, AB2].XY2'),
            (('[AB1, A].X', '[AB1, B, AB1, A].X'), '[AB1, B, AB2].XY2'),
            (('[AB1, A].X', '[AB1, B, AB2, A].X'), '[AB1, B, AB2].XY2'),
            ('[AB1, B, AB2].XY2', ('[AB1, A, AB1].XY1', '[AB1, B, AB1].XY1')),
            ('[AB1, A].X', ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2')),
            ('[AB1, B, AB1, A].X', ('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2')),
            (('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'), '[AB1].XY1'),
            (('[AB1, A, AB2].XY2', '[AB1, B, AB2].XY2'), '[AB1, B, AB1].XY1'),
            (('[AB1, B, AB1, A].X', '[AB1, B, AB2, A].X'), '[AB1, B, AB2].XY2')
        ])
        self.assertAGGEdgesEqual(expectedEdges, ab1AGG)
Пример #20
0
 def dictStrsToRelVars(self, attrToParents):
     return {
         ParserUtil.parseRelVar(attr):
         [ParserUtil.parseRelVar(parent) for parent in parents]
         for attr, parents in attrToParents.items()
     }
Пример #21
0
    def testOneToManyTwoEntityAGG(self):
        schema = Schema()
        schema.addEntity('A')
        schema.addEntity('B')
        schema.addRelationship('AB', ('A', Schema.MANY), ('B', Schema.ONE))
        model = Model(schema, [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'A', 0),
                                          [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'B', 0),
                                          [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'AB', 0),
                                          [])

        schema.addAttribute('A', 'X')
        model = Model(schema, [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'A', 2),
                                          [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'B', 2),
                                          [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'AB', 2),
                                          [])

        schema.addAttribute('B', 'Y')
        model = Model(schema, [])
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'A', 2),
                                          [])  # putting in max hop threshold
        self.assertAGGEqualNoIntersection(schema,
                                          AbstractGroundGraph(model, 'B', 4),
                                          [])
        abAGG = AbstractGroundGraph(model, 'AB', 3)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr)
            for relVarStr in ['[AB, A].X', '[AB, B].Y', '[AB, A, AB, B].Y']
        ]
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[AB, B].Y', '[AB, A, AB, B].Y')
        ])
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          abAGG.getRelationalVariableNodes())
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            abAGG.getRelationalVariableIntersectionNodes())
        self.assertAGGEdgesEqual([], abAGG)
        # test that order of relVar1, relVar2 for RelationalVariableIntersection doesn't matter
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[AB, A, AB, B].Y', '[AB, B].Y')
        ])
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            abAGG.getRelationalVariableIntersectionNodes())

        model = Model(schema, ['[A, AB, B].Y -> [A].X'])
        aAGG = AbstractGroundGraph(model, 'A', 2)
        expectedEdges = self.relVarStrPairsToRelVarPairs([('[A, AB, B].Y',
                                                           '[A].X')])
        self.assertAGGEdgesEqual(expectedEdges, aAGG)

        # test that extended dependencies are only added among nodes that exist in the AGG (have an appropriate number of hops)
        bAGG = AbstractGroundGraph(model, 'B', 2)
        expectedEdges = self.relVarStrPairsToRelVarPairs([('[B].Y',
                                                           '[B, AB, A].X')])
        self.assertAGGEdgesEqual(expectedEdges, bAGG)

        bAGG = AbstractGroundGraph(model, 'B', 4)
        expectedEdges = self.relVarStrPairsToRelVarPairs([
            ('[B].Y', '[B, AB, A].X'), ('[B, AB, A, AB, B].Y', '[B, AB, A].X')
        ])
        self.assertAGGEdgesEqual(expectedEdges, bAGG)

        # test dependencies get inherited for intersection nodes
        abAGG = AbstractGroundGraph(model, 'AB', 3)
        expectedEdges = self.relVarStrPairsToRelVarPairs([
            ('[AB, B].Y', '[AB, A].X'), ('[AB, A, AB, B].Y', '[AB, A].X'),
            (('[AB, A, AB, B].Y', '[AB, B].Y'), '[AB, A].X')
        ])
        self.assertAGGEdgesEqual(expectedEdges, abAGG)

        schema.addAttribute('B', 'Z')
        model = Model(schema, [])
        abAGG = AbstractGroundGraph(model, 'AB', 3)
        expectedRelVarNodes = [
            ParserUtil.parseRelVar(relVarStr) for relVarStr in [
                '[AB, A].X', '[AB, B].Y', '[AB, A, AB, B].Y', '[AB, B].Z',
                '[AB, A, AB, B].Z'
            ]
        ]
        expectedRelVarIntNodes = self.relVarStrPairsToRelVarInts([
            ('[AB, B].Y', '[AB, A, AB, B].Y'),
            ('[AB, B].Z', '[AB, A, AB, B].Z')
        ])
        TestUtil.assertUnorderedListEqual(self, expectedRelVarNodes,
                                          abAGG.getRelationalVariableNodes())
        TestUtil.assertUnorderedListEqual(
            self, expectedRelVarIntNodes,
            abAGG.getRelationalVariableIntersectionNodes())
        self.assertAGGEdgesEqual([], abAGG)

        model = Model(schema, [
            '[A, AB, B].Y -> [A].X', '[A, AB, B].Z -> [A].X', '[B].Y -> [B].Z'
        ])
        aAGG = AbstractGroundGraph(model, 'A', 2)
        expectedEdges = self.relVarStrPairsToRelVarPairs([
            ('[A, AB, B].Y', '[A].X'), ('[A, AB, B].Z', '[A].X'),
            ('[A, AB, B].Y', '[A, AB, B].Z')
        ])
        self.assertAGGEdgesEqual(expectedEdges, aAGG)

        abAGG = AbstractGroundGraph(model, 'AB', 3)
        expectedEdges = self.relVarStrPairsToRelVarPairs([
            ('[AB, A, AB, B].Y', '[AB, A, AB, B].Z'),
            ('[AB, A, AB, B].Y', '[AB, A].X'), ('[AB, B].Y', '[AB, B].Z'),
            ('[AB, A, AB, B].Z', '[AB, A].X'), ('[AB, B].Y', '[AB, A].X'),
            ('[AB, B].Z', '[AB, A].X'),
            (('[AB, B].Y', '[AB, A, AB, B].Y'), '[AB, A].X'),
            (('[AB, B].Y', '[AB, A, AB, B].Y'), '[AB, B].Z'),
            (('[AB, B].Y', '[AB, A, AB, B].Y'), '[AB, A, AB, B].Z'),
            (('[AB, B].Z', '[AB, A, AB, B].Z'), '[AB, A].X'),
            ('[AB, A, AB, B].Y', ('[AB, B].Z', '[AB, A, AB, B].Z')),
            ('[AB, B].Y', ('[AB, B].Z', '[AB, A, AB, B].Z'))
        ])
        self.assertAGGEdgesEqual(expectedEdges, abAGG)
Пример #22
0
    def testParseRelationalVariable(self):
        relVarStr = '[A].X'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A'], actualRelVar.path)
        self.assertEqual('X', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        relVarStr = '[A].exists'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A'], actualRelVar.path)
        self.assertEqual('exists', actualRelVar.attrName)
        self.assertTrue(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        relVarStr = '[B].Y'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['B'], actualRelVar.path)
        self.assertEqual('Y', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        relVarStr = '[AB].XY'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['AB'], actualRelVar.path)
        self.assertEqual('XY', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        relVarStr = '[A, AB].XY'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A', 'AB'], actualRelVar.path)
        self.assertEqual('XY', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        relVarStr = '[A, AB, B].Y'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A', 'AB', 'B'], actualRelVar.path)
        self.assertEqual('Y', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        relVarStr = '[A, AB, B].exists'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A', 'AB', 'B'], actualRelVar.path)
        self.assertEqual('exists', actualRelVar.attrName)
        self.assertTrue(actualRelVar.isExistence())
        self.assertEqual(relVarStr, str(actualRelVar))

        # testing that spaces are ignored after commas between item names
        relVarStr = '[A,AB,B].Y'
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A', 'AB', 'B'], actualRelVar.path)
        self.assertEqual('Y', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual('[A, AB, B].Y', str(actualRelVar))

        # testing that spaces are ignored in attribute names
        relVarStr = '[A,AB,B].Y '
        actualRelVar = ParserUtil.parseRelVar(relVarStr)
        self.assertTrue(isinstance(actualRelVar, RelationalVariable))
        self.assertEqual(['A', 'AB', 'B'], actualRelVar.path)
        self.assertEqual('Y', actualRelVar.attrName)
        self.assertFalse(actualRelVar.isExistence())
        self.assertEqual('[A, AB, B].Y', str(actualRelVar))