/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef TMAT_IMPLEMENTATION #error "Don't include TMatHelpers.h directly. use ui/mat*.h instead" #else #undef TMAT_IMPLEMENTATION #endif #ifndef UI_TMAT_HELPERS_H #define UI_TMAT_HELPERS_H #include <stdint.h> #include <sys/types.h> #include <math.h> #include <utils/Debug.h> #include <utils/String8.h> #define PURE __attribute__((pure)) namespace android { // ------------------------------------------------------------------------------------- /* * No user serviceable parts here. * * Don't use this file directly, instead include ui/mat*.h */ /* * Matrix utilities */ namespace matrix { inline int PURE transpose(int v) { return v; } inline float PURE transpose(float v) { return v; } inline double PURE transpose(double v) { return v; } inline int PURE trace(int v) { return v; } inline float PURE trace(float v) { return v; } inline double PURE trace(double v) { return v; } template<typename MATRIX> MATRIX PURE inverse(const MATRIX& src) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::COL_SIZE == MATRIX::ROW_SIZE ); typename MATRIX::value_type t; const size_t N = MATRIX::col_size(); size_t swap; MATRIX tmp(src); MATRIX inverse(1); for (size_t i=0 ; i<N ; i++) { // look for largest element in column swap = i; for (size_t j=i+1 ; j<N ; j++) { if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { swap = j; } } if (swap != i) { /* swap rows. */ for (size_t k=0 ; k<N ; k++) { t = tmp[i][k]; tmp[i][k] = tmp[swap][k]; tmp[swap][k] = t; t = inverse[i][k]; inverse[i][k] = inverse[swap][k]; inverse[swap][k] = t; } } t = 1 / tmp[i][i]; for (size_t k=0 ; k<N ; k++) { tmp[i][k] *= t; inverse[i][k] *= t; } for (size_t j=0 ; j<N ; j++) { if (j != i) { t = tmp[j][i]; for (size_t k=0 ; k<N ; k++) { tmp[j][k] -= tmp[i][k] * t; inverse[j][k] -= inverse[i][k] * t; } } } } return inverse; } template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B> MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { // pre-requisite: // lhs : D columns, R rows // rhs : C columns, D rows // res : C columns, R rows COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_A::ROW_SIZE == MATRIX_B::COL_SIZE ); COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::ROW_SIZE == MATRIX_B::ROW_SIZE ); COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::COL_SIZE == MATRIX_A::COL_SIZE ); MATRIX_R res(MATRIX_R::NO_INIT); for (size_t r=0 ; r<MATRIX_R::row_size() ; r++) { res[r] = lhs * rhs[r]; } return res; } // transpose. this handles matrices of matrices template <typename MATRIX> MATRIX PURE transpose(const MATRIX& m) { // for now we only handle square matrix transpose COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); MATRIX result(MATRIX::NO_INIT); for (size_t r=0 ; r<MATRIX::row_size() ; r++) for (size_t c=0 ; c<MATRIX::col_size() ; c++) result[c][r] = transpose(m[r][c]); return result; } // trace. this handles matrices of matrices template <typename MATRIX> typename MATRIX::value_type PURE trace(const MATRIX& m) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); typename MATRIX::value_type result(0); for (size_t r=0 ; r<MATRIX::row_size() ; r++) result += trace(m[r][r]); return result; } // trace. this handles matrices of matrices template <typename MATRIX> typename MATRIX::col_type PURE diag(const MATRIX& m) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); typename MATRIX::col_type result(MATRIX::col_type::NO_INIT); for (size_t r=0 ; r<MATRIX::row_size() ; r++) result[r] = m[r][r]; return result; } template <typename MATRIX> String8 asString(const MATRIX& m) { String8 s; for (size_t c=0 ; c<MATRIX::col_size() ; c++) { s.append("| "); for (size_t r=0 ; r<MATRIX::row_size() ; r++) { s.appendFormat("%7.2f ", m[r][c]); } s.append("|\n"); } return s; } }; // namespace matrix // ------------------------------------------------------------------------------------- /* * TMatProductOperators implements basic arithmetic and basic compound assignments * operators on a vector of type BASE<T>. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically * get all the functionality here. */ template <template<typename T> class BASE, typename T> class TMatProductOperators { public: // multiply by a scalar BASE<T>& operator *= (T v) { BASE<T>& lhs(static_cast< BASE<T>& >(*this)); for (size_t r=0 ; r<lhs.row_size() ; r++) { lhs[r] *= v; } return lhs; } // divide by a scalar BASE<T>& operator /= (T v) { BASE<T>& lhs(static_cast< BASE<T>& >(*this)); for (size_t r=0 ; r<lhs.row_size() ; r++) { lhs[r] /= v; } return lhs; } // matrix * matrix, result is a matrix of the same type than the lhs matrix template<typename U> friend BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) { return matrix::multiply<BASE<T> >(lhs, rhs); } }; /* * TMatSquareFunctions implements functions on a matrix of type BASE<T>. * * BASE only needs to implement: * - operator[] * - col_type * - row_type * - COL_SIZE * - ROW_SIZE * * By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically * get all the functionality here. */ template<template<typename U> class BASE, typename T> class TMatSquareFunctions { public: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE<T> being known). */ friend BASE<T> PURE inverse(const BASE<T>& m) { return matrix::inverse(m); } friend BASE<T> PURE transpose(const BASE<T>& m) { return matrix::transpose(m); } friend T PURE trace(const BASE<T>& m) { return matrix::trace(m); } }; template <template<typename T> class BASE, typename T> class TMatDebug { public: String8 asString() const { return matrix::asString( static_cast< const BASE<T>& >(*this) ); } }; // ------------------------------------------------------------------------------------- }; // namespace android #undef PURE #endif /* UI_TMAT_HELPERS_H */