Example #1
0
 def isRandom(self):
     # type: () -> bool
     """Return whether this PSP is stochastic or not.  This is important
 because only nodes whose operators are random PSPs can be
 principal.
 """
     raise VentureBuiltinSPMethodError("Do not know whether %s is random",
                                       type(self))
Example #2
0
 def gradientOfSimulate(self, args, _value, direction):
     # Don't need the value if the function is deterministic, because
     # it consumes no randomness.
     if self.sim_grad:
         return self.sim_grad(args, direction)
     else:
         raise VentureBuiltinSPMethodError(
             "Cannot compute simulation gradient of '%s'" %
             self.description("<unknown name>"))
Example #3
0
    def enumerateValues(self, _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.
    """
        raise VentureBuiltinSPMethodError("Cannot enumerate %s.", type(self))
Example #4
0
    def madeSpLogDensityOfDataBound(self, _aux):
        """Upper bound the logDensityOfData the made SP may report for the
    given aux, up to arbitrary changes to the args wherewith the maker
    is simulated.

    TODO Communicate the maker's fixed parameters here to enable more
    precise bounds.
    """
        raise VentureBuiltinSPMethodError(
            "Cannot rejection auto-bound AAA procedure "
            "with unbounded log density of data.")
Example #5
0
    def gradientOfLogDensity(self, _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."""
        raise VentureBuiltinSPMethodError(
            "Cannot compute gradient of log density "
            "of %s", type(self))
Example #6
0
    def gradientOfLogDensityOfData(self, _aux, _args):
        """Return the gradient of the made PSP's logDensityOfData function.
    This method is needed only for gradient-based methods and is
    relevant only for makers of PSPs that collect sufficient
    statistics via incorporate and unincorporate.

    The gradient should be returned as a list of the partial
    derivatives with respect to the arguments.

    """
        raise VentureBuiltinSPMethodError(
            "Cannot compute gradient of log density of data of %s", type(self))
Example #7
0
    def canAbsorb(self, _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.
    """
        raise VentureBuiltinSPMethodError("Do not know whether %s can absorb",
                                          type(self))
Example #8
0
    def logDensity(self, _value, _args):
        # type: (vv.VentureValue, IArgs) -> float
        """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.
    """
        raise VentureBuiltinSPMethodError("Cannot compute log density of %s",
                                          type(self))
Example #9
0
    def logDensityOfData(self, _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 return the sum of the log-density at each application
    of this PSP; which is also the joint log-density of producing any
    one permutation of the observed output sequence.  For some
    distributions (e.g., Poisson), this may not be computable from the
    traditional sufficient statisitc; in such a case, the sufficient
    statistic should be augmented with sufficient information to
    compute this.  For rationales for this specification, see
    doc/on-log-density-of-counts.md.
    """
        raise VentureBuiltinSPMethodError(
            "Cannot compute log density of data of "
            "%s", type(self))
Example #10
0
    def gradientOfSimulate(self, _args, _value, _direction):
        # type: (IArgs, vv.VentureValue, vv.VentureValue) -> List[vv.VentureValue]
        """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).
    """
        raise VentureBuiltinSPMethodError(
            "Cannot compute simulation gradient of %s", type(self))
Example #11
0
    def logDensityBound(self, _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 IArgs instance 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?
    """
        raise VentureBuiltinSPMethodError(
            "Cannot compute log density bound of %s", type(self))
Example #12
0
 def simulate(self, _args):
     # type: (IArgs) -> vv.VentureValue
     """Simulate this process with the given parameters and return the result."""
     raise VentureBuiltinSPMethodError("Simulate not implemented!")
Example #13
0
 def getAAALKernel(self):
     raise VentureBuiltinSPMethodError("%s has no AAA LKernel", type(self))