bessel_derivative_append_negative.cpp 8.8 KB

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