Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-23 09:21:02

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 /**
0027  *  \file electromagnetic/TestEm7/include/c2_function.hh
0028  *  \brief Provides the headers for the general c2_function algebra which
0029  *  fast, flexible operations on piecewise-twice-differentiable functions
0030  *
0031  *  \author Created by R. A. Weller and Marcus H. Mendenhall on 7/9/05.
0032  *  \author Copyright 2005 __Vanderbilt University__. All rights reserved.
0033  *
0034  *         \version c2_function.hh 490 2012-04-10 19:05:40Z marcus
0035  *  \see \ref c2_factory "Factory Functions" for information on constructing
0036  */
0037 
0038 //
0039 
0040 #ifndef __has_c2_function_hh
0041 #define __has_c2_function_hh 1
0042 
0043 // MSVC does not automatically define numerical constants such as M_PI
0044 // this came from the msdn website, so it should be right...
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 /// \brief the exception class for c2_function operations.
0062 class c2_exception : public std::exception
0063 {
0064   public:
0065     /// \brief construct the exception with an error message
0066     /// \param msgcode the message
0067     c2_exception(const char msgcode[]) : info(msgcode) {}
0068     virtual ~c2_exception() throw() {}
0069     /** Returns a C-style character string describing the general cause
0070      *  of the current error.  */
0071     virtual const char* what() const throw() { return info.c_str(); }
0072 
0073   private:
0074     std::string info;
0075 };
0076 
0077 // put these forward references here, and with a bogus typename to make swig
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         \defgroup abstract_classes Abstract Classes
0096         \defgroup arithmetic_functions Arithmetic Functions
0097         \defgroup math_functions Mathemetical Functions
0098         \defgroup parametric_functions Parametric Families of Functions
0099         \defgroup interpolators Interpolating Functions
0100         \defgroup containers Functions which are containers for, or functions
0101                   of, other functions
0102         \defgroup factories Factory classes which reduce silly template typing
0103         \defgroup transforms Classes which provide coordinate system
0104                   transformations,
0105         \defgroup with derivatives
0106 */
0107 
0108 /// \brief structure used to hold evaluated function data at a point.
0109 ///
0110 /// Contains all the information for the function at one point.
0111 template<typename float_type>
0112 class c2_fblock
0113 {
0114   public:
0115     /// \brief the abscissa
0116     float_type x;
0117     /// \brief the value of the function at \a x
0118     float_type y;
0119     /// \brief the derivative at \a x
0120     float_type yp;
0121     /// \brief the second derivative at \a x
0122     float_type ypp;
0123     /// flag, filled in by c2_function::fill_fblock(),
0124     /// indicating the derivative is NaN of Inf
0125     bool ypbad;
0126     /// is NaN of Inf
0127     bool yppbad;
0128 };
0129 
0130 /**
0131  \brief the parent class for all c2_functions.
0132  \ingroup abstract_classes
0133   c2_functions know their value, first, and second derivative at
0134   almost every point.
0135   They can be efficiently combined with binary operators,
0136   via c2_binary_function,
0137   composed via c2_composed_function_,
0138   have their roots found via find_root(),
0139   and be adaptively integrated via partial_integrals() or integral().
0140   They also can carry information with them about how to find 'interesting'
0141   points on the function.
0142   This information is set with set_sampling_grid() and extracted with
0143   get_sampling_grid().
0144 
0145   Particularly important subclasses are the interpolating functions classes,
0146   interpolating_function , lin_log_interpolating_function,
0147   log_lin_interpolating_function,
0148     log_log_interpolating_function, and arrhenius_interpolating_function,
0149     as well as the template functions
0150     inverse_integrated_density_function().
0151 
0152  For a discussion of memory management, see ref memory_management
0153 
0154  */
0155 template<typename float_type = double>
0156 class c2_function
0157 {
0158   public:
0159     /// \brief get versioning information for the header file
0160     /// \return the CVS Id string
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     /// \brief get versioning information for the source file
0167     /// \return the CVS Id string
0168     const std::string cvs_file_vers() const;
0169 
0170   public:
0171     /// \brief destructor
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         // throw c2_exception(outstr.str().c_str());
0181       }
0182     }
0183 
0184     /// \brief get the value and derivatives.
0185     ///
0186     /// There is required checking for null pointers on the derivatives,
0187     /// and most implementations should operate faster if derivatives are not
0188     /// \param[in] x the point at which to evaluate the function
0189     /// \param[out] yprime the first derivative (if pointer is non-null)
0190     /// \param[out] yprime2 the second derivative (if pointer is non-null)
0191     /// \return the value of the function
0192     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
0193                                               float_type* yprime2) const /* throw(c2_exception) */
0194       = 0;
0195 
0196     /// \brief evaluate the function in the classic way, ignoring derivatives.
0197     /// \param x the point at which to evaluate
0198     /// \return the value of the function
0199     inline float_type operator()(float_type x) const /* throw(c2_exception) */
0200     {
0201       return value_with_derivatives(x, (float_type*)0, (float_type*)0);
0202     }
0203 
0204     /// \brief get the value and derivatives.
0205     ///
0206     /// \param[in] x the point at which to evaluate the function
0207     /// \param[out] yprime the first derivative (if pointer is non-null)
0208     /// \param[out] yprime2 the second derivative (if pointer is non-null)
0209     /// \return the value of the function
0210     inline float_type operator()(float_type x, float_type* yprime,
0211                                  float_type* yprime2) const /* throw(c2_exception) */
0212     {
0213       return value_with_derivatives(x, yprime, yprime2);
0214     }
0215 
0216     /// \brief solve f(x)==value very efficiently, with explicit knowledge
0217     /// of derivatives of the function
0218     ///
0219     /// find_root solves by iterated inverse quadratic extrapolation
0220     /// for a solution
0221     /// to f(x)=y.  It includes checks against bad convergence, so it should
0222     /// never be
0223     /// able to fail.  Unlike typical secant method or fancier Brent's
0224     /// method finders,
0225     /// this does not depend in any strong wasy on the brackets,
0226     /// unless the finder has
0227     /// to resort to successive approximations to close in on a root.
0228     /// Often, it is possible
0229     /// to make the brackets equal to the domain of the function, if there is
0230     /// any clue as to where the root lies, as given by the parameter \a start.
0231     /// \param lower_bracket the lower bound for the search
0232     /// \param upper_bracket the upper bound for the search.
0233     /// Function sign must be
0234     /// opposite to that at \a lower_bracket
0235     /// \param start starting value for the search
0236     /// \param value the value of the function being sought
0237     /// (solves f(x) = \a value)
0238     /// \param[out] error If pointer is zero, errors raise exception.
0239     /// Otherwise, returns error here.
0240     /// \param[out] final_yprime If pointer is not zero,
0241     /// return derivative of function
0242     /// at root
0243     /// \param[out] final_yprime2 If pointer is not zero,
0244     /// return second derivative of
0245     /// function at root
0246     /// \return the position of the root.
0247     /// \see ref rootfinder_subsec "Root finding sample"
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 /* throw(c2_exception) */;
0251     /// solve f(x)=value
0252     /// partial_integrals uses a method with an error O(dx**10) with
0253     /// full information from
0254     /// the derivatives, and falls back to lower order methods
0255     /// if informed of incomplete
0256     /// derivatives. It uses exact midpoint splitting of the intervals
0257     /// for recursion,
0258     /// resulting in no recomputation of the function during recursive
0259     /// descent at previously
0260     /// computed points.
0261     /// \param xgrid points between which to evaluate definite integrals.
0262     /// \param partials if non-NULL, a vector in which to receive the
0263     /// partial integrals.
0264     /// It will automatically be sized apprpropriately,
0265     /// if provided, to contain \a n - 1
0266     /// elements where \a n is the length of \a xgrid
0267     /// \param abs_tol the absolute error bound for each segment
0268     /// \param rel_tol the fractional error bound for each segment.
0269     /// If the error is smaller than either the relative or absolute tolerance,
0270     /// the integration step is finished.
0271     /// \param derivs number of derivatives to trust,
0272     /// which sets the order of the integrator.
0273     /// The order is 3*\a derivs + 4. \a derivs can be 0, 1, or 2.
0274     /// \param adapt if true, use recursive adaptation,
0275     /// otherwise do simple evaluation on
0276     /// the grid provided with no error checking.
0277     /// \param extrapolate if true, use simple Richardson
0278     /// extrapolation on the final 2 steps
0279     /// to reduce the error. \return sum of partial integrals,
0280     /// which is the definite integral
0281     /// from the first value in \a xgrid to the last.
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 /* throw(c2_exception) */;
0286 
0287     /// \brief a fully-automated integrator which uses the information
0288     /// provided by the
0289     /// get_sampling_grid() function to figure out what to do.
0290     ///
0291     /// It returns the integral of the function over the domain requested
0292     /// with error tolerances as specified.  It is just a front-end
0293     /// to partial_integrals()
0294     ///
0295     /// \param amin lower bound of the domain for integration
0296     /// \param amax upper bound of the domain for integration
0297     /// \param partials if non-NULL, a vector in which to receive
0298     /// the partial integrals.
0299     /// It will automatically be sized appropriately,
0300     /// if provided, to contain \a n - 1
0301     /// elements where \a n is the length of \a xgrid
0302     /// \param abs_tol the absolute error bound for each segment
0303     /// \param rel_tol the fractional error bound for each segment.
0304     /// If the error is smaller than either the relative or absolute tolerance,
0305     /// the integration
0306     /// step is finished.
0307     /// \param derivs number of derivatives to trust, which sets the
0308     /// order of the integrator.
0309     /// The order is 3*\a derivs + 4. \a derivs can be 0, 1, or 2.
0310     /// \param adapt if true, use recursive adaptation,
0311     /// otherwise do simple evaluation on
0312     /// the grid provided with no error checking.
0313     /// \param extrapolate if true, use simple Richardson
0314     /// extrapolation on the final 2 steps
0315     /// to reduce the error. \return sum of partial integrals,
0316     /// which is the definite integral
0317     /// from the first value in \a xgrid to the last.
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 /* throw(c2_exception) */;
0321 
0322     /// \brief create a c2_piecewise_function_p from
0323     /// c2_connector_function_p segments which
0324     /// is a representation of the parent function to the specified accuracy,
0325     /// but maybe much cheaper to evaluate
0326     ///
0327     /// This method has three modes, depending on the \a derivs flag.
0328     ///
0329     /// If \a derivs is 2,
0330     /// it computes a c2_piecewise_function_p representation of its
0331     /// parent function,
0332     /// which may be a much faster
0333     /// function to use in codes if the parent function is expensive.
0334     /// If \a xvals
0335     /// and \a yvals are non-null,
0336     /// it will also fill them in with the function values at each grid point the
0337     /// adaptive algorithm chooses.
0338     ///
0339     /// If \a derivs is 1, this does not create the connectors,
0340     /// and returns an null pointer, but will fill in the \a xvals and \a yvals
0341     /// vectors with values of the function at points such that the
0342     /// linear interpolation
0343     /// error between the points
0344     /// is bounded by the tolerance values given.
0345     /// Because it uses derivative information
0346     /// from the function to manage the
0347     /// error control, it is almost completely free of issues with
0348     /// missing periods of oscillatory functions,
0349     /// even with no information provided in the sampling grid.
0350     /// This is typically useful for sampling a function for plotting.
0351     ///
0352     /// If \a derivs is 0, this does something very like what it does
0353     /// if \a derivs = 1,
0354     /// but without derivatives.
0355     /// Instead, to compute the intermediate value of the function
0356     /// for error control,
0357     /// it just uses
0358     /// 3-point parabolic interpolation.
0359     /// This is useful amost exclusively for converting
0360     /// a non-c2_function,
0361     /// with no derivatives, but wrapped in a c2_classic_function wrapper,
0362     /// into a table
0363     /// of values to seed an interpolating_function_p.
0364     /// Note, however, that without derivatives, this is very
0365     /// susceptible to missing
0366     /// periods of oscillatory
0367     /// functions, so it is important to set a sampling grid
0368     /// which isn't too much coarser
0369     /// than the typical oscillations.
0370     ///
0371     /// \note the \a sampling_grid of the returned function matches the
0372     /// \a sampling_grid of its parent.
0373     /// \see ref sample_function_for_plotting "Adaptive Sampling Examples"
0374     /// \param amin lower bound of the domain for sampling
0375     /// \param amax upper bound of the domain for sampling
0376     /// \param abs_tol the absolute error bound for each segment
0377     /// \param rel_tol the fractional error bound for each segment.
0378     /// \param derivs if 0 or 1, return a useless function,
0379     /// but fill in the \a xvals and
0380     /// \a yvals vectors (if non-null).
0381     /// Also, if 0 or 1, tolerances refer to linear interpolation, not high-order
0382     /// interpolation.
0383     /// If 2, return a full piecewise collection of
0384     /// c2_connector_function_p segments.
0385     /// See discussion above.
0386     /// \param [in,out] xvals vector of abscissas at which the function
0387     /// was actually
0388     /// sampled (if non-null)
0389     /// \param [in,out] yvals vector of function values corresponding to \a xvals
0390     /// (if non-null)
0391     /// \return a new, sampled representation, if \a derivs is 2.
0392     /// A null pointer if \a derivs is 0 or 1.
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       /* throw(c2_exception) */;
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     /// and sampler do increment it.
0408     /// \return number of evaluations logged since last reset.
0409     size_t get_evaluations() const { return evaluations; }
0410     /// \brief reset the counter
0411     void reset_evaluations() const { evaluations = 0; }
0412     /// \brief count evaluations
0413     inline void increment_evaluations() const { evaluations++; }
0414 
0415     /// \brief check that a vector is monotonic, throw an exception if not,
0416     /// and return a flag if it is reversed
0417     ///
0418     /// \param data a vector of data points which are expected to be monotonic.
0419     /// \param message an informative string to include in an exception if
0420     /// this throws c2_exception
0421     /// \return true if in decreasing order, false if increasing
0422     bool check_monotonicity(const std::vector<float_type>& data, const char message[]) const
0423       /* throw(c2_exception) */;
0424 
0425     /// \brief establish a grid of 'interesting' points on the function.
0426     ///
0427     /// The sampling grid describes a reasonable initial set of points
0428     /// to look at the function.
0429     /// this should generally be set at a scale which is quite coarse,
0430     /// and sufficient for initializing
0431     /// adaptive integration or possibly root bracketing.
0432     /// For sampling a function to build a new
0433     /// interpolating function, one may want to refine this for accuracy.
0434     /// However,
0435     /// interpolating_functions themselves return their original
0436     /// X grid by default, so refining
0437     /// the grid in this case might be a bad idea.
0438     /// \param grid a vector of abscissas.
0439     /// The contents is copied into an internal vector,
0440     /// so the \a grid can be discarded after passingin.
0441     virtual void set_sampling_grid(const std::vector<float_type>& grid)
0442       /* throw(c2_exception) */;
0443 
0444     /// \brief get the sampling grid, which may be a null pointer
0445     /// \return pointer to the sampling grid
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     /// The grid is modified in place.
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     /// \brief create a new c2_function from this one which
0456     /// is normalized on the interval
0457     /// \param amin lower bound of the domain for integration
0458     /// \param amax upper bound of the domain for integration
0459     /// \param norm the desired integral for the function over the region
0460     /// \return a new c2_function with the desired \a norm.
0461     c2_function<float_type>& normalized_function(float_type amin, float_type amax,
0462                                                  float_type norm = 1.0) const
0463       /* throw(c2_exception) */;
0464     c2_function<float_type>& square_normalized_function(float_type amin, float_type amax,
0465                                                         float_type norm = 1.0) const
0466       /* throw(c2_exception) */;
0467     /// \brief create a new c2_function from this one which is square-normalized
0468     /// with the provided \a weight on the interval
0469     /// \param amin lower bound of the domain for integration
0470     /// \param amax upper bound of the domain for integration
0471     /// \param weight a c2_function providing the weight
0472     /// \param norm the desired integral for the function over the region
0473     /// \return a new c2_function with the desired \a norm.
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       /* throw(c2_exception) */;
0478 
0479     /// \brief factory function to create a c2_sum_p from a regular
0480     /// algebraic expression.
0481     /// \param rhs the right-hand term of the sum
0482     /// \return a new c2_function
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     /// \brief factory function to create a c2_diff_p from a regular
0488     /// algebraic expression.
0489     /// \param rhs the right-hand term of the difference
0490     /// \return a new c2_function
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     /// \brief factory function to create a c2_product_p from a
0496     /// regular algebraic expression.
0497     /// \param rhs the right-hand term of the product
0498     /// \return a new c2_function
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     /// \brief compose this function outside another.
0508     /// \param inner the inner function
0509     /// \return the composed function
0510     /// \anchor compose_operator
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     /// \brief Find out where a calculation ran into trouble, if it got a nan.
0517     /// If the most recent computation did not return a nan, this is undefined.
0518     /// \return \a x value of point at which something went wrong, if integrator
0519     /// (or otherwise) returned a nan.
0520     float_type get_trouble_point() const { return bad_x_point; }
0521 
0522     /// \brief increment our reference count.
0523     /// Destruction is only legal if the count is zero.
0524     void claim_ownership() const { owner_count++; }
0525     /// \brief decrement our reference count. Do not destroy at zero.
0526     /// \return final owner count, to check whether object should disappear.
0527     size_t release_ownership_for_return() const /* throw(c2_exception) */
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 /* throw(c2_exception) */
0539     {
0540       if (!release_ownership_for_return()) delete this;
0541     }
0542     /// \brief get the reference count, mostly for debugging
0543     /// \return the count
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     {}  // copy constructor only copies domain, and is only for internal use
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     /// \brief this point may be used to record where a calculation
0577     /// ran into trouble
0578     mutable float_type bad_x_point;
0579 
0580   public:
0581     /// \brief fill in a c2_fblock<float_type>... a
0582     /// shortcut for the integrator & sampler
0583     /// \param [in,out] fb the block to fill in with information
0584     inline void fill_fblock(c2_fblock<float_type>& fb) const /* throw(c2_exception) */
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     /// \brief the data element for the internal recursion stack for
0594     /// the sampler and integrator
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     /// \brief structure used to pass information recursively in integrator.
0605     ///
0606     /// the \a abs_tol is scaled by a factor of two at each division.
0607     /// Everything else is just passed down.
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     /// \brief structure used to pass information recursively in sampler.
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     /// \brief structure used to hold root bracketing information
0631     ///
0632     struct c2_root_info
0633     {
0634         c2_fblock<float_type> lower, upper;
0635         bool inited;
0636     };
0637 
0638     /// \brief Carry out the recursive subdivision and integration.
0639     ///
0640     /// This passes information recursively through the \a recur block pointer
0641     /// to allow very efficient recursion.
0642     /// \param rb a pointer to the recur struct.
0643     float_type integrate_step(struct c2_integrate_recur& rb) const /* throw(c2_exception) */;
0644 
0645     /// \brief Carry out the recursive subdivision for sampling.
0646     ///
0647     /// This passes information recursively through the \a recur block pointer
0648     /// to allow very efficient recursion.
0649     /// \param rb a pointer to the recur struct.
0650     void sample_step(struct c2_sample_recur& rb) const /* throw(c2_exception) */;
0651 
0652     /// this carry a memory of the last root bracketing,
0653     /// to avoid the necessity of evaluating the function on the
0654     /// brackets every time
0655     /// if the brackets have not been changed.
0656     /// it is declared as a pointer, since many c2_functions may
0657     /// never need one allocated
0658     mutable struct c2_root_info* root_info;
0659 
0660     mutable size_t owner_count;
0661 };
0662 
0663 /// \brief a container into which any conventional c-style
0664 /// function can be dropped,
0665 /// to create a degenerate c2_function without derivatives.
0666 /// Mostly useful for sampling into interpolating functions.
0667 /// construct a reference to this with c2_classic_function()
0668 /// \ingroup containers
0669 template<typename float_type = double>
0670 class c2_classic_function_p : public c2_function<float_type>
0671 {
0672   public:
0673     /// \brief construct the container
0674     /// \param c_func a pointer to a conventional c-style function
0675     c2_classic_function_p(const float_type (*c_func)(float_type))
0676       : c2_function<float_type>(), func(c_func)
0677     {}
0678 
0679     /// \copydoc c2_function::value_with_derivatives
0680     /// Uses the internal function pointer set by set_function().
0681     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
0682                                               float_type* yprime2) const /* throw(c2_exception) */
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     /// \brief pointer to our function
0693     const float_type (*func)(float_type);
0694 };
0695 
0696 /// \brief create a container for a c2_function which handles the
0697 /// reference counting. \ingroup containers
0698 /// It is useful as a smart container to hold a c2_function and keep
0699 /// the reference count correct.
0700 /// The recommended way for a class to store a c2_function which is
0701 /// handed in from the outside
0702 /// is for it to have a c2_ptr member into which the passed-in
0703 /// function is stored.
0704 /// This way, when the class instance is deleted,
0705 /// it will automatically dereference any function
0706 /// which it was handed.
0707 ///
0708 /// This class contains a copy constructor and operator=,
0709 /// to make it fairly easy to make
0710 /// a std::vector of these objects, and have it work as expected.
0711 template<typename float_type>
0712 class c2_const_ptr
0713 {
0714   public:
0715     /// \brief construct the container with no function
0716     c2_const_ptr() : func(0) {}
0717     /// \brief construct the container with a pre-defined function
0718     /// \param f the function to store
0719     c2_const_ptr(const c2_function<float_type>& f) : func(0) { this->set_function(&f); }
0720     /// \brief copy constructor
0721     /// \param src the container to copy
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     /// \brief fill the container from another container
0734     /// \param f the container to copy
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     /// \brief fill the container with a function
0741     /// \param f the function
0742     const c2_function<float_type>& operator=(const c2_function<float_type>& f)
0743     {
0744       this->set_function(&f);
0745       return f;
0746     }
0747     /// \brief release the function without destroying it,
0748     /// so it can be returned from a function
0749     ///
0750     /// This is usually the very last line of a function
0751     /// before the return statement, so that
0752     /// any exceptions that happen during execution of the
0753     /// function will cause proper cleanup.
0754     /// Once the function has been released from its container this way,
0755     /// it is an orhpaned object
0756     /// until the caller claims it, so it could get lost if an exception happens.
0757     void release_for_return() /* throw(c2_exception) */
0758     {
0759       if (func) func->release_ownership_for_return();
0760       func = 0;
0761     }
0762     /// \brief clear the function
0763     ///
0764     /// Any attempt to use this c2_plugin_function_p throws an exception
0765     /// if the saved
0766     /// function is cleared.
0767     void unset_function(void) { this->set_function(0); }
0768     /// \brief destructor
0769     ~c2_const_ptr() { this->set_function(0); }
0770 
0771     /// \brief get a reference to our owned function
0772     inline const c2_function<float_type>& get() const /* throw(c2_exception) */
0773     {
0774       if (!func) throw c2_exception("c2_ptr accessed uninitialized");
0775       return *func;
0776     }
0777     /// \brief get an unchecked pointer to our owned function
0778     inline const c2_function<float_type>* get_ptr() const { return func; }
0779     /// \brief get a checked pointer to our owned function
0780     inline const c2_function<float_type>* operator->() const { return &get(); }
0781     /// \brief check if we have a valid function
0782     bool valid() const { return func != 0; }
0783 
0784     /// \brief type coercion operator which lets us use a pointer as if it were
0785     /// a const c2_function
0786     operator const c2_function<float_type>&() const { return this->get(); }
0787 
0788     /// \brief convenience operator to make us look like a function
0789     /// \param x the value at which to evaluate the contained function
0790     /// \return the evaluated function
0791 
0792     float_type operator()(float_type x) const /* throw(c2_exception) */ { return get()(x); }
0793     /// \brief convenience operator to make us look like a function
0794     /// \param x the value at which to evaluate the contained function
0795     /// \param yprime the derivative
0796     /// \param yprime2 the second derivative
0797     /// \return the evaluated function
0798     /// \note If you using this repeatedly,
0799     /// do const c2_function<float_type> &func=ptr;
0800     /// and use func(x).  Calling this operator wastes some time,
0801     /// since it checks the alidity of the pointer every time.
0802     float_type operator()(float_type x, float_type* yprime,
0803                           float_type* yprime2) const /* throw(c2_exception) */
0804     {
0805       return get().value_with_derivatives(x, yprime, yprime2);
0806     }
0807     /// \brief factory function to create a c2_sum_p from a regular
0808     /// algebraic expression.
0809     /// \param rhs the right-hand term of the sum
0810     /// \return a new c2_function
0811     c2_sum_p<float_type>&
0812     operator+(const c2_function<float_type>& rhs) const /* throw(c2_exception) */
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 /* throw(c2_exception) */
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 /* throw(c2_exception) */
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 /* throw(c2_exception) */
0828     {
0829       return *new c2_ratio_p<float_type>(get(), rhs);
0830     }
0831     /// \brief compose this function outside another.
0832     /// \param inner the inner function
0833     /// \return the composed function
0834     c2_composed_function_p<float_type>&
0835     operator()(const c2_function<float_type>& inner) const /* throw(c2_exception) */
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     /// \brief construct the container with no function
0849     c2_ptr() : c2_const_ptr<float_type>() {}
0850     /// \brief construct the container with a pre-defined function
0851     /// \param f the function to store
0852     c2_ptr(c2_function<float_type>& f) : c2_const_ptr<float_type>() { this->set_function(&f); }
0853     /// \brief copy constructor
0854     /// \param src the container to copy
0855     c2_ptr(const c2_ptr<float_type>& src) : c2_const_ptr<float_type>()
0856     {
0857       this->set_function(src.get_ptr());
0858     }
0859     /// \brief get a checked pointer to our owned function
0860     inline c2_function<float_type>& get() const /* throw(c2_exception) */
0861     {
0862       return *const_cast<c2_function<float_type>*>(&c2_const_ptr<float_type>::get());
0863     }
0864     /// \brief get an unchecked pointer to our owned function
0865     inline c2_function<float_type>* get_ptr() const
0866     {
0867       return const_cast<c2_function<float_type>*>(this->func);
0868     }
0869     /// \brief get a checked pointer to our owned function
0870     inline c2_function<float_type>* operator->() const { return &get(); }
0871     /// \brief fill the container from another container
0872     /// \param f the container to copy
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     /// \brief fill the container with a function
0879     /// \param f the function
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     /// \brief hidden non-const-safe version of operator=
0888     void operator=(const c2_const_ptr<float_type>&) {}
0889     /// \brief hidden non-const-safe version of operator=
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     /// \brief construct the container with no function
0898     c2_typed_ptr() : c2_ptr<float_type>() {}
0899     /// \brief construct the container with a pre-defined function
0900     /// \param f the function to store
0901     c2_typed_ptr(c2_class<float_type>& f) : c2_const_ptr<float_type>() { this->set_function(&f); }
0902     /// \brief copy constructor
0903     /// \param src the container to copy
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     /// \brief get a reference to our owned function
0910     inline c2_class<float_type>& get() const /* throw(c2_exception) */
0911     {
0912       return *static_cast<c2_class<float_type>*>(
0913         const_cast<c2_function<float_type>*>(&c2_const_ptr<float_type>::get()));
0914     }
0915     /// \brief get a checked pointer to our owned function
0916     inline c2_class<float_type>* operator->() const { return &get(); }
0917     /// \brief get an unchecked pointer to our owned function
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     /// \brief fill the container from another container
0925     /// \param f the container to copy
0926     void operator=(const c2_typed_ptr<float_type, c2_class>& f) { this->set_function(f.get_ptr()); }
0927     /// \brief fill the container with a function
0928     /// \param f the function
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     /// \brief construct the container with no function
0941     c2_plugin_function_p() : c2_function<float_type>(), func() {}
0942     /// \brief construct the container with a pre-defined function
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     /// \copydoc c2_function::value_with_derivatives
0951     /// Uses the internal function pointer set by set_function().
0952     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
0953                                               float_type* yprime2) const /* throw(c2_exception) */
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     /// \brief destructor
0959     virtual ~c2_plugin_function_p() {}
0960 
0961     /// \brief clear our function
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     /// \brief construct the container with no function
0983     c2_const_plugin_function_p() : c2_plugin_function_p<float_type>() {}
0984     /// \brief construct the container with a pre-defined function
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     /// \brief destructor
0995     virtual ~c2_const_plugin_function_p() {}
0996 
0997     /// \brief get a const reference to our owned function, for direct access
0998     const c2_function<float_type>& get() const /* throw(c2_exception) */
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 /* throw(c2_exception) */
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     /// \brief destructor releases ownership of member functions
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     /// \brief construct the function with its scale factor.
1050     ///
1051     /// \param outer the function to be scaled
1052     /// \param scale the multiplicative scale factor
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     /// \brief set a new scale factor
1058     /// \param scale the new factor
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 /* throw (c2_exception) */
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     /// \brief the scaling factor for the function
1073     const c2_const_ptr<float_type> func;
1074     float_type yscale;
1075 };
1076 
1077 /// \brief A container into which any other c2_function can be dropped.
1078 /// \ingroup containers
1079 /// It allows a function to be pre-evaluated at a point,
1080 /// and used at multiple places
1081 /// in an expression
1082 /// efficiently. If it is re-evaluated at the previous point,
1083 /// it returns the remembered values;
1084 /// otherwise, it re-evauates the function at the new point.
1085 ///
1086 template<typename float_type = double>
1087 class c2_cached_function_p : public c2_function<float_type>
1088 {
1089   public:
1090     /// \brief construct the container
1091     ///
1092     /// \param f the function to be cached
1093     c2_cached_function_p(const c2_function<float_type>& f)
1094       : c2_function<float_type>(), func(f), init(false)
1095     {}
1096     /// \copydoc c2_function::value_with_derivatives
1097     ///
1098     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1099                                               float_type* yprime2) const /* throw(c2_exception) */
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     /// \brief Create a stub just for the combiner to avoid statics.
1129     c2_composed_function_p() : c2_binary_function<float_type>(combine) {}
1130 
1131     /// \brief execute math necessary to do composition
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) /* throw(c2_exception) */
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     /// \brief construct \a left + \a right
1157     /// \param left the left function
1158     /// \param right the right function
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     /// \brief Create a stub just for the combiner to avoid statics.
1163     c2_sum_p() : c2_binary_function<float_type>(combine) {};
1164 
1165     /// \brief execute math necessary to do addition
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) /* throw(c2_exception) */
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     /// \brief construct \a left - \a right
1191     /// \param left the left function
1192     /// \param right the right function
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     /// \brief Create a stub just for the combiner to avoid statics.
1197     c2_diff_p() : c2_binary_function<float_type>(combine) {};
1198 
1199     /// \brief execute math necessary to do subtraction
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) /* throw(c2_exception) */
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 /// \brief create a c2_function which is the product of two other c2_functions.
1221 /// \ingroup arithmetic_functions
1222 /// This should always be constructed using c2_function::operator*()
1223 template<typename float_type = double>
1224 class c2_product_p : public c2_binary_function<float_type>
1225 {
1226   public:
1227     /// \brief construct \a left * \a right
1228     /// \param left the left function
1229     /// \param right the right function
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     /// \brief Create a stub just for the combiner to avoid statics.
1234     c2_product_p() : c2_binary_function<float_type>(combine) {};
1235 
1236     /// \brief execute math necessary to do multiplication
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) /* throw(c2_exception) */
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 /// \brief create a c2_function which is the ratio of two other c2_functions.
1258 /// \ingroup arithmetic_functions
1259 /// This should always be constructed using c2_function::operator/()
1260 template<typename float_type = double>
1261 class c2_ratio_p : public c2_binary_function<float_type>
1262 {
1263   public:
1264     /// \brief construct \a left / \a right
1265     /// \param left the left function
1266     /// \param right the right function
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     /// \brief Create a stub just for the combiner to avoid statics.
1271     c2_ratio_p() : c2_binary_function<float_type>(combine) {};
1272 
1273     /// \brief execute math necessary to do division
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) /* throw(c2_exception) */
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);  // first deriv of ratio
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 /// \brief a c2_function which is constant
1297 /// \ingroup parametric_functions
1298 ///
1299 /// The factory function c2_factory::constant() creates *new c2_constant_p()
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 /* throw(c2_exception) */
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 /// \brief a transformation of a coordinate, including an inverse
1319 /// \ingroup transforms
1320 template<typename float_type>
1321 class c2_transformation
1322 {
1323   public:
1324     /// \brief initialize all our function pointers
1325     /// \param transformed true if this function is not the identity
1326     /// \param xin input X transform
1327     /// \param xinp input X transform derivative
1328     /// \param xinpp input X transform second derivative
1329     /// \param xout output X transform, which MUST be the inverse of \a xin
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     /// \brief initialize all our function pointers so that only the (overridden)
1342     /// virtual functions can be called without an error
1343     /// \param transformed true if this function is nonlinear
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     /// \brief the destructor
1353     virtual ~c2_transformation() {}
1354     /// \brief flag to indicate if this transform is not the identity
1355     const bool fTransformed;
1356     /// \brief flag to indicate if the static function pointers can
1357     /// be used for efficiency
1358     const bool fHasStaticTransforms;
1359 
1360     /// \note the pointers to functions allow highly optimized access when static
1361     /// functions are available.
1362     /// They are only used inside value_with_derivatives(),
1363     /// which is assumed to be the most critical routine.
1364     /// \brief non-virtual pointer to input X transform
1365     float_type (*const pIn)(float_type);
1366     /// \brief non-virtual pointer to input X transform derivative
1367     float_type (*const pInPrime)(float_type);
1368     /// \brief non-virtual pointer to input X transform second derivative
1369     float_type (*const pInDPrime)(float_type);
1370     /// \brief non-virtual pointer to output X transform
1371     float_type (*const pOut)(float_type);
1372 
1373     /// \brief virtual input X transform
1374     virtual float_type fIn(float_type x) const { return pIn(x); }
1375     /// \brief virtual input X transform derivative
1376     virtual float_type fInPrime(float_type x) const { return pInPrime(x); }
1377     /// \brief virtual input X transform second derivative
1378     virtual float_type fInDPrime(float_type x) const { return pInDPrime(x); }
1379     /// \brief virtual output X transform
1380     virtual float_type fOut(float_type x) const { return pOut(x); }
1381 
1382   protected:
1383     /// \brief utility function for unimplemented conversion
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     /// \brief utility function f(x)=x useful in axis transforms
1390     static float_type ident(float_type x) { return x; }
1391     /// \brief utility function f(x)=1 useful in axis transforms
1392     static float_type one(float_type) { return 1; }
1393     /// \brief utility function f(x)=0 useful in axis transforms
1394     static float_type zero(float_type) { return 0; }
1395     /// \brief utility function f(x)=1/x useful in axis transforms
1396     static float_type recip(float_type x) { return 1.0 / x; }
1397     /// \brief utility function f(x)=-1/x**2 useful in axis transforms
1398     static float_type recip_prime(float_type x) { return -1 / (x * x); }
1399     /// \brief utility function f(x)=2/x**3 useful in axis transforms
1400     static float_type recip_prime2(float_type x) { return 2 / (x * x * x); }
1401 };
1402 
1403 /// \brief the identity transform
1404 /// \ingroup transforms
1405 template<typename float_type>
1406 class c2_transformation_linear : public c2_transformation<float_type>
1407 {
1408   public:
1409     /// \brief constructor
1410     c2_transformation_linear()
1411       : c2_transformation<float_type>(false, this->ident, this->one, this->zero, this->ident)
1412     {}
1413     /// \brief destructor
1414     virtual ~c2_transformation_linear() {}
1415 };
1416 /// \brief log axis transform
1417 /// \ingroup transforms
1418 template<typename float_type>
1419 class c2_transformation_log : public c2_transformation<float_type>
1420 {
1421   public:
1422     /// \brief constructor
1423     c2_transformation_log()
1424       : c2_transformation<float_type>(true, std::log, this->recip, this->recip_prime, std::exp)
1425     {}
1426     /// \brief destructor
1427     virtual ~c2_transformation_log() {}
1428 };
1429 /// \brief reciprocal axis transform
1430 /// \ingroup transforms
1431 template<typename float_type>
1432 class c2_transformation_recip : public c2_transformation<float_type>
1433 {
1434   public:
1435     /// \brief constructor
1436     c2_transformation_recip()
1437       : c2_transformation<float_type>(true, this->recip, this->recip_prime, this->recip_prime2,
1438                                       this->recip)
1439     {}
1440     /// \brief destructor
1441     virtual ~c2_transformation_recip() {}
1442 };
1443 
1444 /// \brief a transformation of a function in and out of a coordinate space,
1445 /// using 2 c2_transformations
1446 ///
1447 /// This class is a container for two axis transforms,
1448 ///  but also provides the critical evaluate()
1449 /// function which converts a result in internal
1450 /// coordinates (with derivatives) into the
1451 /// external representation
1452 /// \ingroup transforms
1453 template<typename float_type>
1454 class c2_function_transformation
1455 {
1456   public:
1457     /// \brief construct this from two c2_transformation instances
1458     /// \param xx the X axis transform
1459     /// \param yy the Y axis transform
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     /// \brief destructor
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     /// \brief the X axis transform
1474     const c2_transformation<float_type>& X;
1475     /// \brief the Y axis transform
1476     const c2_transformation<float_type>& Y;
1477 };
1478 
1479 /// \brief a transformation of a function in and out of lin-lin space
1480 ///
1481 /// \ingroup transforms
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 /// \brief a transformation of a function in and out of log-log space
1494 ///
1495 /// \ingroup transforms
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 /// \brief a transformation of a function in and out of lin-log space
1508 ///
1509 /// \ingroup transforms
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 /// \brief a transformation of a function in and out of log-lin space
1522 ///
1523 /// \ingroup transforms
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 /// \brief a transformation of a function in and out of Arrhenius
1536 /// (1/x vs. log(y)) space
1537 ///
1538 /// \ingroup transforms
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     \brief create a cubic spline interpolation of a set of (x,y) pairs
1552         \ingroup interpolators
1553     This is one of the main reasons for c2_function objects to exist.
1554 
1555     It provides support for cubic spline interpolation of data
1556     provides from tables
1557     of \a x, \a y pairs.
1558     It supports automatic, transparent linearization of the data
1559     before storing in
1560     its tables (through
1561     subclasses such as
1562     log_lin_interpolating_function, lin_log_interpolating_function, and
1563     log_log_interpolating_function) to permit very high
1564     accuracy representations of
1565     data which have a suitable
1566     structure.  It provides utility functions
1567     LinearInterpolatingGrid() and LogLogInterpolatingGrid()
1568     to create grids for mapping other functions onto a arithmetic
1569     or geometric grid.
1570 
1571     In its simplest form, an untransformed cubic spline of a data set,
1572     using natural boundary conditions
1573     (vanishing second derivative), is created as: \n
1574     \code
1575         c2_ptr<double> c2p;
1576         c2_factory<double> c2;
1577     std::vector<double> xvals(10), yvals(10);
1578     // < fill in xvals and yvals >
1579     c2p myfunc=c2.interpolating_function().load(xvals, yvals,true,0,true,0);
1580     // and it can be evaluated at a point for its value only by:
1581     double y=myfunc(x);
1582     // or it can be evaluated with its derivatives by
1583     double yprime, yprime2;
1584     double y=myfunc(x,&yprime, &yprime2);
1585     \endcode
1586 
1587     The factory function c2_factory::interpolating_function()
1588     creates *new interpolating_function_p()
1589 */
1590 
1591 template<typename float_type = double>
1592 class interpolating_function_p : public c2_function<float_type>
1593 {
1594   public:
1595     /// \brief an empty linear-linear cubic-spline interpolating_function_p
1596     ///
1597     interpolating_function_p()
1598       : c2_function<float_type>(), fTransform(*new c2_lin_lin_function_transformation<float_type>)
1599     {}
1600 
1601     /// \brief an empty cubic-spline interpolating_function_p with a
1602     /// specific transform
1603     ///
1604     interpolating_function_p(const c2_function_transformation<float_type>& transform)
1605       : c2_function<float_type>(), fTransform(transform)
1606     {}
1607 
1608     /// \brief do the dirty work of constructing the spline from a function.
1609     /// \param x the list of abscissas.  Must be either strictly
1610     /// increasing or strictly decreasing.
1611     /// Strictly increasing is preferred, as less memory is used since
1612     /// a copy is not
1613     /// required for the sampling grid.
1614     /// \param f the list of function values.
1615     /// \param lowerSlopeNatural if true, set y''(first point)=0,
1616     /// otherwise compute it
1617     /// from \a lowerSope
1618     /// \param lowerSlope derivative of the function at the lower bound,
1619     /// used only
1620     /// if \a lowerSlopeNatural is false
1621     /// \param upperSlopeNatural if true, set y''(last point)=0,
1622     /// otherwise compute
1623     /// it from \a upperSope
1624     /// \param upperSlope derivative of the function at the upper bound,
1625     /// used only
1626     /// if \a upperSlopeNatural is false
1627     /// \param splined if true (default), use cubic spline,
1628     /// if false, use linear interpolation.
1629     /// \return the same interpolating function, filled
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) /* throw(c2_exception) */;
1635 
1636     /// \brief do the dirty work of constructing the spline from a function.
1637     /// \param data std::vector of std::pairs of x,y.
1638     /// Will be sorted into x increasing order in place.
1639     /// \param lowerSlopeNatural if true, set y''(first point)=0,
1640     /// otherwise compute it from \a lowerSope
1641     /// \param lowerSlope derivative of the function at the lower bound,
1642     /// used only if \a lowerSlopeNatural is false
1643     /// \param upperSlopeNatural if true, set y''(last point)=0,
1644     /// otherwise compute
1645     /// it from \a upperSope
1646     /// \param upperSlope derivative of the function at the upper bound,
1647     /// used only if \a upperSlopeNatural is false
1648     /// \param splined if true (default), use cubic spline,
1649     /// if false, use linear interpolation.
1650     /// \return the same interpolating function, filled
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) /* throw(c2_exception) */;
1655 
1656     /// \brief do the dirty work of constructing the spline from a function.
1657     /// \param func a function without any requirement of valid derivatives
1658     /// to sample
1659     /// into an interpolating function.
1660     /// Very probably a c2_classic_function.
1661     /// \param amin the lower bound of the region to sample
1662     /// \param amax the upper bound of the region to sample
1663     /// \param abs_tol the maximum absolute error permitted when
1664     /// linearly interpolating the points.
1665     /// the real error will be much smaller,
1666     /// since this uses cubic splines at the end.
1667     /// \param rel_tol the maximum relative error
1668     /// permitted when linearly interpolating the points.
1669     /// the real error will be much smaller,
1670     /// since this uses cubic splines at the end.
1671     /// \param lowerSlopeNatural if true, set y'(first point)
1672     /// from 3-point parabola,
1673     /// otherwise compute it from \a lowerSope
1674     /// \param lowerSlope derivative of the function at the lower bound,
1675     /// used only if \a lowerSlopeNatural is false
1676     /// \param upperSlopeNatural if true,
1677     /// set y'(last point) from 3-point parabola,
1678     /// otherwise compute it from \a upperSope
1679     /// \param upperSlope derivative of the function at the upper bound,
1680     /// used only
1681     /// if \a upperSlopeNatural is false
1682     /// \return the same interpolating function, filled
1683     /// \note If the interpolator being filled has a log vertical axis,
1684     /// put the desired
1685     /// relative error in
1686     /// \a abs_tol, and 0 in \a rel_tol since the absolute error
1687     /// on the log of a function
1688     /// is the relative error
1689     /// on the function itself.
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) /* throw(c2_exception) */;
1695 
1696     /// \brief initialize from a grid of points and a
1697     /// c2_function (un-normalized) to an
1698     /// interpolator which, when evaluated with a
1699     /// uniform random variate on [0,1] returns
1700     /// random numbers
1701     /// distributed as the input function.
1702     /// \see  ref random_subsec "Arbitrary random generation"
1703     /// inverse_integrated_density starts with a probability density
1704     /// std::vector,
1705     /// generates the integral,
1706     /// and generates an interpolating_function_p  of the inverse function which,
1707     /// when evaluated using a uniform random on [0,1] returns values
1708     /// with a density distribution equal to the input distribution
1709     /// If the data are passed in reverse order (large X first),
1710     /// the integral is carried out
1711     /// from the big end.
1712     /// \param bincenters the positions at which to sample the
1713     /// function \a binheights
1714     /// \param binheights a function which describes the density
1715     /// of the random number
1716     /// distribution to be produced.
1717     /// \return an initialized interpolator, which
1718     /// if evaluated randomly with a uniform variate on [0,1] produces numbers
1719     /// distributed according to \a binheights
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       /* throw(c2_exception) */;
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       /* throw(c2_exception) */;
1729 
1730     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
1731                                               float_type* yprime2) const /* throw(c2_exception) */;
1732 
1733     /// \brief destructor
1734     virtual ~interpolating_function_p() { delete &fTransform; }
1735 
1736     virtual interpolating_function_p<float_type>& clone() const /* throw(c2_exception) */
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       /* throw() */;
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     /// \brief create the spline coefficients
1792     void spline(bool lowerSlopeNatural, float_type lowerSlope, bool upperSlopeNatural,
1793                 float_type upperSlope) /* throw(c2_exception) */;
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 /// \brief A spline with X transformed into log space.
1808 /// \ingroup interpolators
1809 ///
1810 template<typename float_type = double>
1811 class log_lin_interpolating_function_p : public interpolating_function_p<float_type>
1812 {
1813   public:
1814     /// \brief an empty log-linear cubic-spline interpolating_function_p
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 /* throw(c2_exception) */
1820     {
1821       return *new log_lin_interpolating_function_p<float_type>();
1822     }
1823 };
1824 
1825 /// \brief A spline with Y transformed into log space.
1826 /// \ingroup interpolators
1827 /// Most useful for functions looking like y=exp(x)
1828 ///
1829 template<typename float_type = double>
1830 class lin_log_interpolating_function_p : public interpolating_function_p<float_type>
1831 {
1832   public:
1833     /// \brief an empty linear-log cubic-spline interpolating_function_p
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 /* throw(c2_exception) */
1839     {
1840       return *new lin_log_interpolating_function_p<float_type>();
1841     }
1842 };
1843 
1844 /// \brief A spline with X and Y transformed into log space.
1845 /// \ingroup interpolators
1846 /// Most useful for functions looking like y=x^n or any other
1847 /// function with a huge X and Y dynamic range.
1848 ///
1849 template<typename float_type = double>
1850 class log_log_interpolating_function_p : public interpolating_function_p<float_type>
1851 {
1852   public:
1853     /// \brief an empty log-log cubic-spline interpolating_function_p
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 /* throw(c2_exception) */
1859     {
1860       return *new log_log_interpolating_function_p<float_type>();
1861     }
1862 };
1863 
1864 /// \brief A spline with X in reciprocal space and Y transformed in log space.
1865 /// \ingroup interpolators
1866 /// Most useful for thermodynamic types of data where Y is roughly A*exp(-B/x).
1867 /// Typical examples are reaction rate data, and thermistor calibration data.
1868 ///
1869 template<typename float_type = double>
1870 class arrhenius_interpolating_function_p : public interpolating_function_p<float_type>
1871 {
1872   public:
1873     /// \brief an empty arrhenius cubic-spline interpolating_function_p
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 /* throw(c2_exception) */
1879     {
1880       return *new arrhenius_interpolating_function_p<float_type>();
1881     }
1882 };
1883 
1884 /// \brief compute sin(x) with its derivatives.
1885 /// \ingroup math_functions
1886 ///
1887 /// The factory function c2_factory::sin() creates *new c2_sin_p
1888 template<typename float_type = double>
1889 class c2_sin_p : public c2_function<float_type>
1890 {
1891   public:
1892     /// \brief constructor.
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 /* throw(c2_exception) */
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 /// \brief compute cos(x) with its derivatives.
1909 /// \ingroup math_functions
1910 ///
1911 /// The factory function c2_factory::cos() creates *new c2_cos_p
1912 template<typename float_type = double>
1913 class c2_cos_p : public c2_sin_p<float_type>
1914 {
1915   public:
1916     /// \brief constructor.
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 /* throw(c2_exception) */
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 /// \brief compute tan(x) with its derivatives.
1930 /// \ingroup math_functions
1931 ///
1932 /// The factory function c2_factory::tan() creates *new c2_tan_p
1933 template<typename float_type = double>
1934 class c2_tan_p : public c2_function<float_type>
1935 {
1936   public:
1937     /// \brief constructor.
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 /* throw(c2_exception) */
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 /// \brief compute log(x) with its derivatives.
1957 /// \ingroup math_functions
1958 ///
1959 /// The factory function c2_factory::log() creates *new c2_log_p
1960 template<typename float_type = double>
1961 class c2_log_p : public c2_function<float_type>
1962 {
1963   public:
1964     /// \brief constructor.
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 /* throw(c2_exception) */
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 /// \brief compute exp(x) with its derivatives.
1977 /// \ingroup math_functions
1978 ///
1979 /// The factory function c2_factory::exp() creates *new c2_exp_p
1980 template<typename float_type = double>
1981 class c2_exp_p : public c2_function<float_type>
1982 {
1983   public:
1984     /// \brief constructor.
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 /* throw(c2_exception) */
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 /// \brief compute sqrt(x) with its derivatives.
1998 /// \ingroup math_functions
1999 ///
2000 /// The factory function c2_factory::sqrt() creates *new c2_sqrt_p()
2001 template<typename float_type = double>
2002 class c2_sqrt_p : public c2_function<float_type>
2003 {
2004   public:
2005     /// \brief constructor.
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 /* throw(c2_exception) */
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 /// \brief compute scale/x with its derivatives.
2019 /// \ingroup parametric_functions
2020 ///
2021 /// The factory function c2_factory::recip() creates *new c2_recip_p
2022 template<typename float_type = double>
2023 class c2_recip_p : public c2_function<float_type>
2024 {
2025   public:
2026     /// \brief constructor.
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 /* throw(c2_exception) */
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     /// \brief reset the scale factor
2039     /// \param scale the new numerator
2040     void reset(float_type scale) { rscale = scale; }
2041 
2042   private:
2043     float_type rscale;
2044 };
2045 
2046 /// \brief compute x with its derivatives.
2047 /// \ingroup math_functions
2048 ///
2049 /// The factory function c2_factory::identity() creates *new c2_identity_p
2050 template<typename float_type = double>
2051 class c2_identity_p : public c2_function<float_type>
2052 {
2053   public:
2054     /// \brief constructor.
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 /* throw(c2_exception) */
2059     {
2060       if (yprime) *yprime = 1.0;
2061       if (yprime2) *yprime2 = 0;
2062       return x;
2063     }
2064 };
2065 
2066 /**
2067  \brief create a linear mapping of another function
2068  \ingroup parametric_functions
2069  for example, given a c2_function \a f
2070  \code
2071  c2_function<double> &F=c2_linear<double>(1.2, 2.0, 3.0)(f);
2072  \endcode
2073  produces a new c2_function F=2.0+3.0*(\a f - 1.2)
2074 
2075  The factory function c2_factory::linear() creates *new c2_linear_p
2076 */
2077 template<typename float_type = double>
2078 class c2_linear_p : public c2_function<float_type>
2079 {
2080   public:
2081     /// \brief Construct the operator f=y0 + slope * (x-x0)
2082     /// \param x0 the x offset
2083     /// \param y0 the y-intercept i.e. f(x0)
2084     /// \param slope the slope of the mapping
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     /// \brief Change the slope and intercepts after construction.
2089     /// \param x0 the x offset
2090     /// \param y0 the y-intercept
2091     /// \param slope the slope of the mapping
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 /* throw(c2_exception) */
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 \brief create a quadratic mapping of another function
2115  \ingroup parametric_functions
2116  for example, given a c2_function \a f
2117  \code
2118  c2_function<double> &F=c2_quadratic<double>(1.2, 2.0, 3.0, 4.0)(f);
2119  \endcode
2120  produces a new c2_function F=2.0 + 3.0*(f-1.2) + 4.0*(f-1.2)^2
2121 
2122  note that the parameters are overdetermined,
2123  but allows the flexibility of two different representations
2124 
2125  The factory function c2_factory::quadratic() creates *new c2_quadratic_p
2126  */
2127 template<typename float_type = double>
2128 class c2_quadratic_p : public c2_function<float_type>
2129 {
2130   public:
2131     /// \brief Construct the operator
2132     /// \param x0 the center around which the powers are computed
2133     /// \param y0 the value of the function at \a x = \a x0
2134     /// \param xcoef the scale on the (\a x - \a x0) term
2135     /// \param x2coef the scale on the (\a x - \a x0)^2 term
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     /// \brief Modify the coefficients after construction
2140     /// \param x0 the new center around which the powers are computed
2141     /// \param y0 the new value of the function at \a x = \a x0
2142     /// \param xcoef the new scale on the (\a x - \a x0) term
2143     /// \param x2coef the new scale on the (\a x - \a x0)^2 term
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 /* throw(c2_exception) */
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 \brief create a power law mapping of another function
2169  \ingroup parametric_functions
2170  for example, given a c2_function \a f
2171  \code
2172  c2_power_law_p<double> PLaw(1.2, 2.5);
2173  c2_composed_function_p<double> &F=PLaw(f);
2174  \endcode
2175  produces a new c2_function F=1.2 * f^2.5
2176 
2177  The factory function c2_factory::power_law() creates *new c2_power_law_p
2178  */
2179 template<typename float_type = double>
2180 class c2_power_law_p : public c2_function<float_type>
2181 {
2182   public:
2183     /// \brief Construct the operator
2184     /// \param scale the multipler
2185     /// \param power the exponent
2186     c2_power_law_p(float_type scale, float_type power)
2187       : c2_function<float_type>(), a(scale), b(power)
2188     {}
2189     /// \brief Modify the mapping after construction
2190     /// \param scale the new multipler
2191     /// \param power the new exponent
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 /* throw(c2_exception) */
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 \brief create the formal inverse function of another function
2215  \ingroup containers
2216  for example, given a c2_function \a f
2217  \code
2218  c2_inverse_function<double> inv(f);
2219  a=f(x);
2220  x1=inv(a);
2221  \endcode
2222  will return x1=x to machine precision.  The important part of this
2223  is that the resulting function is a first-class c2_function, so it knows its
2224  derivatives, too, unlike the case of a simple root-finding inverse.  This means
2225  it can be integrated (for example) quite efficiently.
2226 
2227  \see ref combined_inversion_hinting_sampling
2228 
2229 */
2230 template<typename float_type = double>
2231 class c2_inverse_function_p : public c2_function<float_type>
2232 {
2233   public:
2234     /// \brief Construct the operator
2235     /// \param source the function to be inverted
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 /* throw(c2_exception) */;
2239 
2240     /// \brief give the function a hint as to where to look for its inverse
2241     /// \param hint the likely value of the inverse,
2242     /// which defaults to whatever the evaluation returned.
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     /// \brief set or unset the approximate function used to start the root finder
2251     /// \anchor set_hinting_function_discussion
2252     /// A hinting function is mostly useful if the evaluation of this inverse is
2253     /// going to be carried out in very non-local order,
2254     /// so the root finder has to start over
2255     /// for each step.  If most evaluations are going to be made
2256     /// in fairly localized clusters
2257     /// (scanning through the function, for example), the default mechanism used
2258     /// (which just remembers the last point)
2259     /// is almost certainly faster.
2260     ///
2261     /// Typically, the hinting function is likely to be set up by
2262     /// creating the inverse function,
2263     /// and then adaptively sampling an interpolating function from it,
2264     /// and then using the result
2265     /// to hint it.  Another way, if the parent function is already
2266     /// an interpolating function,
2267     /// is just to create a version of the parent with the x & y
2268     /// coordinates reversed.
2269     ///
2270     /// \see ref combined_inversion_hinting_sampling
2271     ///
2272     /// \param hint_func the function that is an approximate inverse
2273     /// of the parent of
2274     /// this inverse_function
2275     void set_hinting_function(const c2_function<float_type>* hint_func)
2276     {
2277       hinting_function.set_function(hint_func);
2278     }
2279     /// \brief set the hinting function from a pointer.
2280     ///
2281     /// See \ref set_hinting_function_discussion "discussion"
2282     /// \param hint_func the container holding the function
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   \brief
2297   An interpolating_function_p  which is the cumulative integral of a histogram.
2298   \ingroup interpolators
2299   Note than binedges should be one element longer than binheights,
2300   since the lower & upper edges are specified.
2301   Note that this is a malformed spline,
2302   since the second derivatives are all zero,
2303   so it has less continuity.
2304   Also, note that the bin edges can be given in backwards order to generate the
2305   reversed accumulation (starting at the high end)
2306 */
2307 
2308 template<typename float_type = double>
2309 class accumulated_histogram : public interpolating_function_p<float_type>
2310 {
2311   public:
2312     /// \brief Construct the integrated histogram
2313     /// \param binedges the edges of the bins in \a binheights.
2314     /// It should have one more element than \a binheights
2315     /// \param binheights the number of counts in each bin.
2316     /// \param normalize if true, normalize integral to 1
2317     /// \param inverse_function if true, drop zero channels,
2318     /// and return inverse function for random generation
2319     /// \param drop_zeros eliminate null bins before integrating,
2320     /// so integral is strictly monotonic.
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 /// \brief create a c2_function which smoothly connects two other c2_functions.
2327 /// \ingroup parametric_functions
2328 /// This takes two points and generates a polynomial
2329 /// which matches two c2_function arguments
2330 /// at those two points, with two derivatives at each point,
2331 /// and an arbitrary value at the center of the
2332 /// region.  It is useful for splicing together functions
2333 /// over rough spots (0/0, for example).
2334 ///
2335 /// If \a auto_center is true, the value at the midpoint is computed so
2336 /// that the resulting polynomial is
2337 /// of order 5.  If \a auto_center is false, the
2338 /// value \a y1 is used at the midpoint,
2339 /// resulting in a
2340 /// polynomial of order 6.
2341 ///
2342 /// This is usually used in conjunction
2343 /// with c2_piecewise_function_p to assemble an
2344 /// apparently seamless
2345 /// function from a series of segments.
2346 /// \see ref piecewise_applications_subsec "Sample Applications"
2347 /// and \ref c2_function::adaptively_sample() "Adaptive sampling"
2348 ///
2349 template<typename float_type = double>
2350 class c2_connector_function_p : public c2_function<float_type>
2351 {
2352   public:
2353     /// \brief construct the container from two functions
2354     /// \param x0 the point at which to match \a f1 and its derivatives
2355     /// \param f0 the function on the left side to be connected
2356     /// \param x2 the point at which to match \a f2 and its derivatives
2357     /// \param f2 the function on the right side to be connected
2358     /// \param auto_center if true, no midpoint value is specified.
2359     /// If false, match the value \a y1 at the midpoint
2360     /// \param y1 the value to match at the midpoint, if \a auto_center is false
2361     /// \return a c2_function with domain (\a x0,\a x2) which smoothly
2362     /// connects \a f0(x0) and \a f2(x2)
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     /// \brief construct the container from numerical values
2366     /// \param x0 the position of the left edge
2367     /// \param y0 the function derivative on the left boundary
2368     /// \param yp0 the function second derivative on the left boundary
2369     /// \param ypp0 the function value on the left boundary
2370     /// \param x2 the position of the right edge
2371     /// \param y2 the function derivative on the right boundary
2372     /// \param yp2 the function second derivative on the right boundary
2373     /// \param ypp2 the function value on the right boundary
2374     /// \param auto_center if true, no midpoint value is specified.
2375     /// If false, match the value \a y1 at the midpoint
2376     /// \param y1 the value to match at the midpoint, if \a auto_center is false
2377     /// \return a c2_function with domain (\a x0,\a x2)
2378     /// which smoothly connects the points described
2379     /// \anchor c2_connector_raw_init_docs
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     /// \brief construct the container from c2_fblock<float_type> objects
2384     /// \param fb0 the left edge
2385     /// \param fb2 the right edge
2386     /// \param auto_center if true, no midpoint value is specified.
2387     /// If false, match the value \a y1 at the midpoint
2388     /// \param y1 the value to match at the midpoint, if \a auto_center is false
2389     /// \return a c2_function with domain (\a fb0.x,\a fb2.x) which smoothly
2390     /// connects \a fb0 and \a fb2
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     /// \brief destructor
2395     virtual ~c2_connector_function_p();
2396     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2397                                               float_type* yprime2) const /* throw (c2_exception) */;
2398 
2399   protected:
2400     /// \brief fill container numerically
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 /// \brief create a c2_function which is a piecewise assembly
2408 /// of other c2_functions.
2409 /// \ingroup containers
2410 /// The functions must have increasing, non-overlapping domains.
2411 /// Any empty space
2412 /// between functions will be filled with a linear interpolation.
2413 ///
2414 /// \note If you want a smooth connection,
2415 /// instead of the default linear interpolation,
2416 /// create a c2_connector_function_p to bridge the gap.
2417 /// The linear interpolation is intended
2418 /// to be a barely intelligent bridge, and may never get used by anyone.
2419 ///
2420 /// \note The creation of the container results in the
2421 /// creation of an explicit sampling grid.
2422 /// If this is used with functions with a large domain,
2423 /// or which generate very dense sampling grids,
2424 /// it could eat a lot of memory.  Do not abuse this by using functions which
2425 /// can generate gigantic grids.
2426 ///
2427 /// \see ref piecewise_applications_subsec "Sample Applications" \n
2428 /// c2_plugin_function_p page \n
2429 /// c2_connector_function_p page \n
2430 /// \ref c2_function::adaptively_sample() "Adaptive sampling"
2431 ///
2432 template<typename float_type = double>
2433 class c2_piecewise_function_p : public c2_function<float_type>
2434 {
2435   public:
2436     /// \brief construct the container
2437     c2_piecewise_function_p();
2438     /// \brief destructor
2439     virtual ~c2_piecewise_function_p();
2440     virtual float_type value_with_derivatives(float_type x, float_type* yprime,
2441                                               float_type* yprime2) const /* throw (c2_exception) */;
2442     /// \brief append a new function to the sequence
2443     ///
2444     /// This takes a c2_function, and appends it onto the end of
2445     /// the piecewise collection.
2446     /// The domain of the function (which MUST be set)
2447     /// specifies the place it will be used in
2448     /// the final function.  If the domain exactly abuts
2449     /// the domain of the previous function, it
2450     /// will be directly attached.  If there is a gap, the gap will be filled
2451     /// in by linear interpolation.
2452     /// \param func a c2_function with a defined domain to be
2453     /// appended to the collection
2454     void append_function(const c2_function<float_type>& func)
2455       /* throw (c2_exception) */;
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