/usr/include/shark/LinAlg/rotations.h is in libshark-dev 3.0.1+ds1-2ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | /*!
*
*
* \brief Some operations for creating rotation matrices
*
*
*
*
* \author O. Krause
* \date 2011
*
*
* \par Copyright 1995-2015 Shark Development Team
*
* <BR><HR>
* This file is part of Shark.
* <http://image.diku.dk/shark/>
*
* Shark is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Shark is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Shark. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SHARK_LINALG_ROTATIONS_H
#define SHARK_LINALG_ROTATIONS_H
#include <shark/LinAlg/Base.h>
#include <shark/Rng/GlobalRng.h>
namespace shark{ namespace blas{
/**
* \ingroup shark_globals
*
* @{
*/
//! \brief Generates a Householder reflection from a vector to use with applyHouseholderLeft/Right
//!
//! Given a Vector x=(x0,x1,...,xn), finds a reflection with the property
//! (c, 0,0,...0) = (I-beta v v^t)x
//! and v = (x0-c,x1,x2,...,xn)
template<class X, class R>
typename X::value_type createHouseholderReflection(
vector_expression<X> const& x,
vector_expression<R>& reflection
){
SIZE_CHECK(x().size() != 0);
SIZE_CHECK(x().size() == reflection().size());
//special case for last iteration of QR etc
//by convention diagonal elements are > 0
if(x().size() == 1){
reflection()(0) = 1;
return 2;
}
typedef typename X::value_type Value;
double norm = norm_2(x);
if (x()(0) >= 0.0)
norm *= -1.0;
noalias(reflection()) = x;
reflection()(0) -= norm;
reflection() /= (x()(0) - norm);
//if pivot is close to 0, this is one->numericaly stable
//compared to the usual formula
Value beta = (norm - x()(0)) / norm;
return beta;
}
//\brief rotates a matrix using a householder reflection
//
//calculates A*(1-beta*xx^T)
template<class Mat, class R, class T>
void applyHouseholderOnTheRight(
matrix_expression<Mat> & matrix,
vector_expression<R> const& reflection,
T beta
){
SIZE_CHECK(matrix().size2() == reflection().size());
SIZE_CHECK(reflection().size() != 0 );
//special case for last iteration of QR etc
if(reflection().size() == 1){
matrix() *= 1-beta;
return;
}
SIZE_CHECK(matrix().size2() == reflection().size());
//Ax
vector<T> temp = prod(matrix,reflection);
//A -=beta*(Ax)x^T
noalias(matrix()) -= beta * outer_prod(temp,reflection);
}
/// \brief rotates a matrix using a householder reflection
///
/// calculates (1-beta*xx^T)*A
template<class Mat, class R, class T>
void applyHouseholderOnTheLeft(
matrix_expression<Mat> & matrix,
vector_expression<R> const& reflection,
T const& beta
){
SIZE_CHECK(matrix().size1() == reflection().size());
SIZE_CHECK(reflection().size() != 0 );
//special case for last iteration of QR etc
if(reflection().size() == 1){
matrix()*=1-beta;
return;
}
//x^T A
vector<T> temp = prod(trans(matrix),reflection);
//A -=beta*x(x^T A)
noalias(matrix()) -= beta * outer_prod(reflection,temp);
}
/// \brief rotates a matrix using a householder reflection
///
/// calculates (1-beta*xx^T)*A
template<class Mat, class R, class T>
void applyHouseholderOnTheLeft(
temporary_proxy<Mat> matrix,
vector_expression<R> const& reflection,
T const& beta
){
applyHouseholderOnTheLeft(static_cast<Mat&>(matrix),reflection,beta);
}
/// \brief Initializes a matrix such that it forms a random rotation matrix.
///
/// The matrix needs to be quadratic and have the proper size
/// (e.g. call matrix::resize before).
///
/// One common way to do this is using Gram-Schmidt-Orthogonalisation
/// on a matrix which is initialized with gaussian numbers. However, this is
/// highly unstable for big matrices.
///
/// This algorithm is implemented from one of the algorithms presented in
/// Francesco Mezzadri "How to generate random matrices from the classical compact groups"
/// http://arxiv.org/abs/math-ph/0609050v2
///
/// He gives two algorithms: the first one uses QR decomposition on the random gaussian
/// matrix and ensures that the signs of Q are correct by multiplying every column of Q
/// with the sign of the diagonal of R.
///
/// We use nother algorithm implemented in the paper which works similarly, but
/// reversed. We apply Householder rotations H_N H_{N-1}..H_1 where
/// H_1 is generated from a random vector on the n-dimensional unit sphere.
/// this requires less operations and is thus preferable. Also only half the
/// random numbers need to be generated
template< class MatrixT, typename RngType >
void randomRotationMatrix(matrix_container<MatrixT>& matrixC,RngType& rng){
MatrixT& matrix = matrixC();
SIZE_CHECK(matrix.size1() == matrix.size2());
SIZE_CHECK(matrix.size1() > 0);
Normal< RngType > normal( rng, 0, 1 );
size_t size = matrix.size1();
diag(matrix) = repeat(1.0,size);
//the first element is just -1 or 1
matrix(size-1,size-1) = normal();
matrix(size-1,size-1) /= std::abs(matrix(size-1,size-1));
RealVector v(size);
for(std::size_t i = 2; i != size;++i){
//create the random vector on the unit-sphere for the i-dimensional subproblem
for(std::size_t j=0;j != i; ++j){
v(j) = normal();
}
subrange(v,0,i) /=norm_2(subrange(v,0,i));//project on sphere
double v0 = v(0);
v(0) += v0/std::abs(v0);
//compute new norm of v
//~ double normvSqr = 1.0+(1+v0)*(1+v0)-v0*v0;
double normvSqr = norm_sqr(subrange(v,0,i));
//apply the householder rotation to the i-th submatrix
applyHouseholderOnTheLeft(subrange(matrix,size-i,size,size-i,size),subrange(v,0,i),2.0/normvSqr);
}
}
/// \brief Initializes a matrix such that it forms a random rotation
///
///matrix. The matrix needs to be quadratic and have the proper size
///(e.g. call matrix::resize before) uses the global RNG.
template<class MatrixT>
void randomRotationMatrix(matrix_container<MatrixT>& matrixC){
randomRotationMatrix( matrixC, Rng::globalRng );
}
//! Creates a random rotation matrix with a certain size using the random number generator rng.
template<typename RngType>
RealMatrix randomRotationMatrix(size_t size,RngType& rng){
RealMatrix mat(size,size);
randomRotationMatrix(mat,rng);
return mat;
}
//! Creates a random rotation matrix with a certain size using the global random number gneerator.
inline RealMatrix randomRotationMatrix(size_t size){
return randomRotationMatrix( size, shark::Rng::globalRng );
}
/** @}*/
}}
#endif
|