mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-03 21:40:52 -05: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;
							 | 
						||
| 
								 | 
							
								}
							 |