Upgrade OpenShift and its dependencies.

OpenShift version 1.4.0-alpha.0
This commit is contained in:
Tomas Kral
2016-10-18 12:04:00 +02:00
parent 5e1a5cbb3b
commit 1f8a0e06c9
1786 changed files with 424709 additions and 33395 deletions
+44
View File
@@ -0,0 +1,44 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "github.com/gonum/blas"
// Dgelq2 computes the LQ factorization of the m×n matrix a.
//
// During Dgelq2, a is modified to contain the information to construct Q and L.
// The lower triangle of a contains the matrix L. The upper triangular elements
// (not including the diagonal) contain the elementary reflectors. Tau is modified
// to contain the reflector scales. Tau must have length of at least k = min(m,n)
// and this function will panic otherwise.
//
// See Dgeqr2 for a description of the elementary reflectors and orthonormal
// matrix Q. Q is constructed as a product of these elementary reflectors,
// Q = H_k ... H_2*H_1.
//
// Work is temporary storage of length at least m and this function will panic otherwise.
func (impl Implementation) Dgelq2(m, n int, a []float64, lda int, tau, work []float64) {
checkMatrix(m, n, a, lda)
k := min(m, n)
if len(tau) < k {
panic(badTau)
}
if len(work) < m {
panic(badWork)
}
for i := 0; i < k; i++ {
a[i*lda+i], tau[i] = impl.Dlarfg(n-i, a[i*lda+i], a[i*lda+min(i+1, n-1):], 1)
if i < m-1 {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(blas.Right, m-i-1, n-i,
a[i*lda+i:], 1,
tau[i],
a[(i+1)*lda+i:], lda,
work)
a[i*lda+i] = aii
}
}
}
+84
View File
@@ -0,0 +1,84 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/lapack"
)
// Dgelqf computes the LQ factorization of the m×n matrix a using a blocked
// algorithm. Please see the documentation for Dgelq2 for a description of the
// parameters at entry and exit.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m, and this function will panic otherwise.
// Dgelqf is a blocked LQ factorization, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Dgelqf,
// the optimal work length will be stored into work[0].
//
// tau must have length at least min(m,n), and this function will panic otherwise.
func (impl Implementation) Dgelqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) {
nb := impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1)
lworkopt := m * max(nb, 1)
if lwork == -1 {
work[0] = float64(lworkopt)
return
}
checkMatrix(m, n, a, lda)
if len(work) < lwork {
panic(shortWork)
}
if lwork < m {
panic(badWork)
}
k := min(m, n)
if len(tau) < k {
panic(badTau)
}
if k == 0 {
return
}
// Find the optimal blocking size based on the size of available memory
// and optimal machine parameters.
nbmin := 2
var nx int
iws := m
ldwork := nb
if nb > 1 && k > nb {
nx = max(0, impl.Ilaenv(3, "DGELQF", " ", m, n, -1, -1))
if nx < k {
iws = m * nb
if lwork < iws {
nb = lwork / m
nbmin = max(2, impl.Ilaenv(2, "DGELQF", " ", m, n, -1, -1))
}
}
}
// Computed blocked LQ factorization.
var i int
if nb >= nbmin && nb < k && nx < k {
for i = 0; i < k-nx; i += nb {
ib := min(k-i, nb)
impl.Dgelq2(ib, n-i, a[i*lda+i:], lda, tau[i:], work)
if i+ib < m {
impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib,
a[i*lda+i:], lda,
tau[i:],
work, ldwork)
impl.Dlarfb(blas.Right, blas.NoTrans, lapack.Forward, lapack.RowWise,
m-i-ib, n-i, ib,
a[i*lda+i:], lda,
work, ldwork,
a[(i+ib)*lda+i:], lda,
work[ib*ldwork:], ldwork)
}
}
}
// Perform unblocked LQ factorization on the remainder.
if i < k {
impl.Dgelq2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work)
}
}
+200
View File
@@ -0,0 +1,200 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/lapack"
)
// Dgels finds a minimum-norm solution based on the matrices a and b using the
// QR or LQ factorization. Dgels returns false if the matrix
// A is singular, and true if this solution was successfully found.
//
// The minimization problem solved depends on the input parameters.
//
// 1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2
// is minimized.
// 2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of
// A * X = B.
// 3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of
// A^T * X = B.
// 4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2
// is minimized.
// Note that the least-squares solutions (cases 1 and 3) perform the minimization
// per column of B. This is not the same as finding the minimum-norm matrix.
//
// The matrix a is a general matrix of size m×n and is modified during this call.
// The input matrix b is of size max(m,n)×nrhs, and serves two purposes. On entry,
// the elements of b specify the input matrix B. B has size m×nrhs if
// trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the
// leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans,
// this submatrix is of size n×nrhs, and of size m×nrhs otherwise.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic
// otherwise. A longer work will enable blocked algorithms to be called.
// In the special case that lwork == -1, work[0] will be set to the optimal working
// length.
func (impl Implementation) Dgels(trans blas.Transpose, m, n, nrhs int, a []float64, lda int, b []float64, ldb int, work []float64, lwork int) bool {
notran := trans == blas.NoTrans
checkMatrix(m, n, a, lda)
mn := min(m, n)
checkMatrix(mn, nrhs, b, ldb)
// Find optimal block size.
tpsd := true
if notran {
tpsd = false
}
var nb int
if m >= n {
nb = impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1)
if tpsd {
nb = max(nb, impl.Ilaenv(1, "DORMQR", "LN", m, nrhs, n, -1))
} else {
nb = max(nb, impl.Ilaenv(1, "DORMQR", "LT", m, nrhs, n, -1))
}
} else {
nb = impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1)
if tpsd {
nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LT", n, nrhs, m, -1))
} else {
nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LN", n, nrhs, m, -1))
}
}
if lwork == -1 {
work[0] = float64(max(1, mn+max(mn, nrhs)*nb))
return true
}
if len(work) < lwork {
panic(shortWork)
}
if lwork < mn+max(mn, nrhs) {
panic(badWork)
}
if m == 0 || n == 0 || nrhs == 0 {
impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb)
return true
}
// Scale the input matrices if they contain extreme values.
smlnum := dlamchS / dlamchP
bignum := 1 / smlnum
anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil)
var iascl int
if anrm > 0 && anrm < smlnum {
impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda)
iascl = 1
} else if anrm > bignum {
impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda)
} else if anrm == 0 {
// Matrix all zeros
impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb)
return true
}
brow := m
if tpsd {
brow = n
}
bnrm := impl.Dlange(lapack.MaxAbs, brow, nrhs, b, ldb, nil)
ibscl := 0
if bnrm > 0 && bnrm < smlnum {
impl.Dlascl(lapack.General, 0, 0, bnrm, smlnum, brow, nrhs, b, ldb)
ibscl = 1
} else if bnrm > bignum {
impl.Dlascl(lapack.General, 0, 0, bnrm, bignum, brow, nrhs, b, ldb)
ibscl = 2
}
// Solve the minimization problem using a QR or an LQ decomposition.
var scllen int
if m >= n {
impl.Dgeqrf(m, n, a, lda, work, work[mn:], lwork-mn)
if !tpsd {
impl.Dormqr(blas.Left, blas.Trans, m, nrhs, n,
a, lda,
work,
b, ldb,
work[mn:], lwork-mn)
ok := impl.Dtrtrs(blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs,
a, lda,
b, ldb)
if !ok {
return false
}
scllen = n
} else {
ok := impl.Dtrtrs(blas.Upper, blas.Trans, blas.NonUnit, n, nrhs,
a, lda,
b, ldb)
if !ok {
return false
}
for i := n; i < m; i++ {
for j := 0; j < nrhs; j++ {
b[i*ldb+j] = 0
}
}
impl.Dormqr(blas.Left, blas.NoTrans, m, nrhs, n,
a, lda,
work,
b, ldb,
work[mn:], lwork-mn)
scllen = m
}
} else {
impl.Dgelqf(m, n, a, lda, work, work[mn:], lwork-mn)
if !tpsd {
ok := impl.Dtrtrs(blas.Lower, blas.NoTrans, blas.NonUnit,
m, nrhs,
a, lda,
b, ldb)
if !ok {
return false
}
for i := m; i < n; i++ {
for j := 0; j < nrhs; j++ {
b[i*ldb+j] = 0
}
}
impl.Dormlq(blas.Left, blas.Trans, n, nrhs, m,
a, lda,
work,
b, ldb,
work[mn:], lwork-mn)
scllen = n
} else {
impl.Dormlq(blas.Left, blas.NoTrans, n, nrhs, m,
a, lda,
work,
b, ldb,
work[mn:], lwork-mn)
ok := impl.Dtrtrs(blas.Lower, blas.Trans, blas.NonUnit,
m, nrhs,
a, lda,
b, ldb)
if !ok {
return false
}
}
}
// Adjust answer vector based on scaling.
if iascl == 1 {
impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, scllen, nrhs, b, ldb)
}
if iascl == 2 {
impl.Dlascl(lapack.General, 0, 0, anrm, bignum, scllen, nrhs, b, ldb)
}
if ibscl == 1 {
impl.Dlascl(lapack.General, 0, 0, smlnum, bnrm, scllen, nrhs, b, ldb)
}
if ibscl == 2 {
impl.Dlascl(lapack.General, 0, 0, bignum, bnrm, scllen, nrhs, b, ldb)
}
return true
}
+57
View File
@@ -0,0 +1,57 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "github.com/gonum/blas"
// Dgeqr2 computes a QR factorization of the m×n matrix a.
//
// In a QR factorization, Q is an m×m orthonormal matrix, and R is an
// upper triangular m×n matrix.
//
// During Dgeqr2, a is modified to contain the information to construct Q and R.
// The upper triangle of a contains the matrix R. The lower triangular elements
// (not including the diagonal) contain the elementary reflectors. Tau is modified
// to contain the reflector scales. Tau must have length at least k = min(m,n), and
// this function will panic otherwise.
//
// The ith elementary reflector can be explicitly constructed by first extracting
// the
// v[j] = 0 j < i
// v[j] = i j == i
// v[j] = a[i*lda+j] j > i
// and computing h_i = I - tau[i] * v * v^T.
//
// The orthonormal matrix Q can be constucted from a product of these elementary
// reflectors, Q = H_1*H_2 ... H_k, where k = min(m,n).
//
// Work is temporary storage of length at least n and this function will panic otherwise.
func (impl Implementation) Dgeqr2(m, n int, a []float64, lda int, tau, work []float64) {
// TODO(btracey): This is oriented such that columns of a are eliminated.
// This likely could be re-arranged to take better advantage of row-major
// storage.
checkMatrix(m, n, a, lda)
if len(work) < n {
panic(badWork)
}
k := min(m, n)
if len(tau) < k {
panic(badTau)
}
for i := 0; i < k; i++ {
// Generate elementary reflector H(i).
a[i*lda+i], tau[i] = impl.Dlarfg(m-i, a[i*lda+i], a[min((i+1), m-1)*lda+i:], lda)
if i < n-1 {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(blas.Left, m-i, n-i-1,
a[i*lda+i:], lda,
tau[i],
a[i*lda+i+1:], lda,
work)
a[i*lda+i] = aii
}
}
}
+98
View File
@@ -0,0 +1,98 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/lapack"
)
// Dgeqrf computes the QR factorization of the m×n matrix a using a blocked
// algorithm. Please see the documentation for Dgeqr2 for a description of the
// parameters at entry and exit.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m and this function will panic otherwise.
// Dgeqrf is a blocked LQ factorization, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Dgelqf,
// the optimal work length will be stored into work[0].
//
// tau must be at least len min(m,n), and this function will panic otherwise.
func (impl Implementation) Dgeqrf(m, n int, a []float64, lda int, tau, work []float64, lwork int) {
// TODO(btracey): This algorithm is oriented for column-major storage.
// Consider modifying the algorithm to better suit row-major storage.
// nb is the optimal blocksize, i.e. the number of columns transformed at a time.
nb := impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1)
lworkopt := n * max(nb, 1)
lworkopt = max(n, lworkopt)
if lwork == -1 {
work[0] = float64(lworkopt)
return
}
checkMatrix(m, n, a, lda)
if len(work) < lwork {
panic(shortWork)
}
if lwork < n {
panic(badWork)
}
k := min(m, n)
if len(tau) < k {
panic(badTau)
}
if k == 0 {
return
}
nbmin := 2 // Minimal number of blocks
var nx int // Use unblocked (unless changed in the next for loop)
iws := n
ldwork := nb
// Only consider blocked if the suggested number of blocks is > 1 and the
// number of columns is sufficiently large.
if nb > 1 && k > nb {
// nx is the crossover point. Above this value the blocked routine should be used.
nx = max(0, impl.Ilaenv(3, "DGEQRF", " ", m, n, -1, -1))
if k > nx {
iws = ldwork * n
if lwork < iws {
// Not enough workspace to use the optimal number of blocks. Instead,
// get the maximum allowable number of blocks.
nb = lwork / n
nbmin = max(2, impl.Ilaenv(2, "DGEQRF", " ", m, n, -1, -1))
}
}
}
for i := range work {
work[i] = 0
}
// Compute QR using a blocked algorithm.
var i int
if nb >= nbmin && nb < k && nx < k {
for i = 0; i < k-nx; i += nb {
ib := min(k-i, nb)
// Compute the QR factorization of the current block.
impl.Dgeqr2(m-i, ib, a[i*lda+i:], lda, tau[i:], work)
if i+ib < n {
// Form the triangular factor of the block reflector and apply H^T
// In Dlarft, work becomes the T matrix.
impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib,
a[i*lda+i:], lda,
tau[i:],
work, ldwork)
impl.Dlarfb(blas.Left, blas.Trans, lapack.Forward, lapack.ColumnWise,
m-i, n-i-ib, ib,
a[i*lda+i:], lda,
work, ldwork,
a[i*lda+i+ib:], lda,
work[ib*ldwork:], ldwork)
}
}
}
// Call unblocked code on the remaining columns.
if i < k {
impl.Dgeqr2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work)
}
}
+76
View File
@@ -0,0 +1,76 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"math"
"github.com/gonum/lapack"
)
// Dlange computes the matrix norm of the general m×n matrix a. The input norm
// specifies the norm computed.
// lapack.MaxAbs: the maximum absolute value of an element.
// lapack.MaxColumnSum: the maximum column sum of the absolute values of the entries.
// lapack.MaxRowSum: the maximum row sum of the absolute values of the entries.
// lapack.Frobenius: the square root of the sum of the squares of the entries.
// If norm == lapack.MaxColumnSum, work must be of length n, and this function will panic otherwise.
// There are no restrictions on work for the other matrix norms.
func (impl Implementation) Dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int, work []float64) float64 {
// TODO(btracey): These should probably be refactored to use BLAS calls.
checkMatrix(m, n, a, lda)
if m == 0 && n == 0 {
return 0
}
if norm == lapack.MaxAbs {
var value float64
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
value = math.Max(value, math.Abs(a[i*lda+j]))
}
}
return value
}
if norm == lapack.MaxColumnSum {
if len(work) < n {
panic(badWork)
}
for i := 0; i < n; i++ {
work[i] = 0
}
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
work[j] += math.Abs(a[i*lda+j])
}
}
var value float64
for i := 0; i < n; i++ {
value = math.Max(value, work[i])
}
return value
}
if norm == lapack.MaxRowSum {
var value float64
for i := 0; i < m; i++ {
var sum float64
for j := 0; j < n; j++ {
sum += math.Abs(a[i*lda+j])
}
value = math.Max(value, sum)
}
return value
}
if norm == lapack.NormFrob {
var value float64
scale := 0.0
sum := 1.0
for i := 0; i < m; i++ {
scale, sum = impl.Dlassq(n, a[i*lda:], 1, scale, sum)
}
value = scale * math.Sqrt(sum)
return value
}
panic("lapack: bad matrix norm")
}
+12
View File
@@ -0,0 +1,12 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "math"
// Dlapy2 is the LAPACK version of math.Hypot.
func (Implementation) Dlapy2(x, y float64) float64 {
return math.Hypot(x, y)
}
+82
View File
@@ -0,0 +1,82 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
)
// Dlarf applies an elementary reflector to a general rectangular matrix c.
// This computes
// c = h * c if side == Left
// c = c * h if side == right
// where
// h = 1 - tau * v * v^T
// and c is an m * n matrix.
//
// Work is temporary storage of length at least m if side == Left and at least
// n if side == Right. This function will panic if this length requirement is not met.
func (impl Implementation) Dlarf(side blas.Side, m, n int, v []float64, incv int, tau float64, c []float64, ldc int, work []float64) {
applyleft := side == blas.Left
if (applyleft && len(work) < n) || (!applyleft && len(work) < m) {
panic(badWork)
}
checkMatrix(m, n, c, ldc)
// v has length m if applyleft and n otherwise.
lenV := n
if applyleft {
lenV = m
}
checkVector(lenV, v, incv)
lastv := 0 // last non-zero element of v
lastc := 0 // last non-zero row/column of c
if tau != 0 {
var i int
if applyleft {
lastv = m - 1
} else {
lastv = n - 1
}
if incv > 0 {
i = lastv * incv
}
// Look for the last non-zero row in v.
for lastv >= 0 && v[i] == 0 {
lastv--
i -= incv
}
if applyleft {
// Scan for the last non-zero column in C[0:lastv, :]
lastc = impl.Iladlc(lastv+1, n, c, ldc)
} else {
// Scan for the last non-zero row in C[:, 0:lastv]
lastc = impl.Iladlr(m, lastv+1, c, ldc)
}
}
if lastv == -1 || lastc == -1 {
return
}
// Sometimes 1-indexing is nicer ...
bi := blas64.Implementation()
if applyleft {
// Form H * C
// w[0:lastc+1] = c[1:lastv+1, 1:lastc+1]^T * v[1:lastv+1,1]
bi.Dgemv(blas.Trans, lastv+1, lastc+1, 1, c, ldc, v, incv, 0, work, 1)
// c[0: lastv, 0: lastc] = c[...] - w[0:lastv, 1] * v[1:lastc, 1]^T
bi.Dger(lastv+1, lastc+1, -tau, v, incv, work, 1, c, ldc)
return
}
// Form C*H
// w[0:lastc+1,1] := c[0:lastc+1,0:lastv+1] * v[0:lastv+1,1]
bi.Dgemv(blas.NoTrans, lastc+1, lastv+1, 1, c, ldc, v, incv, 0, work, 1)
// c[0:lastc+1,0:lastv+1] = c[...] - w[0:lastc+1,0] * v[0:lastv+1,0]^T
bi.Dger(lastc+1, lastv+1, -tau, work, 1, v, incv, c, ldc)
}
+424
View File
@@ -0,0 +1,424 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
"github.com/gonum/lapack"
)
// Dlarfb applies a block reflector to a matrix.
//
// In the call to Dlarfb, the mxn c is multiplied by the implicitly defined matrix h as follows:
// c = h * c if side == Left and trans == NoTrans
// c = c * h if side == Right and trans == NoTrans
// c = h^T * c if side == Left and trans == Trans
// c = c * h^t if side == Right and trans == Trans
// h is a product of elementary reflectors. direct sets the direction of multiplication
// h = h_1 * h_2 * ... * h_k if direct == Forward
// h = h_k * h_k-1 * ... * h_1 if direct == Backward
// The combination of direct and store defines the orientation of the elementary
// reflectors. In all cases the ones on the diagonal are implicitly represented.
//
// If direct == lapack.Forward and store == lapack.ColumnWise
// V = ( 1 )
// ( v1 1 )
// ( v1 v2 1 )
// ( v1 v2 v3 )
// ( v1 v2 v3 )
// If direct == lapack.Forward and store == lapack.RowWise
// V = ( 1 v1 v1 v1 v1 )
// ( 1 v2 v2 v2 )
// ( 1 v3 v3 )
// If direct == lapack.Backward and store == lapack.ColumnWise
// V = ( v1 v2 v3 )
// ( v1 v2 v3 )
// ( 1 v2 v3 )
// ( 1 v3 )
// ( 1 )
// If direct == lapack.Backward and store == lapack.RowWise
// V = ( v1 v1 1 )
// ( v2 v2 v2 1 )
// ( v3 v3 v3 v3 1 )
// An elementary reflector can be explicitly constructed by extracting the
// corresponding elements of v, placing a 1 where the diagonal would be, and
// placing zeros in the remaining elements.
//
// t is a k×k matrix containing the block reflector, and this function will panic
// if t is not of sufficient size. See Dlarft for more information.
//
// Work is a temporary storage matrix with stride ldwork.
// Work must be of size at least n×k side == Left and m×k if side == Right, and
// this function will panic if this size is not met.
func (Implementation) Dlarfb(side blas.Side, trans blas.Transpose, direct lapack.Direct,
store lapack.StoreV, m, n, k int, v []float64, ldv int, t []float64, ldt int,
c []float64, ldc int, work []float64, ldwork int) {
checkMatrix(m, n, c, ldc)
if m == 0 || n == 0 {
return
}
if k < 0 {
panic("lapack: negative number of transforms")
}
if side != blas.Left && side != blas.Right {
panic(badSide)
}
if trans != blas.Trans && trans != blas.NoTrans {
panic(badTrans)
}
if direct != lapack.Forward && direct != lapack.Backward {
panic(badDirect)
}
if store != lapack.ColumnWise && store != lapack.RowWise {
panic(badStore)
}
rowsWork := n
if side == blas.Right {
rowsWork = m
}
checkMatrix(rowsWork, k, work, ldwork)
bi := blas64.Implementation()
transt := blas.Trans
if trans == blas.Trans {
transt = blas.NoTrans
}
// TODO(btracey): This follows the original Lapack code where the
// elements are copied into the columns of the working array. The
// loops should go in the other direction so the data is written
// into the rows of work so the copy is not strided. A bigger change
// would be to replace work with work^T, but benchmarks would be
// needed to see if the change is merited.
if store == lapack.ColumnWise {
if direct == lapack.Forward {
// V1 is the first k rows of C. V2 is the remaining rows.
if side == blas.Left {
// W = C^T V = C1^T V1 + C2^T V2 (stored in work).
// W = C1.
for j := 0; j < k; j++ {
bi.Dcopy(n, c[j*ldc:], 1, work[j:], ldwork)
}
// W = W * V1.
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit,
n, k, 1,
v, ldv,
work, ldwork)
if m > k {
// W = W + C2^T V2.
bi.Dgemm(blas.Trans, blas.NoTrans, n, k, m-k,
1, c[k*ldc:], ldc, v[k*ldv:], ldv,
1, work, ldwork)
}
// W = W * T^T or W * T.
bi.Dtrmm(blas.Right, blas.Upper, transt, blas.NonUnit, n, k,
1, t, ldt,
work, ldwork)
// C -= V * W^T.
if m > k {
// C2 -= V2 * W^T.
bi.Dgemm(blas.NoTrans, blas.Trans, m-k, n, k,
-1, v[k*ldv:], ldv, work, ldwork,
1, c[k*ldc:], ldc)
}
// W *= V1^T.
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, n, k,
1, v, ldv,
work, ldwork)
// C1 -= W^T.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < n; i++ {
for j := 0; j < k; j++ {
c[j*ldc+i] -= work[i*ldwork+j]
}
}
return
}
// Form C = C * H or C * H^T, where C = (C1 C2).
// W = C1.
for i := 0; i < k; i++ {
bi.Dcopy(m, c[i:], ldc, work[i:], ldwork)
}
// W *= V1.
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, m, k,
1, v, ldv,
work, ldwork)
if n > k {
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, k, n-k,
1, c[k:], ldc, v[k*ldv:], ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Upper, trans, blas.NonUnit, m, k,
1, t, ldt,
work, ldwork)
if n > k {
bi.Dgemm(blas.NoTrans, blas.Trans, m, n-k, k,
-1, work, ldwork, v[k*ldv:], ldv,
1, c[k:], ldc)
}
// C -= W * V^T.
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, m, k,
1, v, ldv,
work, ldwork)
// C -= W.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < m; i++ {
for j := 0; j < k; j++ {
c[i*ldc+j] -= work[i*ldwork+j]
}
}
return
}
// V = (V1)
// = (V2) (last k rows)
// Where V2 is unit upper triangular.
if side == blas.Left {
// Form H * C or
// W = C^T V.
// W = C2^T.
for j := 0; j < k; j++ {
bi.Dcopy(n, c[(m-k+j)*ldc:], 1, work[j:], ldwork)
}
// W *= V2.
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, n, k,
1, v[(m-k)*ldv:], ldv,
work, ldwork)
if m > k {
// W += C1^T * V1.
bi.Dgemm(blas.Trans, blas.NoTrans, n, k, m-k,
1, c, ldc, v, ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Lower, transt, blas.NonUnit, n, k,
1, t, ldt,
work, ldwork)
// C -= V * W^T.
if m > k {
bi.Dgemm(blas.NoTrans, blas.Trans, m-k, n, k,
-1, v, ldv, work, ldwork,
1, c, ldc)
}
// W *= V2^T.
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, n, k,
1, v[(m-k)*ldv:], ldv,
work, ldwork)
// C2 -= W^T.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < n; i++ {
for j := 0; j < k; j++ {
c[(m-k+j)*ldc+i] -= work[i*ldwork+j]
}
}
return
}
// Form C * H or C * H^T where C = (C1 C2).
// W = C * V.
// W = C2.
for j := 0; j < k; j++ {
bi.Dcopy(m, c[n-k+j:], ldc, work[j:], ldwork)
}
// W = W * V2.
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, m, k,
1, v[(n-k)*ldv:], ldv,
work, ldwork)
if n > k {
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, k, n-k,
1, c, ldc, v, ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Lower, trans, blas.NonUnit, m, k,
1, t, ldt,
work, ldwork)
// C -= W * V^T.
if n > k {
// C1 -= W * V1^T.
bi.Dgemm(blas.NoTrans, blas.Trans, m, n-k, k,
-1, work, ldwork, v, ldv,
1, c, ldc)
}
// W *= V2^T.
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, m, k,
1, v[(n-k)*ldv:], ldv,
work, ldwork)
// C2 -= W.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < m; i++ {
for j := 0; j < k; j++ {
c[i*ldc+n-k+j] -= work[i*ldwork+j]
}
}
return
}
// Store = Rowwise.
if direct == lapack.Forward {
// V = (V1 V2) where v1 is unit upper triangular.
if side == blas.Left {
// Form H * C or H^T * C where C = (C1; C2).
// W = C^T * V^T.
// W = C1^T.
for j := 0; j < k; j++ {
bi.Dcopy(n, c[j*ldc:], 1, work[j:], ldwork)
}
// W *= V1^T.
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, n, k,
1, v, ldv,
work, ldwork)
if m > k {
bi.Dgemm(blas.Trans, blas.Trans, n, k, m-k,
1, c[k*ldc:], ldc, v[k:], ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Upper, transt, blas.NonUnit, n, k,
1, t, ldt,
work, ldwork)
// C -= V^T * W^T.
if m > k {
bi.Dgemm(blas.Trans, blas.Trans, m-k, n, k,
-1, v[k:], ldv, work, ldwork,
1, c[k*ldc:], ldc)
}
// W *= V1.
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, n, k,
1, v, ldv,
work, ldwork)
// C1 -= W^T.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < n; i++ {
for j := 0; j < k; j++ {
c[j*ldc+i] -= work[i*ldwork+j]
}
}
return
}
// Form C * H or C * H^T where C = (C1 C2).
// W = C * V^T.
// W = C1.
for j := 0; j < k; j++ {
bi.Dcopy(m, c[j:], ldc, work[j:], ldwork)
}
// W *= V1^T.
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, m, k,
1, v, ldv,
work, ldwork)
if n > k {
bi.Dgemm(blas.NoTrans, blas.Trans, m, k, n-k,
1, c[k:], ldc, v[k:], ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Upper, trans, blas.NonUnit, m, k,
1, t, ldt,
work, ldwork)
// C -= W * V.
if n > k {
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n-k, k,
-1, work, ldwork, v[k:], ldv,
1, c[k:], ldc)
}
// W *= V1.
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, m, k,
1, v, ldv,
work, ldwork)
// C1 -= W.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < m; i++ {
for j := 0; j < k; j++ {
c[i*ldc+j] -= work[i*ldwork+j]
}
}
return
}
// V = (V1 V2) where V2 is the last k columns and is lower unit triangular.
if side == blas.Left {
// Form H * C or H^T C where C = (C1 ; C2).
// W = C^T * V^T.
// W = C2^T.
for j := 0; j < k; j++ {
bi.Dcopy(n, c[(m-k+j)*ldc:], 1, work[j:], ldwork)
}
// W *= V2^T.
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, n, k,
1, v[m-k:], ldv,
work, ldwork)
if m > k {
bi.Dgemm(blas.Trans, blas.Trans, n, k, m-k,
1, c, ldc, v, ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Lower, transt, blas.NonUnit, n, k,
1, t, ldt,
work, ldwork)
// C -= V^T * W^T.
if m > k {
bi.Dgemm(blas.Trans, blas.Trans, m-k, n, k,
-1, v, ldv, work, ldwork,
1, c, ldc)
}
// W *= V2.
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, n, k,
1, v[m-k:], ldv,
work, ldwork)
// C2 -= W^T.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < n; i++ {
for j := 0; j < k; j++ {
c[(m-k+j)*ldc+i] -= work[i*ldwork+j]
}
}
return
}
// Form C * H or C * H^T where C = (C1 C2).
// W = C * V^T.
// W = C2.
for j := 0; j < k; j++ {
bi.Dcopy(m, c[n-k+j:], ldc, work[j:], ldwork)
}
// W *= V2^T.
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, m, k,
1, v[n-k:], ldv,
work, ldwork)
if n > k {
bi.Dgemm(blas.NoTrans, blas.Trans, m, k, n-k,
1, c, ldc, v, ldv,
1, work, ldwork)
}
// W *= T or T^T.
bi.Dtrmm(blas.Right, blas.Lower, trans, blas.NonUnit, m, k,
1, t, ldt,
work, ldwork)
// C -= W * V.
if n > k {
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n-k, k,
-1, work, ldwork, v, ldv,
1, c, ldc)
}
// W *= V2.
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, m, k,
1, v[n-k:], ldv,
work, ldwork)
// C1 -= W.
// TODO(btracey): This should use blas.Axpy.
for i := 0; i < m; i++ {
for j := 0; j < k; j++ {
c[i*ldc+n-k+j] -= work[i*ldwork+j]
}
}
}
+60
View File
@@ -0,0 +1,60 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"math"
"github.com/gonum/blas/blas64"
)
// Dlarfg generates an elementary reflector for a Householder matrix. It creates
// a real elementary reflector of order n such that
// H * (alpha) = (beta)
// ( x) ( 0)
// H^T * H = I
// H is represented in the form
// H = 1 - tau * (1; v) * (1 v^T)
// where tau is a real scalar.
//
// On entry, x contains the vector x, on exit it contains v.
func (impl Implementation) Dlarfg(n int, alpha float64, x []float64, incX int) (beta, tau float64) {
if n < 0 {
panic(nLT0)
}
if n <= 1 {
return alpha, 0
}
checkVector(n-1, x, incX)
bi := blas64.Implementation()
xnorm := bi.Dnrm2(n-1, x, incX)
if xnorm == 0 {
return alpha, 0
}
beta = -math.Copysign(impl.Dlapy2(alpha, xnorm), alpha)
safmin := dlamchS / dlamchE
knt := 0
if math.Abs(beta) < safmin {
// xnorm and beta may be innacurate, scale x and recompute.
rsafmn := 1 / safmin
for {
knt++
bi.Dscal(n-1, rsafmn, x, incX)
beta *= rsafmn
alpha *= rsafmn
if math.Abs(beta) >= safmin {
break
}
}
xnorm = bi.Dnrm2(n-1, x, incX)
beta = -math.Copysign(impl.Dlapy2(alpha, xnorm), alpha)
}
tau = (beta - alpha) / beta
bi.Dscal(n-1, 1/(alpha-beta), x, incX)
for j := 0; j < knt; j++ {
beta *= safmin
}
return beta, tau
}
+148
View File
@@ -0,0 +1,148 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
"github.com/gonum/lapack"
)
// Dlarft forms the triangular factor t of a block reflector, storing the answer
// in t.
// H = 1 - V * T * V^T if store == lapack.ColumnWise
// H = 1 - V^T * T * V if store == lapack.RowWise
// H is defined by a product of the elementary reflectors where
// H = H_1 * H_2 * ... * H_k if direct == lapack.Forward
// H = H_k * H_k-1 * ... * H_1 if direct == lapack.Backward
//
// t is a k×k triangular matrix. t is upper triangular if direct = lapack.Forward
// and lower triangular otherwise. This function will panic if t is not of
// sufficient size.
//
// store describes the storage of the elementary reflectors in v. Please see
// Dlarfb for a description of layout.
//
// tau contains the scalar factor of the elementary reflectors h.
func (Implementation) Dlarft(direct lapack.Direct, store lapack.StoreV, n, k int,
v []float64, ldv int, tau []float64, t []float64, ldt int) {
if n == 0 {
return
}
if n < 0 || k < 0 {
panic(negDimension)
}
if direct != lapack.Forward && direct != lapack.Backward {
panic(badDirect)
}
if store != lapack.RowWise && store != lapack.ColumnWise {
panic(badStore)
}
if len(tau) < k {
panic(badTau)
}
checkMatrix(k, k, t, ldt)
bi := blas64.Implementation()
// TODO(btracey): There are a number of minor obvious loop optimizations here.
// TODO(btracey): It may be possible to rearrange some of the code so that
// index of 1 is more common in the Dgemv.
if direct == lapack.Forward {
prevlastv := n - 1
for i := 0; i < k; i++ {
prevlastv = max(i, prevlastv)
if tau[i] == 0 {
for j := 0; j <= i; j++ {
t[j*ldt+i] = 0
}
continue
}
var lastv int
if store == lapack.ColumnWise {
// skip trailing zeros
for lastv = n - 1; lastv >= i+1; lastv-- {
if v[lastv*ldv+i] != 0 {
break
}
}
for j := 0; j < i; j++ {
t[j*ldt+i] = -tau[i] * v[i*ldv+j]
}
j := min(lastv, prevlastv)
bi.Dgemv(blas.Trans, j-i, i,
-tau[i], v[(i+1)*ldv:], ldv, v[(i+1)*ldv+i:], ldv,
1, t[i:], ldt)
} else {
for lastv = n - 1; lastv >= i+1; lastv-- {
if v[i*ldv+lastv] != 0 {
break
}
}
for j := 0; j < i; j++ {
t[j*ldt+i] = -tau[i] * v[j*ldv+i]
}
j := min(lastv, prevlastv)
bi.Dgemv(blas.NoTrans, i, j-i,
-tau[i], v[i+1:], ldv, v[i*ldv+i+1:], 1,
1, t[i:], ldt)
}
bi.Dtrmv(blas.Upper, blas.NoTrans, blas.NonUnit, i, t, ldt, t[i:], ldt)
t[i*ldt+i] = tau[i]
if i > 1 {
prevlastv = max(prevlastv, lastv)
} else {
prevlastv = lastv
}
}
return
}
prevlastv := 0
for i := k - 1; i >= 0; i-- {
if tau[i] == 0 {
for j := i; j < k; j++ {
t[j*ldt+i] = 0
}
continue
}
var lastv int
if i < k-1 {
if store == lapack.ColumnWise {
for lastv = 0; lastv < i; lastv++ {
if v[lastv*ldv+i] != 0 {
break
}
}
for j := i + 1; j < k; j++ {
t[j*ldt+i] = -tau[i] * v[(n-k+i)*ldv+j]
}
j := max(lastv, prevlastv)
bi.Dgemv(blas.Trans, n-k+i-j, k-i-1,
-tau[i], v[j*ldv+i+1:], ldv, v[j*ldv+i:], ldv,
1, t[(i+1)*ldt+i:], ldt)
} else {
for lastv := 0; lastv < i; lastv++ {
if v[i*ldv+lastv] != 0 {
break
}
}
for j := i + 1; j < k; j++ {
t[j*ldt+i] = -tau[i] * v[j*ldv+n-k+i]
}
j := max(lastv, prevlastv)
bi.Dgemv(blas.NoTrans, k-i-1, n-k+i-j,
-tau[i], v[(i+1)*ldv+j:], ldv, v[i*ldv+j:], 1,
1, t[(i+1)*ldt+i:], ldt)
}
bi.Dtrmv(blas.Lower, blas.NoTrans, blas.NonUnit, k-i-1,
t[(i+1)*ldt+i+1:], ldt,
t[(i+1)*ldt+i:], ldt)
if i > 0 {
prevlastv = min(prevlastv, lastv)
} else {
prevlastv = lastv
}
}
t[i*ldt+i] = tau[i]
}
}
+72
View File
@@ -0,0 +1,72 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"math"
"github.com/gonum/lapack"
)
// Dlascl multiplies a rectangular matrix by a scalar.
func (impl Implementation) Dlascl(kind lapack.MatrixType, kl, ku int, cfrom, cto float64, m, n int, a []float64, lda int) {
checkMatrix(m, n, a, lda)
if cfrom == 0 {
panic("dlascl: zero divisor")
}
if math.IsNaN(cfrom) || math.IsNaN(cto) {
panic("dlascl: NaN scale factor")
}
if n == 0 || m == 0 {
return
}
smlnum := dlamchS
bignum := 1 / smlnum
cfromc := cfrom
ctoc := cto
cfrom1 := cfromc * smlnum
for {
var done bool
var mul, ctol float64
if cfrom1 == cfromc {
// cfromc is inf
mul = ctoc / cfromc
done = true
ctol = ctoc
} else {
ctol = ctoc / bignum
if ctol == ctoc {
// ctoc is either 0 or inf.
mul = ctoc
done = true
cfromc = 1
} else if math.Abs(cfrom1) > math.Abs(ctoc) && ctoc != 0 {
mul = smlnum
done = false
cfromc = cfrom1
} else if math.Abs(ctol) > math.Abs(cfromc) {
mul = bignum
done = false
ctoc = ctol
} else {
mul = ctoc / cfromc
done = true
}
}
switch kind {
default:
panic("lapack: not implemented")
case lapack.General:
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
a[i*lda+j] = a[i*lda+j] * mul
}
}
}
if done {
break
}
}
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "github.com/gonum/blas"
// Dlaset sets the off-diagonal elements of a to alpha, and the diagonal elements
// of a to beta. If uplo == blas.Upper, only the upper diagonal elements are set.
// If uplo == blas.Lower, only the lower diagonal elements are set. If uplo is
// otherwise, all of the elements of a are set.
func (impl Implementation) Dlaset(uplo blas.Uplo, m, n int, alpha, beta float64, a []float64, lda int) {
checkMatrix(m, n, a, lda)
if uplo == blas.Upper {
for i := 0; i < m; i++ {
for j := i + 1; j < n; j++ {
a[i*lda+j] = alpha
}
}
} else if uplo == blas.Lower {
for i := 0; i < m; i++ {
for j := 0; j < i; j++ {
a[i*lda+j] = alpha
}
}
} else {
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
a[i*lda+j] = alpha
}
}
}
for i := 0; i < min(m, n); i++ {
a[i*lda+i] = beta
}
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "math"
// Dlassq updates a sum of squares in scaled form. The input parameters scale and
// sumsq represent the current scale and total sum of squares. These values are
// updated with the information in the first n elements of the vector specified
// by x and incX.
func (impl Implementation) Dlassq(n int, x []float64, incx int, scale float64, sumsq float64) (scl, smsq float64) {
if n <= 0 {
return scale, sumsq
}
for ix := 0; ix <= (n-1)*incx; ix += incx {
absxi := math.Abs(x[ix])
if absxi > 0 || math.IsNaN(absxi) {
if scale < absxi {
sumsq = 1 + sumsq*(scale/absxi)*(scale/absxi)
scale = absxi
} else {
sumsq += (absxi / scale) * (absxi / scale)
}
}
}
return scale, sumsq
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package native is a pure-go implementation of the LAPACK API. The LAPACK API defines
// a set of algorithms for advanced matrix operations.
//
// The function definitions and implementations follow that of the netlib reference
// implementation. Please see http://www.netlib.org/lapack/explore-html/ for more
// information, and http://www.netlib.org/lapack/explore-html/d4/de1/_l_i_c_e_n_s_e_source.html
// for more license information.
//
// Slice function arguments frequently represent vectors and matrices. The data
// layout is identical to that found in https://godoc.org/github.com/gonum/blas/native.
//
// Most LAPACK functions are built on top the routines defined in the BLAS API,
// and as such the computation time for many LAPACK functions is
// dominated by BLAS calls. Here, BLAS is accessed through the
// the blas64 package (https://godoc.org/github.com/gonum/blas/blas64). In particular,
// this implies that an external BLAS library will be used if it is
// registered in blas64.
//
// The full LAPACK capability has not been implemented at present. The full
// API is very large, containing approximately 200 functions for double precision
// alone. Future additions will be focused on supporting the gonum matrix
// package (https://godoc.org/github.com/gonum/matrix/mat64), though pull requests
// with implementations and tests for LAPACK function are encouraged.
package native
+86
View File
@@ -0,0 +1,86 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "github.com/gonum/blas"
// Dorm2r multiplies a general matrix c by an orthogonal matrix from a QR factorization
// determined by Dgeqrf.
// C = Q * C if side == blas.Left and trans == blas.NoTrans
// C = Q^T * C if side == blas.Left and trans == blas.Trans
// C = C * Q if side == blas.Right and trans == blas.NoTrans
// C = C * Q^T if side == blas.Right and trans == blas.Trans
// If side == blas.Left, a is a matrix of size m×k, and if side == blas.Right
// a is of size n×k.
//
// Tau contains the householder factors and is of length at least k and this function
// will panic otherwise.
//
// Work is temporary storage of length at least n if side == blas.Left
// and at least m if side == blas.Right and this function will panic otherwise.
func (impl Implementation) Dorm2r(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) {
if side != blas.Left && side != blas.Right {
panic(badSide)
}
if trans != blas.Trans && trans != blas.NoTrans {
panic(badTrans)
}
left := side == blas.Left
notran := trans == blas.NoTrans
if left {
// Q is m x m
checkMatrix(m, k, a, lda)
if len(work) < n {
panic(badWork)
}
} else {
// Q is n x n
checkMatrix(n, k, a, lda)
if len(work) < m {
panic(badWork)
}
}
checkMatrix(m, n, c, ldc)
if m == 0 || n == 0 || k == 0 {
return
}
if len(tau) < k {
panic(badTau)
}
if left {
if notran {
for i := k - 1; i >= 0; i-- {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m-i, n, a[i*lda+i:], lda, tau[i], c[i*ldc:], ldc, work)
a[i*lda+i] = aii
}
return
}
for i := 0; i < k; i++ {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m-i, n, a[i*lda+i:], lda, tau[i], c[i*ldc:], ldc, work)
a[i*lda+i] = aii
}
return
}
if notran {
for i := 0; i < k; i++ {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m, n-i, a[i*lda+i:], lda, tau[i], c[i:], ldc, work)
a[i*lda+i] = aii
}
return
}
for i := k - 1; i >= 0; i-- {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m, n-i, a[i*lda+i:], lda, tau[i], c[i:], ldc, work)
a[i*lda+i] = aii
}
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import "github.com/gonum/blas"
// Dorml2 multiplies a general matrix c by an orthogonal matrix from an LQ factorization
// determined by Dgelqf.
// C = Q * C if side == blas.Left and trans == blas.NoTrans
// C = Q^T * C if side == blas.Left and trans == blas.Trans
// C = C * Q if side == blas.Right and trans == blas.NoTrans
// C = C * Q^T if side == blas.Right and trans == blas.Trans
// If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right
// a is of size k×n.
//
//
// Tau contains the householder factors and is of length at least k and this function will
// panic otherwise.
//
// Work is temporary storage of length at least n if side == blas.Left
// and at least m if side == blas.Right and this function will panic otherwise.
func (impl Implementation) Dorml2(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) {
if side != blas.Left && side != blas.Right {
panic(badSide)
}
if trans != blas.Trans && trans != blas.NoTrans {
panic(badTrans)
}
left := side == blas.Left
notran := trans == blas.NoTrans
if left {
checkMatrix(k, m, a, lda)
if len(work) < n {
panic(badWork)
}
} else {
checkMatrix(k, n, a, lda)
if len(work) < m {
panic(badWork)
}
}
checkMatrix(m, n, c, ldc)
if m == 0 || n == 0 || k == 0 {
return
}
switch {
case left && notran:
for i := 0; i < k; i++ {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m-i, n, a[i*lda+i:], 1, tau[i], c[i*ldc:], ldc, work)
a[i*lda+i] = aii
}
return
case left && !notran:
for i := k - 1; i >= 0; i-- {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m-i, n, a[i*lda+i:], 1, tau[i], c[i*ldc:], ldc, work)
a[i*lda+i] = aii
}
return
case !left && notran:
for i := k - 1; i >= 0; i-- {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m, n-i, a[i*lda+i:], 1, tau[i], c[i:], ldc, work)
a[i*lda+i] = aii
}
return
case !left && !notran:
for i := 0; i < k; i++ {
aii := a[i*lda+i]
a[i*lda+i] = 1
impl.Dlarf(side, m, n-i, a[i*lda+i:], 1, tau[i], c[i:], ldc, work)
a[i*lda+i] = aii
}
return
}
}
+155
View File
@@ -0,0 +1,155 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/lapack"
)
// Dormlq multiplies the matrix c by the othogonal matrix q defined by the
// slices a and tau. A and tau are as returned from Dgelqf.
// C = Q * C if side == blas.Left and trans == blas.NoTrans
// C = Q^T * C if side == blas.Left and trans == blas.Trans
// C = C * Q if side == blas.Right and trans == blas.NoTrans
// C = C * Q^T if side == blas.Right and trans == blas.Trans
// If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right
// a is of size k×n. This uses a blocked algorithm.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
// and this function will panic otherwise.
// Dormlq uses a block algorithm, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Dormlq,
// the optimal work length will be stored into work[0].
//
// Tau contains the householder scales and must have length at least k, and
// this function will panic otherwise.
func (impl Implementation) Dormlq(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) {
if side != blas.Left && side != blas.Right {
panic(badSide)
}
if trans != blas.Trans && trans != blas.NoTrans {
panic(badTrans)
}
left := side == blas.Left
notran := trans == blas.NoTrans
if left {
checkMatrix(k, m, a, lda)
} else {
checkMatrix(k, n, a, lda)
}
checkMatrix(m, n, c, ldc)
if len(tau) < k {
panic(badTau)
}
const nbmax = 64
nw := n
if !left {
nw = m
}
opts := string(side) + string(trans)
nb := min(nbmax, impl.Ilaenv(1, "DORMLQ", opts, m, n, k, -1))
lworkopt := max(1, nw) * nb
if lwork == -1 {
work[0] = float64(lworkopt)
return
}
if left {
if lwork < n {
panic(badWork)
}
} else {
if lwork < m {
panic(badWork)
}
}
if m == 0 || n == 0 || k == 0 {
return
}
nbmin := 2
ldwork := nb
if nb > 1 && nb < k {
iws := nw * nb
if lwork < iws {
nb = lwork / nw
nbmin = max(2, impl.Ilaenv(2, "DORMLQ", opts, m, n, k, -1))
}
}
if nb < nbmin || nb >= k {
// Call unblocked code
impl.Dorml2(side, trans, m, n, k, a, lda, tau, c, ldc, work)
return
}
ldt := nb
t := make([]float64, nb*ldt)
transt := blas.NoTrans
if notran {
transt = blas.Trans
}
switch {
case left && notran:
for i := 0; i < k; i += nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.RowWise, m-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m-i, n, ib,
a[i*lda+i:], lda,
t, ldt,
c[i*ldc:], ldc,
work, ldwork)
}
return
case left && !notran:
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.RowWise, m-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m-i, n, ib,
a[i*lda+i:], lda,
t, ldt,
c[i*ldc:], ldc,
work, ldwork)
}
return
case !left && notran:
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m, n-i, ib,
a[i*lda+i:], lda,
t, ldt,
c[i:], ldc,
work, ldwork)
}
return
case !left && !notran:
for i := 0; i < k; i += nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m, n-i, ib,
a[i*lda+i:], lda,
t, ldt,
c[i:], ldc,
work, ldwork)
}
return
}
}
+139
View File
@@ -0,0 +1,139 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/lapack"
)
// Dormqr multiplies the matrix c by the othogonal matrix q defined by the
// slices a and tau. A and tau are as returned from Dgeqrf.
// C = Q * C if side == blas.Left and trans == blas.NoTrans
// C = Q^T * C if side == blas.Left and trans == blas.Trans
// C = C * Q if side == blas.Right and trans == blas.NoTrans
// C = C * Q^T if side == blas.Right and trans == blas.Trans
// If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right
// a is of size k×n. This uses a blocked algorithm.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
// and this function will panic otherwise.
// Dormqr uses a block algorithm, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Dormqr,
// the optimal work length will be stored into work[0].
//
// Tau contains the householder scales and must have length at least k, and
// this function will panic otherwise.
func (impl Implementation) Dormqr(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) {
left := side == blas.Left
notran := trans == blas.NoTrans
if left {
checkMatrix(m, k, a, lda)
} else {
checkMatrix(n, k, a, lda)
}
checkMatrix(m, n, c, ldc)
const nbmax = 64
nw := n
if side == blas.Right {
nw = m
}
opts := string(side) + string(trans)
nb := min(nbmax, impl.Ilaenv(1, "DORMQR", opts, m, n, k, -1))
lworkopt := max(1, nw) * nb
if lwork == -1 {
work[0] = float64(lworkopt)
return
}
if left {
if lwork < n {
panic(badWork)
}
} else {
if lwork < m {
panic(badWork)
}
}
if m == 0 || n == 0 || k == 0 {
return
}
nbmin := 2
ldwork := nb
if nb > 1 && nb < k {
iws := nw * nb
if lwork < iws {
nb = lwork / nw
nbmin = max(2, impl.Ilaenv(2, "DORMQR", opts, m, n, k, -1))
}
}
if nb < nbmin || nb >= k {
// Call unblocked code
impl.Dorm2r(side, trans, m, n, k, a, lda, tau, c, ldc, work)
return
}
ldt := nb
t := make([]float64, nb*ldt)
switch {
case left && notran:
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m-i, n, ib,
a[i*lda+i:], lda,
t, ldt,
c[i*ldc:], ldc,
work, ldwork)
}
return
case left && !notran:
for i := 0; i < k; i += nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m-i, n, ib,
a[i*lda+i:], lda,
t, ldt,
c[i*ldc:], ldc,
work, ldwork)
}
return
case !left && notran:
for i := 0; i < k; i += nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.ColumnWise, n-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m, n-i, ib,
a[i*lda+i:], lda,
t, ldt,
c[i:], ldc,
work, ldwork)
}
return
case !left && !notran:
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
ib := min(nb, k-i)
impl.Dlarft(lapack.Forward, lapack.ColumnWise, n-i, ib,
a[i*lda+i:], lda,
tau[i:],
t, ldt)
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m, n-i, ib,
a[i*lda+i:], lda,
t, ldt,
c[i:], ldc,
work, ldwork)
}
return
}
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"math"
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
)
// Dpotf2 computes the cholesky decomposition of the symmetric positive definite
// matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix,
// and a = U^T U is stored in place into a. If ul == blas.Lower, then a = L L^T
// is computed and stored in-place into a. If a is not positive definite, false
// is returned. This is the unblocked version of the algorithm.
func (Implementation) Dpotf2(ul blas.Uplo, n int, a []float64, lda int) (ok bool) {
if ul != blas.Upper && ul != blas.Lower {
panic(badUplo)
}
if n < 0 {
panic(nLT0)
}
if lda < n {
panic(badLdA)
}
if n == 0 {
return true
}
bi := blas64.Implementation()
if ul == blas.Upper {
for j := 0; j < n; j++ {
ajj := a[j*lda+j]
if j != 0 {
ajj -= bi.Ddot(j, a[j:], lda, a[j:], lda)
}
if ajj <= 0 || math.IsNaN(ajj) {
a[j*lda+j] = ajj
return false
}
ajj = math.Sqrt(ajj)
a[j*lda+j] = ajj
if j < n-1 {
bi.Dgemv(blas.Trans, j, n-j-1,
-1, a[j+1:], lda, a[j:], lda,
1, a[j*lda+j+1:], 1)
bi.Dscal(n-j-1, 1/ajj, a[j*lda+j+1:], 1)
}
}
return true
}
for j := 0; j < n; j++ {
ajj := a[j*lda+j]
if j != 0 {
ajj -= bi.Ddot(j, a[j*lda:], 1, a[j*lda:], 1)
}
if ajj <= 0 || math.IsNaN(ajj) {
a[j*lda+j] = ajj
return false
}
ajj = math.Sqrt(ajj)
a[j*lda+j] = ajj
if j < n-1 {
bi.Dgemv(blas.NoTrans, n-j-1, j,
-1, a[(j+1)*lda:], lda, a[j*lda:], 1,
1, a[(j+1)*lda+j:], lda)
bi.Dscal(n-j-1, 1/ajj, a[(j+1)*lda+j:], lda)
}
}
return true
}
+75
View File
@@ -0,0 +1,75 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
)
// Dpotrf computes the cholesky decomposition of the symmetric positive definite
// matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix,
// and a = U U^T is stored in place into a. If ul == blas.Lower, then a = L L^T
// is computed and stored in-place into a. If a is not positive definite, false
// is returned. This is the blocked version of the algorithm.
func (impl Implementation) Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool) {
bi := blas64.Implementation()
if ul != blas.Upper && ul != blas.Lower {
panic(badUplo)
}
if n < 0 {
panic(nLT0)
}
if lda < n {
panic(badLdA)
}
if n == 0 {
return true
}
nb := impl.Ilaenv(1, "DPOTRF", string(ul), n, -1, -1, -1)
if n <= nb {
return impl.Dpotf2(ul, n, a, lda)
}
if ul == blas.Upper {
for j := 0; j < n; j += nb {
jb := min(nb, n-j)
bi.Dsyrk(blas.Upper, blas.Trans, jb, j,
-1, a[j:], lda,
1, a[j*lda+j:], lda)
ok = impl.Dpotf2(blas.Upper, jb, a[j*lda+j:], lda)
if !ok {
return ok
}
if j+jb < n {
bi.Dgemm(blas.Trans, blas.NoTrans, jb, n-j-jb, j,
-1, a[j:], lda, a[j+jb:], lda,
1, a[j*lda+j+jb:], lda)
bi.Dtrsm(blas.Left, blas.Upper, blas.Trans, blas.NonUnit, jb, n-j-jb,
1, a[j*lda+j:], lda,
a[j*lda+j+jb:], lda)
}
}
return true
}
for j := 0; j < n; j += nb {
jb := min(nb, n-j)
bi.Dsyrk(blas.Lower, blas.NoTrans, jb, j,
-1, a[j*lda:], lda,
1, a[j*lda+j:], lda)
ok := impl.Dpotf2(blas.Lower, jb, a[j*lda+j:], lda)
if !ok {
return ok
}
if j+jb < n {
bi.Dgemm(blas.NoTrans, blas.Trans, n-j-jb, jb, j,
-1, a[(j+jb)*lda:], lda, a[j*lda:], lda,
1, a[(j+jb)*lda+j:], lda)
bi.Dtrsm(blas.Right, blas.Lower, blas.Trans, blas.NonUnit, n-j-jb, jb,
1, a[j*lda+j:], lda,
a[(j+jb)*lda+j:], lda)
}
}
return true
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
)
// Dtrtrs solves a triangular system of the form a * x = b or a^T * x = b. Dtrtrs
// checks for singularity in a. If a is singular, false is returned and no solve
// is performed. True is returned otherwise.
func (impl Implementation) Dtrtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, nrhs int, a []float64, lda int, b []float64, ldb int) (ok bool) {
nounit := diag == blas.NonUnit
if n == 0 {
return false
}
// Check for singularity.
if nounit {
for i := 0; i < n; i++ {
if a[i*lda+i] == 0 {
return false
}
}
}
bi := blas64.Implementation()
bi.Dtrsm(blas.Left, uplo, trans, diag, n, nrhs, 1, a, lda, b, ldb)
return true
}
+92
View File
@@ -0,0 +1,92 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
import (
"math"
"github.com/gonum/lapack"
)
// Implementation is the native Go implementation of LAPACK routines. It
// is built on top of calls to the return of blas64.Implementation(), so while
// this code is in pure Go, the underlying BLAS implementation may not be.
type Implementation struct{}
var _ lapack.Float64 = Implementation{}
const (
badDirect = "lapack: bad direct"
badLdA = "lapack: index of a out of range"
badSide = "lapack: bad side"
badStore = "lapack: bad store"
badTau = "lapack: tau has insufficient length"
badTrans = "lapack: bad trans"
badUplo = "lapack: illegal triangle"
badWork = "lapack: insufficient working memory"
badWorkStride = "lapack: insufficient working array stride"
negDimension = "lapack: negative matrix dimension"
nLT0 = "lapack: n < 0"
shortWork = "lapack: working array shorter than declared"
)
// checkMatrix verifies the parameters of a matrix input.
func checkMatrix(m, n int, a []float64, lda int) {
if m < 0 {
panic("lapack: has negative number of rows")
}
if m < 0 {
panic("lapack: has negative number of columns")
}
if lda < n {
panic("lapack: stride less than number of columns")
}
if len(a) < (m-1)*lda+n {
panic("lapack: insufficient matrix slice length")
}
}
func checkVector(n int, v []float64, inc int) {
if n < 0 {
panic("lapack: negative matrix length")
}
if (inc > 0 && (n-1)*inc >= len(v)) || (inc < 0 && (1-n)*inc >= len(v)) {
panic("lapack: insufficient vector slice length")
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// dlamch is a function in fortran, but since go forces IEEE-754 these are all
// fixed values. Probably a way to get them as constants.
// TODO(btracey): Is there a better way to find the smallest number such that 1+E > 1
var dlamchE, dlamchS, dlamchP float64
func init() {
onePlusEps := math.Nextafter(1, math.Inf(1))
eps := (math.Nextafter(1, math.Inf(1)) - 1) * 0.5
dlamchE = eps
sfmin := math.SmallestNonzeroFloat64
small := 1 / math.MaxFloat64
if small >= sfmin {
sfmin = small * onePlusEps
}
dlamchS = sfmin
radix := 2.0
dlamchP = radix * eps
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
// Iladlc scans a matrix for its last non-zero column. Returns -1 if the matrix
// is all zeros.
func (Implementation) Iladlc(m, n int, a []float64, lda int) int {
if n == 0 || m == 0 {
return n - 1
}
checkMatrix(m, n, a, lda)
// Test common case where corner is non-zero.
if a[n-1] != 0 || a[(m-1)*lda+(n-1)] != 0 {
return n - 1
}
// Scan each row tracking the highest column seen.
highest := -1
for i := 0; i < m; i++ {
for j := n - 1; j >= 0; j-- {
if a[i*lda+j] != 0 {
highest = max(highest, j)
break
}
}
}
return highest
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
// Iladlr scans a matrix for its last non-zero row. Returns -1 if the matrix
// is all zeros.
func (Implementation) Iladlr(m, n int, a []float64, lda int) int {
if m == 0 {
return m - 1
}
checkMatrix(m, n, a, lda)
// Check the common case where the corner is non-zero
if a[(m-1)*lda] != 0 || a[(m-1)*lda+n-1] != 0 {
return m - 1
}
for i := m - 1; i >= 0; i-- {
for j := 0; j < n; j++ {
if a[i*lda+j] != 0 {
return i
}
}
}
return -1
}
+375
View File
@@ -0,0 +1,375 @@
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package native
// Ilaenv returns algorithm tuning parameters for the algorithm given by the
// input string. ispec specifies the parameter to return.
// 1: The optimal block size
// 2: The minimum block size for which the algorithm should be used.
// 3: The crossover point below which an unblocked routine should be used.
// 4: The number of shifts.
// 5: The minumum column dimension for blocking to be used.
// 6: The crossover point for SVD (to use QR factorization or not).
// 7: The number of processors.
// 8: The crossover point for multishift in QR and QZ methods for nonsymmetric eigenvalue problems.
// 9: Maximum size of the subproblems in divide-and-conquer algorithms.
// 10: ieee NaN arithmetic can be trusted not to trap.
// 11: infinity arithmetic can be trusted not to trap.
func (Implementation) Ilaenv(ispec int, s string, opts string, n1, n2, n3, n4 int) int {
// TODO(btracey): Replace this with a constant lookup? A list of constants?
// TODO: What is the difference between 2 and 3?
sname := s[0] == 'S' || s[0] == 'D'
cname := s[0] == 'C' || s[0] == 'Z'
if !sname && !cname {
panic("lapack: bad name")
}
c2 := s[1:3]
c3 := s[3:6]
c4 := c3[1:3]
switch ispec {
default:
panic("lapack: bad ispec")
case 1:
switch c2 {
default:
panic("lapack: bad function name")
case "GE":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
if sname {
return 64
}
return 64
case "QRF", "RQF", "LQF", "QLF":
if sname {
return 32
}
return 32
case "HRD":
if sname {
return 32
}
return 32
case "BRD":
if sname {
return 32
}
return 32
case "TRI":
if sname {
return 64
}
return 64
}
case "PO":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
if sname {
return 64
}
return 64
}
case "SY":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
if sname {
return 64
}
return 64
case "TRD":
return 32
case "GST":
return 64
}
case "HE":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
return 64
case "TRD":
return 32
case "GST":
return 64
}
case "OR":
switch c3[0] {
default:
panic("lapack: bad function name")
case 'G':
switch c3[1:] {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 32
}
case 'M':
switch c3[1:] {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 32
}
}
case "UN":
switch c3[0] {
default:
panic("lapack: bad function name")
case 'G':
switch c3[1:] {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 32
}
case 'M':
switch c3[1:] {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 32
}
}
case "GB":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
if sname {
if n4 <= 64 {
return 1
}
return 32
}
if n4 <= 64 {
return 1
}
return 32
}
case "PB":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
if sname {
if n4 <= 64 {
return 1
}
return 32
}
if n4 <= 64 {
return 1
}
return 32
}
case "TR":
switch c3 {
default:
panic("lapack: bad function name")
case "TRI":
if sname {
return 64
}
return 64
}
case "LA":
switch c3 {
default:
panic("lapack: bad function name")
case "UUM":
if sname {
return 64
}
return 64
}
case "ST":
if sname && c3 == "EBZ" {
return 1
}
panic("lapack: bad function name")
}
case 2:
switch c2 {
default:
panic("lapack: bad function name")
case "GE":
switch c3 {
default:
panic("lapack: bad function name")
case "QRF", "RQF", "LQF", "QLF":
if sname {
return 2
}
return 2
case "HRD":
if sname {
return 2
}
return 2
case "BRD":
if sname {
return 2
}
return 2
case "TRI":
if sname {
return 2
}
return 2
}
case "SY":
switch c3 {
default:
panic("lapack: bad function name")
case "TRF":
if sname {
return 8
}
return 8
case "TRD":
if sname {
return 2
}
panic("lapack: bad function name")
}
case "HE":
if c3 == "TRD" {
return 2
}
panic("lapack: bad function name")
case "OR":
if !sname {
panic("lapack: bad function name")
}
switch c3[0] {
default:
panic("lapack: bad function name")
case 'G':
switch c4 {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 2
}
case 'M':
switch c4 {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 2
}
}
case "UN":
switch c3[0] {
default:
panic("lapack: bad function name")
case 'G':
switch c4 {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 2
}
case 'M':
switch c4 {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 2
}
}
}
case 3:
switch c2 {
default:
panic("lapack: bad function name")
case "GE":
switch c3 {
default:
panic("lapack: bad function name")
case "QRF", "RQF", "LQF", "QLF":
if sname {
return 128
}
return 128
case "HRD":
if sname {
return 128
}
return 128
case "BRD":
if sname {
return 128
}
return 128
}
case "SY":
if sname && c3 == "TRD" {
return 32
}
panic("lapack: bad function name")
case "HE":
if c3 == "TRD" {
return 32
}
panic("lapack: bad function name")
case "OR":
switch c3[0] {
default:
panic("lapack: bad function name")
case 'G':
switch c4 {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 128
}
}
case "UN":
switch c3[0] {
default:
panic("lapack: bad function name")
case 'G':
switch c4 {
default:
panic("lapack: bad function name")
case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
return 128
}
}
}
case 4:
// Used by xHSEQR
return 6
case 5:
// Not used
return 2
case 6:
// Used by xGELSS and xGESVD
return min(n1, n2) * 1e6
case 7:
// Not used
return 1
case 8:
// Used by xHSEQR
return 50
case 9:
// used by xGELSD and xGESDD
return 25
case 10:
// Go guarantees ieee
return 1
case 11:
// Go guarantees ieee
return 1
}
}