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.
8 "gonum.org/v1/gonum/blas"
9 "gonum.org/v1/gonum/lapack"
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.
16 // The minimization problem solved depends on the input parameters.
18 // 1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2
20 // 2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of
22 // 3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of
24 // 4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2
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.
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.
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
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)
45 checkMatrix(max(m, n), nrhs, b, ldb)
47 // Find optimal block size.
54 nb = impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1)
56 nb = max(nb, impl.Ilaenv(1, "DORMQR", "LN", m, nrhs, n, -1))
58 nb = max(nb, impl.Ilaenv(1, "DORMQR", "LT", m, nrhs, n, -1))
61 nb = impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1)
63 nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LT", n, nrhs, m, -1))
65 nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LN", n, nrhs, m, -1))
69 work[0] = float64(max(1, mn+max(mn, nrhs)*nb))
73 if len(work) < lwork {
76 if lwork < mn+max(mn, nrhs) {
79 if m == 0 || n == 0 || nrhs == 0 {
80 impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb)
84 // Scale the input matrices if they contain extreme values.
85 smlnum := dlamchS / dlamchP
87 anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil)
89 if anrm > 0 && anrm < smlnum {
90 impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda)
92 } else if anrm > bignum {
93 impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda)
95 // Matrix is all zeros.
96 impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb)
103 bnrm := impl.Dlange(lapack.MaxAbs, brow, nrhs, b, ldb, nil)
105 if bnrm > 0 && bnrm < smlnum {
106 impl.Dlascl(lapack.General, 0, 0, bnrm, smlnum, brow, nrhs, b, ldb)
108 } else if bnrm > bignum {
109 impl.Dlascl(lapack.General, 0, 0, bnrm, bignum, brow, nrhs, b, ldb)
113 // Solve the minimization problem using a QR or an LQ decomposition.
116 impl.Dgeqrf(m, n, a, lda, work, work[mn:], lwork-mn)
118 impl.Dormqr(blas.Left, blas.Trans, m, nrhs, n,
123 ok := impl.Dtrtrs(blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs,
131 ok := impl.Dtrtrs(blas.Upper, blas.Trans, blas.NonUnit, n, nrhs,
137 for i := n; i < m; i++ {
138 for j := 0; j < nrhs; j++ {
142 impl.Dormqr(blas.Left, blas.NoTrans, m, nrhs, n,
150 impl.Dgelqf(m, n, a, lda, work, work[mn:], lwork-mn)
152 ok := impl.Dtrtrs(blas.Lower, blas.NoTrans, blas.NonUnit,
159 for i := m; i < n; i++ {
160 for j := 0; j < nrhs; j++ {
164 impl.Dormlq(blas.Left, blas.Trans, n, nrhs, m,
171 impl.Dormlq(blas.Left, blas.NoTrans, n, nrhs, m,
176 ok := impl.Dtrtrs(blas.Lower, blas.Trans, blas.NonUnit,
186 // Adjust answer vector based on scaling.
188 impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, scllen, nrhs, b, ldb)
191 impl.Dlascl(lapack.General, 0, 0, anrm, bignum, scllen, nrhs, b, ldb)
194 impl.Dlascl(lapack.General, 0, 0, smlnum, bnrm, scllen, nrhs, b, ldb)
197 impl.Dlascl(lapack.General, 0, 0, bignum, bnrm, scllen, nrhs, b, ldb)