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