]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/math/minimax/main.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / math / minimax / main.cpp
1 // (C) Copyright John Maddock 2006.
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #define BOOST_TEST_MODULE foobar
7 #define BOOST_UBLAS_TYPE_CHECK_EPSILON (type_traits<real_type>::type_sqrt (boost::math::tools::epsilon <real_type>()))
8 #define BOOST_UBLAS_TYPE_CHECK_MIN (type_traits<real_type>::type_sqrt ( boost::math::tools::min_value<real_type>()))
9 #define BOOST_UBLAS_NDEBUG
10
11 #include "multiprecision.hpp"
12
13 #include <boost/math/tools/remez.hpp>
14 #include <boost/math/tools/test.hpp>
15 #include <boost/math/special_functions/binomial.hpp>
16 #include <boost/spirit/include/classic_core.hpp>
17 #include <boost/spirit/include/classic_actor.hpp>
18 #include <boost/lexical_cast.hpp>
19 #include <iostream>
20 #include <iomanip>
21 #include <string>
22 #include <boost/test/included/unit_test.hpp> // for test_main
23 #include <boost/multiprecision/cpp_bin_float.hpp>
24
25
26 extern mp_type f(const mp_type& x, int variant);
27 extern void show_extra(
28 const boost::math::tools::polynomial<mp_type>& n,
29 const boost::math::tools::polynomial<mp_type>& d,
30 const mp_type& x_offset,
31 const mp_type& y_offset,
32 int variant);
33
34 using namespace boost::spirit::classic;
35
36 mp_type a(0), b(1); // range to optimise over
37 bool rel_error(true);
38 bool pin(false);
39 int orderN(3);
40 int orderD(1);
41 int target_precision = boost::math::tools::digits<long double>();
42 int working_precision = target_precision * 2;
43 bool started(false);
44 int variant(0);
45 int skew(0);
46 int brake(50);
47 mp_type x_offset(0), y_offset(0), x_scale(1);
48 bool auto_offset_y;
49
50 boost::shared_ptr<boost::math::tools::remez_minimax<mp_type> > p_remez;
51
52 mp_type the_function(const mp_type& val)
53 {
54 return f(x_scale * (val + x_offset), variant) + y_offset;
55 }
56
57 void step_some(unsigned count)
58 {
59 try{
60 set_working_precision(working_precision);
61 if(!started)
62 {
63 //
64 // If we have an automatic y-offset calculate it now:
65 //
66 if(auto_offset_y)
67 {
68 mp_type fa, fb, fm;
69 fa = f(x_scale * (a + x_offset), variant);
70 fb = f(x_scale * (b + x_offset), variant);
71 fm = f(x_scale * ((a+b)/2 + x_offset), variant);
72 y_offset = -(fa + fb + fm) / 3;
73 set_output_precision(5);
74 std::cout << "Setting auto-y-offset to " << y_offset << std::endl;
75 }
76 //
77 // Truncate offsets to float precision:
78 //
79 x_offset = round_to_precision(x_offset, 20);
80 y_offset = round_to_precision(y_offset, 20);
81 //
82 // Construct new Remez state machine:
83 //
84 p_remez.reset(new boost::math::tools::remez_minimax<mp_type>(
85 &the_function,
86 orderN, orderD,
87 a, b,
88 pin,
89 rel_error,
90 skew,
91 working_precision));
92 std::cout << "Max error in interpolated form: " << std::setprecision(3) << std::scientific << boost::math::tools::real_cast<double>(p_remez->max_error()) << std::endl;
93 //
94 // Signal that we've started:
95 //
96 started = true;
97 }
98 unsigned i;
99 for(i = 0; i < count; ++i)
100 {
101 std::cout << "Stepping..." << std::endl;
102 p_remez->set_brake(brake);
103 mp_type r = p_remez->iterate();
104 set_output_precision(3);
105 std::cout
106 << "Maximum Deviation Found: " << std::setprecision(3) << std::scientific << boost::math::tools::real_cast<double>(p_remez->max_error()) << std::endl
107 << "Expected Error Term: " << std::setprecision(3) << std::scientific << boost::math::tools::real_cast<double>(p_remez->error_term()) << std::endl
108 << "Maximum Relative Change in Control Points: " << std::setprecision(3) << std::scientific << boost::math::tools::real_cast<double>(r) << std::endl;
109 }
110 }
111 catch(const std::exception& e)
112 {
113 std::cout << "Step failed with exception: " << e.what() << std::endl;
114 }
115 }
116
117 void step(const char*, const char*)
118 {
119 step_some(1);
120 }
121
122 void show(const char*, const char*)
123 {
124 set_working_precision(working_precision);
125 if(started)
126 {
127 boost::math::tools::polynomial<mp_type> n = p_remez->numerator();
128 boost::math::tools::polynomial<mp_type> d = p_remez->denominator();
129 std::vector<mp_type> cn = n.chebyshev();
130 std::vector<mp_type> cd = d.chebyshev();
131 int prec = 2 + (target_precision * 3010LL)/10000;
132 std::cout << std::scientific << std::setprecision(prec);
133 set_output_precision(prec);
134 boost::numeric::ublas::vector<mp_type> v = p_remez->zero_points();
135
136 std::cout << " Zeros = {\n";
137 unsigned i;
138 for(i = 0; i < v.size(); ++i)
139 {
140 std::cout << " " << v[i] << std::endl;
141 }
142 std::cout << " }\n";
143
144 v = p_remez->chebyshev_points();
145 std::cout << " Chebeshev Control Points = {\n";
146 for(i = 0; i < v.size(); ++i)
147 {
148 std::cout << " " << v[i] << std::endl;
149 }
150 std::cout << " }\n";
151
152 std::cout << "X offset: " << x_offset << std::endl;
153 std::cout << "X scale: " << x_scale << std::endl;
154 std::cout << "Y offset: " << y_offset << std::endl;
155
156 std::cout << "P = {";
157 for(i = 0; i < n.size(); ++i)
158 {
159 std::cout << " " << n[i] << "L," << std::endl;
160 }
161 std::cout << " }\n";
162
163 std::cout << "Q = {";
164 for(i = 0; i < d.size(); ++i)
165 {
166 std::cout << " " << d[i] << "L," << std::endl;
167 }
168 std::cout << " }\n";
169
170 std::cout << "CP = {";
171 for(i = 0; i < cn.size(); ++i)
172 {
173 std::cout << " " << cn[i] << "L," << std::endl;
174 }
175 std::cout << " }\n";
176
177 std::cout << "CQ = {";
178 for(i = 0; i < cd.size(); ++i)
179 {
180 std::cout << " " << cd[i] << "L," << std::endl;
181 }
182 std::cout << " }\n";
183
184 show_extra(n, d, x_offset, y_offset, variant);
185 }
186 else
187 {
188 std::cerr << "Nothing to display" << std::endl;
189 }
190 }
191
192 void do_graph(unsigned points)
193 {
194 set_working_precision(working_precision);
195 mp_type step = (b - a) / (points - 1);
196 mp_type x = a;
197 while(points > 1)
198 {
199 set_output_precision(10);
200 std::cout << std::setprecision(10) << std::setw(30) << std::left
201 << boost::lexical_cast<std::string>(x) << the_function(x) << std::endl;
202 --points;
203 x += step;
204 }
205 std::cout << std::setprecision(10) << std::setw(30) << std::left
206 << boost::lexical_cast<std::string>(b) << the_function(b) << std::endl;
207 }
208
209 void graph(const char*, const char*)
210 {
211 do_graph(3);
212 }
213
214 template <class T>
215 mp_type convert_to_rr(const T& val)
216 {
217 return val;
218 }
219 template <class Backend, boost::multiprecision::expression_template_option ET>
220 mp_type convert_to_rr(const boost::multiprecision::number<Backend, ET>& val)
221 {
222 return boost::lexical_cast<mp_type>(val.str());
223 }
224
225 template <class T>
226 void do_test(T, const char* name)
227 {
228 set_working_precision(working_precision);
229 if(started)
230 {
231 //
232 // We want to test the approximation at fixed precision:
233 // either float, double or long double. Begin by getting the
234 // polynomials:
235 //
236 boost::math::tools::polynomial<T> n, d;
237 boost::math::tools::polynomial<mp_type> nr, dr;
238 nr = p_remez->numerator();
239 dr = p_remez->denominator();
240 n = nr;
241 d = dr;
242
243 std::vector<mp_type> cn1, cd1;
244 cn1 = nr.chebyshev();
245 cd1 = dr.chebyshev();
246 std::vector<T> cn, cd;
247 for(unsigned i = 0; i < cn1.size(); ++i)
248 {
249 cn.push_back(boost::math::tools::real_cast<T>(cn1[i]));
250 }
251 for(unsigned i = 0; i < cd1.size(); ++i)
252 {
253 cd.push_back(boost::math::tools::real_cast<T>(cd1[i]));
254 }
255 //
256 // We'll test at the Chebeshev control points which is where
257 // (in theory) the largest deviation should occur. For good
258 // measure we'll test at the zeros as well:
259 //
260 boost::numeric::ublas::vector<mp_type>
261 zeros(p_remez->zero_points()),
262 cheb(p_remez->chebyshev_points());
263
264 mp_type max_error(0), cheb_max_error(0);
265
266 //
267 // Do the tests at the zeros:
268 //
269 std::cout << "Starting tests at " << name << " precision...\n";
270 std::cout << "Absissa Error (Poly) Error (Cheb)\n";
271 for(unsigned i = 0; i < zeros.size(); ++i)
272 {
273 mp_type true_result = the_function(zeros[i]);
274 T absissa = boost::math::tools::real_cast<T>(zeros[i]);
275 mp_type test_result = convert_to_rr(n.evaluate(absissa) / d.evaluate(absissa));
276 mp_type cheb_result = convert_to_rr(boost::math::tools::evaluate_chebyshev(cn, absissa) / boost::math::tools::evaluate_chebyshev(cd, absissa));
277 mp_type err, cheb_err;
278 if(rel_error)
279 {
280 err = boost::math::tools::relative_error(test_result, true_result);
281 cheb_err = boost::math::tools::relative_error(cheb_result, true_result);
282 }
283 else
284 {
285 err = fabs(test_result - true_result);
286 cheb_err = fabs(cheb_result - true_result);
287 }
288 if(err > max_error)
289 max_error = err;
290 if(cheb_err > cheb_max_error)
291 cheb_max_error = cheb_err;
292 std::cout << std::setprecision(6) << std::setw(15) << std::left << absissa
293 << std::setw(15) << std::left << boost::math::tools::real_cast<T>(err) << boost::math::tools::real_cast<T>(cheb_err) << std::endl;
294 }
295 //
296 // Do the tests at the Chebeshev control points:
297 //
298 for(unsigned i = 0; i < cheb.size(); ++i)
299 {
300 mp_type true_result = the_function(cheb[i]);
301 T absissa = boost::math::tools::real_cast<T>(cheb[i]);
302 mp_type test_result = convert_to_rr(n.evaluate(absissa) / d.evaluate(absissa));
303 mp_type cheb_result = convert_to_rr(boost::math::tools::evaluate_chebyshev(cn, absissa) / boost::math::tools::evaluate_chebyshev(cd, absissa));
304 mp_type err, cheb_err;
305 if(rel_error)
306 {
307 err = boost::math::tools::relative_error(test_result, true_result);
308 cheb_err = boost::math::tools::relative_error(cheb_result, true_result);
309 }
310 else
311 {
312 err = fabs(test_result - true_result);
313 cheb_err = fabs(cheb_result - true_result);
314 }
315 if(err > max_error)
316 max_error = err;
317 std::cout << std::setprecision(6) << std::setw(15) << std::left << absissa
318 << std::setw(15) << std::left << boost::math::tools::real_cast<T>(err) <<
319 boost::math::tools::real_cast<T>(cheb_err) << std::endl;
320 }
321 std::string msg = "Max Error found at ";
322 msg += name;
323 msg += " precision = ";
324 msg.append(62 - 17 - msg.size(), ' ');
325 std::cout << msg << std::setprecision(6) << "Poly: " << std::setw(20) << std::left
326 << boost::math::tools::real_cast<T>(max_error) << "Cheb: " << boost::math::tools::real_cast<T>(cheb_max_error) << std::endl;
327 }
328 else
329 {
330 std::cout << "Nothing to test: try converging an approximation first!!!" << std::endl;
331 }
332 }
333
334 void test_float(const char*, const char*)
335 {
336 do_test(float(0), "float");
337 }
338
339 void test_double(const char*, const char*)
340 {
341 do_test(double(0), "double");
342 }
343
344 void test_long(const char*, const char*)
345 {
346 do_test((long double)(0), "long double");
347 }
348
349 void test_float80(const char*, const char*)
350 {
351 do_test((boost::multiprecision::cpp_bin_float_double_extended)(0), "float80");
352 }
353
354 void test_float128(const char*, const char*)
355 {
356 do_test((boost::multiprecision::cpp_bin_float_quad)(0), "float128");
357 }
358
359 void test_all(const char*, const char*)
360 {
361 do_test(float(0), "float");
362 do_test(double(0), "double");
363 do_test((long double)(0), "long double");
364 }
365
366 template <class T>
367 void do_test_n(T, const char* name, unsigned count)
368 {
369 set_working_precision(working_precision);
370 if(started)
371 {
372 //
373 // We want to test the approximation at fixed precision:
374 // either float, double or long double. Begin by getting the
375 // polynomials:
376 //
377 boost::math::tools::polynomial<T> n, d;
378 boost::math::tools::polynomial<mp_type> nr, dr;
379 nr = p_remez->numerator();
380 dr = p_remez->denominator();
381 n = nr;
382 d = dr;
383
384 std::vector<mp_type> cn1, cd1;
385 cn1 = nr.chebyshev();
386 cd1 = dr.chebyshev();
387 std::vector<T> cn, cd;
388 for(unsigned i = 0; i < cn1.size(); ++i)
389 {
390 cn.push_back(boost::math::tools::real_cast<T>(cn1[i]));
391 }
392 for(unsigned i = 0; i < cd1.size(); ++i)
393 {
394 cd.push_back(boost::math::tools::real_cast<T>(cd1[i]));
395 }
396
397 mp_type max_error(0), max_cheb_error(0);
398 mp_type step = (b - a) / count;
399
400 //
401 // Do the tests at the zeros:
402 //
403 std::cout << "Starting tests at " << name << " precision...\n";
404 std::cout << "Absissa Error (poly) Error (Cheb)\n";
405 for(mp_type x = a; x <= b; x += step)
406 {
407 mp_type true_result = the_function(x);
408 //std::cout << true_result << std::endl;
409 T absissa = boost::math::tools::real_cast<T>(x);
410 mp_type test_result = convert_to_rr(n.evaluate(absissa) / d.evaluate(absissa));
411 //std::cout << test_result << std::endl;
412 mp_type cheb_result = convert_to_rr(boost::math::tools::evaluate_chebyshev(cn, absissa) / boost::math::tools::evaluate_chebyshev(cd, absissa));
413 //std::cout << cheb_result << std::endl;
414 mp_type err, cheb_err;
415 if(rel_error)
416 {
417 err = boost::math::tools::relative_error(test_result, true_result);
418 cheb_err = boost::math::tools::relative_error(cheb_result, true_result);
419 }
420 else
421 {
422 err = fabs(test_result - true_result);
423 cheb_err = fabs(cheb_result - true_result);
424 }
425 if(err > max_error)
426 max_error = err;
427 if(cheb_err > max_cheb_error)
428 max_cheb_error = cheb_err;
429 std::cout << std::setprecision(6) << std::setw(15) << std::left << boost::math::tools::real_cast<double>(absissa)
430 << (test_result < true_result ? "-" : "") << std::setw(20) << std::left
431 << boost::math::tools::real_cast<double>(err)
432 << boost::math::tools::real_cast<double>(cheb_err) << std::endl;
433 }
434 std::string msg = "Max Error found at ";
435 msg += name;
436 msg += " precision = ";
437 //msg.append(62 - 17 - msg.size(), ' ');
438 std::cout << msg << "Poly: " << std::setprecision(6)
439 //<< std::setw(15) << std::left
440 << boost::math::tools::real_cast<T>(max_error)
441 << " Cheb: " << boost::math::tools::real_cast<T>(max_cheb_error) << std::endl;
442 }
443 else
444 {
445 std::cout << "Nothing to test: try converging an approximation first!!!" << std::endl;
446 }
447 }
448
449 void test_n(unsigned n)
450 {
451 do_test_n(mp_type(), "mp_type", n);
452 }
453
454 void test_float_n(unsigned n)
455 {
456 do_test_n(float(0), "float", n);
457 }
458
459 void test_double_n(unsigned n)
460 {
461 do_test_n(double(0), "double", n);
462 }
463
464 void test_long_n(unsigned n)
465 {
466 do_test_n((long double)(0), "long double", n);
467 }
468
469 void test_float80_n(unsigned n)
470 {
471 do_test_n((boost::multiprecision::cpp_bin_float_double_extended)(0), "float80", n);
472 }
473
474 void test_float128_n(unsigned n)
475 {
476 do_test_n((boost::multiprecision::cpp_bin_float_quad)(0), "float128", n);
477 }
478
479 void rotate(const char*, const char*)
480 {
481 if(p_remez)
482 {
483 p_remez->rotate();
484 }
485 else
486 {
487 std::cerr << "Nothing to rotate" << std::endl;
488 }
489 }
490
491 void rescale(const char*, const char*)
492 {
493 if(p_remez)
494 {
495 p_remez->rescale(a, b);
496 }
497 else
498 {
499 std::cerr << "Nothing to rescale" << std::endl;
500 }
501 }
502
503 void graph_poly(const char*, const char*)
504 {
505 int i = 50;
506 set_working_precision(working_precision);
507 if(started)
508 {
509 //
510 // We want to test the approximation at fixed precision:
511 // either float, double or long double. Begin by getting the
512 // polynomials:
513 //
514 boost::math::tools::polynomial<mp_type> n, d;
515 n = p_remez->numerator();
516 d = p_remez->denominator();
517
518 mp_type max_error(0);
519 mp_type step = (b - a) / i;
520
521 std::cout << "Evaluating Numerator...\n";
522 mp_type val;
523 for(val = a; val <= b; val += step)
524 std::cout << n.evaluate(val) << std::endl;
525 std::cout << "Evaluating Denominator...\n";
526 for(val = a; val <= b; val += step)
527 std::cout << d.evaluate(val) << std::endl;
528 }
529 else
530 {
531 std::cout << "Nothing to test: try converging an approximation first!!!" << std::endl;
532 }
533 }
534
535 BOOST_AUTO_TEST_CASE( test_main )
536 {
537 std::string line;
538 real_parser<long double/*mp_type*/ > const rr_p;
539 while(std::getline(std::cin, line))
540 {
541 if(parse(line.c_str(), str_p("quit"), space_p).full)
542 return;
543 if(false == parse(line.c_str(),
544 (
545
546 str_p("range")[assign_a(started, false)] && real_p[assign_a(a)] && real_p[assign_a(b)]
547 ||
548 str_p("relative")[assign_a(started, false)][assign_a(rel_error, true)]
549 ||
550 str_p("absolute")[assign_a(started, false)][assign_a(rel_error, false)]
551 ||
552 str_p("pin")[assign_a(started, false)] && str_p("true")[assign_a(pin, true)]
553 ||
554 str_p("pin")[assign_a(started, false)] && str_p("false")[assign_a(pin, false)]
555 ||
556 str_p("pin")[assign_a(started, false)] && str_p("1")[assign_a(pin, true)]
557 ||
558 str_p("pin")[assign_a(started, false)] && str_p("0")[assign_a(pin, false)]
559 ||
560 str_p("pin")[assign_a(started, false)][assign_a(pin, true)]
561 ||
562 str_p("order")[assign_a(started, false)] && uint_p[assign_a(orderN)] && uint_p[assign_a(orderD)]
563 ||
564 str_p("order")[assign_a(started, false)] && uint_p[assign_a(orderN)]
565 ||
566 str_p("target-precision") && uint_p[assign_a(target_precision)]
567 ||
568 str_p("working-precision")[assign_a(started, false)] && uint_p[assign_a(working_precision)]
569 ||
570 str_p("variant")[assign_a(started, false)] && int_p[assign_a(variant)]
571 ||
572 str_p("skew")[assign_a(started, false)] && int_p[assign_a(skew)]
573 ||
574 str_p("brake") && int_p[assign_a(brake)]
575 ||
576 str_p("step") && int_p[&step_some]
577 ||
578 str_p("step")[&step]
579 ||
580 str_p("poly")[&graph_poly]
581 ||
582 str_p("info")[&show]
583 ||
584 str_p("graph") && uint_p[&do_graph]
585 ||
586 str_p("graph")[&graph]
587 ||
588 str_p("x-offset") && real_p[assign_a(x_offset)]
589 ||
590 str_p("x-scale") && real_p[assign_a(x_scale)]
591 ||
592 str_p("y-offset") && str_p("auto")[assign_a(auto_offset_y, true)]
593 ||
594 str_p("y-offset") && real_p[assign_a(y_offset)][assign_a(auto_offset_y, false)]
595 ||
596 str_p("test") && str_p("float80") && uint_p[&test_float80_n]
597 ||
598 str_p("test") && str_p("float80")[&test_float80]
599 ||
600 str_p("test") && str_p("float128") && uint_p[&test_float128_n]
601 ||
602 str_p("test") && str_p("float128")[&test_float128]
603 ||
604 str_p("test") && str_p("float") && uint_p[&test_float_n]
605 ||
606 str_p("test") && str_p("float")[&test_float]
607 ||
608 str_p("test") && str_p("double") && uint_p[&test_double_n]
609 ||
610 str_p("test") && str_p("double")[&test_double]
611 ||
612 str_p("test") && str_p("long") && uint_p[&test_long_n]
613 ||
614 str_p("test") && str_p("long")[&test_long]
615 ||
616 str_p("test") && str_p("all")[&test_all]
617 ||
618 str_p("test") && uint_p[&test_n]
619 ||
620 str_p("rotate")[&rotate]
621 ||
622 str_p("rescale") && real_p[assign_a(a)] && real_p[assign_a(b)] && epsilon_p[&rescale]
623
624 ), space_p).full)
625 {
626 std::cout << "Unable to parse directive: \"" << line << "\"" << std::endl;
627 }
628 else
629 {
630 std::cout << "Variant = " << variant << std::endl;
631 std::cout << "range = [" << a << "," << b << "]" << std::endl;
632 std::cout << "Relative Error = " << rel_error << std::endl;
633 std::cout << "Pin to Origin = " << pin << std::endl;
634 std::cout << "Order (Num/Denom) = " << orderN << "/" << orderD << std::endl;
635 std::cout << "Target Precision = " << target_precision << std::endl;
636 std::cout << "Working Precision = " << working_precision << std::endl;
637 std::cout << "Skew = " << skew << std::endl;
638 std::cout << "Brake = " << brake << std::endl;
639 std::cout << "X Offset = " << x_offset << std::endl;
640 std::cout << "X scale = " << x_scale << std::endl;
641 std::cout << "Y Offset = ";
642 if(auto_offset_y)
643 std::cout << "Auto (";
644 std::cout << y_offset;
645 if(auto_offset_y)
646 std::cout << ")";
647 std::cout << std::endl;
648 }
649 }
650 }