diff --git a/cgo/lapack_test.go b/cgo/lapack_test.go index 10ffdd37..975ef01d 100644 --- a/cgo/lapack_test.go +++ b/cgo/lapack_test.go @@ -48,6 +48,10 @@ func TestDlacn2(t *testing.T) { testlapack.Dlacn2Test(t, impl) } +func TestDlascl(t *testing.T) { + testlapack.DlasclTest(t, impl) +} + func TestDlacpy(t *testing.T) { testlapack.DlacpyTest(t, impl) } diff --git a/native/lapack_test.go b/native/lapack_test.go index 299e4c9f..03d9253a 100644 --- a/native/lapack_test.go +++ b/native/lapack_test.go @@ -140,6 +140,10 @@ func TestDlas2(t *testing.T) { testlapack.Dlas2Test(t, impl) } +func TestDlascl(t *testing.T) { + testlapack.DlasclTest(t, impl) +} + func TestDlaset(t *testing.T) { testlapack.DlasetTest(t, impl) } diff --git a/testlapack/dlascl.go b/testlapack/dlascl.go new file mode 100644 index 00000000..eaaf6273 --- /dev/null +++ b/testlapack/dlascl.go @@ -0,0 +1,106 @@ +// Copyright ©2016 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 testlapack + +import ( + "fmt" + "math" + "math/rand" + "testing" + + "github.com/gonum/lapack" +) + +type Dlascler interface { + Dlascl(kind lapack.MatrixType, kl, ku int, cfrom, cto float64, m, n int, a []float64, lda int) +} + +func DlasclTest(t *testing.T, impl Dlascler) { + const tol = 1e-16 + + rnd := rand.New(rand.NewSource(1)) + for ti, test := range []struct { + m, n int + }{ + {0, 0}, + {1, 1}, + {1, 10}, + {10, 1}, + {2, 2}, + {2, 11}, + {11, 2}, + {3, 3}, + {3, 11}, + {11, 3}, + {11, 11}, + {11, 100}, + {100, 11}, + } { + m := test.m + n := test.n + for _, extra := range []int{0, 11} { + for _, kind := range []lapack.MatrixType{lapack.General, lapack.UpperTri, lapack.LowerTri} { + a := randomGeneral(m, n, n+extra, rnd) + aCopy := cloneGeneral(a) + cfrom := rnd.NormFloat64() + cto := rnd.NormFloat64() + scale := cto / cfrom + + impl.Dlascl(kind, -1, -1, cfrom, cto, m, n, a.Data, a.Stride) + + prefix := fmt.Sprintf("Case #%v: kind=%v,m=%v,n=%v,extra=%v", ti, kind, m, n, extra) + if !generalOutsideAllNaN(a) { + t.Errorf("%v: out-of-range write to A", prefix) + } + switch kind { + case lapack.General: + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + want := scale * aCopy.Data[i*aCopy.Stride+j] + got := a.Data[i*a.Stride+j] + if math.Abs(want-got) > tol { + t.Errorf("%v: unexpected A[%v,%v]=%v, want %v", prefix, i, j, got, want) + } + } + } + case lapack.UpperTri: + for i := 0; i < m; i++ { + for j := i; j < n; j++ { + want := scale * aCopy.Data[i*aCopy.Stride+j] + got := a.Data[i*a.Stride+j] + if math.Abs(want-got) > tol { + t.Errorf("%v: unexpected A[%v,%v]=%v, want %v", prefix, i, j, got, want) + } + } + } + for i := 0; i < m; i++ { + for j := 0; j < min(i, n); j++ { + if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { + t.Errorf("%v: unexpected modification in lower triangle of A", prefix) + } + } + } + case lapack.LowerTri: + for i := 0; i < m; i++ { + for j := 0; j <= min(i, n-1); j++ { + want := scale * aCopy.Data[i*aCopy.Stride+j] + got := a.Data[i*a.Stride+j] + if math.Abs(want-got) > tol { + t.Errorf("%v: unexpected A[%v,%v]=%v, want %v", prefix, i, j, got, want) + } + } + } + for i := 0; i < m; i++ { + for j := i + 1; j < n; j++ { + if a.Data[i*a.Stride+j] != aCopy.Data[i*aCopy.Stride+j] { + t.Errorf("%v: unexpected modification in upper triangle of A", prefix) + } + } + } + } + } + } + } +}