Example #1
0
 def backward(self, obs, start=0, length=0):
     if length == 0:
         length = obs.shape[0]
         start = length-1
     beta = []
     for i in range(start, start - length, -1):
         message = Message()
         # change
         p_obs = Potential.from_observation(obs[i, :], self.m, self.n)
         pot_change = p_obs.copy()
         if len(beta) > 0:
             temp = Message()
             for p in beta[-1].potentials:
                 temp.add_potential(p * self.prior)
             pot_change.log_c += self.log_p1 + temp.log_likelihood()
         message.add_potential(pot_change)
         # no change
         if len(beta) > 0:
             for p in beta[-1].potentials:
                 p2 = p * p_obs
                 p2.log_c += self.log_p0
                 message.add_potential(p2)
         beta.append(message)
     beta.reverse()
     return beta
Example #2
0
 def __init__(self, p1, alpha, a, b):
     self.p1 = None      # prob. of change
     self.log_p1 = None  # log prob. of change
     self.log_p0 = None  # log prob. no change
     self.set_p1(p1)
     self.prior = Potential(alpha, a, b)
     self.m = len(alpha)
     self.n = len(a)
Example #3
0
class Model:
    def __init__(self, p1, alpha, a, b):
        self.p1 = None      # prob. of change
        self.log_p1 = None  # log prob. of change
        self.log_p0 = None  # log prob. no change
        self.set_p1(p1)
        self.prior = Potential(alpha, a, b)
        self.m = len(alpha)
        self.n = len(a)

    def set_p1(self, p1):
        self.p1 = p1
        self.log_p1 = np.log(p1)
        self.log_p0 = np.log(1-p1)

    @classmethod
    def load(cls, filename):
        buffer = utils.load_txt(filename)
        p1 = buffer[0]
        m = int(buffer[1])
        n = int(buffer[2])
        alpha = buffer[3:m+3]
        a = buffer[3+m:3+m+n]
        b = buffer[3+m+n:3+m+n+n]
        return cls(p1, alpha, a, b)

    @classmethod
    def default_model(cls, p1, m, n):
        alpha = np.ones(m)
        a = np.ones(n) * 10
        b = np.ones(n)
        return cls(p1, alpha, a, b)

    def save(self, filename):
        buffer = np.concatenate(([self.p1, self.m, self.n], self.prior.alpha, self.prior.a, self.prior.b))
        utils.save_txt(filename, buffer)

    def generate_data(self, t):
        s = np.random.binomial(1, self.p1, t)               # change points
        h = np.zeros((t, self.m + self.n))    # hidden states
        v = np.zeros((t, self.m + self.n))    # observations
        for i in range(t):
            if i == 0 or s[i] == 1:
                # generate random state:
                h[i, :] = self.prior.rand()
            else:
                # copy previous state
                h[i, :] = h[i-1, :]
            # generate observation
            v[i, :] = self.rand_obs(h[i, :])
        return Data(s, h, v)

    def rand_obs(self, state):
        obs = np.asarray([])
        if self.m > 0:
            obs = np.random.multinomial(100, state[0:self.m])
        if self.n > 0:
            obs = np.concatenate((obs, np.random.poisson(state[self.m:])))
        return obs

    def predict(self, alpha):
        m = Message()
        # add change component
        m.add_potential(Potential(self.prior.alpha, self.prior.a, self.prior.b, self.log_p1 + alpha.log_likelihood()))
        # add no-change components
        for p in alpha.potentials:
            m.add_potential(Potential(p.alpha, p.a, p.b, p.log_c + self.log_p0))
        return m

    def update(self, predict, obs):
        m = Message()
        p_obs = Potential.from_observation(obs, self.m, self.n)
        for p in predict.potentials:
            m.add_potential(p * p_obs)
        return m

    def forward(self, obs):
        alpha = []
        alpha_predict = []
        for i in range(obs.shape[0]):
            if i == 0:
                m = Message()
                m.add_potential(Potential(self.prior.alpha, self.prior.a, self.prior.b, self.log_p1))
                m.add_potential(Potential(self.prior.alpha, self.prior.a, self.prior.b, self.log_p0))
                alpha_predict.append(m)
            else:
                alpha_predict.append(self.predict(alpha[-1]))
            alpha.append(self.update(alpha_predict[-1], obs[i, :]))
        return [alpha_predict, alpha]

    def backward(self, obs, start=0, length=0):
        if length == 0:
            length = obs.shape[0]
            start = length-1
        beta = []
        for i in range(start, start - length, -1):
            message = Message()
            # change
            p_obs = Potential.from_observation(obs[i, :], self.m, self.n)
            pot_change = p_obs.copy()
            if len(beta) > 0:
                temp = Message()
                for p in beta[-1].potentials:
                    temp.add_potential(p * self.prior)
                pot_change.log_c += self.log_p1 + temp.log_likelihood()
            message.add_potential(pot_change)
            # no change
            if len(beta) > 0:
                for p in beta[-1].potentials:
                    p2 = p * p_obs
                    p2.log_c += self.log_p0
                    message.add_potential(p2)
            beta.append(message)
        beta.reverse()
        return beta

    def filter(self, obs):
        alpha = self.forward(obs)[1]
        # compile result
        result = Result()
        result.cpp = [message.cpp() for message in alpha]
        result.mean = [message.mean() for message in alpha]
        result.ll = [alpha[-1].log_likelihood()]
        return result

    def smooth(self, obs):
        [alpha_predict, alpha] = self.forward(obs)
        beta = self.backward(obs)
        # compile result
        result = Result()
        for i in range(len(alpha)):
            gamma = alpha_predict[i] * beta[i]
            result.cpp.append(gamma.cpp(len(beta[i].potentials)))
            result.mean.append(gamma.mean())
        result.ll = [alpha[-1].log_likelihood()]
        return result

    def online_smooth(self, obs, lag):
        if lag == 0:
            return self.filter(obs)

        t = obs.shape[0]
        if lag >= t:
            return self.smooth(obs)

        result = Result()
        [alpha_predict, alpha] = self.forward(obs)
        beta = []

        # Run Fixed-Lag for alpha[0:T - lag]
        for i in range(t - lag + 1):
            beta = self.backward(obs, i + lag - 1, lag)
            gamma = alpha_predict[i] * beta[0]
            result.cpp.append(gamma.cpp(len(beta[0])))
            result.mean.append(gamma.mean())

        # Smooth alpha[T-lag+1:T] with last beta.
        for i in range(1, lag):
            gamma = alpha_predict[t - lag + i] * beta[i]
            result.cpp.append(gamma.cpp(len(beta[i])))
            result.mean.append(gamma.mean())

        result.ll = [alpha[-1].log_likelihood()]
        return result
Example #4
0
 def update(self, predict, obs):
     m = Message()
     p_obs = Potential.from_observation(obs, self.m, self.n)
     for p in predict.potentials:
         m.add_potential(p * p_obs)
     return m