def computeMeanCovar(self):
     weights = np.exp(self.logweights - logsumexp(self.logweights))
     mu = np.dot(self.mus, weights).reshape((self.dim, 1))
     Ex2 = np.reshape(np.dot(
         self.Sigmas, weights), (self.dim, self.dim)) + np.asarray(
             np.dot(np.multiply(self.mus, weights), self.mus.T))
     Sigma = Ex2 - np.dot(mu, mu.T)
     return (mu, Sigma)
 def logProb(self, x):
     N = self.numComps()
     if len(x.shape) == 1:
         x = x.reshape((self.dim, -1))
     lps = np.empty((N, x.shape[1]))
     for i in range(N):
         lps[i, :] = gaussian_logprob(
             x, self.getMu(i), self.Sigmas[:, :, i]) + self.logweights[i]
     return logsumexp(lps, 0)
 def normalizeWeights(self):
     N = self.numComps()
     if N == 0:
         return -np.inf
     elif N == 1:
         normFactor = self.logweights[0]
         self.logweights[0] = 0
         #            print 'Normalizing single component mixture, normFactor = {0}, lw = {1}'.format(normFactor,self.logweights[0,0])
         return normFactor
     else:
         normFactor = logsumexp(self.logweights)
         assert (np.isfinite(normFactor))
         self.logweights -= normFactor
         normFactor2 = logsumexp(self.logweights)
         if np.abs(normFactor2) > 1e-8:
             normFactor += normFactor2
             self.logweights -= normFactor2
         return normFactor
def klDiv_varit(Phi,
                logPhi,
                logPsi,
                logweights_ref,
                logweights_other,
                KLdivs,
                upd_other_logweights=False):
    tmp = logPsi - KLdivs
    lsetmp = logsumexp(tmp, 0)
    lsetmp[np.logical_not(np.isfinite(lsetmp))] = 0
    logPhi = logweights_ref.reshape((1, -1)) + (tmp - lsetmp)
    Phi = np.exp(logPhi)
    if upd_other_logweights:
        logweights_other = logsumexp(logPhi, 1)
    logPsi = logweights_other.reshape(
        (-1, 1)) + logPhi - logsumexp(logPhi, 1).reshape((-1, 1))

    D_upper = klDiv_var(Phi, logPhi, logPsi, KLdivs)

    if upd_other_logweights:
        return (D_upper, Phi, logPhi, logPsi, logweights_other)
    else:
        return (D_upper, Phi, logPhi, logPsi)
    def eval(self, X):
        X = np.asarray(X)
        if X.ndim == 1:
            X = X[:, np.newaxis]
        if X.size == 0:
            return np.array([]), np.empty((0, self.n_components))
        if X.shape[1] != self.means_.shape[1]:
            raise ValueError('the shape of X  is not compatible with self')

        lpr = (log_multivariate_normal_density(
                X, self.means_, self.covars_, self.covariance_type)
               + np.log(self.weights_))
        logprob = logsumexp(lpr, axis=1)
        responsibilities = np.exp(lpr - logprob[:, np.newaxis])
        return logprob, responsibilities
 def dlogProb(self, x):
     N = self.numComps()
     origxshape = x.shape
     if len(x.shape) == 1:
         x = x.reshape((self.dim, 1))
     lps = np.empty((N, 1))
     grads = np.empty((N, self.dim))
     for i in range(N):
         cmu = self.getMu(i)
         cSigma = self.Sigmas[:, :, i]
         cholSigma = np.linalg.cholesky(cSigma)
         lps[i, 0] = gaussian_logprob(x, cmu, cSigma,
                                      cholSigma) + self.logweights[i]
         grads[i, :] = gaussian_logprob_grad(x, cmu, cSigma, cholSigma)
     return np.sum(np.multiply(np.exp(lps - logsumexp(lps, 0)), grads),
                   0).reshape(origxshape)
    def klDivergence_varupper(self, other):
        """ Returns an (upper bound) approximation to KL(self||other). """
        D = self.dim
        Nref = self.numComps()
        Nother = other.numComps()

        if KLdivs == None:
            cholSigmaSelf = np.empty((D, D, Nref))
            for b in range(Nref):
                cholSigmaSelf[:, :, b] = np.linalg.cholesky(self.getSigma(b))

            KLdivs = np.empty((Nother, Nref))
            for b in range(Nother):
                mub = other.getMu(b)
                Sigmab = other.getSigma(b)
                cholSigmab = np.linalg.cholesky(other.getSigma(b))

                KLdivs[b, :] = gaussian_kl_vec(self.mus,
                                               self.Sigmas,
                                               mub,
                                               Sigmab,
                                               cholSigma1=cholSigmaSelf,
                                               cholSigma2=cholSigmab)

        logPhi = other.logweights.reshape(Nother, 1) + self.logweights.reshape(
            1, Nref)
        logPsi = self.logweights.reshape(Nother, 1) + logPhi - logsumexp(
            logPhi, 1).reshape((Nother, 1))
        Phi = np.exp(logPhi)

        done = False
        itNum = 0
        D_upper = np.inf
        while not done:
            itNum += 1
            last_D_upper = D_upper

            (D_upper, Phi, logPhi,
             logPsi) = klDiv_varit(Phi, logPhi, logPsi, self.logweights,
                                   other.logweights, KLdivs)

            assert (np.isfinite(D_upper))
            print '{0}: D_upper = {2}'.format(itNum, D_upper)
            if D_upper - last_D_upper > 1e-6:
                break

        return D_upper
 def drawSamples(self, N):
     Ws = np.exp(self.logweights - logsumexp(self.logweights))
     sampleComps = np.random.multinomial(N, Ws)
     samples = np.empty((self.dim, N))
     startInd = 0
     for i in range(len(sampleComps)):
         cN = sampleComps[i]
         if cN < 0:
             print cN
             print sampleComps
             print Ws
             print self.logweights
         assert (cN >= 0)
         assert (startInd >= 0)
         samples[:, startInd:(startInd + cN)] = self.getMu(i) + np.dot(
             np.linalg.cholesky(self.Sigmas[:, :, i]),
             np.random.randn(self.dim, cN))
         startInd += cN
     return samples
 def computeMean(self):
     weights = np.exp(self.logweights - logsumexp(self.logweights))
     mu = np.dot(self.mus, weights).reshape((self.dim, 1))
     return mu
    def simplify(self, ref=None, natThresh=None, minNumComps=1):
        """ Remove components and adjust the mixture until just before the KL divergence exceeds natThresh """
        maxNumSubVarIts = 5
        maxNumVarIts = 20
        maxNumDelPerIt = 1

        D = self.dim
        Nself = self.numComps()
        Nnew = Nself

        # Compute Cholesky decompositions
        cholSigmaSelf = np.empty((D, D, Nself))
        for b in range(Nself):
            cholSigmaSelf[:, :, b] = np.linalg.cholesky(self.getSigma(b))

        if ref == None:
            ref = deepcopy(self)
            cholSigmaRef = deepcopy(cholSigmaSelf)
            Nref = Nself
            # Initialize the variational parameters
            Phi = np.diag(np.exp(self.logweights.reshape(Nnew)))
            #            logPhi = np.log(Phi)
            logPhi = np.empty_like(Phi)
            logPhi[Phi > 0] = np.log(Phi[Phi > 0])
            logPhi[Phi <= 0] = -np.inf
            #            logPsi = np.log(Phi)
            logPsi = np.copy(logPhi)
        else:
            Nref = ref.numComps()
            cholSigmaRef = np.empty((D, D, Nref))
            for a in range(Nref):
                cholSigmaRef[:, :, a] = np.linalg.cholesky(ref.getSigma(a))
            # Initialize the variational parameters
            logPhi = self.logweights.reshape(Nnew, 1) + ref.logweights.reshape(
                1, Nref)
            logPsi = self.logweights.reshape(Nnew, 1) + logPhi - logsumexp(
                logPhi, 1).reshape((Nnew, 1))
            Phi = np.exp(logPhi)

        # Compute KL divergence between components
        KLdivs = np.empty((Nself, Nref))
        for b in range(Nself):
            mub = self.getMu(b)
            Sigmab = self.getSigma(b)
            cholSigmab = cholSigmaSelf[:, :, b]

            KLdivs[b, :] = gaussian_kl_vec(ref.mus,
                                           ref.Sigmas,
                                           mub,
                                           Sigmab,
                                           cholSigma1=cholSigmaRef,
                                           cholSigma2=cholSigmab)
        del cholSigmaSelf

        new_D_upper = klDiv_var(Phi, logPhi, logPsi, KLdivs)

        newActiveComps = [i for i in range(0, Nself)]
        newActiveComps.sort(key=lambda x: self.logweights[x])

        globalVarItCnt = 0
        itNum = 0
        while Nnew - maxNumDelPerIt >= minNumComps:
            itNum += 1

            currNumDel = 1
            #            delLogW = logsumexp(self.logweights[newActiveComps[0:2]])
            #            while delLogW < np.log(1e-4) and currNumDel < maxNumDelPerIt:
            #                currNumDel += 1
            #                delLogW = logsumexp(self.logweights[newActiveComps[0:(currNumDel+1)]])
            #            print '{0}: numDel = {1}'.format(itNum,currNumDel)
            delCompI = newActiveComps[0:currNumDel]
            propComps = newActiveComps[currNumDel:]
            numDel = len(delCompI)
            Nprop = Nnew - numDel

            propLogWeights = np.logaddexp(
                self.logweights[propComps],
                logsumexp(self.logweights[delCompI]) - np.log(Nprop))
            propMus = self.mus[:, propComps].reshape((D, Nprop))
            propSigmas = self.Sigmas[:, :, propComps].reshape((D, D, Nprop))

            propLogPhi = np.logaddexp(
                logPhi[propComps, :],
                logsumexp(logsumexp(logPhi[delCompI, :], 1), 0) -
                np.log(Nprop))
            propPhi = np.exp(propLogPhi)
            prevNormPropPhi = None
            propKLdivs = KLdivs[propComps, :]
            propLogPsi = propLogWeights.reshape(
                Nprop, 1) + propLogPhi - logsumexp(propLogPhi, 1).reshape(
                    (Nprop, 1))

            D_upper = klDiv_var(propPhi, propLogPhi, propLogPsi, propKLdivs)

            varItNum = 0
            #            while varItNum < maxNumVarIts and (itNum == 0 or D_upper >= natThresh):
            while varItNum < maxNumVarIts and (varItNum == 0
                                               or D_upper >= natThresh):
                varItNum += 1
                globalVarItCnt += 1

                last_propLogWeights = propLogWeights
                lastVarIt_D_upper = D_upper

                # Minimize the upper bound wrt the variational parameters and log weights
                subVarItNum = 0
                while subVarItNum < maxNumSubVarIts and D_upper >= natThresh:
                    lastsub_propLogWeights = propLogWeights
                    lastSubVarIt_D_upper = D_upper
                    (D_upper, propPhi, propLogPhi, propLogPsi,
                     propLogWeights) = klDiv_varit(propPhi, propLogPhi,
                                                   propLogPsi, ref.logweights,
                                                   propLogWeights, propKLdivs,
                                                   True)
                    if np.abs(D_upper - lastSubVarIt_D_upper) < 1e-6:
                        break

                if D_upper >= natThresh:
                    normPropPhi = np.exp(
                        propLogPhi -
                        logsumexp(propLogPhi, 1).reshape(Nprop, 1))
                    if prevNormPropPhi != None:
                        #                        updPropComps = np.nonzero(np.sum(np.abs(normPropPhi - prevNormPropPhi),1).ravel() > 1e-2)
                        #                        updPropComps = updPropComps[0]
                        updPropComps = np.array([
                            np.argmax(
                                np.sum(np.abs(normPropPhi - prevNormPropPhi),
                                       1).ravel())
                        ])
                    else:
                        updPropComps = range(Nprop)
#                    updPropComps = range(Nprop)
#                    updPropComps = np.array([np.argmax(logsumexp(propLogPhi,1).ravel())])
                else:
                    updPropComps = []

                if len(updPropComps) > 0:
                    if prevNormPropPhi == None:
                        prevNormPropPhi = normPropPhi
                    else:
                        prevNormPropPhi[updPropComps, :] = normPropPhi[
                            updPropComps, :]
                    propMus[:, updPropComps] = np.dot(
                        ref.mus, normPropPhi[updPropComps, :].T)
                    dmus = propMus[:, updPropComps].reshape(
                        D, -1, 1) - ref.mus.reshape(D, 1, Nref)
                    dmuCovs = np.multiply(dmus.reshape(D, 1, -1, Nref),
                                          dmus.reshape(1, D, -1, Nref))
                    #updPropSigmas = np.sum(np.multiply((ref.Sigmas.reshape(D,D,1,Nref) + dmuCovs).reshape((D,D,-1,Nref)),normPropPhi[updPropComps,:].reshape((1,1,-1,Nref))),3)
                    updPropSigmas = np.sum(
                        np.multiply(
                            ref.Sigmas.reshape(D, D, 1, Nref),
                            normPropPhi[updPropComps, :].reshape(
                                (1, 1, -1, Nref))), 3) + np.sum(
                                    np.multiply(
                                        dmuCovs.reshape((D, D, -1, Nref)),
                                        normPropPhi[updPropComps, :].reshape(
                                            (1, 1, -1, Nref))), 3)
                    propSigmas[:, :, updPropComps] = updPropSigmas

                    prev___D_upper = D_upper
                    prev___KLDivs = propKLdivs[updPropComps, :]
                    for (tInd, propInd) in enumerate(updPropComps):
                        mub = propMus[:, propInd].reshape((D, 1))
                        Sigmab = propSigmas[:, :, propInd]
                        propKLdivs[propInd, :] = gaussian_kl_vec(
                            ref.mus,
                            ref.Sigmas,
                            mub,
                            Sigmab,
                            cholSigma1=cholSigmaRef)

#                    (D_upper,propPhi,propLogPhi,propLogPsi,propLogWeights) = klDiv_varit(propPhi,propLogPhi,propLogPsi,ref.logweights,propLogWeights,propKLdivs,True)
                    D_upper = klDiv_var(propPhi, propLogPhi, propLogPsi,
                                        propKLdivs)
                    if False and D_upper - prev___D_upper >= 1e-6:
                        print '{0} -> {1}'.format(prev___D_upper, D_upper)
                        print 'prevKLDivs = {0}'.format(prev___KLDivs)
                        print 'currKLDivs = {0}'.format(
                            propKLdivs[updPropComps, :])
                        assert (D_upper - prev___D_upper < 1e-6)
#                    print '{0} -> {1}'.format(prev___D_upper,D_upper)
                    if prev___D_upper >= D_upper + 1e-8:
                        break

#                (D_upper,propPhi,propLogPhi,propLogPsi,propLogWeights) = klDiv_varit(propPhi,propLogPhi,propLogPsi,ref.logweights,propLogWeights,propKLdivs,True)
#                print '  {1}: D_upper = {0}, subVarItNums = {2}'.format(D_upper,varItNum,subVarItNum)

                if np.abs(D_upper - lastVarIt_D_upper) < 1e-6 and np.all(
                        np.abs(last_propLogWeights - propLogWeights) < 1e-6):
                    break

#            print '{2}: D_upper = {0}, varItNums = {1}'.format(D_upper,varItNum,itNum)

            if D_upper > natThresh:
                break
            else:
                Nnew = Nprop
                new_D_upper = D_upper

                KLdivs[propComps, :] = propKLdivs
                logPhi[propComps, :] = propLogPhi
                Phi[propComps, :] = propPhi
                logPsi[propComps, :] = propLogPsi

                self.logweights[delCompI] = -np.inf
                self.logweights[propComps] = propLogWeights
                self.mus[:, propComps] = propMus
                self.Sigmas[:, :, propComps] = propSigmas

                while numDel > 0:
                    newActiveComps.pop(0)
                    numDel += -1
                newActiveComps.sort(key=lambda x: self.logweights[x])

        if Nnew < Nself:
            self.logweights = self.logweights[newActiveComps]
            self.mus = self.mus[:, newActiveComps].reshape(D, Nnew)
            self.Sigmas = self.Sigmas[:, :, newActiveComps].reshape(D, D, Nnew)

        return new_D_upper