File indexing completed on 2025-02-23 09:21:02
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 #ifndef __has_c2_function_hh
0041 #define __has_c2_function_hh 1
0042
0043
0044
0045 #ifdef _MSC_VER
0046 # define _USE_MATH_DEFINES
0047 #endif
0048
0049 #define c2_isnan std::isnan
0050 #define c2_isfinite std::isfinite
0051
0052 #include <cmath>
0053 #include <limits> // fails under gcc-4.3 without this here, was ok
0054 #include <sstream>
0055 #include <stdexcept>
0056 #include <string>
0057 #include <typeinfo>
0058 #include <utility>
0059 #include <vector>
0060
0061
0062 class c2_exception : public std::exception
0063 {
0064 public:
0065
0066
0067 c2_exception(const char msgcode[]) : info(msgcode) {}
0068 virtual ~c2_exception() throw() {}
0069
0070
0071 virtual const char* what() const throw() { return info.c_str(); }
0072
0073 private:
0074 std::string info;
0075 };
0076
0077
0078 template<typename float_type>
0079 class c2_composed_function_p;
0080 template<typename float_type>
0081 class c2_sum_p;
0082 template<typename float_type>
0083 class c2_diff_p;
0084 template<typename float_type>
0085 class c2_product_p;
0086 template<typename float_type>
0087 class c2_ratio_p;
0088 template<typename float_type>
0089 class c2_piecewise_function_p;
0090 template<typename float_type>
0091 class c2_quadratic_p;
0092 template<typename float_type>
0093 class c2_ptr;
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111 template<typename float_type>
0112 class c2_fblock
0113 {
0114 public:
0115
0116 float_type x;
0117
0118 float_type y;
0119
0120 float_type yp;
0121
0122 float_type ypp;
0123
0124
0125 bool ypbad;
0126
0127 bool yppbad;
0128 };
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 template<typename float_type = double>
0156 class c2_function
0157 {
0158 public:
0159
0160
0161 const std::string cvs_header_vers() const
0162 {
0163 return "c2_function.hh 490 2012-04-10 19:05:40Z marcus ";
0164 }
0165
0166
0167
0168 const std::string cvs_file_vers() const;
0169
0170 public:
0171
0172 virtual ~c2_function()
0173 {
0174 if (sampling_grid && !no_overwrite_grid) delete sampling_grid;
0175 if (root_info) delete root_info;
0176 if (owner_count) {
0177 std::ostringstream outstr;
0178 outstr << "attempt to delete an object with non-zero ownership in class";
0179 outstr << typeid(*this).name() << std::endl;
0180
0181 }
0182 }
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
0193 float_type* yprime2) const
0194 = 0;
0195
0196
0197
0198
0199 inline float_type operator()(float_type x) const
0200 {
0201 return value_with_derivatives(x, (float_type*)0, (float_type*)0);
0202 }
0203
0204
0205
0206
0207
0208
0209
0210 inline float_type operator()(float_type x, float_type* yprime,
0211 float_type* yprime2) const
0212 {
0213 return value_with_derivatives(x, yprime, yprime2);
0214 }
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248 float_type find_root(float_type lower_bracket, float_type upper_bracket, float_type start,
0249 float_type value, int* error = 0, float_type* final_yprime = 0,
0250 float_type* final_yprime2 = 0) const ;
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282 float_type partial_integrals(std::vector<float_type> xgrid,
0283 std::vector<float_type>* partials = 0, float_type abs_tol = 1e-12,
0284 float_type rel_tol = 1e-12, int derivs = 2, bool adapt = true,
0285 bool extrapolate = true) const ;
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318 float_type integral(float_type amin, float_type amax, std::vector<float_type>* partials = 0,
0319 float_type abs_tol = 1e-12, float_type rel_tol = 1e-12, int derivs = 2,
0320 bool adapt = true, bool extrapolate = true) const ;
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393 c2_piecewise_function_p<float_type>*
0394 adaptively_sample(float_type amin, float_type amax, float_type abs_tol = 1e-12,
0395 float_type rel_tol = 1e-12, int derivs = 2,
0396 std::vector<float_type>* xvals = 0, std::vector<float_type>* yvals = 0) const
0397 ;
0398
0399 inline float_type xmin() const { return fXMin; }
0400 inline float_type xmax() const { return fXMax; }
0401 void set_domain(float_type amin, float_type amax)
0402 {
0403 fXMin = amin;
0404 fXMax = amax;
0405 }
0406
0407
0408
0409 size_t get_evaluations() const { return evaluations; }
0410
0411 void reset_evaluations() const { evaluations = 0; }
0412
0413 inline void increment_evaluations() const { evaluations++; }
0414
0415
0416
0417
0418
0419
0420
0421
0422 bool check_monotonicity(const std::vector<float_type>& data, const char message[]) const
0423 ;
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441 virtual void set_sampling_grid(const std::vector<float_type>& grid)
0442 ;
0443
0444
0445
0446 std::vector<float_type>* get_sampling_grid_pointer() const { return sampling_grid; }
0447
0448 virtual void get_sampling_grid(float_type amin, float_type amax,
0449 std::vector<float_type>& grid) const;
0450
0451
0452 void preen_sampling_grid(std::vector<float_type>* result) const;
0453 void refine_sampling_grid(std::vector<float_type>& grid, size_t refinement) const;
0454
0455
0456
0457
0458
0459
0460
0461 c2_function<float_type>& normalized_function(float_type amin, float_type amax,
0462 float_type norm = 1.0) const
0463 ;
0464 c2_function<float_type>& square_normalized_function(float_type amin, float_type amax,
0465 float_type norm = 1.0) const
0466 ;
0467
0468
0469
0470
0471
0472
0473
0474 c2_function<float_type>& square_normalized_function(float_type amin, float_type amax,
0475 const c2_function<float_type>& weight,
0476 float_type norm = 1.0) const
0477 ;
0478
0479
0480
0481
0482
0483 c2_sum_p<float_type>& operator+(const c2_function<float_type>& rhs) const
0484 {
0485 return *new c2_sum_p<float_type>(*this, rhs);
0486 }
0487
0488
0489
0490
0491 c2_diff_p<float_type>& operator-(const c2_function<float_type>& rhs) const
0492 {
0493 return *new c2_diff_p<float_type>(*this, rhs);
0494 }
0495
0496
0497
0498
0499 c2_product_p<float_type>& operator*(const c2_function<float_type>& rhs) const
0500 {
0501 return *new c2_product_p<float_type>(*this, rhs);
0502 }
0503 c2_ratio_p<float_type>& operator/(const c2_function<float_type>& rhs) const
0504 {
0505 return *new c2_ratio_p<float_type>(*this, rhs);
0506 }
0507
0508
0509
0510
0511 c2_composed_function_p<float_type>& operator()(const c2_function<float_type>& inner) const
0512 {
0513 return *new c2_composed_function_p<float_type>((*this), inner);
0514 }
0515
0516
0517
0518
0519
0520 float_type get_trouble_point() const { return bad_x_point; }
0521
0522
0523
0524 void claim_ownership() const { owner_count++; }
0525
0526
0527 size_t release_ownership_for_return() const
0528 {
0529 if (!owner_count) {
0530 std::ostringstream outstr;
0531 outstr << "attempt to release ownership of an unowned function in class ";
0532 outstr << typeid(*this).name() << std::endl;
0533 throw c2_exception(outstr.str().c_str());
0534 }
0535 owner_count--;
0536 return owner_count;
0537 }
0538 void release_ownership() const
0539 {
0540 if (!release_ownership_for_return()) delete this;
0541 }
0542
0543
0544 size_t count_owners() const { return owner_count; }
0545
0546 protected:
0547 c2_function(const c2_function<float_type>& src)
0548 : sampling_grid(0),
0549 no_overwrite_grid(false),
0550 fXMin(src.fXMin),
0551 fXMax(src.fXMax),
0552 root_info(0),
0553 owner_count(0)
0554 {}
0555 c2_function()
0556 : sampling_grid(0),
0557 no_overwrite_grid(0),
0558 fXMin(-std::numeric_limits<float_type>::max()),
0559 fXMax(std::numeric_limits<float_type>::max()),
0560 root_info(0),
0561 owner_count(0)
0562 {}
0563
0564 virtual void set_sampling_grid_pointer(std::vector<float_type>& grid)
0565 {
0566 if (sampling_grid && !no_overwrite_grid) delete sampling_grid;
0567 sampling_grid = &grid;
0568 no_overwrite_grid = 1;
0569 }
0570
0571 std::vector<float_type>* sampling_grid;
0572 bool no_overwrite_grid;
0573
0574 float_type fXMin, fXMax;
0575 mutable size_t evaluations;
0576
0577
0578 mutable float_type bad_x_point;
0579
0580 public:
0581
0582
0583
0584 inline void fill_fblock(c2_fblock<float_type>& fb) const
0585 {
0586 fb.y = value_with_derivatives(fb.x, &fb.yp, &fb.ypp);
0587 fb.ypbad = c2_isnan(fb.yp) || !c2_isfinite(fb.yp);
0588 fb.yppbad = c2_isnan(fb.ypp) || !c2_isfinite(fb.ypp);
0589 increment_evaluations();
0590 }
0591
0592 private:
0593
0594
0595 struct recur_item
0596 {
0597 c2_fblock<float_type> f1;
0598 size_t depth;
0599 float_type previous_estimate, abs_tol, step_sum;
0600 bool done;
0601 size_t f0index, f2index;
0602 };
0603
0604
0605
0606
0607
0608 struct c2_integrate_recur
0609 {
0610 c2_fblock<float_type>*f0, *f1;
0611 float_type abs_tol, rel_tol, eps_scale, extrap_coef, extrap2, dx_tolerance, abs_tol_min;
0612 std::vector<recur_item>* rb_stack;
0613 int derivs;
0614 bool adapt, extrapolate, inited;
0615 };
0616
0617
0618
0619 struct c2_sample_recur
0620 {
0621 c2_fblock<float_type>*f0, *f1;
0622 float_type abs_tol, rel_tol, dx_tolerance, abs_tol_min;
0623 int derivs;
0624 c2_piecewise_function_p<float_type>* out;
0625 std::vector<float_type>*xvals, *yvals;
0626 std::vector<recur_item>* rb_stack;
0627 bool inited;
0628 };
0629
0630
0631
0632 struct c2_root_info
0633 {
0634 c2_fblock<float_type> lower, upper;
0635 bool inited;
0636 };
0637
0638
0639
0640
0641
0642
0643 float_type integrate_step(struct c2_integrate_recur& rb) const ;
0644
0645
0646
0647
0648
0649
0650 void sample_step(struct c2_sample_recur& rb) const ;
0651
0652
0653
0654
0655
0656
0657
0658 mutable struct c2_root_info* root_info;
0659
0660 mutable size_t owner_count;
0661 };
0662
0663
0664
0665
0666
0667
0668
0669 template<typename float_type = double>
0670 class c2_classic_function_p : public c2_function<float_type>
0671 {
0672 public:
0673
0674
0675 c2_classic_function_p(const float_type (*c_func)(float_type))
0676 : c2_function<float_type>(), func(c_func)
0677 {}
0678
0679
0680
0681 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
0682 float_type* yprime2) const
0683 {
0684 if (!func) throw c2_exception("c2_classic_function called with null function");
0685 if (yprime) *yprime = 0;
0686 if (yprime2) *yprime2 = 0;
0687 return func(x);
0688 }
0689 virtual ~c2_classic_function_p() {}
0690
0691 protected:
0692
0693 const float_type (*func)(float_type);
0694 };
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711 template<typename float_type>
0712 class c2_const_ptr
0713 {
0714 public:
0715
0716 c2_const_ptr() : func(0) {}
0717
0718
0719 c2_const_ptr(const c2_function<float_type>& f) : func(0) { this->set_function(&f); }
0720
0721
0722 c2_const_ptr(const c2_const_ptr<float_type>& src) : func(0)
0723 {
0724 this->set_function(src.get_ptr());
0725 }
0726 void set_function(const c2_function<float_type>* f)
0727 {
0728 if (func) func->release_ownership();
0729 func = f;
0730 if (func) func->claim_ownership();
0731 }
0732
0733
0734
0735 const c2_const_ptr<float_type>& operator=(const c2_const_ptr<float_type>& f)
0736 {
0737 this->set_function(f.get_ptr());
0738 return f;
0739 }
0740
0741
0742 const c2_function<float_type>& operator=(const c2_function<float_type>& f)
0743 {
0744 this->set_function(&f);
0745 return f;
0746 }
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757 void release_for_return()
0758 {
0759 if (func) func->release_ownership_for_return();
0760 func = 0;
0761 }
0762
0763
0764
0765
0766
0767 void unset_function(void) { this->set_function(0); }
0768
0769 ~c2_const_ptr() { this->set_function(0); }
0770
0771
0772 inline const c2_function<float_type>& get() const
0773 {
0774 if (!func) throw c2_exception("c2_ptr accessed uninitialized");
0775 return *func;
0776 }
0777
0778 inline const c2_function<float_type>* get_ptr() const { return func; }
0779
0780 inline const c2_function<float_type>* operator->() const { return &get(); }
0781
0782 bool valid() const { return func != 0; }
0783
0784
0785
0786 operator const c2_function<float_type>&() const { return this->get(); }
0787
0788
0789
0790
0791
0792 float_type operator()(float_type x) const { return get()(x); }
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802 float_type operator()(float_type x, float_type* yprime,
0803 float_type* yprime2) const
0804 {
0805 return get().value_with_derivatives(x, yprime, yprime2);
0806 }
0807
0808
0809
0810
0811 c2_sum_p<float_type>&
0812 operator+(const c2_function<float_type>& rhs) const
0813 {
0814 return *new c2_sum_p<float_type>(get(), rhs);
0815 }
0816 c2_diff_p<float_type>&
0817 operator-(const c2_function<float_type>& rhs) const
0818 {
0819 return *new c2_diff_p<float_type>(get(), rhs);
0820 }
0821 c2_product_p<float_type>&
0822 operator*(const c2_function<float_type>& rhs) const
0823 {
0824 return *new c2_product_p<float_type>(get(), rhs);
0825 }
0826 c2_ratio_p<float_type>&
0827 operator/(const c2_function<float_type>& rhs) const
0828 {
0829 return *new c2_ratio_p<float_type>(get(), rhs);
0830 }
0831
0832
0833
0834 c2_composed_function_p<float_type>&
0835 operator()(const c2_function<float_type>& inner) const
0836 {
0837 return *new c2_composed_function_p<float_type>(get(), inner);
0838 }
0839
0840 protected:
0841 const c2_function<float_type>* func;
0842 };
0843
0844 template<typename float_type>
0845 class c2_ptr : public c2_const_ptr<float_type>
0846 {
0847 public:
0848
0849 c2_ptr() : c2_const_ptr<float_type>() {}
0850
0851
0852 c2_ptr(c2_function<float_type>& f) : c2_const_ptr<float_type>() { this->set_function(&f); }
0853
0854
0855 c2_ptr(const c2_ptr<float_type>& src) : c2_const_ptr<float_type>()
0856 {
0857 this->set_function(src.get_ptr());
0858 }
0859
0860 inline c2_function<float_type>& get() const
0861 {
0862 return *const_cast<c2_function<float_type>*>(&c2_const_ptr<float_type>::get());
0863 }
0864
0865 inline c2_function<float_type>* get_ptr() const
0866 {
0867 return const_cast<c2_function<float_type>*>(this->func);
0868 }
0869
0870 inline c2_function<float_type>* operator->() const { return &get(); }
0871
0872
0873 const c2_ptr<float_type>& operator=(const c2_ptr<float_type>& f)
0874 {
0875 this->set_function(f.get_ptr());
0876 return f;
0877 }
0878
0879
0880 c2_function<float_type>& operator=(c2_function<float_type>& f)
0881 {
0882 this->set_function(&f);
0883 return f;
0884 }
0885
0886 private:
0887
0888 void operator=(const c2_const_ptr<float_type>&) {}
0889
0890 void operator=(const c2_function<float_type>&) {}
0891 };
0892
0893 template<typename float_type, template<typename> class c2_class>
0894 class c2_typed_ptr : public c2_const_ptr<float_type>
0895 {
0896 public:
0897
0898 c2_typed_ptr() : c2_ptr<float_type>() {}
0899
0900
0901 c2_typed_ptr(c2_class<float_type>& f) : c2_const_ptr<float_type>() { this->set_function(&f); }
0902
0903
0904 c2_typed_ptr(const c2_typed_ptr<float_type, c2_class>& src) : c2_const_ptr<float_type>()
0905 {
0906 this->set_function(src.get_ptr());
0907 }
0908
0909
0910 inline c2_class<float_type>& get() const
0911 {
0912 return *static_cast<c2_class<float_type>*>(
0913 const_cast<c2_function<float_type>*>(&c2_const_ptr<float_type>::get()));
0914 }
0915
0916 inline c2_class<float_type>* operator->() const { return &get(); }
0917
0918 inline c2_class<float_type>* get_ptr() const
0919 {
0920 return static_cast<c2_class<float_type>*>(const_cast<c2_function<float_type>*>(this->func));
0921 }
0922
0923 operator c2_class<float_type>&() const { return get(); }
0924
0925
0926 void operator=(const c2_typed_ptr<float_type, c2_class>& f) { this->set_function(f.get_ptr()); }
0927
0928
0929 void operator=(c2_class<float_type>& f) { this->set_function(&f); }
0930
0931 private:
0932 void operator=(const c2_const_ptr<float_type>&) {}
0933 void operator=(const c2_function<float_type>&) {}
0934 };
0935
0936 template<typename float_type = double>
0937 class c2_plugin_function_p : public c2_function<float_type>
0938 {
0939 public:
0940
0941 c2_plugin_function_p() : c2_function<float_type>(), func() {}
0942
0943 c2_plugin_function_p(c2_function<float_type>& f) : c2_function<float_type>(), func(f) {}
0944
0945 void set_function(c2_function<float_type>* f)
0946 {
0947 func.set_function(f);
0948 if (f) this->set_domain(f->xmin(), f->xmax());
0949 }
0950
0951
0952 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
0953 float_type* yprime2) const
0954 {
0955 if (!func.valid()) throw c2_exception("c2_plugin_function_p called uninitialized");
0956 return func->value_with_derivatives(x, yprime, yprime2);
0957 }
0958
0959 virtual ~c2_plugin_function_p() {}
0960
0961
0962 void unset_function() { func.unset_function(); }
0963
0964 virtual void get_sampling_grid(float_type amin, float_type amax,
0965 std::vector<float_type>& grid) const
0966 {
0967 if (!func.valid()) throw c2_exception("c2_plugin_function_p called uninitialized");
0968 if (this->sampling_grid)
0969 c2_function<float_type>::get_sampling_grid(amin, amax, grid);
0970 else
0971 func->get_sampling_grid(amin, amax, grid);
0972 }
0973
0974 protected:
0975 c2_ptr<float_type> func;
0976 };
0977
0978 template<typename float_type = double>
0979 class c2_const_plugin_function_p : public c2_plugin_function_p<float_type>
0980 {
0981 public:
0982
0983 c2_const_plugin_function_p() : c2_plugin_function_p<float_type>() {}
0984
0985 c2_const_plugin_function_p(const c2_function<float_type>& f)
0986 : c2_plugin_function_p<float_type>()
0987 {
0988 this->set_function(&f);
0989 }
0990 void set_function(const c2_function<float_type>* f)
0991 {
0992 c2_plugin_function_p<float_type>::set_function(const_cast<c2_function<float_type>*>(f));
0993 }
0994
0995 virtual ~c2_const_plugin_function_p() {}
0996
0997
0998 const c2_function<float_type>& get() const
0999 {
1000 return this->func.get();
1001 }
1002 };
1003
1004 template<typename float_type = double>
1005 class c2_binary_function : public c2_function<float_type>
1006 {
1007 public:
1008 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1009 float_type* yprime2) const
1010 {
1011 if (stub) throw c2_exception("attempt to evaluate a c2_binary_function stub");
1012 return this->combine(*Left.get_ptr(), *Right.get_ptr(), x, yprime, yprime2);
1013 }
1014
1015
1016
1017 virtual ~c2_binary_function() {}
1018
1019 protected:
1020 c2_binary_function(float_type (*combiner)(const c2_function<float_type>& left,
1021 const c2_function<float_type>& right, float_type x,
1022 float_type* yprime, float_type* yprime2),
1023 const c2_function<float_type>& left, const c2_function<float_type>& right)
1024 : c2_function<float_type>(), combine(combiner), Left(left), Right(right), stub(false)
1025 {
1026 this->set_domain((left.xmin() > right.xmin()) ? left.xmin() : right.xmin(),
1027 (left.xmax() < right.xmax()) ? left.xmax() : right.xmax());
1028 }
1029 c2_binary_function(float_type (*combiner)(const c2_function<float_type>& left,
1030 const c2_function<float_type>& right, float_type x,
1031 float_type* yprime, float_type* yprime2))
1032 : c2_function<float_type>(), combine(combiner), Left(), Right(), stub(true)
1033 {}
1034
1035 public:
1036 float_type (*const combine)(const c2_function<float_type>& left,
1037 const c2_function<float_type>& right, float_type x,
1038 float_type* yprime, float_type* yprime2);
1039
1040 protected:
1041 const c2_const_ptr<float_type> Left, Right;
1042 bool stub;
1043 };
1044
1045 template<typename float_type = double>
1046 class c2_scaled_function_p : public c2_function<float_type>
1047 {
1048 public:
1049
1050
1051
1052
1053 c2_scaled_function_p(const c2_function<float_type>& outer, float_type scale)
1054 : c2_function<float_type>(), func(outer), yscale(scale)
1055 {}
1056
1057
1058
1059 void reset(float_type scale) { yscale = scale; }
1060
1061 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1062 float_type* yprime2) const
1063 {
1064 float_type y = this->func->value_with_derivatives(x, yprime, yprime2);
1065 if (yprime) (*yprime) *= yscale;
1066 if (yprime2) (*yprime2) *= yscale;
1067 return y * yscale;
1068 }
1069
1070 protected:
1071 c2_scaled_function_p(float_type scale) : func(), yscale(scale) {}
1072
1073 const c2_const_ptr<float_type> func;
1074 float_type yscale;
1075 };
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086 template<typename float_type = double>
1087 class c2_cached_function_p : public c2_function<float_type>
1088 {
1089 public:
1090
1091
1092
1093 c2_cached_function_p(const c2_function<float_type>& f)
1094 : c2_function<float_type>(), func(f), init(false)
1095 {}
1096
1097
1098 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1099 float_type* yprime2) const
1100 {
1101 if (!init || x != x0) {
1102 y = this->func->value_with_derivatives(x, &yp, &ypp);
1103 x0 = x;
1104 init = true;
1105 }
1106 if (yprime) *yprime = yp;
1107 if (yprime2) *yprime2 = ypp;
1108 return y;
1109 }
1110
1111 protected:
1112 c2_cached_function_p() : func() {}
1113 const c2_const_ptr<float_type> func;
1114 mutable bool init;
1115 mutable float_type x0, y, yp, ypp;
1116 };
1117
1118 template<typename float_type = double>
1119 class c2_composed_function_p : public c2_binary_function<float_type>
1120 {
1121 public:
1122 c2_composed_function_p(const c2_function<float_type>& outer,
1123 const c2_function<float_type>& inner)
1124 : c2_binary_function<float_type>(combine, outer, inner)
1125 {
1126 this->set_domain(inner.xmin(), inner.xmax());
1127 }
1128
1129 c2_composed_function_p() : c2_binary_function<float_type>(combine) {}
1130
1131
1132 static float_type combine(const c2_function<float_type>& left,
1133 const c2_function<float_type>& right, float_type x,
1134 float_type* yprime, float_type* yprime2)
1135 {
1136 float_type y0, y1;
1137 if (yprime || yprime2) {
1138 float_type yp0, ypp0, yp1, ypp1;
1139 y0 = right.value_with_derivatives(x, &yp0, &ypp0);
1140 y1 = left.value_with_derivatives(y0, &yp1, &ypp1);
1141 if (yprime) *yprime = yp1 * yp0;
1142 if (yprime2) *yprime2 = ypp0 * yp1 + yp0 * yp0 * ypp1;
1143 }
1144 else {
1145 y0 = right(x);
1146 y1 = left(y0);
1147 }
1148 return y1;
1149 }
1150 };
1151
1152 template<typename float_type = double>
1153 class c2_sum_p : public c2_binary_function<float_type>
1154 {
1155 public:
1156
1157
1158
1159 c2_sum_p(const c2_function<float_type>& left, const c2_function<float_type>& right)
1160 : c2_binary_function<float_type>(combine, left, right)
1161 {}
1162
1163 c2_sum_p() : c2_binary_function<float_type>(combine) {};
1164
1165
1166 static float_type combine(const c2_function<float_type>& left,
1167 const c2_function<float_type>& right, float_type x,
1168 float_type* yprime, float_type* yprime2)
1169 {
1170 float_type y0, y1;
1171 if (yprime || yprime2) {
1172 float_type yp0, ypp0, yp1, ypp1;
1173 y0 = left.value_with_derivatives(x, &yp0, &ypp0);
1174 y1 = right.value_with_derivatives(x, &yp1, &ypp1);
1175 if (yprime) *yprime = yp0 + yp1;
1176 if (yprime2) *yprime2 = ypp0 + ypp1;
1177 }
1178 else {
1179 y0 = left(x);
1180 y1 = right(x);
1181 }
1182 return y0 + y1;
1183 }
1184 };
1185
1186 template<typename float_type = double>
1187 class c2_diff_p : public c2_binary_function<float_type>
1188 {
1189 public:
1190
1191
1192
1193 c2_diff_p(const c2_function<float_type>& left, const c2_function<float_type>& right)
1194 : c2_binary_function<float_type>(combine, left, right)
1195 {}
1196
1197 c2_diff_p() : c2_binary_function<float_type>(combine) {};
1198
1199
1200 static float_type combine(const c2_function<float_type>& left,
1201 const c2_function<float_type>& right, float_type x,
1202 float_type* yprime, float_type* yprime2)
1203 {
1204 float_type y0, y1;
1205 if (yprime || yprime2) {
1206 float_type yp0, ypp0, yp1, ypp1;
1207 y0 = left.value_with_derivatives(x, &yp0, &ypp0);
1208 y1 = right.value_with_derivatives(x, &yp1, &ypp1);
1209 if (yprime) *yprime = yp0 - yp1;
1210 if (yprime2) *yprime2 = ypp0 - ypp1;
1211 }
1212 else {
1213 y0 = left(x);
1214 y1 = right(x);
1215 }
1216 return y0 - y1;
1217 }
1218 };
1219
1220
1221
1222
1223 template<typename float_type = double>
1224 class c2_product_p : public c2_binary_function<float_type>
1225 {
1226 public:
1227
1228
1229
1230 c2_product_p(const c2_function<float_type>& left, const c2_function<float_type>& right)
1231 : c2_binary_function<float_type>(combine, left, right)
1232 {}
1233
1234 c2_product_p() : c2_binary_function<float_type>(combine) {};
1235
1236
1237 static float_type combine(const c2_function<float_type>& left,
1238 const c2_function<float_type>& right, float_type x,
1239 float_type* yprime, float_type* yprime2)
1240 {
1241 float_type y0, y1;
1242 if (yprime || yprime2) {
1243 float_type yp0, ypp0, yp1, ypp1;
1244 y0 = left.value_with_derivatives(x, &yp0, &ypp0);
1245 y1 = right.value_with_derivatives(x, &yp1, &ypp1);
1246 if (yprime) *yprime = y1 * yp0 + y0 * yp1;
1247 if (yprime2) *yprime2 = ypp0 * y1 + 2.0 * yp0 * yp1 + ypp1 * y0;
1248 }
1249 else {
1250 y0 = left(x);
1251 y1 = right(x);
1252 }
1253 return y0 * y1;
1254 }
1255 };
1256
1257
1258
1259
1260 template<typename float_type = double>
1261 class c2_ratio_p : public c2_binary_function<float_type>
1262 {
1263 public:
1264
1265
1266
1267 c2_ratio_p(const c2_function<float_type>& left, const c2_function<float_type>& right)
1268 : c2_binary_function<float_type>(combine, left, right)
1269 {}
1270
1271 c2_ratio_p() : c2_binary_function<float_type>(combine) {};
1272
1273
1274 static float_type combine(const c2_function<float_type>& left,
1275 const c2_function<float_type>& right, float_type x,
1276 float_type* yprime, float_type* yprime2)
1277 {
1278 float_type y0, y1;
1279 if (yprime || yprime2) {
1280 float_type yp0, ypp0, yp1, ypp1;
1281 y0 = left.value_with_derivatives(x, &yp0, &ypp0);
1282 y1 = right.value_with_derivatives(x, &yp1, &ypp1);
1283 if (yprime) *yprime = (yp0 * y1 - y0 * yp1) / (y1 * y1);
1284 if (yprime2)
1285 *yprime2 = (y1 * y1 * ypp0 + y0 * (2 * yp1 * yp1 - y1 * ypp1) - 2 * y1 * yp0 * yp1)
1286 / (y1 * y1 * y1);
1287 }
1288 else {
1289 y0 = left(x);
1290 y1 = right(x);
1291 }
1292 return y0 / y1;
1293 }
1294 };
1295
1296
1297
1298
1299
1300 template<typename float_type>
1301 class c2_constant_p : public c2_function<float_type>
1302 {
1303 public:
1304 c2_constant_p(float_type x) : c2_function<float_type>(), value(x) {}
1305 void reset(float_type val) { value = val; }
1306 virtual float_type value_with_derivatives(float_type, float_type* yprime,
1307 float_type* yprime2) const
1308 {
1309 if (yprime) *yprime = 0;
1310 if (yprime2) *yprime2 = 0;
1311 return value;
1312 }
1313
1314 private:
1315 float_type value;
1316 };
1317
1318
1319
1320 template<typename float_type>
1321 class c2_transformation
1322 {
1323 public:
1324
1325
1326
1327
1328
1329
1330 c2_transformation(bool transformed, float_type (*xin)(float_type),
1331 float_type (*xinp)(float_type), float_type (*xinpp)(float_type),
1332 float_type (*xout)(float_type))
1333 : fTransformed(transformed),
1334 fHasStaticTransforms(true),
1335 pIn(xin),
1336 pInPrime(xinp),
1337 pInDPrime(xinpp),
1338 pOut(xout)
1339 {}
1340
1341
1342
1343
1344 c2_transformation(bool transformed)
1345 : fTransformed(transformed),
1346 fHasStaticTransforms(false),
1347 pIn(report_error),
1348 pInPrime(report_error),
1349 pInDPrime(report_error),
1350 pOut(report_error)
1351 {}
1352
1353 virtual ~c2_transformation() {}
1354
1355 const bool fTransformed;
1356
1357
1358 const bool fHasStaticTransforms;
1359
1360
1361
1362
1363
1364
1365 float_type (*const pIn)(float_type);
1366
1367 float_type (*const pInPrime)(float_type);
1368
1369 float_type (*const pInDPrime)(float_type);
1370
1371 float_type (*const pOut)(float_type);
1372
1373
1374 virtual float_type fIn(float_type x) const { return pIn(x); }
1375
1376 virtual float_type fInPrime(float_type x) const { return pInPrime(x); }
1377
1378 virtual float_type fInDPrime(float_type x) const { return pInDPrime(x); }
1379
1380 virtual float_type fOut(float_type x) const { return pOut(x); }
1381
1382 protected:
1383
1384 static float_type report_error(float_type x)
1385 {
1386 throw c2_exception("use of improperly constructed axis transform");
1387 return x;
1388 }
1389
1390 static float_type ident(float_type x) { return x; }
1391
1392 static float_type one(float_type) { return 1; }
1393
1394 static float_type zero(float_type) { return 0; }
1395
1396 static float_type recip(float_type x) { return 1.0 / x; }
1397
1398 static float_type recip_prime(float_type x) { return -1 / (x * x); }
1399
1400 static float_type recip_prime2(float_type x) { return 2 / (x * x * x); }
1401 };
1402
1403
1404
1405 template<typename float_type>
1406 class c2_transformation_linear : public c2_transformation<float_type>
1407 {
1408 public:
1409
1410 c2_transformation_linear()
1411 : c2_transformation<float_type>(false, this->ident, this->one, this->zero, this->ident)
1412 {}
1413
1414 virtual ~c2_transformation_linear() {}
1415 };
1416
1417
1418 template<typename float_type>
1419 class c2_transformation_log : public c2_transformation<float_type>
1420 {
1421 public:
1422
1423 c2_transformation_log()
1424 : c2_transformation<float_type>(true, std::log, this->recip, this->recip_prime, std::exp)
1425 {}
1426
1427 virtual ~c2_transformation_log() {}
1428 };
1429
1430
1431 template<typename float_type>
1432 class c2_transformation_recip : public c2_transformation<float_type>
1433 {
1434 public:
1435
1436 c2_transformation_recip()
1437 : c2_transformation<float_type>(true, this->recip, this->recip_prime, this->recip_prime2,
1438 this->recip)
1439 {}
1440
1441 virtual ~c2_transformation_recip() {}
1442 };
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453 template<typename float_type>
1454 class c2_function_transformation
1455 {
1456 public:
1457
1458
1459
1460 c2_function_transformation(const c2_transformation<float_type>& xx,
1461 const c2_transformation<float_type>& yy)
1462 : isIdentity(!(xx.fTransformed || yy.fTransformed)), X(xx), Y(yy)
1463 {}
1464
1465 virtual ~c2_function_transformation()
1466 {
1467 delete &X;
1468 delete &Y;
1469 }
1470 virtual float_type evaluate(float_type xraw, float_type y, float_type yp0, float_type ypp0,
1471 float_type* yprime, float_type* yprime2) const;
1472 const bool isIdentity;
1473
1474 const c2_transformation<float_type>& X;
1475
1476 const c2_transformation<float_type>& Y;
1477 };
1478
1479
1480
1481
1482 template<typename float_type>
1483 class c2_lin_lin_function_transformation : public c2_function_transformation<float_type>
1484 {
1485 public:
1486 c2_lin_lin_function_transformation()
1487 : c2_function_transformation<float_type>(*new c2_transformation_linear<float_type>,
1488 *new c2_transformation_linear<float_type>)
1489 {}
1490 virtual ~c2_lin_lin_function_transformation() {}
1491 };
1492
1493
1494
1495
1496 template<typename float_type>
1497 class c2_log_log_function_transformation : public c2_function_transformation<float_type>
1498 {
1499 public:
1500 c2_log_log_function_transformation()
1501 : c2_function_transformation<float_type>(*new c2_transformation_log<float_type>,
1502 *new c2_transformation_log<float_type>)
1503 {}
1504 virtual ~c2_log_log_function_transformation() {}
1505 };
1506
1507
1508
1509
1510 template<typename float_type>
1511 class c2_lin_log_function_transformation : public c2_function_transformation<float_type>
1512 {
1513 public:
1514 c2_lin_log_function_transformation()
1515 : c2_function_transformation<float_type>(*new c2_transformation_linear<float_type>,
1516 *new c2_transformation_log<float_type>)
1517 {}
1518 virtual ~c2_lin_log_function_transformation() {}
1519 };
1520
1521
1522
1523
1524 template<typename float_type>
1525 class c2_log_lin_function_transformation : public c2_function_transformation<float_type>
1526 {
1527 public:
1528 c2_log_lin_function_transformation()
1529 : c2_function_transformation<float_type>(*new c2_transformation_log<float_type>,
1530 *new c2_transformation_linear<float_type>)
1531 {}
1532 virtual ~c2_log_lin_function_transformation() {}
1533 };
1534
1535
1536
1537
1538
1539 template<typename float_type>
1540 class c2_arrhenius_function_transformation : public c2_function_transformation<float_type>
1541 {
1542 public:
1543 c2_arrhenius_function_transformation()
1544 : c2_function_transformation<float_type>(*new c2_transformation_recip<float_type>,
1545 *new c2_transformation_log<float_type>)
1546 {}
1547 virtual ~c2_arrhenius_function_transformation() {}
1548 };
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591 template<typename float_type = double>
1592 class interpolating_function_p : public c2_function<float_type>
1593 {
1594 public:
1595
1596
1597 interpolating_function_p()
1598 : c2_function<float_type>(), fTransform(*new c2_lin_lin_function_transformation<float_type>)
1599 {}
1600
1601
1602
1603
1604 interpolating_function_p(const c2_function_transformation<float_type>& transform)
1605 : c2_function<float_type>(), fTransform(transform)
1606 {}
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630 interpolating_function_p<float_type>& load(const std::vector<float_type>& x,
1631 const std::vector<float_type>& f,
1632 bool lowerSlopeNatural, float_type lowerSlope,
1633 bool upperSlopeNatural, float_type upperSlope,
1634 bool splined = true) ;
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651 interpolating_function_p<float_type>&
1652 load_pairs(std::vector<std::pair<float_type, float_type>>& data, bool lowerSlopeNatural,
1653 float_type lowerSlope, bool upperSlopeNatural, float_type upperSlope,
1654 bool splined = true) ;
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690 interpolating_function_p<float_type>&
1691 sample_function(const c2_function<float_type>& func, float_type amin, float_type amax,
1692 float_type abs_tol, float_type rel_tol, bool lowerSlopeNatural,
1693 float_type lowerSlope, bool upperSlopeNatural,
1694 float_type upperSlope) ;
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720 interpolating_function_p<float_type>&
1721 load_random_generator_function(const std::vector<float_type>& bincenters,
1722 const c2_function<float_type>& binheights)
1723 ;
1724
1725 interpolating_function_p<float_type>&
1726 load_random_generator_bins(const std::vector<float_type>& bins,
1727 const std::vector<float_type>& binheights, bool splined = true)
1728 ;
1729
1730 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1731 float_type* yprime2) const ;
1732
1733
1734 virtual ~interpolating_function_p() { delete &fTransform; }
1735
1736 virtual interpolating_function_p<float_type>& clone() const
1737 {
1738 return *new interpolating_function_p<float_type>();
1739 }
1740
1741 void get_data(std::vector<float_type>& xvals, std::vector<float_type>& yvals) const
1742 ;
1743
1744 void get_internal_data(std::vector<float_type>& xvals, std::vector<float_type>& yvals,
1745 std::vector<float_type>& y2vals) const
1746 {
1747 xvals = X;
1748 yvals = F;
1749 y2vals = y2;
1750 }
1751
1752 void set_lower_extrapolation(float_type bound);
1753 void set_upper_extrapolation(float_type bound);
1754
1755 interpolating_function_p<float_type>&
1756 unary_operator(const c2_function<float_type>& source) const;
1757
1758 interpolating_function_p<float_type>&
1759 binary_operator(const c2_function<float_type>& rhs,
1760 const c2_binary_function<float_type>* combining_stub) const;
1761 interpolating_function_p<float_type>& add_pointwise(const c2_function<float_type>& rhs) const
1762 {
1763 return binary_operator(rhs, new c2_sum_p<float_type>());
1764 }
1765 interpolating_function_p<float_type>&
1766 subtract_pointwise(const c2_function<float_type>& rhs) const
1767 {
1768 return binary_operator(rhs, new c2_diff_p<float_type>());
1769 }
1770 interpolating_function_p<float_type>&
1771 multiply_pointwise(const c2_function<float_type>& rhs) const
1772 {
1773 return binary_operator(rhs, new c2_product_p<float_type>());
1774 }
1775 interpolating_function_p<float_type>& divide_pointwise(const c2_function<float_type>& rhs) const
1776 {
1777 return binary_operator(rhs, new c2_ratio_p<float_type>());
1778 }
1779 void clone_data(const interpolating_function_p<float_type>& rhs)
1780 {
1781 Xraw = rhs.Xraw;
1782 X = rhs.X;
1783 F = rhs.F;
1784 y2 = rhs.y2;
1785 set_sampling_grid_pointer(Xraw);
1786 }
1787
1788 const c2_function_transformation<float_type>& fTransform;
1789
1790 protected:
1791
1792 void spline(bool lowerSlopeNatural, float_type lowerSlope, bool upperSlopeNatural,
1793 float_type upperSlope) ;
1794
1795 static bool comp_pair(std::pair<float_type, float_type> const& i,
1796 std::pair<float_type, float_type> const& j)
1797 {
1798 return i.first < j.first;
1799 }
1800
1801 std::vector<float_type> Xraw, X, F, y2;
1802 c2_const_ptr<float_type> sampler_function;
1803 bool xInverted;
1804 mutable size_t lastKLow;
1805 };
1806
1807
1808
1809
1810 template<typename float_type = double>
1811 class log_lin_interpolating_function_p : public interpolating_function_p<float_type>
1812 {
1813 public:
1814
1815
1816 log_lin_interpolating_function_p()
1817 : interpolating_function_p<float_type>(*new c2_log_lin_function_transformation<float_type>)
1818 {}
1819 virtual interpolating_function_p<float_type>& clone() const
1820 {
1821 return *new log_lin_interpolating_function_p<float_type>();
1822 }
1823 };
1824
1825
1826
1827
1828
1829 template<typename float_type = double>
1830 class lin_log_interpolating_function_p : public interpolating_function_p<float_type>
1831 {
1832 public:
1833
1834
1835 lin_log_interpolating_function_p()
1836 : interpolating_function_p<float_type>(*new c2_lin_log_function_transformation<float_type>)
1837 {}
1838 virtual interpolating_function_p<float_type>& clone() const
1839 {
1840 return *new lin_log_interpolating_function_p<float_type>();
1841 }
1842 };
1843
1844
1845
1846
1847
1848
1849 template<typename float_type = double>
1850 class log_log_interpolating_function_p : public interpolating_function_p<float_type>
1851 {
1852 public:
1853
1854
1855 log_log_interpolating_function_p()
1856 : interpolating_function_p<float_type>(*new c2_log_log_function_transformation<float_type>)
1857 {}
1858 virtual interpolating_function_p<float_type>& clone() const
1859 {
1860 return *new log_log_interpolating_function_p<float_type>();
1861 }
1862 };
1863
1864
1865
1866
1867
1868
1869 template<typename float_type = double>
1870 class arrhenius_interpolating_function_p : public interpolating_function_p<float_type>
1871 {
1872 public:
1873
1874
1875 arrhenius_interpolating_function_p()
1876 : interpolating_function_p<float_type>(*new c2_arrhenius_function_transformation<float_type>)
1877 {}
1878 virtual interpolating_function_p<float_type>& clone() const
1879 {
1880 return *new arrhenius_interpolating_function_p<float_type>();
1881 }
1882 };
1883
1884
1885
1886
1887
1888 template<typename float_type = double>
1889 class c2_sin_p : public c2_function<float_type>
1890 {
1891 public:
1892
1893 c2_sin_p() : c2_function<float_type>() {}
1894
1895 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1896 float_type* yprime2) const
1897 {
1898 float_type q = std::sin(x);
1899 if (yprime) *yprime = std::cos(x);
1900 if (yprime2) *yprime2 = -q;
1901 return q;
1902 }
1903
1904 virtual void get_sampling_grid(float_type amin, float_type amax,
1905 std::vector<float_type>& grid) const;
1906 };
1907
1908
1909
1910
1911
1912 template<typename float_type = double>
1913 class c2_cos_p : public c2_sin_p<float_type>
1914 {
1915 public:
1916
1917 c2_cos_p() : c2_sin_p<float_type>() {}
1918
1919 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1920 float_type* yprime2) const
1921 {
1922 float_type q = std::cos(x);
1923 if (yprime) *yprime = -std::sin(x);
1924 if (yprime2) *yprime2 = -q;
1925 return q;
1926 }
1927 };
1928
1929
1930
1931
1932
1933 template<typename float_type = double>
1934 class c2_tan_p : public c2_function<float_type>
1935 {
1936 public:
1937
1938 c2_tan_p() : c2_function<float_type>() {}
1939
1940 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1941 float_type* yprime2) const
1942 {
1943 float_type c = std::cos(x), ss = std::sin(x);
1944 float_type t = ss / c;
1945 float_type yp = 1 / (c * c);
1946 if (yprime) {
1947 *yprime = yp;
1948 }
1949 if (yprime2) {
1950 *yprime2 = 2 * t * yp;
1951 }
1952 return t;
1953 }
1954 };
1955
1956
1957
1958
1959
1960 template<typename float_type = double>
1961 class c2_log_p : public c2_function<float_type>
1962 {
1963 public:
1964
1965 c2_log_p() : c2_function<float_type>() {}
1966
1967 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1968 float_type* yprime2) const
1969 {
1970 if (yprime) *yprime = 1.0 / x;
1971 if (yprime2) *yprime2 = -1.0 / (x * x);
1972 return std::log(x);
1973 }
1974 };
1975
1976
1977
1978
1979
1980 template<typename float_type = double>
1981 class c2_exp_p : public c2_function<float_type>
1982 {
1983 public:
1984
1985 c2_exp_p() : c2_function<float_type>() {}
1986
1987 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1988 float_type* yprime2) const
1989 {
1990 float_type q = std::exp(x);
1991 if (yprime) *yprime = q;
1992 if (yprime2) *yprime2 = q;
1993 return q;
1994 }
1995 };
1996
1997
1998
1999
2000
2001 template<typename float_type = double>
2002 class c2_sqrt_p : public c2_function<float_type>
2003 {
2004 public:
2005
2006 c2_sqrt_p() : c2_function<float_type>() {}
2007
2008 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2009 float_type* yprime2) const
2010 {
2011 float_type q = std::sqrt(x);
2012 if (yprime) *yprime = 0.5 / q;
2013 if (yprime2) *yprime2 = -0.25 / (x * q);
2014 return q;
2015 }
2016 };
2017
2018
2019
2020
2021
2022 template<typename float_type = double>
2023 class c2_recip_p : public c2_function<float_type>
2024 {
2025 public:
2026
2027 c2_recip_p(float_type scale) : c2_function<float_type>(), rscale(scale) {}
2028
2029 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2030 float_type* yprime2) const
2031 {
2032 float_type q = 1.0 / x;
2033 float_type y = rscale * q;
2034 if (yprime) *yprime = -y * q;
2035 if (yprime2) *yprime2 = 2 * y * q * q;
2036 return y;
2037 }
2038
2039
2040 void reset(float_type scale) { rscale = scale; }
2041
2042 private:
2043 float_type rscale;
2044 };
2045
2046
2047
2048
2049
2050 template<typename float_type = double>
2051 class c2_identity_p : public c2_function<float_type>
2052 {
2053 public:
2054
2055 c2_identity_p() : c2_function<float_type>() {}
2056
2057 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2058 float_type* yprime2) const
2059 {
2060 if (yprime) *yprime = 1.0;
2061 if (yprime2) *yprime2 = 0;
2062 return x;
2063 }
2064 };
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077 template<typename float_type = double>
2078 class c2_linear_p : public c2_function<float_type>
2079 {
2080 public:
2081
2082
2083
2084
2085 c2_linear_p(float_type x0, float_type y0, float_type slope)
2086 : c2_function<float_type>(), xint(x0), intercept(y0), m(slope)
2087 {}
2088
2089
2090
2091
2092 void reset(float_type x0, float_type y0, float_type slope)
2093 {
2094 xint = x0;
2095 intercept = y0;
2096 m = slope;
2097 }
2098 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2099 float_type* yprime2) const
2100 {
2101 if (yprime) *yprime = m;
2102 if (yprime2) *yprime2 = 0;
2103 return m * (x - xint) + intercept;
2104 }
2105
2106 private:
2107 float_type xint, intercept, m;
2108
2109 protected:
2110 c2_linear_p() {}
2111 };
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127 template<typename float_type = double>
2128 class c2_quadratic_p : public c2_function<float_type>
2129 {
2130 public:
2131
2132
2133
2134
2135
2136 c2_quadratic_p(float_type x0, float_type y0, float_type xcoef, float_type x2coef)
2137 : c2_function<float_type>(), intercept(y0), center(x0), a(x2coef), b(xcoef)
2138 {}
2139
2140
2141
2142
2143
2144 void reset(float_type x0, float_type y0, float_type xcoef, float_type x2coef)
2145 {
2146 intercept = y0;
2147 center = x0;
2148 a = x2coef;
2149 b = xcoef;
2150 }
2151 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2152 float_type* yprime2) const
2153 {
2154 float_type dx = x - center;
2155 if (yprime) *yprime = 2 * a * dx + b;
2156 if (yprime2) *yprime2 = 2 * a;
2157 return a * dx * dx + b * dx + intercept;
2158 }
2159
2160 private:
2161 float_type intercept, center, a, b;
2162
2163 protected:
2164 c2_quadratic_p() {}
2165 };
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179 template<typename float_type = double>
2180 class c2_power_law_p : public c2_function<float_type>
2181 {
2182 public:
2183
2184
2185
2186 c2_power_law_p(float_type scale, float_type power)
2187 : c2_function<float_type>(), a(scale), b(power)
2188 {}
2189
2190
2191
2192 void reset(float_type scale, float_type power)
2193 {
2194 a = scale;
2195 b = power;
2196 }
2197 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2198 float_type* yprime2) const
2199 {
2200 float_type q = a * std::pow(x, b - 2);
2201 if (yprime) *yprime = b * q * x;
2202 if (yprime2) *yprime2 = b * (b - 1) * q;
2203 return q * x * x;
2204 }
2205
2206 private:
2207 float_type a, b;
2208
2209 protected:
2210 c2_power_law_p() {}
2211 };
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230 template<typename float_type = double>
2231 class c2_inverse_function_p : public c2_function<float_type>
2232 {
2233 public:
2234
2235
2236 c2_inverse_function_p(const c2_function<float_type>& source);
2237 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2238 float_type* yprime2) const ;
2239
2240
2241
2242
2243 void set_start_hint(float_type hint) const { start_hint = hint; }
2244
2245 virtual float_type get_start_hint(float_type x) const
2246 {
2247 return hinting_function.valid() ? hinting_function(x) : start_hint;
2248 }
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275 void set_hinting_function(const c2_function<float_type>* hint_func)
2276 {
2277 hinting_function.set_function(hint_func);
2278 }
2279
2280
2281
2282
2283 void set_hinting_function(const c2_const_ptr<float_type> hint_func)
2284 {
2285 hinting_function = hint_func;
2286 }
2287
2288 protected:
2289 c2_inverse_function_p() {}
2290 mutable float_type start_hint;
2291 const c2_const_ptr<float_type> func;
2292 c2_const_ptr<float_type> hinting_function;
2293 };
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308 template<typename float_type = double>
2309 class accumulated_histogram : public interpolating_function_p<float_type>
2310 {
2311 public:
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321 accumulated_histogram(const std::vector<float_type> binedges,
2322 const std::vector<float_type> binheights, bool normalize = false,
2323 bool inverse_function = false, bool drop_zeros = true);
2324 };
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349 template<typename float_type = double>
2350 class c2_connector_function_p : public c2_function<float_type>
2351 {
2352 public:
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363 c2_connector_function_p(float_type x0, const c2_function<float_type>& f0, float_type x2,
2364 const c2_function<float_type>& f2, bool auto_center, float_type y1);
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380 c2_connector_function_p(float_type x0, float_type y0, float_type yp0, float_type ypp0,
2381 float_type x2, float_type y2, float_type yp2, float_type ypp2,
2382 bool auto_center, float_type y1);
2383
2384
2385
2386
2387
2388
2389
2390
2391 c2_connector_function_p(const c2_fblock<float_type>& fb0, const c2_fblock<float_type>& fb2,
2392 bool auto_center, float_type y1);
2393
2394
2395 virtual ~c2_connector_function_p();
2396 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2397 float_type* yprime2) const ;
2398
2399 protected:
2400
2401 void init(const c2_fblock<float_type>& fb0, const c2_fblock<float_type>& fb2, bool auto_center,
2402 float_type y1);
2403
2404 float_type fhinv, fy1, fa, fb, fc, fd, fe, ff;
2405 };
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432 template<typename float_type = double>
2433 class c2_piecewise_function_p : public c2_function<float_type>
2434 {
2435 public:
2436
2437 c2_piecewise_function_p();
2438
2439 virtual ~c2_piecewise_function_p();
2440 virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2441 float_type* yprime2) const ;
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454 void append_function(const c2_function<float_type>& func)
2455 ;
2456
2457 protected:
2458 std::vector<c2_const_ptr<float_type>> functions;
2459 mutable int lastKLow;
2460 };
2461
2462 #include "c2_function.icc"
2463
2464 #endif