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;
|
|
}
|