/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitCore                                                       *
 *    File: $Id: RooMath.h,v 1.16 2007/05/11 09:11:30 verkerke Exp $
 * Authors:                                                                  *
 *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
 *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
 *                                                                           *
 * Copyright (c) 2000-2005, Regents of the University of California          *
 *                          and Stanford University. All rights reserved.    *
 *                                                                           *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/
#ifndef ROO_MATH
#define ROO_MATH

#include <cmath>
#include <complex>

#include "Rtypes.h"
#include "TMath.h"
#include "RooComplex.h"

#if defined(__my_func__)
#undef __my_func__
#endif
#if defined(WIN32)
#define __my_func__ __FUNCTION__
#else
#define __my_func__ __func__
#endif

typedef Double_t* pDouble_t;

class RooMath {
public:

  virtual ~RooMath() {};

  /** @brief evaluate Faddeeva function for complex argument
   *
   * @author Manuel Schiller <manuel.schiller@nikhef.nl>
   * @date 2013-02-21
   *
   * Calculate the value of the Faddeeva function @f$w(z) = \exp(-z^2)
   * \mathrm{erfc}(-i z)@f$.
   *
   * The method described in
   *
   * S.M. Abrarov, B.M. Quine: "Efficient algotithmic implementation of
   * Voigt/complex error function based on exponential series approximation"
   * published in Applied Mathematics and Computation 218 (2011) 1894-1902
   * doi:10.1016/j.amc.2011.06.072
   *
   * is used. At the heart of the method (equation (14) of the paper) is the
   * following Fourier series based approximation:
   *
   * @f[ w(z) \approx \frac{i}{2\sqrt{\pi}}\left(
   * \sum^N_{n=0} a_n \tau_m\left(
   * \frac{1-e^{i(n\pi+\tau_m z)}}{n\pi + \tau_m z} -
   * \frac{1-e^{i(-n\pi+\tau_m z)}}{n\pi - \tau_m z}
   * \right) - a_0 \frac{1-e^{i \tau_m z}}{z}
   * \right) @f]
   * 
   * The coefficients @f$a_b@f$ are given by:
   *
   * @f[ a_n=\frac{2\sqrt{\pi}}{\tau_m}
   * \exp\left(-\frac{n^2\pi^2}{\tau_m^2}\right) @f]
   *
   * To achieve machine accuracy in double precision floating point arithmetic
   * for most of the upper half of the complex plane, chose @f$t_m=12@f$ and
   * @f$N=23@f$ as is done in the paper.
   *
   * There are two complications: For Im(z) negative, the exponent in the
   * equation above becomes so large that the roundoff in the rest of the
   * calculation is amplified enough that the result cannot be trusted.
   * Therefore, for Im(z) < 0, the symmetry of the erfc function under the
   * transformation z --> -z is used to avoid accuracy issues for Im(z) < 0 by
   * formulating the problem such that the calculation can be done for Im(z) > 0
   * where the accuracy of the method is fine, and some postprocessing then
   * yields the desired final result.
   *
   * Second, the denominators in the equation above become singular at
   * @f$z = n * pi / 12@f$ (for 0 <= n < 24). In a tiny disc around these
   * points, Taylor expansions are used to overcome that difficulty.
   *
   * This routine precomputes everything it can, and tries to write out complex
   * operations to minimise subroutine calls, e.g. for the multiplication of
   * complex numbers.
   *
   * In the square -8 <= Re(z) <= 8, -8 <= Im(z) <= 8, the routine is accurate
   * to better than 4e-13 relative, the average relative error is better than
   * 7e-16. On a modern x86_64 machine, the routine is roughly three times as
   * fast than the old CERNLIB implementation and offers better accuracy.
   *
   * For large @f$|z|@f$, the familiar continued fraction approximation
   * 
   * @f[ w(z)=\frac{-iz/\sqrt{\pi}}{-z^2+\frac{1/2}{1+\frac{2/2}{-z^2 +
   * \frac{3/2}{1+\frac{4/2}{-z^2+\frac{5/2}{1+\frac{6/2}{-z^2+\frac{7/2
   * }{1+\frac{8/2}{-z^2+\frac{9/2}{1+\ldots}}}}}}}}}} @f]
   *
   * is used, truncated at the ellipsis ("...") in the formula; for @f$|z| >
   * 12@f$, @f$Im(z)>0@f$ it will give full double precision at a smaller
   * computational cost than the method described above. (For @f$|z|>12@f$,
   * @f$Im(z)<0@f$, the symmetry property @f$w(x-iy)=2e^{-(x+iy)^2-w(x+iy)}@f$
   * is used.
   */
  static std::complex<double> faddeeva(std::complex<double> z);
  /** @brief evaluate Faddeeva function for complex argument (fast version)
   *
   * @author Manuel Schiller <manuel.schiller@nikhef.nl>
   * @date 2013-02-21
   *
   * Calculate the value of the Faddeeva function @f$w(z) = \exp(-z^2)
   * \mathrm{erfc}(-i z)@f$.
   *
   * This is the "fast" version of the faddeeva routine above. Fast means that
   * is takes roughly half the amount of CPU of the slow version of the
   * routine, but is a little less accurate.
   *
   * To be fast, chose @f$t_m=8@f$ and @f$N=11@f$ which should give accuracies
   * around 1e-7.
   *
   * In the square -8 <= Re(z) <= 8, -8 <= Im(z) <= 8, the routine is accurate
   * to better than 4e-7 relative, the average relative error is better than
   * 5e-9. On a modern x86_64 machine, the routine is roughly five times as
   * fast than the old CERNLIB implementation, or about 30% faster than the
   * interpolation/lookup table based fast method used previously in RooFit,
   * and offers better accuracy than the latter (the relative error is roughly
   * a factor 280 smaller than the old interpolation/table lookup routine).
   *
   * For large @f$|z|@f$, the familiar continued fraction approximation
   * 
   * @f[ w(z)=\frac{-iz/\sqrt{\pi}}{-z^2+\frac{1/2}{1+\frac{2/2}{-z^2 +
   * \frac{3/2}{1+\ldots}}}} @f]
   *
   * is used, truncated at the ellipsis ("...") in the formula; for @f$|z| >
   * 8@f$, @f$Im(z)>0@f$ it will give full float precision at a smaller
   * computational cost than the method described above. (For @f$|z|>8@f$,
   * @f$Im(z)<0@f$, the symmetry property @f$w(x-iy)=2e^{-(x+iy)^2-w(x+iy)}@f$
   * is used.
   */
  static std::complex<double> faddeeva_fast(std::complex<double> z);

  /** @brief complex erf function
   *
   * @author Manuel Schiller <manuel.schiller@nikhef.nl>
   * @date 2013-02-21
   *
   * Calculate erf(z) for complex z.
   */
  static std::complex<double> erf(const std::complex<double> z);

  /** @brief complex erf function (fast version)
   *
   * @author Manuel Schiller <manuel.schiller@nikhef.nl>
   * @date 2013-02-21
   *
   * Calculate erf(z) for complex z. Use the code in faddeeva_fast to save some time.
   */
  static std::complex<double> erf_fast(const std::complex<double> z);
  /** @brief complex erfc function
   *
   * @author Manuel Schiller <manuel.schiller@nikhef.nl>
   * @date 2013-02-21
   *
   * Calculate erfc(z) for complex z.
   */
  static std::complex<double> erfc(const std::complex<double> z);
  /** @brief complex erfc function (fast version)
   *
   * @author Manuel Schiller <manuel.schiller@nikhef.nl>
   * @date 2013-02-21
   *
   * Calculate erfc(z) for complex z. Use the code in faddeeva_fast to save some time.
   */
  static std::complex<double> erfc_fast(const std::complex<double> z);

  // 1-D nth order polynomial interpolation routines
  static Double_t interpolate(Double_t yArr[],Int_t nOrder, Double_t x) ;
  static Double_t interpolate(Double_t xa[], Double_t ya[], Int_t n, Double_t x) ;

  static inline Double_t erf(Double_t x)
  { return TMath::Erf(x); }

  static inline Double_t erfc(Double_t x)
  { return TMath::Erfc(x); }
  
  /// deprecated function
  static RooComplex ComplexErrFunc(Double_t re, Double_t im = 0.)
  { warn(__my_func__, "RooMath::faddeeva"); std::complex<Double_t> z = faddeeva(std::complex<Double_t>(re, im)); return RooComplex(z.real(), z.imag()); }
  /// deprecated function
  static RooComplex ComplexErrFunc(const RooComplex& zz)
  { warn(__my_func__, "RooMath::faddeeva"); std::complex<Double_t> z = faddeeva(std::complex<Double_t>(zz.re(), zz.im())); return RooComplex(z.real(), z.imag()); }
  /// deprecated function
  static RooComplex ComplexErrFuncFast(const RooComplex& zz)
  { warn(__my_func__, "RooMath::faddeeva_fast"); std::complex<Double_t> z = faddeeva_fast(std::complex<Double_t>(zz.re(), zz.im())); return RooComplex(z.real(), z.imag()); }
  /// deprecated function
  static Double_t ComplexErrFuncFastRe(const RooComplex& zz)
  { warn(__my_func__, "RooMath::faddeeva_fast"); std::complex<Double_t> z = faddeeva_fast(std::complex<Double_t>(zz.re(), zz.im())); return z.real(); }
  /// deprecated function
  static Double_t ComplexErrFuncFastIm(const RooComplex& zz)
  { warn(__my_func__, "RooMath::faddeeva_fast"); std::complex<Double_t> z = faddeeva_fast(std::complex<Double_t>(zz.re(), zz.im())); return z.imag(); }
  /// deprecated function
  static RooComplex ITPComplexErrFuncFast(const RooComplex& zz, Int_t)
  { warn(__my_func__, "RooMath::faddeeva_fast"); std::complex<Double_t> z = faddeeva_fast(std::complex<Double_t>(zz.re(), zz.im())); return RooComplex(z.real(), z.imag()); }
  /// deprecated function
  static Double_t ITPComplexErrFuncFastRe(const RooComplex& zz, Int_t)
  { warn(__my_func__, "RooMath::faddeeva_fast"); std::complex<Double_t> z = faddeeva_fast(std::complex<Double_t>(zz.re(), zz.im())); return z.real(); }
  /// deprecated function
  static Double_t ITPComplexErrFuncFastIm(const RooComplex& zz, Int_t)
  { warn(__my_func__, "RooMath::faddeeva_fast"); std::complex<Double_t> z = faddeeva_fast(std::complex<Double_t>(zz.re(), zz.im())); return z.imag(); }
  /// deprecated function
  static void cacheCERF(Bool_t) { warn(__my_func__); }
  /// deprecated function
  static void cleanup() { warn(__my_func__); }
  /// deprecated function
  static void initFastCERF(Int_t /*reBins =  800*/, Double_t /*reMin = -4.0*/, Double_t /*reMax = 4.0*/, 
			   Int_t /*imBins = 1000*/, Double_t /*imMin = -4.0*/, Double_t /*imMax = 6.0*/)
  {
    warn(__my_func__);
  }
  
private:
  // deprecation warnings
  static void warn(const char* oldfun, const char* newfun = 0);

  ClassDef(RooMath,0) // math utility routines
};

#undef __my_func__

#endif
 RooMath.h:1
 RooMath.h:2
 RooMath.h:3
 RooMath.h:4
 RooMath.h:5
 RooMath.h:6
 RooMath.h:7
 RooMath.h:8
 RooMath.h:9
 RooMath.h:10
 RooMath.h:11
 RooMath.h:12
 RooMath.h:13
 RooMath.h:14
 RooMath.h:15
 RooMath.h:16
 RooMath.h:17
 RooMath.h:18
 RooMath.h:19
 RooMath.h:20
 RooMath.h:21
 RooMath.h:22
 RooMath.h:23
 RooMath.h:24
 RooMath.h:25
 RooMath.h:26
 RooMath.h:27
 RooMath.h:28
 RooMath.h:29
 RooMath.h:30
 RooMath.h:31
 RooMath.h:32
 RooMath.h:33
 RooMath.h:34
 RooMath.h:35
 RooMath.h:36
 RooMath.h:37
 RooMath.h:38
 RooMath.h:39
 RooMath.h:40
 RooMath.h:41
 RooMath.h:42
 RooMath.h:43
 RooMath.h:44
 RooMath.h:45
 RooMath.h:46
 RooMath.h:47
 RooMath.h:48
 RooMath.h:49
 RooMath.h:50
 RooMath.h:51
 RooMath.h:52
 RooMath.h:53
 RooMath.h:54
 RooMath.h:55
 RooMath.h:56
 RooMath.h:57
 RooMath.h:58
 RooMath.h:59
 RooMath.h:60
 RooMath.h:61
 RooMath.h:62
 RooMath.h:63
 RooMath.h:64
 RooMath.h:65
 RooMath.h:66
 RooMath.h:67
 RooMath.h:68
 RooMath.h:69
 RooMath.h:70
 RooMath.h:71
 RooMath.h:72
 RooMath.h:73
 RooMath.h:74
 RooMath.h:75
 RooMath.h:76
 RooMath.h:77
 RooMath.h:78
 RooMath.h:79
 RooMath.h:80
 RooMath.h:81
 RooMath.h:82
 RooMath.h:83
 RooMath.h:84
 RooMath.h:85
 RooMath.h:86
 RooMath.h:87
 RooMath.h:88
 RooMath.h:89
 RooMath.h:90
 RooMath.h:91
 RooMath.h:92
 RooMath.h:93
 RooMath.h:94
 RooMath.h:95
 RooMath.h:96
 RooMath.h:97
 RooMath.h:98
 RooMath.h:99
 RooMath.h:100
 RooMath.h:101
 RooMath.h:102
 RooMath.h:103
 RooMath.h:104
 RooMath.h:105
 RooMath.h:106
 RooMath.h:107
 RooMath.h:108
 RooMath.h:109
 RooMath.h:110
 RooMath.h:111
 RooMath.h:112
 RooMath.h:113
 RooMath.h:114
 RooMath.h:115
 RooMath.h:116
 RooMath.h:117
 RooMath.h:118
 RooMath.h:119
 RooMath.h:120
 RooMath.h:121
 RooMath.h:122
 RooMath.h:123
 RooMath.h:124
 RooMath.h:125
 RooMath.h:126
 RooMath.h:127
 RooMath.h:128
 RooMath.h:129
 RooMath.h:130
 RooMath.h:131
 RooMath.h:132
 RooMath.h:133
 RooMath.h:134
 RooMath.h:135
 RooMath.h:136
 RooMath.h:137
 RooMath.h:138
 RooMath.h:139
 RooMath.h:140
 RooMath.h:141
 RooMath.h:142
 RooMath.h:143
 RooMath.h:144
 RooMath.h:145
 RooMath.h:146
 RooMath.h:147
 RooMath.h:148
 RooMath.h:149
 RooMath.h:150
 RooMath.h:151
 RooMath.h:152
 RooMath.h:153
 RooMath.h:154
 RooMath.h:155
 RooMath.h:156
 RooMath.h:157
 RooMath.h:158
 RooMath.h:159
 RooMath.h:160
 RooMath.h:161
 RooMath.h:162
 RooMath.h:163
 RooMath.h:164
 RooMath.h:165
 RooMath.h:166
 RooMath.h:167
 RooMath.h:168
 RooMath.h:169
 RooMath.h:170
 RooMath.h:171
 RooMath.h:172
 RooMath.h:173
 RooMath.h:174
 RooMath.h:175
 RooMath.h:176
 RooMath.h:177
 RooMath.h:178
 RooMath.h:179
 RooMath.h:180
 RooMath.h:181
 RooMath.h:182
 RooMath.h:183
 RooMath.h:184
 RooMath.h:185
 RooMath.h:186
 RooMath.h:187
 RooMath.h:188
 RooMath.h:189
 RooMath.h:190
 RooMath.h:191
 RooMath.h:192
 RooMath.h:193
 RooMath.h:194
 RooMath.h:195
 RooMath.h:196
 RooMath.h:197
 RooMath.h:198
 RooMath.h:199
 RooMath.h:200
 RooMath.h:201
 RooMath.h:202
 RooMath.h:203
 RooMath.h:204
 RooMath.h:205
 RooMath.h:206
 RooMath.h:207
 RooMath.h:208
 RooMath.h:209
 RooMath.h:210
 RooMath.h:211
 RooMath.h:212
 RooMath.h:213
 RooMath.h:214
 RooMath.h:215
 RooMath.h:216
 RooMath.h:217
 RooMath.h:218
 RooMath.h:219
 RooMath.h:220
 RooMath.h:221
 RooMath.h:222
 RooMath.h:223
 RooMath.h:224
 RooMath.h:225
 RooMath.h:226
 RooMath.h:227
 RooMath.h:228
 RooMath.h:229
 RooMath.h:230
 RooMath.h:231
 RooMath.h:232
 RooMath.h:233
 RooMath.h:234
 RooMath.h:235