github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/lapack/gonum/dtrexc.go (about) 1 // Copyright ©2016 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gonum 6 7 import "github.com/jingcheng-WU/gonum/lapack" 8 9 // Dtrexc reorders the real Schur factorization of a n×n real matrix 10 // A = Q*T*Qᵀ 11 // so that the diagonal block of T with row index ifst is moved to row ilst. 12 // 13 // On entry, T must be in Schur canonical form, that is, block upper triangular 14 // with 1×1 and 2×2 diagonal blocks; each 2×2 diagonal block has its diagonal 15 // elements equal and its off-diagonal elements of opposite sign. 16 // 17 // On return, T will be reordered by an orthogonal similarity transformation Z 18 // as Zᵀ*T*Z, and will be again in Schur canonical form. 19 // 20 // If compq is lapack.UpdateSchur, on return the matrix Q of Schur vectors will be 21 // updated by post-multiplying it with Z. 22 // If compq is lapack.UpdateSchurNone, the matrix Q is not referenced and will not be 23 // updated. 24 // For other values of compq Dtrexc will panic. 25 // 26 // ifst and ilst specify the reordering of the diagonal blocks of T. The block 27 // with row index ifst is moved to row ilst, by a sequence of transpositions 28 // between adjacent blocks. 29 // 30 // If ifst points to the second row of a 2×2 block, ifstOut will point to the 31 // first row, otherwise it will be equal to ifst. 32 // 33 // ilstOut will point to the first row of the block in its final position. If ok 34 // is true, ilstOut may differ from ilst by +1 or -1. 35 // 36 // It must hold that 37 // 0 <= ifst < n, and 0 <= ilst < n, 38 // otherwise Dtrexc will panic. 39 // 40 // If ok is false, two adjacent blocks were too close to swap because the 41 // problem is very ill-conditioned. T may have been partially reordered, and 42 // ilstOut will point to the first row of the block at the position to which it 43 // has been moved. 44 // 45 // work must have length at least n, otherwise Dtrexc will panic. 46 // 47 // Dtrexc is an internal routine. It is exported for testing purposes. 48 func (impl Implementation) Dtrexc(compq lapack.UpdateSchurComp, n int, t []float64, ldt int, q []float64, ldq int, ifst, ilst int, work []float64) (ifstOut, ilstOut int, ok bool) { 49 switch { 50 case compq != lapack.UpdateSchur && compq != lapack.UpdateSchurNone: 51 panic(badUpdateSchurComp) 52 case n < 0: 53 panic(nLT0) 54 case ldt < max(1, n): 55 panic(badLdT) 56 case ldq < 1, compq == lapack.UpdateSchur && ldq < n: 57 panic(badLdQ) 58 case (ifst < 0 || n <= ifst) && n > 0: 59 panic(badIfst) 60 case (ilst < 0 || n <= ilst) && n > 0: 61 panic(badIlst) 62 } 63 64 // Quick return if possible. 65 if n == 0 { 66 return ifst, ilst, true 67 } 68 69 switch { 70 case len(t) < (n-1)*ldt+n: 71 panic(shortT) 72 case compq == lapack.UpdateSchur && len(q) < (n-1)*ldq+n: 73 panic(shortQ) 74 case len(work) < n: 75 panic(shortWork) 76 } 77 78 // Quick return if possible. 79 if n == 1 { 80 return ifst, ilst, true 81 } 82 83 // Determine the first row of specified block 84 // and find out it is 1×1 or 2×2. 85 if ifst > 0 && t[ifst*ldt+ifst-1] != 0 { 86 ifst-- 87 } 88 nbf := 1 // Size of the first block. 89 if ifst+1 < n && t[(ifst+1)*ldt+ifst] != 0 { 90 nbf = 2 91 } 92 // Determine the first row of the final block 93 // and find out it is 1×1 or 2×2. 94 if ilst > 0 && t[ilst*ldt+ilst-1] != 0 { 95 ilst-- 96 } 97 nbl := 1 // Size of the last block. 98 if ilst+1 < n && t[(ilst+1)*ldt+ilst] != 0 { 99 nbl = 2 100 } 101 102 ok = true 103 wantq := compq == lapack.UpdateSchur 104 105 switch { 106 case ifst == ilst: 107 return ifst, ilst, true 108 109 case ifst < ilst: 110 // Update ilst. 111 switch { 112 case nbf == 2 && nbl == 1: 113 ilst-- 114 case nbf == 1 && nbl == 2: 115 ilst++ 116 } 117 here := ifst 118 for here < ilst { 119 // Swap block with next one below. 120 if nbf == 1 || nbf == 2 { 121 // Current block either 1×1 or 2×2. 122 nbnext := 1 // Size of the next block. 123 if here+nbf+1 < n && t[(here+nbf+1)*ldt+here+nbf] != 0 { 124 nbnext = 2 125 } 126 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, nbf, nbnext, work) 127 if !ok { 128 return ifst, here, false 129 } 130 here += nbnext 131 // Test if 2×2 block breaks into two 1×1 blocks. 132 if nbf == 2 && t[(here+1)*ldt+here] == 0 { 133 nbf = 3 134 } 135 continue 136 } 137 138 // Current block consists of two 1×1 blocks each of 139 // which must be swapped individually. 140 nbnext := 1 // Size of the next block. 141 if here+3 < n && t[(here+3)*ldt+here+2] != 0 { 142 nbnext = 2 143 } 144 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here+1, 1, nbnext, work) 145 if !ok { 146 return ifst, here, false 147 } 148 if nbnext == 1 { 149 // Swap two 1×1 blocks, no problems possible. 150 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, nbnext, work) 151 here++ 152 continue 153 } 154 // Recompute nbnext in case 2×2 split. 155 if t[(here+2)*ldt+here+1] == 0 { 156 nbnext = 1 157 } 158 if nbnext == 2 { 159 // 2×2 block did not split. 160 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, nbnext, work) 161 if !ok { 162 return ifst, here, false 163 } 164 } else { 165 // 2×2 block did split. 166 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, 1, work) 167 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here+1, 1, 1, work) 168 } 169 here += 2 170 } 171 return ifst, here, true 172 173 default: // ifst > ilst 174 here := ifst 175 for here > ilst { 176 // Swap block with next one above. 177 if nbf == 1 || nbf == 2 { 178 // Current block either 1×1 or 2×2. 179 nbnext := 1 180 if here-2 >= 0 && t[(here-1)*ldt+here-2] != 0 { 181 nbnext = 2 182 } 183 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-nbnext, nbnext, nbf, work) 184 if !ok { 185 return ifst, here, false 186 } 187 here -= nbnext 188 // Test if 2×2 block breaks into two 1×1 blocks. 189 if nbf == 2 && t[(here+1)*ldt+here] == 0 { 190 nbf = 3 191 } 192 continue 193 } 194 195 // Current block consists of two 1×1 blocks each of 196 // which must be swapped individually. 197 nbnext := 1 198 if here-2 >= 0 && t[(here-1)*ldt+here-2] != 0 { 199 nbnext = 2 200 } 201 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-nbnext, nbnext, 1, work) 202 if !ok { 203 return ifst, here, false 204 } 205 if nbnext == 1 { 206 // Swap two 1×1 blocks, no problems possible. 207 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, nbnext, 1, work) 208 here-- 209 continue 210 } 211 // Recompute nbnext in case 2×2 split. 212 if t[here*ldt+here-1] == 0 { 213 nbnext = 1 214 } 215 if nbnext == 2 { 216 // 2×2 block did not split. 217 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-1, 2, 1, work) 218 if !ok { 219 return ifst, here, false 220 } 221 } else { 222 // 2×2 block did split. 223 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, 1, work) 224 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-1, 1, 1, work) 225 } 226 here -= 2 227 } 228 return ifst, here, true 229 } 230 }