github.com/gopherd/gonum@v0.0.4/lapack/gonum/dgels.go (about) 1 // Copyright ©2015 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 ( 8 "github.com/gopherd/gonum/blas" 9 "github.com/gopherd/gonum/lapack" 10 ) 11 12 // Dgels finds a minimum-norm solution based on the matrices A and B using the 13 // QR or LQ factorization. Dgels returns false if the matrix 14 // A is singular, and true if this solution was successfully found. 15 // 16 // The minimization problem solved depends on the input parameters. 17 // 18 // 1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2 19 // is minimized. 20 // 2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of 21 // A * X = B. 22 // 3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of 23 // Aᵀ * X = B. 24 // 4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2 25 // is minimized. 26 // Note that the least-squares solutions (cases 1 and 3) perform the minimization 27 // per column of B. This is not the same as finding the minimum-norm matrix. 28 // 29 // The matrix A is a general matrix of size m×n and is modified during this call. 30 // The input matrix B is of size max(m,n)×nrhs, and serves two purposes. On entry, 31 // the elements of b specify the input matrix B. B has size m×nrhs if 32 // trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the 33 // leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans, 34 // this submatrix is of size n×nrhs, and of size m×nrhs otherwise. 35 // 36 // work is temporary storage, and lwork specifies the usable memory length. 37 // At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic 38 // otherwise. A longer work will enable blocked algorithms to be called. 39 // In the special case that lwork == -1, work[0] will be set to the optimal working 40 // length. 41 func (impl Implementation) Dgels(trans blas.Transpose, m, n, nrhs int, a []float64, lda int, b []float64, ldb int, work []float64, lwork int) bool { 42 mn := min(m, n) 43 minwrk := mn + max(mn, nrhs) 44 switch { 45 case trans != blas.NoTrans && trans != blas.Trans && trans != blas.ConjTrans: 46 panic(badTrans) 47 case m < 0: 48 panic(mLT0) 49 case n < 0: 50 panic(nLT0) 51 case nrhs < 0: 52 panic(nrhsLT0) 53 case lda < max(1, n): 54 panic(badLdA) 55 case ldb < max(1, nrhs): 56 panic(badLdB) 57 case lwork < max(1, minwrk) && lwork != -1: 58 panic(badLWork) 59 case len(work) < max(1, lwork): 60 panic(shortWork) 61 } 62 63 // Quick return if possible. 64 if mn == 0 || nrhs == 0 { 65 impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb) 66 work[0] = 1 67 return true 68 } 69 70 // Find optimal block size. 71 var nb int 72 if m >= n { 73 nb = impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1) 74 if trans != blas.NoTrans { 75 nb = max(nb, impl.Ilaenv(1, "DORMQR", "LN", m, nrhs, n, -1)) 76 } else { 77 nb = max(nb, impl.Ilaenv(1, "DORMQR", "LT", m, nrhs, n, -1)) 78 } 79 } else { 80 nb = impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1) 81 if trans != blas.NoTrans { 82 nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LT", n, nrhs, m, -1)) 83 } else { 84 nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LN", n, nrhs, m, -1)) 85 } 86 } 87 wsize := max(1, mn+max(mn, nrhs)*nb) 88 work[0] = float64(wsize) 89 90 if lwork == -1 { 91 return true 92 } 93 94 switch { 95 case len(a) < (m-1)*lda+n: 96 panic(shortA) 97 case len(b) < (max(m, n)-1)*ldb+nrhs: 98 panic(shortB) 99 } 100 101 // Scale the input matrices if they contain extreme values. 102 smlnum := dlamchS / dlamchP 103 bignum := 1 / smlnum 104 anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil) 105 var iascl int 106 if anrm > 0 && anrm < smlnum { 107 impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda) 108 iascl = 1 109 } else if anrm > bignum { 110 impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda) 111 } else if anrm == 0 { 112 // Matrix is all zeros. 113 impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb) 114 return true 115 } 116 brow := m 117 if trans != blas.NoTrans { 118 brow = n 119 } 120 bnrm := impl.Dlange(lapack.MaxAbs, brow, nrhs, b, ldb, nil) 121 ibscl := 0 122 if bnrm > 0 && bnrm < smlnum { 123 impl.Dlascl(lapack.General, 0, 0, bnrm, smlnum, brow, nrhs, b, ldb) 124 ibscl = 1 125 } else if bnrm > bignum { 126 impl.Dlascl(lapack.General, 0, 0, bnrm, bignum, brow, nrhs, b, ldb) 127 ibscl = 2 128 } 129 130 // Solve the minimization problem using a QR or an LQ decomposition. 131 var scllen int 132 if m >= n { 133 impl.Dgeqrf(m, n, a, lda, work, work[mn:], lwork-mn) 134 if trans == blas.NoTrans { 135 impl.Dormqr(blas.Left, blas.Trans, m, nrhs, n, 136 a, lda, 137 work[:n], 138 b, ldb, 139 work[mn:], lwork-mn) 140 ok := impl.Dtrtrs(blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs, 141 a, lda, 142 b, ldb) 143 if !ok { 144 return false 145 } 146 scllen = n 147 } else { 148 ok := impl.Dtrtrs(blas.Upper, blas.Trans, blas.NonUnit, n, nrhs, 149 a, lda, 150 b, ldb) 151 if !ok { 152 return false 153 } 154 for i := n; i < m; i++ { 155 for j := 0; j < nrhs; j++ { 156 b[i*ldb+j] = 0 157 } 158 } 159 impl.Dormqr(blas.Left, blas.NoTrans, m, nrhs, n, 160 a, lda, 161 work[:n], 162 b, ldb, 163 work[mn:], lwork-mn) 164 scllen = m 165 } 166 } else { 167 impl.Dgelqf(m, n, a, lda, work, work[mn:], lwork-mn) 168 if trans == blas.NoTrans { 169 ok := impl.Dtrtrs(blas.Lower, blas.NoTrans, blas.NonUnit, 170 m, nrhs, 171 a, lda, 172 b, ldb) 173 if !ok { 174 return false 175 } 176 for i := m; i < n; i++ { 177 for j := 0; j < nrhs; j++ { 178 b[i*ldb+j] = 0 179 } 180 } 181 impl.Dormlq(blas.Left, blas.Trans, n, nrhs, m, 182 a, lda, 183 work, 184 b, ldb, 185 work[mn:], lwork-mn) 186 scllen = n 187 } else { 188 impl.Dormlq(blas.Left, blas.NoTrans, n, nrhs, m, 189 a, lda, 190 work, 191 b, ldb, 192 work[mn:], lwork-mn) 193 ok := impl.Dtrtrs(blas.Lower, blas.Trans, blas.NonUnit, 194 m, nrhs, 195 a, lda, 196 b, ldb) 197 if !ok { 198 return false 199 } 200 } 201 } 202 203 // Adjust answer vector based on scaling. 204 if iascl == 1 { 205 impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, scllen, nrhs, b, ldb) 206 } 207 if iascl == 2 { 208 impl.Dlascl(lapack.General, 0, 0, anrm, bignum, scllen, nrhs, b, ldb) 209 } 210 if ibscl == 1 { 211 impl.Dlascl(lapack.General, 0, 0, smlnum, bnrm, scllen, nrhs, b, ldb) 212 } 213 if ibscl == 2 { 214 impl.Dlascl(lapack.General, 0, 0, bignum, bnrm, scllen, nrhs, b, ldb) 215 } 216 217 work[0] = float64(wsize) 218 return true 219 }