Primitive Stochastic Procedure Interface: module venture.lite.psp

class venture.lite.psp.DeterministicMakerAAAPSP

Bases: venture.lite.psp.DeterministicPSP

Provides good default implementations of PSP methods for PSPs that are deterministic makers whose children can absorb at applications.

childrenCanAAA()
getAAALKernel()
class venture.lite.psp.DeterministicPSP

Bases: venture.lite.psp.PSP

Provides good default implementations of PSP methods for deterministic PSPs.

canAbsorb(_trace, _appNode, _parentNode)
gradientOfLogDensity(_value, args)
isRandom()
logDensity(_value, _args)
logDensityBound(_value, _args)
class venture.lite.psp.DispatchingPSP(f_types, psps)

Bases: venture.lite.psp.PSP

canAbsorb(trace, appNode, parentNode)
canEnumerate()
childrenCanAAA()
description(name)
description_rst_format(name)
enumerateValues(args)
getAAALKernel()
getDeltaKernel(args)
getVariationalLKernel(args)
gradientOfLogDensity(value, args)
gradientOfSimulate(args, value, direction)
hasDeltaKernel()
hasSimulationKernel()
hasVariationalLKernel()
incorporate(value, args)
isRandom()
logDensity(value, args)
logDensityBound(value, args)
logDensityOfCounts(aux)
simulate(args)
unincorporate(value, args)
class venture.lite.psp.ESRRefOutputPSP

Bases: venture.lite.psp.DeterministicPSP

canAbsorb(trace, appNode, parentNode)
gradientOfLogDensity(_value, args)
gradientOfSimulate(args, _value, direction)
simulate(args)
class venture.lite.psp.LikelihoodFreePSP

Bases: venture.lite.psp.RandomPSP

Provides good default implementations of (two) PSP methods for likelihood-free stochastic PSPs.

canAbsorb(_trace, _appNode, _parentNode)
class venture.lite.psp.NullRequestPSP

Bases: venture.lite.psp.DeterministicPSP

canAbsorb(_trace, _appNode, _parentNode)
gradientOfSimulate(args, _value, _direction)
simulate(_args)
class venture.lite.psp.PSP

Bases: object

A Primitive Stochastic Procedure.

PSPs are the basic units of computation in Venture. A PSP represents a (potentially) stochastic process that computes a value conditioned on some arguments (A PSP may instead compute a set of requests for further evaluation by Venture – this is how compound Venture procedures are implemented – but this is an advanced topic).

The PSP interface is for people wishing to extend Venture with bindings to additional external computations (including traditional foreign functions, as well as things like a custom inference method for a particular model type). Users of Venture who do not wish to extend it need not learn the PSP interface.

The main part of the PSP interface is about providing information about the stochastic process the PSP represents – simulating from it, computing log densities, etc. Generally only the ability to simulate is required to define a valid PSP, but implementing the other methods may improve efficiency and/or permit the application of additional inference methods to scaffolds containing the PSP in question.

The PSP interface also currently contains several methods used for the selection of lkernels, pending the invention of a better mechanism. If you don’t know what lkernels are, don’t worry about it – the defaults will do.

The general pattern of PSP methods is that they accept an Args struct (and possibly some additional arguments) and compute something about the stochastic process at that Args struct. The main thing the Args struct contains is the list of arguments this stochastic process is applied to, but it also has a bunch of additional contextual information that can be useful for special PSPs. See node.py for the definition of Args.

The data members of the Args struct will generally be represented as Venture values (instances of the venture.lite.value.VentureValue class). The data returned from psp methods should generally also be instances of the VentureValue class, except methods that yield information for direct consumption by the engine itself (such as the isRandom method). See doc/type-system.md for the design.

Most of the time, the requisite marshalling between VentureValues and corresponding Python representations is mechanical boilerplate, which can be taken care of for you by the TypedPSP class, which see.

canAbsorb(_trace, _appNode, _parentNode)

Return whether this PSP, which is the operator of the given application node, can absorb a change to the value of the given parent node.

If this returns True, then logDensity must return a finite value for any proposed new value of the given parent node. canAbsorb calls are assumed to be cumulative: if a PSP claims to be able to absorb changes to two of its parents individually, that amounts to claiming to absorb changes to both of them simultaneously.

canEnumerate()

Return whether this PSP can enumerate the space of its possible return values. Enumeration is used only for principal nodes in enumerative Gibbs.

childrenCanAAA()
description(_name)

Return a string describing this PSP. The string may include the name argument, which is the symbol that the enclosing SP is bound to.

description_rst_format(_name)
enumerateValues(_args)

Return a list of all the values this PSP can return given the arguments. Enumeration is used only for principal nodes in enumerative Gibbs.

For enumerative Gibbs to work, logDensity must return a finite number for the probability of every value returned from this method, given the same arguments.

getAAALKernel()
getVariationalLKernel(args)
gradientOfLogDensity(_value, _args)

Return the gradient of this PSP’s logDensity function. This method is needed only for gradient-based methods (currently Hamiltonian Monte Carlo and Meanfield).

The gradient should be returned as a 2-tuple of the partial derivative with respect to the value and a list of the partial derivatives with respect to the arguments.

gradientOfSimulate(_args, _value, _direction)

Return the gradient of this PSP’s simulation function. This method is needed only for Hamiltonian Monte Carlo.

Specifically, the gradient of the simulation function must be with respect to the given direction on the output space, at the point given by the args struct (the input space is taken to be the full list of parents). In other words, the Jacobian-vector product

direction^T J_simulate(args).

For PSPs with one scalar output, the direction will be a number, and the correct answer is the gradient of simulate multiplied by that number.

The gradient should be returned as a list of the partial derivatives with respect to each parent node represented in the args.

We circumvent problems with trying to compute derivatives of stochastic functions by mixing over the randomness consumed. What this practically means is that the gradient to be computed is the gradient of the deterministic function of the arguments that is this process, if its randomness is fixed at some particular stream of bits. The gradient will, in general, depend on what those bits are. Pending a better interface for communicating it, the value argument of this method is the value that simulating this PSP outputs when using the fixed randomness with respect to which the gradient is to be computed. We hope that, for sufficiently simple PSPs, this proxy is sufficient.

The exact circumstances when this method is needed for HMC are this PSP appearing as the operator of a non-principal, non-absorbing scaffold node (that is, in the non-principal part of the DRG, or in the brush).

hasDeltaKernel()
hasSimulationKernel()
hasVariationalLKernel()
incorporate(value, args)

Register that an application of this PSP produced the given value at the given args. This is relevant only if the SP needs to maintain statistics about results of its applications (e.g., for collapsed models, or for external inference schemes that need to maintain statistics).

isRandom()

Return whether this PSP is stochastic or not. This is important because only nodes whose operators are random PSPs can be principal.

logDensity(_value, _args)

Return the log-density of simulating the given value from the given args.

If the output space is discrete, return the log-probability.

Note: Venture does not ensure that the given value actually was simulated from the given args. The ability to measure the density of other values (or of the same value at other args) is invaluable for many inference methods.

Implementing this method is not strictly necessary for a valid PSP, but is very helpful for many purposes if the density information is available. See also canAbsorb.

logDensityBound(_value, _args)

Return an upper bound on the possible log density of this PSP holding the given values fixed. This method is needed only for rejection sampling.

Specifically, the value and any or all of the operands present in the Args struct may be None. Return an upper bound on the value the logDensity function could take for any values substituted for the None arguments, but holding fixed the given non-None arguments. See NormalOutputPSP for an example implementation.

This method is used only when this PSP is the operator of an absorbing node under rejection sampling. Tighter upper bounds lead to more efficient rejection sampling.

TODO maybe allow the logDensityBound to return None to indicate no bound, and in this case do not try to absorb at this node when doing rejection sampling? Or should that be a separate method called logDensityBounded?

logDensityOfCounts(_aux)

Return the log-density of simulating a dataset with the given collected statistics.

This is relevant only for PSPs that collect statistics about their uses via incorporate and unincorporate that are sufficient to bulk absorb at all applications of the PSP, without traversing them.

Specifically, the log-density to be returned is the sum of the log-density at each application of this PSP; which is also the log-density of producing any one output sequence consistent with the given collected statistics, given inputs consistent with the same set of collected statistics (which should be equal for all such output sequences, since the statistics are supposed to be sufficient).

madeSpLogDensityOfCountsBound(_aux)
simulate(_args)

Simulate this process with the given parameters and return the result.

unincorporate(value, args)

Unregister one instance of an application of this PSP producing the given value at the given args. This is the inverse of incorporate.

class venture.lite.psp.RandomPSP

Bases: venture.lite.psp.PSP

Provides good default implementations of (two) PSP methods for (assessable) stochastic PSPs.

canAbsorb(_trace, _appNode, _parentNode)
isRandom()
class venture.lite.psp.TypedLKernel(kernel, f_type)

Bases: venture.lite.lkernel.LKernel

forwardSimulate(trace, oldValue, args)
forwardWeight(trace, newValue, oldValue, args)
gradientOfReverseWeight(trace, value, args)
reverseWeight(trace, oldValue, args)
weightBound(trace, value, args)
class venture.lite.psp.TypedPSP(psp, f_type)

Bases: venture.lite.psp.PSP

Wrapper that implements the PSP interface by marshalling and unmarshalling according to a type signature, delegating to an internal PSP.

The interface offered to the delegate of this class has all the same methods as the PSP interface, with all the same semantics, except that the values being operated upon and returned are native Python objects rather than Venture Values. TODO: Perhaps delegates of TypedPSP should not be subclasses of PSP, but of another base class named something like PythonPSP.

canAbsorb(trace, appNode, parentNode)
canEnumerate()
childrenCanAAA()
description(name)
description_rst_format(name)
enumerateValues(args)
getAAALKernel()
getDeltaKernel(args)
getVariationalLKernel(args)
gradientOfLogDensity(value, args)
gradientOfSimulate(args, value, direction)
hasDeltaKernel()
hasSimulationKernel()
hasVariationalLKernel()
incorporate(value, args)
isRandom()
logDensity(value, args)
logDensityBound(value, args)
logDensityOfCounts(aux)
simulate(args)
unincorporate(value, args)
class venture.lite.psp.TypedVariationalLKernel(kernel, f_type)

Bases: venture.lite.psp.TypedLKernel

gradientOfLogDensity(value, args)
updateParameters(gradient, gain, stepSize)

Previous topic

Stochastic Procedure Interface: module venture.lite.sp

Next topic

Foreign SP helpers: module venture.lite.sp_help

This Page