Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Matrix2x2.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "Matrix2x2.hh"
27 #include "Vector2.hh"
28 #include "Base/Common/CompareFloatingPoint.hh"
29 
30 #include <Base/Common/BIASpragma.hh>
31 
32 
33 using namespace BIAS;
34 using namespace std;
35 
36 namespace BIAS {
37 
38 #define MATRIX2X2_ZERO_EPS 1e-13
39 
40 //#ifdef BIAS_DEBUG
41 //#define MATRIX_DEBUG(arg) cout << arg;
42 //#else
43 #define MATRIX_DEBUG(arg)
44 //#endif
45 
46 // template<class T>
47 // Matrix2x2<T>::Matrix2x2(const Matrix<T> & A)
48 // : Matrix<T>(2, 2)
49 // {
50 // if (A.num_rows() != 2 || A.num_cols() != 2){
51 // BIASERR("try to cast from Matrix with inavlid size "<<A);
52 // } else {
53 // register T *dataP = A.GetData();
54 // memcpy(v_, dataP, 4*sizeof(T));
55 // }
56 // }
57 
58 template<class T>
60 {
61  if ((mat.num_rows() != 2) || (mat.num_cols() != 2)) {
62  BIASERR("Wrong matrix size "<<mat.num_rows()<<"x"<< mat.num_cols()<<
63  " for 2x2 matrix!");
64  BIASABORT;
65  }
66 }
67 
68 
69 template<class T>
70 Matrix2x2<T>::Matrix2x2(const std::string & s)
71 : Matrix<T>(2, 2, s)
72 {}
73 
74 
75 template<class T>
76 Matrix2x2<T>::Matrix2x2(const T a0, const T a1,
77  const T a2, const T a3)
78  : Matrix<T>(2, 2)
79 {
80  this->GetData()[0]=a0; this->GetData()[1]=a1;
81  this->GetData()[2]=a2; this->GetData()[3]=a3;
82 }
83 
84 
85 template<class T>
87 
88 template<class T>
90 {
91  register const T *matP = mat.GetData();
92  register T *destP = this->GetData();
93  memcpy(destP, matP, 4*sizeof(T));
94  return *this;
95 }
96 
97 template<class T>
98 Matrix2x2<T>& Matrix2x2<T>::newsize(int rows, int cols)
99 {
100  BIASERR("newsize(" << rows << ", " << cols << ") does not make sense "
101  "for fixed size 2x2 matrix!");
102  return *((Matrix2x2 *)NULL);
103 }
104 
105 
106 template<>
108  BIASERR("Unsigned integer matrix can not be inverted!");
109  BIASBREAK;
110  return -1;
111 }
112 
113 
114 template<class T>
116 {
117  T den=(*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0];
118  //if (den==0.0) std::cerr << *this << std::endl << den << std::endl;
119  if (den==0.0) return -1;
120  BIASASSERT(den!=0.0);
121 
122  result[0][0]=(*this)[1][1]/den;
123  result[1][0]=-(*this)[1][0]/den;
124  result[0][1]=-(*this)[0][1]/den;
125  result[1][1]=(*this)[0][0]/den;
126  return 0;
127 }
128 
129 template<class T>
130 int Matrix2x2<T>::
131 EigenvalueDecomposition(T& /*value1*/, Vector2<T>& /*vector1*/,
132  T& /*value2*/, Vector2<T>& /*vector2*/) const
133 {
134  BIASERR("Eigenvalue decomposition can not be computed for integer matrices!");
135  return -1;
136 }
137 
138 template<>
141  double& value2, Vector2<double>& vec2) const
142 {
143  int res=2;
144  double a=(*this)[0][0], b=(*this)[0][1], c=(*this)[1][1], d=(*this)[1][0];
145  MATRIX_DEBUG( "a "<<a <<"\tb "<<b<<"\tc "<<c<<"\td "<<d<<endl);
146 
147  // this code does not work on the matrix
148  // 1.74776224781231 4.82304033948846
149  // 5.91024707366034 -0.89410165009984
150 
151  //output:
152  // a 1.74776224781231 b 4.82304033948846 c -0.89410165009984 d 5.91024707366034
153  // value1: -5.07318981623247 value2: 5.92685041394494
154  // value1: 5.07318981623247 value2: 5.92685041394494
155  // rank 2 5.07318981623247 5.92685041394494
156  // norm1: 5.85834333486369
157  // vec1: [ -0.8232771731 -0.5676395831 ]
158  // vec1: [ 0.8232771731 0.5676395831 ]
159  // norm2: 9.025320356
160  // vec2: [ 0.7557573355 0.654851777 ]
161  // vec2: [ 0.7557573355 0.654851777 ]
162  // Found 2 real eigenvalues
163  // eigenvectors are [ 0.8232771731 0.5676395831 ] and [ 0.7557573355 0.654851777 ]
164 
165  // eigenvectors are not orthogonal
166  // lapack finds values = [ 5.926850414 -5.073189816 ] imag=[ 0 0 ]
167  // and vectors=2 2
168  // 0.755757335458229 -0.57734219951434
169  // 0.654851777046591 0.816502286990027
170 
171  // I suspect symmetry is assumed somewhere, but why is b,d needed then ???
172  // koeser 05/2007
173  //BIASASSERT(Equal(b,d));
174 
175 
176 
177 
178  // eigenvalue decoposition of symmetric 2 by 2 matrix
179  // | a b | | x_12 | | x_12 |
180  // | d c | | y_12 | = l_12 | y_12 |
181  // characteristic polynomial
182  // (lambda-a)*(lambda-c)-b*d = lambda^2 - lambda*a - lambda*c + a*c -b*d
183  // = lambda^2 - lambda*(a+c) +a*c-b*d = 0
184  // -> \lambda_12 = (a+c)/2 +- \sqrt((a+c)^2/4-ac+bd)
185  // x_1 = - b / sqrt(b*b+(a-l1)*(a-l1));
186  // y_1 = (a-l1) / sqrt(b*b+(a-l1)*(a-l1));
187  // x_2 = - (c-l2) / sqrt(b*b+(c-l2)*(c-l2));
188  // y_2 = d / sqrt(d*d+(c-l2)*(c-l2));
189  double norm1, norm2;
190  //TimeMeasure t;
191  //t.Start();
192 
193  norm1=(a+c)/2.0;
194  norm2=(a+c)*(a+c)/4.0-a*c+b*d;
195  if (norm2 > -numeric_limits<double>::epsilon() && norm2 < 0.0 ) {
196  norm2 = 0.0;
197  }
198  if (norm2<0.0) { // imaginary solution
199  MATRIX_DEBUG("only imaginary solutions\n");
200  MATRIX_DEBUG("norm2<0.0: "<<norm2<<endl);
201  res=0;
202  } else {
203  norm2=sqrt(norm2);
204  value2=norm1+norm2;
205  value1=norm1-norm2;
206 
207  // number of eigenvalues!=0
208  res = ((fabs(value1)<DOUBLE_EPSILON)?0:1) +
209  ((fabs(value2)<DOUBLE_EPSILON)?0:1);
210  MATRIX_DEBUG("rank "<<res<<"\t"<<value1<<"\t"<<value2<<"\n");
211 
212  norm1 = sqrt(b*b+(a-value1)*(a-value1));
213  MATRIX_DEBUG("norm1: "<<norm1<<endl);
214  if (norm1>=MATRIX2X2_ZERO_EPS){
215  vec1[0] = - b / norm1;
216  vec1[1] = (a-value1) / norm1;
217  } else { //happens if b=0 -> cov is already orthogonal
218  vec1[0] = 1.0 ;
219  vec1[1] = 0.0;
220  }
221  MATRIX_DEBUG("vec1: "<<vec1<<endl);
222 
223  norm2 = sqrt(d*d+(c-value2)*(c-value2));
224  MATRIX_DEBUG("norm2: "<<norm2<<endl);
225  if (norm2>=MATRIX2X2_ZERO_EPS){
226  vec2[0] = - (c-value2) / norm2;
227  vec2[1] = d / norm2;
228  } else { //happens if b=0 -> cov is already orthogonal
229  vec2[0] = 0.0;
230  vec2[1] = 1.0;
231  }
232  MATRIX_DEBUG("vec2: "<<vec2<<endl);
233  /*
234  t.Stop();
235  cout << "manual took "<<t.GetRealTime()<<" us"<<endl;
236  t.Reset();
237  */
238 
239  // cout << "value1 "<<value1<<"\tvalue2 "<<value2<<endl;
240  // cout << "norm1 "<<norm1<<"\tnorm2 "<<norm2<<endl;
241  // cout << "vec1 : "<<vec1[0]<<", "<<vec1[1]<<endl;
242  // cout << "vec2 : "<<vec2[0]<<", "<<vec2[1]<<endl;
243  // cout << "vec1 . vec2 : "
244  // <<vec1[0]*vec2[0]+vec1[1]*vec2[1]<<endl;
245  }
246 
247  /*
248  // compare with svd
249  // t.Start();
250  Matrix2x2<double> A, U;
251  Vector2<double> S;
252  A[0][0]=a;
253  A[0][1]=b;
254  A[1][1]=c;
255  A[1][0]=d;
256  SVD svd(A);
257  U = svd.GetU();
258  S = svd.GetS();
259  vec1[0] = S[0] * U[0][0];
260  vec1[1] = S[0] * U[0][1];
261  vec2[0] = S[1] * U[1][0];
262  vec2[1] = S[1] * U[1][1];
263  //t.Stop();
264  // cout << "svd took "<<t.GetRealTime()<<" us"<<endl;
265  cout << "\nsvd :\n";
266  cout << "vec1 : "<<vec1[0]<<", "<<vec1[1]<<endl;
267  cout << "vec2 : "<<vec2[0]<<", "<<vec2[1]<<endl;
268  cout << "U: "<<svd.GetU()<<"\nS: "<<svd.GetS()<<"\nVT: "<<svd.GetVT()<<endl;
269  */
270 
271  return res;
272 }
273 
274 } // namespace BIAS
275 
276 
277 #define INST(type) \
278 template class BIASMathBase_EXPORT BIAS::Matrix2x2<type>;\
279 
280 INST(unsigned char)
281 INST(char)
282 INST(float)
283 INST(short)
284 INST(unsigned short)
285 INST(long int)
286 INST(int)
287 INST(unsigned int)
288 INST(double)
Subscript num_cols() const
Definition: cmat.h:320
is a &#39;fixed size&#39; quadratic matrix of dim.
Definition: Matrix2x2.hh:48
Matrix2x2 & newsize(int rows, int cols)
just neccessary to avoid resizing of this &#39;fixed size&#39; matrix because it is derived from the resizabl...
Definition: Matrix2x2.cpp:98
class Vector2 contains a Vector of dim.
Definition: Vector2.hh:79
Matrix2x2< T > Invert() const
Definition: Matrix2x2.hh:152
T * GetData()
get the pointer to the data array of the matrix (for faster direct memeory access) ...
Definition: Matrix.hh:185
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
Definition: Matrix2x2.cpp:131
Matrix2x2< T > & operator=(const Matrix2x2< T > &mat)
assignment operator
Definition: Matrix2x2.cpp:89
matrix class with arbitrary size, indexing is row major.
Subscript num_rows() const
Definition: cmat.h:319
virtual ~Matrix2x2()
Definition: Matrix2x2.cpp:86