/* Update the group and model sufficient statistics based on assignments qZj. * * mutable: the clusters (add sufficient stats). * returns: the number of observations in each cluster for this groups. */ template <class C> ArrayXd updateSS ( const MatrixXd& Xj, // Observations in group j const MatrixXd& qZj, // Observations to group mixture assignments vector<C>& clusters, // Cluster Distributions const bool sparse // Do sparse updates to groups ) { const unsigned int K = qZj.cols(); const ArrayXd Njk = qZj.colwise().sum(); // count obs. in this group ArrayXi Kful = ArrayXi::Zero(1), // Initialise and set K = 1 defaults Kemp = ArrayXi::Zero(0); // Find empty clusters if sparse if ( (sparse == false) && (K > 1) ) Kful = ArrayXi::LinSpaced(Sequential, K, 0, K-1); else if (sparse == true) arrfind((Njk >= ZEROCUTOFF), Kful, Kemp); const unsigned int nKful = Kful.size(); // Sufficient statistics - with observations for (unsigned int k = 0; k < nKful; ++k) { #ifdef WITH_OMP #pragma omp critical #endif clusters[Kful(k)].addobs(qZj.col(Kful(k)), Xj); } return Njk; }
ArrayXi perm_nodes_2_locations(const PermutationMatrix<Dynamic, Dynamic, int> &_perm_nodes) { ArrayXi indices = _perm_nodes.indices().array(); for (unsigned int i = 0; i<indices.size(); i++) indices = (indices > indices(i)).select(indices + nodes_.at(i).dim-1, indices); return indices; }
void nodePermutation2VariablesPermutation(const PermutationMatrix<Dynamic, Dynamic, int> &_perm_nodes, PermutationMatrix<Dynamic, Dynamic, int> &perm_variables) { ArrayXi locations = perm_nodes_2_locations(_perm_nodes); int last_idx = 0; for (unsigned int i = 0; i<locations.size(); i++) { perm_variables.indices().segment(last_idx, nodes_.at(i).dim) = VectorXi::LinSpaced(nodes_.at(i).dim, locations(i), locations(i)+nodes_.at(i).dim-1); last_idx += nodes_.at(i).dim; } }
BlockMatrixXcd random_hermitian(ArrayXi sizes) { if (log) std::cout << "A random hermitian matrix is made!" << std::endl; const long full_size = sizes.sum(); if (log) std::cout << "We initialize with zeros." << std::endl; BlockMatrixXcd result = MatrixXcd::Zero(full_size,full_size); if (log) std::cout << "We define blocks." << std::endl; result.setBlocks(sizes); if (log) std::cout << "We randomly set the diagonal as well as lower and upper diagonal blocks." << std::endl; for(int i = 0; i < sizes.size(); i++) { if (log) std::cout << "Diagonal block " << i << " is set." << std::endl; result.block(i, i) = MatrixXcd::Random(sizes[i],sizes[i]); if( i < sizes.size() - 1) { if (log) std::cout << "Upper diagonal block " << i << " is set." << std::endl; result.block(i + 1, i) = MatrixXcd::Random(sizes[i + 1], sizes[i]); if (log) std::cout << "Lower diagonal block " << i << " is set." << std::endl; result.block(i, i + 1) = MatrixXcd::Random(sizes[i], sizes[i + 1]); } } if (log) std::cout << "The matrix is added to its adjoint." << std::endl; result += result.adjoint().eval(); if (log) std::cout << "The matrix is finished." << std::endl; return result; }
/* The Variational Bayes Expectation step for each group. * * mutable: Group assignment probabilities, qZj * returns: The complete-data (X,Z) free energy E[log p(X,Z)/q(Z)] for group j. * throws: invalid_argument rethrown from other functions. */ template <class W, class C> double vbexpectation ( const MatrixXd& Xj, // Observations in group J const W& weights, // Group Weight parameter distribution const vector<C>& clusters, // Cluster parameter distributions MatrixXd& qZj, // Observations to group mixture assignments const bool sparse // Do sparse updates to groups ) { const int K = clusters.size(), Nj = Xj.rows(); // Get log marginal weight likelihoods const ArrayXd E_logZ = weights.Elogweight(); // Initialise and set K = 1 defaults for cluster counts ArrayXi Kful = ArrayXi::Zero(1), Kemp = ArrayXi::Zero(0); // Find empty clusters if sparse if ( (sparse == false) && (K > 1) ) Kful = ArrayXi::LinSpaced(Sequential, K, 0, K-1); else if (sparse == true) arrfind((weights.getNk() >= ZEROCUTOFF), Kful, Kemp); const int nKful = Kful.size(), nKemp = Kemp.size(); // Find Expectations of log joint observation probs -- allow sparse evaluation MatrixXd logqZj(Nj, nKful); for (int k = 0; k < nKful; ++k) logqZj.col(k) = E_logZ(Kful(k)) + clusters[Kful(k)].Eloglike(Xj).array(); // Log normalisation constant of log observation likelihoods const VectorXd logZzj = logsumexp(logqZj); // Make sure qZ is the right size, this is a nop if it is qZj.resize(Nj, K); // Normalise and Compute Responsibilities -- again allow sparse evaluation for (int k = 0; k < nKful; ++k) qZj.col(Kful(k)) = ((logqZj.col(k) - logZzj).array().exp()).matrix(); // Empty Cluster Responsabilities for (int k = 0; k < nKemp; ++k) qZj.col(Kemp(k)).setZero(); return -logZzj.sum(); }