123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- // Copyright (c) 2014 Anton Bikineev
- // Use, modification and distribution are subject to the
- // Boost Software License, Version 1.0. (See accompanying file
- // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Appends negative test cases to the *.ipp files.
- // Takes the next parameters:
- // -f <file> file where the negative values will be appended;
- // -x add minus to existing x values and append result;
- // -v, -xv like previous option.
- // Usage example:
- // ./bessel_derivative_append_negative -f "bessel_y_derivative_large_data.ipp" -x -v -xv
- #include <fstream>
- #include <utility>
- #include <functional>
- #include <map>
- #include <vector>
- #include <iterator>
- #include <algorithm>
- #include <boost/multiprecision/mpfr.hpp>
- #include <boost/program_options.hpp>
- #include <boost/lexical_cast.hpp>
- #include <boost/math/special_functions/bessel.hpp>
- template <class T>
- T bessel_j_derivative_bare(T v, T x)
- {
- return (v / x) * boost::math::cyl_bessel_j(v, x) - boost::math::cyl_bessel_j(v+1, x);
- }
- template <class T>
- T bessel_y_derivative_bare(T v, T x)
- {
- return (v / x) * boost::math::cyl_neumann(v, x) - boost::math::cyl_neumann(v+1, x);
- }
- template <class T>
- T bessel_i_derivative_bare(T v, T x)
- {
- return (v / x) * boost::math::cyl_bessel_i(v, x) + boost::math::cyl_bessel_i(v+1, x);
- }
- template <class T>
- T bessel_k_derivative_bare(T v, T x)
- {
- return (v / x) * boost::math::cyl_bessel_k(v, x) - boost::math::cyl_bessel_k(v+1, x);
- }
- template <class T>
- T sph_bessel_j_derivative_bare(T v, T x)
- {
- if((v < 0) || (floor(v) != v))
- throw std::domain_error("");
- if(v == 0)
- return -boost::math::sph_bessel(1, x);
- return boost::math::sph_bessel(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_bessel(itrunc(v), x);
- }
- template <class T>
- T sph_bessel_y_derivative_bare(T v, T x)
- {
- if((v < 0) || (floor(v) != v))
- throw std::domain_error("");
- if(v == 0)
- return -boost::math::sph_neumann(1, x);
- return boost::math::sph_neumann(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_neumann(itrunc(v), x);
- }
- namespace opt = boost::program_options;
- using FloatType = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<200u> >;
- using Function = FloatType(*)(FloatType, FloatType);
- using Lines = std::vector<std::string>;
- enum class Negate: char
- {
- x,
- v,
- xv
- };
- namespace
- {
- const unsigned kSignificand = 50u;
- std::map<std::string, Function> kFileMapper = {
- {"bessel_j_derivative_data.ipp", ::bessel_j_derivative_bare},
- {"bessel_j_derivative_int_data.ipp", ::bessel_j_derivative_bare},
- {"bessel_j_derivative_large_data.ipp", ::bessel_j_derivative_bare},
- {"bessel_y01_derivative_data.ipp", ::bessel_y_derivative_bare},
- {"bessel_yn_derivative_data.ipp", ::bessel_y_derivative_bare},
- {"bessel_yv_derivative_data.ipp", ::bessel_y_derivative_bare},
- {"bessel_i_derivative_data.ipp", ::bessel_i_derivative_bare},
- {"bessel_i_derivative_int_data.ipp", ::bessel_i_derivative_bare},
- {"bessel_k_derivative_data.ipp", ::bessel_k_derivative_bare},
- {"bessel_k_derivative_int_data.ipp", ::bessel_k_derivative_bare},
- {"sph_bessel_derivative_data.ipp", ::sph_bessel_j_derivative_bare},
- {"sph_neumann_derivative_data.ipp", ::sph_bessel_y_derivative_bare}
- };
- Function fp = ::bessel_j_derivative_bare;
- Lines getSourcePartOfFile(std::fstream& file)
- {
- file.seekg(std::ios::beg);
- Lines lines;
- while (true)
- {
- auto line = std::string{};
- std::getline(file, line);
- if (line.find("}};") != std::string::npos)
- break;
- lines.push_back(line);
- }
- file.seekg(std::ios::beg);
- return lines;
- }
- std::pair<std::string, std::string::iterator> parseValue(std::string::iterator& iter)
- {
- using std::isdigit;
- auto value = std::string{};
- auto iterator = std::string::iterator{};
- while (!isdigit(*iter) && *iter != '-')
- ++iter;
- iterator = iter;
- while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+')
- {
- value.push_back(*iter);
- ++iter;
- }
- return {value, iterator};
- }
- void addMinusToValue(std::string& line, Negate which)
- {
- using std::isdigit;
- auto iter = line.begin();
- switch (which)
- {
- case Negate::x:
- {
- ::parseValue(iter);
- auto value_begin = ::parseValue(iter).second;
- if (*value_begin != '-')
- line.insert(value_begin, '-');
- break;
- }
- case Negate::v:
- {
- auto value_begin = ::parseValue(iter).second;
- if (*value_begin != '-')
- line.insert(value_begin, '-');
- break;
- }
- case Negate::xv:
- {
- auto v_value_begin = ::parseValue(iter).second;
- if (*v_value_begin != '-')
- line.insert(v_value_begin, '-');
- // iterator could get invalid
- iter = line.begin();
- ::parseValue(iter);
- auto x_value_begin = ::parseValue(iter).second;
- if (*x_value_begin != '-')
- line.insert(x_value_begin, '-');
- break;
- }
- }
- }
- void replaceResultInLine(std::string& line)
- {
- using std::isdigit;
- auto iter = line.begin();
- // parse v and x values from line and convert them to FloatType
- auto v = FloatType{::parseValue(iter).first};
- auto x = FloatType{::parseValue(iter).first};
- auto result = fp(v, x).str(kSignificand);
- while (!isdigit(*iter) && *iter != '-')
- ++iter;
- const auto where_to_write = iter;
- while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+')
- line.erase(iter);
- line.insert(where_to_write, result.begin(), result.end());
- }
- Lines processValues(const Lines& source_lines, Negate which)
- {
- using std::placeholders::_1;
- auto processed_lines = source_lines;
- std::for_each(std::begin(processed_lines), std::end(processed_lines), std::bind(&addMinusToValue, _1, which));
- std::for_each(std::begin(processed_lines), std::end(processed_lines), &replaceResultInLine);
- return processed_lines;
- }
- void updateTestCount(Lines& source_lines, std::size_t mult)
- {
- using std::isdigit;
- const auto where = std::find_if(std::begin(source_lines), std::end(source_lines),
- [](const std::string& str){ return str.find("boost::array") != std::string::npos; });
- auto& str = *where;
- const auto pos = str.find(">, ") + 3;
- auto digits_length = 0;
- auto k = pos;
- while (isdigit(str[k++]))
- ++digits_length;
- const auto new_value = mult * boost::lexical_cast<std::size_t>(str.substr(pos, digits_length));
- str.replace(pos, digits_length, boost::lexical_cast<std::string>(new_value));
- }
- } // namespace
- int main(int argc, char*argv [])
- {
- auto desc = opt::options_description{"All options"};
- desc.add_options()
- ("help", "produce help message")
- ("file", opt::value<std::string>()->default_value("bessel_j_derivative_data.ipp"))
- ("x", "append negative x")
- ("v", "append negative v")
- ("xv", "append negative x and v");
- opt::variables_map vm;
- opt::store(opt::command_line_parser(argc, argv).options(desc)
- .style(opt::command_line_style::default_style |
- opt::command_line_style::allow_long_disguise)
- .run(),vm);
- opt::notify(vm);
- if (vm.count("help"))
- {
- std::cout << desc;
- return 0;
- }
- auto filename = vm["file"].as<std::string>();
- fp = kFileMapper[filename];
- std::fstream file{filename.c_str()};
- if (!file.is_open())
- return -1;
- auto source_part = ::getSourcePartOfFile(file);
- source_part.back().push_back(',');
- auto cases_lines = Lines{};
- for (const auto& str: source_part)
- {
- if (str.find("SC_") != std::string::npos)
- cases_lines.push_back(str);
- }
- auto new_lines = Lines{};
- new_lines.reserve(cases_lines.size());
- std::size_t mult = 1;
- if (vm.count("x"))
- {
- std::cout << "process x..." << std::endl;
- const auto x_lines = ::processValues(cases_lines, Negate::x);
- new_lines.insert(std::end(new_lines), std::begin(x_lines), std::end(x_lines));
- ++mult;
- }
- if (vm.count("v"))
- {
- std::cout << "process v..." << std::endl;
- const auto v_lines = ::processValues(cases_lines, Negate::v);
- new_lines.insert(std::end(new_lines), std::begin(v_lines), std::end(v_lines));
- ++mult;
- }
- if (vm.count("xv"))
- {
- std::cout << "process xv..." << std::endl;
- const auto xv_lines = ::processValues(cases_lines, Negate::xv);
- new_lines.insert(std::end(new_lines), std::begin(xv_lines), std::end(xv_lines));
- ++mult;
- }
- source_part.insert(std::end(source_part), std::begin(new_lines), std::end(new_lines));
- ::updateTestCount(source_part, mult);
- file.close();
- file.open(filename, std::ios::out | std::ios::trunc);
- std::for_each(std::begin(source_part), std::end(source_part), [&file](const std::string& str)
- { file << str << std::endl; });
- file << " }};";
- std::cout << "processed, ok\n";
- return 0;
- }
|