github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/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 native 6 7 import "github.com/gonum/lapack" 8 9 // Dtrexc reorders the real Schur factorization of a n×n real matrix 10 // A = Q*T*Q^T 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*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 postmultiplying it with Z. 22 // If compq is lapack.None, 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.EVComp, n int, t []float64, ldt int, q []float64, ldq int, ifst, ilst int, work []float64) (ifstOut, ilstOut int, ok bool) { 49 checkMatrix(n, n, t, ldt) 50 var wantq bool 51 switch compq { 52 default: 53 panic("lapack: bad value of compq") 54 case lapack.None: 55 // Nothing to do because wantq is already false. 56 case lapack.UpdateSchur: 57 wantq = true 58 checkMatrix(n, n, q, ldq) 59 } 60 if (ifst < 0 || n <= ifst) && n > 0 { 61 panic("lapack: ifst out of range") 62 } 63 if (ilst < 0 || n <= ilst) && n > 0 { 64 panic("lapack: ilst out of range") 65 } 66 if len(work) < n { 67 panic(badWork) 68 } 69 70 ok = true 71 72 // Quick return if possible. 73 if n <= 1 { 74 return ifst, ilst, true 75 } 76 77 // Determine the first row of specified block 78 // and find out it is 1×1 or 2×2. 79 if ifst > 0 && t[ifst*ldt+ifst-1] != 0 { 80 ifst-- 81 } 82 nbf := 1 // Size of the first block. 83 if ifst+1 < n && t[(ifst+1)*ldt+ifst] != 0 { 84 nbf = 2 85 } 86 // Determine the first row of the final block 87 // and find out it is 1×1 or 2×2. 88 if ilst > 0 && t[ilst*ldt+ilst-1] != 0 { 89 ilst-- 90 } 91 nbl := 1 // Size of the last block. 92 if ilst+1 < n && t[(ilst+1)*ldt+ilst] != 0 { 93 nbl = 2 94 } 95 96 switch { 97 case ifst == ilst: 98 return ifst, ilst, true 99 100 case ifst < ilst: 101 // Update ilst. 102 switch { 103 case nbf == 2 && nbl == 1: 104 ilst-- 105 case nbf == 1 && nbl == 2: 106 ilst++ 107 } 108 here := ifst 109 for here < ilst { 110 // Swap block with next one below. 111 if nbf == 1 || nbf == 2 { 112 // Current block either 1×1 or 2×2. 113 nbnext := 1 // Size of the next block. 114 if here+nbf+1 < n && t[(here+nbf+1)*ldt+here+nbf] != 0 { 115 nbnext = 2 116 } 117 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, nbf, nbnext, work) 118 if !ok { 119 return ifst, here, false 120 } 121 here += nbnext 122 // Test if 2×2 block breaks into two 1×1 blocks. 123 if nbf == 2 && t[(here+1)*ldt+here] == 0 { 124 nbf = 3 125 } 126 continue 127 } 128 129 // Current block consists of two 1×1 blocks each of 130 // which must be swapped individually. 131 nbnext := 1 // Size of the next block. 132 if here+3 < n && t[(here+3)*ldt+here+2] != 0 { 133 nbnext = 2 134 } 135 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here+1, 1, nbnext, work) 136 if !ok { 137 return ifst, here, false 138 } 139 if nbnext == 1 { 140 // Swap two 1×1 blocks, no problems possible. 141 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, nbnext, work) 142 here++ 143 continue 144 } 145 // Recompute nbnext in case 2×2 split. 146 if t[(here+2)*ldt+here+1] == 0 { 147 nbnext = 1 148 } 149 if nbnext == 2 { 150 // 2×2 block did not split. 151 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, nbnext, work) 152 if !ok { 153 return ifst, here, false 154 } 155 } else { 156 // 2×2 block did split. 157 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, 1, work) 158 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here+1, 1, 1, work) 159 } 160 here += 2 161 } 162 return ifst, here, true 163 164 default: // ifst > ilst 165 here := ifst 166 for here > ilst { 167 // Swap block with next one above. 168 if nbf == 1 || nbf == 2 { 169 // Current block either 1×1 or 2×2. 170 nbnext := 1 171 if here-2 >= 0 && t[(here-1)*ldt+here-2] != 0 { 172 nbnext = 2 173 } 174 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-nbnext, nbnext, nbf, work) 175 if !ok { 176 return ifst, here, false 177 } 178 here -= nbnext 179 // Test if 2×2 block breaks into two 1×1 blocks. 180 if nbf == 2 && t[(here+1)*ldt+here] == 0 { 181 nbf = 3 182 } 183 continue 184 } 185 186 // Current block consists of two 1×1 blocks each of 187 // which must be swapped individually. 188 nbnext := 1 189 if here-2 >= 0 && t[(here-1)*ldt+here-2] != 0 { 190 nbnext = 2 191 } 192 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-nbnext, nbnext, 1, work) 193 if !ok { 194 return ifst, here, false 195 } 196 if nbnext == 1 { 197 // Swap two 1×1 blocks, no problems possible. 198 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, nbnext, 1, work) 199 here-- 200 continue 201 } 202 // Recompute nbnext in case 2×2 split. 203 if t[here*ldt+here-1] == 0 { 204 nbnext = 1 205 } 206 if nbnext == 2 { 207 // 2×2 block did not split. 208 ok = impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-1, 2, 1, work) 209 if !ok { 210 return ifst, here, false 211 } 212 } else { 213 // 2×2 block did split. 214 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here, 1, 1, work) 215 impl.Dlaexc(wantq, n, t, ldt, q, ldq, here-1, 1, 1, work) 216 } 217 here -= 2 218 } 219 return ifst, here, true 220 } 221 }