// Copyright ©2013 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 mat64 import ( "github.com/gonum/blas/cblas" "fmt" "testing" check "launchpad.net/gocheck" ) // Tests func Test(t *testing.T) { check.TestingT(t) } type S struct{} var _ = check.Suite(&S{}) func leaksPanic(fn Panicker) (panicked bool) { defer func() { r := recover() panicked = r != nil }() Maybe(fn) return } func panics(fn func()) (panicked bool, message string) { defer func() { r := recover() panicked = r != nil message = fmt.Sprint(r) }() fn() return } func (s *S) SetUpSuite(c *check.C) { blasEngine = cblas.Blas{} } func flatten(f [][]float64) (r, c int, d []float64) { for _, r := range f { d = append(d, r...) } return len(f), len(f[0]), d } func unflatten(r, c int, d []float64) [][]float64 { m := make([][]float64, r) for i := 0; i < r; i++ { m[i] = d[i*c : (i+1)*c] } return m } func eye() *Dense { return NewDense(3, 3, []float64{ 1, 0, 0, 0, 1, 0, 0, 0, 1, }) } func (s *S) TestMaybe(c *check.C) { for i, test := range []struct { fn Panicker panics bool }{ { func() {}, false, }, { func() { panic("panic") }, true, }, { func() { panic(Error("panic")) }, false, }, } { c.Check(leaksPanic(test.fn), check.Equals, test.panics, check.Commentf("Test %d", i)) } } func (s *S) TestSolve(c *check.C) { for _, test := range []struct { name string panics bool a [][]float64 b [][]float64 x [][]float64 }{ { name: "OneElement", panics: false, a: [][]float64{{6}}, b: [][]float64{{3}}, x: [][]float64{{0.5}}, }, { name: "SquareIdentity", panics: false, a: [][]float64{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, }, b: [][]float64{ {3}, {2}, {1}, }, x: [][]float64{ {3}, {2}, {1}, }, }, { name: "Square", panics: false, a: [][]float64{ {0.8147, 0.9134, 0.5528}, {0.9058, 0.6324, 0.8723}, {0.1270, 0.0975, 0.7612}, }, b: [][]float64{ {0.278}, {0.547}, {0.958}, }, x: [][]float64{ {-0.932687281002860}, {0.303963920182067}, {1.375216503507109}, }, }, { name: "ColumnMismatch", panics: true, a: [][]float64{ {0.6046602879796196, 0.9405090880450124, 0.6645600532184904}, {0.4377141871869802, 0.4246374970712657, 0.6868230728671094}, }, b: [][]float64{ {0.30091186058528707}, {0.5152126285020654}, {0.8136399609900968}, {0.12345}, }, x: [][]float64{ {-26.618512183136257}, {8.730387239011677}, {12.316510032082446}, {0.1234}, }, }, { name: "WideMatrix", panics: false, a: [][]float64{ {0.8147, 0.9134, 0.5528}, {0.9058, 0.6324, 0.8723}, }, b: [][]float64{ {0.278}, {0.547}, }, x: [][]float64{ {0.25919787248965376}, {-0.25560256266441034}, {0.5432324059702451}, }, }, { name: "Skinny1", panics: false, a: [][]float64{ {0.8147, 0.9134, 0.9}, {0.9058, 0.6324, 0.9}, {0.1270, 0.0975, 0.1}, {1.6, 2.8, -3.5}, }, b: [][]float64{ {0.278}, {0.547}, {-0.958}, {1.452}, }, x: [][]float64{ {0.820970340787782}, {-0.218604626527306}, {-0.212938815234215}, }, }, { name: "Skinny2", panics: false, a: [][]float64{ {0.8147, 0.9134, 0.231, -1.65}, {0.9058, 0.6324, 0.9, 0.72}, {0.1270, 0.0975, 0.1, 1.723}, {1.6, 2.8, -3.5, 0.987}, {7.231, 9.154, 1.823, 0.9}, }, b: [][]float64{ {0.278, 8.635}, {0.547, 9.125}, {-0.958, -0.762}, {1.452, 1.444}, {1.999, -7.234}, }, x: [][]float64{ {1.863006789511373, 44.467887791812750}, {-1.127270935407224, -34.073794226035126}, {-0.527926457947330, -8.032133759788573}, {-0.248621916204897, -2.366366415805275}, }, }, } { a := NewDense(flatten(test.a)) b := NewDense(flatten(test.b)) var x *Dense fn := func() { x = Solve(a, b) } panicked, message := panics(fn) if panicked { c.Check(panicked, check.Equals, test.panics, check.Commentf("Test %v panicked: %s", test.name, message)) continue } trueX := NewDense(flatten(test.x)) c.Check(x.EqualsApprox(trueX, 1e-13), check.Equals, true, check.Commentf("Test %v solution mismatch: Found %v, expected %v ", test.name, x, trueX)) } }