#ifndef SimTK_SimTKCOMMON_VECTOR_MATH_H_ #define SimTK_SimTKCOMMON_VECTOR_MATH_H_ /* -------------------------------------------------------------------------- * * SimTK Core: SimTKcommon * * -------------------------------------------------------------------------- * * This is part of the SimTK Core biosimulation toolkit originating from * * Simbios, the NIH National Center for Physics-Based Simulation of * * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * * Portions copyright (c) 2008 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ #include "SimTKcommon/basics.h" #include "SimTKcommon/Simmatrix.h" #include // for std:sin, sqrt, etc. #include // for std:sort, nth_element, etc. /** @file * This file defines a large number of standard math functions that can be * applied to vectors and matrices (both the large matrix and small matrix * classes). */ namespace SimTK { // We can use a single definition for a number of functions that simply call a function // on each element, returning a value of the same type. #define SimTK_ELEMENTWISE_FUNCTION(func) \ template \ VectorBase func(const VectorBase v) { \ const int size = v.size(); \ Vector_ temp(size); \ for (int i = 0; i < size; ++i) \ temp[i] = std::func(v[i]); \ return temp; \ } \ template \ RowVectorBase func(const RowVectorBase v) {\ const int size = v.size(); \ RowVector_ temp(size); \ for (int i = 0; i < size; ++i) \ temp[i] = std::func(v[i]); \ return temp; \ } \ template \ MatrixBase func(const MatrixBase v) { \ const int rows = v.nrow(), cols = v.ncol(); \ Matrix_ temp(rows, cols); \ for (int i = 0; i < rows; ++i) \ for (int j = 0; j < cols; ++j) \ temp(i, j) = std::func(v(i, j)); \ return temp; \ } \ template \ Vec func(Vec v) { \ for (int i = 0; i < N; ++i) \ v[i] = std::func(v[i]); \ return v; \ } \ template \ Row func(Row v) { \ for (int i = 0; i < N; ++i) \ v[i] = std::func(v[i]); \ return v; \ } \ template \ Mat func(Mat v) { \ for (int i = 0; i < M; ++i) \ for (int j = 0; j < N; ++j) \ v(i, j) = std::func(v(i, j)); \ return v; \ } \ template \ SymMat func(SymMat v) { \ for (int i = 0; i < N; ++i) \ for (int j = 0; j <= i; ++j) \ v(i, j) = std::func(v(i, j)); \ return v; \ } \ SimTK_ELEMENTWISE_FUNCTION(exp) SimTK_ELEMENTWISE_FUNCTION(log) SimTK_ELEMENTWISE_FUNCTION(sqrt) SimTK_ELEMENTWISE_FUNCTION(sin) SimTK_ELEMENTWISE_FUNCTION(cos) SimTK_ELEMENTWISE_FUNCTION(tan) SimTK_ELEMENTWISE_FUNCTION(asin) SimTK_ELEMENTWISE_FUNCTION(acos) SimTK_ELEMENTWISE_FUNCTION(atan) SimTK_ELEMENTWISE_FUNCTION(sinh) SimTK_ELEMENTWISE_FUNCTION(cosh) SimTK_ELEMENTWISE_FUNCTION(tanh) #undef SimTK_ELEMENTWISE_FUNCTION // The abs() function. template VectorBase::TAbs> abs(const VectorBase v) { return v.abs(); } template RowVectorBase::TAbs> abs(const RowVectorBase v) { return v.abs(); } template MatrixBase::TAbs> abs(const MatrixBase v) { return v.abs(); } template Vec::TAbs> abs(const Vec v) { return v.abs(); } template Row::TAbs> abs(const Row v) { return v.abs(); } template Mat::TAbs> abs(const Mat v) { return v.abs(); } template SymMat::TAbs> abs(const SymMat v) { return v.abs(); } // The sum() function. template ELEM sum(const VectorBase v) { return v.sum(); } template ELEM sum(const RowVectorBase v) { return v.sum(); } template RowVectorBase sum(const MatrixBase v) { return v.sum(); } template ELEM sum(const Vec v) { return v.sum(); } template ELEM sum(const Row v) { return v.sum(); } template Row sum(const Mat v) { return v.sum(); } template Row sum(const SymMat v) { return v.sum(); } // The min() function. template ELEM min(const VectorBase v) { const int size = v.size(); ELEM min = NTraits::getMostPositive(); for (int i = 0; i < size; ++i) { ELEM val = v[i]; if (val < min) min = val; } return min; } template ELEM min(const RowVectorBase v) { const int size = v.size(); ELEM min = NTraits::getMostPositive(); for (int i = 0; i < size; ++i) { ELEM val = v[i]; if (val < min) min = val; } return min; } template RowVectorBase min(const MatrixBase v) { int cols = v.ncol(); RowVectorBase temp(cols); for (int i = 0; i < cols; ++i) temp[i] = min(v(i)); return temp; } template ELEM min(const Vec v) { ELEM min = NTraits::getMostPositive(); for (int i = 0; i < N; ++i) { ELEM val = v[i]; if (val < min) min = val; } return min; } template ELEM min(Row v) { ELEM min = NTraits::getMostPositive(); for (int i = 0; i < N; ++i) { ELEM val = v[i]; if (val < min) min = val; } return min; } template Row min(const Mat v) { Row temp; for (int i = 0; i < N; ++i) temp[i] = min(v(i)); return temp; } template Row min(SymMat v) { Row temp(~v.getDiag()); for (int i = 1; i < N; ++i) for (int j = 0; j < i; ++j) { ELEM value = v.getEltLower(i, j); if (value < temp[i]) temp[i] = value; if (value < temp[j]) temp[j] = value; } return temp; } // The max() function. template ELEM max(const VectorBase v) { const int size = v.size(); ELEM max = NTraits::getMostNegative(); for (int i = 0; i < size; ++i) { ELEM val = v[i]; if (val > max) max = val; } return max; } template ELEM max(const RowVectorBase v) { const int size = v.size(); ELEM max = NTraits::getMostNegative(); for (int i = 0; i < size; ++i) { ELEM val = v[i]; if (val > max) max = val; } return max; } template RowVectorBase max(const MatrixBase v) { int cols = v.ncol(); RowVectorBase temp(cols); for (int i = 0; i < cols; ++i) temp[i] = max(v(i)); return temp; } template ELEM max(Vec v) { ELEM max = NTraits::getMostNegative(); for (int i = 0; i < N; ++i) { ELEM val = v[i]; if (val > max) max = val; } return max; } template ELEM max(const Row v) { ELEM max = NTraits::getMostNegative(); for (int i = 0; i < N; ++i) { ELEM val = v[i]; if (val > max) max = val; } return max; } template Row max(const Mat v) { Row temp; for (int i = 0; i < N; ++i) temp[i] = max(v(i)); return temp; } template Row max(const SymMat v) { Row temp(~v.getDiag()); for (int i = 1; i < N; ++i) for (int j = 0; j < i; ++j) { ELEM value = v.getEltLower(i, j); if (value > temp[i]) temp[i] = value; if (value > temp[j]) temp[j] = value; } return temp; } // The mean() function. template ELEM mean(const VectorBase v) { return sum(v)/v.size(); } template ELEM mean(const RowVectorBase v) { return sum(v)/v.size(); } template RowVectorBase mean(const MatrixBase v) { return sum(v)/v.nrow(); } template ELEM mean(const Vec v) { return sum(v)/N; } template ELEM mean(const Row v) { return sum(v)/N; } template Row mean(const Mat v) { return sum(v)/M; } template Row mean(const SymMat v) { return sum(v)/N; } // The sort() function. template VectorBase sort(const VectorBase v) { const int size = v.size(); VectorBase temp(v); std::sort(temp.begin(), temp.end()); return temp; } template RowVectorBase sort(const RowVectorBase v) { const int size = v.size(); RowVectorBase temp(v); std::sort(temp.begin(), temp.end()); return temp; } template MatrixBase sort(const MatrixBase v) { const int rows = v.nrow(), cols = v.ncol(); MatrixBase temp(v); for (int i = 0; i < cols; ++i) temp.updCol(i) = sort(temp.col(i)); return temp; } template Vec sort(Vec v) { ELEM* pointer = reinterpret_cast(&v); std::sort(pointer, pointer+N); return v; } template Row sort(Row v) { ELEM* pointer = reinterpret_cast(&v); std::sort(pointer, pointer+N); return v; } template Mat sort(Mat v) { for (int i = 0; i < N; ++i) v.col(i) = sort(v.col(i)); return v; } template Mat sort(const SymMat v) { return sort(Mat(v)); } // The median() function. template ELEM median(RandomAccessIterator start, RandomAccessIterator end) { const int size = (int)(end-start); RandomAccessIterator mid = start+(size-1)/2; std::nth_element(start, mid, end); if (size%2 == 0 && mid+1 < end) { // An even number of element. The median is the mean of the two middle elements. // nth_element has given us the first of them and partially sorted the list. // We need to scan through the rest of the list and find the next element in // sorted order. RandomAccessIterator min = mid+1; for (RandomAccessIterator iter = mid+1; iter < end; iter++) { if (*iter < *min) min = iter; } return (*mid+*min)/2; } return *mid; } template ELEM median(const VectorBase v) { VectorBase temp(v); return median(temp.begin(), temp.end()); } template ELEM median(const RowVectorBase v) { RowVectorBase temp(v); return median(temp.begin(), temp.end()); } template RowVectorBase median(const MatrixBase v) { int cols = v.ncol(), rows = v.nrow(); RowVectorBase temp(cols); VectorBase column(rows); for (int i = 0; i < cols; ++i) { column = v.col(i); temp[i] = median(column); } return temp; } template ELEM median(Vec v) { ELEM* pointer = reinterpret_cast(&v); return median(pointer, pointer+N); } template ELEM median(Row v) { ELEM* pointer = reinterpret_cast(&v); return median(pointer, pointer+N); } template Row median(const Mat v) { Row temp; for (int i = 0; i < N; ++i) temp[i] = median(v(i)); return temp; } template Row median(const SymMat v) { return median(Mat(v)); } } // namespace SimTK #endif // SimTK_SimTKCOMMON_VECTOR_MATH_H_