lapack/testlapack: add implementation comments to Dlatrd test

This commit is contained in:
Vladimir Chalupecky
2018-11-23 19:05:42 +01:00
committed by Vladimír Chalupecký
parent 6dfebf106b
commit c015e0732d

View File

@@ -42,11 +42,15 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
ldw = nb ldw = nb
} }
// Allocate n×n matrix A and fill it with random numbers.
a := make([]float64, n*lda) a := make([]float64, n*lda)
for i := range a { for i := range a {
a[i] = rnd.NormFloat64() a[i] = rnd.NormFloat64()
} }
// Allocate output slices and matrix W and fill them
// with NaN. All their elements should be overwritten by
// Dlatrd.
e := make([]float64, n-1) e := make([]float64, n-1)
for i := range e { for i := range e {
e[i] = math.NaN() e[i] = math.NaN()
@@ -63,30 +67,30 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
aCopy := make([]float64, len(a)) aCopy := make([]float64, len(a))
copy(aCopy, a) copy(aCopy, a)
// Reduce nb rows and columns of the symmetric matrix A
// defined by uplo triangle to symmetric tridiagonal
// form.
impl.Dlatrd(uplo, n, nb, a, lda, e, tau, w, ldw) impl.Dlatrd(uplo, n, nb, a, lda, e, tau, w, ldw)
// Construct Q. // Construct Q from elementary reflectors stored in
ldq := n // columns of A.
q := blas64.General{ q := blas64.General{
Rows: n, Rows: n,
Cols: n, Cols: n,
Stride: ldq, Stride: n,
Data: make([]float64, n*ldq), Data: make([]float64, n*n),
} }
// Initialize Q to the identity matrix.
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
q.Data[i*ldq+i] = 1 q.Data[i*q.Stride+i] = 1
} }
if uplo == blas.Upper { if uplo == blas.Upper {
for i := n - 1; i >= n-nb; i-- { for i := n - 1; i >= n-nb; i-- {
if i == 0 { if i == 0 {
continue continue
} }
h := blas64.General{
Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), // Extract the elementary reflector v from A.
}
for j := 0; j < n; j++ {
h.Data[j*n+j] = 1
}
v := blas64.Vector{ v := blas64.Vector{
Inc: 1, Inc: 1,
Data: make([]float64, n), Data: make([]float64, n),
@@ -96,8 +100,16 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
} }
v.Data[i-1] = 1 v.Data[i-1] = 1
// Compute H = I - tau[i-1] * v * v^T.
h := blas64.General{
Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n),
}
for j := 0; j < n; j++ {
h.Data[j*n+j] = 1
}
blas64.Ger(-tau[i-1], v, v, h) blas64.Ger(-tau[i-1], v, v, h)
// Update Q <- Q * H.
qTmp := blas64.General{ qTmp := blas64.General{
Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n),
} }
@@ -109,12 +121,8 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
if i == n-1 { if i == n-1 {
continue continue
} }
h := blas64.General{
Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), // Extract the elementary reflector v from A.
}
for j := 0; j < n; j++ {
h.Data[j*n+j] = 1
}
v := blas64.Vector{ v := blas64.Vector{
Inc: 1, Inc: 1,
Data: make([]float64, n), Data: make([]float64, n),
@@ -123,8 +131,17 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
for j := i + 2; j < n; j++ { for j := i + 2; j < n; j++ {
v.Data[j] = a[j*lda+i] v.Data[j] = a[j*lda+i]
} }
// Compute H = I - tau[i] * v * v^T.
h := blas64.General{
Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n),
}
for j := 0; j < n; j++ {
h.Data[j*n+j] = 1
}
blas64.Ger(-tau[i], v, v, h) blas64.Ger(-tau[i], v, v, h)
// Update Q <- Q * H.
qTmp := blas64.General{ qTmp := blas64.General{
Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n), Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n),
} }
@@ -134,11 +151,11 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
} }
errStr := fmt.Sprintf("isUpper = %v, n = %v, nb = %v", uplo == blas.Upper, n, nb) errStr := fmt.Sprintf("isUpper = %v, n = %v, nb = %v", uplo == blas.Upper, n, nb)
if !isOrthogonal(q) { if !isOrthogonal(q) {
t.Errorf("Q not orthogonal. %s", errStr) t.Errorf("Case %v: Q not orthogonal", errStr)
} }
aGen := genFromSym(blas64.Symmetric{N: n, Stride: lda, Uplo: uplo, Data: aCopy}) aGen := genFromSym(blas64.Symmetric{N: n, Stride: lda, Uplo: uplo, Data: aCopy})
if !dlatrdCheckDecomposition(t, uplo, n, nb, e, tau, a, lda, aGen, q) { if !dlatrdCheckDecomposition(t, uplo, n, nb, e, a, lda, aGen, q) {
t.Errorf("Decomposition mismatch. %s", errStr) t.Errorf("Case %v: Decomposition mismatch", errStr)
} }
} }
} }
@@ -146,44 +163,49 @@ func DlatrdTest(t *testing.T, impl Dlatrder) {
// dlatrdCheckDecomposition checks that the first nb rows have been successfully // dlatrdCheckDecomposition checks that the first nb rows have been successfully
// reduced. // reduced.
func dlatrdCheckDecomposition(t *testing.T, uplo blas.Uplo, n, nb int, e, tau, a []float64, lda int, aGen, q blas64.General) bool { func dlatrdCheckDecomposition(t *testing.T, uplo blas.Uplo, n, nb int, e, a []float64, lda int, aGen, q blas64.General) bool {
// Compute Q^T * A * Q. // Compute ans = Q^T * A * Q.
// ans should be a tridiagonal matrix in the first or last nb rows and
// columns, depending on uplo.
tmp := blas64.General{ tmp := blas64.General{
Rows: n, Rows: n,
Cols: n, Cols: n,
Stride: n, Stride: n,
Data: make([]float64, n*n), Data: make([]float64, n*n),
} }
ans := blas64.General{ ans := blas64.General{
Rows: n, Rows: n,
Cols: n, Cols: n,
Stride: n, Stride: n,
Data: make([]float64, n*n), Data: make([]float64, n*n),
} }
blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, aGen, 0, tmp) blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, aGen, 0, tmp)
blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, ans) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, ans)
// Compare with T. // Compare the output of Dlatrd (stored in a and e) with the explicit
// reduction to tridiagonal matrix Q^T * A * Q (stored in ans).
if uplo == blas.Upper { if uplo == blas.Upper {
for i := n - 1; i >= n-nb; i-- { for i := n - nb; i < n; i++ {
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
v := ans.Data[i*ans.Stride+j] v := ans.Data[i*ans.Stride+j]
switch { switch {
case i == j: case i == j:
// Diagonal elements of a and ans should match.
if math.Abs(v-a[i*lda+j]) > 1e-10 { if math.Abs(v-a[i*lda+j]) > 1e-10 {
return false return false
} }
case i == j-1: case i == j-1:
// Superdiagonal elements in a should be 1.
if math.Abs(a[i*lda+j]-1) > 1e-10 { if math.Abs(a[i*lda+j]-1) > 1e-10 {
return false return false
} }
// Superdiagonal elements of ans should match e.
if math.Abs(v-e[i]) > 1e-10 { if math.Abs(v-e[i]) > 1e-10 {
return false return false
} }
case i == j+1: case i == j+1:
default: default:
// All other elements should be 0.
if math.Abs(v) > 1e-10 { if math.Abs(v) > 1e-10 {
return false return false
} }
@@ -196,18 +218,22 @@ func dlatrdCheckDecomposition(t *testing.T, uplo blas.Uplo, n, nb int, e, tau, a
v := ans.Data[i*ans.Stride+j] v := ans.Data[i*ans.Stride+j]
switch { switch {
case i == j: case i == j:
// Diagonal elements of a and ans should match.
if math.Abs(v-a[i*lda+j]) > 1e-10 { if math.Abs(v-a[i*lda+j]) > 1e-10 {
return false return false
} }
case i == j-1: case i == j-1:
case i == j+1: case i == j+1:
// Subdiagonal elements in a should be 1.
if math.Abs(a[i*lda+j]-1) > 1e-10 { if math.Abs(a[i*lda+j]-1) > 1e-10 {
return false return false
} }
// Subdiagonal elements of ans should match e.
if math.Abs(v-e[i-1]) > 1e-10 { if math.Abs(v-e[i-1]) > 1e-10 {
return false return false
} }
default: default:
// All other elements should be 0.
if math.Abs(v) > 1e-10 { if math.Abs(v) > 1e-10 {
return false return false
} }