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