v0.15.5
Loading...
Searching...
No Matches
lambert_w_raw.hpp
Go to the documentation of this file.
1
2// Copyright Balazs Cziraki 2016.
3// Use, modification and distribution are subject to the
4// Boost Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_MATH_LAMBERT_W_RAW_HPP_INCLUDED
8#define BOOST_MATH_LAMBERT_W_RAW_HPP_INCLUDED
9
10#include <cmath>
11#include <complex>
12#include <boost/math/special_functions/fpclassify.hpp>
13#include <boost/math/special_functions/round.hpp>
14#include <boost/math/policies/policy.hpp>
15#include "lambert_w_tools.hpp"
16#include "lambert_w_tay.hpp"
17#include "lambert_w_laur.hpp"
18#include "lambert_w_sing.hpp"
19#include "lambert_w_asy.hpp"
20#include "lambert_w_mid.hpp"
21#include "lambert_w_iter.hpp"
22
23#define BOOST_MATH_LAMBERT_W_NEWTON_ITERATION
24#define BOOST_MATH_LAMBERT_W_FRITSCH_ITERATION
25
26namespace boost
27{
28namespace math
29{
30namespace lambw
31{
32 //Unfinished dynamic approximation selector
33 /*
34 template<class ArgumentType, std::size_t L>
35 ArgumentType _best_approx(const ArgumentType &z, const boost::array<ArgumentType,L> &approxes)
36 {
37 int prec;
38 int prec_max = _test_score(z,approxes[0]);
39 std::size_t max_place = 0;
40
41 for(std::size_t k = 1; k < approxes.size(); ++k)
42 {
43 prec = _test_score(z,approxes[k]);
44 if(prec_max < prec)
45 {
46 prec_max = prec;
47 max_place = k;
48 }
49 }
50 return approxes[max_place];
51 }
52 */
53
54 //This function determines which approximation to use as input for iterations, then applies those iterations.
55 //It makes a few Newton's method iterations to refine the input for Fritsch's iteration, which runs until it hits machine precision.
56 //Policies are accepted as arguments, but because this function template accepts both real and complex values,
57 //policy-based errors have not been introduced in here. Instead, there are separate checking function following this one.
58 template<class ArgumentType, class CoeffType, class IndexType, class Policy>
59 ArgumentType _raw(const ArgumentType &z, IndexType k, const Policy& pol)
60 {
61 using std::abs;
62 using std::exp;
63
64 ArgumentType w;
65
66 CoeffType z_imag = _complex_imag(z);
67
68 if(k==-1)
69 {
70 if(abs(z+(CoeffType)0.04)<=0.14 && z_imag>=0)
71 {
72 w = _N1<ArgumentType,CoeffType>(z);
73 }
74 else
75 {
76 if(abs(z+rec_e<CoeffType>())<0.3 && z_imag>=0)
77 {
78 w = _sing<ArgumentType,CoeffType,IndexType>(z,k);
79 }
80 else
81 {
82 w = _asy<ArgumentType,CoeffType,IndexType>(z,-1);
83 }
84 }
85 }
86 else
87 {
88 if(k==1)
89 {
90 if(abs(z+(CoeffType)0.04)<=0.14 && z_imag<0)
91 {
92 w = _N1<ArgumentType,CoeffType>(z);
93 }
94 else
95 {
96 if(abs(z+rec_e<CoeffType>())<0.3 && z_imag<0)
97 {
98 w = _sing<ArgumentType,CoeffType,IndexType>(z,k);
99 }
100 else
101 {
102 w = _asy<ArgumentType,CoeffType,IndexType>(z,1);
103 }
104 }
105 }
106 else
107 {
108 if(k!=0)
109 {
110 w = _asy<ArgumentType,CoeffType,IndexType>(z,k);
111 }
112 else
113 {
114 if(abs(z-(CoeffType)0.02)<0.28)
115 {
116 w = _laur<ArgumentType,CoeffType>(z);
117 }
118 else
119 {
120 if(abs(z+rec_e<CoeffType>())<0.3)
121 {
122 w = _sing<ArgumentType,CoeffType,IndexType>(z,k);
123 }
124 else
125 {
126 if(abs(z-(CoeffType)8.)<13)
127 {
128 w = _mid<ArgumentType,CoeffType>(z);
129 }
130 else
131 {
132 w = _asy<ArgumentType,CoeffType,IndexType>(z,0);
133 }
134 }
135 }
136 }
137 }
138 }
139
140 ///Unfinished dynamic approximation selector
141 /*
142 if(k == 0)
143 {
144 boost::array<ArgumentType,4> approxes = {_laur<ArgumentType,CoeffType>(z),
145 _sing<ArgumentType,CoeffType,IndexType>(z,0),
146 _mid<ArgumentType,CoeffType>(z),
147 _asy<ArgumentType,CoeffType,IndexType>(z,0)};
148 w = _best_approx(z,approxes);
149 }
150 else if(k == -1)
151 {
152 if(_complex_imag(z) >= 0)
153 {
154 boost::array<ArgumentType,3> approxes = {_sing<ArgumentType,CoeffType,IndexType>(z,-1),
155 _N1<ArgumentType,CoeffType>(z),
156 _asy<ArgumentType,CoeffType,IndexType>(z,-1)};
157 w = _best_approx(z,approxes);
158 }
159 else
160 {
161 w = _asy<ArgumentType,CoeffType,IndexType>(z,-1);
162 }
163 }
164 else if(k == 1)
165 {
166 if(_complex_imag(z) < 0)
167 {
168 boost::array<ArgumentType,3> approxes = {_sing<ArgumentType,CoeffType,IndexType>(z,1),
169 _N1<ArgumentType,CoeffType>(z),
170 _asy<ArgumentType,CoeffType,IndexType>(z,1)};
171 w = _best_approx(z,approxes);
172 }
173 else
174 {
175 w = _asy<ArgumentType,CoeffType,IndexType>(z,1);
176 }
177 }
178 else
179 {
180 w = _asy<ArgumentType,CoeffType,IndexType>(z,k);
181 }
182 */
183
184 if( (boost::math::isnan(_complex_real(w))
185 ||boost::math::isnan(_complex_imag(w)))
186 || (_complex_real(z)==0.
187 && _complex_imag(z)==0.) )
188 {
189 return w;
190 }
191
192 CoeffType err = abs(_test_s<ArgumentType>(z,w,pol));
193
194 #ifdef BOOST_MATH_LAMBERT_W_NEWTON_ITERATION
195 for(std::size_t cntr = 0; cntr < 3; ++cntr)
196 {
197 _iter_newt<ArgumentType,CoeffType,IndexType>(z,k,w);
198 }
199 #endif
200
201 ArgumentType w_prev = w;
202
203 CoeffType err_prev;
204
205 #ifdef BOOST_MATH_LAMBERT_W_FRITSCH_ITERATION
206 do
207 {
208 err_prev = err;
209 w_prev = w;
210 _iter_frit<ArgumentType,CoeffType,IndexType>(z,k,w);
211 err = abs(_test_s<ArgumentType>(z,w,pol));
212 }
213 while(err < err_prev);
214
215 _iter_newt<ArgumentType,CoeffType,IndexType>(z,k,w_prev);
216 #endif
217
218 return w_prev;
219 }
220
221 //Checks for errors in input arguments and the return value using the policy pol for real valued arguments.
222 template<class ArgumentType, class IndexType, class Policy>
223 inline ArgumentType _with_real_range_checks(const ArgumentType& z, const IndexType& k, const Policy& pol)
224 {
225 ArgumentType w = (ArgumentType)0.;
226
227 if(boost::math::isnan(z))
228 {
229 w = boost::math::policies::raise_evaluation_error<ArgumentType>("lambert_w(%1%,IndexType)", "Argument value %1% is Not-a-Number!",z,pol);
230 }
231 else if( ( k == 0 || k == -1 ) )
232 {
233 if( z < -lambw::rec_e<ArgumentType>())
234 {
235 w = boost::math::policies::raise_domain_error<ArgumentType>("lambert_w(%1%,IndexType)", "Argument value %1% out of range for real arguments.", z, pol);
236 }
237 else if( (k == 0) && (z == std::numeric_limits<ArgumentType>::infinity()) )
238 {
239 w = boost::math::policies::raise_overflow_error<ArgumentType>("lambert_w(%1%,IndexType)", "Result value overflow for an infinite argument at 0 index.", pol);
240 }
241 else if( k == -1 )
242 {
243 if(z == -0.)
244 {
245 w = -boost::math::policies::raise_overflow_error<ArgumentType>("lambert_w(%1%,IndexType)", "Result value overflow for 0 argument at -1 index.", pol);
246 }
247 else if( z > 0. )
248 {
249 w = boost::math::policies::raise_domain_error<ArgumentType>("lambert_w(%1%,IndexType)", "Argument value %1% out of range for real arguments.", z, pol);
250 }
251 else
252 {
253 w = lambw::_raw<ArgumentType,ArgumentType,IndexType>(z, boost::math::round(k,pol),pol);
254 }
255 }
256 else
257 {
258 w = lambw::_raw<ArgumentType,ArgumentType,IndexType>(z, boost::math::round(k,pol),pol);
259 }
260 }
261 else
262 {
263 w = boost::math::policies::raise_domain_error<ArgumentType>("lambert_w(%1%,IndexType)", "Invalid index value of %1% for real arguments. Valid values are 0 and -1.", k, pol);
264 }
265
266 if(boost::math::isnan(w))
267 {
268 return boost::math::policies::raise_evaluation_error<ArgumentType>("lambert_w(%1%,IndexType)", "Function return value %1% is Not-a-Number", w, pol);
269 }
270 else if( !(k == 0 && z == 0.) && w == 0 )
271 {
272 return boost::math::policies::raise_underflow_error<ArgumentType>("lambert_w(%1%,IndexType)", "Function return value has underflowed to zero.", pol);
273 }
274 else if( !boost::math::isnormal(w) )
275 {
276 return boost::math::policies::raise_denorm_error<ArgumentType>("lambert_w(%1%,IndexType)", "Function return value %1% is denormalised.", w, pol);
277 }
278 else if( boost::math::isinf(w) )
279 {
280 return boost::math::policies::raise_overflow_error<ArgumentType>("lambert_w(%1%,IndexType)", "Result value overflow.", pol);
281 }
282 else
283 {
284 return w;
285 }
286 }
287
288 //Checks for errors in input arguments and the return value using the policy pol for complex valued arguments.
289 template<class ArgumentType, class IndexType, class Policy>
290 inline std::complex<ArgumentType> _with_complex_range_checks(const std::complex<ArgumentType>& z, const IndexType& k, const Policy& pol)
291 {
292 std::complex<ArgumentType> w;
293
294 if(boost::math::isnan(_complex_real(z)) || boost::math::isnan(_complex_imag(z)))
295 {
296 w = std::complex<ArgumentType>(
297 boost::math::policies::raise_evaluation_error<ArgumentType>(
298 "lambert_w(%1%,IndexType)",
299 "Argument with real value %1% is Not-a-Number!",
300 _complex_real(z),pol),
301 std::numeric_limits<ArgumentType>::quiet_NaN());
302 }
303 else if(boost::math::isinf(_complex_real(z)) || boost::math::isinf(_complex_imag(z)))
304 {
305 boost::math::policies::raise_overflow_error<ArgumentType>(
306 "lambert_w(%1%,IndexType)",
307 "Argument value overflow.",pol);
308 return std::complex<ArgumentType>(std::numeric_limits<ArgumentType>::quiet_NaN(), std::numeric_limits<ArgumentType>::quiet_NaN());
309 }
310 else if(k != 0 && _complex_real(z) == 0. && _complex_imag(z) == 0.)
311 {
312 w = std::complex<ArgumentType>(
313 boost::math::policies::raise_pole_error<ArgumentType>(
314 "lambert_w(std::complex<%1%>,IndexType)",
315 "Function has a pole at %1% for indices other than 0.",
316 _complex_real(z),pol),
317 std::numeric_limits<ArgumentType>::quiet_NaN());
318 }
319 else
320 {
321 w = lambw::_raw<std::complex<ArgumentType>,ArgumentType,IndexType,Policy>(z,boost::math::round(k,pol),pol);
322 }
323
324 if(boost::math::isnan(_complex_real(w)) || boost::math::isnan(_complex_imag(w)))
325 {
326 boost::math::policies::raise_evaluation_error<ArgumentType>(
327 "lambert_w(%1%,IndexType)",
328 "Return value with real value %1% is Not-a-Number!",
329 _complex_real(w),pol);
330 return w;
331 }
332 else if(boost::math::isinf(_complex_real(w)) || boost::math::isinf(_complex_imag(w)))
333 {
334 boost::math::policies::raise_overflow_error<ArgumentType>(
335 "lambert_w(%1%,IndexType)",
336 "Return value overflow.",pol);
337 return w;
338 }
339 else if(!boost::math::isnormal(_complex_real(w)) || !boost::math::isnormal(_complex_imag(w)))
340 {
341 boost::math::policies::raise_denorm_error<ArgumentType>(
342 "lambert_w(%1%,IndexType)",
343 "Return value with real value %1% is denormalised.",_complex_real(w),pol);
344 return w;
345 }
346 else
347 {
348 return w;
349 }
350 }
351} // namespace lambw
352} // namespace math
353} // namespace boost
354
355#endif // BOOST_MATH_LAMBERT_W_RAW_HPP_INCLUDED
FTensor::Index< 'k', 3 > k
ArgumentType _raw(const ArgumentType &z, IndexType k, const Policy &pol)
ArgumentType _with_real_range_checks(const ArgumentType &z, const IndexType &k, const Policy &pol)
std::complex< ArgumentType > _with_complex_range_checks(const std::complex< ArgumentType > &z, const IndexType &k, const Policy &pol)
CoeffType _complex_imag(const CoeffType &z)
CoeffType _complex_real(const CoeffType &z)