Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
least_squares.hGo to the documentation of this file.00001 #ifndef INCLUDED_least_squares_h 00002 #define INCLUDED_least_squares_h 00003 00004 #include <valarray> 00005 #include <stdexcept> 00006 00007 /*! 00008 00009 Least Squares Solver 00010 by Ethan Tira-Thompson, © 2011 00011 00012 Solves linear systems using Ordinary Least Squares. 00013 00014 Provides the namespace 'least_squares'. 00015 00016 There are two solver functions: 00017 00018 linearFit(x,y) 00019 Returns the parameters 'a' such that y = x·a minimizes squared error. 00020 x should be a valarray< valarray<T> >, where each x[i] is a column 00021 of data with length matching that of the valarray y. 00022 00023 polyFit(degree,x,y) 00024 Performs a polynomial fit of degree n: 00025 y = [ 1 x .. xⁿ ] · a 00026 given x and y (as vector or valarray) Results will be in order of 00027 increasing power (i.e. index 0 is constant term, 1 is linear term, etc.) 00028 00029 Additionally, there are two helper functions: 00030 00031 polyApply(poly,x) 00032 Computes the polynomial of 'x' given polynomial terms 'poly'. 00033 These arguments can be either vector or valarray. 00034 00035 invert(x) 00036 Inverts a square valarray matrix 'x', overwriting results in-place. 00037 Throws std::underflow_error if the matrix is deficient. 00038 00039 TODO: does not handle degenerate/low-rank conditions very well. 00040 Ideally, the fit functions should handle internally instead of allowing 00041 invert()'s std::underflow_error to pass through 00042 00043 LICENSE: 00044 least_squares is free software: you can redistribute it and/or modify 00045 it under the terms of the Lesser GNU General Public License as published 00046 by the Free Software Foundation, either version 2 of the License, or 00047 (at your option) any later version, waiving any requirement to 00048 distribute the license document itself. 00049 00050 least_squares is distributed in the hope that it will be useful, 00051 but WITHOUT ANY WARRANTY; without even the implied warranty of 00052 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00053 Lesser GNU General Public License for more details. 00054 00055 */ 00056 00057 namespace least_squares { 00058 00059 // can't template a typedef, so use macro :-P 00060 // (we'll undef these again at the end so we don't pollute global namespace) 00061 #define V(T) std::valarray< T > 00062 #define M(T) std::valarray< V(T) > 00063 00064 00065 //! Returns parameters 'a' via ordinary least squares such that y = x·a 00066 /*! Each element of @a x should be a valarray with length matching that of @a y. 00067 * Will then compute invert(x' * x) * x' * y to find the fit. 00068 * 00069 * TODO: does not handle degenerate/low-rank conditions. Ideally, this 00070 * should be handled internally instead of allowing invert()'s 00071 * std::underflow_error to pass through. */ 00072 template<class T> 00073 V(T) linearFit(const M(T)& x, const V(T)& y); 00074 00075 //! Returns fit 'a' of @a degree powers of @a x: y = [ 1 x .. xⁿ ] · a 00076 /*! Accepts vector or valarray... results will be in order of 00077 * increasing power (i.e. 0 is constant term, 1 is linear term, etc.) 00078 * 00079 * TODO: does not handle degenerate/low-rank conditions. Ideally, this 00080 * should be handled internally instead of allowing invert()'s 00081 * std::underflow_error to pass through. */ 00082 template<class Vx, class Vy> 00083 V(typename Vx::value_type) polyFit(size_t degree, const Vx& x, const Vy& y); 00084 00085 //! Computes the polynomial of x given terms from @a poly. 00086 /*! Accepts either vector and valarray arguments... @a poly terms should 00087 * be in order of increasing degree à la polyFit() */ 00088 template<class Vp, class Vx> 00089 V(typename Vx::value_type) polyApply(const Vp& poly, const Vx& x); 00090 00091 //! Invert a matrix, in-place, using Gauss-Jordan elimination 00092 /*! Throws std::underflow_error if the matrix is deficient. */ 00093 template<class T> 00094 void invert(M(T)& m); 00095 00096 00097 /* Extern specializations allow us to move this template code to the .cpp file. 00098 * The downside is template will be undefined other than float and double... 00099 * Add more specializations here (e.g. complex) or else move template code 00100 * back into header. */ 00101 extern template void invert(M(float)& m); 00102 extern template void invert(M(double)& m); 00103 extern template V(float) linearFit(const M(float)& x, const V(float)& y); 00104 extern template V(double) linearFit(const M(double)& x, const V(double)& y); 00105 00106 00107 template<class Vx, class Vy> 00108 V(typename Vx::value_type) polyFit(size_t degree, const Vx& x, const Vy& y) { 00109 #ifdef DEBUG 00110 if(degree>0) { 00111 if(x.size()!=y.size()) { 00112 throw std::invalid_argument("polyFit(): x and y length mismatch"); 00113 } 00114 } 00115 if(y.size()<degree) { 00116 throw std::invalid_argument("polyFit(): insufficient values for degree"); 00117 } 00118 #endif 00119 typedef typename Vx::value_type T; 00120 const size_t N=y.size(); 00121 M(T) xn(V(T)(1,N),degree+1); 00122 if(degree>0) { 00123 memcpy(&xn[1][0], &x[0], sizeof(T)*N); 00124 for(size_t i=2; i<=degree; ++i) { 00125 xn[i] = xn[i-1]*xn[1]; 00126 } 00127 } 00128 return linearFit(xn,V(T)(&y[0],N)); 00129 } 00130 00131 00132 template<class Vp, class Vx> 00133 V(typename Vx::value_type) polyApply(const Vp& poly, const Vx& x) { 00134 typedef typename Vx::value_type T; 00135 const size_t N=x.size(); 00136 if(poly.size()==0) 00137 return V(T)(N); 00138 if(poly.size()==1) 00139 return V(T)(poly[0],N); 00140 V(T) v(N); // need to copy x into valarray in case it's a vector 00141 memcpy(&v[0],&x[0],sizeof(T)*N); 00142 V(T) acc(v*poly[1]); // linear term 00143 acc+=poly[0]; // constant term 00144 if(poly.size()>2) { 00145 V(T) p(v); // going to have to compute powers 00146 for(size_t i=2; i<poly.size(); ++i) { 00147 p*=v; 00148 acc += p*poly[i]; 00149 } 00150 } 00151 return acc; 00152 } 00153 00154 #undef V 00155 #undef M 00156 00157 } 00158 00159 #endif |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:58:43 2016 by Doxygen 1.6.3 |