////////////////////////////////////////////////////////////////////////// // // Implementaiton of iterative 3x3 SVD without branches, using approximate Givens rotations, // applied sequentially to every off-diagonal element. The same code can compile into scalar, SSE and AVX // by templetizing on the Float data type. // #include "ssemath.h" namespace SVD { inline fltx4 CmpLt( const fltx4 &a, const fltx4 &b ) { return CmpLtSIMD( a, b ); } inline bool CmpLt( float a, float b ) { return a < b ? true : false; } inline bool AllLe( const fltx4 &a, const fltx4 &b ){ return IsAllGreaterThanOrEq( b, a ); } inline bool AllLe( float a, float b ) { return a <= b; } template struct FloatTraits { typedef Float Bool; }; template <> struct FloatTraits < float > { typedef bool Bool; }; template< typename Float > inline Float Replicate( float a ); template <> inline fltx4 Replicate< fltx4 >( float a ) { return _mm_set1_ps( a ); } template <> inline float Replicate< float >( float a ){ return a; } template class SymMatrix3; inline fltx4 RsqrtEst( const fltx4 &a ){ return ReciprocalSqrtEstSIMD( a ); } template inline Float Rsqrt( const Float &a ) { fltx4 it = RsqrtEst( a ); // a single Newton iteration; can repeat multiple times return Replicate( .5f ) * it * ( Replicate( 3.0f ) - ( a * it * it ) ); } inline float RsqrtEst( float a ) { float res; StoreUnalignedFloat( &res, RsqrtEst( LoadUnalignedFloatSIMD(&a) ) ); return res; } template <> inline float Rsqrt( const float &a ) { return 1.0f / sqrtf( a ); } inline fltx4 Select( const fltx4& a /*mask=0*/, const fltx4& b/*mask=1*/, const fltx4& mask ) { // (((b ^ a) & mask)^a) return _mm_xor_ps( a, _mm_and_ps( mask, _mm_xor_ps( b, a ) ) ); } inline float Select( float a, float b, bool mask ) { return mask ? b : a; } template class Matrix3 { public: Matrix3() {} Float m[ 3 ][ 3 ]; Matrix3 < Float > operator * ( const Matrix3< Float > &other )const { Matrix3 < Float > res; for ( int i = 0; i < 3; ++i ) for ( int j = 0; j < 3; ++j ) res.m[ i ][ j ] = m[ i ][ 0 ] * other.m[ 0 ][ j ] + m[ i ][ 1 ] * other.m[ 1 ][ j ] + m[ i ][ 2 ] * other.m[ 2 ][ j ]; return res; } Matrix3 < Float > operator - ( const Matrix3< Float > &other )const { Matrix3 < Float > res; for ( int i = 0; i < 3; ++i ) for ( int j = 0; j < 3; ++j ) res.m[ i ][ j ] = m[ i ][ j ] - other.m[ i ][ j ]; return res; } explicit Matrix3< Float >( const SymMatrix3< Float > &other ); Float FrobeniusNorm()const { Float sum = Replicate( 0.0f ); for ( int i = 0; i < 3; ++i ) for ( int j = 0; j < 3; ++j ) sum += m[ i ][ j ] * m[ i ][ j ]; return sum; } Float AtA( int i, int j )const { return m[ 0 ][ i ] * m[ 0 ][ j ] + m[ 1 ][ i ] * m[ 1 ][ j ] + m[ 2 ][ i ] * m[ 2 ][ j ]; } void SetIdentity() { m[ 0 ][ 0 ] = m[ 1 ][ 1 ] = m[ 2 ][ 2 ] = Replicate( 1.0f ); m[ 0 ][ 1 ] = m[ 1 ][ 0 ] = m[ 0 ][ 2 ] = m[ 2 ][ 0 ] = m[ 2 ][ 1 ] = m[ 1 ][ 2 ] = Replicate( 0.0f ); } void SetZero() { memset( this, 0, sizeof( *this ) ); } Float ColLenSqr( int j )const { return m[ 0 ][ j ] * m[ 0 ][ j ] + m[ 1 ][ j ] * m[ 1 ][ j ] + m[ 2 ][ j ] * m[ 2 ][ j ]; } Float Det()const { return -( m[ 0 ][ 2 ]*m[ 1 ][ 1 ]*m[ 2 ][ 0 ] ) + m[ 0 ][ 1 ]*m[ 1 ][ 2 ]*m[ 2 ][ 0 ] + m[ 0 ][ 2 ]*m[ 1 ][ 0 ]*m[ 2 ][ 1 ] - m[ 0 ][ 0 ]*m[ 1 ][ 2 ]*m[ 2 ][ 1 ] - m[ 0 ][ 1 ]*m[ 1 ][ 0 ]*m[ 2 ][ 2 ] + m[ 0 ][ 0 ]*m[ 1 ][ 1 ]*m[ 2 ][ 2 ]; } }; template inline Matrix3 < Float > MulT( const Matrix3< Float > &u, const Matrix3< Float > &vt ) { Matrix3 < Float > res; for ( int i = 0; i < 3; ++i ) for ( int j = 0; j < 3; ++j ) res.m[ i ][ j ] = u.m[ i ][ 0 ] * vt.m[ j ][ 0 ] + u.m[ i ][ 1 ] * vt.m[ j ][ 1 ] + u.m[ i ][ 2 ] * vt.m[ j ][ 2 ]; return res; } template Float OrthogonalityError( const Matrix3 &m ) { Float result = Replicate( 0.0f ); for ( int i = 0; i < 2; ++i ) { for ( int j = i + 1; j < 3; ++j ) { Float dot = m.m[ 0 ][ i ] * m.m[ 0 ][ j ] + m.m[ 1 ][ i ] * m.m[ 1 ][ j ] + m.m[ 2 ][ i ] * m.m[ 2 ][ j ]; result += dot * dot; } } return result; } template class DiagMatrix3 { public: Float m[ 3 ]; }; template class SymMatrix3 { public: enum Index_t { a00, a10, a11, a20, a21, a22, Count, a01 = a10, a02 = a20, a12 = a21 }; Float m[ 6 ]; Float &m00() { return m[ a00 ]; } Float &m01() { return m[ a01 ]; } Float &m02() { return m[ a02 ]; } Float &m11() { return m[ a11 ]; } Float &m12() { return m[ a12 ]; } Float &m22() { return m[ a22 ]; } Float OffDiagNorm()const { return m[ a01 ] * m[ a01 ] + m[ a21 ] * m[ a21 ] + m[ a02 ] * m[ a02 ]; } Float DiagNorm()const { return m[ a00 ] * m[ a00 ] + m[ a11 ] * m[ a11 ] + m[ a22 ] * m[ a22 ]; } }; template < typename Float > Matrix3< Float >::Matrix3( const SymMatrix3< Float > &other ) { m[ 0 ][ 0 ] = other.m[ other.a00 ]; m[ 0 ][ 1 ] = m[ 1 ][ 0 ] = other.m[ other.a01 ]; m[ 1 ][ 1 ] = other.m[ other.a11 ]; m[ 2 ][ 0 ] = m[ 0 ][ 2 ] = other.m[ other.a01 ]; m[ 2 ][ 1 ] = m[ 1 ][ 2 ] = other.m[ other.a01 ]; m[ 2 ][ 2 ] = other.m[ other.a22 ]; } template class SinCos { public: Float s, c; SinCos() {} SinCos( const Float &_c, const Float &_s ) : c( _c ), s( _s ) {} SinCos< Float> DoubleAngle()const { SinCos< Float> res; res.s = Replicate( 2.0f ) * s * c; res.c = c * c - s * s; return res; } }; template class Quaternion { public: Float x, y, z, w; void SetIdentity() { x = y = z = Replicate( 0.0f ); w = Replicate( 1.0f ); } Quaternion operator * ( const Float &f )const { Quaternion< Float > res; res.x = x * f; res.y = y * f; res.z = z * f; res.w = w * f; return res; } Float LengthSqr() const { return x * x + y * y + z * z + w * w; } }; template Matrix3 QuaternionMatrix( const Quaternion &q ) { Matrix3 matrix; const Float one = Replicate( 1.0f ), two = Replicate( 2.0f ); matrix.m[ 0 ][ 0 ] = one - two * q.y * q.y - two * q.z * q.z; matrix.m[ 1 ][ 0 ] = two * q.x * q.y + two * q.w * q.z; matrix.m[ 2 ][ 0 ] = two * q.x * q.z - two * q.w * q.y; matrix.m[ 0 ][ 1 ] = two * q.x * q.y - two * q.w * q.z; matrix.m[ 1 ][ 1 ] = one - two * q.x * q.x - two * q.z * q.z; matrix.m[ 2 ][ 1 ] = two * q.y * q.z + two * q.w * q.x; matrix.m[ 0 ][ 2 ] = two * q.x * q.z + two * q.w * q.y; matrix.m[ 1 ][ 2 ] = two * q.y * q.z - two * q.w * q.x; matrix.m[ 2 ][ 2 ] = one - two * q.x * q.x - two * q.y * q.y; return matrix; } template inline SymMatrix3< Float > AtA( const Matrix3< Float > &a ) { SymMatrix3< Float > res; res.m[ res.a00 ] = a.AtA( 0, 0 ); res.m[ res.a10 ] = a.AtA( 1, 0 ); res.m[ res.a11 ] = a.AtA( 1, 1 ); res.m[ res.a20 ] = a.AtA( 2, 0 ); res.m[ res.a21 ] = a.AtA( 2, 1 ); res.m[ res.a22 ] = a.AtA( 2, 2 ); return res; } template inline SymMatrix3< Float > QtAQ( const Matrix3< Float > &q, const SymMatrix3< Float > &a ) { SymMatrix3< Float > res; res.m[ res.a00 ] = q.m[ 0 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 0 ] + a.m[ a.a01 ] * q.m[ 1 ][ 0 ] + a.m[ a.a02 ] * q.m[ 2 ][ 0 ] ) + q.m[ 1 ][ 0 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 0 ] + a.m[ a.a11 ] * q.m[ 1 ][ 0 ] + a.m[ a.a12 ] * q.m[ 2 ][ 0 ] ) + q.m[ 2 ][ 0 ] * ( a.m[ a.a02 ] * q.m[ 0 ][ 0 ] + a.m[ a.a12 ] * q.m[ 1 ][ 0 ] + a.m[ a.a22 ] * q.m[ 2 ][ 0 ] ); res.m[ res.a01 ] = q.m[ 0 ][ 1 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 0 ] + a.m[ a.a01 ] * q.m[ 1 ][ 0 ] + a.m[ a.a02 ] * q.m[ 2 ][ 0 ] ) + q.m[ 1 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 0 ] + a.m[ a.a11 ] * q.m[ 1 ][ 0 ] + a.m[ a.a12 ] * q.m[ 2 ][ 0 ] ) + ( a.m[ a.a02 ] * q.m[ 0 ][ 0 ] + a.m[ a.a12 ] * q.m[ 1 ][ 0 ] + a.m[ a.a22 ] * q.m[ 2 ][ 0 ] ) * q.m[ 2 ][ 1 ]; res.m[ res.a02 ] = q.m[ 0 ][ 2 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 0 ] + a.m[ a.a01 ] * q.m[ 1 ][ 0 ] + a.m[ a.a02 ] * q.m[ 2 ][ 0 ] ) + q.m[ 1 ][ 2 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 0 ] + a.m[ a.a11 ] * q.m[ 1 ][ 0 ] + a.m[ a.a12 ] * q.m[ 2 ][ 0 ] ) + ( a.m[ a.a02 ] * q.m[ 0 ][ 0 ] + a.m[ a.a12 ] * q.m[ 1 ][ 0 ] + a.m[ a.a22 ] * q.m[ 2 ][ 0 ] ) * q.m[ 2 ][ 2 ]; res.m[ res.a11 ] = q.m[ 0 ][ 1 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 1 ] + a.m[ a.a01 ] * q.m[ 1 ][ 1 ] + a.m[ a.a02 ] * q.m[ 2 ][ 1 ] ) + q.m[ 1 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 1 ] + a.m[ a.a11 ] * q.m[ 1 ][ 1 ] + a.m[ a.a12 ] * q.m[ 2 ][ 1 ] ) + q.m[ 2 ][ 1 ] * ( a.m[ a.a02 ] * q.m[ 0 ][ 1 ] + a.m[ a.a12 ] * q.m[ 1 ][ 1 ] + a.m[ a.a22 ] * q.m[ 2 ][ 1 ] ); res.m[ res.a12 ] = q.m[ 0 ][ 2 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 1 ] + a.m[ a.a01 ] * q.m[ 1 ][ 1 ] + a.m[ a.a02 ] * q.m[ 2 ][ 1 ] ) + q.m[ 1 ][ 2 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 1 ] + a.m[ a.a11 ] * q.m[ 1 ][ 1 ] + a.m[ a.a12 ] * q.m[ 2 ][ 1 ] ) + ( a.m[ a.a02 ] * q.m[ 0 ][ 1 ] + a.m[ a.a12 ] * q.m[ 1 ][ 1 ] + a.m[ a.a22 ] * q.m[ 2 ][ 1 ] ) * q.m[ 2 ][ 2 ]; res.m[ res.a22 ] = q.m[ 0 ][ 2 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 2 ] + a.m[ a.a01 ] * q.m[ 1 ][ 2 ] + a.m[ a.a02 ] * q.m[ 2 ][ 2 ] ) + q.m[ 1 ][ 2 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 2 ] + a.m[ a.a11 ] * q.m[ 1 ][ 2 ] + a.m[ a.a12 ] * q.m[ 2 ][ 2 ] ) + q.m[ 2 ][ 2 ] * ( a.m[ a.a02 ] * q.m[ 0 ][ 2 ] + a.m[ a.a12 ] * q.m[ 1 ][ 2 ] + a.m[ a.a22 ] * q.m[ 2 ][ 2 ] ); return res; } template inline SymMatrix3< Float > QAQt( const Matrix3< Float > &q, const SymMatrix3< Float > &a ) { SymMatrix3< Float > res; res.m[ res.a00 ] = q.m[ 0 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 0 ] + a.m[ a.a01 ] * q.m[ 0 ][ 1 ] + a.m[ a.a02 ] * q.m[ 0 ][ 2 ] ) + q.m[ 0 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 0 ] + a.m[ a.a11 ] * q.m[ 0 ][ 1 ] + a.m[ a.a12 ] * q.m[ 0 ][ 2 ] ) + q.m[ 0 ][ 2 ] * ( a.m[ a.a02 ] * q.m[ 0 ][ 0 ] + a.m[ a.a12 ] * q.m[ 0 ][ 1 ] + a.m[ a.a22 ] * q.m[ 0 ][ 2 ] ); res.m[ res.a01 ] = q.m[ 1 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 0 ] + a.m[ a.a01 ] * q.m[ 0 ][ 1 ] + a.m[ a.a02 ] * q.m[ 0 ][ 2 ] ) + q.m[ 1 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 0 ] + a.m[ a.a11 ] * q.m[ 0 ][ 1 ] + a.m[ a.a12 ] * q.m[ 0 ][ 2 ] ) + ( a.m[ a.a02 ] * q.m[ 0 ][ 0 ] + a.m[ a.a12 ] * q.m[ 0 ][ 1 ] + a.m[ a.a22 ] * q.m[ 0 ][ 2 ] ) * q.m[ 1 ][ 2 ]; res.m[ res.a02 ] = q.m[ 2 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 0 ][ 0 ] + a.m[ a.a01 ] * q.m[ 0 ][ 1 ] + a.m[ a.a02 ] * q.m[ 0 ][ 2 ] ) + q.m[ 2 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 0 ][ 0 ] + a.m[ a.a11 ] * q.m[ 0 ][ 1 ] + a.m[ a.a12 ] * q.m[ 0 ][ 2 ] ) + ( a.m[ a.a02 ] * q.m[ 0 ][ 0 ] + a.m[ a.a12 ] * q.m[ 0 ][ 1 ] + a.m[ a.a22 ] * q.m[ 0 ][ 2 ] ) * q.m[ 2 ][ 2 ]; res.m[ res.a11 ] = q.m[ 1 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 1 ][ 0 ] + a.m[ a.a01 ] * q.m[ 1 ][ 1 ] + a.m[ a.a02 ] * q.m[ 1 ][ 2 ] ) + q.m[ 1 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 1 ][ 0 ] + a.m[ a.a11 ] * q.m[ 1 ][ 1 ] + a.m[ a.a12 ] * q.m[ 1 ][ 2 ] ) + q.m[ 1 ][ 2 ] * ( a.m[ a.a02 ] * q.m[ 1 ][ 0 ] + a.m[ a.a12 ] * q.m[ 1 ][ 1 ] + a.m[ a.a22 ] * q.m[ 1 ][ 2 ] ); res.m[ res.a12 ] = q.m[ 2 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 1 ][ 0 ] + a.m[ a.a01 ] * q.m[ 1 ][ 1 ] + a.m[ a.a02 ] * q.m[ 1 ][ 2 ] ) + q.m[ 2 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 1 ][ 0 ] + a.m[ a.a11 ] * q.m[ 1 ][ 1 ] + a.m[ a.a12 ] * q.m[ 1 ][ 2 ] ) + ( a.m[ a.a02 ] * q.m[ 1 ][ 0 ] + a.m[ a.a12 ] * q.m[ 1 ][ 1 ] + a.m[ a.a22 ] * q.m[ 1 ][ 2 ] ) * q.m[ 2 ][ 2 ]; res.m[ res.a22 ] = q.m[ 2 ][ 0 ] * ( a.m[ a.a00 ] * q.m[ 2 ][ 0 ] + a.m[ a.a01 ] * q.m[ 2 ][ 1 ] + a.m[ a.a02 ] * q.m[ 2 ][ 2 ] ) + q.m[ 2 ][ 1 ] * ( a.m[ a.a01 ] * q.m[ 2 ][ 0 ] + a.m[ a.a11 ] * q.m[ 2 ][ 1 ] + a.m[ a.a12 ] * q.m[ 2 ][ 2 ] ) + q.m[ 2 ][ 2 ] * ( a.m[ a.a02 ] * q.m[ 2 ][ 0 ] + a.m[ a.a12 ] * q.m[ 2 ][ 1 ] + a.m[ a.a22 ] * q.m[ 2 ][ 2 ] ); return res; } template inline SymMatrix3< Float > QAQt( const Matrix3< Float > &q, const DiagMatrix3< Float > &a ) { SymMatrix3< Float > res; res.m[ res.a00 ] = q.m[ 0 ][ 0 ] * a.m[ 0 ] * q.m[ 0 ][ 0 ] + q.m[ 0 ][ 1 ] * a.m[ 1 ] * q.m[ 0 ][ 1 ] + q.m[ 0 ][ 2 ] * a.m[ 2 ] * q.m[ 0 ][ 2 ] ; res.m[ res.a01 ] = q.m[ 1 ][ 0 ] * ( a.m[ 0 ] * q.m[ 0 ][ 0 ]) + q.m[ 1 ][ 1 ] * ( a.m[ 1 ] * q.m[ 0 ][ 1 ]) + ( a.m[ 2 ] * q.m[ 0 ][ 2 ] ) * q.m[ 1 ][ 2 ]; res.m[ res.a02 ] = q.m[ 2 ][ 0 ] * ( a.m[ 0 ] * q.m[ 0 ][ 0 ]) + q.m[ 2 ][ 1 ] * ( a.m[ 1 ] * q.m[ 0 ][ 1 ] ) + ( a.m[ 2 ] * q.m[ 0 ][ 2 ] ) * q.m[ 2 ][ 2 ]; res.m[ res.a11 ] = q.m[ 1 ][ 0 ] * ( a.m[ 0 ] * q.m[ 1 ][ 0 ]) + q.m[ 1 ][ 1 ] * ( a.m[ 1 ] * q.m[ 1 ][ 1 ]) + q.m[ 1 ][ 2 ] * ( a.m[ 2 ] * q.m[ 1 ][ 2 ] ); res.m[ res.a12 ] = q.m[ 2 ][ 0 ] * ( a.m[ 0 ] * q.m[ 1 ][ 0 ]) + q.m[ 2 ][ 1 ] * ( a.m[ 1 ] * q.m[ 1 ][ 1 ] ) + ( a.m[ 2 ] * q.m[ 1 ][ 2 ] ) * q.m[ 2 ][ 2 ]; res.m[ res.a22 ] = q.m[ 2 ][ 0 ] * ( a.m[ 0 ] * q.m[ 2 ][ 0 ] ) + q.m[ 2 ][ 1 ] * ( a.m[ 1 ] * q.m[ 2 ][ 1 ] ) + q.m[ 2 ][ 2 ] * ( a.m[ 2 ] * q.m[ 2 ][ 2 ] ); return res; } template void PerformGivensRotation2x2( const SinCos &res, Float &a11, Float &a12, Float &a22 ) { const Float two = Replicate( 2.0f ); Float cc = res.c * res.c, ss = res.s * res.s, cs = res.c * res.s; Float b11 = cc * a11 + two * cs * a12 + ss * a22; Float b12 = cs * ( a22 - a11 ) + ( cc - ss ) * a12; Float b22 = ss * a11 - two * cs * a12 + cc * a22; a11 = b11; a12 = b12; a22 = b22; } template void UnperformGivensRotation3x3( const SinCos &r, Float &a00, Float &a01, Float &a11, Float &a02, Float &a12 ) { const Float two = Replicate( 2.0f ); Float b00 = a00 * r.c * r.c - r.s * ( two * a01 * r.c - a11 * r.s ); Float b01 = r.c*( a01 * r.c + a00 * r.s ) - r.s * ( a11 * r.c + a01 * r.s ); Float b11 = a11 * r.c * r.c + r.s * ( two * a01 * r.c + a00 * r.s ); Float b02 = a02 *r.c - a12 * r.s; Float b12 = a12 *r.c + a02 * r.s; a00 = b00; a01 = b01; a11 = b11; a02 = b02; a12 = b12; } template void PerformGivensRotation3x3( const SinCos &r, Float &a00, Float &a01, Float &a11, Float &a02, Float &a12 ) { const Float two = Replicate( 2.0f ); Float b00 = a00 * r.c * r.c + r.s * ( two * a01 * r.c + a11 * r.s ); Float b01 = r.c*( a01 *r.c - a00 * r.s ) + r.s * ( a11 *r.c - a01 * r.s ); Float b11 = a11 * r.c *r.c - r.s * ( two * a01 * r.c - a00 * r.s ); Float b02 = a02 *r.c + a12 * r.s; Float b12 = a12 *r.c - a02 * r.s; a00 = b00; a01 = b01; a11 = b11; a02 = b02; a12 = b12; } inline SinCos< float > ComputeGivensRotation( float a11, float a12, float a22 ) { float theta = fabsf( a11 - a22 ) > 1e-6f ? 0.5f * atanf( 2 * a12 / ( a11 - a22 ) ) : 3.14159265358979323846f / 4; SinCos< float >res( cosf( theta ), sinf( theta ) ); #ifdef _DEBUG PerformGivensRotation2x2( res, a11, a12, a22 ); Assert( fabsf( a12 ) < 0.001f * ( 1 + fabsf( a11 ) + fabsf( a22 ) ) ); #endif return res; } template inline SinCos< Float> ApproximateGivensRotation( const Float & a11, const Float & a12, const Float & a22 ) { const Float two = Replicate( 2.0f ); Float ch = two * ( a11 - a22 ); Float sh = a12; typename FloatTraits::Bool b = CmpLt( Replicate( 5.82842712474619f ) * sh*sh, ch*ch ); Float r2 = ch*ch + sh *sh; typename FloatTraits::Bool bZero = CmpLt( r2, Replicate( 1e-12f ) ); Float omega = RsqrtEst( r2 ); SinCosres; res.s = Select( Replicate( 0.3826834323650897717284599840304f ), omega * sh, b ); res.c = Select( Replicate( 0.92387953251128675612818318939679f ), omega * ch, b ); res.s = Select( res.s, Replicate( 0.0f ), bZero ); // todo: replace with And res.c = Select( res.c, Replicate( 1.0f ), bZero ); return res; } template void PerformGivensRotationQuaternion( const SinCos &res, Float &x, Float &y, Float &z, Float &w ) { //const Float two = Replicate( 2.0f ); Float xNew = res.c * x + res.s * w, yNew = res.c * y + res.s * z, zNew = res.c * z - res.s * y, wNew = res.c * w - res.s * x; x = xNew; y = yNew; z = zNew; w = wNew; } template class SvdIterator { public: SvdIterator(){} Quaternion < Float > q; SymMatrix3 ata; void Init( const Matrix3 a ) { q.SetIdentity(); ata = AtA( a ); } void Iterate( int nIterations, float flEpsilon = 0.0f ) { SinCos< Float> r; //SymMatrix3 inv0 = QAQt( QuaternionMatrix( q ), ata ), origAta = AtA( a ); for ( int i = 0; i < nIterations; ++i ) { r = ApproximateGivensRotation( ata.m[ ata.a00 ], ata.m[ ata.a10 ], ata.m[ ata.a11 ] ); Float sumErrors = r.s * r.s; PerformGivensRotation3x3( r.DoubleAngle(), ata.m[ ata.a00 ], ata.m[ ata.a10 ], ata.m[ ata.a11 ], ata.m[ ata.a20 ], ata.m[ ata.a21 ] ); PerformGivensRotationQuaternion( r, q.z, q.x, q.y, q.w ); //SymMatrix3 inv1 = QAQt( QuaternionMatrix( q ), ata ); r = ApproximateGivensRotation( ata.m[ ata.a11 ], ata.m[ ata.a21 ], ata.m[ ata.a22 ] ); sumErrors += r.s * r.s; PerformGivensRotation3x3( r.DoubleAngle(), ata.m[ ata.a11 ], ata.m[ ata.a21 ], ata.m[ ata.a22 ], ata.m[ ata.a01 ], ata.m[ ata.a02 ] ); PerformGivensRotationQuaternion( r, q.x, q.y, q.z, q.w ); //SymMatrix3 inv2 = QAQt( QuaternionMatrix( q ), ata ); r = ApproximateGivensRotation( ata.m[ ata.a22 ], ata.m[ ata.a20 ], ata.m[ ata.a00 ] ); sumErrors += r.s * r.s; PerformGivensRotation3x3( r.DoubleAngle(), ata.m[ ata.a22 ], ata.m[ ata.a02 ], ata.m[ ata.a00 ], ata.m[ ata.a12 ], ata.m[ ata.a10 ] ); PerformGivensRotationQuaternion( r, q.y, q.z, q.x, q.w ); //SymMatrix3 inv3 = QAQt( QuaternionMatrix( q ), ata ); if ( AllLe( sumErrors, Replicate( flEpsilon ) ) ) break; // early out } } Matrix3< Float > ComputeV()const { return QuaternionMatrix( q * Rsqrt( q.LengthSqr() ) ); } }; inline float PseudoInverse( float fl ) { return fabsf( fl ) < FLT_EPSILON ? 0 : 1.0f / fl; } inline SymMatrix3< float > PseudoInverse( const SymMatrix3< float > &cov ) { SvdIterator< float > si; si.q.SetIdentity(); si.ata = cov; si.Iterate( 5 ); DiagMatrix3< float > pseudoInverseDiag; pseudoInverseDiag.m[ 0 ] = PseudoInverse( si.ata.m00() ); pseudoInverseDiag.m[ 1 ] = PseudoInverse( si.ata.m11() ); pseudoInverseDiag.m[ 2 ] = PseudoInverse( si.ata.m22() ); return QAQt( si.ComputeV(), pseudoInverseDiag ); } }