SLAMflex SE  0.1.0
SLAMflex provides detection and tracking of dominant planes for smartphone devices. This plane can then be used to show AR content relative to the plane orientation. The detection of plane is performed in the field of view of the smartphone camera. In subsequent frames it is tracked. The interface returns the plane position and orientation.
SymEigen.h
Go to the documentation of this file.
1 // -*- c++ -*-
2 
3 // Copyright (C) 2005,2009 Tom Drummond (twd20@cam.ac.uk)
4 //
5 // This file is part of the TooN Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // You should have received a copy of the GNU General Public License along
17 // with this library; see the file COPYING. If not, write to the Free
18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 // USA.
20 
21 // As a special exception, you may use this file as part of a free software
22 // library without restriction. Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License. This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
29 
30 #ifndef __SYMEIGEN_H
31 #define __SYMEIGEN_H
32 
33 #include <iostream>
34 #include <cassert>
35 #include <cmath>
36 #include <complex>
37 #include "lapack.h"
38 
39 #include "TooN.h"
40 
41 namespace TooN {
42 static const double root3=1.73205080756887729352744634150587236694280525381038062805580;
43 
44 namespace Internal{
45 
46  using std::swap;
47 
49  static const double symeigen_condition_no=1e9;
50 
56  template <int Size> struct ComputeSymEigen {
57 
63  template<int Rows, int Cols, typename P, typename B>
64  static inline void compute(const Matrix<Rows,Cols,P, B>& m, Matrix<Size,Size,P> & evectors, Vector<Size, P>& evalues) {
65 
66  SizeMismatch<Rows, Cols>::test(m.num_rows(), m.num_cols()); //m must be square
67  SizeMismatch<Size, Rows>::test(m.num_rows(), evalues.size()); //m must be the size of the system
68 
69 
70  evectors = m;
71  int N = evalues.size();
72  int lda = evalues.size();
73  int info;
74  int lwork=-1;
75  P size;
76 
77  // find out how much space fortran needs
78  syev_((char*)"V",(char*)"U",&N,&evectors[0][0],&lda,&evalues[0], &size,&lwork,&info);
79  lwork = int(size);
80  Vector<Dynamic, P> WORK(lwork);
81 
82  // now compute the decomposition
83  syev_((char*)"V",(char*)"U",&N,&evectors[0][0],&lda,&evalues[0], &WORK[0],&lwork,&info);
84 
85  if(info!=0){
86  std::cerr << "In SymEigen<"<<Size<<">: " << info
87  << " off-diagonal elements of an intermediate tridiagonal form did not converge to zero." << std::endl
88  << "M = " << m << std::endl;
89  }
90  }
91  };
92 
97  template <> struct ComputeSymEigen<2> {
98 
104  template<typename P, typename B>
105  static inline void compute(const Matrix<2,2,P,B>& m, Matrix<2,2,P>& eig, Vector<2, P>& ev) {
106  double trace = m[0][0] + m[1][1];
107  double det = m[0][0]*m[1][1] - m[0][1]*m[1][0];
108  double disc = trace*trace - 4 * det;
109  assert(disc>=0);
110  using std::sqrt;
111  double root_disc = sqrt(disc);
112  ev[0] = 0.5 * (trace - root_disc);
113  ev[1] = 0.5 * (trace + root_disc);
114  double a = m[0][0] - ev[0];
115  double b = m[0][1];
116  double magsq = a*a + b*b;
117  if (magsq == 0) {
118  eig[0][0] = 1.0;
119  eig[0][1] = 0;
120  } else {
121  eig[0][0] = -b;
122  eig[0][1] = a;
123  eig[0] *= 1.0/sqrt(magsq);
124  }
125  eig[1][0] = -eig[0][1];
126  eig[1][1] = eig[0][0];
127  }
128  };
129 
134  template <> struct ComputeSymEigen<3> {
135 
141  template<typename P, typename B>
142  static inline void compute(const Matrix<3,3,P,B>& m, Matrix<3,3,P>& eig, Vector<3, P>& ev) {
143  //method uses closed form solution of cubic equation to obtain roots of characteristic equation.
144 
145  //Polynomial terms of |a - l * Identity|
146  //l^3 + a*l^2 + b*l + c
147 
148  const double& a11 = m[0][0];
149  const double& a12 = m[0][1];
150  const double& a13 = m[0][2];
151 
152  const double& a22 = m[1][1];
153  const double& a23 = m[1][2];
154 
155  const double& a33 = m[2][2];
156 
157  //From matlab:
158  double a = -a11-a22-a33;
159  double b = a11*a22+a11*a33+a22*a33-a12*a12-a13*a13-a23*a23;
160  double c = a11*(a23*a23)+(a13*a13)*a22+(a12*a12)*a33-a12*a13*a23*2.0-a11*a22*a33;
161 
162  //Using Cardano's method:
163  double p = b - a*a/3;
164  double q = c + (2*a*a*a - 9*a*b)/27;
165 
166  double alpha = -q/2;
167  double beta_descriminant = q*q/4 + p*p*p/27;
168 
169  //beta_descriminant <= 0 for real roots!
170  double beta = sqrt(-beta_descriminant);
171  double r2 = alpha*alpha - beta_descriminant;
172 
176 
177  double cuberoot_r = pow(r2, 1./6);
178  double theta3 = atan2(beta, alpha)/3;
179 
180  double A_plus_B = 2*cuberoot_r*cos(theta3);
181  double A_minus_B = -2*cuberoot_r*sin(theta3);
182 
183  //calculate eigenvalues
184  ev = makeVector(A_plus_B, -A_plus_B/2 + A_minus_B * sqrt(3)/2, -A_plus_B/2 - A_minus_B * sqrt(3)/2) - Ones * a/3;
185 
186  if(ev[0] > ev[1])
187  swap(ev[0], ev[1]);
188  if(ev[1] > ev[2])
189  swap(ev[1], ev[2]);
190  if(ev[0] > ev[1])
191  swap(ev[0], ev[1]);
192 
193  //calculate the eigenvectors
194  eig[0][0]=a12 * a23 - a13 * (a22 - ev[0]);
195  eig[0][1]=a12 * a13 - a23 * (a11 - ev[0]);
196  eig[0][2]=(a11-ev[0])*(a22-ev[0]) - a12*a12;
197  normalize(eig[0]);
198  eig[1][0]=a12 * a23 - a13 * (a22 - ev[1]);
199  eig[1][1]=a12 * a13 - a23 * (a11 - ev[1]);
200  eig[1][2]=(a11-ev[1])*(a22-ev[1]) - a12*a12;
201  normalize(eig[1]);
202  eig[2][0]=a12 * a23 - a13 * (a22 - ev[2]);
203  eig[2][1]=a12 * a13 - a23 * (a11 - ev[2]);
204  eig[2][2]=(a11-ev[2])*(a22-ev[2]) - a12*a12;
205  normalize(eig[2]);
206  }
207  };
208 
209 };
210 
259 template <int Size=Dynamic, typename Precision = double>
260 class SymEigen {
261 public:
262  inline SymEigen(){}
263 
268  inline SymEigen(int m) : my_evectors(m,m), my_evalues(m) {}
269 
272  template<int R, int C, typename B>
273  inline SymEigen(const Matrix<R, C, Precision, B>& m) : my_evectors(m.num_rows(), m.num_cols()), my_evalues(m.num_rows()) {
274  compute(m);
275  }
276 
278  template<int R, int C, typename B>
279  inline void compute(const Matrix<R,C,Precision,B>& m){
280  SizeMismatch<R, C>::test(m.num_rows(), m.num_cols());
281  SizeMismatch<R, Size>::test(m.num_rows(), my_evectors.num_rows());
283  }
284 
289  template <int S, typename P, typename B>
292  }
293 
298  template <int R, int C, typename P, typename B>
301  }
302 
309  return my_evectors.T() * diagmult(get_inv_diag(condition),my_evectors);
310  }
311 
318  Vector<Size, Precision> get_inv_diag(const double condition) const {
319  Precision max_diag = -my_evalues[0] > my_evalues[my_evalues.size()-1] ? -my_evalues[0]:my_evalues[my_evalues.size()-1];
320  Vector<Size, Precision> invdiag(my_evalues.size());
321  for(int i=0; i<my_evalues.size(); i++){
322  if(fabs(my_evalues[i]) * condition > max_diag) {
323  invdiag[i] = 1/my_evalues[i];
324  } else {
325  invdiag[i]=0;
326  }
327  }
328  return invdiag;
329  }
330 
337 
341 
342 
350 
352  bool is_posdef() const {
353  for (int i = 0; i < my_evalues.size(); ++i) {
354  if (my_evalues[i] <= 0.0)
355  return false;
356  }
357  return true;
358  }
359 
361  bool is_negdef() const {
362  for (int i = 0; i < my_evalues.size(); ++i) {
363  if (my_evalues[i] >= 0.0)
364  return false;
365  }
366  return true;
367  }
368 
370  Precision get_determinant () const {
371  Precision det = 1.0;
372  for (int i = 0; i < my_evalues.size(); ++i) {
373  det *= my_evalues[i];
374  }
375  return det;
376  }
377 
381  Vector<Size, Precision> diag_sqrt(my_evalues.size());
382  // In the future, maybe throw an exception if an
383  // eigenvalue is negative?
384  for (int i = 0; i < my_evalues.size(); ++i) {
385  diag_sqrt[i] = std::sqrt(my_evalues[i]);
386  }
387  return my_evectors.T() * diagmult(diag_sqrt, my_evectors);
388  }
389 
397  Vector<Size, Precision> diag_isqrt(my_evalues.size());
398 
399  // Because sqrt is a monotonic-preserving transformation,
400  Precision max_diag = -my_evalues[0] > my_evalues[my_evalues.size()-1] ? (-std::sqrt(my_evalues[0])):(std::sqrt(my_evalues[my_evalues.size()-1]));
401  // In the future, maybe throw an exception if an
402  // eigenvalue is negative?
403  for (int i = 0; i < my_evalues.size(); ++i) {
404  diag_isqrt[i] = std::sqrt(my_evalues[i]);
405  if(fabs(diag_isqrt[i]) * condition > max_diag) {
406  diag_isqrt[i] = 1/diag_isqrt[i];
407  } else {
408  diag_isqrt[i] = 0;
409  }
410  }
411  return my_evectors.T() * diagmult(diag_isqrt, my_evectors);
412  }
413 
414 private:
415  // eigen vectors laid out row-wise so evectors[i] is the ith evector
417 
419 };
420 
421 }
422 
423 #endif
424 
Matrix< Size, Size, Precision > get_pinv(const double condition=Internal::symeigen_condition_no) const
Definition: SymEigen.h:308
SymEigen(const Matrix< R, C, Precision, B > &m)
Definition: SymEigen.h:273
void normalize(Vector< Size, Precision, Base > v)
Definition: helpers.h:138
Matrix< Size, Size, Precision > get_isqrtm(const double condition=Internal::symeigen_condition_no) const
Definition: SymEigen.h:396
void compute(const Matrix< R, C, Precision, B > &m)
Perform the eigen decomposition of a matrix.
Definition: SymEigen.h:279
Vector< Size, Precision > my_evalues
Definition: SymEigen.h:418
Matrix< Size, Size, Precision > get_sqrtm() const
Definition: SymEigen.h:380
Everything lives inside this namespace.
Definition: allocator.hh:48
static void test(int s1, int s2)
static void compute(const Matrix< Rows, Cols, P, B > &m, Matrix< Size, Size, P > &evectors, Vector< Size, P > &evalues)
Definition: SymEigen.h:64
Precision get_determinant() const
Get the determinant of the matrix.
Definition: SymEigen.h:370
static const Operator< Internal::Scalars< Internal::One > > Ones
Definition: objects.h:713
static void compute(const Matrix< 2, 2, P, B > &m, Matrix< 2, 2, P > &eig, Vector< 2, P > &ev)
Definition: SymEigen.h:105
Matrix< Size, Size, Precision > & get_evectors()
Definition: SymEigen.h:336
const Matrix< Size, Size, Precision > & get_evectors() const
Definition: SymEigen.h:340
Matrix< Size, C, Precision > backsub(const Matrix< R, C, P, B > &rhs) const
Definition: SymEigen.h:299
Precision trace(const Matrix< Rows, Cols, Precision, Base > &m)
Definition: helpers.h:336
void syev_(const char *JOBZ, const char *UPLO, int *N, double *A, int *lda, double *W, double *WORK, int *LWORK, int *INFO)
Definition: lapack.h:156
bool is_posdef() const
Is the matrix positive definite?
Definition: SymEigen.h:352
Matrix< Size, Size, Precision > my_evectors
Definition: SymEigen.h:416
bool is_negdef() const
Is the matrix negative definite?
Definition: SymEigen.h:361
Vector< 1 > makeVector(double x1)
Definition: make_vector.hh:4
const Vector< Size, Precision > & get_evalues() const
Definition: SymEigen.h:349
Vector< Size, Precision > backsub(const Vector< S, P, B > &rhs) const
Definition: SymEigen.h:290
static const double symeigen_condition_no
Default condition number for SymEigen::backsub, SymEigen::get_pinv and SymEigen::get_inv_diag.
Definition: SymEigen.h:49
static const double root3
Definition: SymEigen.h:42
Vector< Size, Precision > get_inv_diag(const double condition) const
Definition: SymEigen.h:318
SymEigen(int m)
Definition: SymEigen.h:268
Vector< Internal::Sizer< S1, S2 >::size, typename Internal::MultiplyType< P1, P2 >::type > diagmult(const Vector< S1, P1, B1 > &v1, const Vector< S2, P2, B2 > &v2)
Definition: operators.hh:149
static void compute(const Matrix< 3, 3, P, B > &m, Matrix< 3, 3, P > &eig, Vector< 3, P > &ev)
Definition: SymEigen.h:142
Vector< Size, Precision > & get_evalues()
Definition: SymEigen.h:346