mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-31 04:50:34 -04:00 
			
		
		
		
	
		
			
	
	
		
			306 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			306 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //  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; | ||
|  | } |