@@ -396,7 +396,7 @@ namespace test_two_state_estimation {
396
396
397
397
DiscreteKey m1 (M(1 ), 2);
398
398
399
- void addMeasurement (HybridBayesNet& hbn, Key z_key, Key x_key, double sigma) {
399
+ void addMeasurement (HybridBayesNet & hbn, Key z_key, Key x_key, double sigma) {
400
400
auto measurement_model = noiseModel::Isotropic::Sigma (1 , sigma);
401
401
hbn.emplace_shared <GaussianConditional>(z_key, Vector1 (0.0 ), I_1x1, x_key,
402
402
-I_1x1, measurement_model);
@@ -420,7 +420,7 @@ static HybridGaussianConditional::shared_ptr CreateHybridMotionModel(
420
420
421
421
// / Create two state Bayes network with 1 or two measurement models
422
422
HybridBayesNet CreateBayesNet (
423
- const HybridGaussianConditional::shared_ptr& hybridMotionModel,
423
+ const HybridGaussianConditional::shared_ptr & hybridMotionModel,
424
424
bool add_second_measurement = false ) {
425
425
HybridBayesNet hbn;
426
426
@@ -443,9 +443,9 @@ HybridBayesNet CreateBayesNet(
443
443
444
444
// / Approximate the discrete marginal P(m1) using importance sampling
445
445
std::pair<double , double > approximateDiscreteMarginal (
446
- const HybridBayesNet& hbn,
447
- const HybridGaussianConditional::shared_ptr& hybridMotionModel,
448
- const VectorValues& given, size_t N = 100000 ) {
446
+ const HybridBayesNet & hbn,
447
+ const HybridGaussianConditional::shared_ptr & hybridMotionModel,
448
+ const VectorValues & given, size_t N = 100000 ) {
449
449
// / Create importance sampling network q(x0,x1,m) = p(x1|x0,m1) q(x0) P(m1),
450
450
// / using q(x0) = N(z0, sigmaQ) to sample x0.
451
451
HybridBayesNet q;
@@ -741,6 +741,171 @@ TEST(HybridGaussianFactor, TwoStateModel4) {
741
741
EXPECT (assert_equal (expected, *(bn->at (2 )->asDiscrete ()), 0.002 ));
742
742
}
743
743
744
+ namespace test_direct_factor_graph {
745
+ /* *
746
+ * @brief Create a Factor Graph by directly specifying all
747
+ * the factors instead of creating conditionals first.
748
+ * This way we can directly provide the likelihoods and
749
+ * then perform linearization.
750
+ *
751
+ * @param values Initial values to linearize around.
752
+ * @param means The means of the HybridGaussianFactor components.
753
+ * @param sigmas The covariances of the HybridGaussianFactor components.
754
+ * @param m1 The discrete key.
755
+ * @return HybridGaussianFactorGraph
756
+ */
757
+ static HybridGaussianFactorGraph CreateFactorGraph (
758
+ const gtsam::Values &values, const std::vector<double > &means,
759
+ const std::vector<double > &sigmas, DiscreteKey &m1,
760
+ double measurement_noise = 1e-3 ) {
761
+ auto model0 = noiseModel::Isotropic::Sigma (1 , sigmas[0 ]);
762
+ auto model1 = noiseModel::Isotropic::Sigma (1 , sigmas[1 ]);
763
+ auto prior_noise = noiseModel::Isotropic::Sigma (1 , measurement_noise);
764
+
765
+ auto f0 =
766
+ std::make_shared<BetweenFactor<double >>(X (0 ), X (1 ), means[0 ], model0)
767
+ ->linearize (values);
768
+ auto f1 =
769
+ std::make_shared<BetweenFactor<double >>(X (0 ), X (1 ), means[1 ], model1)
770
+ ->linearize (values);
771
+
772
+ // Create HybridGaussianFactor
773
+ // We take negative since we want
774
+ // the underlying scalar to be log(\sqrt(|2πΣ|))
775
+ std::vector<GaussianFactorValuePair> factors{
776
+ {f0, -model0->logNormalizationConstant ()},
777
+ {f1, -model1->logNormalizationConstant ()}};
778
+ HybridGaussianFactor motionFactor ({X (0 ), X (1 )}, m1, factors);
779
+
780
+ HybridGaussianFactorGraph hfg;
781
+ hfg.push_back (motionFactor);
782
+
783
+ hfg.push_back (PriorFactor<double >(X (0 ), values.at <double >(X (0 )), prior_noise)
784
+ .linearize (values));
785
+
786
+ return hfg;
787
+ }
788
+ } // namespace test_direct_factor_graph
789
+
790
+ /* ************************************************************************* */
791
+ /* *
792
+ * @brief Test components with differing means but the same covariances.
793
+ * The factor graph is
794
+ * *-X1-*-X2
795
+ * |
796
+ * M1
797
+ */
798
+ TEST (HybridGaussianFactor, DifferentMeansFG) {
799
+ using namespace test_direct_factor_graph ;
800
+
801
+ DiscreteKey m1 (M (1 ), 2 );
802
+
803
+ Values values;
804
+ double x1 = 0.0 , x2 = 1.75 ;
805
+ values.insert (X (0 ), x1);
806
+ values.insert (X (1 ), x2);
807
+
808
+ std::vector<double > means = {0.0 , 2.0 }, sigmas = {1e-0 , 1e-0 };
809
+
810
+ HybridGaussianFactorGraph hfg = CreateFactorGraph (values, means, sigmas, m1);
811
+
812
+ {
813
+ auto bn = hfg.eliminateSequential ();
814
+ HybridValues actual = bn->optimize ();
815
+
816
+ HybridValues expected (
817
+ VectorValues{{X (0 ), Vector1 (0.0 )}, {X (1 ), Vector1 (-1.75 )}},
818
+ DiscreteValues{{M (1 ), 0 }});
819
+
820
+ EXPECT (assert_equal (expected, actual));
821
+
822
+ DiscreteValues dv0{{M (1 ), 0 }};
823
+ VectorValues cont0 = bn->optimize (dv0);
824
+ double error0 = bn->error (HybridValues (cont0, dv0));
825
+ // regression
826
+ EXPECT_DOUBLES_EQUAL (0.69314718056 , error0, 1e-9 );
827
+
828
+ DiscreteValues dv1{{M (1 ), 1 }};
829
+ VectorValues cont1 = bn->optimize (dv1);
830
+ double error1 = bn->error (HybridValues (cont1, dv1));
831
+ EXPECT_DOUBLES_EQUAL (error0, error1, 1e-9 );
832
+ }
833
+
834
+ {
835
+ auto prior_noise = noiseModel::Isotropic::Sigma (1 , 1e-3 );
836
+ hfg.push_back (
837
+ PriorFactor<double >(X (1 ), means[1 ], prior_noise).linearize (values));
838
+
839
+ auto bn = hfg.eliminateSequential ();
840
+ HybridValues actual = bn->optimize ();
841
+
842
+ HybridValues expected (
843
+ VectorValues{{X (0 ), Vector1 (0.0 )}, {X (1 ), Vector1 (0.25 )}},
844
+ DiscreteValues{{M (1 ), 1 }});
845
+
846
+ EXPECT (assert_equal (expected, actual));
847
+
848
+ {
849
+ DiscreteValues dv{{M (1 ), 0 }};
850
+ VectorValues cont = bn->optimize (dv);
851
+ double error = bn->error (HybridValues (cont, dv));
852
+ // regression
853
+ EXPECT_DOUBLES_EQUAL (2.12692448787 , error, 1e-9 );
854
+ }
855
+ {
856
+ DiscreteValues dv{{M (1 ), 1 }};
857
+ VectorValues cont = bn->optimize (dv);
858
+ double error = bn->error (HybridValues (cont, dv));
859
+ // regression
860
+ EXPECT_DOUBLES_EQUAL (0.126928487854 , error, 1e-9 );
861
+ }
862
+ }
863
+ }
864
+
865
+ /* ************************************************************************* */
866
+ /* *
867
+ * @brief Test components with differing covariances but the same means.
868
+ * The factor graph is
869
+ * *-X1-*-X2
870
+ * |
871
+ * M1
872
+ */
873
+ TEST (HybridGaussianFactor, DifferentCovariancesFG) {
874
+ using namespace test_direct_factor_graph ;
875
+
876
+ DiscreteKey m1 (M (1 ), 2 );
877
+
878
+ Values values;
879
+ double x1 = 1.0 , x2 = 1.0 ;
880
+ values.insert (X (0 ), x1);
881
+ values.insert (X (1 ), x2);
882
+
883
+ std::vector<double > means = {0.0 , 0.0 }, sigmas = {1e2 , 1e-2 };
884
+
885
+ // Create FG with HybridGaussianFactor and prior on X1
886
+ HybridGaussianFactorGraph fg = CreateFactorGraph (values, means, sigmas, m1);
887
+ auto hbn = fg.eliminateSequential ();
888
+
889
+ VectorValues cv;
890
+ cv.insert (X (0 ), Vector1 (0.0 ));
891
+ cv.insert (X (1 ), Vector1 (0.0 ));
892
+
893
+ // Check that the error values at the MLE point μ.
894
+ AlgebraicDecisionTree<Key> errorTree = hbn->errorTree (cv);
895
+
896
+ DiscreteValues dv0{{M (1 ), 0 }};
897
+ DiscreteValues dv1{{M (1 ), 1 }};
898
+
899
+ // regression
900
+ EXPECT_DOUBLES_EQUAL (9.90348755254 , errorTree (dv0), 1e-9 );
901
+ EXPECT_DOUBLES_EQUAL (0.69314718056 , errorTree (dv1), 1e-9 );
902
+
903
+ DiscreteConditional expected_m1 (m1, " 0.5/0.5" );
904
+ DiscreteConditional actual_m1 = *(hbn->at (2 )->asDiscrete ());
905
+
906
+ EXPECT (assert_equal (expected_m1, actual_m1));
907
+ }
908
+
744
909
/* ************************************************************************* */
745
910
int main () {
746
911
TestResult tr;
0 commit comments