Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / math / test / norms_test.cpp
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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 }