// 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 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 #include #include #include #include #include #include #include #include #include #include template 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 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 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 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 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 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 >; using Function = FloatType(*)(FloatType, FloatType); using Lines = std::vector; enum class Negate: char { x, v, xv }; namespace { const unsigned kSignificand = 50u; std::map 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 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(str.substr(pos, digits_length)); str.replace(pos, digits_length, boost::lexical_cast(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()->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(); 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; }