• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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