Skip to content
This repository was archived by the owner on Nov 24, 2018. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cgo/lapack.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,23 @@ func (impl Implementation) Dtrcon(norm lapack.MatrixNorm, uplo blas.Uplo, diag b
return rcond[0]
}

// Dtrtri computes the inverse of a triangular matrix, storing the result in place
// into a. This is the BLAS level 3 version of the algorithm which builds upon
// Dtrti2 to operate on matrix blocks instead of only individual columns.
//
// Dtrti returns whether the matrix a is singular or whether it's not singular.
// If the matrix is singular the inversion is not performed.
func (impl Implementation) Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) (ok bool) {
checkMatrix(n, n, a, lda)
if uplo != blas.Upper && uplo != blas.Lower {
panic(badUplo)
}
if diag != blas.NonUnit && diag != blas.Unit {
panic(badDiag)
}
return clapack.Dtrtri(uplo, diag, n, a, lda)
}

// Dtrtrs solves a triangular system of the form A * X = B or A^T * X = B. Dtrtrs
// returns whether the solve completed successfully. If A is singular, no solve is performed.
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) {
Expand Down
4 changes: 4 additions & 0 deletions cgo/lapack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,7 @@ func TestDpocon(t *testing.T) {
func TestDtrcon(t *testing.T) {
testlapack.DtrconTest(t, impl)
}

func TestDtrtri(t *testing.T) {
testlapack.DtrtriTest(t, impl)
}
2 changes: 1 addition & 1 deletion native/dtrti2.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

// Dtrti2 computes the inverse of a triangular matrix, storing the result in place
// into a.
// into a. This is the BLAS level 2 version of the algorithm.
func (impl Implementation) Dtrti2(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) {
checkMatrix(n, n, a, lda)
if uplo != blas.Upper && uplo != blas.Lower {
Expand Down
60 changes: 60 additions & 0 deletions native/dtrtri.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package native

import (
"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
)

// Dtrtri computes the inverse of a triangular matrix, storing the result in place
// into a. This is the BLAS level 3 version of the algorithm which builds upon
// Dtrti2 to operate on matrix blocks instead of only individual columns.
//
// Dtrti returns whether the matrix a is singular or whether it's not singular.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be better: "Dtrtri will not perform the inversion if the matrix is singular, and returns a boolean indicating whether the inversion was successful."

I think that covers the behaviour.

// If the matrix is singular the inversion is not performed.
func (impl Implementation) Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) (ok bool) {
checkMatrix(n, n, a, lda)
if uplo != blas.Upper && uplo != blas.Lower {
panic(badUplo)
}
if diag != blas.NonUnit && diag != blas.Unit {
panic(badDiag)
}
if n == 0 {
return
}
nonUnit := diag == blas.NonUnit
if nonUnit {
for i := 0; i < n; i++ {
if a[i*lda+i] == 0 {
return false
}
}
}

bi := blas64.Implementation()

nb := impl.Ilaenv(1, "DTRTRI", "UD", n, -1, -1, -1)
if nb <= 1 || nb > n {
impl.Dtrti2(uplo, diag, n, a, lda)
return true
}
if uplo == blas.Upper {
for j := 0; j < n; j += nb {
jb := min(nb, n-j)
bi.Dtrmm(blas.Left, blas.Upper, blas.NoTrans, diag, j, jb, 1, a, lda, a[j:], lda)
bi.Dtrsm(blas.Right, blas.Upper, blas.NoTrans, diag, j, jb, -1, a[j*lda+j:], lda, a[j:], lda)
impl.Dtrti2(blas.Upper, diag, jb, a[j*lda+j:], lda)
}
return true
}
nn := ((n - 1) / nb) * nb
for j := nn; j >= 0; j -= nb {
jb := min(nb, n-j)
if j+jb <= n-1 {
bi.Dtrmm(blas.Left, blas.Lower, blas.NoTrans, diag, n-j-jb, jb, 1, a[(j+jb)*lda+j+jb:], lda, a[(j+jb)*lda+j:], lda)
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, diag, n-j-jb, jb, -1, a[j*lda+j:], lda, a[(j+jb)*lda+j:], lda)
}
impl.Dtrti2(blas.Lower, diag, jb, a[j*lda+j:], lda)
}
return true
}
8 changes: 6 additions & 2 deletions native/lapack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ func TestDtrcon(t *testing.T) {
testlapack.DtrconTest(t, impl)
}

func TestDtrtri2(t *testing.T) {
testlapack.Dtrtri2Test(t, impl)
func TestDtrti2(t *testing.T) {
testlapack.Dtrti2Test(t, impl)
}

func TestDtrtri(t *testing.T) {
testlapack.DtrtriTest(t, impl)
}

func TestIladlc(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion testlapack/dtrti2.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Dtrti2er interface {
Dtrti2(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int)
}

func Dtrtri2Test(t *testing.T, impl Dtrti2er) {
func Dtrti2Test(t *testing.T, impl Dtrti2er) {
for _, test := range []struct {
a []float64
n int
Expand Down
89 changes: 89 additions & 0 deletions testlapack/dtrtri.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package testlapack

import (
"math"
"math/rand"
"testing"

"github.com/gonum/blas"
"github.com/gonum/blas/blas64"
)

type Dtrtrier interface {
Dtrconer
Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) bool
}

func DtrtriTest(t *testing.T, impl Dtrtrier) {
bi := blas64.Implementation()
for _, uplo := range []blas.Uplo{blas.Upper} {
for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} {
for _, test := range []struct {
n, lda int
}{
{3, 0},
{70, 0},
{200, 0},
{3, 5},
{70, 92},
{200, 205},
} {
n := test.n
lda := test.lda
if lda == 0 {
lda = n
}
a := make([]float64, n*lda)
for i := range a {
a[i] = rand.Float64() + 1 // This keeps the matrices well conditioned.
}
aCopy := make([]float64, len(a))
copy(aCopy, a)
impl.Dtrtri(uplo, diag, n, a, lda)
if uplo == blas.Upper {
for i := 1; i < n; i++ {
for j := 0; j < i; j++ {
aCopy[i*lda+j] = 0
a[i*lda+j] = 0
}
}
} else {
for i := 1; i < n; i++ {
for j := i + 1; j < n; j++ {
aCopy[i*lda+j] = 0
a[i*lda+j] = 0
}
}
}
if diag == blas.Unit {
for i := 0; i < n; i++ {
a[i*lda+i] = 1
aCopy[i*lda+i] = 1
}
}
ans := make([]float64, len(a))
bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, a, lda, aCopy, lda, 0, ans, lda)
iseye := true
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if i == j {
if math.Abs(ans[i*lda+i]-1) > 1e-4 {
iseye = false
break
}
} else {
if math.Abs(ans[i*lda+j]) > 1e-4 {
iseye = false
break
}
}
}
}
if !iseye {
t.Errorf("inv(A) * A != I. Upper = %v, unit = %v, n = %v, lda = %v",
uplo == blas.Upper, diag == blas.Unit, n, lda)
}
}
}
}
}