Simbody
|
00001 #ifndef SimTK_SimTKCOMMON_VECTOR_MATH_H_ 00002 #define SimTK_SimTKCOMMON_VECTOR_MATH_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org. * 00011 * * 00012 * Portions copyright (c) 2008 Stanford University and the Authors. * 00013 * Authors: Peter Eastman * 00014 * Contributors: * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00035 #include "SimTKcommon/basics.h" 00036 #include "SimTKcommon/Simmatrix.h" 00037 00038 #include <cmath> // for std:sin, sqrt, etc. 00039 #include <algorithm> // for std:sort, nth_element, etc. 00040 00047 namespace SimTK { 00048 00049 // We can use a single definition for a number of functions that simply call a function 00050 // on each element, returning a value of the same type. 00051 00052 #define SimTK_ELEMENTWISE_FUNCTION(func) \ 00053 template <class ELEM> \ 00054 VectorBase<ELEM> func(const VectorBase<ELEM> v) { \ 00055 const int size = v.size(); \ 00056 Vector_<ELEM> temp(size); \ 00057 for (int i = 0; i < size; ++i) \ 00058 temp[i] = std::func(v[i]); \ 00059 return temp; \ 00060 } \ 00061 template <class ELEM> \ 00062 RowVectorBase<ELEM> func(const RowVectorBase<ELEM> v) {\ 00063 const int size = v.size(); \ 00064 RowVector_<ELEM> temp(size); \ 00065 for (int i = 0; i < size; ++i) \ 00066 temp[i] = std::func(v[i]); \ 00067 return temp; \ 00068 } \ 00069 template <class ELEM> \ 00070 MatrixBase<ELEM> func(const MatrixBase<ELEM> v) { \ 00071 const int rows = v.nrow(), cols = v.ncol(); \ 00072 Matrix_<ELEM> temp(rows, cols); \ 00073 for (int i = 0; i < rows; ++i) \ 00074 for (int j = 0; j < cols; ++j) \ 00075 temp(i, j) = std::func(v(i, j)); \ 00076 return temp; \ 00077 } \ 00078 template <int N, class ELEM> \ 00079 Vec<N, ELEM> func(Vec<N, ELEM> v) { \ 00080 for (int i = 0; i < N; ++i) \ 00081 v[i] = std::func(v[i]); \ 00082 return v; \ 00083 } \ 00084 template <int N, class ELEM> \ 00085 Row<N, ELEM> func(Row<N, ELEM> v) { \ 00086 for (int i = 0; i < N; ++i) \ 00087 v[i] = std::func(v[i]); \ 00088 return v; \ 00089 } \ 00090 template <int M, int N, class ELEM> \ 00091 Mat<M, N, ELEM> func(Mat<M, N, ELEM> v) { \ 00092 for (int i = 0; i < M; ++i) \ 00093 for (int j = 0; j < N; ++j) \ 00094 v(i, j) = std::func(v(i, j)); \ 00095 return v; \ 00096 } \ 00097 template <int N, class ELEM> \ 00098 SymMat<N, ELEM> func(SymMat<N, ELEM> v) { \ 00099 for (int i = 0; i < N; ++i) \ 00100 for (int j = 0; j <= i; ++j) \ 00101 v(i, j) = std::func(v(i, j)); \ 00102 return v; \ 00103 } \ 00104 00105 SimTK_ELEMENTWISE_FUNCTION(exp) 00106 SimTK_ELEMENTWISE_FUNCTION(log) 00107 SimTK_ELEMENTWISE_FUNCTION(sqrt) 00108 SimTK_ELEMENTWISE_FUNCTION(sin) 00109 SimTK_ELEMENTWISE_FUNCTION(cos) 00110 SimTK_ELEMENTWISE_FUNCTION(tan) 00111 SimTK_ELEMENTWISE_FUNCTION(asin) 00112 SimTK_ELEMENTWISE_FUNCTION(acos) 00113 SimTK_ELEMENTWISE_FUNCTION(atan) 00114 SimTK_ELEMENTWISE_FUNCTION(sinh) 00115 SimTK_ELEMENTWISE_FUNCTION(cosh) 00116 SimTK_ELEMENTWISE_FUNCTION(tanh) 00117 00118 #undef SimTK_ELEMENTWISE_FUNCTION 00119 00120 // The abs() function. 00121 00122 template <class ELEM> 00123 VectorBase<typename CNT<ELEM>::TAbs> abs(const VectorBase<ELEM> v) { 00124 return v.abs(); 00125 } 00126 template <class ELEM> 00127 RowVectorBase<typename CNT<ELEM>::TAbs> abs(const RowVectorBase<ELEM> v) { 00128 return v.abs(); 00129 } 00130 template <class ELEM> 00131 MatrixBase<typename CNT<ELEM>::TAbs> abs(const MatrixBase<ELEM> v) { 00132 return v.abs(); 00133 } 00134 template <int N, class ELEM> 00135 Vec<N, typename CNT<ELEM>::TAbs> abs(const Vec<N, ELEM> v) { 00136 return v.abs(); 00137 } 00138 template <int N, class ELEM> 00139 Row<N, typename CNT<ELEM>::TAbs> abs(const Row<N, ELEM> v) { 00140 return v.abs(); 00141 } 00142 template <int M, int N, class ELEM> 00143 Mat<M, N, typename CNT<ELEM>::TAbs> abs(const Mat<M, N, ELEM> v) { 00144 return v.abs(); 00145 } 00146 template <int N, class ELEM> 00147 SymMat<N, typename CNT<ELEM>::TAbs> abs(const SymMat<N, ELEM> v) { 00148 return v.abs(); 00149 } 00150 00151 // The sum() function. 00152 00153 template <class ELEM> 00154 ELEM sum(const VectorBase<ELEM> v) { 00155 return v.sum(); 00156 } 00157 template <class ELEM> 00158 ELEM sum(const RowVectorBase<ELEM> v) { 00159 return v.sum(); 00160 } 00161 template <class ELEM> 00162 RowVectorBase<ELEM> sum(const MatrixBase<ELEM> v) { 00163 return v.sum(); 00164 } 00165 template <int N, class ELEM> 00166 ELEM sum(const Vec<N, ELEM> v) { 00167 return v.sum(); 00168 } 00169 template <int N, class ELEM> 00170 ELEM sum(const Row<N, ELEM> v) { 00171 return v.sum(); 00172 } 00173 template <int M, int N, class ELEM> 00174 Row<N, ELEM> sum(const Mat<M, N, ELEM> v) { 00175 return v.sum(); 00176 } 00177 template <int N, class ELEM> 00178 Row<N, ELEM> sum(const SymMat<N, ELEM> v) { 00179 return v.sum(); 00180 } 00181 00182 // The min() function. 00183 00184 template <class ELEM> 00185 ELEM min(const VectorBase<ELEM> v) { 00186 const int size = v.size(); 00187 ELEM min = NTraits<ELEM>::getMostPositive(); 00188 for (int i = 0; i < size; ++i) { 00189 ELEM val = v[i]; 00190 if (val < min) 00191 min = val; 00192 } 00193 return min; 00194 } 00195 template <class ELEM> 00196 ELEM min(const RowVectorBase<ELEM> v) { 00197 const int size = v.size(); 00198 ELEM min = NTraits<ELEM>::getMostPositive(); 00199 for (int i = 0; i < size; ++i) { 00200 ELEM val = v[i]; 00201 if (val < min) 00202 min = val; 00203 } 00204 return min; 00205 } 00206 template <class ELEM> 00207 RowVectorBase<ELEM> min(const MatrixBase<ELEM> v) { 00208 int cols = v.ncol(); 00209 RowVectorBase<ELEM> temp(cols); 00210 for (int i = 0; i < cols; ++i) 00211 temp[i] = min(v(i)); 00212 return temp; 00213 } 00214 template <int N, class ELEM> 00215 ELEM min(const Vec<N, ELEM> v) { 00216 ELEM min = NTraits<ELEM>::getMostPositive(); 00217 for (int i = 0; i < N; ++i) { 00218 ELEM val = v[i]; 00219 if (val < min) 00220 min = val; 00221 } 00222 return min; 00223 } 00224 template <int N, class ELEM> 00225 ELEM min(Row<N, ELEM> v) { 00226 ELEM min = NTraits<ELEM>::getMostPositive(); 00227 for (int i = 0; i < N; ++i) { 00228 ELEM val = v[i]; 00229 if (val < min) 00230 min = val; 00231 } 00232 return min; 00233 } 00234 template <int M, int N, class ELEM> 00235 Row<N, ELEM> min(const Mat<M, N, ELEM> v) { 00236 Row<N, ELEM> temp; 00237 for (int i = 0; i < N; ++i) 00238 temp[i] = min(v(i)); 00239 return temp; 00240 } 00241 template <int N, class ELEM> 00242 Row<N, ELEM> min(SymMat<N, ELEM> v) { 00243 Row<N, ELEM> temp(~v.getDiag()); 00244 for (int i = 1; i < N; ++i) 00245 for (int j = 0; j < i; ++j) { 00246 ELEM value = v.getEltLower(i, j); 00247 if (value < temp[i]) 00248 temp[i] = value; 00249 if (value < temp[j]) 00250 temp[j] = value; 00251 } 00252 return temp; 00253 } 00254 00255 // The max() function. 00256 00257 template <class ELEM> 00258 ELEM max(const VectorBase<ELEM> v) { 00259 const int size = v.size(); 00260 ELEM max = NTraits<ELEM>::getMostNegative(); 00261 for (int i = 0; i < size; ++i) { 00262 ELEM val = v[i]; 00263 if (val > max) 00264 max = val; 00265 } 00266 return max; 00267 } 00268 template <class ELEM> 00269 ELEM max(const RowVectorBase<ELEM> v) { 00270 const int size = v.size(); 00271 ELEM max = NTraits<ELEM>::getMostNegative(); 00272 for (int i = 0; i < size; ++i) { 00273 ELEM val = v[i]; 00274 if (val > max) 00275 max = val; 00276 } 00277 return max; 00278 } 00279 template <class ELEM> 00280 RowVectorBase<ELEM> max(const MatrixBase<ELEM> v) { 00281 int cols = v.ncol(); 00282 RowVectorBase<ELEM> temp(cols); 00283 for (int i = 0; i < cols; ++i) 00284 temp[i] = max(v(i)); 00285 return temp; 00286 } 00287 template <int N, class ELEM> 00288 ELEM max(Vec<N, ELEM> v) { 00289 ELEM max = NTraits<ELEM>::getMostNegative(); 00290 for (int i = 0; i < N; ++i) { 00291 ELEM val = v[i]; 00292 if (val > max) 00293 max = val; 00294 } 00295 return max; 00296 } 00297 template <int N, class ELEM> 00298 ELEM max(const Row<N, ELEM> v) { 00299 ELEM max = NTraits<ELEM>::getMostNegative(); 00300 for (int i = 0; i < N; ++i) { 00301 ELEM val = v[i]; 00302 if (val > max) 00303 max = val; 00304 } 00305 return max; 00306 } 00307 template <int M, int N, class ELEM> 00308 Row<N, ELEM> max(const Mat<M, N, ELEM> v) { 00309 Row<N, ELEM> temp; 00310 for (int i = 0; i < N; ++i) 00311 temp[i] = max(v(i)); 00312 return temp; 00313 } 00314 template <int N, class ELEM> 00315 Row<N, ELEM> max(const SymMat<N, ELEM> v) { 00316 Row<N, ELEM> temp(~v.getDiag()); 00317 for (int i = 1; i < N; ++i) 00318 for (int j = 0; j < i; ++j) { 00319 ELEM value = v.getEltLower(i, j); 00320 if (value > temp[i]) 00321 temp[i] = value; 00322 if (value > temp[j]) 00323 temp[j] = value; 00324 } 00325 return temp; 00326 } 00327 00328 // The mean() function. 00329 00330 template <class ELEM> 00331 ELEM mean(const VectorBase<ELEM> v) { 00332 return sum(v)/v.size(); 00333 } 00334 template <class ELEM> 00335 ELEM mean(const RowVectorBase<ELEM> v) { 00336 return sum(v)/v.size(); 00337 } 00338 template <class ELEM> 00339 RowVectorBase<ELEM> mean(const MatrixBase<ELEM> v) { 00340 return sum(v)/v.nrow(); 00341 } 00342 template <int N, class ELEM> 00343 ELEM mean(const Vec<N, ELEM> v) { 00344 return sum(v)/N; 00345 } 00346 template <int N, class ELEM> 00347 ELEM mean(const Row<N, ELEM> v) { 00348 return sum(v)/N; 00349 } 00350 template <int M, int N, class ELEM> 00351 Row<N, ELEM> mean(const Mat<M, N, ELEM> v) { 00352 return sum(v)/M; 00353 } 00354 template <int N, class ELEM> 00355 Row<N, ELEM> mean(const SymMat<N, ELEM> v) { 00356 return sum(v)/N; 00357 } 00358 00359 // The sort() function. 00360 00361 template <class ELEM> 00362 VectorBase<ELEM> sort(const VectorBase<ELEM> v) { 00363 const int size = v.size(); 00364 VectorBase<ELEM> temp(v); 00365 std::sort(temp.begin(), temp.end()); 00366 return temp; 00367 } 00368 template <class ELEM> 00369 RowVectorBase<ELEM> sort(const RowVectorBase<ELEM> v) { 00370 const int size = v.size(); 00371 RowVectorBase<ELEM> temp(v); 00372 std::sort(temp.begin(), temp.end()); 00373 return temp; 00374 } 00375 template <class ELEM> 00376 MatrixBase<ELEM> sort(const MatrixBase<ELEM> v) { 00377 const int rows = v.nrow(), cols = v.ncol(); 00378 MatrixBase<ELEM> temp(v); 00379 for (int i = 0; i < cols; ++i) 00380 temp.updCol(i) = sort(temp.col(i)); 00381 return temp; 00382 } 00383 template <int N, class ELEM> 00384 Vec<N, ELEM> sort(Vec<N, ELEM> v) { 00385 ELEM* pointer = reinterpret_cast<ELEM*>(&v); 00386 std::sort(pointer, pointer+N); 00387 return v; 00388 } 00389 template <int N, class ELEM> 00390 Row<N, ELEM> sort(Row<N, ELEM> v) { 00391 ELEM* pointer = reinterpret_cast<ELEM*>(&v); 00392 std::sort(pointer, pointer+N); 00393 return v; 00394 } 00395 template <int M, int N, class ELEM> 00396 Mat<M, N, ELEM> sort(Mat<M, N, ELEM> v) { 00397 for (int i = 0; i < N; ++i) 00398 v.col(i) = sort(v.col(i)); 00399 return v; 00400 } 00401 template <int N, class ELEM> 00402 Mat<N, N, ELEM> sort(const SymMat<N, ELEM> v) { 00403 return sort(Mat<N, N, ELEM>(v)); 00404 } 00405 00406 // The median() function. 00407 00408 template <class ELEM, class RandomAccessIterator> 00409 ELEM median(RandomAccessIterator start, RandomAccessIterator end) { 00410 const int size = (int)(end-start); 00411 RandomAccessIterator mid = start+(size-1)/2; 00412 std::nth_element(start, mid, end); 00413 if (size%2 == 0 && mid+1 < end) { 00414 // An even number of element. The median is the mean of the two middle elements. 00415 // nth_element has given us the first of them and partially sorted the list. 00416 // We need to scan through the rest of the list and find the next element in 00417 // sorted order. 00418 00419 RandomAccessIterator min = mid+1; 00420 for (RandomAccessIterator iter = mid+1; iter < end; iter++) { 00421 if (*iter < *min) 00422 min = iter; 00423 } 00424 return (*mid+*min)/2; 00425 } 00426 return *mid; 00427 } 00428 template <class ELEM> 00429 ELEM median(const VectorBase<ELEM> v) { 00430 VectorBase<ELEM> temp(v); 00431 return median<ELEM>(temp.begin(), temp.end()); 00432 } 00433 template <class ELEM> 00434 ELEM median(const RowVectorBase<ELEM> v) { 00435 RowVectorBase<ELEM> temp(v); 00436 return median<ELEM>(temp.begin(), temp.end()); 00437 } 00438 template <class ELEM> 00439 RowVectorBase<ELEM> median(const MatrixBase<ELEM> v) { 00440 int cols = v.ncol(), rows = v.nrow(); 00441 RowVectorBase<ELEM> temp(cols); 00442 VectorBase<ELEM> column(rows); 00443 for (int i = 0; i < cols; ++i) { 00444 column = v.col(i); 00445 temp[i] = median<ELEM>(column); 00446 } 00447 return temp; 00448 } 00449 template <int N, class ELEM> 00450 ELEM median(Vec<N, ELEM> v) { 00451 ELEM* pointer = reinterpret_cast<ELEM*>(&v); 00452 return median<ELEM>(pointer, pointer+N); 00453 } 00454 template <int N, class ELEM> 00455 ELEM median(Row<N, ELEM> v) { 00456 ELEM* pointer = reinterpret_cast<ELEM*>(&v); 00457 return median<ELEM>(pointer, pointer+N); 00458 } 00459 template <int M, int N, class ELEM> 00460 Row<N, ELEM> median(const Mat<M, N, ELEM> v) { 00461 Row<N, ELEM> temp; 00462 for (int i = 0; i < N; ++i) 00463 temp[i] = median(v(i)); 00464 return temp; 00465 } 00466 template <int N, class ELEM> 00467 Row<N, ELEM> median(const SymMat<N, ELEM> v) { 00468 return median(Mat<N, N, ELEM>(v)); 00469 } 00470 00471 } // namespace SimTK 00472 00473 #endif // SimTK_SimTKCOMMON_VECTOR_MATH_H_