summaryrefslogtreecommitdiff
path: root/thirdparty/bullet/LinearMath/btImplicitQRSVD.h
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/bullet/LinearMath/btImplicitQRSVD.h')
-rw-r--r--thirdparty/bullet/LinearMath/btImplicitQRSVD.h916
1 files changed, 0 insertions, 916 deletions
diff --git a/thirdparty/bullet/LinearMath/btImplicitQRSVD.h b/thirdparty/bullet/LinearMath/btImplicitQRSVD.h
deleted file mode 100644
index aaedc964f6..0000000000
--- a/thirdparty/bullet/LinearMath/btImplicitQRSVD.h
+++ /dev/null
@@ -1,916 +0,0 @@
-/**
- Bullet Continuous Collision Detection and Physics Library
- Copyright (c) 2019 Google Inc. http://bulletphysics.org
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it freely,
- subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
- Copyright (c) 2016 Theodore Gast, Chuyuan Fu, Chenfanfu Jiang, Joseph Teran
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- If the code is used in an article, the following paper shall be cited:
- @techreport{qrsvd:2016,
- title={Implicit-shifted Symmetric QR Singular Value Decomposition of 3x3 Matrices},
- author={Gast, Theodore and Fu, Chuyuan and Jiang, Chenfanfu and Teran, Joseph},
- year={2016},
- institution={University of California Los Angeles}
- }
-
- 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-**/
-
-#ifndef btImplicitQRSVD_h
-#define btImplicitQRSVD_h
-#include <limits>
-#include "btMatrix3x3.h"
-class btMatrix2x2
-{
-public:
- btScalar m_00, m_01, m_10, m_11;
- btMatrix2x2(): m_00(0), m_10(0), m_01(0), m_11(0)
- {
- }
- btMatrix2x2(const btMatrix2x2& other): m_00(other.m_00),m_01(other.m_01),m_10(other.m_10),m_11(other.m_11)
- {}
- btScalar& operator()(int i, int j)
- {
- if (i == 0 && j == 0)
- return m_00;
- if (i == 1 && j == 0)
- return m_10;
- if (i == 0 && j == 1)
- return m_01;
- if (i == 1 && j == 1)
- return m_11;
- btAssert(false);
- return m_00;
- }
- const btScalar& operator()(int i, int j) const
- {
- if (i == 0 && j == 0)
- return m_00;
- if (i == 1 && j == 0)
- return m_10;
- if (i == 0 && j == 1)
- return m_01;
- if (i == 1 && j == 1)
- return m_11;
- btAssert(false);
- return m_00;
- }
- void setIdentity()
- {
- m_00 = 1;
- m_11 = 1;
- m_01 = 0;
- m_10 = 0;
- }
-};
-
-static inline btScalar copySign(btScalar x, btScalar y) {
- if ((x < 0 && y > 0) || (x > 0 && y < 0))
- return -x;
- return x;
-}
-
-/**
- Class for givens rotation.
- Row rotation G*A corresponds to something like
- c -s 0
- ( s c 0 ) A
- 0 0 1
- Column rotation A G' corresponds to something like
- c -s 0
- A ( s c 0 )
- 0 0 1
-
- c and s are always computed so that
- ( c -s ) ( a ) = ( * )
- s c b ( 0 )
-
- Assume rowi<rowk.
- */
-
-class GivensRotation {
-public:
- int rowi;
- int rowk;
- btScalar c;
- btScalar s;
-
- inline GivensRotation(int rowi_in, int rowk_in)
- : rowi(rowi_in)
- , rowk(rowk_in)
- , c(1)
- , s(0)
- {
- }
-
- inline GivensRotation(btScalar a, btScalar b, int rowi_in, int rowk_in)
- : rowi(rowi_in)
- , rowk(rowk_in)
- {
- compute(a, b);
- }
-
- ~GivensRotation() {}
-
- inline void transposeInPlace()
- {
- s = -s;
- }
-
- /**
- Compute c and s from a and b so that
- ( c -s ) ( a ) = ( * )
- s c b ( 0 )
- */
- inline void compute(const btScalar a, const btScalar b)
- {
- btScalar d = a * a + b * b;
- c = 1;
- s = 0;
- if (d > SIMD_EPSILON) {
- btScalar sqrtd = btSqrt(d);
- if (sqrtd>SIMD_EPSILON)
- {
- btScalar t = btScalar(1.0)/sqrtd;
- c = a * t;
- s = -b * t;
- }
- }
- }
-
- /**
- This function computes c and s so that
- ( c -s ) ( a ) = ( 0 )
- s c b ( * )
- */
- inline void computeUnconventional(const btScalar a, const btScalar b)
- {
- btScalar d = a * a + b * b;
- c = 0;
- s = 1;
- if (d > SIMD_EPSILON) {
- btScalar t = btScalar(1.0)/btSqrt(d);
- s = a * t;
- c = b * t;
- }
- }
- /**
- Fill the R with the entries of this rotation
- */
- inline void fill(const btMatrix3x3& R) const
- {
- btMatrix3x3& A = const_cast<btMatrix3x3&>(R);
- A.setIdentity();
- A[rowi][rowi] = c;
- A[rowk][rowi] = -s;
- A[rowi][rowk] = s;
- A[rowk][rowk] = c;
- }
-
- inline void fill(const btMatrix2x2& R) const
- {
- btMatrix2x2& A = const_cast<btMatrix2x2&>(R);
- A(rowi,rowi) = c;
- A(rowk,rowi) = -s;
- A(rowi,rowk) = s;
- A(rowk,rowk) = c;
- }
-
- /**
- This function does something like
- c -s 0
- ( s c 0 ) A -> A
- 0 0 1
- It only affects row i and row k of A.
- */
- inline void rowRotation(btMatrix3x3& A) const
- {
- for (int j = 0; j < 3; j++) {
- btScalar tau1 = A[rowi][j];
- btScalar tau2 = A[rowk][j];
- A[rowi][j] = c * tau1 - s * tau2;
- A[rowk][j] = s * tau1 + c * tau2;
- }
- }
- inline void rowRotation(btMatrix2x2& A) const
- {
- for (int j = 0; j < 2; j++) {
- btScalar tau1 = A(rowi,j);
- btScalar tau2 = A(rowk,j);
- A(rowi,j) = c * tau1 - s * tau2;
- A(rowk,j) = s * tau1 + c * tau2;
- }
- }
-
- /**
- This function does something like
- c s 0
- A ( -s c 0 ) -> A
- 0 0 1
- It only affects column i and column k of A.
- */
- inline void columnRotation(btMatrix3x3& A) const
- {
- for (int j = 0; j < 3; j++) {
- btScalar tau1 = A[j][rowi];
- btScalar tau2 = A[j][rowk];
- A[j][rowi] = c * tau1 - s * tau2;
- A[j][rowk] = s * tau1 + c * tau2;
- }
- }
- inline void columnRotation(btMatrix2x2& A) const
- {
- for (int j = 0; j < 2; j++) {
- btScalar tau1 = A(j,rowi);
- btScalar tau2 = A(j,rowk);
- A(j,rowi) = c * tau1 - s * tau2;
- A(j,rowk) = s * tau1 + c * tau2;
- }
- }
-
- /**
- Multiply givens must be for same row and column
- **/
- inline void operator*=(const GivensRotation& A)
- {
- btScalar new_c = c * A.c - s * A.s;
- btScalar new_s = s * A.c + c * A.s;
- c = new_c;
- s = new_s;
- }
-
- /**
- Multiply givens must be for same row and column
- **/
- inline GivensRotation operator*(const GivensRotation& A) const
- {
- GivensRotation r(*this);
- r *= A;
- return r;
- }
-};
-
-/**
- \brief zero chasing the 3X3 matrix to bidiagonal form
- original form of H: x x 0
- x x x
- 0 0 x
- after zero chase:
- x x 0
- 0 x x
- 0 0 x
- */
-inline void zeroChase(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
-{
-
- /**
- Reduce H to of form
- x x +
- 0 x x
- 0 0 x
- */
- GivensRotation r1(H[0][0], H[1][0], 0, 1);
- /**
- Reduce H to of form
- x x 0
- 0 x x
- 0 + x
- Can calculate r2 without multiplying by r1 since both entries are in first two
- rows thus no need to divide by sqrt(a^2+b^2)
- */
- GivensRotation r2(1, 2);
- if (H[1][0] != 0)
- r2.compute(H[0][0] * H[0][1] + H[1][0] * H[1][1], H[0][0] * H[0][2] + H[1][0] * H[1][2]);
- else
- r2.compute(H[0][1], H[0][2]);
-
- r1.rowRotation(H);
-
- /* GivensRotation<T> r2(H(0, 1), H(0, 2), 1, 2); */
- r2.columnRotation(H);
- r2.columnRotation(V);
-
- /**
- Reduce H to of form
- x x 0
- 0 x x
- 0 0 x
- */
- GivensRotation r3(H[1][1], H[2][1], 1, 2);
- r3.rowRotation(H);
-
- // Save this till end for better cache coherency
- // r1.rowRotation(u_transpose);
- // r3.rowRotation(u_transpose);
- r1.columnRotation(U);
- r3.columnRotation(U);
-}
-
-/**
- \brief make a 3X3 matrix to upper bidiagonal form
- original form of H: x x x
- x x x
- x x x
- after zero chase:
- x x 0
- 0 x x
- 0 0 x
- */
-inline void makeUpperBidiag(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
-{
- U.setIdentity();
- V.setIdentity();
-
- /**
- Reduce H to of form
- x x x
- x x x
- 0 x x
- */
-
- GivensRotation r(H[1][0], H[2][0], 1, 2);
- r.rowRotation(H);
- // r.rowRotation(u_transpose);
- r.columnRotation(U);
- // zeroChase(H, u_transpose, V);
- zeroChase(H, U, V);
-}
-
-/**
- \brief make a 3X3 matrix to lambda shape
- original form of H: x x x
- * x x x
- * x x x
- after :
- * x 0 0
- * x x 0
- * x 0 x
- */
-inline void makeLambdaShape(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
-{
- U.setIdentity();
- V.setIdentity();
-
- /**
- Reduce H to of form
- * x x 0
- * x x x
- * x x x
- */
-
- GivensRotation r1(H[0][1], H[0][2], 1, 2);
- r1.columnRotation(H);
- r1.columnRotation(V);
-
- /**
- Reduce H to of form
- * x x 0
- * x x 0
- * x x x
- */
-
- r1.computeUnconventional(H[1][2], H[2][2]);
- r1.rowRotation(H);
- r1.columnRotation(U);
-
- /**
- Reduce H to of form
- * x x 0
- * x x 0
- * x 0 x
- */
-
- GivensRotation r2(H[2][0], H[2][1], 0, 1);
- r2.columnRotation(H);
- r2.columnRotation(V);
-
- /**
- Reduce H to of form
- * x 0 0
- * x x 0
- * x 0 x
- */
- r2.computeUnconventional(H[0][1], H[1][1]);
- r2.rowRotation(H);
- r2.columnRotation(U);
-}
-
-/**
- \brief 2x2 polar decomposition.
- \param[in] A matrix.
- \param[out] R Robustly a rotation matrix.
- \param[out] S_Sym Symmetric. Whole matrix is stored
-
- Polar guarantees negative sign is on the small magnitude singular value.
- S is guaranteed to be the closest one to identity.
- R is guaranteed to be the closest rotation to A.
- */
-inline void polarDecomposition(const btMatrix2x2& A,
- GivensRotation& R,
- const btMatrix2x2& S_Sym)
-{
- btScalar a = (A(0, 0) + A(1, 1)), b = (A(1, 0) - A(0, 1));
- btScalar denominator = btSqrt(a*a+b*b);
- R.c = (btScalar)1;
- R.s = (btScalar)0;
- if (denominator > SIMD_EPSILON) {
- /*
- No need to use a tolerance here because x(0) and x(1) always have
- smaller magnitude then denominator, therefore overflow never happens.
- In Bullet, we use a tolerance anyway.
- */
- R.c = a / denominator;
- R.s = -b / denominator;
- }
- btMatrix2x2& S = const_cast<btMatrix2x2&>(S_Sym);
- S = A;
- R.rowRotation(S);
-}
-
-inline void polarDecomposition(const btMatrix2x2& A,
- const btMatrix2x2& R,
- const btMatrix2x2& S_Sym)
-{
- GivensRotation r(0, 1);
- polarDecomposition(A, r, S_Sym);
- r.fill(R);
-}
-
-/**
- \brief 2x2 SVD (singular value decomposition) A=USV'
- \param[in] A Input matrix.
- \param[out] U Robustly a rotation matrix in Givens form
- \param[out] Sigma matrix of singular values sorted with decreasing magnitude. The second one can be negative.
- \param[out] V Robustly a rotation matrix in Givens form
- */
-inline void singularValueDecomposition(
- const btMatrix2x2& A,
- GivensRotation& U,
- const btMatrix2x2& Sigma,
- GivensRotation& V,
- const btScalar tol = 64 * std::numeric_limits<btScalar>::epsilon())
-{
- btMatrix2x2& sigma = const_cast<btMatrix2x2&>(Sigma);
- sigma.setIdentity();
- btMatrix2x2 S_Sym;
- polarDecomposition(A, U, S_Sym);
- btScalar cosine, sine;
- btScalar x = S_Sym(0, 0);
- btScalar y = S_Sym(0, 1);
- btScalar z = S_Sym(1, 1);
- if (y == 0) {
- // S is already diagonal
- cosine = 1;
- sine = 0;
- sigma(0,0) = x;
- sigma(1,1) = z;
- }
- else {
- btScalar tau = 0.5 * (x - z);
- btScalar val = tau * tau + y * y;
- if (val > SIMD_EPSILON)
- {
- btScalar w = btSqrt(val);
- // w > y > 0
- btScalar t;
- if (tau > 0) {
- // tau + w > w > y > 0 ==> division is safe
- t = y / (tau + w);
- }
- else {
- // tau - w < -w < -y < 0 ==> division is safe
- t = y / (tau - w);
- }
- cosine = btScalar(1) / btSqrt(t * t + btScalar(1));
- sine = -t * cosine;
- /*
- V = [cosine -sine; sine cosine]
- Sigma = V'SV. Only compute the diagonals for efficiency.
- Also utilize symmetry of S and don't form V yet.
- */
- btScalar c2 = cosine * cosine;
- btScalar csy = 2 * cosine * sine * y;
- btScalar s2 = sine * sine;
- sigma(0,0) = c2 * x - csy + s2 * z;
- sigma(1,1) = s2 * x + csy + c2 * z;
- } else
- {
- cosine = 1;
- sine = 0;
- sigma(0,0) = x;
- sigma(1,1) = z;
- }
- }
-
- // Sorting
- // Polar already guarantees negative sign is on the small magnitude singular value.
- if (sigma(0,0) < sigma(1,1)) {
- std::swap(sigma(0,0), sigma(1,1));
- V.c = -sine;
- V.s = cosine;
- }
- else {
- V.c = cosine;
- V.s = sine;
- }
- U *= V;
-}
-
-/**
- \brief 2x2 SVD (singular value decomposition) A=USV'
- \param[in] A Input matrix.
- \param[out] U Robustly a rotation matrix.
- \param[out] Sigma Vector of singular values sorted with decreasing magnitude. The second one can be negative.
- \param[out] V Robustly a rotation matrix.
- */
-inline void singularValueDecomposition(
- const btMatrix2x2& A,
- const btMatrix2x2& U,
- const btMatrix2x2& Sigma,
- const btMatrix2x2& V,
- const btScalar tol = 64 * std::numeric_limits<btScalar>::epsilon())
-{
- GivensRotation gv(0, 1);
- GivensRotation gu(0, 1);
- singularValueDecomposition(A, gu, Sigma, gv);
-
- gu.fill(U);
- gv.fill(V);
-}
-
-/**
- \brief compute wilkinsonShift of the block
- a1 b1
- b1 a2
- based on the wilkinsonShift formula
- mu = c + d - sign (d) \ sqrt (d*d + b*b), where d = (a-c)/2
-
- */
-inline btScalar wilkinsonShift(const btScalar a1, const btScalar b1, const btScalar a2)
-{
- btScalar d = (btScalar)0.5 * (a1 - a2);
- btScalar bs = b1 * b1;
- btScalar val = d * d + bs;
- if (val>SIMD_EPSILON)
- {
- btScalar denom = btFabs(d) + btSqrt(val);
-
- btScalar mu = a2 - copySign(bs / (denom), d);
- // T mu = a2 - bs / ( d + sign_d*sqrt (d*d + bs));
- return mu;
- }
- return a2;
-}
-
-/**
- \brief Helper function of 3X3 SVD for processing 2X2 SVD
- */
-template <int t>
-inline void process(btMatrix3x3& B, btMatrix3x3& U, btVector3& sigma, btMatrix3x3& V)
-{
- int other = (t == 1) ? 0 : 2;
- GivensRotation u(0, 1);
- GivensRotation v(0, 1);
- sigma[other] = B[other][other];
-
- btMatrix2x2 B_sub, sigma_sub;
- if (t == 0)
- {
- B_sub.m_00 = B[0][0];
- B_sub.m_10 = B[1][0];
- B_sub.m_01 = B[0][1];
- B_sub.m_11 = B[1][1];
- sigma_sub.m_00 = sigma[0];
- sigma_sub.m_11 = sigma[1];
-// singularValueDecomposition(B.template block<2, 2>(t, t), u, sigma.template block<2, 1>(t, 0), v);
- singularValueDecomposition(B_sub, u, sigma_sub, v);
- B[0][0] = B_sub.m_00;
- B[1][0] = B_sub.m_10;
- B[0][1] = B_sub.m_01;
- B[1][1] = B_sub.m_11;
- sigma[0] = sigma_sub.m_00;
- sigma[1] = sigma_sub.m_11;
- }
- else
- {
- B_sub.m_00 = B[1][1];
- B_sub.m_10 = B[2][1];
- B_sub.m_01 = B[1][2];
- B_sub.m_11 = B[2][2];
- sigma_sub.m_00 = sigma[1];
- sigma_sub.m_11 = sigma[2];
- // singularValueDecomposition(B.template block<2, 2>(t, t), u, sigma.template block<2, 1>(t, 0), v);
- singularValueDecomposition(B_sub, u, sigma_sub, v);
- B[1][1] = B_sub.m_00;
- B[2][1] = B_sub.m_10;
- B[1][2] = B_sub.m_01;
- B[2][2] = B_sub.m_11;
- sigma[1] = sigma_sub.m_00;
- sigma[2] = sigma_sub.m_11;
- }
- u.rowi += t;
- u.rowk += t;
- v.rowi += t;
- v.rowk += t;
- u.columnRotation(U);
- v.columnRotation(V);
-}
-
-/**
- \brief Helper function of 3X3 SVD for flipping signs due to flipping signs of sigma
- */
-inline void flipSign(int i, btMatrix3x3& U, btVector3& sigma)
-{
- sigma[i] = -sigma[i];
- U[0][i] = -U[0][i];
- U[1][i] = -U[1][i];
- U[2][i] = -U[2][i];
-}
-
-inline void flipSign(int i, btMatrix3x3& U)
-{
- U[0][i] = -U[0][i];
- U[1][i] = -U[1][i];
- U[2][i] = -U[2][i];
-}
-
-inline void swapCol(btMatrix3x3& A, int i, int j)
-{
- for (int d = 0; d < 3; ++d)
- std::swap(A[d][i], A[d][j]);
-}
-/**
- \brief Helper function of 3X3 SVD for sorting singular values
- */
-inline void sort(btMatrix3x3& U, btVector3& sigma, btMatrix3x3& V, int t)
-{
- if (t == 0)
- {
- // Case: sigma(0) > |sigma(1)| >= |sigma(2)|
- if (btFabs(sigma[1]) >= btFabs(sigma[2])) {
- if (sigma[1] < 0) {
- flipSign(1, U, sigma);
- flipSign(2, U, sigma);
- }
- return;
- }
-
- //fix sign of sigma for both cases
- if (sigma[2] < 0) {
- flipSign(1, U, sigma);
- flipSign(2, U, sigma);
- }
-
- //swap sigma(1) and sigma(2) for both cases
- std::swap(sigma[1], sigma[2]);
- // swap the col 1 and col 2 for U,V
- swapCol(U,1,2);
- swapCol(V,1,2);
-
- // Case: |sigma(2)| >= sigma(0) > |simga(1)|
- if (sigma[1] > sigma[0]) {
- std::swap(sigma[0], sigma[1]);
- swapCol(U,0,1);
- swapCol(V,0,1);
- }
-
- // Case: sigma(0) >= |sigma(2)| > |simga(1)|
- else {
- flipSign(2, U);
- flipSign(2, V);
- }
- }
- else if (t == 1)
- {
- // Case: |sigma(0)| >= sigma(1) > |sigma(2)|
- if (btFabs(sigma[0]) >= sigma[1]) {
- if (sigma[0] < 0) {
- flipSign(0, U, sigma);
- flipSign(2, U, sigma);
- }
- return;
- }
-
- //swap sigma(0) and sigma(1) for both cases
- std::swap(sigma[0], sigma[1]);
- swapCol(U, 0, 1);
- swapCol(V, 0, 1);
-
- // Case: sigma(1) > |sigma(2)| >= |sigma(0)|
- if (btFabs(sigma[1]) < btFabs(sigma[2])) {
- std::swap(sigma[1], sigma[2]);
- swapCol(U, 1, 2);
- swapCol(V, 1, 2);
- }
-
- // Case: sigma(1) >= |sigma(0)| > |sigma(2)|
- else {
- flipSign(1, U);
- flipSign(1, V);
- }
-
- // fix sign for both cases
- if (sigma[1] < 0) {
- flipSign(1, U, sigma);
- flipSign(2, U, sigma);
- }
- }
-}
-
-/**
- \brief 3X3 SVD (singular value decomposition) A=USV'
- \param[in] A Input matrix.
- \param[out] U is a rotation matrix.
- \param[out] sigma Diagonal matrix, sorted with decreasing magnitude. The third one can be negative.
- \param[out] V is a rotation matrix.
- */
-inline int singularValueDecomposition(const btMatrix3x3& A,
- btMatrix3x3& U,
- btVector3& sigma,
- btMatrix3x3& V,
- btScalar tol = 128*std::numeric_limits<btScalar>::epsilon())
-{
-// using std::fabs;
- btMatrix3x3 B = A;
- U.setIdentity();
- V.setIdentity();
-
- makeUpperBidiag(B, U, V);
-
- int count = 0;
- btScalar mu = (btScalar)0;
- GivensRotation r(0, 1);
-
- btScalar alpha_1 = B[0][0];
- btScalar beta_1 = B[0][1];
- btScalar alpha_2 = B[1][1];
- btScalar alpha_3 = B[2][2];
- btScalar beta_2 = B[1][2];
- btScalar gamma_1 = alpha_1 * beta_1;
- btScalar gamma_2 = alpha_2 * beta_2;
- btScalar val = alpha_1 * alpha_1 + alpha_2 * alpha_2 + alpha_3 * alpha_3 + beta_1 * beta_1 + beta_2 * beta_2;
- if (val > SIMD_EPSILON)
- {
- tol *= btMax((btScalar)0.5 * btSqrt(val), (btScalar)1);
- }
- /**
- Do implicit shift QR until A^T A is block diagonal
- */
- int max_count = 100;
-
- while (btFabs(beta_2) > tol && btFabs(beta_1) > tol
- && btFabs(alpha_1) > tol && btFabs(alpha_2) > tol
- && btFabs(alpha_3) > tol
- && count < max_count) {
- mu = wilkinsonShift(alpha_2 * alpha_2 + beta_1 * beta_1, gamma_2, alpha_3 * alpha_3 + beta_2 * beta_2);
-
- r.compute(alpha_1 * alpha_1 - mu, gamma_1);
- r.columnRotation(B);
-
- r.columnRotation(V);
- zeroChase(B, U, V);
-
- alpha_1 = B[0][0];
- beta_1 = B[0][1];
- alpha_2 = B[1][1];
- alpha_3 = B[2][2];
- beta_2 = B[1][2];
- gamma_1 = alpha_1 * beta_1;
- gamma_2 = alpha_2 * beta_2;
- count++;
- }
- /**
- Handle the cases of one of the alphas and betas being 0
- Sorted by ease of handling and then frequency
- of occurrence
-
- If B is of form
- x x 0
- 0 x 0
- 0 0 x
- */
- if (btFabs(beta_2) <= tol) {
- process<0>(B, U, sigma, V);
- sort(U, sigma, V,0);
- }
- /**
- If B is of form
- x 0 0
- 0 x x
- 0 0 x
- */
- else if (btFabs(beta_1) <= tol) {
- process<1>(B, U, sigma, V);
- sort(U, sigma, V,1);
- }
- /**
- If B is of form
- x x 0
- 0 0 x
- 0 0 x
- */
- else if (btFabs(alpha_2) <= tol) {
- /**
- Reduce B to
- x x 0
- 0 0 0
- 0 0 x
- */
- GivensRotation r1(1, 2);
- r1.computeUnconventional(B[1][2], B[2][2]);
- r1.rowRotation(B);
- r1.columnRotation(U);
-
- process<0>(B, U, sigma, V);
- sort(U, sigma, V, 0);
- }
- /**
- If B is of form
- x x 0
- 0 x x
- 0 0 0
- */
- else if (btFabs(alpha_3) <= tol) {
- /**
- Reduce B to
- x x +
- 0 x 0
- 0 0 0
- */
- GivensRotation r1(1, 2);
- r1.compute(B[1][1], B[1][2]);
- r1.columnRotation(B);
- r1.columnRotation(V);
- /**
- Reduce B to
- x x 0
- + x 0
- 0 0 0
- */
- GivensRotation r2(0, 2);
- r2.compute(B[0][0], B[0][2]);
- r2.columnRotation(B);
- r2.columnRotation(V);
-
- process<0>(B, U, sigma, V);
- sort(U, sigma, V, 0);
- }
- /**
- If B is of form
- 0 x 0
- 0 x x
- 0 0 x
- */
- else if (btFabs(alpha_1) <= tol) {
- /**
- Reduce B to
- 0 0 +
- 0 x x
- 0 0 x
- */
- GivensRotation r1(0, 1);
- r1.computeUnconventional(B[0][1], B[1][1]);
- r1.rowRotation(B);
- r1.columnRotation(U);
-
- /**
- Reduce B to
- 0 0 0
- 0 x x
- 0 + x
- */
- GivensRotation r2(0, 2);
- r2.computeUnconventional(B[0][2], B[2][2]);
- r2.rowRotation(B);
- r2.columnRotation(U);
-
- process<1>(B, U, sigma, V);
- sort(U, sigma, V, 1);
- }
-
- return count;
-}
-#endif /* btImplicitQRSVD_h */