flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
Li.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// FlexibleSUSY is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
19#include "Li.hpp"
20#include "Li2.hpp"
21#include "Li3.hpp"
22#include "Li4.hpp"
23#include "Li5.hpp"
24#include "Li6.hpp"
25#include "eta.hpp"
26#include "factorial.hpp"
27#include "harmonic.hpp"
28#include "zeta.hpp"
29#include <cmath>
30#include <complex>
31#include <cstdint>
32#include <limits>
33
34namespace flexiblesusy {
35
36namespace {
37 constexpr double inf = std::numeric_limits<double>::infinity();
38 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
39 constexpr double PI = 3.1415926535897932;
40
41 constexpr bool is_even(int64_t n) noexcept { return n % 2 == 0; }
42
43 constexpr bool is_finite(const std::complex<double>& z) noexcept
44 {
45 return std::isfinite(std::real(z)) && std::isfinite(std::imag(z));
46 }
47
49 std::complex<double> clog(const std::complex<double>& z) noexcept
50 {
51 if (std::imag(z) == 0.0 && std::real(z) > 0.0) {
52 return { std::log(std::real(z)), 0.0 };
53 } else if (std::imag(z) == 0.0) {
54 return { std::log(-std::real(z)), PI };
55 }
56 return { std::log(std::hypot(std::real(z), std::imag(z))), std::arg(z) };
57 }
58
61 std::complex<double> Li_series(int64_t n, const std::complex<double>& z) noexcept
62 {
63 std::complex<double> sum(0.0, 0.0), sum_old(0.0, 0.0), p = z;
64 int64_t k = 0;
65
66 do {
67 k++;
68 sum_old = sum;
69 sum += p;
70 p *= z*std::pow(k/(1.0 + k), n);
71 if (!is_finite(p)) { break; }
72 } while (sum != sum_old &&
73 k < std::numeric_limits<int64_t>::max() - 2);
74
75 return sum;
76 }
77
79 std::complex<double> Li_unity_pos(int64_t n, const std::complex<double>& z) noexcept
80 {
81 const std::complex<double> lnz = clog(z);
82 const std::complex<double> lnz2 = lnz*lnz;
83 std::complex<double> sum(zeta(n), 0.0), p(1.0, 0.0);
84
85 for (int64_t j = 1; j < n - 1; ++j) {
86 p *= lnz/static_cast<double>(j);
87 sum += zeta(n - j)*p;
88 }
89
90 p *= lnz/static_cast<double>(n - 1);
91 sum += (harmonic(n - 1) - clog(-lnz))*p;
92
93 p *= lnz/static_cast<double>(n);
94 sum += zeta(0)*p;
95
96 p *= lnz/static_cast<double>(n + 1);
97 sum += zeta(-1)*p;
98
99 for (int64_t j = (n + 3); j < std::numeric_limits<int64_t>::max() - 2; j += 2) {
100 p *= lnz2/static_cast<double>((j - 1)*j);
101 const auto old_sum = sum;
102 sum += zeta(n - j)*p;
103 if (sum == old_sum) { break; }
104 }
105
106 return sum;
107 }
108
110 std::complex<double> stable_pow(const std::complex<double>& z, int64_t n) noexcept
111 {
112 if (std::imag(z) == 0) {
113 return { std::pow(std::real(z), n), 0.0 };
114 } else if (std::real(z) == 0) {
115 const double p = std::pow(std::imag(z), n);
116 if (n % 4 == 0) {
117 return { p, 0.0 };
118 } else if (n % 2 == 0) {
119 return { -p, 0.0 };
120 } else if ((n - 1) % 4 == 0) {
121 return { 0.0, p };
122 }
123 return { 0.0, -p };
124 }
125 return std::pow(z, n);
126 }
127
129 std::complex<double> Li_unity_neg(int64_t n, const std::complex<double>& z) noexcept
130 {
131 const std::complex<double> lnz = clog(z);
132 const std::complex<double> lnz2 = lnz*lnz;
133 std::complex<double> sum = std::tgamma(1 - n)*stable_pow(-lnz, n - 1);
134 std::complex<double> lnzk, sum_old, term;
135 int64_t k;
136
137 if (is_even(n)) {
138 lnzk = lnz;
139 k = 1;
140 } else {
141 lnzk = lnz2;
142 sum += zeta(n);
143 k = 2;
144 }
145
146 do {
147 term = zeta(n - k)*inv_fac(k)*lnzk;
148 if (!is_finite(term)) { break; }
149 sum_old = sum;
150 sum += term;
151 lnzk *= lnz2;
152 k += 2;
153 } while (sum != sum_old);
154
155 return sum;
156 }
157
159 std::complex<double> Li_rest(int64_t n, const std::complex<double>& z) noexcept
160 {
161 const std::complex<double> lnz = clog(-z);
162 const std::complex<double> lnz2 = lnz*lnz;
163 const int64_t kmax = is_even(n) ? n/2 : (n - 1)/2;
164 std::complex<double> p = is_even(n) ? 1.0 : lnz;
165 std::complex<double> sum(0.0, 0.0), old_sum;
166
167 for (int64_t k = kmax; k != 0; --k) {
168 const double ifac = inv_fac(n - 2*k);
169 if (ifac == 0) { return 2.0*sum; }
170 sum += neg_eta(2*k)*ifac*p;
171 p *= lnz2;
172 if (sum == old_sum) { break; }
173 }
174
175 return 2.0*sum - p*inv_fac(n);
176 }
177
178} // anonymous namespace
179
191std::complex<double> Li(int64_t n, const std::complex<double>& z) noexcept
192{
193 if (std::isnan(std::real(z)) || std::isnan(std::imag(z))) {
194 return {nan, nan};
195 } else if (std::isinf(std::real(z)) || std::isinf(std::imag(z))) {
196 return {-inf, 0.0};
197 } else if (z == 0.0) {
198 return z;
199 } else if (z == 1.0) {
200 if (n <= 0) {
201 return {inf, inf};
202 }
203 return {zeta(n), std::imag(z)};
204 } else if (z == -1.0) {
205 return {neg_eta(n), std::imag(z)};
206 } else if (n < -1) {
207 // arXiv:2010.09860
208 const double nz = std::norm(z);
209 const double nl = std::norm(clog(z));
210 if (4*PI*PI*nz < nl) {
211 return Li_series(n, z);
212 } else if (nl < 0.512*0.512*4*PI*PI) {
213 return Li_unity_neg(n, z);
214 }
215 const auto sqrtz = std::sqrt(z);
216 return std::exp2(n - 1)*(Li(n, sqrtz) + Li(n, -sqrtz));
217 } else if (n == -1) {
218 return z/((1.0 - z)*(1.0 - z));
219 } else if (n == 0) {
220 return z/(1.0 - z);
221 } else if (n == 1) {
222 return -clog(1.0 - z);
223 } else if (n == 2) {
224 return Li2(z);
225 } else if (n == 3) {
226 return Li3(z);
227 } else if (n == 4) {
228 return Li4(z);
229 } else if (n == 5) {
230 return Li5(z);
231 } else if (n == 6) {
232 return Li6(z);
233 } else if (std::norm(z) <= 0.75*0.75) {
234 return Li_series(n, z);
235 } else if (std::norm(z) >= 1.4*1.4) {
236 const double sgn = is_even(n) ? -1.0 : 1.0;
237 return sgn*Li_series(n, 1.0/z) + Li_rest(n, z);
238 }
239 return Li_unity_pos(n, z);
240}
241
242} // namespace flexiblesusy
std::complex< double > Li_series(int64_t n, const std::complex< double > &z) noexcept
Definition Li.cpp:61
std::complex< double > clog(const std::complex< double > &z) noexcept
complex logarithm, converts -0.0 to 0.0
Definition Li.cpp:49
std::complex< double > stable_pow(const std::complex< double > &z, int64_t n) noexcept
returns z^n, treating Re(z) == 0 and Im(z) == 0 in a stable way
Definition Li.cpp:110
std::complex< double > Li_unity_neg(int64_t n, const std::complex< double > &z) noexcept
Series expansion of Li_n(z) around z ~ 1, n < 0.
Definition Li.cpp:129
std::complex< double > Li_rest(int64_t n, const std::complex< double > &z) noexcept
returns remainder from inversion formula
Definition Li.cpp:159
std::complex< double > Li_unity_pos(int64_t n, const std::complex< double > &z) noexcept
Series expansion of Li_n(z) around z ~ 1, n > 0.
Definition Li.cpp:79
double neg_eta(int64_t n) noexcept
negative Dirichlet eta function
Definition eta.cpp:81
std::complex< double > Li(int64_t n, const std::complex< double > &z) noexcept
Complex polylogarithm .
Definition Li.cpp:191
double zeta(int64_t n) noexcept
Riemann zeta function for integer arguments.
Definition zeta.cpp:83
double Li4(double x) noexcept
Real 4-th order polylogarithm .
Definition Li4.cpp:131
float Li2(float x) noexcept
Real dilogarithm .
Definition Li2.cpp:38
std::complex< double > Li5(const std::complex< double > &z) noexcept
Complex polylogarithm .
Definition Li5.cpp:34
bool is_finite(const gsl_vector *x)
Returns true if GSL vector contains only finite elements, false otherwise.
Definition gsl_utils.cpp:32
double Li3(double x) noexcept
Real trilogarithm .
Definition Li3.cpp:88
double harmonic(int64_t n) noexcept
harmonic number n
Definition harmonic.cpp:54
double inv_fac(int64_t n) noexcept
negative Dirichlet eta function
Definition factorial.cpp:80
std::complex< double > Li6(const std::complex< double > &z) noexcept
Complex polylogarithm .
Definition Li6.cpp:34
auto sum(Idx ini, Idx fin, Function f) -> decltype(EvalEigenXpr< Idx >(ini, f))
Definition sum.hpp:91