Example #1
0
    def log_likelihood(self, RVs, observations, llik):
        """
        The output from this function may be a random variable, if not all sources
        of randomness are observed.

        llik - a vector to which observation log-likelihoods will be added.
        """

        if len(RVs) != len(observations):
            raise TypeError("RVs and observations must have same length")

        for iv in RVs:
            if not montetheano.rv.is_rv(iv.vals):
                raise ValueError("non-random var in RVs element", iv)

        assignment = {}
        idxs_of = {}
        for rv, o in zip(RVs, observations):
            assignment[rv.vals] = o.vals
            idxs_of[o.vals] = o.idxs

        # All random variables that are not assigned should stay as the same
        # object so it can later be replaced
        # If this is not done this way, they get cloned
        # raw_RVs = [v for v in ancestors(RVs.flatten())
        # if montetheano.rv.is_raw_rv(v)]

        # Cast assignment elements to the right kind of thing
        assignment = montetheano.rv.typed_items(assignment)

        for rv_vals, obs_vals in assignment.items():
            lpdf = montetheano.rv.lpdf(rv_vals, obs_vals)
            llik = tensor.inc_subtensor(llik[idxs_of[obs_vals]], lpdf)

        # rewire the graph so that the posteriors depend on other
        # observations instead of each other.

        involved = [llik] + RVs.flatten() + observations.flatten()

        inputs = theano.gof.graph.inputs(involved)
        env = ienv.std_interactive_env(inputs, involved, clone_inputs_and_orphans=False)

        env.replace_all_sorted(
            zip(RVs.flatten(), observations.flatten()), reason="IndependentNodeTreeEstimator.log_likelihood"
        )

        # raise an exception if we created cycles
        env.toposort()

        rval = env.newest(llik)
        env.disown()
        return rval
Example #2
0
    def posterior(self, priors, observations, s_rng):
        """
        priors - an IdxsValsList of random variables
        observations - an IdxsValsList of corresponding samples

        returns - an IdxsValsList of posterior random variables
        """

        assert len(priors) == len(observations)

        # observation.idxs could be invalid.
        # They could be invalid, in the sense of describing samples that
        # could not have been drawn from the prior.
        # This code does not try to detect that situation.
        post_vals = [self.s_posterior_helper(p, o, s_rng) for p, o in zip(priors, observations)]

        # At this point, each post_vals[i] is connected to the original graph
        # formed of prior nodes.
        #
        # We want each post_vals[i] to be connected instead to the other
        # post_vals just created, corresponding to the posterior values of other
        # random vars.
        #
        # The way to get all the new_s_val nodes hooked up to one another is to
        # use the clone_keep_replacements function.

        # XXX: this clones everything. It should be possible to do a more
        #      selective clone of just the pieces that change.
        inputs = theano.gof.graph.inputs(priors.flatten() + post_vals)
        env = ienv.std_interactive_env(inputs, priors.flatten() + post_vals, clone_inputs_and_orphans=False)
        env.prefer_replace(zip(priors.valslist(), post_vals), reason="IndependentNodeTreeEstimator.posterior")

        # raise an exception if we created cycles
        env.toposort()

        # extract the cloned results from the env
        rval = IdxsValsList.fromlists([env.newest(v) for v in priors.idxslist()], [env.newest(v) for v in post_vals])

        # remove all references in the variables to the env. Prepare them
        # to be inserted into another env if necessary.
        env.disown()
        return rval