diff --git a/examples/UGM_chain.cpp b/examples/UGM_chain.cpp index e7f408cb0..56dbd4726 100644 --- a/examples/UGM_chain.cpp +++ b/examples/UGM_chain.cpp @@ -13,7 +13,7 @@ * @file small.cpp * @brief UGM (undirected graphical model) examples: chain * @author Frank Dellaert - * @author Abhijit + * @author Abhijit Kundu * * See http://www.di.ens.fr/~mschmidt/Software/UGM/chain.html * for more explanation. This code demos the same example using GTSAM. diff --git a/examples/UGM_small.cpp b/examples/UGM_small.cpp index 3c0e77e67..e9424d369 100644 --- a/examples/UGM_small.cpp +++ b/examples/UGM_small.cpp @@ -49,21 +49,17 @@ int main(int argc, char** argv) { // Print the UGM distribution cout << "\nUGM distribution:" << endl; - for (size_t a = 0; a < nrStates; a++) - for (size_t m = 0; m < nrStates; m++) - for (size_t h = 0; h < nrStates; h++) - for (size_t c = 0; c < nrStates; c++) { - DiscreteFactor::Values values; - values[1] = c; - values[2] = h; - values[3] = m; - values[4] = a; - double prodPot = graph(values); - cout << c << " " << h << " " << m << " " << a << " :\t" - << prodPot << "\t" << prodPot/3790 << endl; - } + vector allPosbValues = cartesianProduct( + Cathy & Heather & Mark & Allison); + for (size_t i = 0; i < allPosbValues.size(); ++i) { + DiscreteFactor::Values values = allPosbValues[i]; + double prodPot = graph(values); + cout << values[Cathy.first] << " " << values[Heather.first] << " " + << values[Mark.first] << " " << values[Allison.first] << " :\t" + << prodPot << "\t" << prodPot / 3790 << endl; + } - // "Decoding", i.e., configuration with largest value + // "Decoding", i.e., configuration with largest value (MPE) // We use sequential variable elimination DiscreteSequentialSolver solver(graph); DiscreteFactor::sharedValues optimalDecoding = solver.optimize(); diff --git a/gtsam/discrete/Assignment.h b/gtsam/discrete/Assignment.h index 2e84485dd..f6decc359 100644 --- a/gtsam/discrete/Assignment.h +++ b/gtsam/discrete/Assignment.h @@ -20,8 +20,10 @@ #include #include +#include #include + namespace gtsam { /** @@ -42,6 +44,44 @@ namespace gtsam { bool equals(const Assignment& other, double tol = 1e-9) const { return (*this == other); } - }; //Assignment + }; //Assignment + + + /** + * @brief Get Cartesian product consisting all possible configurations + * @param vector list of keys (label,cardinality) pairs. + * @return vector list of all possible value assignments + * + * This function returns a vector of Assignment values for all possible + * (Cartesian product) configurations of set of Keys which are nothing + * but (Label,cardinality) pairs. This function should NOT be called for + * more than a small number of variables and cardinalities. E.g. For 6 + * variables with each having cardinalities 4, we get 4096 possible + * configurations!! + */ + template + std::vector > cartesianProduct( + const std::vector >& keys) { + std::vector > allPossValues; + Assignment values; + typedef std::pair DiscreteKey; + BOOST_FOREACH(const DiscreteKey& key, keys) + values[key.first] = 0; //Initialize from 0 + while (1) { + allPossValues.push_back(values); + size_t j = 0; + for (j = 0; j < keys.size(); j++) { + L idx = keys[j].first; + values[idx]++; + if (values[idx] < keys[j].second) + break; + //Wrap condition + values[idx] = 0; + } + if (j == keys.size()) + break; + } + return allPossValues; + } } // namespace gtsam diff --git a/gtsam/discrete/DecisionTreeFactor.h b/gtsam/discrete/DecisionTreeFactor.h index a29a5683a..27c31fbb9 100644 --- a/gtsam/discrete/DecisionTreeFactor.h +++ b/gtsam/discrete/DecisionTreeFactor.h @@ -127,9 +127,16 @@ namespace gtsam { */ shared_ptr combine(size_t nrFrontals, ADT::Binary op) const; + /** + * @brief Permutes the keys in Potentials and DiscreteFactor + * + * This re-implements the permuteWithInverse() in both Potentials + * and DiscreteFactor by doing both of them together. + */ + void permuteWithInverse(const Permutation& inversePermutation){ DiscreteFactor::permuteWithInverse(inversePermutation); - Potentials::permute(inversePermutation); + Potentials::permuteWithInverse(inversePermutation); } /// @} diff --git a/gtsam/discrete/DiscreteConditional.cpp b/gtsam/discrete/DiscreteConditional.cpp index 34cf016ec..029873d2c 100644 --- a/gtsam/discrete/DiscreteConditional.cpp +++ b/gtsam/discrete/DiscreteConditional.cpp @@ -75,41 +75,38 @@ namespace gtsam { /* ******************************************************************************** */ void DiscreteConditional::solveInPlace(Values& values) const { +// OLD // assert(nrFrontals() == 1); // Index j = (firstFrontalKey()); // size_t mpe = solve(values); // Solve for variable // values[j] = mpe; // store result in partial solution +// OLD // TODO: is this really the fastest way? I think it is. + + //The following is to make make adjustment for nFrontals \neq 1 ADT pFS = choose(values); // P(F|S=parentsValues) // Initialize Values mpe; - Values frontalVals; - BOOST_FOREACH(Index j, frontals()) { - frontalVals[j] = 0; - } double maxP = 0; - while (1) { + DiscreteKeys keys; + BOOST_FOREACH(Index idx, frontals()) { + DiscreteKey dk(idx,cardinality(idx)); + keys & dk; + } + // Get all Possible Configurations + vector allPosbValues = cartesianProduct(keys); + + // Find the MPE + BOOST_FOREACH(Values& frontalVals, allPosbValues) { double pValueS = pFS(frontalVals); // P(F=value|S=parentsValues) // Update MPE solution if better if (pValueS > maxP) { maxP = pValueS; mpe = frontalVals; } - - size_t j = 0; - for (j = 0; j < nrFrontals(); j++) { - Index idx = frontals()[j]; - frontalVals[idx]++; - if (frontalVals[idx] < cardinality(idx)) - break; - //Wrap condition - frontalVals[idx] = 0; - } - if (j == nrFrontals()) - break; } //set values (inPlace) to mpe @@ -197,7 +194,7 @@ namespace gtsam { /* ******************************************************************************** */ void DiscreteConditional::permuteWithInverse(const Permutation& inversePermutation){ IndexConditional::permuteWithInverse(inversePermutation); - Potentials::permute(inversePermutation); + Potentials::permuteWithInverse(inversePermutation); } diff --git a/gtsam/discrete/Potentials.cpp b/gtsam/discrete/Potentials.cpp index e6f07ccac..b9a87dea9 100644 --- a/gtsam/discrete/Potentials.cpp +++ b/gtsam/discrete/Potentials.cpp @@ -60,7 +60,7 @@ namespace gtsam { } /* ************************************************************************* */ - void Potentials::permute(const Permutation& permutation) { + void Potentials::permuteWithInverse(const Permutation& permutation) { // Permute the _cardinalities (TODO: Inefficient Consider Improving) DiscreteKeys keys; map ordering; @@ -72,7 +72,6 @@ namespace gtsam { // Perform Permutation BOOST_FOREACH(DiscreteKey& key, keys) { ordering[key.first] = permutation[key.first]; - //cout << key.first << " -> " << ordering[key.first] << endl; key.first = ordering[key.first]; } diff --git a/gtsam/discrete/Potentials.h b/gtsam/discrete/Potentials.h index fe22288f4..367a323c2 100644 --- a/gtsam/discrete/Potentials.h +++ b/gtsam/discrete/Potentials.h @@ -73,8 +73,10 @@ namespace gtsam { * @brief Permutes the keys in Potentials * * This permutes the Indices and performs necessary re-ordering of ADD. + * This is virtual so that derived types e.g. DecisionTreeFactor can + * re-implement it. */ - void permute(const Permutation& perm); + virtual void permuteWithInverse(const Permutation& inversePermutation); }; // Potentials diff --git a/gtsam/discrete/tests/testDiscreteMarginals.cpp b/gtsam/discrete/tests/testDiscreteMarginals.cpp index ad35e131e..7f2b7b1b1 100644 --- a/gtsam/discrete/tests/testDiscreteMarginals.cpp +++ b/gtsam/discrete/tests/testDiscreteMarginals.cpp @@ -10,8 +10,8 @@ * -------------------------------------------------------------------------- */ /* - * @ file testDiscreteMarginals.cpp - * @date Feb 14, 2011 + * @file testDiscreteMarginals.cpp + * @date Jun 7, 2012 * @author Abhijit Kundu * @author Richard Roberts * @author Frank Dellaert