1 /*
2  * Copyright 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef TMAT_IMPLEMENTATION
18 #error "Don't include TMatHelpers.h directly. use ui/mat*.h instead"
19 #else
20 #undef TMAT_IMPLEMENTATION
21 #endif
22 
23 
24 #ifndef UI_TMAT_HELPERS_H
25 #define UI_TMAT_HELPERS_H
26 
27 #include <stdint.h>
28 #include <sys/types.h>
29 #include <math.h>
30 #include <utils/Debug.h>
31 #include <utils/String8.h>
32 
33 #define PURE __attribute__((pure))
34 
35 namespace android {
36 // -------------------------------------------------------------------------------------
37 
38 /*
39  * No user serviceable parts here.
40  *
41  * Don't use this file directly, instead include ui/mat*.h
42  */
43 
44 
45 /*
46  * Matrix utilities
47  */
48 
49 namespace matrix {
50 
transpose(int v)51 inline int     PURE transpose(int v)    { return v; }
transpose(float v)52 inline float   PURE transpose(float v)  { return v; }
transpose(double v)53 inline double  PURE transpose(double v) { return v; }
54 
trace(int v)55 inline int     PURE trace(int v)    { return v; }
trace(float v)56 inline float   PURE trace(float v)  { return v; }
trace(double v)57 inline double  PURE trace(double v) { return v; }
58 
59 template<typename MATRIX>
inverse(const MATRIX & src)60 MATRIX PURE inverse(const MATRIX& src) {
61 
62     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::COL_SIZE == MATRIX::ROW_SIZE );
63 
64     typename MATRIX::value_type t;
65     const size_t N = MATRIX::col_size();
66     size_t swap;
67     MATRIX tmp(src);
68     MATRIX inverse(1);
69 
70     for (size_t i=0 ; i<N ; i++) {
71         // look for largest element in column
72         swap = i;
73         for (size_t j=i+1 ; j<N ; j++) {
74             if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
75                 swap = j;
76             }
77         }
78 
79         if (swap != i) {
80             /* swap rows. */
81             for (size_t k=0 ; k<N ; k++) {
82                 t = tmp[i][k];
83                 tmp[i][k] = tmp[swap][k];
84                 tmp[swap][k] = t;
85 
86                 t = inverse[i][k];
87                 inverse[i][k] = inverse[swap][k];
88                 inverse[swap][k] = t;
89             }
90         }
91 
92         t = 1 / tmp[i][i];
93         for (size_t k=0 ; k<N ; k++) {
94             tmp[i][k] *= t;
95             inverse[i][k] *= t;
96         }
97         for (size_t j=0 ; j<N ; j++) {
98             if (j != i) {
99                 t = tmp[j][i];
100                 for (size_t k=0 ; k<N ; k++) {
101                     tmp[j][k] -= tmp[i][k] * t;
102                     inverse[j][k] -= inverse[i][k] * t;
103                 }
104             }
105         }
106     }
107     return inverse;
108 }
109 
110 template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
multiply(const MATRIX_A & lhs,const MATRIX_B & rhs)111 MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
112     // pre-requisite:
113     //  lhs : D columns, R rows
114     //  rhs : C columns, D rows
115     //  res : C columns, R rows
116 
117     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_A::ROW_SIZE == MATRIX_B::COL_SIZE );
118     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::ROW_SIZE == MATRIX_B::ROW_SIZE );
119     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::COL_SIZE == MATRIX_A::COL_SIZE );
120 
121     MATRIX_R res(MATRIX_R::NO_INIT);
122     for (size_t r=0 ; r<MATRIX_R::row_size() ; r++) {
123         res[r] = lhs * rhs[r];
124     }
125     return res;
126 }
127 
128 // transpose. this handles matrices of matrices
129 template <typename MATRIX>
transpose(const MATRIX & m)130 MATRIX PURE transpose(const MATRIX& m) {
131     // for now we only handle square matrix transpose
132     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE );
133     MATRIX result(MATRIX::NO_INIT);
134     for (size_t r=0 ; r<MATRIX::row_size() ; r++)
135         for (size_t c=0 ; c<MATRIX::col_size() ; c++)
136             result[c][r] = transpose(m[r][c]);
137     return result;
138 }
139 
140 // trace. this handles matrices of matrices
141 template <typename MATRIX>
trace(const MATRIX & m)142 typename MATRIX::value_type PURE trace(const MATRIX& m) {
143     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE );
144     typename MATRIX::value_type result(0);
145     for (size_t r=0 ; r<MATRIX::row_size() ; r++)
146         result += trace(m[r][r]);
147     return result;
148 }
149 
150 // trace. this handles matrices of matrices
151 template <typename MATRIX>
diag(const MATRIX & m)152 typename MATRIX::col_type PURE diag(const MATRIX& m) {
153     COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE );
154     typename MATRIX::col_type result(MATRIX::col_type::NO_INIT);
155     for (size_t r=0 ; r<MATRIX::row_size() ; r++)
156         result[r] = m[r][r];
157     return result;
158 }
159 
160 template <typename MATRIX>
asString(const MATRIX & m)161 String8 asString(const MATRIX& m) {
162     String8 s;
163     for (size_t c=0 ; c<MATRIX::col_size() ; c++) {
164         s.append("|  ");
165         for (size_t r=0 ; r<MATRIX::row_size() ; r++) {
166             s.appendFormat("%7.2f  ", m[r][c]);
167         }
168         s.append("|\n");
169     }
170     return s;
171 }
172 
173 }; // namespace matrix
174 
175 // -------------------------------------------------------------------------------------
176 
177 /*
178  * TMatProductOperators implements basic arithmetic and basic compound assignments
179  * operators on a vector of type BASE<T>.
180  *
181  * BASE only needs to implement operator[] and size().
182  * By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically
183  * get all the functionality here.
184  */
185 
186 template <template<typename T> class BASE, typename T>
187 class TMatProductOperators {
188 public:
189     // multiply by a scalar
190     BASE<T>& operator *= (T v) {
191         BASE<T>& lhs(static_cast< BASE<T>& >(*this));
192         for (size_t r=0 ; r<lhs.row_size() ; r++) {
193             lhs[r] *= v;
194         }
195         return lhs;
196     }
197 
198     // divide by a scalar
199     BASE<T>& operator /= (T v) {
200         BASE<T>& lhs(static_cast< BASE<T>& >(*this));
201         for (size_t r=0 ; r<lhs.row_size() ; r++) {
202             lhs[r] /= v;
203         }
204         return lhs;
205     }
206 
207     // matrix * matrix, result is a matrix of the same type than the lhs matrix
208     template<typename U>
209     friend BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
210         return matrix::multiply<BASE<T> >(lhs, rhs);
211     }
212 };
213 
214 
215 /*
216  * TMatSquareFunctions implements functions on a matrix of type BASE<T>.
217  *
218  * BASE only needs to implement:
219  *  - operator[]
220  *  - col_type
221  *  - row_type
222  *  - COL_SIZE
223  *  - ROW_SIZE
224  *
225  * By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically
226  * get all the functionality here.
227  */
228 
229 template<template<typename U> class BASE, typename T>
230 class TMatSquareFunctions {
231 public:
232     /*
233      * NOTE: the functions below ARE NOT member methods. They are friend functions
234      * with they definition inlined with their declaration. This makes these
235      * template functions available to the compiler when (and only when) this class
236      * is instantiated, at which point they're only templated on the 2nd parameter
237      * (the first one, BASE<T> being known).
238      */
inverse(const BASE<T> & m)239     friend BASE<T> PURE inverse(const BASE<T>& m)   { return matrix::inverse(m); }
transpose(const BASE<T> & m)240     friend BASE<T> PURE transpose(const BASE<T>& m) { return matrix::transpose(m); }
trace(const BASE<T> & m)241     friend T       PURE trace(const BASE<T>& m)     { return matrix::trace(m); }
242 };
243 
244 template <template<typename T> class BASE, typename T>
245 class TMatDebug {
246 public:
asString()247     String8 asString() const {
248         return matrix::asString( static_cast< const BASE<T>& >(*this) );
249     }
250 };
251 
252 // -------------------------------------------------------------------------------------
253 }; // namespace android
254 
255 #undef PURE
256 
257 #endif /* UI_TMAT_HELPERS_H */
258