2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2019 Google Inc. http://bulletphysics.org
4 This software is provided 'as-is', without any express or implied warranty.
5 In no event will the authors be held liable for any damages arising from the use of this software.
6 Permission is granted to anyone to use this software for any purpose,
7 including commercial applications, and to alter it and redistribute it freely,
8 subject to the following restrictions:
9 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.
10 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
11 3. This notice may not be removed or altered from any source distribution.
13 Copyright (c) 2016 Theodore Gast, Chuyuan Fu, Chenfanfu Jiang, Joseph Teran
15 Permission is hereby granted, free of charge, to any person obtaining a copy of
16 this software and associated documentation files (the "Software"), to deal in
17 the Software without restriction, including without limitation the rights to
18 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
19 of the Software, and to permit persons to whom the Software is furnished to do
20 so, subject to the following conditions:
22 The above copyright notice and this permission notice shall be included in all
23 copies or substantial portions of the Software.
25 If the code is used in an article, the following paper shall be cited:
26 @techreport{qrsvd:2016,
27 title={Implicit-shifted Symmetric QR Singular Value Decomposition of 3x3 Matrices},
28 author={Gast, Theodore and Fu, Chuyuan and Jiang, Chenfanfu and Teran, Joseph},
30 institution={University of California Los Angeles}
33 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42 #ifndef btImplicitQRSVD_h
43 #define btImplicitQRSVD_h
45 #include "btMatrix3x3.h"
49 btScalar m_00, m_01, m_10, m_11;
50 btMatrix2x2(): m_00(0), m_10(0), m_01(0), m_11(0)
53 btMatrix2x2(const btMatrix2x2& other): m_00(other.m_00),m_01(other.m_01),m_10(other.m_10),m_11(other.m_11)
55 btScalar& operator()(int i, int j)
68 const btScalar& operator()(int i, int j) const
90 static inline btScalar copySign(btScalar x, btScalar y) {
91 if ((x < 0 && y > 0) || (x > 0 && y < 0))
97 Class for givens rotation.
98 Row rotation G*A corresponds to something like
102 Column rotation A G' corresponds to something like
107 c and s are always computed so that
108 ( c -s ) ( a ) = ( * )
114 class GivensRotation {
121 inline GivensRotation(int rowi_in, int rowk_in)
129 inline GivensRotation(btScalar a, btScalar b, int rowi_in, int rowk_in)
138 inline void transposeInPlace()
144 Compute c and s from a and b so that
145 ( c -s ) ( a ) = ( * )
148 inline void compute(const btScalar a, const btScalar b)
150 btScalar d = a * a + b * b;
153 if (d > SIMD_EPSILON) {
154 btScalar sqrtd = btSqrt(d);
155 if (sqrtd>SIMD_EPSILON)
157 btScalar t = btScalar(1.0)/sqrtd;
165 This function computes c and s so that
166 ( c -s ) ( a ) = ( 0 )
169 inline void computeUnconventional(const btScalar a, const btScalar b)
171 btScalar d = a * a + b * b;
174 if (d > SIMD_EPSILON) {
175 btScalar t = btScalar(1.0)/btSqrt(d);
181 Fill the R with the entries of this rotation
183 inline void fill(const btMatrix3x3& R) const
185 btMatrix3x3& A = const_cast<btMatrix3x3&>(R);
193 inline void fill(const btMatrix2x2& R) const
195 btMatrix2x2& A = const_cast<btMatrix2x2&>(R);
203 This function does something like
207 It only affects row i and row k of A.
209 inline void rowRotation(btMatrix3x3& A) const
211 for (int j = 0; j < 3; j++) {
212 btScalar tau1 = A[rowi][j];
213 btScalar tau2 = A[rowk][j];
214 A[rowi][j] = c * tau1 - s * tau2;
215 A[rowk][j] = s * tau1 + c * tau2;
218 inline void rowRotation(btMatrix2x2& A) const
220 for (int j = 0; j < 2; j++) {
221 btScalar tau1 = A(rowi,j);
222 btScalar tau2 = A(rowk,j);
223 A(rowi,j) = c * tau1 - s * tau2;
224 A(rowk,j) = s * tau1 + c * tau2;
229 This function does something like
233 It only affects column i and column k of A.
235 inline void columnRotation(btMatrix3x3& A) const
237 for (int j = 0; j < 3; j++) {
238 btScalar tau1 = A[j][rowi];
239 btScalar tau2 = A[j][rowk];
240 A[j][rowi] = c * tau1 - s * tau2;
241 A[j][rowk] = s * tau1 + c * tau2;
244 inline void columnRotation(btMatrix2x2& A) const
246 for (int j = 0; j < 2; j++) {
247 btScalar tau1 = A(j,rowi);
248 btScalar tau2 = A(j,rowk);
249 A(j,rowi) = c * tau1 - s * tau2;
250 A(j,rowk) = s * tau1 + c * tau2;
255 Multiply givens must be for same row and column
257 inline void operator*=(const GivensRotation& A)
259 btScalar new_c = c * A.c - s * A.s;
260 btScalar new_s = s * A.c + c * A.s;
266 Multiply givens must be for same row and column
268 inline GivensRotation operator*(const GivensRotation& A) const
270 GivensRotation r(*this);
277 \brief zero chasing the 3X3 matrix to bidiagonal form
278 original form of H: x x 0
286 inline void zeroChase(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
295 GivensRotation r1(H[0][0], H[1][0], 0, 1);
301 Can calculate r2 without multiplying by r1 since both entries are in first two
302 rows thus no need to divide by sqrt(a^2+b^2)
304 GivensRotation r2(1, 2);
306 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]);
308 r2.compute(H[0][1], H[0][2]);
312 /* GivensRotation<T> r2(H(0, 1), H(0, 2), 1, 2); */
313 r2.columnRotation(H);
314 r2.columnRotation(V);
322 GivensRotation r3(H[1][1], H[2][1], 1, 2);
325 // Save this till end for better cache coherency
326 // r1.rowRotation(u_transpose);
327 // r3.rowRotation(u_transpose);
328 r1.columnRotation(U);
329 r3.columnRotation(U);
333 \brief make a 3X3 matrix to upper bidiagonal form
334 original form of H: x x x
342 inline void makeUpperBidiag(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
354 GivensRotation r(H[1][0], H[2][0], 1, 2);
356 // r.rowRotation(u_transpose);
358 // zeroChase(H, u_transpose, V);
363 \brief make a 3X3 matrix to lambda shape
364 original form of H: x x x
372 inline void makeLambdaShape(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
384 GivensRotation r1(H[0][1], H[0][2], 1, 2);
385 r1.columnRotation(H);
386 r1.columnRotation(V);
395 r1.computeUnconventional(H[1][2], H[2][2]);
397 r1.columnRotation(U);
406 GivensRotation r2(H[2][0], H[2][1], 0, 1);
407 r2.columnRotation(H);
408 r2.columnRotation(V);
416 r2.computeUnconventional(H[0][1], H[1][1]);
418 r2.columnRotation(U);
422 \brief 2x2 polar decomposition.
424 \param[out] R Robustly a rotation matrix.
425 \param[out] S_Sym Symmetric. Whole matrix is stored
427 Polar guarantees negative sign is on the small magnitude singular value.
428 S is guaranteed to be the closest one to identity.
429 R is guaranteed to be the closest rotation to A.
431 inline void polarDecomposition(const btMatrix2x2& A,
433 const btMatrix2x2& S_Sym)
435 btScalar a = (A(0, 0) + A(1, 1)), b = (A(1, 0) - A(0, 1));
436 btScalar denominator = btSqrt(a*a+b*b);
439 if (denominator > SIMD_EPSILON) {
441 No need to use a tolerance here because x(0) and x(1) always have
442 smaller magnitude then denominator, therefore overflow never happens.
443 In Bullet, we use a tolerance anyway.
445 R.c = a / denominator;
446 R.s = -b / denominator;
448 btMatrix2x2& S = const_cast<btMatrix2x2&>(S_Sym);
453 inline void polarDecomposition(const btMatrix2x2& A,
454 const btMatrix2x2& R,
455 const btMatrix2x2& S_Sym)
457 GivensRotation r(0, 1);
458 polarDecomposition(A, r, S_Sym);
463 \brief 2x2 SVD (singular value decomposition) A=USV'
464 \param[in] A Input matrix.
465 \param[out] U Robustly a rotation matrix in Givens form
466 \param[out] Sigma matrix of singular values sorted with decreasing magnitude. The second one can be negative.
467 \param[out] V Robustly a rotation matrix in Givens form
469 inline void singularValueDecomposition(
470 const btMatrix2x2& A,
472 const btMatrix2x2& Sigma,
474 const btScalar tol = 64 * std::numeric_limits<btScalar>::epsilon())
476 btMatrix2x2& sigma = const_cast<btMatrix2x2&>(Sigma);
479 polarDecomposition(A, U, S_Sym);
480 btScalar cosine, sine;
481 btScalar x = S_Sym(0, 0);
482 btScalar y = S_Sym(0, 1);
483 btScalar z = S_Sym(1, 1);
485 // S is already diagonal
492 btScalar tau = 0.5 * (x - z);
493 btScalar val = tau * tau + y * y;
494 if (val > SIMD_EPSILON)
496 btScalar w = btSqrt(val);
500 // tau + w > w > y > 0 ==> division is safe
504 // tau - w < -w < -y < 0 ==> division is safe
507 cosine = btScalar(1) / btSqrt(t * t + btScalar(1));
510 V = [cosine -sine; sine cosine]
511 Sigma = V'SV. Only compute the diagonals for efficiency.
512 Also utilize symmetry of S and don't form V yet.
514 btScalar c2 = cosine * cosine;
515 btScalar csy = 2 * cosine * sine * y;
516 btScalar s2 = sine * sine;
517 sigma(0,0) = c2 * x - csy + s2 * z;
518 sigma(1,1) = s2 * x + csy + c2 * z;
529 // Polar already guarantees negative sign is on the small magnitude singular value.
530 if (sigma(0,0) < sigma(1,1)) {
531 std::swap(sigma(0,0), sigma(1,1));
543 \brief 2x2 SVD (singular value decomposition) A=USV'
544 \param[in] A Input matrix.
545 \param[out] U Robustly a rotation matrix.
546 \param[out] Sigma Vector of singular values sorted with decreasing magnitude. The second one can be negative.
547 \param[out] V Robustly a rotation matrix.
549 inline void singularValueDecomposition(
550 const btMatrix2x2& A,
551 const btMatrix2x2& U,
552 const btMatrix2x2& Sigma,
553 const btMatrix2x2& V,
554 const btScalar tol = 64 * std::numeric_limits<btScalar>::epsilon())
556 GivensRotation gv(0, 1);
557 GivensRotation gu(0, 1);
558 singularValueDecomposition(A, gu, Sigma, gv);
565 \brief compute wilkinsonShift of the block
568 based on the wilkinsonShift formula
569 mu = c + d - sign (d) \ sqrt (d*d + b*b), where d = (a-c)/2
572 inline btScalar wilkinsonShift(const btScalar a1, const btScalar b1, const btScalar a2)
574 btScalar d = (btScalar)0.5 * (a1 - a2);
575 btScalar bs = b1 * b1;
576 btScalar val = d * d + bs;
577 if (val>SIMD_EPSILON)
579 btScalar denom = btFabs(d) + btSqrt(val);
581 btScalar mu = a2 - copySign(bs / (denom), d);
582 // T mu = a2 - bs / ( d + sign_d*sqrt (d*d + bs));
589 \brief Helper function of 3X3 SVD for processing 2X2 SVD
592 inline void process(btMatrix3x3& B, btMatrix3x3& U, btVector3& sigma, btMatrix3x3& V)
594 int other = (t == 1) ? 0 : 2;
595 GivensRotation u(0, 1);
596 GivensRotation v(0, 1);
597 sigma[other] = B[other][other];
599 btMatrix2x2 B_sub, sigma_sub;
602 B_sub.m_00 = B[0][0];
603 B_sub.m_10 = B[1][0];
604 B_sub.m_01 = B[0][1];
605 B_sub.m_11 = B[1][1];
606 sigma_sub.m_00 = sigma[0];
607 sigma_sub.m_11 = sigma[1];
608 // singularValueDecomposition(B.template block<2, 2>(t, t), u, sigma.template block<2, 1>(t, 0), v);
609 singularValueDecomposition(B_sub, u, sigma_sub, v);
610 B[0][0] = B_sub.m_00;
611 B[1][0] = B_sub.m_10;
612 B[0][1] = B_sub.m_01;
613 B[1][1] = B_sub.m_11;
614 sigma[0] = sigma_sub.m_00;
615 sigma[1] = sigma_sub.m_11;
619 B_sub.m_00 = B[1][1];
620 B_sub.m_10 = B[2][1];
621 B_sub.m_01 = B[1][2];
622 B_sub.m_11 = B[2][2];
623 sigma_sub.m_00 = sigma[1];
624 sigma_sub.m_11 = sigma[2];
625 // singularValueDecomposition(B.template block<2, 2>(t, t), u, sigma.template block<2, 1>(t, 0), v);
626 singularValueDecomposition(B_sub, u, sigma_sub, v);
627 B[1][1] = B_sub.m_00;
628 B[2][1] = B_sub.m_10;
629 B[1][2] = B_sub.m_01;
630 B[2][2] = B_sub.m_11;
631 sigma[1] = sigma_sub.m_00;
632 sigma[2] = sigma_sub.m_11;
643 \brief Helper function of 3X3 SVD for flipping signs due to flipping signs of sigma
645 inline void flipSign(int i, btMatrix3x3& U, btVector3& sigma)
647 sigma[i] = -sigma[i];
653 inline void flipSign(int i, btMatrix3x3& U)
660 inline void swapCol(btMatrix3x3& A, int i, int j)
662 for (int d = 0; d < 3; ++d)
663 std::swap(A[d][i], A[d][j]);
666 \brief Helper function of 3X3 SVD for sorting singular values
668 inline void sort(btMatrix3x3& U, btVector3& sigma, btMatrix3x3& V, int t)
672 // Case: sigma(0) > |sigma(1)| >= |sigma(2)|
673 if (btFabs(sigma[1]) >= btFabs(sigma[2])) {
675 flipSign(1, U, sigma);
676 flipSign(2, U, sigma);
681 //fix sign of sigma for both cases
683 flipSign(1, U, sigma);
684 flipSign(2, U, sigma);
687 //swap sigma(1) and sigma(2) for both cases
688 std::swap(sigma[1], sigma[2]);
689 // swap the col 1 and col 2 for U,V
693 // Case: |sigma(2)| >= sigma(0) > |simga(1)|
694 if (sigma[1] > sigma[0]) {
695 std::swap(sigma[0], sigma[1]);
700 // Case: sigma(0) >= |sigma(2)| > |simga(1)|
708 // Case: |sigma(0)| >= sigma(1) > |sigma(2)|
709 if (btFabs(sigma[0]) >= sigma[1]) {
711 flipSign(0, U, sigma);
712 flipSign(2, U, sigma);
717 //swap sigma(0) and sigma(1) for both cases
718 std::swap(sigma[0], sigma[1]);
722 // Case: sigma(1) > |sigma(2)| >= |sigma(0)|
723 if (btFabs(sigma[1]) < btFabs(sigma[2])) {
724 std::swap(sigma[1], sigma[2]);
729 // Case: sigma(1) >= |sigma(0)| > |sigma(2)|
735 // fix sign for both cases
737 flipSign(1, U, sigma);
738 flipSign(2, U, sigma);
744 \brief 3X3 SVD (singular value decomposition) A=USV'
745 \param[in] A Input matrix.
746 \param[out] U is a rotation matrix.
747 \param[out] sigma Diagonal matrix, sorted with decreasing magnitude. The third one can be negative.
748 \param[out] V is a rotation matrix.
750 inline int singularValueDecomposition(const btMatrix3x3& A,
754 btScalar tol = 128*std::numeric_limits<btScalar>::epsilon())
761 makeUpperBidiag(B, U, V);
764 btScalar mu = (btScalar)0;
765 GivensRotation r(0, 1);
767 btScalar alpha_1 = B[0][0];
768 btScalar beta_1 = B[0][1];
769 btScalar alpha_2 = B[1][1];
770 btScalar alpha_3 = B[2][2];
771 btScalar beta_2 = B[1][2];
772 btScalar gamma_1 = alpha_1 * beta_1;
773 btScalar gamma_2 = alpha_2 * beta_2;
774 btScalar val = alpha_1 * alpha_1 + alpha_2 * alpha_2 + alpha_3 * alpha_3 + beta_1 * beta_1 + beta_2 * beta_2;
775 if (val > SIMD_EPSILON)
777 tol *= btMax((btScalar)0.5 * btSqrt(val), (btScalar)1);
780 Do implicit shift QR until A^T A is block diagonal
784 while (btFabs(beta_2) > tol && btFabs(beta_1) > tol
785 && btFabs(alpha_1) > tol && btFabs(alpha_2) > tol
786 && btFabs(alpha_3) > tol
787 && count < max_count) {
788 mu = wilkinsonShift(alpha_2 * alpha_2 + beta_1 * beta_1, gamma_2, alpha_3 * alpha_3 + beta_2 * beta_2);
790 r.compute(alpha_1 * alpha_1 - mu, gamma_1);
801 gamma_1 = alpha_1 * beta_1;
802 gamma_2 = alpha_2 * beta_2;
806 Handle the cases of one of the alphas and betas being 0
807 Sorted by ease of handling and then frequency
815 if (btFabs(beta_2) <= tol) {
816 process<0>(B, U, sigma, V);
825 else if (btFabs(beta_1) <= tol) {
826 process<1>(B, U, sigma, V);
835 else if (btFabs(alpha_2) <= tol) {
842 GivensRotation r1(1, 2);
843 r1.computeUnconventional(B[1][2], B[2][2]);
845 r1.columnRotation(U);
847 process<0>(B, U, sigma, V);
848 sort(U, sigma, V, 0);
856 else if (btFabs(alpha_3) <= tol) {
863 GivensRotation r1(1, 2);
864 r1.compute(B[1][1], B[1][2]);
865 r1.columnRotation(B);
866 r1.columnRotation(V);
873 GivensRotation r2(0, 2);
874 r2.compute(B[0][0], B[0][2]);
875 r2.columnRotation(B);
876 r2.columnRotation(V);
878 process<0>(B, U, sigma, V);
879 sort(U, sigma, V, 0);
887 else if (btFabs(alpha_1) <= tol) {
894 GivensRotation r1(0, 1);
895 r1.computeUnconventional(B[0][1], B[1][1]);
897 r1.columnRotation(U);
905 GivensRotation r2(0, 2);
906 r2.computeUnconventional(B[0][2], B[2][2]);
908 r2.columnRotation(U);
910 process<1>(B, U, sigma, V);
911 sort(U, sigma, V, 1);
916 #endif /* btImplicitQRSVD_h */