Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F102459324
eig33.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Feb 20, 23:13
Size
7 KB
Mime Type
text/x-c
Expires
Sat, Feb 22, 23:13 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
24324242
Attached To
rDLMA Diffusion limited mixed aggregation
eig33.cpp
View Options
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// The computeRoots function included in this is based on materials
// covered by the following copyright and license:
//
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <bench/BenchTimer.h>
using
namespace
Eigen
;
using
namespace
std
;
template
<
typename
Matrix
,
typename
Roots
>
inline
void
computeRoots
(
const
Matrix
&
m
,
Roots
&
roots
)
{
typedef
typename
Matrix
::
Scalar
Scalar
;
const
Scalar
s_inv3
=
1.0
/
3.0
;
const
Scalar
s_sqrt3
=
std
::
sqrt
(
Scalar
(
3.0
));
// The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The
// eigenvalues are the roots to this equation, all guaranteed to be
// real-valued, because the matrix is symmetric.
Scalar
c0
=
m
(
0
,
0
)
*
m
(
1
,
1
)
*
m
(
2
,
2
)
+
Scalar
(
2
)
*
m
(
0
,
1
)
*
m
(
0
,
2
)
*
m
(
1
,
2
)
-
m
(
0
,
0
)
*
m
(
1
,
2
)
*
m
(
1
,
2
)
-
m
(
1
,
1
)
*
m
(
0
,
2
)
*
m
(
0
,
2
)
-
m
(
2
,
2
)
*
m
(
0
,
1
)
*
m
(
0
,
1
);
Scalar
c1
=
m
(
0
,
0
)
*
m
(
1
,
1
)
-
m
(
0
,
1
)
*
m
(
0
,
1
)
+
m
(
0
,
0
)
*
m
(
2
,
2
)
-
m
(
0
,
2
)
*
m
(
0
,
2
)
+
m
(
1
,
1
)
*
m
(
2
,
2
)
-
m
(
1
,
2
)
*
m
(
1
,
2
);
Scalar
c2
=
m
(
0
,
0
)
+
m
(
1
,
1
)
+
m
(
2
,
2
);
// Construct the parameters used in classifying the roots of the equation
// and in solving the equation for the roots in closed form.
Scalar
c2_over_3
=
c2
*
s_inv3
;
Scalar
a_over_3
=
(
c1
-
c2
*
c2_over_3
)
*
s_inv3
;
if
(
a_over_3
>
Scalar
(
0
))
a_over_3
=
Scalar
(
0
);
Scalar
half_b
=
Scalar
(
0.5
)
*
(
c0
+
c2_over_3
*
(
Scalar
(
2
)
*
c2_over_3
*
c2_over_3
-
c1
));
Scalar
q
=
half_b
*
half_b
+
a_over_3
*
a_over_3
*
a_over_3
;
if
(
q
>
Scalar
(
0
))
q
=
Scalar
(
0
);
// Compute the eigenvalues by solving for the roots of the polynomial.
Scalar
rho
=
std
::
sqrt
(
-
a_over_3
);
Scalar
theta
=
std
::
atan2
(
std
::
sqrt
(
-
q
),
half_b
)
*
s_inv3
;
Scalar
cos_theta
=
std
::
cos
(
theta
);
Scalar
sin_theta
=
std
::
sin
(
theta
);
roots
(
2
)
=
c2_over_3
+
Scalar
(
2
)
*
rho
*
cos_theta
;
roots
(
0
)
=
c2_over_3
-
rho
*
(
cos_theta
+
s_sqrt3
*
sin_theta
);
roots
(
1
)
=
c2_over_3
-
rho
*
(
cos_theta
-
s_sqrt3
*
sin_theta
);
}
template
<
typename
Matrix
,
typename
Vector
>
void
eigen33
(
const
Matrix
&
mat
,
Matrix
&
evecs
,
Vector
&
evals
)
{
typedef
typename
Matrix
::
Scalar
Scalar
;
// Scale the matrix so its entries are in [-1,1]. The scaling is applied
// only when at least one matrix entry has magnitude larger than 1.
Scalar
shift
=
mat
.
trace
()
/
3
;
Matrix
scaledMat
=
mat
;
scaledMat
.
diagonal
().
array
()
-=
shift
;
Scalar
scale
=
scaledMat
.
cwiseAbs
()
/*.template triangularView<Lower>()*/
.
maxCoeff
();
scale
=
std
::
max
(
scale
,
Scalar
(
1
));
scaledMat
/=
scale
;
// Compute the eigenvalues
// scaledMat.setZero();
computeRoots
(
scaledMat
,
evals
);
// compute the eigen vectors
// **here we assume 3 different eigenvalues**
// "optimized version" which appears to be slower with gcc!
// Vector base;
// Scalar alpha, beta;
// base << scaledMat(1,0) * scaledMat(2,1),
// scaledMat(1,0) * scaledMat(2,0),
// -scaledMat(1,0) * scaledMat(1,0);
// for(int k=0; k<2; ++k)
// {
// alpha = scaledMat(0,0) - evals(k);
// beta = scaledMat(1,1) - evals(k);
// evecs.col(k) = (base + Vector(-beta*scaledMat(2,0), -alpha*scaledMat(2,1), alpha*beta)).normalized();
// }
// evecs.col(2) = evecs.col(0).cross(evecs.col(1)).normalized();
// // naive version
// Matrix tmp;
// tmp = scaledMat;
// tmp.diagonal().array() -= evals(0);
// evecs.col(0) = tmp.row(0).cross(tmp.row(1)).normalized();
//
// tmp = scaledMat;
// tmp.diagonal().array() -= evals(1);
// evecs.col(1) = tmp.row(0).cross(tmp.row(1)).normalized();
//
// tmp = scaledMat;
// tmp.diagonal().array() -= evals(2);
// evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized();
// a more stable version:
if
((
evals
(
2
)
-
evals
(
0
))
<=
Eigen
::
NumTraits
<
Scalar
>::
epsilon
())
{
evecs
.
setIdentity
();
}
else
{
Matrix
tmp
;
tmp
=
scaledMat
;
tmp
.
diagonal
().
array
()
-=
evals
(
2
);
evecs
.
col
(
2
)
=
tmp
.
row
(
0
).
cross
(
tmp
.
row
(
1
)).
normalized
();
tmp
=
scaledMat
;
tmp
.
diagonal
().
array
()
-=
evals
(
1
);
evecs
.
col
(
1
)
=
tmp
.
row
(
0
).
cross
(
tmp
.
row
(
1
));
Scalar
n1
=
evecs
.
col
(
1
).
norm
();
if
(
n1
<=
Eigen
::
NumTraits
<
Scalar
>::
epsilon
())
evecs
.
col
(
1
)
=
evecs
.
col
(
2
).
unitOrthogonal
();
else
evecs
.
col
(
1
)
/=
n1
;
// make sure that evecs[1] is orthogonal to evecs[2]
evecs
.
col
(
1
)
=
evecs
.
col
(
2
).
cross
(
evecs
.
col
(
1
).
cross
(
evecs
.
col
(
2
))).
normalized
();
evecs
.
col
(
0
)
=
evecs
.
col
(
2
).
cross
(
evecs
.
col
(
1
));
}
// Rescale back to the original size.
evals
*=
scale
;
evals
.
array
()
+=
shift
;
}
int
main
()
{
BenchTimer
t
;
int
tries
=
10
;
int
rep
=
400000
;
typedef
Matrix3d
Mat
;
typedef
Vector3d
Vec
;
Mat
A
=
Mat
::
Random
(
3
,
3
);
A
=
A
.
adjoint
()
*
A
;
// Mat Q = A.householderQr().householderQ();
// A = Q * Vec(2.2424567,2.2424566,7.454353).asDiagonal() * Q.transpose();
SelfAdjointEigenSolver
<
Mat
>
eig
(
A
);
BENCH
(
t
,
tries
,
rep
,
eig
.
compute
(
A
));
std
::
cout
<<
"Eigen iterative: "
<<
t
.
best
()
<<
"s
\n
"
;
BENCH
(
t
,
tries
,
rep
,
eig
.
computeDirect
(
A
));
std
::
cout
<<
"Eigen direct : "
<<
t
.
best
()
<<
"s
\n
"
;
Mat
evecs
;
Vec
evals
;
BENCH
(
t
,
tries
,
rep
,
eigen33
(
A
,
evecs
,
evals
));
std
::
cout
<<
"Direct: "
<<
t
.
best
()
<<
"s
\n\n
"
;
// std::cerr << "Eigenvalue/eigenvector diffs:\n";
// std::cerr << (evals - eig.eigenvalues()).transpose() << "\n";
// for(int k=0;k<3;++k)
// if(evecs.col(k).dot(eig.eigenvectors().col(k))<0)
// evecs.col(k) = -evecs.col(k);
// std::cerr << evecs - eig.eigenvectors() << "\n\n";
}
Event Timeline
Log In to Comment