210 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
| /**
 | |
|  * @file summarization.cpp
 | |
|  *
 | |
|  * @date Jun 22, 2012
 | |
|  * @author Alex Cunningham
 | |
|  */
 | |
| 
 | |
| #include <gtsam_unstable/linear/conditioning.h>
 | |
| #include <gtsam_unstable/linear/bayesTreeOperations.h>
 | |
| 
 | |
| #include <boost/assign/std/vector.hpp>
 | |
| 
 | |
| using namespace std;
 | |
| using namespace boost::assign;
 | |
| 
 | |
| namespace gtsam {
 | |
| 
 | |
| /* ************************************************************************* */
 | |
| GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shared_ptr& initConditional,
 | |
|     const std::set<Key>& saved_indices, const VectorValues& solution) {
 | |
|   const bool verbose = false;
 | |
| 
 | |
|   if (!initConditional)
 | |
|     return initConditional;
 | |
| 
 | |
|   if (verbose) {
 | |
|     cout << "backsubSummarize() Starting" << endl;
 | |
|     initConditional->print("Full initial conditional");
 | |
|   }
 | |
| 
 | |
|   // Check for presence of variables to remove
 | |
|   std::set<Key> frontalsToRemove, parentsToRemove;
 | |
|   BOOST_FOREACH(const Key& frontal, initConditional->frontals())
 | |
|     if (!saved_indices.count(frontal))
 | |
|       frontalsToRemove.insert(frontal);
 | |
| 
 | |
|   BOOST_FOREACH(const Key& parent, initConditional->parents())
 | |
|     if (!saved_indices.count(parent))
 | |
|       parentsToRemove.insert(parent);
 | |
| 
 | |
|   // If all variables in this conditional are to be saved, just return initial conditional
 | |
|   if (frontalsToRemove.empty() && parentsToRemove.empty())
 | |
|     return initConditional;
 | |
| 
 | |
|   // If none of the frontal variables are to be saved, return empty pointer
 | |
|   if (frontalsToRemove.size() == initConditional->nrFrontals())
 | |
|     return GaussianConditional::shared_ptr();
 | |
| 
 | |
|   // Collect dimensions of the new conditional
 | |
|   if (verbose) cout << "  Collecting dimensions" << endl;
 | |
|   size_t newTotalRows = 0, newTotalCols = 1; // Need spacing for RHS
 | |
|   size_t newNrFrontals = 0;
 | |
|   size_t oldOffset = 0;
 | |
|   vector<size_t> newDims, oldDims;
 | |
|   vector<size_t> oldColOffsets;
 | |
|   vector<Key> newIndices;
 | |
|   vector<size_t> newIdxToOldIdx; // Access to arrays, maps from new var to old var
 | |
|   const vector<Key>& oldIndices = initConditional->keys();
 | |
|   const size_t oldNrFrontals = initConditional->nrFrontals();
 | |
|   GaussianConditional::const_iterator varIt = initConditional->beginFrontals();
 | |
|   size_t oldIdx = 0;
 | |
|   for (; varIt != initConditional->endFrontals(); ++varIt) {
 | |
|     size_t varDim = initConditional->getDim(varIt);
 | |
|     oldDims += varDim;
 | |
|     if (!frontalsToRemove.count(*varIt)) {
 | |
|       newTotalCols += varDim;
 | |
|       newTotalRows += varDim;
 | |
|       newDims += varDim;
 | |
|       newIndices += *varIt;
 | |
|       ++newNrFrontals;
 | |
|       newIdxToOldIdx += oldIdx;
 | |
|       oldColOffsets += oldOffset;
 | |
|     }
 | |
|     oldOffset += varDim;
 | |
|     ++oldIdx;
 | |
|   }
 | |
|   varIt = initConditional->beginParents();
 | |
|   for (; varIt != initConditional->endParents(); ++varIt) {
 | |
|     size_t varDim = initConditional->getDim(varIt);
 | |
|     oldDims += varDim;
 | |
|     if (!parentsToRemove.count(*varIt)) {
 | |
|       newTotalCols += varDim;
 | |
|       newDims += varDim;
 | |
|       newIndices += *varIt;
 | |
|     }
 | |
|   }
 | |
|   newDims += 1; // For the RHS
 | |
| 
 | |
|   // Initialize new conditional
 | |
|   Matrix full_matrix = Matrix::Zero(newTotalRows, newTotalCols);
 | |
|   Vector sigmas = zero(newTotalRows);
 | |
|   if (verbose) cout << "  Initializing new conditional\nfull_matrix:\n" << full_matrix << endl;
 | |
| 
 | |
|   // Fill in full matrix - iterate over rows for each sub-conditional
 | |
|   const size_t oldRNrCols = initConditional->get_R().cols();
 | |
|   size_t newColOffset = 0;
 | |
|   for (size_t newfrontalIdx=0; newfrontalIdx<newNrFrontals; ++newfrontalIdx) {
 | |
|     const size_t& dim = newDims.at(newfrontalIdx);
 | |
|     if (verbose) cout << "     Filling in Matrix: newfrontalIdx " << newfrontalIdx
 | |
|         << " frontalKey: " << newIndices[newfrontalIdx] << " dim: " << dim << endl;
 | |
| 
 | |
|     size_t oldColOffset = oldColOffsets.at(newfrontalIdx);
 | |
| 
 | |
|     // get R block, sliced by row
 | |
|     Eigen::Block<GaussianConditional::constABlock> rblock =
 | |
|         initConditional->get_R().block(oldColOffset, oldColOffset, dim, oldRNrCols-oldColOffset);
 | |
|     if (verbose) cout << "   rblock\n" << rblock << endl;
 | |
| 
 | |
| 
 | |
|     // set the R matrix for this var
 | |
|     full_matrix.block(newColOffset, newColOffset, dim, dim) = rblock.leftCols(dim);
 | |
|     if (verbose) cout << "   full_matrix: set R\n" << full_matrix << endl;
 | |
| 
 | |
|     // set RHS
 | |
|     full_matrix.block(newColOffset, newTotalCols-1, dim, 1) = initConditional->get_d().segment(oldColOffset, dim);
 | |
|     if (verbose) cout << "   full_matrix: set rhs\n" << full_matrix << endl;
 | |
| 
 | |
|     // set sigmas
 | |
|     sigmas.segment(newColOffset, dim) = initConditional->get_model()->sigmas().segment(oldColOffset, dim);
 | |
| 
 | |
|     // add parents in R block, while updating rhs
 | |
|     // Loop through old variable list
 | |
|     size_t newParentStartCol = newColOffset + dim;
 | |
|     size_t oldParentStartCol = dim; // Copying from Rblock - offset already accounted for
 | |
|     for (size_t oldIdx = newIdxToOldIdx[newfrontalIdx]+1; oldIdx<oldNrFrontals; ++oldIdx) {
 | |
|       Key parentKey = oldIndices[oldIdx];
 | |
|       size_t parentDim = oldDims[oldIdx];
 | |
|       if (verbose) cout << "   Adding parents from R: parentKey: " << parentKey << " parentDim: " << parentDim << endl;
 | |
|       if (!frontalsToRemove.count(parentKey)) {
 | |
|         if (verbose) {
 | |
|           cout << "         Copying block (from): oldParentStartCol " << oldParentStartCol << endl;
 | |
|           cout << "         Copying block   (to): newColOffset " << newColOffset << ", newParentStartCol " << newParentStartCol << endl;
 | |
|         }
 | |
|         full_matrix.block(newColOffset, newParentStartCol, dim, parentDim)
 | |
|             = rblock.middleCols(oldParentStartCol, parentDim);
 | |
|         newParentStartCol += parentDim;
 | |
|         if (verbose) cout << "      full_matrix: add parent from R\n" << full_matrix << endl;
 | |
|       } else {
 | |
|         const Vector& parentSol = solution.at(parentKey);
 | |
|         full_matrix.block(newColOffset, newTotalCols-1, dim, 1) -=
 | |
|             rblock.middleCols(oldParentStartCol, parentDim) * parentSol;
 | |
|         if (verbose) cout << "      full_matrix: update rhs from parent in R\n" << full_matrix << endl;
 | |
|       }
 | |
|       oldParentStartCol += parentDim;
 | |
|     }
 | |
| 
 | |
|     // add parents (looping over original block structure), while updating rhs
 | |
|     GaussianConditional::const_iterator oldParent = initConditional->beginParents();
 | |
|     for (; oldParent != initConditional->endParents(); ++oldParent) {
 | |
|       Key parentKey = *oldParent;
 | |
|       size_t parentDim = initConditional->getDim(oldParent);
 | |
|       if (verbose) cout << "   Adding parents from S: parentKey: " << parentKey << " parentDim: " << parentDim << endl;
 | |
|       if (parentsToRemove.count(parentKey)) {
 | |
|         // Solve out the variable
 | |
|         const Vector& parentSol = solution.at(parentKey);
 | |
|         assert((size_t)parentSol.size() == parentDim);
 | |
|         full_matrix.block(newColOffset, newTotalCols-1, dim, 1) -=
 | |
|           initConditional->get_S(oldParent).middleRows(oldColOffset, dim) * parentSol;
 | |
|         if (verbose) cout << "      full_matrix: update rhs from parent in S\n" << full_matrix << endl;
 | |
|       } else {
 | |
|         // Copy the matrix block
 | |
|         full_matrix.block(newColOffset, newParentStartCol, dim, parentDim) =
 | |
|             initConditional->get_S(oldParent).middleRows(oldColOffset, dim);
 | |
|         if (verbose) cout << "      full_matrix: add parent from S\n" << full_matrix << endl;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Increment the rows
 | |
|     newColOffset += dim;
 | |
|     oldColOffset += dim;
 | |
|   }
 | |
| 
 | |
|   // Construct a new conditional
 | |
|   if (verbose) cout << "backsubSummarize() Complete!" << endl;
 | |
| //  GaussianConditional::rsd_type matrices(full_matrix, newDims.begin(), newDims.end());
 | |
|   VerticalBlockMatrix matrices(newDims, full_matrix);
 | |
|   return GaussianConditional::shared_ptr(new
 | |
|       GaussianConditional(newIndices, newNrFrontals, matrices, noiseModel::Diagonal::Sigmas(sigmas)));
 | |
| }
 | |
| 
 | |
| /* ************************************************************************* */
 | |
| GaussianFactorGraph conditionDensity(const GaussianBayesTree& bayesTree,
 | |
|     const std::set<Key>& saved_indices) {
 | |
|   const bool verbose = false;
 | |
| 
 | |
|   VectorValues solution = bayesTree.optimize();
 | |
| 
 | |
|   // FIXME: set of conditionals does not manage possibility of solving out whole separators
 | |
|   std::set<GaussianConditional::shared_ptr> affected_cliques = findAffectedCliqueConditionals(bayesTree, saved_indices);
 | |
| 
 | |
|   // Summarize conditionals separately
 | |
|   GaussianFactorGraph summarized_graph;
 | |
|   BOOST_FOREACH(const GaussianConditional::shared_ptr& conditional, affected_cliques) {
 | |
|     if (verbose) conditional->print("Initial conditional");
 | |
|     GaussianConditional::shared_ptr reducedConditional = conditionDensity(conditional, saved_indices, solution);
 | |
|     if (reducedConditional) {
 | |
|       if (verbose) reducedConditional->print("Final conditional");
 | |
|       summarized_graph.push_back(reducedConditional);
 | |
|     } else if (verbose) {
 | |
|       cout << "Conditional removed after summarization!" << endl;
 | |
|     }
 | |
|   }
 | |
|   return summarized_graph;
 | |
| }
 | |
| 
 | |
| /* ************************************************************************* */
 | |
| 
 | |
| } // \namespace gtsam
 | |
| 
 |