• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright (c) 2014 Anton Bikineev
2 //  Use, modification and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //
6 //  Appends negative test cases to the *.ipp files.
7 //  Takes the next parameters:
8 //  -f <file> file where the negative values will be appended;
9 //  -x add minus to existing x values and append result;
10 //  -v, -xv like previous option.
11 //  Usage example:
12 //  ./bessel_derivative_append_negative -f "bessel_y_derivative_large_data.ipp" -x -v -xv
13 
14 #include <fstream>
15 #include <utility>
16 #include <functional>
17 #include <map>
18 #include <vector>
19 #include <iterator>
20 #include <algorithm>
21 
22 #include <boost/multiprecision/mpfr.hpp>
23 #include <boost/program_options.hpp>
24 #include <boost/lexical_cast.hpp>
25 
26 #include <boost/math/special_functions/bessel.hpp>
27 
28 template <class T>
bessel_j_derivative_bare(T v,T x)29 T bessel_j_derivative_bare(T v, T x)
30 {
31    return (v / x) * boost::math::cyl_bessel_j(v, x) - boost::math::cyl_bessel_j(v+1, x);
32 }
33 
34 template <class T>
bessel_y_derivative_bare(T v,T x)35 T bessel_y_derivative_bare(T v, T x)
36 {
37    return (v / x) * boost::math::cyl_neumann(v, x) - boost::math::cyl_neumann(v+1, x);
38 }
39 
40 template <class T>
bessel_i_derivative_bare(T v,T x)41 T bessel_i_derivative_bare(T v, T x)
42 {
43    return (v / x) * boost::math::cyl_bessel_i(v, x) + boost::math::cyl_bessel_i(v+1, x);
44 }
45 
46 template <class T>
bessel_k_derivative_bare(T v,T x)47 T bessel_k_derivative_bare(T v, T x)
48 {
49    return (v / x) * boost::math::cyl_bessel_k(v, x) - boost::math::cyl_bessel_k(v+1, x);
50 }
51 
52 template <class T>
sph_bessel_j_derivative_bare(T v,T x)53 T sph_bessel_j_derivative_bare(T v, T x)
54 {
55    if((v < 0) || (floor(v) != v))
56       throw std::domain_error("");
57    if(v == 0)
58       return -boost::math::sph_bessel(1, x);
59    return boost::math::sph_bessel(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_bessel(itrunc(v), x);
60 }
61 
62 template <class T>
sph_bessel_y_derivative_bare(T v,T x)63 T sph_bessel_y_derivative_bare(T v, T x)
64 {
65    if((v < 0) || (floor(v) != v))
66       throw std::domain_error("");
67    if(v == 0)
68       return -boost::math::sph_neumann(1, x);
69    return boost::math::sph_neumann(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_neumann(itrunc(v), x);
70 }
71 
72 namespace opt = boost::program_options;
73 using FloatType = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<200u> >;
74 using Function = FloatType(*)(FloatType, FloatType);
75 using Lines = std::vector<std::string>;
76 
77 enum class Negate: char
78 {
79    x,
80    v,
81    xv
82 };
83 
84 namespace
85 {
86 
87 const unsigned kSignificand = 50u;
88 
89 std::map<std::string, Function> kFileMapper = {
90    {"bessel_j_derivative_data.ipp", ::bessel_j_derivative_bare},
91    {"bessel_j_derivative_int_data.ipp", ::bessel_j_derivative_bare},
92    {"bessel_j_derivative_large_data.ipp", ::bessel_j_derivative_bare},
93    {"bessel_y01_derivative_data.ipp", ::bessel_y_derivative_bare},
94    {"bessel_yn_derivative_data.ipp", ::bessel_y_derivative_bare},
95    {"bessel_yv_derivative_data.ipp", ::bessel_y_derivative_bare},
96    {"bessel_i_derivative_data.ipp", ::bessel_i_derivative_bare},
97    {"bessel_i_derivative_int_data.ipp", ::bessel_i_derivative_bare},
98    {"bessel_k_derivative_data.ipp", ::bessel_k_derivative_bare},
99    {"bessel_k_derivative_int_data.ipp", ::bessel_k_derivative_bare},
100    {"sph_bessel_derivative_data.ipp", ::sph_bessel_j_derivative_bare},
101    {"sph_neumann_derivative_data.ipp", ::sph_bessel_y_derivative_bare}
102 };
103 
104 Function fp = ::bessel_j_derivative_bare;
105 
getSourcePartOfFile(std::fstream & file)106 Lines getSourcePartOfFile(std::fstream& file)
107 {
108    file.seekg(std::ios::beg);
109 
110    Lines lines;
111    while (true)
112    {
113       auto line = std::string{};
114       std::getline(file, line);
115       if (line.find("}};") != std::string::npos)
116          break;
117       lines.push_back(line);
118    }
119    file.seekg(std::ios::beg);
120    return lines;
121 }
122 
parseValue(std::string::iterator & iter)123 std::pair<std::string, std::string::iterator> parseValue(std::string::iterator& iter)
124 {
125    using std::isdigit;
126 
127    auto value = std::string{};
128    auto iterator = std::string::iterator{};
129 
130    while (!isdigit(*iter) && *iter != '-')
131       ++iter;
132    iterator = iter;
133    while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+')
134    {
135       value.push_back(*iter);
136       ++iter;
137    }
138    return {value, iterator};
139 }
140 
addMinusToValue(std::string & line,Negate which)141 void addMinusToValue(std::string& line, Negate which)
142 {
143    using std::isdigit;
144 
145    auto iter = line.begin();
146    switch (which)
147    {
148       case Negate::x:
149       {
150          ::parseValue(iter);
151          auto value_begin = ::parseValue(iter).second;
152          if (*value_begin != '-')
153             line.insert(value_begin, '-');
154          break;
155       }
156       case Negate::v:
157       {
158          auto value_begin = ::parseValue(iter).second;
159          if (*value_begin != '-')
160             line.insert(value_begin, '-');
161          break;
162       }
163       case Negate::xv:
164       {
165          auto v_value_begin = ::parseValue(iter).second;
166          if (*v_value_begin != '-')
167             line.insert(v_value_begin, '-');
168          // iterator could get invalid
169          iter = line.begin();
170          ::parseValue(iter);
171          auto x_value_begin = ::parseValue(iter).second;
172          if (*x_value_begin != '-')
173             line.insert(x_value_begin, '-');
174          break;
175       }
176    }
177 }
178 
replaceResultInLine(std::string & line)179 void replaceResultInLine(std::string& line)
180 {
181    using std::isdigit;
182 
183    auto iter = line.begin();
184 
185    // parse v and x values from line and convert them to FloatType
186    auto v = FloatType{::parseValue(iter).first};
187    auto x = FloatType{::parseValue(iter).first};
188    auto result = fp(v, x).str(kSignificand);
189 
190    while (!isdigit(*iter) && *iter != '-')
191       ++iter;
192    const auto where_to_write = iter;
193    while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+')
194       line.erase(iter);
195 
196    line.insert(where_to_write, result.begin(), result.end());
197 }
198 
processValues(const Lines & source_lines,Negate which)199 Lines processValues(const Lines& source_lines, Negate which)
200 {
201    using std::placeholders::_1;
202 
203    auto processed_lines = source_lines;
204    std::for_each(std::begin(processed_lines), std::end(processed_lines), std::bind(&addMinusToValue, _1, which));
205    std::for_each(std::begin(processed_lines), std::end(processed_lines), &replaceResultInLine);
206 
207    return processed_lines;
208 }
209 
updateTestCount(Lines & source_lines,std::size_t mult)210 void updateTestCount(Lines& source_lines, std::size_t mult)
211 {
212    using std::isdigit;
213 
214    const auto where = std::find_if(std::begin(source_lines), std::end(source_lines),
215       [](const std::string& str){ return str.find("boost::array") != std::string::npos; });
216    auto& str = *where;
217    const auto pos = str.find(">, ") + 3;
218    auto digits_length = 0;
219 
220    auto k = pos;
221    while (isdigit(str[k++]))
222       ++digits_length;
223 
224    const auto new_value = mult * boost::lexical_cast<std::size_t>(str.substr(pos, digits_length));
225    str.replace(pos, digits_length, boost::lexical_cast<std::string>(new_value));
226 }
227 
228 } // namespace
229 
main(int argc,char * argv[])230 int main(int argc, char*argv [])
231 {
232    auto desc = opt::options_description{"All options"};
233    desc.add_options()
234       ("help", "produce help message")
235       ("file", opt::value<std::string>()->default_value("bessel_j_derivative_data.ipp"))
236       ("x", "append negative x")
237       ("v", "append negative v")
238       ("xv", "append negative x and v");
239    opt::variables_map vm;
240    opt::store(opt::command_line_parser(argc, argv).options(desc)
241          .style(opt::command_line_style::default_style |
242          opt::command_line_style::allow_long_disguise)
243       .run(),vm);
244    opt::notify(vm);
245 
246    if (vm.count("help"))
247    {
248       std::cout << desc;
249       return 0;
250    }
251 
252    auto filename = vm["file"].as<std::string>();
253    fp = kFileMapper[filename];
254 
255    std::fstream file{filename.c_str()};
256    if (!file.is_open())
257       return -1;
258    auto source_part = ::getSourcePartOfFile(file);
259    source_part.back().push_back(',');
260 
261    auto cases_lines = Lines{};
262    for (const auto& str: source_part)
263    {
264       if (str.find("SC_") != std::string::npos)
265          cases_lines.push_back(str);
266    }
267 
268    auto new_lines = Lines{};
269    new_lines.reserve(cases_lines.size());
270 
271    std::size_t mult = 1;
272    if (vm.count("x"))
273    {
274       std::cout << "process x..." << std::endl;
275       const auto x_lines = ::processValues(cases_lines, Negate::x);
276       new_lines.insert(std::end(new_lines), std::begin(x_lines), std::end(x_lines));
277       ++mult;
278    }
279    if (vm.count("v"))
280    {
281       std::cout << "process v..." << std::endl;
282       const auto v_lines = ::processValues(cases_lines, Negate::v);
283       new_lines.insert(std::end(new_lines), std::begin(v_lines), std::end(v_lines));
284       ++mult;
285    }
286    if (vm.count("xv"))
287    {
288       std::cout << "process xv..." << std::endl;
289       const auto xv_lines = ::processValues(cases_lines, Negate::xv);
290       new_lines.insert(std::end(new_lines), std::begin(xv_lines), std::end(xv_lines));
291       ++mult;
292    }
293 
294    source_part.insert(std::end(source_part), std::begin(new_lines), std::end(new_lines));
295    ::updateTestCount(source_part, mult);
296 
297    file.close();
298    file.open(filename, std::ios::out | std::ios::trunc);
299    std::for_each(std::begin(source_part), std::end(source_part), [&file](const std::string& str)
300       { file << str << std::endl; });
301    file << "   }};";
302 
303    std::cout << "processed, ok\n";
304    return 0;
305 }
306