コード例 #1
0
def testPMapStressInsertDelete():
    r = PMap()
    N = 1000
    for i in range(N):
        r = r.insert(_hash(i), i)

    for i in range(N):
        assert _hash(i) in r
        assert r.lookup(_hash(i)) == i

    r2 = r
    for i in range(N / 2, N):
        r2 = r2.delete(_hash(i))

    for i in range(N / 2):
        assert _hash(i) in r
        assert r.lookup(_hash(i)) == i
        assert _hash(i) in r2
        assert r2.lookup(_hash(i)) == i

    for i in range(N / 2, N):
        assert _hash(i) in r
        assert r.lookup(_hash(i)) == i
        assert _hash(i) not in r2
        assert r2.lookup(_hash(i)) is None
コード例 #2
0
class Particle(Trace):

    # The trace is expected to be a torus, with the chosen scaffold
    # already detached, or a particle.
    def __init__(self, trace):
        # Intentionally emulating algebraic data type
        # pylint: disable=unidiomatic-typecheck
        if type(trace) is Particle: self.initFromParticle(trace)
        elif type(trace) is Trace: self.initFromTrace(trace)
        else: raise Exception("Must init particle from trace or particle")
        # Assumed by hasMadeSPRecordAt.
        assert type(self.base) is Trace

    # Note: using "copy()" informally for both legit_copy and persistent_copy
    def initFromParticle(self, particle):
        self.base = particle.base

        # (1) Persistent stuff
        self.rcs = particle.rcs
        self.ccs = particle.ccs
        self.aes = particle.aes

        self.values = particle.values
        self.madeSPs = particle.madeSPs

        self.scopes = particle.scopes  # pmap => pmap => pset
        self.esrParents = particle.esrParents
        self.numRequests = particle.numRequests
        self.regenCounts = particle.regenCounts
        self.newMadeSPFamilies = particle.newMadeSPFamilies  # pmap => pmap => node
        self.newChildren = particle.newChildren
        self.discardedAAAMakerNodes = particle.discardedAAAMakerNodes

        prng = particle.py_rng
        self.py_rng = random.Random(prng.randint(1, 2**31 - 1))
        self.np_rng = npr.RandomState(prng.randint(1, 2**31 - 1))

        # (2) Maps to things that change outside of particle methods
        self.madeSPAuxs = OrderedDict(
            (node, spaux.copy())
            for node, spaux in particle.madeSPAuxs.iteritems())

    def initFromTrace(self, trace):
        self.base = trace

        # (1) Persistent stuff
        self.rcs = PSet(node_key)  # PSet Node
        self.ccs = PSet(node_key)  # PSet Node
        self.aes = PSet(node_key)  # PSet Node

        self.values = PMap(node_key)  # PMap Node VentureValue
        self.madeSPs = PMap(node_key)  # PMap Node SP

        self.scopes = PMap()  # PMap scopeid (PMap blockid (PSet Node))
        # mutable list ok here b/c only touched by one particle
        self.esrParents = PMap(node_key)  # PMap Node [Node]
        self.numRequests = PMap(node_key)  # PMap Node Int
        self.regenCounts = PMap(node_key)  # PMap Node int
        self.newMadeSPFamilies = PMap(node_key)  # PMap Node (PMap id Node)
        self.newChildren = PMap(node_key)  # PMap Node (PSet Node)
        self.discardedAAAMakerNodes = PSet(node_key)  # PSet Node

        prng = trace.py_rng
        self.py_rng = random.Random(prng.randint(1, 2**31 - 1))
        self.np_rng = npr.RandomState(prng.randint(1, 2**31 - 1))

        # (2) Maps to things that change outside of particle methods
        self.madeSPAuxs = OrderedDict()

    ### Random choices and scopes

    def registerRandomChoice(self, node):
        self.rcs = self.rcs.insert(node)
        self.registerRandomChoiceInScope("default", node, node)

    def registerAEKernel(self, node):
        self.aes = self.aes.insert(node)

    def registerConstrainedChoice(self, node):
        self.ccs = self.ccs.insert(node)

    def unregisterRandomChoice(self, node):
        assert False

    def registerRandomChoiceInScope(self, scope, block, node, unboxed=False):
        assert block is not None
        if not unboxed:
            (scope,
             block) = self._normalizeEvaluatedScopeAndBlock(scope, block)
        if scope not in self.scopes:
            self.scopes = self.scopes.insert(scope, PMap())
        if block not in self.scopes.lookup(scope):

            def ins_b(blocks):
                return blocks.insert(block, PSet(node_key))

            self.scopes = self.scopes.adjust(scope, ins_b)

        def ins_n(blocks):
            return blocks.adjust(block, lambda pnodes: pnodes.insert(node))

        self.scopes = self.scopes.adjust(scope, ins_n)

    def unregisterRandomChoiceInScope(self, scope, block, node):
        assert False

    ### Misc

    def valueAt(self, node):
        if node in self.values: return self.values.lookup(node)
        else:
            return self.base.valueAt(node)

    def setValueAt(self, node, value):
        self.values = self.values.insert(node, value)

    @override(Trace)
    def hasMadeSPRecordAt(self, node):
        # Nobody should call this because the base is always a Trace, not
        # a Particle.
        raise NotImplementedError('You should not be calling this!')

    def madeSPRecordAt(self, node):
        return VentureSPRecord(self.madeSPAt(node), self.madeSPAuxAt(node))

    def setMadeSPRecordAt(self, node, spRecord):
        self.madeSPs = self.madeSPs.insert(node, spRecord.sp)
        self.madeSPAuxs[node] = spRecord.spAux
        self.newMadeSPFamilies = self.newMadeSPFamilies.insert(node, PMap())

    def madeSPAt(self, node):
        if node in self.madeSPs: return self.madeSPs.lookup(node)
        else: return self.base.madeSPAt(node)

    def setMadeSPAt(self, node, sp):
        assert node not in self.madeSPs
        assert self.base.madeSPAt(node) is None
        self.madeSPs = self.madeSPs.insert(node, sp)

    def esrParentsAt(self, node):
        if node in self.esrParents: return self.esrParents.lookup(node)
        else: return self.base.esrParentsAt(node)

    def appendEsrParentAt(self, node, parent):
        assert not self.base.esrParentsAt(node)
        if node not in self.esrParents:
            self.esrParents = self.esrParents.insert(node, [])
        self.esrParents.lookup(node).append(parent)

    def regenCountAt(self, scaffold, node):
        assert self.base.regenCountAt(scaffold, node) == 0
        if node in self.regenCounts: return self.regenCounts.lookup(node)
        else: return self.base.regenCountAt(scaffold, node)

    def incRegenCountAt(self, scaffold, node):
        if node not in self.regenCounts:
            self.regenCounts = self.regenCounts.insert(node, 0)
        self.regenCounts = self.regenCounts.adjust(node, lambda rc: rc + 1)

    def incRequestsAt(self, node):
        if node not in self.numRequests:
            base_num_requests = self.base.numRequestsAt(node)
            self.numRequests = self.numRequests.insert(node, base_num_requests)
        self.numRequests = self.numRequests.adjust(node, lambda nr: nr + 1)

    def childrenAt(self, node):
        if node in self.newChildren:
            return self.base.childrenAt(node).union(
                self.newChildren.lookup(node))
        else:
            return self.base.childrenAt(node)

    def addChildAt(self, node, child):
        if node not in self.newChildren:
            self.newChildren = self.newChildren.insert(node, PSet(node_key))

        def ins(children):
            return children.insert(child)

        self.newChildren = self.newChildren.adjust(node, ins)

    def discardAAAMadeSPAuxAt(self, node):
        self.discardedAAAMakerNodes = self.discardedAAAMakerNodes.insert(node)

    def getAAAMadeSPAuxAt(self, node):
        if node in self.discardedAAAMakerNodes:
            return None
        else:
            return self.base.getAAAMadeSPAuxAt(node)

    ### SPFamilies

    def containsSPFamilyAt(self, node, id):
        makerNode = self.spRefAt(node).makerNode
        assert makerNode in self.newMadeSPFamilies or \
          self.base.hasMadeSPRecordAt(makerNode)
        if makerNode in self.newMadeSPFamilies:
            assert isinstance(self.newMadeSPFamilies.lookup(makerNode), PMap)
            if id in self.newMadeSPFamilies.lookup(makerNode):
                return True
            if self.base.hasMadeSPRecordAt(makerNode) and \
               self.base.madeSPFamiliesAt(makerNode).containsFamily(id):
                return True
        elif self.base.madeSPFamiliesAt(makerNode).containsFamily(id):
            return True
        return False

    def initMadeSPFamiliesAt(self, node):
        assert node not in self.newMadeSPFamilies
        assert node.madeSPFamilies is None
        self.newMadeSPFamilies = self.newMadeSPFamilies.insert(node, PMap())

    def registerFamilyAt(self, node, esrId, esrParent):
        makerNode = self.spRefAt(node).makerNode
        if makerNode not in self.newMadeSPFamilies:
            self.newMadeSPFamilies = self.newMadeSPFamilies.insert(
                makerNode, PMap())

        def ins(ids):
            return ids.insert(esrId, esrParent)

        self.newMadeSPFamilies = self.newMadeSPFamilies.adjust(makerNode, ins)

    def madeSPFamilyAt(self, node, esrId):
        if node in self.newMadeSPFamilies and \
           esrId in self.newMadeSPFamilies.lookup(node):
            return self.newMadeSPFamilies.lookup(node).lookup(esrId)
        else:
            return self.base.madeSPFamilyAt(node, esrId)

    def spFamilyAt(self, node, esrId):
        makerNode = self.spRefAt(node).makerNode
        return self.madeSPFamilyAt(makerNode, esrId)

    ### Regular maps

    def madeSPAuxAt(self, node):
        if node not in self.madeSPAuxs:
            if self.base.madeSPAuxAt(node) is not None:
                self.madeSPAuxs[node] = self.base.madeSPAuxAt(node).copy()
            else:
                return None
        return self.madeSPAuxs[node]

    def setMadeSPAuxAt(self, node, aux):
        assert node not in self.madeSPAuxs
        assert self.base.madeSPAuxAt(node) is None
        self.madeSPAuxs[node] = aux

    ### Miscellaneous bookkeeping

    def numBlocksInScope(self, scope):
        # Why is this weird piece of code arranged like this?
        # Because in a custom scope, the number of blocks is given by the
        # number of `tag` invocations, regardless of whether the resulting
        # blocks have any unconstrained random choices.  In the default
        # scope, however, the number of "blocks" does depend on whether
        # random choices are constrained or not.
        # This place will need to be touched for Issue #421.
        if scope == "default":
            actualUnconstrainedChoices = self.base.rcs.copy()
            for node in self.rcs:
                actualUnconstrainedChoices.add(node)
            for node in self.ccs:
                actualUnconstrainedChoices.remove(node)
            return len(actualUnconstrainedChoices)
        else:
            actualBlocks = set(self.base.blocksInScope(scope))
            if scope in self.scopes:
                for block in self.scopes.lookup(scope):
                    actualBlocks.add(block)
            return len(actualBlocks)

    ### Commit

    def commit(self):
        # note that we do not call registerRandomChoice() because it in
        # turn calls registerRandomChoiceInScope()
        for node in self.rcs:
            self.base.rcs.add(node)

        # this iteration includes "default"
        for (scope, blocks) in self.scopes.iteritems():
            for (block, pnodes) in blocks.iteritems():
                for pnode in pnodes:
                    self.base.registerRandomChoiceInScope(scope,
                                                          block,
                                                          pnode,
                                                          unboxed=True)

        # note that we do not call registerConstrainedChoice() because it
        # in turn calls unregisterRandomChoice()
        for node in self.ccs:
            self.base.registerConstrainedChoice(node)

        for node in self.aes:
            self.base.registerAEKernel(node)

        for (node, value) in self.values.iteritems():
            assert value is not None
            self.base.setValueAt(node, value)

        for (node, madeSP) in self.madeSPs.iteritems():
            self.base.setMadeSPRecordAt(node, VentureSPRecord(madeSP))

        for (node, esrParents) in self.esrParents.iteritems():
            self.base.setEsrParentsAt(node, esrParents)
        for (node, numRequests) in self.numRequests.iteritems():
            self.base.setNumRequestsAt(node, numRequests)
        for (node, newMadeSPFamilies) in self.newMadeSPFamilies.iteritems():
            self.base.addNewMadeSPFamilies(node, newMadeSPFamilies)
        for (node, newChildren) in self.newChildren.iteritems():
            self.base.addNewChildren(node, newChildren)

        for (node, spaux) in self.madeSPAuxs.iteritems():
            self.base.setMadeSPAuxAt(node, spaux)

    # untested
    def transferRegenCounts(self, scaffold):
        for node in self.regenCounts:
            assert node in scaffold.regenCounts
            scaffold.regenCounts[node] = self.regenCounts.lookup(node)

    ### Methods that should never be called on particles

    def registerAAAMadeSPAuxAt(self, node, aux):
        raise Exception("Should not be called on a particle")

    def unregisterFamilyAt(self, node, esrId):
        raise Exception("Should not be called on a particle")

    def popEsrParentAt(self, node):
        raise Exception("Should not be called on a particle")

    def removeChildAt(self, node, child):
        raise Exception("Should not be called on a particle")

    def decRequestsAt(self, node):
        raise Exception("Should not be called on a particle")

    def unregisterAEKernel(self, node):
        raise Exception("Should not be called on a particle")

    def unregisterConstrainedChoice(self, node):
        raise Exception("Should not be called on a particle")

    def decRegenCountAt(self, scaffold, node):
        raise Exception("Should never be called on a particle")

    def numRequestsAt(self, node):
        raise Exception("Should not be called on a particle")