DriveHQ Start Menu
Cloud Drive Mapping
Folder Sync
Cloud Backup
True Drop Box
FTP/SFTP Hosting
Group Account
DriveHQ Start Menu
Online File Server
My Storage
|
Manage Shares
|
Publishes
|
Drop Boxes
|
Group Account
WebDAV Drive Mapping
Cloud Drive Home
|
WebDAV Guide
|
Drive Mapping Tool
|
Drive Mapping URL
Complete Data Backup
Backup Guide
|
Online Backup Tool
|
Cloud-to-Cloud Backup
FTP, Email & Web Service
FTP Home
|
FTP Hosting FAQ
|
Email Hosting
|
EmailManager
|
Web Hosting
Help & Resources
About
|
Enterprise Service
|
Partnership
|
Comparisons
|
Support
Quick Links
Security and Privacy
Download Software
Service Manual
Use Cases
Group Account
Online Help
Blog
Contact
Cloud Surveillance
Sign Up
Login
Features
Business Features
Online File Server
FTP Hosting
Cloud Drive Mapping
Cloud File Backup
Email Backup & Hosting
Cloud File Sharing
Folder Synchronization
Group Management
True Drop Box
Full-text Search
AD Integration/SSO
Mobile Access
IP Camera & DVR Solution
More...
Personal Features
Personal Cloud Drive
Backup All Devices
Mobile APPs
Personal Web Hosting
Sub-Account (for Kids)
Home/PC/Kids Monitoring
More...
Software
DriveHQ Drive Mapping Tool
DriveHQ FileManager
DriveHQ Online Backup
DriveHQ Mobile Apps
Pricing
Business Plans & Pricing
Personal Plans & Pricing
Price Comparison with Others
Feature Comparison with Others
Install Mobile App
Sign up
Creating account...
Invalid character in username! Only 0-9, a-z, A-Z, _, -, . allowed.
Username is required!
Invalid email address!
E-mail is required!
Password is required!
Password is invalid!
Password and confirmation do not match.
Confirm password is required!
I accept
Membership Agreement
Please read the Membership Agreement and check "I accept"!
Free Quick Sign-up
Sign-up Page
Log in
Signing in...
Username or e-mail address is required!
Password is required!
Keep me logged in
Quick Login
Forgot Password
Up
Upload
Download
Share
Publish
New Folder
New File
Copy
Cut
Delete
Paste
Rate
Upgrade
Rotate
Effect
Edit
Slide
History
// (C) Copyright John Maddock 2006. // 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) #ifndef BOOST_MATH_TOOLS_REMEZ_HPP #define BOOST_MATH_TOOLS_REMEZ_HPP #include
#include
#include
#include
#include
#include
#include
#include
namespace boost{ namespace math{ namespace tools{ namespace detail{ // // The error function: the difference between F(x) and // the current approximation. This is the function // for which we must find the extema. // template
struct remez_error_function { typedef boost::function1
function_type; public: remez_error_function( function_type f_, const polynomial
& n, const polynomial
& d, bool rel_err) : f(f_), numerator(n), denominator(d), rel_error(rel_err) {} T operator()(const T& z)const { T y = f(z); T abs = y - (numerator.evaluate(z) / denominator.evaluate(z)); T err; if(rel_error) { if(y != 0) err = abs / fabs(y); else if(0 == abs) { // we must be at a root, or it's not recoverable: BOOST_ASSERT(0 == abs); err = 0; } else { // We have a divide by zero! // Lets assume that f(x) is zero as a result of // internal cancellation error that occurs as a result // of shifting a root at point z to the origin so that // the approximation can be "pinned" to pass through // the origin: in that case it really // won't matter what our approximation calculates here // as long as it's a small number, return the absolute error: err = abs; } } else err = abs; return err; } private: function_type f; polynomial
numerator; polynomial
denominator; bool rel_error; }; // // This function adapts the error function so that it's minima // are the extema of the error function. We can find the minima // with standard techniques. // template
struct remez_max_error_function { remez_max_error_function(const remez_error_function
& f) : func(f) {} T operator()(const T& x) { BOOST_MATH_STD_USING return -fabs(func(x)); } private: remez_error_function
func; }; } // detail template
class remez_minimax { public: typedef boost::function1
function_type; typedef boost::numeric::ublas::vector
vector_type; typedef boost::numeric::ublas::matrix
matrix_type; remez_minimax(function_type f, unsigned oN, unsigned oD, T a, T b, bool pin = true, bool rel_err = false, int sk = 0, int bits = 0); remez_minimax(function_type f, unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits, const vector_type& points); void reset(unsigned oN, unsigned oD, T a, T b, bool pin = true, bool rel_err = false, int sk = 0, int bits = 0); void reset(unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits, const vector_type& points); void set_brake(int b) { BOOST_ASSERT(b < 100); BOOST_ASSERT(b >= 0); m_brake = b; } T iterate(); polynomial
denominator()const; polynomial
numerator()const; vector_type const& chebyshev_points()const { return control_points; } vector_type const& zero_points()const { return zeros; } T error_term()const { return solution[solution.size() - 1]; } T max_error()const { return m_max_error; } T max_change()const { return m_max_change; } void rotate() { --orderN; ++orderD; } void rescale(T a, T b) { T scale = (b - a) / (max - min); for(unsigned i = 0; i < control_points.size(); ++i) { control_points[i] = (control_points[i] - min) * scale + a; } min = a; max = b; } private: void init_chebyshev(); function_type func; // The function to approximate. vector_type control_points; // Current control points to be used for the next iteration. vector_type solution; // Solution from the last iteration contains all unknowns including the error term. vector_type zeros; // Location of points of zero error from last iteration, plus the two end points. vector_type maxima; // Location of maxima of the error function, actually contains the control points used for the last iteration. T m_max_error; // Maximum error found in last approximation. T m_max_change; // Maximum change in location of control points after last iteration. unsigned orderN; // Order of the numerator polynomial. unsigned orderD; // Order of the denominator polynomial. T min, max; // End points of the range to optimise over. bool rel_error; // If true optimise for relative not absolute error. bool pinned; // If true the approximation is "pinned" to go through the origin. unsigned unknowns; // Total number of unknowns. int m_precision; // Number of bits precision to which the zeros and maxima are found. T m_max_change_history[2]; // Past history of changes to control points. int m_brake; // amount to break by in percentage points. int m_skew; // amount to skew starting points by in percentage points: -100-100 }; #ifndef BRAKE #define BRAKE 0 #endif #ifndef SKEW #define SKEW 0 #endif template
void remez_minimax
::init_chebyshev() { BOOST_MATH_STD_USING // // Fill in the zeros: // unsigned terms = pinned ? orderD + orderN : orderD + orderN + 1; for(unsigned i = 0; i < terms; ++i) { T cheb = cos((2 * terms - 1 - 2 * i) * constants::pi
() / (2 * terms)); cheb += 1; cheb /= 2; if(m_skew != 0) { T p = static_cast
(200 + m_skew) / 200; cheb = pow(cheb, p); } cheb *= (max - min); cheb += min; zeros[i+1] = cheb; } zeros[0] = min; zeros[unknowns] = max; // perform a regular interpolation fit: matrix_type A(terms, terms); vector_type b(terms); // fill in the y values: for(unsigned i = 0; i < b.size(); ++i) { b[i] = func(zeros[i+1]); } // fill in powers of x evaluated at each of the control points: unsigned offsetN = pinned ? 0 : 1; unsigned offsetD = offsetN + orderN; unsigned maxorder = (std::max)(orderN, orderD); for(unsigned i = 0; i < b.size(); ++i) { T x0 = zeros[i+1]; T x = x0; if(!pinned) A(i, 0) = 1; for(unsigned j = 0; j < maxorder; ++j) { if(j < orderN) A(i, j + offsetN) = x; if(j < orderD) { A(i, j + offsetD) = -x * b[i]; } x *= x0; } } // // Now go ahead and solve the expression to get our solution: // vector_type l_solution = boost::math::tools::solve(A, b); // need to add a "fake" error term: l_solution.resize(unknowns); l_solution[unknowns-1] = 0; solution = l_solution; // // Now find all the extrema of the error function: // detail::remez_error_function
Err(func, this->numerator(), this->denominator(), rel_error); detail::remez_max_error_function
Ex(Err); m_max_error = 0; int max_err_location = 0; for(unsigned i = 0; i < unknowns; ++i) { std::pair
r = brent_find_minima(Ex, zeros[i], zeros[i+1], m_precision); maxima[i] = r.first; T rel_err = fabs(r.second); if(rel_err > m_max_error) { m_max_error = fabs(r.second); max_err_location = i; } } control_points = maxima; } template
void remez_minimax
::reset( unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits) { control_points = vector_type(oN + oD + (pin ? 1 : 2)); solution = control_points; zeros = vector_type(oN + oD + (pin ? 2 : 3)); maxima = control_points; orderN = oN; orderD = oD; rel_error = rel_err; pinned = pin; m_skew = sk; min = a; max = b; m_max_error = 0; unknowns = orderN + orderD + (pinned ? 1 : 2); // guess our initial control points: control_points[0] = min; control_points[unknowns - 1] = max; T interval = (max - min) / (unknowns - 1); T spot = min + interval; for(unsigned i = 1; i < control_points.size(); ++i) { control_points[i] = spot; spot += interval; } solution[unknowns - 1] = 0; m_max_error = 0; if(bits == 0) { // don't bother about more than float precision: m_precision = (std::min)(24, (boost::math::policies::digits
>() / 2) - 2); } else { // can't be more accurate than half the bits of T: m_precision = (std::min)(bits, (boost::math::policies::digits
>() / 2) - 2); } m_max_change_history[0] = m_max_change_history[1] = 1; init_chebyshev(); // do one iteration whatever: //iterate(); } template
inline remez_minimax
::remez_minimax( typename remez_minimax
::function_type f, unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits) : func(f) { m_brake = 0; reset(oN, oD, a, b, pin, rel_err, sk, bits); } template
void remez_minimax
::reset( unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits, const vector_type& points) { control_points = vector_type(oN + oD + (pin ? 1 : 2)); solution = control_points; zeros = vector_type(oN + oD + (pin ? 2 : 3)); maxima = control_points; orderN = oN; orderD = oD; rel_error = rel_err; pinned = pin; m_skew = sk; min = a; max = b; m_max_error = 0; unknowns = orderN + orderD + (pinned ? 1 : 2); control_points = points; solution[unknowns - 1] = 0; m_max_error = 0; if(bits == 0) { // don't bother about more than float precision: m_precision = (std::min)(24, (boost::math::policies::digits
>() / 2) - 2); } else { // can't be more accurate than half the bits of T: m_precision = (std::min)(bits, (boost::math::policies::digits
>() / 2) - 2); } m_max_change_history[0] = m_max_change_history[1] = 1; // do one iteration whatever: //iterate(); } template
inline remez_minimax
::remez_minimax( typename remez_minimax
::function_type f, unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits, const vector_type& points) : func(f) { m_brake = 0; reset(oN, oD, a, b, pin, rel_err, sk, bits, points); } template
T remez_minimax
::iterate() { BOOST_MATH_STD_USING matrix_type A(unknowns, unknowns); vector_type b(unknowns); // fill in evaluation of f(x) at each of the control points: for(unsigned i = 0; i < b.size(); ++i) { // take care that none of our control points are at the origin: if(pinned && (control_points[i] == 0)) { if(i) control_points[i] = control_points[i-1] / 3; else control_points[i] = control_points[i+1] / 3; } b[i] = func(control_points[i]); } T err_err; unsigned convergence_count = 0; do{ // fill in powers of x evaluated at each of the control points: int sign = 1; unsigned offsetN = pinned ? 0 : 1; unsigned offsetD = offsetN + orderN; unsigned maxorder = (std::max)(orderN, orderD); T Elast = solution[unknowns - 1]; for(unsigned i = 0; i < b.size(); ++i) { T x0 = control_points[i]; T x = x0; if(!pinned) A(i, 0) = 1; for(unsigned j = 0; j < maxorder; ++j) { if(j < orderN) A(i, j + offsetN) = x; if(j < orderD) { T mult = rel_error ? (b[i] - sign * fabs(b[i]) * Elast): (b[i] - sign * Elast); A(i, j + offsetD) = -x * mult; } x *= x0; } // The last variable to be solved for is the error term, // sign changes with each control point: T E = rel_error ? sign * fabs(b[i]) : sign; A(i, unknowns - 1) = E; sign = -sign; } #ifdef BOOST_MATH_INSTRUMENT for(unsigned i = 0; i < b.size(); ++i) std::cout << b[i] << " "; std::cout << "\n\n"; for(unsigned i = 0; i < b.size(); ++i) { for(unsigned j = 0; j < b.size(); ++ j) std::cout << A(i, j) << " "; std::cout << "\n"; } std::cout << std::endl; #endif // // Now go ahead and solve the expression to get our solution: // solution = boost::math::tools::solve(A, b); err_err = (Elast != 0) ? fabs((fabs(solution[unknowns-1]) - fabs(Elast)) / fabs(Elast)) : 1; }while(orderD && (convergence_count++ < 80) && (err_err > 0.001)); // // Perform a sanity check to verify that the solution to the equations // is not so much in error as to be useless. The matrix inversion can // be very close to singular, so this can be a real problem. // vector_type sanity = prod(A, solution); for(unsigned i = 0; i < b.size(); ++i) { T err = fabs((b[i] - sanity[i]) / fabs(b[i])); if(err > sqrt(epsilon
())) { std::cerr << "Sanity check failed: more than half the digits in the found solution are in error." << std::endl; } } // // Next comes another sanity check, we want to verify that all the control // points do actually alternate in sign, in practice we may have // additional roots in the error function that cause this to fail. // Failure here is always fatal: even though this code attempts to correct // the problem it usually only postpones the inevitable. // polynomial
num, denom; num = this->numerator(); denom = this->denominator(); T e1 = b[0] - num.evaluate(control_points[0]) / denom.evaluate(control_points[0]); #ifdef BOOST_MATH_INSTRUMENT std::cout << e1; #endif for(unsigned i = 1; i < b.size(); ++i) { T e2 = b[i] - num.evaluate(control_points[i]) / denom.evaluate(control_points[i]); #ifdef BOOST_MATH_INSTRUMENT std::cout << " " << e2; #endif if(e2 * e1 > 0) { std::cerr << std::flush << "Basic sanity check failed: Error term does not alternate in sign, non-recoverable error may follow..." << std::endl; T perturbation = 0.05; do{ T point = control_points[i] * (1 - perturbation) + control_points[i-1] * perturbation; e2 = func(point) - num.evaluate(point) / denom.evaluate(point); if(e2 * e1 < 0) { control_points[i] = point; break; } perturbation += 0.05; }while(perturbation < 0.8); if((e2 * e1 > 0) && (i + 1 < b.size())) { perturbation = 0.05; do{ T point = control_points[i] * (1 - perturbation) + control_points[i+1] * perturbation; e2 = func(point) - num.evaluate(point) / denom.evaluate(point); if(e2 * e1 < 0) { control_points[i] = point; break; } perturbation += 0.05; }while(perturbation < 0.8); } } e1 = e2; } #ifdef BOOST_MATH_INSTRUMENT for(unsigned i = 0; i < solution.size(); ++i) std::cout << solution[i] << " "; std::cout << std::endl << this->numerator() << std::endl; std::cout << this->denominator() << std::endl; std::cout << std::endl; #endif // // The next step is to find all the intervals in which our maxima // lie: // detail::remez_error_function
Err(func, this->numerator(), this->denominator(), rel_error); zeros[0] = min; zeros[unknowns] = max; for(unsigned i = 1; i < control_points.size(); ++i) { eps_tolerance
tol(m_precision); boost::uintmax_t max_iter = 1000; std::pair
p = toms748_solve( Err, control_points[i-1], control_points[i], tol, max_iter); zeros[i] = (p.first + p.second) / 2; //zeros[i] = bisect(Err, control_points[i-1], control_points[i], m_precision); } // // Now find all the extrema of the error function: // detail::remez_max_error_function
Ex(Err); m_max_error = 0; int max_err_location = 0; for(unsigned i = 0; i < unknowns; ++i) { std::pair
r = brent_find_minima(Ex, zeros[i], zeros[i+1], m_precision); maxima[i] = r.first; T rel_err = fabs(r.second); if(rel_err > m_max_error) { m_max_error = fabs(r.second); max_err_location = i; } } // // Almost done now! we just need to set our control points // to the extrema, and calculate how much each point has changed // (this will be our termination condition): // swap(control_points, maxima); m_max_change = 0; int max_change_location = 0; for(unsigned i = 0; i < unknowns; ++i) { control_points[i] = (control_points[i] * (100 - m_brake) + maxima[i] * m_brake) / 100; T change = fabs((control_points[i] - maxima[i]) / control_points[i]); #if 0 if(change > m_max_change_history[1]) { // divergence!!! try capping the change: std::cerr << "Possible divergent step, change will be capped!!" << std::endl; change = m_max_change_history[1]; if(control_points[i] < maxima[i]) control_points[i] = maxima[i] - change * maxima[i]; else control_points[i] = maxima[i] + change * maxima[i]; } #endif if(change > m_max_change) { m_max_change = change; max_change_location = i; } } // // store max change information: // m_max_change_history[0] = m_max_change_history[1]; m_max_change_history[1] = fabs(m_max_change); return m_max_change; } template
polynomial
remez_minimax
::numerator()const { boost::scoped_array
a(new T[orderN + 1]); if(pinned) a[0] = 0; unsigned terms = pinned ? orderN : orderN + 1; for(unsigned i = 0; i < terms; ++i) a[pinned ? i+1 : i] = solution[i]; return boost::math::tools::polynomial
(&a[0], orderN); } template
polynomial
remez_minimax
::denominator()const { unsigned terms = orderD + 1; unsigned offsetD = pinned ? orderN : (orderN + 1); boost::scoped_array
a(new T[terms]); a[0] = 1; for(unsigned i = 0; i < orderD; ++i) a[i+1] = solution[i + offsetD]; return boost::math::tools::polynomial
(&a[0], orderD); } }}} // namespaces #endif // BOOST_MATH_TOOLS_REMEZ_HPP
remez.hpp
Page URL
File URL
Prev
9/19
Next
Download
( 19 KB )
Note: The DriveHQ service banners will NOT be displayed if the file owner is a paid member.
Comments
Total ratings:
0
Average rating:
Not Rated
Would you like to comment?
Join DriveHQ
for a free account, or
Logon
if you are already a member.