1 /*
2 * (C) Copyright Nick Thompson 2018.
3 * Use, modification and distribution are subject to the
4 * Boost Software License, Version 1.0. (See accompanying file
5 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 */
7 #include <cmath>
8 #include <vector>
9 #include <array>
10 #include <forward_list>
11 #include <algorithm>
12 #include <random>
13 #include <limits>
14 #include <boost/core/lightweight_test.hpp>
15 #include <boost/numeric/ublas/vector.hpp>
16 #include <boost/math/constants/constants.hpp>
17 #include <boost/math/tools/norms.hpp>
18 #include <boost/multiprecision/cpp_bin_float.hpp>
19 #include <boost/multiprecision/cpp_complex.hpp>
20
21 using std::abs;
22 using std::pow;
23 using std::sqrt;
24 using boost::multiprecision::cpp_bin_float_50;
25 using boost::multiprecision::cpp_complex_50;
26 using boost::math::tools::lp_norm;
27 using boost::math::tools::l1_norm;
28 using boost::math::tools::l2_norm;
29 using boost::math::tools::sup_norm;
30 using boost::math::tools::lp_distance;
31 using boost::math::tools::l1_distance;
32 using boost::math::tools::l2_distance;
33 using boost::math::tools::sup_distance;
34 using boost::math::tools::total_variation;
35
36 /*
37 * Test checklist:
38 * 1) Does it work with multiprecision?
39 * 2) Does it work with .cbegin()/.cend() if the data is not altered?
40 * 3) Does it work with ublas and std::array? (Checking Eigen and Armadillo will make the CI system really unhappy.)
41 * 4) Does it work with std::forward_list if a forward iterator is all that is required?
42 * 5) Does it work with complex data if complex data is sensible?
43 */
44
45 // To stress test, set global_seed = 0, global_size = huge.
46 static const constexpr size_t global_seed = 834;
47 static const constexpr size_t global_size = 64;
48
49 template<class T>
generate_random_vector(size_t size,size_t seed)50 std::vector<T> generate_random_vector(size_t size, size_t seed)
51 {
52 if (seed == 0)
53 {
54 std::random_device rd;
55 seed = rd();
56 }
57 std::vector<T> v(size);
58
59 std::mt19937 gen(seed);
60
61 if constexpr (std::is_floating_point<T>::value)
62 {
63 std::normal_distribution<T> dis(0, 1);
64 for (size_t i = 0; i < v.size(); ++i)
65 {
66 v[i] = dis(gen);
67 }
68 return v;
69 }
70 else if constexpr (std::is_integral<T>::value)
71 {
72 // Rescaling by larger than 2 is UB!
73 std::uniform_int_distribution<T> dis(std::numeric_limits<T>::lowest()/2, (std::numeric_limits<T>::max)()/2);
74 for (size_t i = 0; i < v.size(); ++i)
75 {
76 v[i] = dis(gen);
77 }
78 return v;
79 }
80 else if constexpr (boost::is_complex<T>::value)
81 {
82 std::normal_distribution<typename T::value_type> dis(0, 1);
83 for (size_t i = 0; i < v.size(); ++i)
84 {
85 v[i] = {dis(gen), dis(gen)};
86 }
87 return v;
88 }
89 else if constexpr (boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_complex)
90 {
91 std::normal_distribution<long double> dis(0, 1);
92 for (size_t i = 0; i < v.size(); ++i)
93 {
94 v[i] = {dis(gen), dis(gen)};
95 }
96 return v;
97 }
98 else if constexpr (boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_floating_point)
99 {
100 std::normal_distribution<long double> dis(0, 1);
101 for (size_t i = 0; i < v.size(); ++i)
102 {
103 v[i] = dis(gen);
104 }
105 return v;
106 }
107 else
108 {
109 BOOST_ASSERT_MSG(false, "Could not identify type for random vector generation.");
110 return v;
111 }
112 }
113
114
115 template<class Real>
test_lp()116 void test_lp()
117 {
118 Real tol = 50*std::numeric_limits<Real>::epsilon();
119
120 std::array<Real, 3> u{1,0,0};
121 Real l3 = lp_norm(u.begin(), u.end(), 3);
122 BOOST_TEST(abs(l3 - 1) < tol);
123
124 u[0] = -8;
125 l3 = lp_norm(u.cbegin(), u.cend(), 3);
126 BOOST_TEST(abs(l3 - 8) < tol);
127
128 std::vector<Real> v(500);
129 for (size_t i = 0; i < v.size(); ++i) {
130 v[i] = 7;
131 }
132 Real l8 = lp_norm(v, 8);
133 Real expected = 7*pow(v.size(), static_cast<Real>(1)/static_cast<Real>(8));
134 BOOST_TEST(abs(l8 - expected) < tol*abs(expected));
135
136 // Does it work with ublas vectors?
137 // Does it handle the overflow of intermediates?
138 boost::numeric::ublas::vector<Real> w(4);
139 Real bignum = sqrt((std::numeric_limits<Real>::max)())/256;
140 for (size_t i = 0; i < w.size(); ++i)
141 {
142 w[i] = bignum;
143 }
144 Real l20 = lp_norm(w.cbegin(), w.cend(), 4);
145 expected = bignum*pow(w.size(), static_cast<Real>(1)/static_cast<Real>(4));
146 BOOST_TEST(abs(l20 - expected) < tol*expected);
147
148 v = generate_random_vector<Real>(global_size, global_seed);
149 Real scale = 8;
150 Real l7 = scale*lp_norm(v, 7);
151 for (auto & x : v)
152 {
153 x *= -scale;
154 }
155 Real l7_ = lp_norm(v, 7);
156 BOOST_TEST(abs(l7_ - l7) < tol*l7);
157 }
158
159
160 template<class Complex>
test_complex_lp()161 void test_complex_lp()
162 {
163 typedef typename Complex::value_type Real;
164 Real tol = 50*std::numeric_limits<Real>::epsilon();
165 std::vector<Complex> v{{1,0}, {0,0}, {0,0}};
166 Real l3 = lp_norm(v.cbegin(), v.cend(), 3);
167 BOOST_TEST(abs(l3 - 1) < tol);
168
169 l3 = lp_norm(v, 3);
170 BOOST_TEST(abs(l3 - 1) < tol);
171
172 v = generate_random_vector<Complex>(global_size, global_seed);
173 Real scale = 8;
174 Real l7 = scale*lp_norm(v, 7);
175 for (auto & x : v)
176 {
177 x *= -scale;
178 }
179 Real l7_ = lp_norm(v, 7);
180 BOOST_TEST(abs(l7_ - l7) < tol*l7);
181 }
182
183 template<class Z>
test_integer_lp()184 void test_integer_lp()
185 {
186 double tol = 100*std::numeric_limits<double>::epsilon();
187
188 std::array<Z, 3> u{1,0,0};
189 double l3 = lp_norm(u.begin(), u.end(), 3);
190 BOOST_TEST(abs(l3 - 1) < tol);
191
192 auto v = generate_random_vector<Z>(global_size, global_seed);
193 Z scale = 2;
194 double l7 = scale*lp_norm(v, 7);
195 for (auto & x : v)
196 {
197 x *= scale;
198 }
199 double l7_ = lp_norm(v, 7);
200 BOOST_TEST(abs(l7_ - l7) < tol*l7);
201 }
202
203 template<class Real>
test_lp_distance()204 void test_lp_distance()
205 {
206 Real tol = 100*std::numeric_limits<Real>::epsilon();
207
208 std::vector<Real> u{1,0,0};
209 std::vector<Real> v{0,0,0};
210
211 Real dist = lp_distance(u,u, 3);
212 BOOST_TEST(abs(dist) < tol);
213
214 dist = lp_distance(u,v, 3);
215 BOOST_TEST(abs(dist - 1) < tol);
216
217 v = generate_random_vector<Real>(global_size, global_seed);
218 u = generate_random_vector<Real>(global_size, global_seed+1);
219 Real dist1 = lp_distance(u, v, 7);
220 Real dist2 = lp_distance(v, u, 7);
221
222 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
223 }
224
225 template<class Complex>
test_complex_lp_distance()226 void test_complex_lp_distance()
227 {
228 using Real = typename Complex::value_type;
229 Real tol = 100*std::numeric_limits<Real>::epsilon();
230
231 std::vector<Complex> u{{1,0},{0,0},{0,0}};
232 std::vector<Complex> v{{0,0},{0,0},{0,0}};
233
234 Real dist = boost::math::tools::lp_distance(u,u, 3);
235 BOOST_TEST(abs(dist) < tol);
236
237 dist = boost::math::tools::lp_distance(u,v, 3);
238 BOOST_TEST(abs(dist - 1) < tol);
239
240 v = generate_random_vector<Complex>(global_size, global_seed);
241 u = generate_random_vector<Complex>(global_size, global_seed + 1);
242 Real dist1 = lp_distance(u, v, 7);
243 Real dist2 = lp_distance(v, u, 7);
244
245 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
246 }
247
248 template<class Z>
test_integer_lp_distance()249 void test_integer_lp_distance()
250 {
251 double tol = 100*std::numeric_limits<double>::epsilon();
252
253 std::array<Z, 3> u{1,0,0};
254 std::array<Z, 3> w{0,0,0};
255 double l3 = lp_distance(u, w, 3);
256 BOOST_TEST(abs(l3 - 1) < tol);
257
258 auto v = generate_random_vector<Z>(global_size, global_seed);
259 Z scale = 2;
260 for (auto & x : v)
261 {
262 x *= scale;
263 }
264 auto s = generate_random_vector<Z>(global_size, global_seed + 1);
265 double dist1 = lp_distance(v, s, 7);
266 double dist2 = lp_distance(s, v, 7);
267 BOOST_TEST(abs(dist1 - dist2) < tol*dist2);
268 }
269
270
271 template<class Z>
test_integer_total_variation()272 void test_integer_total_variation()
273 {
274 double eps = std::numeric_limits<double>::epsilon();
275 std::vector<Z> v{1,1};
276 double tv = boost::math::tools::total_variation(v);
277 BOOST_TEST_EQ(tv, 0);
278
279 v[1] = 2;
280 tv = boost::math::tools::total_variation(v.begin(), v.end());
281 BOOST_TEST_EQ(tv, 1);
282
283 v.resize(16);
284 for (size_t i = 0; i < v.size(); ++i) {
285 v[i] = i;
286 }
287
288 tv = boost::math::tools::total_variation(v);
289 BOOST_TEST_EQ(tv, v.size() -1);
290
291 for (size_t i = 0; i < v.size(); ++i)
292 {
293 v[i] = i*i;
294 }
295
296 tv = boost::math::tools::total_variation(v);
297 BOOST_TEST_EQ(tv, (v.size() - 1)*(v.size() - 1));
298
299 // Work with std::array?
300 std::array<Z, 2> w{1,1};
301 tv = boost::math::tools::total_variation(w);
302 BOOST_TEST_EQ(tv,0);
303
304 std::array<Z, 4> u{1, 2, 1, 2};
305 tv = boost::math::tools::total_variation(u);
306 BOOST_TEST_EQ(tv, 3);
307
308 v = generate_random_vector<Z>(global_size, global_seed);
309 double tv1 = 2*total_variation(v);
310 Z scale = 2;
311 for (auto & x : v)
312 {
313 x *= scale;
314 }
315 double tv2 = total_variation(v);
316 BOOST_TEST(abs(tv1 - tv2) < tv1*eps);
317 }
318
319 template<class Real>
test_total_variation()320 void test_total_variation()
321 {
322 Real tol = std::numeric_limits<Real>::epsilon();
323 std::vector<Real> v{1,1};
324 Real tv = total_variation(v.begin(), v.end());
325 BOOST_TEST(tv >= 0 && abs(tv) < tol);
326
327 tv = total_variation(v);
328 BOOST_TEST(tv >= 0 && abs(tv) < tol);
329
330 v[1] = 2;
331 tv = total_variation(v.begin(), v.end());
332 BOOST_TEST(abs(tv - 1) < tol);
333
334 v.resize(50);
335 for (size_t i = 0; i < v.size(); ++i) {
336 v[i] = i;
337 }
338
339 tv = total_variation(v.begin(), v.end());
340 BOOST_TEST(abs(tv - (v.size() -1)) < tol);
341
342 for (size_t i = 0; i < v.size(); ++i) {
343 v[i] = i*i;
344 }
345
346 tv = total_variation(v.begin(), v.end());
347 BOOST_TEST(abs(tv - (v.size() - 1)*(v.size() - 1)) < tol);
348
349
350 v = generate_random_vector<Real>(global_size, global_seed);
351 Real scale = 8;
352 Real tv1 = scale*total_variation(v);
353 for (auto & x : v)
354 {
355 x *= -scale;
356 }
357 Real tv2 = total_variation(v);
358 BOOST_TEST(abs(tv1 - tv2) < tol*tv1);
359 }
360
361 template<class Real>
test_sup_norm()362 void test_sup_norm()
363 {
364 Real tol = std::numeric_limits<Real>::epsilon();
365 std::vector<Real> v{-2,1,0};
366 Real s = boost::math::tools::sup_norm(v.begin(), v.end());
367 BOOST_TEST(abs(s - 2) < tol);
368
369 s = boost::math::tools::sup_norm(v);
370 BOOST_TEST(abs(s - 2) < tol);
371
372 // Work with std::array?
373 std::array<Real, 3> w{-2,1,0};
374 s = boost::math::tools::sup_norm(w);
375 BOOST_TEST(abs(s - 2) < tol);
376
377 v = generate_random_vector<Real>(global_size, global_seed);
378 Real scale = 8;
379 Real sup1 = scale*sup_norm(v);
380 for (auto & x : v)
381 {
382 x *= -scale;
383 }
384 Real sup2 = sup_norm(v);
385 BOOST_TEST(abs(sup1 - sup2) < tol*sup1);
386 }
387
388 template<class Z>
test_integer_sup_norm()389 void test_integer_sup_norm()
390 {
391 double eps = std::numeric_limits<double>::epsilon();
392 std::vector<Z> v{2,1,0};
393 Z s = sup_norm(v.begin(), v.end());
394 BOOST_TEST_EQ(s, 2);
395
396 s = sup_norm(v);
397 BOOST_TEST_EQ(s,2);
398
399 v = generate_random_vector<Z>(global_size, global_seed);
400 double sup1 = 2*sup_norm(v);
401 Z scale = 2;
402 for (auto & x : v)
403 {
404 x *= scale;
405 }
406 double sup2 = sup_norm(v);
407 BOOST_TEST(abs(sup1 - sup2) < sup1*eps);
408 }
409
410 template<class Complex>
test_complex_sup_norm()411 void test_complex_sup_norm()
412 {
413 typedef typename Complex::value_type Real;
414 Real tol = std::numeric_limits<Real>::epsilon();
415 std::vector<Complex> w{{0,-8}, {1,1}, {3,2}};
416 Real s = sup_norm(w.cbegin(), w.cend());
417 BOOST_TEST(abs(s-8) < tol);
418
419 s = sup_norm(w);
420 BOOST_TEST(abs(s-8) < tol);
421
422 auto v = generate_random_vector<Complex>(global_size, global_seed);
423 Real scale = 8;
424 Real sup1 = scale*sup_norm(v);
425 for (auto & x : v)
426 {
427 x *= -scale;
428 }
429 Real sup2 = sup_norm(v);
430 BOOST_TEST(abs(sup1 - sup2) < tol*sup1);
431 }
432
433 template<class Real>
test_l0_pseudo_norm()434 void test_l0_pseudo_norm()
435 {
436 std::vector<Real> v{0,0,1};
437 size_t count = boost::math::tools::l0_pseudo_norm(v.begin(), v.end());
438 BOOST_TEST_EQ(count, 1);
439
440 // Compiles with cbegin()/cend()?
441 count = boost::math::tools::l0_pseudo_norm(v.cbegin(), v.cend());
442 BOOST_TEST_EQ(count, 1);
443
444 count = boost::math::tools::l0_pseudo_norm(v);
445 BOOST_TEST_EQ(count, 1);
446
447 std::array<Real, 3> w{0,0,1};
448 count = boost::math::tools::l0_pseudo_norm(w);
449 BOOST_TEST_EQ(count, 1);
450 }
451
452 template<class Complex>
test_complex_l0_pseudo_norm()453 void test_complex_l0_pseudo_norm()
454 {
455 std::vector<Complex> v{{0,0}, {0,0}, {1,0}};
456 size_t count = boost::math::tools::l0_pseudo_norm(v.begin(), v.end());
457 BOOST_TEST_EQ(count, 1);
458
459 count = boost::math::tools::l0_pseudo_norm(v);
460 BOOST_TEST_EQ(count, 1);
461 }
462
463 template<class Z>
test_hamming_distance()464 void test_hamming_distance()
465 {
466 std::vector<Z> v{1,2,3};
467 std::vector<Z> w{1,2,4};
468 size_t count = boost::math::tools::hamming_distance(v, w);
469 BOOST_TEST_EQ(count, 1);
470
471 count = boost::math::tools::hamming_distance(v, v);
472 BOOST_TEST_EQ(count, 0);
473 }
474
475 template<class Real>
test_l1_norm()476 void test_l1_norm()
477 {
478 Real tol = std::numeric_limits<Real>::epsilon();
479 std::vector<Real> v{1,1,1};
480 Real l1 = l1_norm(v.begin(), v.end());
481 BOOST_TEST(abs(l1 - 3) < tol);
482
483 l1 = l1_norm(v);
484 BOOST_TEST(abs(l1 - 3) < tol);
485
486 std::array<Real, 3> w{1,1,1};
487 l1 = l1_norm(w);
488 BOOST_TEST(abs(l1 - 3) < tol);
489
490 v = generate_random_vector<Real>(global_size, global_seed);
491 Real scale = 8;
492 Real l1_1 = scale*l1_norm(v);
493 for (auto & x : v)
494 {
495 x *= -scale;
496 }
497 Real l1_2 = l1_norm(v);
498 BOOST_TEST(abs(l1_1 - l1_2) < tol*l1_1);
499 }
500
501 template<class Z>
test_integer_l1_norm()502 void test_integer_l1_norm()
503 {
504 double eps = std::numeric_limits<double>::epsilon();
505 std::vector<Z> v{1,1,1};
506 Z l1 = boost::math::tools::l1_norm(v.begin(), v.end());
507 BOOST_TEST_EQ(l1, 3);
508
509 v = generate_random_vector<Z>(global_size, global_seed);
510 double l1_1 = 2*l1_norm(v);
511 Z scale = 2;
512 for (auto & x : v)
513 {
514 x *= scale;
515 }
516 double l1_2 = l1_norm(v);
517 BOOST_TEST(l1_1 > 0);
518 BOOST_TEST(l1_2 > 0);
519 if (abs(l1_1 - l1_2) > 2*l1_1*eps)
520 {
521 std::cout << std::setprecision(std::numeric_limits<double>::digits10);
522 std::cout << "L1_1 = " << l1_1 << "\n";
523 std::cout << "L1_2 = " << l1_2 << "\n";
524 BOOST_TEST(abs(l1_1 - l1_2) < 2*l1_1*eps);
525 }
526 }
527
528 template<class Complex>
test_complex_l1_norm()529 void test_complex_l1_norm()
530 {
531 typedef typename Complex::value_type Real;
532 Real tol = std::numeric_limits<Real>::epsilon();
533 std::vector<Complex> v{{1,0}, {0,1},{0,-1}};
534 Real l1 = l1_norm(v.begin(), v.end());
535 BOOST_TEST(abs(l1 - 3) < tol);
536
537 l1 = l1_norm(v);
538 BOOST_TEST(abs(l1 - 3) < tol);
539
540 v = generate_random_vector<Complex>(global_size, global_seed);
541 Real scale = 8;
542 Real l1_1 = scale*l1_norm(v);
543 for (auto & x : v)
544 {
545 x *= -scale;
546 }
547 Real l1_2 = l1_norm(v);
548 BOOST_TEST(abs(l1_1 - l1_2) < tol*l1_1);
549 }
550
551 template<class Real>
test_l1_distance()552 void test_l1_distance()
553 {
554 Real tol = std::numeric_limits<Real>::epsilon();
555 std::vector<Real> v{1,2,3};
556 std::vector<Real> w{1,1,1};
557 Real l1 = boost::math::tools::l1_distance(v, v);
558 BOOST_TEST(abs(l1) < tol);
559
560 l1 = boost::math::tools::l1_distance(w, v);
561 BOOST_TEST(abs(l1 - 3) < tol);
562
563 l1 = boost::math::tools::l1_distance(v, w);
564 BOOST_TEST(abs(l1 - 3) < tol);
565
566 v = generate_random_vector<Real>(global_size, global_seed);
567 w = generate_random_vector<Real>(global_size, global_seed+1);
568 Real dist1 = l1_distance(v, w);
569 Real dist2 = l1_distance(w, v);
570 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
571 }
572
573 template<class Z>
test_integer_l1_distance()574 void test_integer_l1_distance()
575 {
576 double tol = std::numeric_limits<double>::epsilon();
577 std::vector<Z> v{1,2,3};
578 std::vector<Z> w{1,1,1};
579 double l1 = boost::math::tools::l1_distance(v, v);
580 BOOST_TEST(abs(l1) < tol);
581
582 l1 = boost::math::tools::l1_distance(w, v);
583 BOOST_TEST(abs(l1 - 3) < tol);
584
585 l1 = boost::math::tools::l1_distance(v, w);
586 BOOST_TEST(abs(l1 - 3) < tol);
587
588 v = generate_random_vector<Z>(global_size, global_seed);
589 w = generate_random_vector<Z>(global_size, global_seed + 1);
590 double dist1 = l1_distance(v, w);
591 double dist2 = l1_distance(w, v);
592 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
593 }
594
595 template<class Complex>
test_complex_l1_distance()596 void test_complex_l1_distance()
597 {
598 typedef typename Complex::value_type Real;
599 Real tol = std::numeric_limits<Real>::epsilon();
600 std::vector<Complex> v{{1,0}, {0,1},{0,-1}};
601 Real l1 = boost::math::tools::l1_distance(v, v);
602 BOOST_TEST(abs(l1) < tol);
603
604 std::vector<Complex> w{{2,0}, {0,1},{0,-1}};
605 l1 = boost::math::tools::l1_distance(v.cbegin(), v.cend(), w.cbegin());
606 BOOST_TEST(abs(l1 - 1) < tol);
607
608 v = generate_random_vector<Complex>(global_size, global_seed);
609 w = generate_random_vector<Complex>(global_size, global_seed + 1);
610 Real dist1 = l1_distance(v, w);
611 Real dist2 = l1_distance(w, v);
612 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
613 }
614
615
616 template<class Real>
test_l2_norm()617 void test_l2_norm()
618 {
619 using std::sqrt;
620 Real tol = std::numeric_limits<Real>::epsilon();
621 std::vector<Real> v{1,1,1,1};
622 Real l2 = boost::math::tools::l2_norm(v.begin(), v.end());
623 BOOST_TEST(abs(l2 - 2) < tol);
624
625 l2 = boost::math::tools::l2_norm(v);
626 BOOST_TEST(abs(l2 - 2) < tol);
627
628 std::array<Real, 4> w{1,1,1,1};
629 l2 = boost::math::tools::l2_norm(w);
630 BOOST_TEST(abs(l2 - 2) < tol);
631
632 Real bignum = 4*sqrt((std::numeric_limits<Real>::max)());
633 v[0] = bignum;
634 v[1] = 0;
635 v[2] = 0;
636 v[3] = 0;
637 l2 = boost::math::tools::l2_norm(v.begin(), v.end());
638 BOOST_TEST(abs(l2 - bignum) < tol*l2);
639
640 v = generate_random_vector<Real>(global_size, global_seed);
641 Real scale = 8;
642 Real l2_1 = scale*l2_norm(v);
643 for (auto & x : v)
644 {
645 x *= -scale;
646 }
647 Real l2_2 = l2_norm(v);
648 BOOST_TEST(l2_1 > 0);
649 BOOST_TEST(l2_2 > 0);
650 BOOST_TEST(abs(l2_1 - l2_2) < tol*l2_1);
651 }
652
653 template<class Z>
test_integer_l2_norm()654 void test_integer_l2_norm()
655 {
656 double tol = 100*std::numeric_limits<double>::epsilon();
657 std::vector<Z> v{1,1,1,1};
658 double l2 = boost::math::tools::l2_norm(v.begin(), v.end());
659 BOOST_TEST(abs(l2 - 2) < tol);
660
661 v = generate_random_vector<Z>(global_size, global_seed);
662 Z scale = 2;
663 double l2_1 = scale*l2_norm(v);
664 for (auto & x : v)
665 {
666 x *= scale;
667 }
668 double l2_2 = l2_norm(v);
669 BOOST_TEST(l2_1 > 0);
670 BOOST_TEST(l2_2 > 0);
671 BOOST_TEST(abs(l2_1 - l2_2) < tol*l2_1);
672 }
673
674 template<class Complex>
test_complex_l2_norm()675 void test_complex_l2_norm()
676 {
677 typedef typename Complex::value_type Real;
678 Real tol = 100*std::numeric_limits<Real>::epsilon();
679 std::vector<Complex> v{{1,0}, {0,1},{0,-1}, {1,0}};
680 Real l2 = boost::math::tools::l2_norm(v.begin(), v.end());
681 BOOST_TEST(abs(l2 - 2) < tol);
682
683 l2 = boost::math::tools::l2_norm(v);
684 BOOST_TEST(abs(l2 - 2) < tol);
685
686 v = generate_random_vector<Complex>(global_size, global_seed);
687 Real scale = 8;
688 Real l2_1 = scale*l2_norm(v);
689 for (auto & x : v)
690 {
691 x *= -scale;
692 }
693 Real l2_2 = l2_norm(v);
694 BOOST_TEST(abs(l2_1 - l2_2) < tol*l2_1);
695 }
696
697 template<class Real>
test_l2_distance()698 void test_l2_distance()
699 {
700 Real tol = std::numeric_limits<Real>::epsilon();
701 std::vector<Real> v{1,1,1,1};
702 Real l2 = boost::math::tools::l2_distance(v, v);
703 BOOST_TEST(abs(l2) < tol);
704
705 v = generate_random_vector<Real>(global_size, global_seed);
706 auto w = generate_random_vector<Real>(global_size, global_seed + 1);
707 Real dist1 = l2_distance(v, w);
708 Real dist2 = l2_distance(w, v);
709 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
710 }
711
712
713 template<class Z>
test_integer_l2_distance()714 void test_integer_l2_distance()
715 {
716 double tol = std::numeric_limits<double>::epsilon();
717 std::vector<Z> v{1,1,1,1};
718 double l2 = boost::math::tools::l2_distance(v, v);
719 BOOST_TEST(abs(l2) < tol);
720
721 v = generate_random_vector<Z>(global_size, global_seed);
722 auto w = generate_random_vector<Z>(global_size, global_seed + 1);
723 double dist1 = l2_distance(v, w);
724 double dist2 = l2_distance(w, v);
725 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
726 }
727
728 template<class Complex>
test_complex_l2_distance()729 void test_complex_l2_distance()
730 {
731 typedef typename Complex::value_type Real;
732 Real tol = 100*std::numeric_limits<Real>::epsilon();
733 std::vector<Complex> v{{1,0}, {0,1},{0,-1}, {1,0}};
734 Real l2 = boost::math::tools::l2_distance(v, v);
735 BOOST_TEST(abs(l2) < tol);
736
737 v = generate_random_vector<Complex>(global_size, global_seed);
738 auto w = generate_random_vector<Complex>(global_size, global_seed + 1);
739 Real dist1 = l2_distance(v, w);
740 Real dist2 = l2_distance(w, v);
741 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
742 }
743
744 template<class Real>
test_sup_distance()745 void test_sup_distance()
746 {
747 Real tol = std::numeric_limits<Real>::epsilon();
748 std::vector<Real> v{1,1,1,1};
749 std::vector<Real> w{0,0,0,0};
750 Real sup = boost::math::tools::sup_distance(v, v);
751 BOOST_TEST(abs(sup) < tol);
752 sup = boost::math::tools::sup_distance(v, w);
753 BOOST_TEST(abs(sup -1) < tol);
754
755 v = generate_random_vector<Real>(global_size, global_seed);
756 w = generate_random_vector<Real>(global_size, global_seed + 1);
757 Real dist1 = sup_distance(v, w);
758 Real dist2 = sup_distance(w, v);
759 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
760 }
761
762
763 template<class Z>
test_integer_sup_distance()764 void test_integer_sup_distance()
765 {
766 double tol = std::numeric_limits<double>::epsilon();
767 std::vector<Z> v{1,1,1,1};
768 std::vector<Z> w{0,0,0,0};
769 double sup = boost::math::tools::sup_distance(v, v);
770 BOOST_TEST(abs(sup) < tol);
771
772 sup = boost::math::tools::sup_distance(v, w);
773 BOOST_TEST(abs(sup -1) < tol);
774
775 v = generate_random_vector<Z>(global_size, global_seed);
776 w = generate_random_vector<Z>(global_size, global_seed + 1);
777 double dist1 = sup_distance(v, w);
778 double dist2 = sup_distance(w, v);
779 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
780 }
781
782 template<class Complex>
test_complex_sup_distance()783 void test_complex_sup_distance()
784 {
785 typedef typename Complex::value_type Real;
786 Real tol = 100*std::numeric_limits<Real>::epsilon();
787 std::vector<Complex> v{{1,0}, {0,1},{0,-1}, {1,0}};
788 Real sup = boost::math::tools::sup_distance(v, v);
789 BOOST_TEST(abs(sup) < tol);
790
791 v = generate_random_vector<Complex>(global_size, global_seed);
792 auto w = generate_random_vector<Complex>(global_size, global_seed + 1);
793 Real dist1 = sup_distance(v, w);
794 Real dist2 = sup_distance(w, v);
795 BOOST_TEST(abs(dist1 - dist2) < tol*dist1);
796 }
797
main()798 int main()
799 {
800 test_l0_pseudo_norm<unsigned>();
801 test_l0_pseudo_norm<int>();
802 test_l0_pseudo_norm<float>();
803 test_l0_pseudo_norm<double>();
804 test_l0_pseudo_norm<long double>();
805 test_l0_pseudo_norm<cpp_bin_float_50>();
806
807 test_complex_l0_pseudo_norm<std::complex<float>>();
808 test_complex_l0_pseudo_norm<std::complex<double>>();
809 test_complex_l0_pseudo_norm<std::complex<long double>>();
810 test_complex_l0_pseudo_norm<cpp_complex_50>();
811
812 test_hamming_distance<int>();
813 test_hamming_distance<unsigned>();
814
815 test_l1_norm<float>();
816 test_l1_norm<double>();
817 test_l1_norm<long double>();
818 test_l1_norm<cpp_bin_float_50>();
819
820 test_integer_l1_norm<int>();
821 test_integer_l1_norm<unsigned>();
822
823 test_complex_l1_norm<std::complex<float>>();
824 test_complex_l1_norm<std::complex<double>>();
825 test_complex_l1_norm<std::complex<long double>>();
826 test_complex_l1_norm<cpp_complex_50>();
827
828 test_l1_distance<float>();
829 test_l1_distance<cpp_bin_float_50>();
830
831 test_integer_l1_distance<int>();
832 test_integer_l1_distance<unsigned>();
833
834 test_complex_l1_distance<std::complex<float>>();
835 test_complex_l1_distance<cpp_complex_50>();
836
837 test_complex_l2_norm<std::complex<float>>();
838 test_complex_l2_norm<std::complex<double>>();
839 test_complex_l2_norm<std::complex<long double>>();
840 test_complex_l2_norm<cpp_complex_50>();
841
842 test_l2_norm<float>();
843 test_l2_norm<double>();
844 test_l2_norm<long double>();
845 test_l2_norm<cpp_bin_float_50>();
846
847 test_integer_l2_norm<int>();
848 test_integer_l2_norm<unsigned>();
849
850 test_l2_distance<double>();
851 test_l2_distance<cpp_bin_float_50>();
852
853 test_integer_l2_distance<int>();
854 test_integer_l2_distance<unsigned>();
855
856 test_complex_l2_distance<std::complex<double>>();
857 test_complex_l2_distance<cpp_complex_50>();
858
859 test_lp<float>();
860 test_lp<double>();
861 test_lp<long double>();
862 test_lp<cpp_bin_float_50>();
863
864 test_complex_lp<std::complex<float>>();
865 test_complex_lp<std::complex<double>>();
866 test_complex_lp<std::complex<long double>>();
867 test_complex_lp<cpp_complex_50>();
868
869 test_integer_lp<int>();
870 test_integer_lp<unsigned>();
871
872 test_lp_distance<double>();
873 test_lp_distance<cpp_bin_float_50>();
874
875 test_complex_lp_distance<std::complex<double>>();
876 test_complex_lp_distance<cpp_complex_50>();
877
878 test_integer_lp_distance<int>();
879 test_integer_lp_distance<unsigned>();
880
881 test_sup_norm<float>();
882 test_sup_norm<double>();
883 test_sup_norm<long double>();
884 test_sup_norm<cpp_bin_float_50>();
885
886 test_integer_sup_norm<int>();
887 test_integer_sup_norm<unsigned>();
888
889 test_complex_sup_norm<std::complex<float>>();
890 test_complex_sup_norm<std::complex<double>>();
891 test_complex_sup_norm<std::complex<long double>>();
892 test_complex_sup_norm<cpp_complex_50>();
893
894 test_sup_distance<double>();
895 test_sup_distance<cpp_bin_float_50>();
896
897 test_integer_sup_distance<int>();
898 test_integer_sup_distance<unsigned>();
899
900 test_complex_sup_distance<std::complex<double>>();
901 test_complex_sup_distance<cpp_complex_50>();
902
903 test_total_variation<float>();
904 test_total_variation<double>();
905 test_total_variation<long double>();
906 test_total_variation<cpp_bin_float_50>();
907
908 test_integer_total_variation<uint32_t>();
909 test_integer_total_variation<int>();
910
911 return boost::report_errors();
912 }
913