1 #include <string>
2 #include <limits>
3 #include <iostream>
4 #include <cmath>
5 #include "testlib/testlib_test.h"
6 #include "vpdl/vpdl_gaussian_sphere.h"
7 #include "vnl/vnl_math.h" // for twopi
8 #ifdef _MSC_VER
9 #  include "vcl_msvc_warnings.h"
10 #endif
11 
12 template <class T>
13 void
test_gaussian_sphere_type(T epsilon,const std::string & type_name)14 test_gaussian_sphere_type(T epsilon, const std::string & type_name)
15 {
16   // test dimension, zero variance
17   {
18     vpdl_gaussian_sphere<T, 3> gauss3;
19     vpdl_gaussian_sphere<T, 1> gauss1;
20     vpdl_gaussian_sphere<T> gauss_default, gauss(3), gauss_init(vnl_vector<T>(10, T(1)), T(3));
21 
22     TEST(("dimension <" + type_name + "> fixed").c_str(), gauss3.dimension(), 3);
23     TEST(("dimension <" + type_name + "> scalar").c_str(), gauss1.dimension(), 1);
24     TEST(("dimension <" + type_name + "> variable").c_str(), gauss_default.dimension(), 0);
25     TEST(("dimension <" + type_name + "> variable").c_str(), gauss.dimension(), 3);
26     TEST(("dimension <" + type_name + "> variable").c_str(), gauss_init.dimension(), 10);
27 
28     TEST(("mean size <" + type_name + "> variable").c_str(), gauss_default.mean().size(), 0);
29     TEST(("mean size <" + type_name + "> variable").c_str(), gauss.mean().size(), 3);
30     TEST(("mean size <" + type_name + "> variable").c_str(), gauss_init.mean().size(), 10);
31 
32     // test initialization to zero mean, zero variance
33     vnl_vector_fixed<T, 3> zero_vector(T(0));
34     TEST(("zero default mean <" + type_name + "> fixed").c_str(), gauss3.mean(), zero_vector);
35     TEST(("zero default mean <" + type_name + "> scalar").c_str(), gauss1.mean(), T(0));
36     TEST(("zero default mean <" + type_name + "> variable").c_str(), gauss.mean(), zero_vector);
37 
38     TEST(("zero default variance <" + type_name + "> fixed").c_str(), gauss3.covariance(), T(0));
39     TEST(("zero default variance <" + type_name + "> scalar").c_str(), gauss1.covariance(), T(0));
40     TEST(("zero default variance <" + type_name + "> variable").c_str(), gauss.covariance(), T(0));
41 
42     // test zero variance evaluations
43     vnl_vector_fixed<T, 3> test_pt(T(1), T(1), T(1));
44     TEST(("zero var mahalanobis dist <" + type_name + "> fixed").c_str(),
45          gauss3.sqr_mahal_dist(test_pt),
46          std::numeric_limits<T>::infinity());
47     TEST(("zero var mahalanobis dist <" + type_name + "> scalar").c_str(),
48          gauss1.sqr_mahal_dist(test_pt[0]),
49          std::numeric_limits<T>::infinity());
50     TEST(("zero var mahalanobis dist <" + type_name + "> variable").c_str(),
51          gauss.sqr_mahal_dist(test_pt.as_ref()),
52          std::numeric_limits<T>::infinity());
53 
54     // test zero variance probability
55     TEST(("zero var probability density<" + type_name + "> fixed").c_str(), gauss3.prob_density(test_pt), T(0));
56     TEST(("zero var probability density<" + type_name + "> scalar").c_str(), gauss1.prob_density(test_pt[0]), T(0));
57     TEST(
58       ("zero var probability density<" + type_name + "> variable").c_str(), gauss.prob_density(test_pt.as_ref()), T(0));
59 
60     // test zero variance log probability
61     TEST(("zero var log probability density<" + type_name + "> fixed").c_str(),
62          gauss3.log_prob_density(test_pt),
63          -std::numeric_limits<T>::infinity());
64     TEST(("zero var log probability density<" + type_name + "> scalar").c_str(),
65          gauss1.log_prob_density(test_pt[0]),
66          -std::numeric_limits<T>::infinity());
67     TEST(("zero var log probability density<" + type_name + "> variable").c_str(),
68          gauss.log_prob_density(test_pt.as_ref()),
69          -std::numeric_limits<T>::infinity());
70   }
71 
72   // test mean, covariance, square malanobis distance, probability density,
73   // cumulative probability, box probability
74   {
75     vnl_vector_fixed<T, 3> mean(T(1.0), T(2.0), T(4.0));
76     T var = T(0.5);
77     vpdl_gaussian_sphere<T, 3> gauss3(mean, var);
78     vpdl_gaussian_sphere<T, 1> gauss1(mean[0], var);
79     vpdl_gaussian_sphere<T> gauss(mean.as_ref(), var);
80 
81     // test direct access to data member
82     TEST(("mean <" + type_name + "> fixed").c_str(), gauss3.mean(), mean);
83     TEST(("covar <" + type_name + "> fixed").c_str(), gauss3.covariance(), var);
84     TEST(("mean <" + type_name + "> scalar").c_str(), gauss1.mean(), mean[0]);
85     TEST(("covar <" + type_name + "> scalar").c_str(), gauss1.covariance(), var);
86     TEST(("mean <" + type_name + "> variable").c_str(), gauss.mean(), mean.as_ref());
87     TEST(("covar <" + type_name + "> variable").c_str(), gauss.covariance(), var);
88 
89     // test virtual functions
90     const vpdl_distribution<T, 3> & dist3 = gauss3;
91     const vpdl_distribution<T, 1> & dist1 = gauss1;
92     const vpdl_distribution<T> & dist = gauss;
93 
94     vnl_matrix_fixed<T, 3, 3> Strue;
95     Strue.fill(T(0)).fill_diagonal(var);
96 
97     // test indirect access to data members (compute full covariance)
98     vnl_vector_fixed<T, 3> m3;
99     dist3.compute_mean(m3);
100     TEST(("compute_mean <" + type_name + "> fixed").c_str(), m3, mean);
101 
102     vnl_matrix_fixed<T, 3, 3> S3;
103     dist3.compute_covar(S3);
104     TEST(("compute_covar <" + type_name + "> fixed").c_str(), S3, Strue);
105 
106     T m1;
107     dist1.compute_mean(m1);
108     TEST(("compute_mean <" + type_name + "> scalar").c_str(), m1, mean[0]);
109 
110     T v1;
111     dist1.compute_covar(v1);
112     TEST(("compute_covar <" + type_name + "> scalar").c_str(), v1, var);
113 
114     vnl_vector<T> m;
115     dist.compute_mean(m);
116     TEST(("compute_mean <" + type_name + "> variable").c_str(), m, mean.as_ref());
117 
118     vnl_matrix<T> S;
119     dist.compute_covar(S);
120     TEST(("compute_covar <" + type_name + "> variable").c_str(), S, Strue.as_ref());
121 
122     vnl_vector_fixed<T, 3> test_pt(T(1.5), T(3.0), T(3.0));
123     vnl_vector_fixed<T, 3> d = mean - test_pt;
124     T sqr_mahal_dist = d[0] * d[0] / var + d[1] * d[1] / var + d[2] * d[2] / var;
125 
126     // test mahalanobis distance calculations
127     TEST(("mahalanobis dist <" + type_name + "> fixed").c_str(), gauss3.sqr_mahal_dist(test_pt), sqr_mahal_dist);
128     TEST(("mahalanobis dist <" + type_name + "> scalar").c_str(), gauss1.sqr_mahal_dist(test_pt[0]), d[0] * d[0] / var);
129     TEST(("mahalanobis dist <" + type_name + "> variable").c_str(),
130          gauss.sqr_mahal_dist(test_pt.as_ref()),
131          sqr_mahal_dist);
132 
133     T two_pi_var = static_cast<T>(vnl_math::twopi * var);
134     T prob3 = static_cast<T>(1.0 / std::sqrt(two_pi_var * two_pi_var * two_pi_var) * std::exp(-sqr_mahal_dist / 2));
135     T prob1 = static_cast<T>(1.0 / std::sqrt(two_pi_var) * std::exp(-d[0] * d[0] / (2 * var)));
136 
137     // test probability density virtual functions
138     TEST_NEAR(("probability density <" + type_name + "> fixed").c_str(), dist3.prob_density(test_pt), prob3, epsilon);
139     TEST_NEAR(
140       ("probability density <" + type_name + "> scalar").c_str(), dist1.prob_density(test_pt[0]), prob1, epsilon);
141     TEST_NEAR(("probability density <" + type_name + "> variable").c_str(),
142               dist.prob_density(test_pt.as_ref()),
143               prob3,
144               epsilon);
145 
146     // test log probability density virtual functions
147     TEST_NEAR(("probability density <" + type_name + "> fixed").c_str(),
148               dist3.log_prob_density(test_pt),
149               std::log(prob3),
150               epsilon);
151     TEST_NEAR(("probability density <" + type_name + "> scalar").c_str(),
152               dist1.log_prob_density(test_pt[0]),
153               std::log(prob1),
154               epsilon);
155     TEST_NEAR(("probability density <" + type_name + "> variable").c_str(),
156               dist.log_prob_density(test_pt.as_ref()),
157               std::log(prob3),
158               epsilon);
159 
160     // test gradient virtual functions against numerical difference
161     vnl_vector_fixed<T, 3> g3;
162     T dp = std::sqrt(epsilon);
163     T den = dist3.density(test_pt);
164     T den_x = dist3.density(test_pt + vnl_vector_fixed<T, 3>(dp, 0, 0));
165     T den_y = dist3.density(test_pt + vnl_vector_fixed<T, 3>(0, dp, 0));
166     T den_z = dist3.density(test_pt + vnl_vector_fixed<T, 3>(0, 0, dp));
167     vnl_vector_fixed<T, 3> grad(den_x - den, den_y - den, den_z - den);
168     grad /= dp;
169     T density = dist3.gradient_density(test_pt, g3);
170     TEST_NEAR(("gradient density <" + type_name + "> fixed").c_str(), (g3 - grad).inf_norm(), 0, dp);
171     TEST_NEAR(("density <" + type_name + "> fixed").c_str(), density, den, epsilon);
172     density = dist1.gradient_density(test_pt[0], g3[0]);
173     T den1 = dist1.density(test_pt[0]);
174     T den1_x = dist1.density(test_pt[0] + dp);
175     TEST_NEAR(("gradient density <" + type_name + "> scalar").c_str(), g3[0], (den1_x - den1) / dp, dp);
176     TEST_NEAR(("density <" + type_name + "> scalar").c_str(), density, den1, epsilon);
177     vnl_vector<T> g;
178     density = dist.gradient_density(test_pt.as_ref(), g);
179     TEST_NEAR(("gradient density <" + type_name + "> variable").c_str(), (g - grad).inf_norm(), 0, dp);
180     TEST_NEAR(("density <" + type_name + "> variable").c_str(), density, den, epsilon);
181 
182     // test cumulative probability
183     vnl_vector_fixed<T, 3> test1(T(3), T(3), T(3));
184     vnl_vector_fixed<T, 3> cum_test1;
185     cum_test1[0] = T((1 + vnl_erf((test1[0] - mean[0]) / std::sqrt(2 * var))) / 2);
186     cum_test1[1] = T((1 + vnl_erf((test1[1] - mean[1]) / std::sqrt(2 * var))) / 2);
187     cum_test1[2] = T((1 + vnl_erf((test1[2] - mean[2]) / std::sqrt(2 * var))) / 2);
188     T joint_cum_test1 = cum_test1[0] * cum_test1[1] * cum_test1[2];
189     TEST(("cumulative probability 1 <" + type_name + "> fixed").c_str(), gauss3.cumulative_prob(mean), T(0.125));
190     TEST_NEAR(("cumulative probability 2 <" + type_name + "> fixed").c_str(),
191               gauss3.cumulative_prob(test1),
192               joint_cum_test1,
193               epsilon);
194     TEST(("cumulative probability 1 <" + type_name + "> scalar").c_str(), gauss1.cumulative_prob(mean[0]), T(0.5));
195     TEST_NEAR(("cumulative probability 2 <" + type_name + "> scalar").c_str(),
196               gauss1.cumulative_prob(test1[0]),
197               cum_test1[0],
198               epsilon);
199     TEST(("cumulative probability 1 <" + type_name + "> variable").c_str(),
200          gauss.cumulative_prob(mean.as_ref()),
201          T(0.125));
202     TEST_NEAR(("cumulative probability 2 <" + type_name + "> variable").c_str(),
203               gauss.cumulative_prob(test1.as_ref()),
204               joint_cum_test1,
205               epsilon);
206 
207     // test box probability
208     vnl_vector_fixed<T, 3> test2(T(-1), T(1), T(0));
209     vnl_vector_fixed<T, 3> cum_test2;
210     cum_test2[0] = T((1 + vnl_erf((test2[0] - mean[0]) / std::sqrt(2 * var))) / 2);
211     cum_test2[1] = T((1 + vnl_erf((test2[1] - mean[1]) / std::sqrt(2 * var))) / 2);
212     cum_test2[2] = T((1 + vnl_erf((test2[2] - mean[2]) / std::sqrt(2 * var))) / 2);
213     T box_test = (cum_test1[0] - cum_test2[0]) * (cum_test1[1] - cum_test2[1]) * (cum_test1[2] - cum_test2[2]);
214     TEST_NEAR(("box probability <" + type_name + "> fixed").c_str(), gauss3.box_prob(test2, test1), box_test, epsilon);
215     TEST_NEAR(("box probability <" + type_name + "> scalar").c_str(),
216               gauss1.box_prob(test2[0], test1[0]),
217               (cum_test1[0] - cum_test2[0]),
218               epsilon);
219     TEST_NEAR(("box probability <" + type_name + "> variable").c_str(),
220               gauss.box_prob(test2.as_ref(), test1.as_ref()),
221               box_test,
222               epsilon);
223 
224     vpdl_distribution<T> * base = &gauss; // pointer to the base class
225     TEST_NEAR(("box probability (base==derived) <" + type_name + ">").c_str(),
226               base->box_prob(test2.as_ref(), test1.as_ref()),
227               gauss.box_prob(test2.as_ref(), test1.as_ref()),
228               epsilon);
229 
230     // This is really a test of the base class box_prob function
231     // An even dimension can have a create a sign error not seen in an odd one
232     vnl_vector_fixed<T, 2> mean2(mean[0], mean[1]);
233     vpdl_gaussian_sphere<T, 2> gauss2(mean2, var);
234     vnl_vector_fixed<T, 2> test1_2(T(3), T(3)), test2_2(T(-1), T(1));
235     typedef vpdl_distribution<T, 2> base2;
236     TEST_NEAR(("box probability (base==derived) <" + type_name + "> even dim").c_str(),
237               gauss2.base2::box_prob(test2_2, test1_2),
238               gauss2.box_prob(test2_2, test1_2),
239               epsilon);
240   }
241 }
242 
243 
244 static void
test_gaussian_sphere()245 test_gaussian_sphere()
246 {
247   test_gaussian_sphere_type(1e-5f, "float");
248   test_gaussian_sphere_type(1e-14, "double");
249 }
250 
251 TESTMAIN(test_gaussian_sphere);
252