def makeConsistent(self): weight = 0 for node, val in self.unpropagatedObservations.iteritems(): appNode = self.getConstrainableNode(node) # print "PROPAGATE", node, appNode scaffold = constructScaffold(self, [OrderedSet([appNode])]) rhoWeight, _ = detachAndExtract(self, scaffold) scaffold.lkernels[appNode] = DeterministicLKernel( self.pspAt(appNode), val) xiWeight = regenAndAttach(self, scaffold, False, OmegaDB(), OrderedDict()) # If xiWeight is -inf, we are in an impossible state, but that might be ok. # Finish constraining, to avoid downstream invariant violations. node.observe(val) constrain(self, appNode, node.observedValue) weight += xiWeight weight -= rhoWeight self.unpropagatedObservations.clear() if not math.isnan(weight): # Note: +inf weight is possible at spikes in density against # Lebesgue measure. return weight else: # How could we get a NaN here? # If one observation made the state inconsistent, the rhoWeight # of another might conceivably be infinite, possibly leading to # a nan weight. I want to normalize these to indicating that # the resulting state is impossible. return float("-inf")
def regen_with_proposal(self, scaffold, values): pnodes = scaffold.getPrincipalNodes() assert len(values) == len( pnodes ), "Tried to propose %d values, but subproblem accepts %d values" % ( len(values), len(pnodes)) infer.registerDeterministicLKernels(self, scaffold, pnodes, values) xiWeight = regenAndAttach(self, scaffold, False, OmegaDB(), OrderedDict()) # de-mutate the scaffold in case it is used for subsequent operations infer.unregisterDeterministicLKernels(self, scaffold, pnodes) return xiWeight
def detachAndExtractAtBorder(trace, border, scaffold, compute_gradient=False): """Returns the weight and an OmegaDB. The OmegaDB contains sufficient information to restore the trace, and, if compute_gradient is True, to determine the partial derivative of the weight with respect to the value at each node. The latter is computed by one level of reverse-mode AD, with the underlying trace serving as tape.""" weight = 0 omegaDB = OmegaDB() for node in reversed(border): if scaffold.isAbsorbing(node): weight += detach(trace, node, scaffold, omegaDB, compute_gradient) else: if node.isObservation: weight += getAndUnconstrain(trace, node) weight += extract(trace, node, scaffold, omegaDB, compute_gradient) return weight, omegaDB
def freeze(self, id): assert id in self.families node = self.families[id] if isConstantNode(node): # All set pass else: assert isOutputNode(node) value = self.valueAt(node) unevalFamily(self, node, Scaffold(), OmegaDB()) # XXX It looks like we kinda want to replace the identity of this # node by a constant node, but we don't have a nice way to do that # so we fake it by dropping the components and marking it frozen. node.isFrozen = True self.setValueAt(node, value) node.requestNode = None node.operandNodes = None node.operatorNode = None
def __call__(self, trace, scaffolder): # CONSDIER how to unify this code with EnumerativeGibbsOperator. # Problems: # - a torus cannot be copied by copy_trace # - a particle cannot be copied by copy_trace either # - copy_trace undoes incorporation (on Lite traces) scaffold = scaffolder.sampleIndex(trace) assertTrace(trace, scaffold) pnodes = scaffold.getPrincipalNodes() allSetsOfValues = \ getCartesianProductOfEnumeratedValuesWithAddresses(trace, pnodes) xiWeights = [] xiParticles = [] for newValuesWithAddresses in allSetsOfValues: xiParticle = self.copy_trace(trace) # CONSIDER what to do with the weight from this xiParticle.makeConsistent() # Impossible original state is probably fine # ASSUME the scaffolder is deterministic. Have to make the # scaffold again b/c detach mutates it, and b/c it may not work # across copies of the trace. scaffold = scaffolder.sampleIndex(xiParticle) (rhoWeight, _) = detachAndExtract(xiParticle, scaffold) assertTorus(scaffold) registerDeterministicLKernelsByAddress(xiParticle, scaffold, newValuesWithAddresses) xiWeight = regenAndAttach(xiParticle, scaffold, False, OmegaDB(), OrderedDict()) xiParticles.append(xiParticle) # CONSIDER What to do with the rhoWeight. Subtract off the # likelihood? Subtract off the prior and the likelihood? Do # nothing? Subtracting off the likelihood makes # hmm-approx-filter.vnt from ppaml-cps/cp4/p3_hmm be # deterministic (except roundoff effects), but that may be an # artifact of the way that program is written. xiWeights.append(xiWeight - rhoWeight) return (xiParticles, xiWeights)
def compute_particles(self, trace, scaffold): assertTrace(trace, scaffold) pnodes = scaffold.getPrincipalNodes() currentValues = getCurrentValues(trace, pnodes) registerDeterministicLKernels(trace, scaffold, pnodes, currentValues) rhoWeight, self.rhoDB = detachAndExtract(trace, scaffold) xiWeights = [] xiParticles = [] allSetsOfValues = getCartesianProductOfEnumeratedValues(trace, pnodes) for newValues in allSetsOfValues: if newValues == currentValues: # If there are random choices downstream, keep their current values. # This follows the auxiliary variable method in Neal 2000, # "Markov Chain Sampling Methods for Dirichlet Process Models" # (Algorithm 8 with m = 1). # Otherwise, we may target the wrong stationary distribution. # See testEnumerativeGibbsBrushRandomness in # test/inference_language/test_enumerative_gibbs.py for an # example. shouldRestore = True omegaDB = self.rhoDB else: shouldRestore = False omegaDB = OmegaDB() xiParticle = self.copy_trace(trace) assertTorus(scaffold) registerDeterministicLKernels(trace, scaffold, pnodes, newValues) xiParticles.append(xiParticle) xiWeights.append( regenAndAttach(xiParticle, scaffold, shouldRestore, omegaDB, OrderedDict())) # if shouldRestore: # assert_almost_equal(xiWeights[-1], rhoWeight) return (xiParticles, xiWeights)
def just_regen(self, scaffold): return regenAndAttach(self, scaffold, False, OmegaDB(), OrderedDict())
def uneval(self, id): assert id in self.families unevalFamily(self, self.families[id], Scaffold(), OmegaDB()) del self.families[id]
def eval(self, id, exp): assert id not in self.families (_, self.families[id]) = evalFamily(self, addr.directive_address(id), self.unboxExpression(exp), self.globalEnv, Scaffold(), False, OmegaDB(), OrderedDict())
def update(trace, node): scaffold = Scaffold() omegaDB = OmegaDB() unapplyPSP(trace, node, scaffold, omegaDB) applyPSP(trace, node, scaffold, False, omegaDB, OrderedDict())