Skip to content

Commit 46f3a48

Browse files
committed
Merge branch 'develop' into release/4.2a5
2 parents 4a1ec24 + 3e65779 commit 46f3a48

24 files changed

+638
-140
lines changed

gtsam/base/FastSet.h

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
#pragma once
2020

21+
#if BOOST_VERSION >= 107400
22+
#include <boost/serialization/library_version_type.hpp>
23+
#endif
2124
#include <boost/serialization/nvp.hpp>
2225
#include <boost/serialization/set.hpp>
2326
#include <gtsam/base/FastDefaultAllocator.h>

gtsam/base/serialization.h

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <string>
2626

2727
// includes for standard serialization types
28+
#include <boost/serialization/version.hpp>
2829
#include <boost/serialization/optional.hpp>
2930
#include <boost/serialization/shared_ptr.hpp>
3031
#include <boost/serialization/vector.hpp>

gtsam/discrete/DiscreteConditional.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,13 @@ DecisionTreeFactor::shared_ptr DiscreteConditional::likelihood(
225225

226226
/* ****************************************************************************/
227227
DecisionTreeFactor::shared_ptr DiscreteConditional::likelihood(
228-
size_t parent_value) const {
228+
size_t frontal) const {
229229
if (nrFrontals() != 1)
230230
throw std::invalid_argument(
231231
"Single value likelihood can only be invoked on single-variable "
232232
"conditional");
233233
DiscreteValues values;
234-
values.emplace(keys_[0], parent_value);
234+
values.emplace(keys_[0], frontal);
235235
return likelihood(values);
236236
}
237237

gtsam/discrete/DiscreteConditional.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class GTSAM_EXPORT DiscreteConditional
177177
const DiscreteValues& frontalValues) const;
178178

179179
/** Single variable version of likelihood. */
180-
DecisionTreeFactor::shared_ptr likelihood(size_t parent_value) const;
180+
DecisionTreeFactor::shared_ptr likelihood(size_t frontal) const;
181181

182182
/**
183183
* sample

gtsam/discrete/tests/testDiscreteBayesNet.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ TEST(DiscreteBayesNet, Dot) {
150150
fragment.add((Either | Tuberculosis, LungCancer) = "F T T T");
151151

152152
string actual = fragment.dot();
153-
cout << actual << endl;
154153
EXPECT(actual ==
155154
"digraph {\n"
156155
" size=\"5,5\";\n"

gtsam/linear/GaussianBayesNet.cpp

+40-15
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
using namespace std;
2727
using namespace gtsam;
2828

29+
// In Wrappers we have no access to this so have a default ready
30+
static std::mt19937_64 kRandomNumberGenerator(42);
31+
2932
namespace gtsam {
3033

3134
// Instantiate base class
@@ -37,28 +40,50 @@ namespace gtsam {
3740
return Base::equals(bn, tol);
3841
}
3942

40-
/* ************************************************************************* */
41-
VectorValues GaussianBayesNet::optimize() const
42-
{
43-
VectorValues soln; // no missing variables -> just create an empty vector
44-
return optimize(soln);
43+
/* ************************************************************************ */
44+
VectorValues GaussianBayesNet::optimize() const {
45+
VectorValues solution; // no missing variables -> create an empty vector
46+
return optimize(solution);
4547
}
4648

47-
/* ************************************************************************* */
48-
VectorValues GaussianBayesNet::optimize(
49-
const VectorValues& solutionForMissing) const {
50-
VectorValues soln(solutionForMissing); // possibly empty
49+
VectorValues GaussianBayesNet::optimize(VectorValues solution) const {
5150
// (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas)
52-
/** solve each node in turn in topological sort order (parents first)*/
53-
for (auto cg: boost::adaptors::reverse(*this)) {
51+
// solve each node in reverse topological sort order (parents first)
52+
for (auto cg : boost::adaptors::reverse(*this)) {
5453
// i^th part of R*x=y, x=inv(R)*y
55-
// (Rii*xi + R_i*x(i+1:))./si = yi <-> xi = inv(Rii)*(yi.*si - R_i*x(i+1:))
56-
soln.insert(cg->solve(soln));
54+
// (Rii*xi + R_i*x(i+1:))./si = yi =>
55+
// xi = inv(Rii)*(yi.*si - R_i*x(i+1:))
56+
solution.insert(cg->solve(solution));
5757
}
58-
return soln;
58+
return solution;
5959
}
6060

61-
/* ************************************************************************* */
61+
/* ************************************************************************ */
62+
VectorValues GaussianBayesNet::sample(std::mt19937_64* rng) const {
63+
VectorValues result; // no missing variables -> create an empty vector
64+
return sample(result, rng);
65+
}
66+
67+
VectorValues GaussianBayesNet::sample(VectorValues result,
68+
std::mt19937_64* rng) const {
69+
// sample each node in reverse topological sort order (parents first)
70+
for (auto cg : boost::adaptors::reverse(*this)) {
71+
const VectorValues sampled = cg->sample(result, rng);
72+
result.insert(sampled);
73+
}
74+
return result;
75+
}
76+
77+
/* ************************************************************************ */
78+
VectorValues GaussianBayesNet::sample() const {
79+
return sample(&kRandomNumberGenerator);
80+
}
81+
82+
VectorValues GaussianBayesNet::sample(VectorValues given) const {
83+
return sample(given, &kRandomNumberGenerator);
84+
}
85+
86+
/* ************************************************************************ */
6287
VectorValues GaussianBayesNet::optimizeGradientSearch() const
6388
{
6489
gttic(GaussianBayesTree_optimizeGradientSearch);

gtsam/linear/GaussianBayesNet.h

+27-3
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,35 @@ namespace gtsam {
8888
/// @name Standard Interface
8989
/// @{
9090

91-
/// Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, by back-substitution
91+
/// Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, by
92+
/// back-substitution
9293
VectorValues optimize() const;
9394

94-
/// Version of optimize for incomplete BayesNet, needs solution for missing variables
95-
VectorValues optimize(const VectorValues& solutionForMissing) const;
95+
/// Version of optimize for incomplete BayesNet, given missing variables
96+
VectorValues optimize(const VectorValues given) const;
97+
98+
/**
99+
* Sample using ancestral sampling
100+
* Example:
101+
* std::mt19937_64 rng(42);
102+
* auto sample = gbn.sample(&rng);
103+
*/
104+
VectorValues sample(std::mt19937_64* rng) const;
105+
106+
/**
107+
* Sample from an incomplete BayesNet, given missing variables
108+
* Example:
109+
* std::mt19937_64 rng(42);
110+
* VectorValues given = ...;
111+
* auto sample = gbn.sample(given, &rng);
112+
*/
113+
VectorValues sample(VectorValues given, std::mt19937_64* rng) const;
114+
115+
/// Sample using ancestral sampling, use default rng
116+
VectorValues sample() const;
117+
118+
/// Sample from an incomplete BayesNet, use default rng
119+
VectorValues sample(VectorValues given) const;
96120

97121
/**
98122
* Return ordering corresponding to a topological sort.

gtsam/linear/GaussianConditional.cpp

+125-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <gtsam/linear/linearExceptions.h>
1919
#include <gtsam/linear/GaussianConditional.h>
2020
#include <gtsam/linear/VectorValues.h>
21+
#include <gtsam/linear/Sampler.h>
2122

2223
#include <boost/format.hpp>
2324
#ifdef __GNUC__
@@ -34,6 +35,9 @@
3435
#include <list>
3536
#include <string>
3637

38+
// In Wrappers we have no access to this so have a default ready
39+
static std::mt19937_64 kRandomNumberGenerator(42);
40+
3741
using namespace std;
3842

3943
namespace gtsam {
@@ -43,19 +47,47 @@ namespace gtsam {
4347
Key key, const Vector& d, const Matrix& R, const SharedDiagonal& sigmas) :
4448
BaseFactor(key, R, d, sigmas), BaseConditional(1) {}
4549

46-
/* ************************************************************************* */
47-
GaussianConditional::GaussianConditional(
48-
Key key, const Vector& d, const Matrix& R,
49-
Key name1, const Matrix& S, const SharedDiagonal& sigmas) :
50-
BaseFactor(key, R, name1, S, d, sigmas), BaseConditional(1) {}
50+
/* ************************************************************************ */
51+
GaussianConditional::GaussianConditional(Key key, const Vector& d,
52+
const Matrix& R, Key parent1,
53+
const Matrix& S,
54+
const SharedDiagonal& sigmas)
55+
: BaseFactor(key, R, parent1, S, d, sigmas), BaseConditional(1) {}
56+
57+
/* ************************************************************************ */
58+
GaussianConditional::GaussianConditional(Key key, const Vector& d,
59+
const Matrix& R, Key parent1,
60+
const Matrix& S, Key parent2,
61+
const Matrix& T,
62+
const SharedDiagonal& sigmas)
63+
: BaseFactor(key, R, parent1, S, parent2, T, d, sigmas),
64+
BaseConditional(1) {}
65+
66+
/* ************************************************************************ */
67+
GaussianConditional GaussianConditional::FromMeanAndStddev(
68+
Key key, const Matrix& A, Key parent, const Vector& b, double sigma) {
69+
// |Rx + Sy - d| = |x-(Ay + b)|/sigma
70+
const Matrix R = Matrix::Identity(b.size(), b.size());
71+
const Matrix S = -A;
72+
const Vector d = b;
73+
return GaussianConditional(key, d, R, parent, S,
74+
noiseModel::Isotropic::Sigma(b.size(), sigma));
75+
}
5176

52-
/* ************************************************************************* */
53-
GaussianConditional::GaussianConditional(
54-
Key key, const Vector& d, const Matrix& R,
55-
Key name1, const Matrix& S, Key name2, const Matrix& T, const SharedDiagonal& sigmas) :
56-
BaseFactor(key, R, name1, S, name2, T, d, sigmas), BaseConditional(1) {}
77+
/* ************************************************************************ */
78+
GaussianConditional GaussianConditional::FromMeanAndStddev(
79+
Key key, const Matrix& A1, Key parent1, const Matrix& A2, Key parent2,
80+
const Vector& b, double sigma) {
81+
// |Rx + Sy + Tz - d| = |x-(A1 y + A2 z + b)|/sigma
82+
const Matrix R = Matrix::Identity(b.size(), b.size());
83+
const Matrix S = -A1;
84+
const Matrix T = -A2;
85+
const Vector d = b;
86+
return GaussianConditional(key, d, R, parent1, S, parent2, T,
87+
noiseModel::Isotropic::Sigma(b.size(), sigma));
88+
}
5789

58-
/* ************************************************************************* */
90+
/* ************************************************************************ */
5991
void GaussianConditional::print(const string &s, const KeyFormatter& formatter) const {
6092
cout << s << " Conditional density ";
6193
for (const_iterator it = beginFrontals(); it != endFrontals(); ++it) {
@@ -192,7 +224,88 @@ namespace gtsam {
192224
}
193225
}
194226

195-
/* ************************************************************************* */
227+
/* ************************************************************************ */
228+
JacobianFactor::shared_ptr GaussianConditional::likelihood(
229+
const VectorValues& frontalValues) const {
230+
// Error is |Rx - (d - Sy - Tz - ...)|^2
231+
// so when we instantiate x (which has to be completely known) we beget:
232+
// |Sy + Tz + ... - (d - Rx)|^2
233+
// The noise model just transfers over!
234+
235+
// Get frontalValues as vector
236+
const Vector x =
237+
frontalValues.vector(KeyVector(beginFrontals(), endFrontals()));
238+
239+
// Copy the augmented Jacobian matrix:
240+
auto newAb = Ab_;
241+
242+
// Restrict view to parent blocks
243+
newAb.firstBlock() += nrFrontals_;
244+
245+
// Update right-hand-side (last column)
246+
auto last = newAb.matrix().cols() - 1;
247+
const auto RR = R().triangularView<Eigen::Upper>();
248+
newAb.matrix().col(last) -= RR * x;
249+
250+
// The keys now do not include the frontal keys:
251+
KeyVector newKeys;
252+
newKeys.reserve(nrParents());
253+
for (auto&& key : parents()) newKeys.push_back(key);
254+
255+
// Hopefully second newAb copy below is optimized out...
256+
return boost::make_shared<JacobianFactor>(newKeys, newAb, model_);
257+
}
258+
259+
/* **************************************************************************/
260+
JacobianFactor::shared_ptr GaussianConditional::likelihood(
261+
const Vector& frontal) const {
262+
if (nrFrontals() != 1)
263+
throw std::invalid_argument(
264+
"GaussianConditional Single value likelihood can only be invoked on "
265+
"single-variable conditional");
266+
VectorValues values;
267+
values.insert(keys_[0], frontal);
268+
return likelihood(values);
269+
}
270+
271+
/* ************************************************************************ */
272+
VectorValues GaussianConditional::sample(const VectorValues& parentsValues,
273+
std::mt19937_64* rng) const {
274+
if (nrFrontals() != 1) {
275+
throw std::invalid_argument(
276+
"GaussianConditional::sample can only be called on single variable "
277+
"conditionals");
278+
}
279+
if (!model_) {
280+
throw std::invalid_argument(
281+
"GaussianConditional::sample can only be called if a diagonal noise "
282+
"model was specified at construction.");
283+
}
284+
VectorValues solution = solve(parentsValues);
285+
Key key = firstFrontalKey();
286+
const Vector& sigmas = model_->sigmas();
287+
solution[key] += Sampler::sampleDiagonal(sigmas, rng);
288+
return solution;
289+
}
290+
291+
VectorValues GaussianConditional::sample(std::mt19937_64* rng) const {
292+
if (nrParents() != 0)
293+
throw std::invalid_argument(
294+
"sample() can only be invoked on no-parent prior");
295+
VectorValues values;
296+
return sample(values);
297+
}
298+
299+
/* ************************************************************************ */
300+
VectorValues GaussianConditional::sample() const {
301+
return sample(&kRandomNumberGenerator);
302+
}
303+
304+
VectorValues GaussianConditional::sample(const VectorValues& given) const {
305+
return sample(given, &kRandomNumberGenerator);
306+
}
307+
308+
/* ************************************************************************ */
196309
#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42
197310
void GTSAM_DEPRECATED
198311
GaussianConditional::scaleFrontalsBySigma(VectorValues& gy) const {

0 commit comments

Comments
 (0)