diff --git a/src/LambertW.cc b/src/LambertW.cc deleted file mode 100644 index ff5e933a05e15892b552b948706a0ff3bb01bab7..0000000000000000000000000000000000000000 --- a/src/LambertW.cc +++ /dev/null @@ -1,389 +0,0 @@ -/* - Implementation of Lambert W function - - Copyright (C) 2009 Darko Veberic, darko.veberic@ung.si - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <iostream> -#include <cmath> -#include <limits> - -using namespace std; - -namespace LambertWDetail { - -const double kInvE = 1 / M_E; - -template <int n> inline double BranchPointPolynomial(const double p); - -template <> inline double BranchPointPolynomial<1>(const double p) { - return -1 + p; -} - -template <> inline double BranchPointPolynomial<2>(const double p) { - return -1 + p * (1 + p * (-1. / 3)); -} - -template <> inline double BranchPointPolynomial<3>(const double p) { - return -1 + p * (1 + p * (-1. / 3 + p * (11. / 72))); -} - -template <> inline double BranchPointPolynomial<4>(const double p) { - return -1 + p * (1 + p * (-1. / 3 + p * (11. / 72 + p * (-43. / 540)))); -} - -template <> inline double BranchPointPolynomial<5>(const double p) { - return -1 + - p * (1 + p * (-1. / 3 + - p * (11. / 72 + p * (-43. / 540 + p * (769. / 17280))))); -} - -template <> inline double BranchPointPolynomial<6>(const double p) { - return -1 + p * (1 + p * (-1. / 3 + - p * (11. / 72 + - p * (-43. / 540 + p * (769. / 17280 + - p * (-221. / 8505)))))); -} - -template <> inline double BranchPointPolynomial<7>(const double p) { - return -1 + p * (1 + p * (-1. / 3 + - p * (11. / 72 + - p * (-43. / 540 + - p * (769. / 17280 + - p * (-221. / 8505 + - p * (680863. / 43545600))))))); -} - -template <> inline double BranchPointPolynomial<8>(const double p) { - return -1 + - p * (1 + p * (-1. / 3 + - p * (11. / 72 + - p * (-43. / 540 + - p * (769. / 17280 + - p * (-221. / 8505 + - p * (680863. / 43545600 + - p * (-1963. / 204120)))))))); -} - -template <> inline double BranchPointPolynomial<9>(const double p) { - return -1 + - p * (1 + p * (-1. / 3 + - p * (11. / 72 + - p * (-43. / 540 + - p * (769. / 17280 + - p * (-221. / 8505 + - p * (680863. / 43545600 + - p * (-1963. / 204120 + - p * (226287557. / - 37623398400.))))))))); -} - -template <int order> -inline double AsymptoticExpansion(const double a, const double b); - -template <> -inline double AsymptoticExpansion<0>(const double a, const double b) { - return a - b; -} - -template <> -inline double AsymptoticExpansion<1>(const double a, const double b) { - return a - b + b / a; -} - -template <> -inline double AsymptoticExpansion<2>(const double a, const double b) { - const double ia = 1 / a; - return a - b + b / a * (1 + ia * 0.5 * (-2 + b)); -} - -template <> -inline double AsymptoticExpansion<3>(const double a, const double b) { - const double ia = 1 / a; - return a - b + b / a * (1 + ia * (0.5 * (-2 + b) + - ia * 1 / 6. * (6 + b * (-9 + b * 2)))); -} - -template <> -inline double AsymptoticExpansion<4>(const double a, const double b) { - const double ia = 1 / a; - return a - b + - b / a * (1 + ia * (0.5 * (-2 + b) + - ia * (1 / 6. * (6 + b * (-9 + b * 2)) + - ia * 1 / 12. * - (-12 + b * (36 + b * (-22 + b * 3)))))); -} - -template <> -inline double AsymptoticExpansion<5>(const double a, const double b) { - const double ia = 1 / a; - return a - b + - b / a * - (1 + - ia * (0.5 * (-2 + b) + - ia * (1 / 6. * (6 + b * (-9 + b * 2)) + - ia * (1 / 12. * (-12 + b * (36 + b * (-22 + b * 3))) + - ia * 1 / 60. * - (60 + - b * (-300 + - b * (350 + b * (-125 + b * 12)))))))); -} - -template <int branch> class Branch { - -public: - template <int order> static double BranchPointExpansion(const double x) { - return BranchPointPolynomial<order>(eSign * sqrt(2 * (M_E * x + 1))); - } - - // Asymptotic expansion - // Corless et al. 1996, de Bruijn (1981) - template <int order> static double AsymptoticExpansion(const double x) { - const double logsx = log(eSign * x); - const double logslogsx = log(eSign * logsx); - return LambertWDetail::AsymptoticExpansion<order>(logsx, logslogsx); - } - - template <int n> static inline double RationalApproximation(const double x); - - // Logarithmic recursion - template <int order> static inline double LogRecursion(const double x) { - return LogRecursionStep<order>(log(eSign * x)); - } - - // generic approximation valid to at least 5 decimal places - static inline double Approximation(const double x); - -private: - // enum { eSign = 2*branch + 1 }; this doesn't work on gcc 3.3.3 - static const int eSign = 2 * branch + 1; - - template <int n> static inline double LogRecursionStep(const double logsx) { - return logsx - log(eSign * LogRecursionStep<n - 1>(logsx)); - } -}; - -// Rational approximations - -template <> -template <> -inline double Branch<0>::RationalApproximation<0>(const double x) { - return x * (60 + x * (114 + 17 * x)) / (60 + x * (174 + 101 * x)); -} - -template <> -template <> -inline double Branch<0>::RationalApproximation<1>(const double x) { - // branch 0, valid for [-0.31,0.3] - return x * - (1 + x * (5.931375839364438 + - x * (11.392205505329132 + - x * (7.338883399111118 + x * 0.6534490169919599)))) / - (1 + x * (6.931373689597704 + - x * (16.82349461388016 + - x * (16.43072324143226 + x * 5.115235195211697)))); -} - -template <> -template <> -inline double Branch<0>::RationalApproximation<2>(const double x) { - // branch 0, valid for [-0.31,0.5] - return x * (1 + x * (4.790423028527326 + - x * (6.695945075293267 + x * 2.4243096805908033))) / - (1 + x * (5.790432723810737 + - x * (10.986445930034288 + - x * (7.391303898769326 + x * 1.1414723648617864)))); -} - -template <> -template <> -inline double Branch<0>::RationalApproximation<3>(const double x) { - // branch 0, valid for [0.3,7] - return x * - (1 + - x * (2.4450530707265568 + - x * (1.3436642259582265 + - x * (0.14844005539759195 + x * 0.0008047501729129999)))) / - (1 + x * (3.4447089864860025 + - x * (3.2924898573719523 + - x * (0.9164600188031222 + x * 0.05306864044833221)))); -} - -template <> -template <> -inline double Branch<-1>::RationalApproximation<4>(const double x) { - // branch -1, valid for [-0.3,-0.05] - return (-7.814176723907436 + - x * (253.88810188892484 + x * 657.9493176902304)) / - (1 + - x * (-60.43958713690808 + - x * (99.98567083107612 + - x * (682.6073999909428 + - x * (962.1784396969866 + x * 1477.9341280760887))))); -} - -// stopping conditions - -template <> -template <> -inline double Branch<0>::LogRecursionStep<0>(const double logsx) { - return logsx; -} - -template <> -template <> -inline double Branch<-1>::LogRecursionStep<0>(const double logsx) { - return logsx; -} - -template <> inline double Branch<0>::Approximation(const double x) { - if (x < -0.32358170806015724) { - if (x < -kInvE) - return numeric_limits<double>::quiet_NaN(); - else if (x < -kInvE + 1e-5) - return BranchPointExpansion<5>(x); - else - return BranchPointExpansion<9>(x); - } else { - if (x < 0.14546954290661823) - return RationalApproximation<1>(x); - else if (x < 8.706658967856612) - return RationalApproximation<3>(x); - else - return AsymptoticExpansion<5>(x); - } -} - -template <> inline double Branch<-1>::Approximation(const double x) { - if (x < -0.051012917658221676) { - if (x < -kInvE + 1e-5) { - if (x < -kInvE) - return numeric_limits<double>::quiet_NaN(); - else - return BranchPointExpansion<5>(x); - } else { - if (x < -0.30298541769) - return BranchPointExpansion<9>(x); - else - return RationalApproximation<4>(x); - } - } else { - if (x < 0) - return LogRecursion<9>(x); - else if (x == 0) - return -numeric_limits<double>::infinity(); - else - return numeric_limits<double>::quiet_NaN(); - } -} - -// iterations - -inline double HalleyStep(const double x, const double w) { - const double ew = exp(w); - const double wew = w * ew; - const double wewx = wew - x; - const double w1 = w + 1; - return w - wewx / (ew * w1 - (w + 2) * wewx / (2 * w1)); -} - -inline double FritschStep(const double x, const double w) { - const double z = log(x / w) - w; - const double w1 = w + 1; - const double q = 2 * w1 * (w1 + (2 / 3.) * z); - const double eps = z / w1 * (q - z) / (q - 2 * z); - return w * (1 + eps); -} - -template <double IterationStep(const double x, const double w)> -inline double Iterate(const double x, double w, const double eps = 1e-6) { - for (int i = 0; i < 100; ++i) { - const double ww = IterationStep(x, w); - if (fabs(ww - w) <= eps) - return ww; - w = ww; - } - cerr << "convergence not reached." << endl; - return w; -} - -template <double IterationStep(const double x, const double w)> -struct Iterator { - - static double Do(const int n, const double x, const double w) { - double tmpw = w; - for (int i = 0; i < n; ++i) - tmpw = IterationStep(x, tmpw); - return tmpw; - } - - template <int n> static double Do(const double x, const double w) { - double tmpw = w; - for (int i = 0; i < n; ++i) - tmpw = IterationStep(x, tmpw); - return tmpw; - } - - template <int n, class = void> struct Depth { - static double Recurse(const double x, double w) { - return Depth<n - 1>::Recurse(x, IterationStep(x, w)); - } - }; - - // stop condition - template <class T> struct Depth<1, T> { - static double Recurse(const double x, const double w) { - return IterationStep(x, w); - } - }; - - // identity - template <class T> struct Depth<0, T> { - static double Recurse(const double x, const double w) { return w; } - }; -}; - -} // LambertWDetail - -template <int branch> double LambertWApproximation(const double x) { - return LambertWDetail::Branch<branch>::Approximation(x); -} - -// instantiations -template double LambertWApproximation<0>(const double x); -template double LambertWApproximation<-1>(const double x); - -template <int branch> double LambertW(const double x); - -template <> double LambertW<0>(const double x) { - if (fabs(x) > 1e-6 && x > -LambertWDetail::kInvE + 1e-5) - return LambertWDetail::Iterator<LambertWDetail::FritschStep>::Depth< - 1>::Recurse(x, LambertWApproximation<0>(x)); - else - return LambertWApproximation<0>(x); -} - -template <> double LambertW<-1>(const double x) { - if (x > -LambertWDetail::kInvE + 1e-5) - return LambertWDetail::Iterator<LambertWDetail::FritschStep>::Depth< - 1>::Recurse(x, LambertWApproximation<-1>(x)); - else - return LambertWApproximation<-1>(x); -} - -// instantiations -template double LambertW<0>(const double x); -template double LambertW<-1>(const double x); diff --git a/src/LambertW.h b/src/LambertW.h deleted file mode 100644 index 9bfd69f6127e696f3d78c34bf9f1ceeca5993dfc..0000000000000000000000000000000000000000 --- a/src/LambertW.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Implementation of Lambert W function - - Copyright (C) 2009 Darko Veberic, darko.veberic@ung.si - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _LambertW_h_ -#define _LambertW_h_ - -#include <limits> - - -/** - \author Darko Veberic - \version $Id: LambertW.h 14958 2009-10-19 11:11:19Z darko $ - \date 25 Jun 2009 -*/ - - -/** Approximate Lambert W function - Accuracy at least 5 decimal places in all definition range. - See LambertW() for details. - - \param branch: valid values are 0 and -1 - \param x: real-valued argument \f$\geq-1/e\f$ - \ingroup math -*/ - -template<int branch> -double LambertWApproximation(const double x); - - -/** Lambert W function - \image html LambertW.png - - Lambert function \f$y={\rm W}(x)\f$ is defined as a solution - to the \f$x=ye^y\f$ expression and is also known as - "product logarithm". Since the inverse of \f$ye^y\f$ is not - single-valued, the Lambert function has two real branches - \f${\rm W}_0\f$ and \f${\rm W}_{-1}\f$. - - \f${\rm W}_0(x)\f$ has real values in the interval - \f$[-1/e,\infty]\f$ and \f${\rm W}_{-1}(x)\f$ has real values - in the interval \f$[-1/e,0]\f$. - Accuracy is the nominal double type resolution - (16 decimal places). - - \param branch: valid values are 0 and -1 - \param x: real-valued argument \f$\geq-1/e\f$ (range depends on branch) - \ingroup math -*/ - -template<int branch> -double LambertW(const double x); - - -inline -double -LambertW(const int branch, const double x) -{ - switch (branch) { - case -1: return LambertW<-1>(x); - case 0: return LambertW<0>(x); - default: return std::numeric_limits<double>::quiet_NaN(); - } -} - - -#endif diff --git a/src/Makefile.am b/src/Makefile.am index 87969e8b7f83fb374ae1a799230fdd39b95c7369..d5647434ed71192049a79e627079b7d2bcb81472 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,6 @@ run-one-body-sample-gdb: one-body-sample libtool --mode execute gdb ./one-body-sample one_body_sample_SOURCES = \ - LambertW.cc \ assemblers.cc \ compute_state.cc \ one-body-sample.cc \ @@ -31,8 +30,6 @@ one_body_sample_SOURCES = \ vtk.cc one_body_sample_CPPFLAGS = \ $(AM_CPPFLAGS) -Dsrcdir=\"$(srcdir)\" -one_body_sample_LDADD = \ - $(LDADD) -lgsl test_gradient_method_SOURCES = \ test-gradient-method.cc diff --git a/src/compute_state.cc b/src/compute_state.cc index 27a6ef67ccc58df62b53dd28bf949532a760b3cf..fbbc3a8e598db8432a2fde504b32161989840403 100644 --- a/src/compute_state.cc +++ b/src/compute_state.cc @@ -1,9 +1,5 @@ #include <cassert> -#include "LambertW.h" - -#include <gsl/gsl_sf_lambert.h> - #include <dune/common/fvector.hh> #include <dune/common/fmatrix.hh> #include <dune/fufem/interval.hh> @@ -42,34 +38,11 @@ double compute_state_update_bisection(double h, double unorm, double L, return bisection.minimize(J, 0.0, 0.0, bisectionsteps); // TODO } -double compute_state_update_lambert(double h, double unorm, double L, - double old_state) { - double const rhs = unorm / L - old_state; - return LambertW(0, h * std::exp(rhs)) - rhs; -} - -double compute_state_update_lambert_gsl(double h, double unorm, double L, - double old_state) { - double const rhs = unorm / L - old_state; - return gsl_sf_lambert_W0(h * std::exp(rhs)) - rhs; -} - double compute_state_update(double h, double unorm, double L, double old_state) { double ret1 = compute_state_update_bisection(h, unorm, L, old_state); assert(std::abs(1.0 / h * ret1 - (old_state - unorm / L) / h - - std::exp(-ret1)) < 1e-10); - - double ret2 = compute_state_update_lambert(h, unorm, L, old_state); - assert(std::abs(1.0 / h * ret2 - (old_state - unorm / L) / h - - std::exp(-ret2)) < 1e-10); - - double ret3 = compute_state_update_lambert_gsl(h, unorm, L, old_state); - assert(std::abs(1.0 / h * ret3 - (old_state - unorm / L) / h - - std::exp(-ret3)) < 1e-10); - - assert(std::abs(ret1 - ret2) < 1e-14); - assert(std::abs(ret1 - ret3) < 1e-14); + std::exp(-ret1)) < 1e-8); return ret1; }