예제 #1
0
def logpow(x, m):
    """
    Calculates log(x**m) since m*log(x) will fail when m, x = 0.
    """
    # return m * log(x)
    return aet.switch(aet.eq(x, 0), aet.switch(aet.eq(m, 0), 0.0, -np.inf),
                      m * aet.log(x))
예제 #2
0
def test_nested():
    notimpl = NotImplementedOp()
    ifelseifelseif = IfElseIfElseIf()

    x1 = tt.scalar("x1")
    x2 = tt.scalar("x2")
    c1 = tt.scalar("c1")
    c2 = tt.scalar("c2")
    t1 = ifelse(c1, x1, notimpl(x2))
    t1.name = "t1"
    t2 = t1 * 10
    t2.name = "t2"
    t3 = ifelse(c2, t2, x1 + t1)
    t3.name = "t3"
    t4 = ifelseifelseif(tt.eq(x1, x2), x1, tt.eq(x1, 5), x2, c2, t3, t3 + 0.5)
    t4.name = "t4"

    linker = aesara.gof.vm.VM_Linker(lazy=False)
    f = function([c1, c2, x1, x2],
                 t4,
                 mode=Mode(linker=linker, optimizer="fast_run"))
    with pytest.raises(NotImplementedOpException):
        f(1, 0, np.array(10, dtype=x1.dtype), 0)

    linker = aesara.gof.vm.VM_Linker(lazy=True)
    f = function([c1, c2, x1, x2],
                 t4,
                 mode=Mode(linker=linker, optimizer="fast_run"))
    assert f(1, 0, np.array(10, dtype=x1.dtype), 0) == 20.5
예제 #3
0
    def __call__(self, X):
        XY = X.dot(X.T)
        x2 = at.sum(X**2, axis=1).dimshuffle(0, "x")
        X2e = at.repeat(x2, X.shape[0], axis=1)
        H = X2e + X2e.T - 2.0 * XY

        V = at.sort(H.flatten())
        length = V.shape[0]
        # median distance
        m = at.switch(
            at.eq((length % 2), 0),
            # if even vector
            at.mean(V[((length // 2) - 1):((length // 2) + 1)]),
            # if odd vector
            V[length // 2],
        )

        h = 0.5 * m / at.log(floatX(H.shape[0]) + floatX(1))

        #  RBF
        Kxy = at.exp(-H / h / 2.0)

        # Derivative
        dxkxy = -at.dot(Kxy, X)
        sumkxy = at.sum(Kxy, axis=-1, keepdims=True)
        dxkxy = at.add(dxkxy, at.mul(X, sumkxy)) / h

        return Kxy, dxkxy
예제 #4
0
def get_steps(
    steps: Optional[Union[int, np.ndarray, TensorVariable]],
    *,
    shape: Optional[Shape] = None,
    dims: Optional[Dims] = None,
    observed: Optional[Any] = None,
    step_shape_offset: int = 0,
):
    """Extract number of steps from shape / dims / observed information

    Parameters
    ----------
    steps:
        User specified steps for timeseries distribution
    shape:
        User specified shape for timeseries distribution
    dims:
        User specified dims for timeseries distribution
    observed:
        User specified observed data from timeseries distribution
    step_shape_offset:
        Difference between last shape dimension and number of steps in timeseries
        distribution, defaults to 0

    Returns
    -------
    steps
        Steps, if specified directly by user, or inferred from the last dimension of
        shape / dims / observed. When two sources of step information are provided,
        a symbolic Assert is added to ensure they are consistent.
    """
    inferred_steps = None
    if shape is not None:
        shape = to_tuple(shape)
        if shape[-1] is not ...:
            inferred_steps = shape[-1] - step_shape_offset

    if inferred_steps is None and dims is not None:
        dims = convert_dims(dims)
        if dims[-1] is not ...:
            model = modelcontext(None)
            inferred_steps = model.dim_lengths[dims[-1]] - step_shape_offset

    if inferred_steps is None and observed is not None:
        observed = convert_observed_data(observed)
        inferred_steps = observed.shape[-1] - step_shape_offset

    if inferred_steps is None:
        inferred_steps = steps
    # If there are two sources of information for the steps, assert they are consistent
    elif steps is not None:
        inferred_steps = Assert(msg="Steps do not match last shape dimension")(
            inferred_steps, at.eq(inferred_steps, steps)
        )
    return inferred_steps
예제 #5
0
def moment_censored(op, rv, dist, lower, upper):
    moment = at.switch(
        at.eq(lower, -np.inf),
        at.switch(
            at.isinf(upper),
            # lower = -inf, upper = inf
            0,
            # lower = -inf, upper = x
            upper - 1,
        ),
        at.switch(
            at.eq(upper, np.inf),
            # lower = x, upper = inf
            lower + 1,
            # lower = x, upper = x
            (lower + upper) / 2,
        ),
    )
    moment = at.full_like(dist, moment)
    return moment
예제 #6
0
    def logp(self, obs):
        """Return the scalar Theano log-likelihood at a point."""

        obs_tt = at.as_tensor_variable(obs)

        logp_val = at.alloc(-np.inf, *obs.shape)

        for i, dist in enumerate(self.comp_dists):
            i_mask = at.eq(self.states, i)
            obs_i = obs_tt[i_mask]
            subset_dist = dist.dist(*distribution_subset_args(dist, obs.shape, i_mask))
            logp_val = at.set_subtensor(logp_val[i_mask], subset_dist.logp(obs_i))

        return logp_val
예제 #7
0
    def _step(i, pkm1, pkm2, qkm1, qkm2, k1, k2, k3, k4, k5, k6, k7, k8, r):
        xk = -(x * k1 * k2) / (k3 * k4)
        pk = pkm1 + pkm2 * xk
        qk = qkm1 + qkm2 * xk
        pkm2 = pkm1
        pkm1 = pk
        qkm2 = qkm1
        qkm1 = qk

        xk = (x * k5 * k6) / (k7 * k8)
        pk = pkm1 + pkm2 * xk
        qk = qkm1 + qkm2 * xk
        pkm2 = pkm1
        pkm1 = pk
        qkm2 = qkm1
        qkm1 = qk

        old_r = r
        r = aet.switch(aet.eq(qk, zero), r, pk / qk)

        k1 += one
        k2 += k26update
        k3 += two
        k4 += two
        k5 += one
        k6 -= k26update
        k7 += two
        k8 += two

        big_cond = aet.gt(aet.abs_(qk) + aet.abs_(pk), BIG)
        biginv_cond = aet.or_(aet.lt(aet.abs_(qk), BIGINV),
                              aet.lt(aet.abs_(pk), BIGINV))

        pkm2 = aet.switch(big_cond, pkm2 * BIGINV, pkm2)
        pkm1 = aet.switch(big_cond, pkm1 * BIGINV, pkm1)
        qkm2 = aet.switch(big_cond, qkm2 * BIGINV, qkm2)
        qkm1 = aet.switch(big_cond, qkm1 * BIGINV, qkm1)

        pkm2 = aet.switch(biginv_cond, pkm2 * BIG, pkm2)
        pkm1 = aet.switch(biginv_cond, pkm1 * BIG, pkm1)
        qkm2 = aet.switch(biginv_cond, qkm2 * BIG, qkm2)
        qkm1 = aet.switch(biginv_cond, qkm1 * BIG, qkm1)

        return (
            (pkm1, pkm2, qkm1, qkm2, k1, k2, k3, k4, k5, k6, k7, k8, r),
            until(aet.abs_(old_r - r) < (THRESH * aet.abs_(r))),
        )
예제 #8
0
 def logp(self, value):
     return at.switch(at.eq(value, self.c), 0.0, -np.inf)
예제 #9
0
    def logp(self, states):
        r"""Create a Theano graph that computes the log-likelihood for a discrete Markov chain.

        This is the log-likelihood for the joint distribution of states, :math:`S_t`, conditional
        on state samples, :math:`s_t`, given by the following:

        .. math::

            \int_{S_0} P(S_1 = s_1 \mid S_0) dP(S_0) \prod^{T}_{t=2} P(S_t = s_t \mid S_{t-1} = s_{t-1})

        The first term (i.e. the integral) simply computes the marginal :math:`P(S_1 = s_1)`, so
        another way to express this result is as follows:

        .. math::

            P(S_1 = s_1) \prod^{T}_{t=2} P(S_t = s_t \mid S_{t-1} = s_{t-1})

        """  # noqa: E501

        Gammas = at.shape_padleft(self.Gammas, states.ndim - (self.Gammas.ndim - 2))

        # Multiply the initial state probabilities by the first transition
        # matrix by to get the marginal probability for state `S_1`.
        # The integral that produces the marginal is essentially
        # `gamma_0.dot(Gammas[0])`
        Gamma_1 = Gammas[..., 0:1, :, :]
        gamma_0 = tt_expand_dims(self.gamma_0, (-3, -1))
        P_S_1 = at.sum(gamma_0 * Gamma_1, axis=-2)

        # The `tt.switch`s allow us to broadcast the indexing operation when
        # the replication dimensions of `states` and `Gammas` don't match
        # (e.g. `states.shape[0] > Gammas.shape[0]`)
        S_1_slices = tuple(
            slice(
                at.switch(at.eq(P_S_1.shape[i], 1), 0, 0),
                at.switch(at.eq(P_S_1.shape[i], 1), 1, d),
            )
            for i, d in enumerate(states.shape)
        )
        S_1_slices = (tuple(at.ogrid[S_1_slices]) if S_1_slices else tuple()) + (
            states[..., 0:1],
        )
        logp_S_1 = at.log(P_S_1[S_1_slices]).sum(axis=-1)

        # These are slices for the extra dimensions--including the state
        # sequence dimension (e.g. "time")--along which which we need to index
        # the transition matrix rows using the "observed" `states`.
        trans_slices = tuple(
            slice(
                at.switch(
                    at.eq(Gammas.shape[i], 1), 0, 1 if i == states.ndim - 1 else 0
                ),
                at.switch(at.eq(Gammas.shape[i], 1), 1, d),
            )
            for i, d in enumerate(states.shape)
        )
        trans_slices = (tuple(at.ogrid[trans_slices]) if trans_slices else tuple()) + (
            states[..., :-1],
        )

        # Select the transition matrix row of each observed state; this yields
        # `P(S_t | S_{t-1} = s_{t-1})`
        P_S_2T = Gammas[trans_slices]

        obs_slices = tuple(slice(None, d) for d in P_S_2T.shape[:-1])
        obs_slices = (tuple(at.ogrid[obs_slices]) if obs_slices else tuple()) + (
            states[..., 1:],
        )
        logp_S_1T = at.log(P_S_2T[obs_slices])

        res = logp_S_1 + at.sum(logp_S_1T, axis=-1)
        res.name = "DiscreteMarkovChain_logp"

        return res