| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <cmath> |
| |
|
| | #include <boost/numeric/ublas/lu.hpp> |
| | #include <boost/math/special_functions/ellint_2.hpp> |
| |
|
| | #include <muParser.h> |
| |
|
| | #include <QString> |
| | #include <QRegularExpressionMatch> |
| | #include <QDebug> |
| |
|
| | #include "rs.h" |
| | #include "rs_debug.h" |
| | #include "rs_math.h" |
| | #include "rs_vector.h" |
| |
|
| | #ifdef EMU_C99 |
| | #include "emu_c99.h" |
| | #endif |
| |
|
| |
|
| | namespace { |
| | constexpr double g_twoPi = M_PI*2; |
| | const QRegularExpression unitreg( |
| | R"((?P<sign>^-?))" |
| | R"((?:(?:(?:(?P<degrees>\d+\.?\d*)(?:degree[s]?|deg|[Dd]|°)))" |
| | R"((?:(?P<minutes>\d+\.?\d*)(?:minute[s]?|min|[Mm]|'))?)" |
| | R"((?:(?P<seconds>\d+\.?\d*)(?:second[s]?|sec|[Ss]|"))?$)|)" |
| | R"((?:(?:(?P<meters>\d+\.?\d*)(?:meter[s]?|m(?![m])))?)" |
| | R"((?:(?P<centis>\d+\.?\d*)(?:centimeter[s]?|centi|cm))?)" |
| | R"((?:(?P<millis>\d+\.?\d*)(?:millimeter[s]?|mm))?$)|)" |
| | R"((?:(?:(?P<yards>\d+\.?\d*)(?:yards|yard|yd))?)" |
| | R"((?:(?P<feet>\d+\.?\d*)(?:feet|foot|ft|'))?)" |
| | R"((?:(?P<inches>\d+\.?\d*)[-+]?)" |
| | R"((?:(?P<numer>\d+)\/(?P<denom>\d+))?)" |
| | R"((?:inches|inch|in|"))?$)))" |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | int RS_Math::round(double v) { |
| | return int(std::lrint(v)); |
| | } |
| |
|
| | double RS_Math::round(double v, double precision){ |
| | return std::abs(precision) > RS_TOLERANCE2 ? precision * std::llround(v / precision) : v; |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::pow(double x, double y) { |
| | errno = 0; |
| | double ret = std::pow(x, y); |
| | if (errno==EDOM) { |
| | RS_DEBUG->print(RS_Debug::D_ERROR, |
| | "RS_Math::pow: EDOM in pow"); |
| | ret = 0.0; |
| | } |
| | else if (errno==ERANGE) { |
| | RS_DEBUG->print(RS_Debug::D_WARNING, |
| | "RS_Math::pow: ERANGE in pow"); |
| | ret = 0.0; |
| | } |
| | return ret; |
| | } |
| |
|
| | |
| | RS_Vector RS_Math::pow(const RS_Vector& vp, int y) { |
| | return { RS_Math::pow(vp.x, y), RS_Math::pow(vp.y, y) }; |
| | } |
| |
|
| | |
| | |
| | |
| | bool RS_Math::equal(double d1, double d2, double tolerance){ |
| | return std::abs(d1 - d2) <= std::max({2. * ulp(d1), 2. * ulp(d2), tolerance}); |
| | } |
| |
|
| | bool RS_Math::notEqual(double d1, double d2, double tolerance){ |
| | return std::abs(d1 - d2) > std::max({2. * ulp(d1), 2. * ulp(d2), tolerance}); |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::rad2deg(double a) { |
| | return 180. / M_PI * a; |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::deg2rad(double a) { |
| | return M_PI / 180.0 * a; |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::rad2gra(double a) { |
| | return 200. / M_PI * a; |
| | } |
| |
|
| | double RS_Math::gra2rad(double a) { |
| | return M_PI / 200. * a; |
| | } |
| |
|
| | double RS_Math::gra2deg(double a){ |
| | double deg = 180 / 200. * a; |
| | return deg; |
| | } |
| |
|
| | |
| | |
| | |
| | unsigned RS_Math::findGCD(unsigned a, unsigned b) { |
| | return std::gcd(a, b); |
| | } |
| |
|
| | bool RS_Math::isAngleBetween(double a, |
| | double a1, double a2, |
| | bool reversed) { |
| |
|
| | if (reversed) { |
| | std::swap(a1,a2); |
| | } |
| |
|
| | if(getAngleDifferenceU(a2, a1 ) < RS_TOLERANCE_ANGLE) { |
| | return true; |
| | } |
| | const double tol=0.5*RS_TOLERANCE_ANGLE; |
| | const double diff0=correctAngle(a2 -a1) + tol; |
| |
|
| | return diff0 >= correctAngle(a - a1) || diff0 >= correctAngle(a2 - a); |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::correctAngle(double a) { |
| | return std::fmod(M_PI + std::remainder(a - M_PI, g_twoPi), g_twoPi); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | int RS_Math::getPeriodsCount(double a1, double a2, bool reversed){ |
| | if (reversed) { |
| | std::swap(a1,a2); |
| | } |
| | double dif = std::abs(a2-a1) + g_twoPi; |
| | double remainder = std::remainder(dif, g_twoPi); |
| | int result = 0; |
| | if (remainder < RS_TOLERANCE_ANGLE){ |
| | result = dif / g_twoPi - 1; |
| | } |
| | return result; |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::correctAnglePlusMinusPi(double a) { |
| | return std::remainder(a, g_twoPi); |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Math::correctAngle0ToPi(double a) { |
| | return std::abs(std::remainder(a, g_twoPi)); |
| | } |
| |
|
| | void RS_Math::calculateAngles(double &angle, double& complementary, double& supplementary, double& alt) { |
| | angle = correctAngle0ToPi(angle); |
| | complementary = M_PI_2 - angle; |
| | supplementary = M_PI - angle; |
| | alt = M_PI + supplementary; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | double RS_Math::getAngleDifference(double a1, double a2, bool reversed) { |
| | if (reversed) { |
| | std::swap(a1,a2); |
| | } |
| | return correctAngle(a2 - a1); |
| | } |
| |
|
| | double RS_Math::getAngleDifferenceU(double a1, double a2){ |
| | return correctAngle0ToPi(a1 - a2); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | double RS_Math::makeAngleReadable(double angle, bool readable, |
| | bool* corrected) { |
| |
|
| | double ret=correctAngle(angle); |
| |
|
| | bool cor = isAngleReadable(ret) ^ readable; |
| |
|
| | |
| | if (cor) { |
| | |
| | |
| | |
| | |
| | ret = correctAngle(angle+M_PI); |
| | } |
| |
|
| | if (corrected) { |
| | *corrected = cor; |
| | } |
| |
|
| | return ret; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | bool RS_Math::isAngleReadable(double angle) { |
| | const double tolerance=0.001; |
| | if (angle>M_PI_2) { |
| | return std::abs(std::remainder(angle, g_twoPi)) < (M_PI_2 - tolerance); |
| | } |
| | else { |
| | return std::abs(std::remainder(angle, g_twoPi)) < (M_PI_2 + tolerance); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | bool RS_Math::isSameDirection(double dir1, double dir2, double tol) { |
| | return getAngleDifferenceU(dir1, dir2) < tol; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | double RS_Math::eval(const QString& expr, double def) { |
| |
|
| | bool ok = false; |
| | double res = RS_Math::eval(expr, &ok); |
| |
|
| | if (!ok) { |
| | LC_ERR << "RS_Math::"<<__func__<<'('<<expr<<"): parser error"; |
| | return def; |
| | } |
| |
|
| | return res; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | double RS_Math::convert_unit(const QRegularExpressionMatch& match, const QString& name, double factor, double defval) { |
| | if (!match.captured(name).isNull()) { |
| | LC_ERR <<"name="<<name<<": "<< match.captured(name); |
| | } |
| | QString input = (!match.captured(name).isNull()) ? match.captured(name) : QString::number(defval, 'g', 16); |
| | return input.toDouble() * factor; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | QString RS_Math::derationalize(const QString& expr) { |
| | |
| |
|
| | QRegularExpressionMatch match = unitreg.match(expr); |
| | if (match.hasMatch()){ |
| | RS_DEBUG->print(RS_Debug::D_DEBUGGING, |
| | "RS_Math::derationalize: matches = '%s'", match.capturedTexts().join(", ").toLatin1().data()); |
| | double total = 0.0; |
| | int sign = (match.captured("sign").isNull() || match.captured("sign") == "") ? 1 : -1; |
| |
|
| | |
| | total += convert_unit(match, "degrees", 1.0, 0.0); |
| | total += convert_unit(match, "minutes", 1/60.0, 0.0); |
| | total += convert_unit(match, "seconds", 1/3600.0, 0.0); |
| | total += convert_unit(match, "meters", 100.0, 0.0); |
| | total += convert_unit(match, "centis", 1.0, 0.0); |
| | total += convert_unit(match, "millis", 0.1, 0.0); |
| | total += convert_unit(match, "yards", 36.0, 0.0); |
| | total += convert_unit(match, "feet", 12.0, 0.0); |
| | total += convert_unit(match, "inches", 1.0, 0.0); |
| | total += convert_unit(match, "numer", 1.0, 0.0) / convert_unit(match, "denom", 1.0, 1.0); |
| | total *= sign; |
| |
|
| | RS_DEBUG->print("RS_Math::derationalize: total = '%f'", total); |
| | return QString::number(total, 'g', 16); |
| | } |
| | else { |
| | return expr; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | double RS_Math::eval(const QString& expr, bool* ok) { |
| | bool okTmp = false; |
| | if(ok == nullptr) { |
| | ok=&okTmp; |
| | } |
| | double ret = 0.; |
| | if (expr.isEmpty()) { |
| | *ok = false; |
| | return ret; |
| | } |
| |
|
| | QString derationalized = derationalize(expr); |
| | |
| |
|
| | try{ |
| | mu::Parser p; |
| | #ifdef _UNICODE |
| | p.DefineConst(L"pi",M_PI); |
| | p.SetExpr(derationalized.toStdWString()); |
| | #else |
| | p.DefineConst("pi",M_PI); |
| | p.SetExpr(derationalized.toStdString()); |
| | #endif |
| | ret=p.Eval(); |
| | *ok=true; |
| | } |
| | catch (mu::Parser::exception_type &e) |
| | { |
| | mu::console() << e.GetMsg() << std::endl; |
| | *ok=false; |
| | } |
| | catch (...) |
| | { |
| | LC_ERR<<"MuParser error"; |
| | } |
| |
|
| | return ret; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | QString RS_Math::doubleToString(double value, double prec) { |
| | if (prec< RS_TOLERANCE ) { |
| | RS_DEBUG->print(RS_Debug::D_ERROR, |
| | "RS_Math::doubleToString: invalid precision"); |
| | return QString().setNum(value, prec); |
| | } |
| |
|
| | double const num = RS_Math::round(value / prec)*prec; |
| |
|
| | QString exaStr = RS_Math::doubleToString(1./prec, 10); |
| | int const dotPos = exaStr.indexOf('.'); |
| |
|
| | if (dotPos==-1) { |
| | |
| | return QString().setNum(RS_Math::round(num)); |
| | } else { |
| | |
| | int digits = dotPos - 1; |
| | return RS_Math::doubleToString(num, digits); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | QString RS_Math::doubleToString(double value, int prec) { |
| | QString valStr; |
| |
|
| | valStr.setNum(value, 'f', prec); |
| |
|
| | if(valStr.contains('.')) { |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if(valStr.at(valStr.length()-1)=='.') { |
| | valStr.truncate(valStr.length()-1); |
| | } |
| |
|
| | } |
| |
|
| | return valStr; |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_Math::test() { |
| | { |
| | std::cout<<"testing quadratic solver"<<std::endl; |
| | |
| | std::vector<std::vector<double>> const eqns{ |
| | {-1., -1.}, |
| | {-101., -1.}, |
| | {-1., -100.}, |
| | {2., 1.}, |
| | {-2., 1.} |
| | }; |
| | |
| | std::vector<std::vector<double>> roots{ |
| | {-0.6180339887498948, 1.6180339887498948}, |
| | {-0.0099000196991084878, 101.009900019699108}, |
| | {-9.5124921972503929, 10.5124921972503929}, |
| | {-1.}, |
| | {1.} |
| | }; |
| |
|
| | for(size_t i=0; i < eqns.size(); i++) { |
| | std::cout<<"Test quadratic solver, test case: x^2 + (" |
| | <<eqns[i].front()<<") x + (" |
| | <<eqns[i].back()<<") = 0"<<std::endl; |
| | auto sol = quadraticSolver(eqns[i]); |
| | assert(sol.size()==roots[i].size()); |
| | if (sol.front() > sol.back()) { |
| | std::swap(sol[0], sol[1]); |
| | } |
| | auto expected=roots[i]; |
| | if (expected.front() > expected.back()) { |
| | std::swap(expected[0], expected[1]); |
| | } |
| | for (size_t j=0; j < sol.size(); j++) { |
| | double x0 = sol[j]; |
| | double x1 = expected[j]; |
| | double const prec = (x0 - x1)/(std::abs(x0 + x1) + RS_TOLERANCE2); |
| | std::cout<<"root "<<j<<" : precision level = "<<prec<<std::endl; |
| | std::cout<<std::setprecision(17)<<"found: "<<x0<<"\texpected: "<<x1<<std::endl; |
| | assert(prec < RS_TOLERANCE); |
| | } |
| | std::cout<<std::endl; |
| | } |
| | return; |
| | } |
| | QString s; |
| | double v; |
| |
|
| | std::cout << "RS_Math::test: doubleToString:\n"; |
| |
|
| | v = 0.1; |
| | s = RS_Math::doubleToString(v, 0.1); |
| | assert(s=="0.1"); |
| | s = RS_Math::doubleToString(v, 0.01); |
| | assert(s=="0.10"); |
| |
|
| | v = 0.01; |
| | s = RS_Math::doubleToString(v, 0.1); |
| | assert(s=="0.0"); |
| | s = RS_Math::doubleToString(v, 0.01); |
| | assert(s=="0.01"); |
| | s = RS_Math::doubleToString(v, 0.001); |
| | assert(s=="0.010"); |
| |
|
| | v = 0.001; |
| | s = RS_Math::doubleToString(v, 0.1); |
| | assert(s=="0.0"); |
| | s = RS_Math::doubleToString(v, 0.01); |
| | assert(s=="0.00"); |
| | s = RS_Math::doubleToString(v, 0.001); |
| | assert(s=="0.001"); |
| |
|
| | std::cout << "RS_Math::test: complete"<<std::endl; |
| | } |
| |
|
| |
|
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | std::vector<double> RS_Math::quadraticSolver(const std::vector<double>& ce) |
| | |
| | |
| | { |
| | std::vector<double> ans(0,0.); |
| | if (ce.size() != 2) return ans; |
| | using LDouble = long double; |
| | LDouble const b = -0.5L * ce[0]; |
| | LDouble const c = ce[1]; |
| | |
| | |
| | |
| | |
| | LDouble const b2= b * b; |
| | LDouble const discriminant= b2 - c; |
| | LDouble const fc = std::abs(c); |
| |
|
| | |
| | LDouble const TOL = 1e-24L; |
| |
|
| | if (discriminant < 0.L) |
| | |
| | return ans; |
| |
|
| | |
| | LDouble r; |
| |
|
| | |
| | |
| | if (b2 >= fc) |
| | r = std::abs(b) * std::sqrt(1.L - c/b2); |
| | else |
| | |
| | r = std::sqrt(fc) * std::sqrt(1.L + b2/fc); |
| |
|
| | if (r >= TOL*std::abs(b)) { |
| | |
| | if (b >= 0.L) |
| | |
| | ans.push_back(b + r); |
| | else |
| | |
| | ans.push_back(b - r); |
| |
|
| | |
| | ans.push_back(c/ans.front()); |
| | } else |
| | |
| | ans.push_back(b); |
| | return ans; |
| | } |
| |
|
| |
|
| | std::vector<double> RS_Math::cubicSolver(const std::vector<double>& ce) |
| | |
| | |
| | { |
| | |
| | std::vector<double> ans; |
| | if (ce.size() != 3) |
| | return {}; |
| |
|
| | |
| | |
| | double shift=(1./3)*ce[0]; |
| | double p=ce[1] -shift*ce[0]; |
| | double q=ce[0]*( (2./27)*ce[0]*ce[0]-(1./3)*ce[1])+ce[2]; |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const double discriminant= (1./27)*p*p*p+(1./4)*q*q; |
| | if ( std::abs(p)< 1.0e-75) { |
| | ans.push_back(std::cbrt(q)); |
| | ans[0] -= shift; |
| | |
| | |
| | return ans; |
| | } |
| | |
| | if(!std::signbit(discriminant)) { |
| | std::vector<double> ce2 = { { q, -1./27*p*p*p } }; |
| | auto r=quadraticSolver(ce2); |
| | if ( r.empty() ) { |
| | LC_ERR<<__FILE__<<" : "<<__func__<<" : line"<<__LINE__<<" :cubicSolver()::Error cubicSolver("<<ce[0]<<' '<<ce[1]<<' '<<ce[2]<<")\n"; |
| | return {}; |
| | } |
| |
|
| | double u; |
| | if (r.size() < 2) { |
| | u = std::cbrt(r[0]); |
| | } |
| | else { |
| | u = std::signbit(q) ? std::cbrt(r[0]) : std::cbrt(r[1]); |
| | } |
| |
|
| | |
| | double v=(-1./3)*p/u; |
| | |
| | |
| | ans.push_back(u+v - shift); |
| |
|
| | |
| | |
| | }else{ |
| | std::complex<double> u(q,0),rt[3]; |
| | u=std::pow(-0.5*u - std::sqrt(0.25*u*u+p*p*p/27), 1./3); |
| | rt[0]=u-p/(3.*u)-shift; |
| | std::complex<double> w(-0.5, std::sqrt(3.)/2); |
| | rt[1]=u*w-p/(3.*u*w)-shift; |
| | rt[2]=u/w-p*w/(3.*u)-shift; |
| | |
| | |
| | |
| | |
| | |
| | ans.push_back(rt[0].real()); |
| | ans.push_back(rt[1].real()); |
| | ans.push_back(rt[2].real()); |
| | } |
| | |
| | for(double& x0: ans){ |
| | double dx=0.; |
| | for(size_t i=0; i<20; ++i){ |
| | double f=( (x0 + ce[0])*x0 + ce[1])*x0 +ce[2]; |
| | double df=(3.*x0+2.*ce[0])*x0 +ce[1]; |
| | if(std::abs(df)>std::abs(f)+RS_TOLERANCE){ |
| | dx=f/df; |
| | x0 -= dx; |
| | }else |
| | break; |
| | } |
| | } |
| |
|
| | return ans; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | std::vector<double> RS_Math::quarticSolver(const std::vector<double>& ce) |
| | { |
| |
|
| | std::vector<double> ans(0,0.); |
| | if(ce.size() != 4) { |
| | LC_ERR<<"expected array size=4, got "<<ce.size(); |
| | return ans; |
| | } |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | double shift=0.25*ce[0]; |
| | double shift2=shift*shift; |
| | double a2=ce[0]*ce[0]; |
| | double p= ce[1] - (3./8)*a2; |
| | double q= ce[2] + ce[0]*((1./8)*a2 - 0.5*ce[1]); |
| | double r= ce[3] - shift*ce[2] + (ce[1] - 3.*shift2)*shift2; |
| | |
| |
|
| | if (q*q <= 1.e-4*RS_TOLERANCE*std::abs(p*r)) { |
| | double discriminant= 0.25*p*p -r; |
| | if (discriminant < -1.e3*RS_TOLERANCE) { |
| |
|
| | |
| | |
| | return ans; |
| | } |
| | double t2[2]; |
| | t2[0]=-0.5*p-sqrt(std::abs(discriminant)); |
| | t2[1]= -p - t2[0]; |
| | |
| | |
| | if ( t2[1] >= 0.) { |
| | ans.push_back(sqrt(t2[1])-shift); |
| | ans.push_back(-sqrt(t2[1])-shift); |
| | } |
| | if ( t2[0] >= 0. ) { |
| | ans.push_back(sqrt(t2[0])-shift); |
| | ans.push_back(-sqrt(t2[0])-shift); |
| | } |
| | |
| | |
| | |
| | |
| | return ans; |
| | } |
| | if ( std::abs(r)< 1.0e-75 ) { |
| | std::vector<double> cubic(3,0.); |
| | cubic[1]=p; |
| | cubic[2]=q; |
| | ans.push_back(0.); |
| | auto r=cubicSolver(cubic); |
| | std::copy(r.begin(),r.end(), std::back_inserter(ans)); |
| | for(size_t i=0; i<ans.size(); i++) ans[i] -= shift; |
| | return ans; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | std::vector<double> cubic(3,0.); |
| | cubic[0]=2.*p; |
| | cubic[1]=p*p-4.*r; |
| | cubic[2]=-q*q; |
| | auto r3= cubicSolver(cubic); |
| | if (r3.empty()) |
| | return {}; |
| | |
| | |
| | |
| | |
| | if (r3.size()==1) { |
| | if (r3[0]< 0.) { |
| | DEBUG_HEADER |
| | qDebug()<<"Quartic Error:: Found one real root for cubic, but negative\n"; |
| | return ans; |
| | } |
| | double sqrtz0=sqrt(r3[0]); |
| | std::vector<double> ce2(2,0.); |
| | ce2[0]= -sqrtz0; |
| | ce2[1]=0.5*(p+r3[0])+0.5*q/sqrtz0; |
| | auto r1=quadraticSolver(ce2); |
| | if (r1.size()==0 ) { |
| | ce2[0]= sqrtz0; |
| | ce2[1]=0.5*(p+r3[0])-0.5*q/sqrtz0; |
| | r1=quadraticSolver(ce2); |
| | } |
| | for(auto& x: r1){ |
| | x -= shift; |
| | } |
| | return r1; |
| | } |
| | if ( r3[0]> 0. && r3[1] > 0. ) { |
| | double sqrtz0=sqrt(r3[0]); |
| | std::vector<double> ce2(2,0.); |
| | ce2[0]= -sqrtz0; |
| | ce2[1]=0.5*(p+r3[0])+0.5*q/sqrtz0; |
| | ans=quadraticSolver(ce2); |
| | ce2[0]= sqrtz0; |
| | ce2[1]=0.5*(p+r3[0])-0.5*q/sqrtz0; |
| | auto r1=quadraticSolver(ce2); |
| | std::copy(r1.begin(),r1.end(),std::back_inserter(ans)); |
| | for(auto& x: ans){ |
| | x -= shift; |
| | } |
| | } |
| | |
| | for(double& x0: ans){ |
| | double dx=0.; |
| | for(size_t i=0; i<20; ++i){ |
| | double f=(( (x0 + ce[0])*x0 + ce[1])*x0 +ce[2])*x0 + ce[3] ; |
| | double df=((4.*x0+3.*ce[0])*x0 +2.*ce[1])*x0+ce[2]; |
| | |
| | |
| | if(std::abs(df)>RS_TOLERANCE2){ |
| | dx=f/df; |
| | x0 -= dx; |
| | }else |
| | break; |
| | } |
| | } |
| |
|
| | return ans; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | std::vector<double> RS_Math::quarticSolverFull(const std::vector<double>& ce) |
| | { |
| | if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ |
| | LC_LOG<<ce[4]<<"*y^4+("<<ce[3]<<")*y^3+("<<ce[2]<<"*y^2+("<<ce[1]<<")*y+("<<ce[0]<<")==0"; |
| | } |
| |
|
| | std::vector<double> roots(0,0.); |
| | if(ce.size()!=5) return roots; |
| | std::vector<double> ce2(4,0.); |
| |
|
| | if ( std::abs(ce[4]) < 1.0e-14) { |
| | if ( std::abs(ce[3]) < 1.0e-14) { |
| | if ( std::abs(ce[2]) < 1.0e-14) { |
| | if( std::abs(ce[1]) > 1.0e-14) { |
| | roots.push_back(-ce[0]/ce[1]); |
| | } else { |
| | return roots; |
| | } |
| | } else { |
| | ce2.resize(2); |
| | ce2[0]=ce[1]/ce[2]; |
| | ce2[1]=ce[0]/ce[2]; |
| | |
| | roots=RS_Math::quadraticSolver(ce2); |
| | } |
| | } else { |
| | ce2.resize(3); |
| | ce2[0]=ce[2]/ce[3]; |
| | ce2[1]=ce[1]/ce[3]; |
| | ce2[2]=ce[0]/ce[3]; |
| | |
| | roots=RS_Math::cubicSolver(ce2); |
| | } |
| | } else { |
| | ce2[0]=ce[3]/ce[4]; |
| | ce2[1]=ce[2]/ce[4]; |
| | ce2[2]=ce[1]/ce[4]; |
| | ce2[3]=ce[0]/ce[4]; |
| | if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ |
| | LC_LOG<< "ce2[4]={ "<<ce2[0]<<' '<<ce2[1]<<' '<<ce2[2]<<' '<<ce2[3]<<" }"; |
| | } |
| | if(std::abs(ce2[3])<= RS_TOLERANCE15) { |
| | |
| | ce2.resize(3); |
| | roots=RS_Math::cubicSolver(ce2); |
| | roots.push_back(0.); |
| | }else |
| | roots=RS_Math::quarticSolver(ce2); |
| | } |
| | return roots; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | bool RS_Math::linearSolver(const std::vector<std::vector<double> >& mt, std::vector<double>& sn){ |
| | |
| | size_t mSize(mt.size()); |
| | size_t aSize(mSize+1); |
| | if(std::any_of(mt.begin(), mt.end(), [&aSize](const std::vector<double>& v)->bool{ |
| | return v.size() != aSize; |
| | })) |
| | return false; |
| | sn.resize(mSize); |
| | #if false |
| | boost::numeric::ublas::matrix<double> bm (mSize, mSize); |
| | boost::numeric::ublas::vector<double> bs(mSize); |
| |
|
| | for(int i=0;i<mSize;i++) { |
| | for(int j=0;j<mSize;j++) { |
| | bm(i,j)=mt[i][j]; |
| | } |
| | bs(i)=mt[i][mSize]; |
| | } |
| | |
| |
|
| | if ( boost::numeric::ublas::lu_factorize<boost::numeric::ublas::matrix<double> >(bm) ) { |
| | std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl; |
| | std::cout<<" linear solver failed"<<std::endl; |
| | |
| | return false; |
| | } |
| |
|
| | boost::numeric::ublas:: triangular_matrix<double, boost::numeric::ublas::unit_lower> |
| | lm = boost::numeric::ublas::triangular_adaptor< boost::numeric::ublas::matrix<double>, boost::numeric::ublas::unit_lower>(bm); |
| | boost::numeric::ublas:: triangular_matrix<double, boost::numeric::ublas::upper> |
| | um = boost::numeric::ublas::triangular_adaptor< boost::numeric::ublas::matrix<double>, boost::numeric::ublas::upper>(bm); |
| | ; |
| | boost::numeric::ublas::inplace_solve(lm,bs, boost::numeric::ublas::lower_tag()); |
| | boost::numeric::ublas::inplace_solve(um,bs, boost::numeric::ublas::upper_tag()); |
| | for(int i=0;i<mSize;i++){ |
| | sn[i]=bs(i); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #else |
| | |
| | std::vector<std::vector<double> > mt0(mt); |
| | for(size_t i=0;i<mSize;++i){ |
| | size_t imax(i); |
| | double cmax(std::abs(mt0[i][i])); |
| | for(size_t j=i+1;j<mSize;++j) { |
| | if(std::abs(mt0[j][i]) > cmax ) { |
| | imax=j; |
| | cmax=std::abs(mt0[j][i]); |
| | } |
| | } |
| |
|
| | |
| | |
| | if(cmax<RS_TOLERANCE) return false; |
| | if(imax != i) { |
| | std::swap(mt0[i],mt0[imax]); |
| | } |
| | for(size_t k=i+1;k<=mSize;++k) { |
| | mt0[i][k] /= mt0[i][i]; |
| | } |
| | mt0[i][i]=1.; |
| | for(size_t j=0;j<mSize;++j) { |
| | if(j != i ) { |
| | double& a = mt0[j][i]; |
| | for(size_t k=i+1;k<=mSize;++k) { |
| | mt0[j][k] -= mt0[i][k]*a; |
| | } |
| | a=0.; |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | } |
| | for(size_t i=0;i<mSize;++i) { |
| | sn[i]=mt0[i][mSize]; |
| | } |
| | #endif |
| |
|
| | return true; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | double RS_Math::ellipticIntegral_2(const double& k, const double& phi) |
| | { |
| | double a= std::remainder(phi-M_PI_2,M_PI); |
| | if(a>0.) { |
| | return boost::math::ellint_2<double,double>(k,a); |
| | } else { |
| | return - boost::math::ellint_2<double,double>(k,std::abs(a)); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | RS_VectorSolutions RS_Math::simultaneousQuadraticSolver(const std::vector<double>& m) |
| | { |
| | RS_VectorSolutions ret(0); |
| | if(m.size() != 8 ) return ret; |
| | std::vector< double> c1(0,0.); |
| | std::vector< std::vector<double> > m1(0,c1); |
| | c1.resize(6); |
| | c1[0]=m[0]; |
| | c1[1]=0.; |
| | c1[2]=m[1]; |
| | c1[3]=0.; |
| | c1[4]=0.; |
| | c1[5]=-1.; |
| | m1.push_back(c1); |
| | c1[0]=m[2]; |
| | c1[1]=2.*m[3]; |
| | c1[2]=m[4]; |
| | c1[3]=m[5]; |
| | c1[4]=m[6]; |
| | c1[5]=m[7]; |
| | m1.push_back(c1); |
| |
|
| | return simultaneousQuadraticSolverFull(m1); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | RS_VectorSolutions RS_Math::simultaneousQuadraticSolverFull(const std::vector<std::vector<double> >& m) |
| | { |
| | RS_VectorSolutions ret; |
| | if(m.size()!=2) return ret; |
| | if( m[0].size() ==3 || m[1].size()==3 ){ |
| | return simultaneousQuadraticSolverMixed(m); |
| | } |
| | if(m[0].size()!=6 || m[1].size()!=6) return ret; |
| | |
| | auto& a=m[0][0]; |
| | auto& b=m[0][1]; |
| | auto& c=m[0][2]; |
| | auto& d=m[0][3]; |
| | auto& e=m[0][4]; |
| | auto& f=m[0][5]; |
| |
|
| | auto& g=m[1][0]; |
| | auto& h=m[1][1]; |
| | auto& i=m[1][2]; |
| | auto& j=m[1][3]; |
| | auto& k=m[1][4]; |
| | auto& l=m[1][5]; |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | double a2=a*a; |
| | double b2=b*b; |
| | double c2=c*c; |
| | double d2=d*d; |
| | double e2=e*e; |
| | double f2=f*f; |
| |
|
| | double g2=g*g; |
| | double h2=h*h; |
| | double i2=i*i; |
| | double j2=j*j; |
| | double k2=k*k; |
| | double l2=l*l; |
| | std::vector<double> qy(5,0.); |
| | |
| | qy[4]=-c2*g2 + b*c*g*h - a*c*h2 - b2*g*i + 2.*a*c*g*i + a*b*h*i - a2*i2; |
| | |
| | qy[3]=-2.*c*e*g2 + c*d*g*h + b*e*g*h - a*e*h2 - 2.*b*d*g*i + 2.*a*e*g*i + a*d*h*i + |
| | b*c*g*j - 2.*a*c*h*j + a*b*i*j - b2*g*k + 2.*a*c*g*k + a*b*h*k - 2.*a2*i*k; |
| | |
| | qy[2]=(-e2*g2 + d*e*g*h - d2*g*i + c*d*g*j + b*e*g*j - 2.*a*e*h*j + a*d*i*j - a*c*j2 - |
| | 2.*b*d*g*k + 2.*a*e*g*k + a*d*h*k + a*b*j*k - a2*k2 - b2*g*l + 2.*a*c*g*l + a*b*h*l - 2.*a2*i*l) |
| | - (2.*c*f*g2 - b*f*g*h + a*f*h2 - 2.*a*f*g*i); |
| | |
| | qy[1]=(d*e*g*j - a*e*j2 - d2*g*k + a*d*j*k - 2.*b*d*g*l + 2.*a*e*g*l + a*d*h*l + a*b*j*l - 2.*a2*k*l) |
| | -(2.*e*f*g2 - d*f*g*h - b*f*g*j + 2.*a*f*h*j - 2.*a*f*g*k); |
| | |
| | qy[0]=-d2*g*l + a*d*j*l - a2*l2 |
| | - ( f2*g2 - d*f*g*j + a*f*j2 - 2.*a*f*g*l); |
| | if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ |
| | DEBUG_HEADER |
| | std::cout<<qy[4]<<"*y^4 +("<<qy[3]<<")*y^3+("<<qy[2]<<")*y^2+("<<qy[1]<<")*y+("<<qy[0]<<")==0"<<std::endl; |
| | } |
| | |
| | auto roots=quarticSolverFull(qy); |
| | if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ |
| | std::cout<<"roots.size()= "<<roots.size()<<std::endl; |
| | } |
| |
|
| | if (roots.size()==0 ) { |
| | return ret; |
| | } |
| | std::vector<double> ce(0,0.); |
| |
|
| | for(size_t i0=0;i0<roots.size();i0++){ |
| | if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ |
| | DEBUG_HEADER |
| | std::cout<<"y="<<roots[i0]<<std::endl; |
| | } |
| | |
| | |
| | |
| | ce.resize(3); |
| | ce[0]=a; |
| | ce[1]=b*roots[i0]+d; |
| | ce[2]=c*roots[i0]*roots[i0]+e*roots[i0]+f; |
| | |
| | |
| | if(std::abs(ce[0])<1e-75 && std::abs(ce[1])<1e-75) { |
| | ce[0]=g; |
| | ce[1]=h*roots[i0]+j; |
| | ce[2]=i*roots[i0]*roots[i0]+k*roots[i0]+f; |
| | |
| | |
| |
|
| | } |
| | if(std::abs(ce[0])<1e-75 && std::abs(ce[1])<1e-75) continue; |
| |
|
| | if(std::abs(a)>1e-75){ |
| | std::vector<double> ce2(2,0.); |
| | ce2[0]=ce[1]/ce[0]; |
| | ce2[1]=ce[2]/ce[0]; |
| | |
| | |
| | auto xRoots=quadraticSolver(ce2); |
| | for(size_t j0=0;j0<xRoots.size();j0++){ |
| | |
| | |
| | RS_Vector vp(xRoots[j0],roots[i0]); |
| | if(simultaneousQuadraticVerify(m,vp)) ret.push_back(vp); |
| | } |
| | continue; |
| | } |
| | RS_Vector vp(-ce[2]/ce[1],roots[i0]); |
| | if(simultaneousQuadraticVerify(m,vp)) ret.push_back(vp); |
| | } |
| | if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ |
| | DEBUG_HEADER |
| | std::cout<<"ret="<<ret<<std::endl; |
| | } |
| | return ret; |
| | } |
| |
|
| | RS_VectorSolutions RS_Math::simultaneousQuadraticSolverMixed(const std::vector<std::vector<double> >& m) |
| | { |
| | RS_VectorSolutions ret; |
| | auto p0=& (m[0]); |
| | auto p1=& (m[1]); |
| | if(p1->size()==3){ |
| | std::swap(p0,p1); |
| | } |
| | if(p1->size()==3) { |
| | |
| | std::vector<double> sn(2,0.); |
| | std::vector<std::vector<double> > ce; |
| | ce.push_back(m[0]); |
| | ce.push_back(m[1]); |
| | ce[0][2]=-ce[0][2]; |
| | ce[1][2]=-ce[1][2]; |
| | if( RS_Math::linearSolver(ce,sn)) ret.push_back(RS_Vector(sn[0],sn[1])); |
| | return ret; |
| | } |
| | |
| | |
| | |
| | |
| | const double& a=p0->at(0); |
| | const double& b=p0->at(1); |
| | const double& c=p0->at(2); |
| | const double& d=p1->at(0); |
| | const double& e=p1->at(1); |
| | const double& f=p1->at(2); |
| | const double& g=p1->at(3); |
| | const double& h=p1->at(4); |
| | const double& i=p1->at(5); |
| | |
| | |
| | |
| | std::vector<double> ce(3,0.); |
| | const double& a2=a*a; |
| | const double& b2=b*b; |
| | const double& c2=c*c; |
| | ce[0]= -f*a2+a*b*e-b2*d; |
| | ce[1]=a*b*g-a2*h- (2*b*c*d-a*c*e); |
| | ce[2]=a*c*g-c2*d-a2*i; |
| | |
| | |
| | std::vector<double> roots(0,0.); |
| | if( std::abs(ce[1])>RS_TOLERANCE15 && std::abs(ce[0]/ce[1])<RS_TOLERANCE15){ |
| | roots.push_back( - ce[2]/ce[1]); |
| | }else{ |
| | std::vector<double> ce2(2,0.); |
| | ce2[0]=ce[1]/ce[0]; |
| | ce2[1]=ce[2]/ce[0]; |
| | roots=quadraticSolver(ce2); |
| | } |
| | |
| | |
| | |
| |
|
| |
|
| | if(roots.size()==0) { |
| | return RS_VectorSolutions(); |
| | } |
| | for(size_t i=0;i<roots.size();i++){ |
| | ret.push_back(RS_Vector(-(b*roots.at(i)+c)/a,roots.at(i))); |
| | |
| | } |
| |
|
| | return ret; |
| |
|
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | bool RS_Math::simultaneousQuadraticVerify(const std::vector<std::vector<double> >& m, RS_Vector& v) |
| | { |
| | RS_Vector v0=v; |
| | auto& a=m[0][0]; |
| | auto& b=m[0][1]; |
| | auto& c=m[0][2]; |
| | auto& d=m[0][3]; |
| | auto& e=m[0][4]; |
| | auto& f=m[0][5]; |
| |
|
| | auto& g=m[1][0]; |
| | auto& h=m[1][1]; |
| | auto& i=m[1][2]; |
| | auto& j=m[1][3]; |
| | auto& k=m[1][4]; |
| | auto& l=m[1][5]; |
| | |
| | |
| | |
| | |
| | double sum0=0., sum1=0.; |
| | double f00=0.,f01=0.; |
| | double amax0, amax1; |
| | for(size_t i0=0; i0<20; ++i0){ |
| | double& x=v.x; |
| | double& y=v.y; |
| | double x2=x*x; |
| | double y2=y*y; |
| | double const terms0[12]={ a*x2, b*x*y, c*y2, d*x, e*y, f, g*x2, h*x*y, i*y2, j*x, k*y, l}; |
| | amax0=std::abs(terms0[0]), amax1=std::abs(terms0[6]); |
| | double px=2.*a*x+b*y+d; |
| | double py=b*x+2.*c*y+e; |
| | sum0=0.; |
| | for(int i=0; i<6; i++) { |
| | if(amax0<std::abs(terms0[i])) amax0=std::abs(terms0[i]); |
| | sum0 += terms0[i]; |
| | } |
| | std::vector<std::vector<double>> nrCe; |
| | nrCe.push_back(std::vector<double>{px, py, sum0}); |
| | px=2.*g*x+h*y+j; |
| | py=h*x+2.*i*y+k; |
| | sum1=0.; |
| | for(int i=6; i<12; i++) { |
| | if(amax1<std::abs(terms0[i])) amax1=std::abs(terms0[i]); |
| | sum1 += terms0[i]; |
| | } |
| | nrCe.push_back(std::vector<double>{px, py, sum1}); |
| | std::vector<double> dn; |
| | bool ret=linearSolver(nrCe, dn); |
| | |
| | |
| | if(!i0){ |
| | f00=sum0; |
| | f01=sum1; |
| | } |
| | if(!ret) break; |
| | v -= RS_Vector(dn[0], dn[1]); |
| | } |
| | if( std::abs(sum0)> std::abs(f00) && std::abs(sum1)>std::abs(f01)){ |
| | v=v0; |
| | sum0=f00; |
| | sum1=f01; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | const double tols=2.*sqrt(6.)*sqrt(DBL_EPSILON); |
| |
|
| | return (amax0<=tols || std::abs(sum0)/amax0<tols) && (amax1<=tols || std::abs(sum1)/amax1<tols); |
| | } |
| | |
| |
|