// 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 blas64 import ( "math" "testing" "gonum.org/v1/gonum/blas" ) func newGeneralFrom(a GeneralCols) General { t := General{ Rows: a.Rows, Cols: a.Cols, Stride: a.Cols, Data: make([]float64, a.Rows*a.Cols), } t.From(a) return t } func (m General) dims() (r, c int) { return m.Rows, m.Cols } func (m General) at(i, j int) float64 { return m.Data[i*m.Stride+j] } func newGeneralColsFrom(a General) GeneralCols { t := GeneralCols{ Rows: a.Rows, Cols: a.Cols, Stride: a.Rows, Data: make([]float64, a.Rows*a.Cols), } t.From(a) return t } func (m GeneralCols) dims() (r, c int) { return m.Rows, m.Cols } func (m GeneralCols) at(i, j int) float64 { return m.Data[i+j*m.Stride] } type general interface { dims() (r, c int) at(i, j int) float64 } func sameGeneral(a, b general) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var generalTests = []General{ {Rows: 2, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 2, Stride: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 2, Cols: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, }}, {Rows: 3, Cols: 2, Stride: 5, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertGeneral(t *testing.T) { for _, test := range generalTests { colmajor := newGeneralColsFrom(test) if !sameGeneral(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newGeneralFrom(colmajor) if !sameGeneral(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularFrom(a TriangularCols) Triangular { t := Triangular{ N: a.N, Stride: a.N, Data: make([]float64, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m Triangular) n() int { return m.N } func (m Triangular) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j && j < m.N { return 0 } if m.Uplo == blas.Upper && i > j { return 0 } return m.Data[i*m.Stride+j] } func (m Triangular) uplo() blas.Uplo { return m.Uplo } func (m Triangular) diag() blas.Diag { return m.Diag } func newTriangularColsFrom(a Triangular) TriangularCols { t := TriangularCols{ N: a.N, Stride: a.N, Data: make([]float64, a.N*a.N), Diag: a.Diag, Uplo: a.Uplo, } t.From(a) return t } func (m TriangularCols) n() int { return m.N } func (m TriangularCols) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } if m.Uplo == blas.Lower && i < j { return 0 } if m.Uplo == blas.Upper && i > j && i < m.N { return 0 } return m.Data[i+j*m.Stride] } func (m TriangularCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularCols) diag() blas.Diag { return m.Diag } type triangular interface { n() int at(i, j int) float64 uplo() blas.Uplo diag() blas.Diag } func sameTriangular(a, b triangular) bool { an := a.n() bn := b.n() if an != bn { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularTests = []Triangular{ {N: 3, Stride: 3, Data: []float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {N: 3, Stride: 5, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, } func TestConvertTriangular(t *testing.T) { for _, test := range triangularTests { for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower, blas.All} { for _, diag := range []blas.Diag{blas.Unit, blas.NonUnit} { test.Uplo = uplo test.Diag = diag colmajor := newTriangularColsFrom(test) if !sameTriangular(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularFrom(colmajor) if !sameTriangular(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } } } func newBandFrom(a BandCols) Band { t := Band{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]float64, a.Rows*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m Band) dims() (r, c int) { return m.Rows, m.Cols } func (m Band) at(i, j int) float64 { pj := j + m.KL - i if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[i*m.Stride+pj] } func (m Band) bandwidth() (kl, ku int) { return m.KL, m.KU } func newBandColsFrom(a Band) BandCols { t := BandCols{ Rows: a.Rows, Cols: a.Cols, KL: a.KL, KU: a.KU, Stride: a.KL + a.KU + 1, Data: make([]float64, a.Cols*(a.KL+a.KU+1)), } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m BandCols) dims() (r, c int) { return m.Rows, m.Cols } func (m BandCols) at(i, j int) float64 { pj := i + m.KU - j if pj < 0 || m.KL+m.KU+1 <= pj { return 0 } return m.Data[j*m.Stride+pj] } func (m BandCols) bandwidth() (kl, ku int) { return m.KL, m.KU } type band interface { dims() (r, c int) at(i, j int) float64 bandwidth() (kl, ku int) } func sameBand(a, b band) bool { ar, ac := a.dims() br, bc := b.dims() if ar != br || ac != bc { return false } akl, aku := a.bandwidth() bkl, bku := b.bandwidth() if akl != bkl || aku != bku { return false } for i := 0; i < ar; i++ { for j := 0; j < ac; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var bandTests = []Band{ {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 1, Data: []float64{ 1, 2, 3, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []float64{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 1, Data: []float64{ 1, 2, 3, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 2, Data: []float64{ 1, 2, 3, 4, 5, 6, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 3, Data: []float64{ -1, 2, 3, 4, 5, 6, 7, 8, 9, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 3, Data: []float64{ -1, 2, 3, 4, 5, 6, 7, 8, -2, 9, -3, -4, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 4, Data: []float64{ -2, -1, 3, 4, -3, 5, 6, 7, 8, 9, 10, 11, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 4, Data: []float64{ -2, -1, 2, 3, -3, 4, 5, 6, 7, 8, 9, -4, 10, 11, -5, -6, }}, {Rows: 3, Cols: 4, KL: 0, KU: 0, Stride: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 3, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 0, Stride: 5, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {Rows: 4, Cols: 3, KL: 0, KU: 1, Stride: 5, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 0, KU: 1, Stride: 5, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, 6, 0, 0, 0, }}, {Rows: 3, Cols: 4, KL: 1, KU: 1, Stride: 5, Data: []float64{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, }}, {Rows: 4, Cols: 3, KL: 1, KU: 1, Stride: 5, Data: []float64{ -1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, -2, 0, 0, 9, -3, -4, 0, 0, }}, {Rows: 3, Cols: 4, KL: 2, KU: 1, Stride: 5, Data: []float64{ -2, -1, 3, 4, 0, -3, 5, 6, 7, 0, 8, 9, 10, 11, 0, }}, {Rows: 4, Cols: 3, KL: 2, KU: 1, Stride: 5, Data: []float64{ -2, -1, 2, 3, 0, -3, 4, 5, 6, 0, 7, 8, 9, -4, 0, 10, 11, -5, -6, 0, }}, } func TestConvertBand(t *testing.T) { for _, test := range bandTests { colmajor := newBandColsFrom(test) if !sameBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newBandFrom(colmajor) if !sameBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } } func newTriangularBandFrom(a TriangularBandCols) TriangularBand { t := TriangularBand{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float64, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBand) n() (n int) { return m.N } func (m TriangularBand) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } b := Band{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas64: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBand) bandwidth() (k int) { return m.K } func (m TriangularBand) uplo() blas.Uplo { return m.Uplo } func (m TriangularBand) diag() blas.Diag { return m.Diag } func newTriangularBandColsFrom(a TriangularBand) TriangularBandCols { t := TriangularBandCols{ N: a.N, K: a.K, Stride: a.K + 1, Data: make([]float64, a.N*(a.K+1)), Uplo: a.Uplo, Diag: a.Diag, } for i := range t.Data { t.Data[i] = math.NaN() } t.From(a) return t } func (m TriangularBandCols) n() (n int) { return m.N } func (m TriangularBandCols) at(i, j int) float64 { if m.Diag == blas.Unit && i == j { return 1 } b := BandCols{ Rows: m.N, Cols: m.N, Stride: m.Stride, Data: m.Data, } switch m.Uplo { default: panic("blas64: bad BLAS uplo") case blas.Upper: if i > j { return 0 } b.KU = m.K case blas.Lower: if i < j { return 0 } b.KL = m.K } return b.at(i, j) } func (m TriangularBandCols) bandwidth() (k int) { return m.K } func (m TriangularBandCols) uplo() blas.Uplo { return m.Uplo } func (m TriangularBandCols) diag() blas.Diag { return m.Diag } type triangularBand interface { n() (n int) at(i, j int) float64 bandwidth() (k int) uplo() blas.Uplo diag() blas.Diag } func sameTriangularBand(a, b triangularBand) bool { an := a.n() bn := b.n() if an != bn { return false } if a.uplo() != b.uplo() { return false } if a.diag() != b.diag() { return false } ak := a.bandwidth() bk := b.bandwidth() if ak != bk { return false } for i := 0; i < an; i++ { for j := 0; j < an; j++ { if a.at(i, j) != b.at(i, j) || math.IsNaN(a.at(i, j)) != math.IsNaN(b.at(i, j)) { return false } } } return true } var triangularBandTests = []TriangularBand{ {N: 3, K: 0, Stride: 1, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, }}, {N: 3, K: 0, Stride: 1, Uplo: blas.Lower, Data: []float64{ 1, 2, 3, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, -1, }}, {N: 3, K: 1, Stride: 2, Uplo: blas.Lower, Data: []float64{ -1, 1, 2, 3, 4, 5, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 4, 5, -1, 6, -2, -3, }}, {N: 3, K: 2, Stride: 3, Uplo: blas.Lower, Data: []float64{ -2, -1, 1, -3, 2, 4, 3, 5, 6, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 0, Stride: 5, Uplo: blas.Lower, Data: []float64{ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 5, -1, 0, 0, 0, }}, {N: 3, K: 1, Stride: 5, Uplo: blas.Lower, Data: []float64{ -1, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Upper, Data: []float64{ 1, 2, 3, 0, 0, 4, 5, -1, 0, 0, 6, -2, -3, 0, 0, }}, {N: 3, K: 2, Stride: 5, Uplo: blas.Lower, Data: []float64{ -2, -1, 1, 0, 0, -3, 2, 4, 0, 0, 3, 5, 6, 0, 0, }}, } func TestConvertTriBand(t *testing.T) { for _, test := range triangularBandTests { colmajor := newTriangularBandColsFrom(test) if !sameTriangularBand(colmajor, test) { t.Errorf("unexpected result for row major to col major conversion:\n\tgot: %#v\n\tfrom:%#v", colmajor, test) } rowmajor := newTriangularBandFrom(colmajor) if !sameTriangularBand(rowmajor, test) { t.Errorf("unexpected result for col major to row major conversion:\n\tgot: %#v\n\twant:%#v", rowmajor, test) } } }