github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/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 native 6 7 import ( 8 "github.com/gonum/blas" 9 "github.com/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^T * 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 notran := trans == blas.NoTrans 43 checkMatrix(m, n, a, lda) 44 mn := min(m, n) 45 checkMatrix(max(m, n), nrhs, b, ldb) 46 47 // Find optimal block size. 48 tpsd := true 49 if notran { 50 tpsd = false 51 } 52 var nb int 53 if m >= n { 54 nb = impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1) 55 if tpsd { 56 nb = max(nb, impl.Ilaenv(1, "DORMQR", "LN", m, nrhs, n, -1)) 57 } else { 58 nb = max(nb, impl.Ilaenv(1, "DORMQR", "LT", m, nrhs, n, -1)) 59 } 60 } else { 61 nb = impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1) 62 if tpsd { 63 nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LT", n, nrhs, m, -1)) 64 } else { 65 nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LN", n, nrhs, m, -1)) 66 } 67 } 68 if lwork == -1 { 69 work[0] = float64(max(1, mn+max(mn, nrhs)*nb)) 70 return true 71 } 72 73 if len(work) < lwork { 74 panic(shortWork) 75 } 76 if lwork < mn+max(mn, nrhs) { 77 panic(badWork) 78 } 79 if m == 0 || n == 0 || nrhs == 0 { 80 impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb) 81 return true 82 } 83 84 // Scale the input matrices if they contain extreme values. 85 smlnum := dlamchS / dlamchP 86 bignum := 1 / smlnum 87 anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil) 88 var iascl int 89 if anrm > 0 && anrm < smlnum { 90 impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda) 91 iascl = 1 92 } else if anrm > bignum { 93 impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda) 94 } else if anrm == 0 { 95 // Matrix is all zeros. 96 impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb) 97 return true 98 } 99 brow := m 100 if tpsd { 101 brow = n 102 } 103 bnrm := impl.Dlange(lapack.MaxAbs, brow, nrhs, b, ldb, nil) 104 ibscl := 0 105 if bnrm > 0 && bnrm < smlnum { 106 impl.Dlascl(lapack.General, 0, 0, bnrm, smlnum, brow, nrhs, b, ldb) 107 ibscl = 1 108 } else if bnrm > bignum { 109 impl.Dlascl(lapack.General, 0, 0, bnrm, bignum, brow, nrhs, b, ldb) 110 ibscl = 2 111 } 112 113 // Solve the minimization problem using a QR or an LQ decomposition. 114 var scllen int 115 if m >= n { 116 impl.Dgeqrf(m, n, a, lda, work, work[mn:], lwork-mn) 117 if !tpsd { 118 impl.Dormqr(blas.Left, blas.Trans, m, nrhs, n, 119 a, lda, 120 work[:n], 121 b, ldb, 122 work[mn:], lwork-mn) 123 ok := impl.Dtrtrs(blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs, 124 a, lda, 125 b, ldb) 126 if !ok { 127 return false 128 } 129 scllen = n 130 } else { 131 ok := impl.Dtrtrs(blas.Upper, blas.Trans, blas.NonUnit, n, nrhs, 132 a, lda, 133 b, ldb) 134 if !ok { 135 return false 136 } 137 for i := n; i < m; i++ { 138 for j := 0; j < nrhs; j++ { 139 b[i*ldb+j] = 0 140 } 141 } 142 impl.Dormqr(blas.Left, blas.NoTrans, m, nrhs, n, 143 a, lda, 144 work[:n], 145 b, ldb, 146 work[mn:], lwork-mn) 147 scllen = m 148 } 149 } else { 150 impl.Dgelqf(m, n, a, lda, work, work[mn:], lwork-mn) 151 if !tpsd { 152 ok := impl.Dtrtrs(blas.Lower, blas.NoTrans, blas.NonUnit, 153 m, nrhs, 154 a, lda, 155 b, ldb) 156 if !ok { 157 return false 158 } 159 for i := m; i < n; i++ { 160 for j := 0; j < nrhs; j++ { 161 b[i*ldb+j] = 0 162 } 163 } 164 impl.Dormlq(blas.Left, blas.Trans, n, nrhs, m, 165 a, lda, 166 work, 167 b, ldb, 168 work[mn:], lwork-mn) 169 scllen = n 170 } else { 171 impl.Dormlq(blas.Left, blas.NoTrans, n, nrhs, m, 172 a, lda, 173 work, 174 b, ldb, 175 work[mn:], lwork-mn) 176 ok := impl.Dtrtrs(blas.Lower, blas.Trans, blas.NonUnit, 177 m, nrhs, 178 a, lda, 179 b, ldb) 180 if !ok { 181 return false 182 } 183 } 184 } 185 186 // Adjust answer vector based on scaling. 187 if iascl == 1 { 188 impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, scllen, nrhs, b, ldb) 189 } 190 if iascl == 2 { 191 impl.Dlascl(lapack.General, 0, 0, anrm, bignum, scllen, nrhs, b, ldb) 192 } 193 if ibscl == 1 { 194 impl.Dlascl(lapack.General, 0, 0, smlnum, bnrm, scllen, nrhs, b, ldb) 195 } 196 if ibscl == 2 { 197 impl.Dlascl(lapack.General, 0, 0, bignum, bnrm, scllen, nrhs, b, ldb) 198 } 199 return true 200 }