mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 23:26:52 +08:00
Merge pull request #65 from gonum/redomat
matrix, all: combine matrix packages, change matrix to mat
This commit is contained in:
@@ -9,7 +9,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/diff/fd"
|
"gonum.org/v1/gonum/diff/fd"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleDerivative() {
|
func ExampleDerivative() {
|
||||||
@@ -53,12 +53,12 @@ func ExampleJacobian() {
|
|||||||
dst[2] = 4*x[1]*x[1] - 2*x[2]
|
dst[2] = 4*x[1]*x[1] - 2*x[2]
|
||||||
dst[3] = x[2] * math.Sin(x[0])
|
dst[3] = x[2] * math.Sin(x[0])
|
||||||
}
|
}
|
||||||
jac := mat64.NewDense(4, 3, nil)
|
jac := mat.NewDense(4, 3, nil)
|
||||||
fd.Jacobian(jac, f, []float64{1, 2, 3}, &fd.JacobianSettings{
|
fd.Jacobian(jac, f, []float64{1, 2, 3}, &fd.JacobianSettings{
|
||||||
Formula: fd.Central,
|
Formula: fd.Central,
|
||||||
Concurrent: true,
|
Concurrent: true,
|
||||||
})
|
})
|
||||||
fmt.Printf("J ≈ %.6v\n", mat64.Formatted(jac, mat64.Prefix(" ")))
|
fmt.Printf("J ≈ %.6v\n", mat.Formatted(jac, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// J ≈ ⎡ 1 0 0⎤
|
// J ≈ ⎡ 1 0 0⎤
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JacobianSettings struct {
|
type JacobianSettings struct {
|
||||||
@@ -39,7 +39,7 @@ type JacobianSettings struct {
|
|||||||
//
|
//
|
||||||
// dst must be non-nil, the number of its columns must equal the length of x, and
|
// dst must be non-nil, the number of its columns must equal the length of x, and
|
||||||
// the derivative order of the formula must be 1, otherwise Jacobian will panic.
|
// the derivative order of the formula must be 1, otherwise Jacobian will panic.
|
||||||
func Jacobian(dst *mat64.Dense, f func(y, x []float64), x []float64, settings *JacobianSettings) {
|
func Jacobian(dst *mat.Dense, f func(y, x []float64), x []float64, settings *JacobianSettings) {
|
||||||
n := len(x)
|
n := len(x)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
panic("jacobian: x has zero length")
|
panic("jacobian: x has zero length")
|
||||||
@@ -93,7 +93,7 @@ func Jacobian(dst *mat64.Dense, f func(y, x []float64), x []float64, settings *J
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func jacobianSerial(dst *mat64.Dense, f func([]float64, []float64), x, origin []float64, formula Formula, step float64) {
|
func jacobianSerial(dst *mat.Dense, f func([]float64, []float64), x, origin []float64, formula Formula, step float64) {
|
||||||
m, n := dst.Dims()
|
m, n := dst.Dims()
|
||||||
xcopy := make([]float64, n)
|
xcopy := make([]float64, n)
|
||||||
y := make([]float64, m)
|
y := make([]float64, m)
|
||||||
@@ -122,7 +122,7 @@ func jacobianSerial(dst *mat64.Dense, f func([]float64, []float64), x, origin []
|
|||||||
dst.Scale(1/step, dst)
|
dst.Scale(1/step, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func jacobianConcurrent(dst *mat64.Dense, f func([]float64, []float64), x, origin []float64, formula Formula, step float64, nWorkers int) {
|
func jacobianConcurrent(dst *mat.Dense, f func([]float64, []float64), x, origin []float64, formula Formula, step float64, nWorkers int) {
|
||||||
m, n := dst.Dims()
|
m, n := dst.Dims()
|
||||||
for i := 0; i < m; i++ {
|
for i := 0; i < m; i++ {
|
||||||
for j := 0; j < n; j++ {
|
for j := 0; j < n; j++ {
|
||||||
@@ -138,7 +138,7 @@ func jacobianConcurrent(dst *mat64.Dense, f func([]float64, []float64), x, origi
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
xcopy := make([]float64, n)
|
xcopy := make([]float64, n)
|
||||||
y := make([]float64, m)
|
y := make([]float64, m)
|
||||||
yVec := mat64.NewVector(m, y)
|
yVec := mat.NewVector(m, y)
|
||||||
for job := range jobs {
|
for job := range jobs {
|
||||||
copy(xcopy, x)
|
copy(xcopy, x)
|
||||||
xcopy[job.j] += job.pt.Loc * step
|
xcopy[job.j] += job.pt.Loc * step
|
||||||
@@ -182,7 +182,7 @@ func jacobianConcurrent(dst *mat64.Dense, f func([]float64, []float64), x, origi
|
|||||||
// all columns of dst. Iterate again over all Formula points
|
// all columns of dst. Iterate again over all Formula points
|
||||||
// because we don't forbid repeated locations.
|
// because we don't forbid repeated locations.
|
||||||
|
|
||||||
originVec := mat64.NewVector(m, origin)
|
originVec := mat.NewVector(m, origin)
|
||||||
for _, pt := range formula.Stencil {
|
for _, pt := range formula.Stencil {
|
||||||
if pt.Loc != 0 {
|
if pt.Loc != 0 {
|
||||||
continue
|
continue
|
||||||
|
@@ -10,13 +10,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func vecFunc13(y, x []float64) {
|
func vecFunc13(y, x []float64) {
|
||||||
y[0] = 5*x[0] + x[2]*math.Sin(x[1]) + 1
|
y[0] = 5*x[0] + x[2]*math.Sin(x[1]) + 1
|
||||||
}
|
}
|
||||||
func vecFunc13Jac(jac *mat64.Dense, x []float64) {
|
func vecFunc13Jac(jac *mat.Dense, x []float64) {
|
||||||
jac.Set(0, 0, 5)
|
jac.Set(0, 0, 5)
|
||||||
jac.Set(0, 1, x[2]*math.Cos(x[1]))
|
jac.Set(0, 1, x[2]*math.Cos(x[1]))
|
||||||
jac.Set(0, 2, math.Sin(x[1]))
|
jac.Set(0, 2, math.Sin(x[1]))
|
||||||
@@ -26,7 +26,7 @@ func vecFunc22(y, x []float64) {
|
|||||||
y[0] = x[0]*x[0]*x[1] + 1
|
y[0] = x[0]*x[0]*x[1] + 1
|
||||||
y[1] = 5*x[0] + math.Sin(x[1]) + 1
|
y[1] = 5*x[0] + math.Sin(x[1]) + 1
|
||||||
}
|
}
|
||||||
func vecFunc22Jac(jac *mat64.Dense, x []float64) {
|
func vecFunc22Jac(jac *mat.Dense, x []float64) {
|
||||||
jac.Set(0, 0, 2*x[0]*x[1])
|
jac.Set(0, 0, 2*x[0]*x[1])
|
||||||
jac.Set(0, 1, x[0]*x[0])
|
jac.Set(0, 1, x[0]*x[0])
|
||||||
jac.Set(1, 0, 5)
|
jac.Set(1, 0, 5)
|
||||||
@@ -39,7 +39,7 @@ func vecFunc43(y, x []float64) {
|
|||||||
y[2] = 4*x[1]*x[1] - 2*x[2] + 1
|
y[2] = 4*x[1]*x[1] - 2*x[2] + 1
|
||||||
y[3] = x[2]*math.Sin(x[0]) + 1
|
y[3] = x[2]*math.Sin(x[0]) + 1
|
||||||
}
|
}
|
||||||
func vecFunc43Jac(jac *mat64.Dense, x []float64) {
|
func vecFunc43Jac(jac *mat.Dense, x []float64) {
|
||||||
jac.Set(0, 0, 1)
|
jac.Set(0, 0, 1)
|
||||||
jac.Set(0, 1, 0)
|
jac.Set(0, 1, 0)
|
||||||
jac.Set(0, 2, 0)
|
jac.Set(0, 2, 0)
|
||||||
@@ -61,7 +61,7 @@ func TestJacobian(t *testing.T) {
|
|||||||
for tc, test := range []struct {
|
for tc, test := range []struct {
|
||||||
m, n int
|
m, n int
|
||||||
f func([]float64, []float64)
|
f func([]float64, []float64)
|
||||||
jac func(*mat64.Dense, []float64)
|
jac func(*mat.Dense, []float64)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
m: 1,
|
m: 1,
|
||||||
@@ -88,15 +88,15 @@ func TestJacobian(t *testing.T) {
|
|||||||
xcopy := make([]float64, test.n)
|
xcopy := make([]float64, test.n)
|
||||||
copy(xcopy, x)
|
copy(xcopy, x)
|
||||||
|
|
||||||
want := mat64.NewDense(test.m, test.n, nil)
|
want := mat.NewDense(test.m, test.n, nil)
|
||||||
test.jac(want, x)
|
test.jac(want, x)
|
||||||
|
|
||||||
got := mat64.NewDense(test.m, test.n, nil)
|
got := mat.NewDense(test.m, test.n, nil)
|
||||||
fillNaNDense(got)
|
fillNaNDense(got)
|
||||||
Jacobian(got, test.f, x, nil)
|
Jacobian(got, test.f, x, nil)
|
||||||
if !mat64.EqualApprox(want, got, tol) {
|
if !mat.EqualApprox(want, got, tol) {
|
||||||
t.Errorf("Case %d (default settings): unexpected Jacobian.\nwant: %v\ngot: %v",
|
t.Errorf("Case %d (default settings): unexpected Jacobian.\nwant: %v\ngot: %v",
|
||||||
tc, mat64.Formatted(want, mat64.Prefix(" ")), mat64.Formatted(got, mat64.Prefix(" ")))
|
tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" ")))
|
||||||
}
|
}
|
||||||
if !floats.Equal(x, xcopy) {
|
if !floats.Equal(x, xcopy) {
|
||||||
t.Errorf("Case %d (default settings): x modified", tc)
|
t.Errorf("Case %d (default settings): x modified", tc)
|
||||||
@@ -107,7 +107,7 @@ func TestJacobian(t *testing.T) {
|
|||||||
for tc, test := range []struct {
|
for tc, test := range []struct {
|
||||||
m, n int
|
m, n int
|
||||||
f func([]float64, []float64)
|
f func([]float64, []float64)
|
||||||
jac func(*mat64.Dense, []float64)
|
jac func(*mat.Dense, []float64)
|
||||||
tol float64
|
tol float64
|
||||||
formula Formula
|
formula Formula
|
||||||
}{
|
}{
|
||||||
@@ -188,17 +188,17 @@ func TestJacobian(t *testing.T) {
|
|||||||
xcopy := make([]float64, test.n)
|
xcopy := make([]float64, test.n)
|
||||||
copy(xcopy, x)
|
copy(xcopy, x)
|
||||||
|
|
||||||
want := mat64.NewDense(test.m, test.n, nil)
|
want := mat.NewDense(test.m, test.n, nil)
|
||||||
test.jac(want, x)
|
test.jac(want, x)
|
||||||
|
|
||||||
got := mat64.NewDense(test.m, test.n, nil)
|
got := mat.NewDense(test.m, test.n, nil)
|
||||||
fillNaNDense(got)
|
fillNaNDense(got)
|
||||||
Jacobian(got, test.f, x, &JacobianSettings{
|
Jacobian(got, test.f, x, &JacobianSettings{
|
||||||
Formula: test.formula,
|
Formula: test.formula,
|
||||||
})
|
})
|
||||||
if !mat64.EqualApprox(want, got, test.tol) {
|
if !mat.EqualApprox(want, got, test.tol) {
|
||||||
t.Errorf("Case %d: unexpected Jacobian.\nwant: %v\ngot: %v",
|
t.Errorf("Case %d: unexpected Jacobian.\nwant: %v\ngot: %v",
|
||||||
tc, mat64.Formatted(want, mat64.Prefix(" ")), mat64.Formatted(got, mat64.Prefix(" ")))
|
tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" ")))
|
||||||
}
|
}
|
||||||
if !floats.Equal(x, xcopy) {
|
if !floats.Equal(x, xcopy) {
|
||||||
t.Errorf("Case %d: x modified", tc)
|
t.Errorf("Case %d: x modified", tc)
|
||||||
@@ -209,9 +209,9 @@ func TestJacobian(t *testing.T) {
|
|||||||
Formula: test.formula,
|
Formula: test.formula,
|
||||||
Concurrent: true,
|
Concurrent: true,
|
||||||
})
|
})
|
||||||
if !mat64.EqualApprox(want, got, test.tol) {
|
if !mat.EqualApprox(want, got, test.tol) {
|
||||||
t.Errorf("Case %d (concurrent): unexpected Jacobian.\nwant: %v\ngot: %v",
|
t.Errorf("Case %d (concurrent): unexpected Jacobian.\nwant: %v\ngot: %v",
|
||||||
tc, mat64.Formatted(want, mat64.Prefix(" ")), mat64.Formatted(got, mat64.Prefix(" ")))
|
tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" ")))
|
||||||
}
|
}
|
||||||
if !floats.Equal(x, xcopy) {
|
if !floats.Equal(x, xcopy) {
|
||||||
t.Errorf("Case %d (concurrent): x modified", tc)
|
t.Errorf("Case %d (concurrent): x modified", tc)
|
||||||
@@ -224,9 +224,9 @@ func TestJacobian(t *testing.T) {
|
|||||||
Formula: test.formula,
|
Formula: test.formula,
|
||||||
OriginValue: origin,
|
OriginValue: origin,
|
||||||
})
|
})
|
||||||
if !mat64.EqualApprox(want, got, test.tol) {
|
if !mat.EqualApprox(want, got, test.tol) {
|
||||||
t.Errorf("Case %d (origin): unexpected Jacobian.\nwant: %v\ngot: %v",
|
t.Errorf("Case %d (origin): unexpected Jacobian.\nwant: %v\ngot: %v",
|
||||||
tc, mat64.Formatted(want, mat64.Prefix(" ")), mat64.Formatted(got, mat64.Prefix(" ")))
|
tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" ")))
|
||||||
}
|
}
|
||||||
if !floats.Equal(x, xcopy) {
|
if !floats.Equal(x, xcopy) {
|
||||||
t.Errorf("Case %d (origin): x modified", tc)
|
t.Errorf("Case %d (origin): x modified", tc)
|
||||||
@@ -238,9 +238,9 @@ func TestJacobian(t *testing.T) {
|
|||||||
OriginValue: origin,
|
OriginValue: origin,
|
||||||
Concurrent: true,
|
Concurrent: true,
|
||||||
})
|
})
|
||||||
if !mat64.EqualApprox(want, got, test.tol) {
|
if !mat.EqualApprox(want, got, test.tol) {
|
||||||
t.Errorf("Case %d (concurrent, origin): unexpected Jacobian.\nwant: %v\ngot: %v",
|
t.Errorf("Case %d (concurrent, origin): unexpected Jacobian.\nwant: %v\ngot: %v",
|
||||||
tc, mat64.Formatted(want, mat64.Prefix(" ")), mat64.Formatted(got, mat64.Prefix(" ")))
|
tc, mat.Formatted(want, mat.Prefix(" ")), mat.Formatted(got, mat.Prefix(" ")))
|
||||||
}
|
}
|
||||||
if !floats.Equal(x, xcopy) {
|
if !floats.Equal(x, xcopy) {
|
||||||
t.Errorf("Case %d (concurrent, origin): x modified", tc)
|
t.Errorf("Case %d (concurrent, origin): x modified", tc)
|
||||||
@@ -258,7 +258,7 @@ func randomSlice(n int, bound float64) []float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fillNaNDense fills the matrix m with NaN values.
|
// fillNaNDense fills the matrix m with NaN values.
|
||||||
func fillNaNDense(m *mat64.Dense) {
|
func fillNaNDense(m *mat.Dense) {
|
||||||
r, c := m.Dims()
|
r, c := m.Dims()
|
||||||
for i := 0; i < r; i++ {
|
for i := 0; i < r; i++ {
|
||||||
for j := 0; j < c; j++ {
|
for j := 0; j < c; j++ {
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/graph"
|
"gonum.org/v1/gonum/graph"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PageRank returns the PageRank weights for nodes of the directed graph g
|
// PageRank returns the PageRank weights for nodes of the directed graph g
|
||||||
@@ -31,7 +31,7 @@ func PageRank(g graph.Directed, damp, tol float64) map[int]float64 {
|
|||||||
indexOf[n.ID()] = i
|
indexOf[n.ID()] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
m := mat64.NewDense(len(nodes), len(nodes), nil)
|
m := mat.NewDense(len(nodes), len(nodes), nil)
|
||||||
dangling := damp / float64(len(nodes))
|
dangling := damp / float64(len(nodes))
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
to := g.From(u)
|
to := g.From(u)
|
||||||
@@ -45,17 +45,17 @@ func PageRank(g graph.Directed, damp, tol float64) map[int]float64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mat := m.RawMatrix().Data
|
matrix := m.RawMatrix().Data
|
||||||
dt := (1 - damp) / float64(len(nodes))
|
dt := (1 - damp) / float64(len(nodes))
|
||||||
for i := range mat {
|
for i := range matrix {
|
||||||
mat[i] += dt
|
matrix[i] += dt
|
||||||
}
|
}
|
||||||
|
|
||||||
last := make([]float64, len(nodes))
|
last := make([]float64, len(nodes))
|
||||||
for i := range last {
|
for i := range last {
|
||||||
last[i] = 1
|
last[i] = 1
|
||||||
}
|
}
|
||||||
lastV := mat64.NewVector(len(nodes), last)
|
lastV := mat.NewVector(len(nodes), last)
|
||||||
|
|
||||||
vec := make([]float64, len(nodes))
|
vec := make([]float64, len(nodes))
|
||||||
var sum float64
|
var sum float64
|
||||||
@@ -68,7 +68,7 @@ func PageRank(g graph.Directed, damp, tol float64) map[int]float64 {
|
|||||||
for i := range vec {
|
for i := range vec {
|
||||||
vec[i] *= f
|
vec[i] *= f
|
||||||
}
|
}
|
||||||
v := mat64.NewVector(len(nodes), vec)
|
v := mat.NewVector(len(nodes), vec)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
lastV, v = v, lastV
|
lastV, v = v, lastV
|
||||||
@@ -122,7 +122,7 @@ func PageRankSparse(g graph.Directed, damp, tol float64) map[int]float64 {
|
|||||||
for i := range last {
|
for i := range last {
|
||||||
last[i] = 1
|
last[i] = 1
|
||||||
}
|
}
|
||||||
lastV := mat64.NewVector(len(nodes), last)
|
lastV := mat.NewVector(len(nodes), last)
|
||||||
|
|
||||||
vec := make([]float64, len(nodes))
|
vec := make([]float64, len(nodes))
|
||||||
var sum float64
|
var sum float64
|
||||||
@@ -135,7 +135,7 @@ func PageRankSparse(g graph.Directed, damp, tol float64) map[int]float64 {
|
|||||||
for i := range vec {
|
for i := range vec {
|
||||||
vec[i] *= f
|
vec[i] *= f
|
||||||
}
|
}
|
||||||
v := mat64.NewVector(len(nodes), vec)
|
v := mat.NewVector(len(nodes), vec)
|
||||||
|
|
||||||
dt := (1 - damp) / float64(len(nodes))
|
dt := (1 - damp) / float64(len(nodes))
|
||||||
for {
|
for {
|
||||||
@@ -171,7 +171,7 @@ func (m rowCompressedMatrix) addTo(i, j int, v float64) { m[i].addTo(j, v) }
|
|||||||
// mulVecUnitary multiplies the receiver by the src vector, storing
|
// mulVecUnitary multiplies the receiver by the src vector, storing
|
||||||
// the result in dst. It assumes src and dst are the same length as m
|
// the result in dst. It assumes src and dst are the same length as m
|
||||||
// and that both have unitary vector increments.
|
// and that both have unitary vector increments.
|
||||||
func (m rowCompressedMatrix) mulVecUnitary(dst, src *mat64.Vector) {
|
func (m rowCompressedMatrix) mulVecUnitary(dst, src *mat.Vector) {
|
||||||
dMat := dst.RawVector().Data
|
dMat := dst.RawVector().Data
|
||||||
for i, r := range m {
|
for i, r := range m {
|
||||||
dMat[i] = r.dotUnitary(src)
|
dMat[i] = r.dotUnitary(src)
|
||||||
@@ -190,7 +190,7 @@ func (r *compressedRow) addTo(j int, v float64) {
|
|||||||
|
|
||||||
// dotUnitary performs a simplified scatter-based Ddot operations on
|
// dotUnitary performs a simplified scatter-based Ddot operations on
|
||||||
// v and the receiver. v must have have a unitary vector increment.
|
// v and the receiver. v must have have a unitary vector increment.
|
||||||
func (r compressedRow) dotUnitary(v *mat64.Vector) float64 {
|
func (r compressedRow) dotUnitary(v *mat.Vector) float64 {
|
||||||
var sum float64
|
var sum float64
|
||||||
vec := v.RawVector().Data
|
vec := v.RawVector().Data
|
||||||
for _, e := range r {
|
for _, e := range r {
|
||||||
@@ -208,7 +208,7 @@ type sparseElement struct {
|
|||||||
// onesDotUnitary performs the equivalent of a Ddot of v with
|
// onesDotUnitary performs the equivalent of a Ddot of v with
|
||||||
// a ones vector of equal length. v must have have a unitary
|
// a ones vector of equal length. v must have have a unitary
|
||||||
// vector increment.
|
// vector increment.
|
||||||
func onesDotUnitary(alpha float64, v *mat64.Vector) float64 {
|
func onesDotUnitary(alpha float64, v *mat.Vector) float64 {
|
||||||
var sum float64
|
var sum float64
|
||||||
for _, f := range v.RawVector().Data {
|
for _, f := range v.RawVector().Data {
|
||||||
sum += alpha * f
|
sum += alpha * f
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/graph"
|
"gonum.org/v1/gonum/graph"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Shortest is a shortest-path tree created by the BellmanFordFrom or DijkstraFrom
|
// Shortest is a shortest-path tree created by the BellmanFordFrom or DijkstraFrom
|
||||||
@@ -125,7 +125,7 @@ type AllShortest struct {
|
|||||||
//
|
//
|
||||||
// dist contains the pairwise
|
// dist contains the pairwise
|
||||||
// distances between nodes.
|
// distances between nodes.
|
||||||
dist *mat64.Dense
|
dist *mat.Dense
|
||||||
// next contains the shortest-path
|
// next contains the shortest-path
|
||||||
// tree of the graph. The first index
|
// tree of the graph. The first index
|
||||||
// is a linear mapping of from-dense-id
|
// is a linear mapping of from-dense-id
|
||||||
@@ -159,7 +159,7 @@ func newAllShortest(nodes []graph.Node, forward bool) AllShortest {
|
|||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
indexOf: indexOf,
|
indexOf: indexOf,
|
||||||
|
|
||||||
dist: mat64.NewDense(len(nodes), len(nodes), dist),
|
dist: mat.NewDense(len(nodes), len(nodes), dist),
|
||||||
next: make([][]int, len(nodes)*len(nodes)),
|
next: make([][]int, len(nodes)*len(nodes)),
|
||||||
forward: forward,
|
forward: forward,
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/graph"
|
"gonum.org/v1/gonum/graph"
|
||||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DirectedMatrix represents a directed graph using an adjacency
|
// DirectedMatrix represents a directed graph using an adjacency
|
||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// Edges are stored implicitly as an edge weight, so edges stored in
|
// Edges are stored implicitly as an edge weight, so edges stored in
|
||||||
// the graph are not recoverable.
|
// the graph are not recoverable.
|
||||||
type DirectedMatrix struct {
|
type DirectedMatrix struct {
|
||||||
mat *mat64.Dense
|
mat *mat.Dense
|
||||||
nodes []graph.Node
|
nodes []graph.Node
|
||||||
|
|
||||||
self float64
|
self float64
|
||||||
@@ -29,17 +29,17 @@ type DirectedMatrix struct {
|
|||||||
// specifies the cost of self connection, and absent specifies the weight
|
// specifies the cost of self connection, and absent specifies the weight
|
||||||
// returned for absent edges.
|
// returned for absent edges.
|
||||||
func NewDirectedMatrix(n int, init, self, absent float64) *DirectedMatrix {
|
func NewDirectedMatrix(n int, init, self, absent float64) *DirectedMatrix {
|
||||||
mat := make([]float64, n*n)
|
matrix := make([]float64, n*n)
|
||||||
if init != 0 {
|
if init != 0 {
|
||||||
for i := range mat {
|
for i := range matrix {
|
||||||
mat[i] = init
|
matrix[i] = init
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < len(mat); i += n + 1 {
|
for i := 0; i < len(matrix); i += n + 1 {
|
||||||
mat[i] = self
|
matrix[i] = self
|
||||||
}
|
}
|
||||||
return &DirectedMatrix{
|
return &DirectedMatrix{
|
||||||
mat: mat64.NewDense(n, n, mat),
|
mat: mat.NewDense(n, n, matrix),
|
||||||
self: self,
|
self: self,
|
||||||
absent: absent,
|
absent: absent,
|
||||||
}
|
}
|
||||||
@@ -255,10 +255,10 @@ func (g *DirectedMatrix) Degree(n graph.Node) int {
|
|||||||
return deg
|
return deg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matrix returns the mat64.Matrix representation of the graph. The orientation
|
// Matrix returns the mat.Matrix representation of the graph. The orientation
|
||||||
// of the matrix is such that the matrix entry at G_{ij} is the weight of the edge
|
// of the matrix is such that the matrix entry at G_{ij} is the weight of the edge
|
||||||
// from node i to node j.
|
// from node i to node j.
|
||||||
func (g *DirectedMatrix) Matrix() mat64.Matrix {
|
func (g *DirectedMatrix) Matrix() mat.Matrix {
|
||||||
// Prevent alteration of dimensions of the returned matrix.
|
// Prevent alteration of dimensions of the returned matrix.
|
||||||
m := *g.mat
|
m := *g.mat
|
||||||
return &m
|
return &m
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/graph"
|
"gonum.org/v1/gonum/graph"
|
||||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UndirectedMatrix represents an undirected graph using an adjacency
|
// UndirectedMatrix represents an undirected graph using an adjacency
|
||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// Edges are stored implicitly as an edge weight, so edges stored in
|
// Edges are stored implicitly as an edge weight, so edges stored in
|
||||||
// the graph are not recoverable.
|
// the graph are not recoverable.
|
||||||
type UndirectedMatrix struct {
|
type UndirectedMatrix struct {
|
||||||
mat *mat64.SymDense
|
mat *mat.SymDense
|
||||||
nodes []graph.Node
|
nodes []graph.Node
|
||||||
|
|
||||||
self float64
|
self float64
|
||||||
@@ -29,17 +29,17 @@ type UndirectedMatrix struct {
|
|||||||
// specifies the cost of self connection, and absent specifies the weight
|
// specifies the cost of self connection, and absent specifies the weight
|
||||||
// returned for absent edges.
|
// returned for absent edges.
|
||||||
func NewUndirectedMatrix(n int, init, self, absent float64) *UndirectedMatrix {
|
func NewUndirectedMatrix(n int, init, self, absent float64) *UndirectedMatrix {
|
||||||
mat := make([]float64, n*n)
|
matrix := make([]float64, n*n)
|
||||||
if init != 0 {
|
if init != 0 {
|
||||||
for i := range mat {
|
for i := range matrix {
|
||||||
mat[i] = init
|
matrix[i] = init
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < len(mat); i += n + 1 {
|
for i := 0; i < len(matrix); i += n + 1 {
|
||||||
mat[i] = self
|
matrix[i] = self
|
||||||
}
|
}
|
||||||
return &UndirectedMatrix{
|
return &UndirectedMatrix{
|
||||||
mat: mat64.NewSymDense(n, mat),
|
mat: mat.NewSymDense(n, matrix),
|
||||||
self: self,
|
self: self,
|
||||||
absent: absent,
|
absent: absent,
|
||||||
}
|
}
|
||||||
@@ -216,8 +216,8 @@ func (g *UndirectedMatrix) Degree(n graph.Node) int {
|
|||||||
return deg
|
return deg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matrix returns the mat64.Matrix representation of the graph.
|
// Matrix returns the mat.Matrix representation of the graph.
|
||||||
func (g *UndirectedMatrix) Matrix() mat64.Matrix {
|
func (g *UndirectedMatrix) Matrix() mat.Matrix {
|
||||||
// Prevent alteration of dimensions of the returned matrix.
|
// Prevent alteration of dimensions of the returned matrix.
|
||||||
m := *g.mat
|
m := *g.mat
|
||||||
return &m
|
return &m
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/graph"
|
"gonum.org/v1/gonum/graph"
|
||||||
"gonum.org/v1/gonum/graph/simple"
|
"gonum.org/v1/gonum/graph/simple"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
var directedGraphs = []struct {
|
var directedGraphs = []struct {
|
||||||
@@ -19,7 +19,7 @@ var directedGraphs = []struct {
|
|||||||
absent float64
|
absent float64
|
||||||
merge func(x, y float64, xe, ye graph.Edge) float64
|
merge func(x, y float64, xe, ye graph.Edge) float64
|
||||||
|
|
||||||
want mat64.Matrix
|
want mat.Matrix
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
g: func() graph.DirectedBuilder { return simple.NewDirectedGraph(0, 0) },
|
g: func() graph.DirectedBuilder { return simple.NewDirectedGraph(0, 0) },
|
||||||
@@ -28,7 +28,7 @@ var directedGraphs = []struct {
|
|||||||
{F: simple.Node(1), T: simple.Node(0), W: 1},
|
{F: simple.Node(1), T: simple.Node(0), W: 1},
|
||||||
{F: simple.Node(1), T: simple.Node(2), W: 1},
|
{F: simple.Node(1), T: simple.Node(2), W: 1},
|
||||||
},
|
},
|
||||||
want: mat64.NewSymDense(3, []float64{
|
want: mat.NewSymDense(3, []float64{
|
||||||
0, (1. + 2.) / 2., 0,
|
0, (1. + 2.) / 2., 0,
|
||||||
(1. + 2.) / 2., 0, 1. / 2.,
|
(1. + 2.) / 2., 0, 1. / 2.,
|
||||||
0, 1. / 2., 0,
|
0, 1. / 2., 0,
|
||||||
@@ -43,7 +43,7 @@ var directedGraphs = []struct {
|
|||||||
},
|
},
|
||||||
absent: 1,
|
absent: 1,
|
||||||
merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Sqrt(x * y) },
|
merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Sqrt(x * y) },
|
||||||
want: mat64.NewSymDense(3, []float64{
|
want: mat.NewSymDense(3, []float64{
|
||||||
0, math.Sqrt(1 * 2), 0,
|
0, math.Sqrt(1 * 2), 0,
|
||||||
math.Sqrt(1 * 2), 0, math.Sqrt(1 * 1),
|
math.Sqrt(1 * 2), 0, math.Sqrt(1 * 1),
|
||||||
0, math.Sqrt(1 * 1), 0,
|
0, math.Sqrt(1 * 1), 0,
|
||||||
@@ -57,7 +57,7 @@ var directedGraphs = []struct {
|
|||||||
{F: simple.Node(1), T: simple.Node(2), W: 1},
|
{F: simple.Node(1), T: simple.Node(2), W: 1},
|
||||||
},
|
},
|
||||||
merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Min(x, y) },
|
merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Min(x, y) },
|
||||||
want: mat64.NewSymDense(3, []float64{
|
want: mat.NewSymDense(3, []float64{
|
||||||
0, math.Min(1, 2), 0,
|
0, math.Min(1, 2), 0,
|
||||||
math.Min(1, 2), 0, math.Min(1, 0),
|
math.Min(1, 2), 0, math.Min(1, 0),
|
||||||
0, math.Min(1, 0), 0,
|
0, math.Min(1, 0), 0,
|
||||||
@@ -79,7 +79,7 @@ var directedGraphs = []struct {
|
|||||||
}
|
}
|
||||||
return math.Min(x, y)
|
return math.Min(x, y)
|
||||||
},
|
},
|
||||||
want: mat64.NewSymDense(3, []float64{
|
want: mat.NewSymDense(3, []float64{
|
||||||
0, math.Min(1, 2), 0,
|
0, math.Min(1, 2), 0,
|
||||||
math.Min(1, 2), 0, 1,
|
math.Min(1, 2), 0, 1,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
@@ -93,7 +93,7 @@ var directedGraphs = []struct {
|
|||||||
{F: simple.Node(1), T: simple.Node(2), W: 1},
|
{F: simple.Node(1), T: simple.Node(2), W: 1},
|
||||||
},
|
},
|
||||||
merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Max(x, y) },
|
merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Max(x, y) },
|
||||||
want: mat64.NewSymDense(3, []float64{
|
want: mat.NewSymDense(3, []float64{
|
||||||
0, math.Max(1, 2), 0,
|
0, math.Max(1, 2), 0,
|
||||||
math.Max(1, 2), 0, math.Max(1, 0),
|
math.Max(1, 2), 0, math.Max(1, 0),
|
||||||
0, math.Max(1, 0), 0,
|
0, math.Max(1, 0), 0,
|
||||||
@@ -116,10 +116,10 @@ func TestUndirect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mat64.Equal(dst.Matrix(), test.want) {
|
if !mat.Equal(dst.Matrix(), test.want) {
|
||||||
t.Errorf("unexpected result:\ngot:\n%.4v\nwant:\n%.4v",
|
t.Errorf("unexpected result:\ngot:\n%.4v\nwant:\n%.4v",
|
||||||
mat64.Formatted(dst.Matrix()),
|
mat.Formatted(dst.Matrix()),
|
||||||
mat64.Formatted(test.want),
|
mat.Formatted(test.want),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
//+build cblas
|
//+build cblas
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
@@ -3,7 +3,7 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Based on the CholeskyDecomposition class from Jama 1.0.3.
|
// Based on the CholeskyDecomposition class from Jama 1.0.3.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -48,8 +47,8 @@ func (c *Cholesky) updateCond(norm float64) {
|
|||||||
// the condition number somewhat.
|
// the condition number somewhat.
|
||||||
// The norm of the original factorized matrix cannot be stored because of
|
// The norm of the original factorized matrix cannot be stored because of
|
||||||
// update possibilities.
|
// update possibilities.
|
||||||
unorm := lapack64.Lantr(matrix.CondNorm, c.chol.mat, work)
|
unorm := lapack64.Lantr(CondNorm, c.chol.mat, work)
|
||||||
lnorm := lapack64.Lantr(matrix.CondNormTrans, c.chol.mat, work)
|
lnorm := lapack64.Lantr(CondNormTrans, c.chol.mat, work)
|
||||||
norm = unorm * lnorm
|
norm = unorm * lnorm
|
||||||
}
|
}
|
||||||
sym := c.chol.asSymBlas()
|
sym := c.chol.asSymBlas()
|
||||||
@@ -65,15 +64,15 @@ func (c *Cholesky) updateCond(norm float64) {
|
|||||||
func (c *Cholesky) Factorize(a Symmetric) (ok bool) {
|
func (c *Cholesky) Factorize(a Symmetric) (ok bool) {
|
||||||
n := a.Symmetric()
|
n := a.Symmetric()
|
||||||
if c.isZero() {
|
if c.isZero() {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, nil)
|
c.chol = NewTriDense(n, Upper, nil)
|
||||||
} else {
|
} else {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, use(c.chol.mat.Data, n*n))
|
c.chol = NewTriDense(n, Upper, use(c.chol.mat.Data, n*n))
|
||||||
}
|
}
|
||||||
copySymIntoTriangle(c.chol, a)
|
copySymIntoTriangle(c.chol, a)
|
||||||
|
|
||||||
sym := c.chol.asSymBlas()
|
sym := c.chol.asSymBlas()
|
||||||
work := getFloats(c.chol.mat.N, false)
|
work := getFloats(c.chol.mat.N, false)
|
||||||
norm := lapack64.Lansy(matrix.CondNorm, sym, work)
|
norm := lapack64.Lansy(CondNorm, sym, work)
|
||||||
putFloats(work)
|
putFloats(work)
|
||||||
_, ok = lapack64.Potrf(sym)
|
_, ok = lapack64.Potrf(sym)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -98,13 +97,13 @@ func (c *Cholesky) Reset() {
|
|||||||
// not stored inside, the receiver.
|
// not stored inside, the receiver.
|
||||||
func (c *Cholesky) SetFromU(t *TriDense) {
|
func (c *Cholesky) SetFromU(t *TriDense) {
|
||||||
n, kind := t.Triangle()
|
n, kind := t.Triangle()
|
||||||
if kind != matrix.Upper {
|
if kind != Upper {
|
||||||
panic("cholesky: matrix must be upper triangular")
|
panic("cholesky: matrix must be upper triangular")
|
||||||
}
|
}
|
||||||
if c.isZero() {
|
if c.isZero() {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, nil)
|
c.chol = NewTriDense(n, Upper, nil)
|
||||||
} else {
|
} else {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, use(c.chol.mat.Data, n*n))
|
c.chol = NewTriDense(n, Upper, use(c.chol.mat.Data, n*n))
|
||||||
}
|
}
|
||||||
c.chol.Copy(t)
|
c.chol.Copy(t)
|
||||||
c.updateCond(-1)
|
c.updateCond(-1)
|
||||||
@@ -119,9 +118,9 @@ func (c *Cholesky) Clone(chol *Cholesky) {
|
|||||||
}
|
}
|
||||||
n := chol.Size()
|
n := chol.Size()
|
||||||
if c.isZero() {
|
if c.isZero() {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, nil)
|
c.chol = NewTriDense(n, Upper, nil)
|
||||||
} else {
|
} else {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, use(c.chol.mat.Data, n*n))
|
c.chol = NewTriDense(n, Upper, use(c.chol.mat.Data, n*n))
|
||||||
}
|
}
|
||||||
c.chol.Copy(chol.chol)
|
c.chol.Copy(chol.chol)
|
||||||
c.cond = chol.cond
|
c.cond = chol.cond
|
||||||
@@ -164,7 +163,7 @@ func (m *Dense) SolveCholesky(chol *Cholesky, b Matrix) error {
|
|||||||
n := chol.chol.mat.N
|
n := chol.chol.mat.N
|
||||||
bm, bn := b.Dims()
|
bm, bn := b.Dims()
|
||||||
if n != bm {
|
if n != bm {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.reuseAs(bm, bn)
|
m.reuseAs(bm, bn)
|
||||||
@@ -173,8 +172,8 @@ func (m *Dense) SolveCholesky(chol *Cholesky, b Matrix) error {
|
|||||||
}
|
}
|
||||||
blas64.Trsm(blas.Left, blas.Trans, 1, chol.chol.mat, m.mat)
|
blas64.Trsm(blas.Left, blas.Trans, 1, chol.chol.mat, m.mat)
|
||||||
blas64.Trsm(blas.Left, blas.NoTrans, 1, chol.chol.mat, m.mat)
|
blas64.Trsm(blas.Left, blas.NoTrans, 1, chol.chol.mat, m.mat)
|
||||||
if chol.cond > matrix.ConditionTolerance {
|
if chol.cond > ConditionTolerance {
|
||||||
return matrix.Condition(chol.cond)
|
return Condition(chol.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -188,7 +187,7 @@ func (m *Dense) solveTwoChol(a, b *Cholesky) error {
|
|||||||
}
|
}
|
||||||
bn := b.chol.mat.N
|
bn := b.chol.mat.N
|
||||||
if a.chol.mat.N != bn {
|
if a.chol.mat.N != bn {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.reuseAsZeroed(bn, bn)
|
m.reuseAsZeroed(bn, bn)
|
||||||
@@ -196,8 +195,8 @@ func (m *Dense) solveTwoChol(a, b *Cholesky) error {
|
|||||||
blas64.Trsm(blas.Left, blas.Trans, 1, a.chol.mat, m.mat)
|
blas64.Trsm(blas.Left, blas.Trans, 1, a.chol.mat, m.mat)
|
||||||
blas64.Trsm(blas.Left, blas.NoTrans, 1, a.chol.mat, m.mat)
|
blas64.Trsm(blas.Left, blas.NoTrans, 1, a.chol.mat, m.mat)
|
||||||
blas64.Trmm(blas.Right, blas.NoTrans, 1, b.chol.mat, m.mat)
|
blas64.Trmm(blas.Right, blas.NoTrans, 1, b.chol.mat, m.mat)
|
||||||
if a.cond > matrix.ConditionTolerance {
|
if a.cond > ConditionTolerance {
|
||||||
return matrix.Condition(a.cond)
|
return Condition(a.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -211,7 +210,7 @@ func (v *Vector) SolveCholeskyVec(chol *Cholesky, b *Vector) error {
|
|||||||
n := chol.chol.mat.N
|
n := chol.chol.mat.N
|
||||||
vn := b.Len()
|
vn := b.Len()
|
||||||
if vn != n {
|
if vn != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if v != b {
|
if v != b {
|
||||||
v.checkOverlap(b.mat)
|
v.checkOverlap(b.mat)
|
||||||
@@ -222,8 +221,8 @@ func (v *Vector) SolveCholeskyVec(chol *Cholesky, b *Vector) error {
|
|||||||
}
|
}
|
||||||
blas64.Trsv(blas.Trans, chol.chol.mat, v.mat)
|
blas64.Trsv(blas.Trans, chol.chol.mat, v.mat)
|
||||||
blas64.Trsv(blas.NoTrans, chol.chol.mat, v.mat)
|
blas64.Trsv(blas.NoTrans, chol.chol.mat, v.mat)
|
||||||
if chol.cond > matrix.ConditionTolerance {
|
if chol.cond > ConditionTolerance {
|
||||||
return matrix.Condition(chol.cond)
|
return Condition(chol.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
@@ -237,7 +236,7 @@ func (t *TriDense) UFromCholesky(chol *Cholesky) {
|
|||||||
panic(badCholesky)
|
panic(badCholesky)
|
||||||
}
|
}
|
||||||
n := chol.chol.mat.N
|
n := chol.chol.mat.N
|
||||||
t.reuseAs(n, matrix.Upper)
|
t.reuseAs(n, Upper)
|
||||||
t.Copy(chol.chol)
|
t.Copy(chol.chol)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +248,7 @@ func (t *TriDense) LFromCholesky(chol *Cholesky) {
|
|||||||
panic(badCholesky)
|
panic(badCholesky)
|
||||||
}
|
}
|
||||||
n := chol.chol.mat.N
|
n := chol.chol.mat.N
|
||||||
t.reuseAs(n, matrix.Lower)
|
t.reuseAs(n, Lower)
|
||||||
t.Copy(chol.chol.TTri())
|
t.Copy(chol.chol.TTri())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,13 +306,13 @@ func (c *Cholesky) SymRankOne(orig *Cholesky, alpha float64, x *Vector) (ok bool
|
|||||||
}
|
}
|
||||||
n := orig.Size()
|
n := orig.Size()
|
||||||
if x.Len() != n {
|
if x.Len() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if orig != c {
|
if orig != c {
|
||||||
if c.isZero() {
|
if c.isZero() {
|
||||||
c.chol = NewTriDense(n, matrix.Upper, nil)
|
c.chol = NewTriDense(n, Upper, nil)
|
||||||
} else if c.chol.mat.N != n {
|
} else if c.chol.mat.N != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
c.chol.Copy(orig.chol)
|
c.chol.Copy(orig.chol)
|
||||||
}
|
}
|
@@ -2,29 +2,29 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64_test
|
package mat_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleCholesky() {
|
func ExampleCholesky() {
|
||||||
// Construct a symmetric positive definite matrix.
|
// Construct a symmetric positive definite matrix.
|
||||||
tmp := mat64.NewDense(4, 4, []float64{
|
tmp := mat.NewDense(4, 4, []float64{
|
||||||
2, 6, 8, -4,
|
2, 6, 8, -4,
|
||||||
1, 8, 7, -2,
|
1, 8, 7, -2,
|
||||||
2, 2, 1, 7,
|
2, 2, 1, 7,
|
||||||
8, -2, -2, 1,
|
8, -2, -2, 1,
|
||||||
})
|
})
|
||||||
var a mat64.SymDense
|
var a mat.SymDense
|
||||||
a.SymOuterK(1, tmp)
|
a.SymOuterK(1, tmp)
|
||||||
|
|
||||||
fmt.Printf("a = %0.4v\n", mat64.Formatted(&a, mat64.Prefix(" ")))
|
fmt.Printf("a = %0.4v\n", mat.Formatted(&a, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Compute the cholesky factorization.
|
// Compute the cholesky factorization.
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
if ok := chol.Factorize(&a); !ok {
|
if ok := chol.Factorize(&a); !ok {
|
||||||
fmt.Println("a matrix is not positive semi-definite.")
|
fmt.Println("a matrix is not positive semi-definite.")
|
||||||
}
|
}
|
||||||
@@ -33,21 +33,21 @@ func ExampleCholesky() {
|
|||||||
fmt.Printf("\nThe determinant of a is %0.4g\n\n", chol.Det())
|
fmt.Printf("\nThe determinant of a is %0.4g\n\n", chol.Det())
|
||||||
|
|
||||||
// Use the factorization to solve the system of equations a * x = b.
|
// Use the factorization to solve the system of equations a * x = b.
|
||||||
b := mat64.NewVector(4, []float64{1, 2, 3, 4})
|
b := mat.NewVector(4, []float64{1, 2, 3, 4})
|
||||||
var x mat64.Vector
|
var x mat.Vector
|
||||||
if err := x.SolveCholeskyVec(&chol, b); err != nil {
|
if err := x.SolveCholeskyVec(&chol, b); err != nil {
|
||||||
fmt.Println("Matrix is near singular: ", err)
|
fmt.Println("Matrix is near singular: ", err)
|
||||||
}
|
}
|
||||||
fmt.Println("Solve a * x = b")
|
fmt.Println("Solve a * x = b")
|
||||||
fmt.Printf("x = %0.4v\n", mat64.Formatted(&x, mat64.Prefix(" ")))
|
fmt.Printf("x = %0.4v\n", mat.Formatted(&x, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Extract the factorization and check that it equals the original matrix.
|
// Extract the factorization and check that it equals the original matrix.
|
||||||
var t mat64.TriDense
|
var t mat.TriDense
|
||||||
t.LFromCholesky(&chol)
|
t.LFromCholesky(&chol)
|
||||||
var test mat64.Dense
|
var test mat.Dense
|
||||||
test.Mul(&t, t.T())
|
test.Mul(&t, t.T())
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Printf("L * L^T = %0.4v\n", mat64.Formatted(&a, mat64.Prefix(" ")))
|
fmt.Printf("L * L^T = %0.4v\n", mat.Formatted(&a, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// a = ⎡120 114 -4 -16⎤
|
// a = ⎡120 114 -4 -16⎤
|
||||||
@@ -70,35 +70,35 @@ func ExampleCholesky() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleCholeskySymRankOne() {
|
func ExampleCholeskySymRankOne() {
|
||||||
a := mat64.NewSymDense(4, []float64{
|
a := mat.NewSymDense(4, []float64{
|
||||||
1, 1, 1, 1,
|
1, 1, 1, 1,
|
||||||
0, 2, 3, 4,
|
0, 2, 3, 4,
|
||||||
0, 0, 6, 10,
|
0, 0, 6, 10,
|
||||||
0, 0, 0, 20,
|
0, 0, 0, 20,
|
||||||
})
|
})
|
||||||
fmt.Printf("A = %0.4v\n", mat64.Formatted(a, mat64.Prefix(" ")))
|
fmt.Printf("A = %0.4v\n", mat.Formatted(a, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Compute the Cholesky factorization.
|
// Compute the Cholesky factorization.
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
if ok := chol.Factorize(a); !ok {
|
if ok := chol.Factorize(a); !ok {
|
||||||
fmt.Println("matrix a is not positive definite.")
|
fmt.Println("matrix a is not positive definite.")
|
||||||
}
|
}
|
||||||
|
|
||||||
x := mat64.NewVector(4, []float64{0, 0, 0, 1})
|
x := mat.NewVector(4, []float64{0, 0, 0, 1})
|
||||||
fmt.Printf("\nx = %0.4v\n", mat64.Formatted(x, mat64.Prefix(" ")))
|
fmt.Printf("\nx = %0.4v\n", mat.Formatted(x, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Rank-1 update the factorization.
|
// Rank-1 update the factorization.
|
||||||
chol.SymRankOne(&chol, 1, x)
|
chol.SymRankOne(&chol, 1, x)
|
||||||
// Rank-1 update the matrix a.
|
// Rank-1 update the matrix a.
|
||||||
a.SymRankOne(a, 1, x)
|
a.SymRankOne(a, 1, x)
|
||||||
|
|
||||||
var au mat64.SymDense
|
var au mat.SymDense
|
||||||
au.FromCholesky(&chol)
|
au.FromCholesky(&chol)
|
||||||
|
|
||||||
// Print the matrix that was updated directly.
|
// Print the matrix that was updated directly.
|
||||||
fmt.Printf("\nA' = %0.4v\n", mat64.Formatted(a, mat64.Prefix(" ")))
|
fmt.Printf("\nA' = %0.4v\n", mat.Formatted(a, mat.Prefix(" ")))
|
||||||
// Print the matrix recovered from the factorization.
|
// Print the matrix recovered from the factorization.
|
||||||
fmt.Printf("\nU'^T * U' = %0.4v\n", mat64.Formatted(&au, mat64.Prefix(" ")))
|
fmt.Printf("\nU'^T * U' = %0.4v\n", mat.Formatted(&au, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// A = ⎡ 1 1 1 1⎤
|
// A = ⎡ 1 1 1 1⎤
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/blas/testblas"
|
"gonum.org/v1/gonum/blas/testblas"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCholesky(t *testing.T) {
|
func TestCholesky(t *testing.T) {
|
||||||
@@ -269,7 +268,7 @@ func TestCloneCholesky(t *testing.T) {
|
|||||||
|
|
||||||
// Corrupt chol2 and try again
|
// Corrupt chol2 and try again
|
||||||
chol2.cond = math.NaN()
|
chol2.cond = math.NaN()
|
||||||
chol2.chol = NewTriDense(2, matrix.Upper, nil)
|
chol2.chol = NewTriDense(2, Upper, nil)
|
||||||
chol2.Clone(&chol)
|
chol2.Clone(&chol)
|
||||||
if chol.cond != chol2.cond {
|
if chol.cond != chol2.cond {
|
||||||
t.Errorf("condition number mismatch from non-zero")
|
t.Errorf("condition number mismatch from non-zero")
|
@@ -2,10 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package cmat128
|
package mat
|
||||||
|
|
||||||
// Matrix is the basic matrix interface type.
|
// CMatrix is the basic matrix interface type for complex matrices.
|
||||||
type Matrix interface {
|
type CMatrix interface {
|
||||||
// Dims returns the dimensions of a Matrix.
|
// Dims returns the dimensions of a Matrix.
|
||||||
Dims() (r, c int)
|
Dims() (r, c int)
|
||||||
|
|
||||||
@@ -17,11 +17,11 @@ type Matrix interface {
|
|||||||
// returns a copy of the underlying data is implementation dependent.
|
// returns a copy of the underlying data is implementation dependent.
|
||||||
// This method may be implemented using the Conjugate type, which
|
// This method may be implemented using the Conjugate type, which
|
||||||
// provides an implicit matrix conjugate transpose.
|
// provides an implicit matrix conjugate transpose.
|
||||||
H() Matrix
|
H() CMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ Matrix = Conjugate{}
|
_ CMatrix = Conjugate{}
|
||||||
_ Unconjugator = Conjugate{}
|
_ Unconjugator = Conjugate{}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,13 +29,13 @@ var (
|
|||||||
// It implements the Matrix interface, returning values from the conjugate
|
// It implements the Matrix interface, returning values from the conjugate
|
||||||
// transpose of the matrix within.
|
// transpose of the matrix within.
|
||||||
type Conjugate struct {
|
type Conjugate struct {
|
||||||
Matrix Matrix
|
CMatrix CMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
// At returns the value of the element at row i and column j of the transposed
|
// At returns the value of the element at row i and column j of the transposed
|
||||||
// matrix, that is, row j and column i of the Matrix field.
|
// matrix, that is, row j and column i of the Matrix field.
|
||||||
func (t Conjugate) At(i, j int) complex128 {
|
func (t Conjugate) At(i, j int) complex128 {
|
||||||
z := t.Matrix.At(j, i)
|
z := t.CMatrix.At(j, i)
|
||||||
return complex(real(z), -imag(z))
|
return complex(real(z), -imag(z))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,18 +43,18 @@ func (t Conjugate) At(i, j int) complex128 {
|
|||||||
// is the number of columns in the Matrix field, and the number of columns is
|
// is the number of columns in the Matrix field, and the number of columns is
|
||||||
// the number of rows in the Matrix field.
|
// the number of rows in the Matrix field.
|
||||||
func (t Conjugate) Dims() (r, c int) {
|
func (t Conjugate) Dims() (r, c int) {
|
||||||
c, r = t.Matrix.Dims()
|
c, r = t.CMatrix.Dims()
|
||||||
return r, c
|
return r, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// H performs an implicit conjugate transpose by returning the Matrix field.
|
// H performs an implicit conjugate transpose by returning the Matrix field.
|
||||||
func (t Conjugate) H() Matrix {
|
func (t Conjugate) H() CMatrix {
|
||||||
return t.Matrix
|
return t.CMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unconjugate returns the Matrix field.
|
// Unconjugate returns the Matrix field.
|
||||||
func (t Conjugate) Unconjugate() Matrix {
|
func (t Conjugate) Unconjugate() CMatrix {
|
||||||
return t.Matrix
|
return t.CMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unconjugator is a type that can undo an implicit conjugate transpose.
|
// Unconjugator is a type that can undo an implicit conjugate transpose.
|
||||||
@@ -67,5 +67,5 @@ type Unconjugator interface {
|
|||||||
|
|
||||||
// Unconjugate returns the underlying Matrix stored for the implicit
|
// Unconjugate returns the underlying Matrix stored for the implicit
|
||||||
// conjugate transpose.
|
// conjugate transpose.
|
||||||
Unconjugate() Matrix
|
Unconjugate() CMatrix
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package matrix
|
package mat
|
||||||
|
|
||||||
// TriKind represents the triangularity of the matrix.
|
// TriKind represents the triangularity of the matrix.
|
||||||
type TriKind bool
|
type TriKind bool
|
@@ -2,12 +2,11 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -45,7 +44,7 @@ type Dense struct {
|
|||||||
// element in the data slice is the {i, j}-th element in the matrix.
|
// element in the data slice is the {i, j}-th element in the matrix.
|
||||||
func NewDense(r, c int, data []float64) *Dense {
|
func NewDense(r, c int, data []float64) *Dense {
|
||||||
if data != nil && r*c != len(data) {
|
if data != nil && r*c != len(data) {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = make([]float64, r*c)
|
data = make([]float64, r*c)
|
||||||
@@ -83,7 +82,7 @@ func (m *Dense) reuseAs(r, c int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r != m.mat.Rows || c != m.mat.Cols {
|
if r != m.mat.Rows || c != m.mat.Cols {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +108,7 @@ func (m *Dense) reuseAsZeroed(r, c int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r != m.mat.Rows || c != m.mat.Cols {
|
if r != m.mat.Rows || c != m.mat.Cols {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
for i := 0; i < r; i++ {
|
for i := 0; i < r; i++ {
|
||||||
zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c])
|
zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c])
|
||||||
@@ -206,7 +205,7 @@ func (m *Dense) T() Matrix {
|
|||||||
// See ColViewer for more information.
|
// See ColViewer for more information.
|
||||||
func (m *Dense) ColView(j int) *Vector {
|
func (m *Dense) ColView(j int) *Vector {
|
||||||
if j >= m.mat.Cols || j < 0 {
|
if j >= m.mat.Cols || j < 0 {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return &Vector{
|
return &Vector{
|
||||||
mat: blas64.Vector{
|
mat: blas64.Vector{
|
||||||
@@ -221,10 +220,10 @@ func (m *Dense) ColView(j int) *Vector {
|
|||||||
// in src. len(src) must equal the number of rows in the receiver.
|
// in src. len(src) must equal the number of rows in the receiver.
|
||||||
func (m *Dense) SetCol(j int, src []float64) {
|
func (m *Dense) SetCol(j int, src []float64) {
|
||||||
if j >= m.mat.Cols || j < 0 {
|
if j >= m.mat.Cols || j < 0 {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
if len(src) != m.mat.Rows {
|
if len(src) != m.mat.Rows {
|
||||||
panic(matrix.ErrColLength)
|
panic(ErrColLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
blas64.Copy(m.mat.Rows,
|
blas64.Copy(m.mat.Rows,
|
||||||
@@ -237,10 +236,10 @@ func (m *Dense) SetCol(j int, src []float64) {
|
|||||||
// in src. len(src) must equal the number of columns in the receiver.
|
// in src. len(src) must equal the number of columns in the receiver.
|
||||||
func (m *Dense) SetRow(i int, src []float64) {
|
func (m *Dense) SetRow(i int, src []float64) {
|
||||||
if i >= m.mat.Rows || i < 0 {
|
if i >= m.mat.Rows || i < 0 {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if len(src) != m.mat.Cols {
|
if len(src) != m.mat.Cols {
|
||||||
panic(matrix.ErrRowLength)
|
panic(ErrRowLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(m.rawRowView(i), src)
|
copy(m.rawRowView(i), src)
|
||||||
@@ -252,7 +251,7 @@ func (m *Dense) SetRow(i int, src []float64) {
|
|||||||
// See RowViewer for more information.
|
// See RowViewer for more information.
|
||||||
func (m *Dense) RowView(i int) *Vector {
|
func (m *Dense) RowView(i int) *Vector {
|
||||||
if i >= m.mat.Rows || i < 0 {
|
if i >= m.mat.Rows || i < 0 {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
return &Vector{
|
return &Vector{
|
||||||
mat: blas64.Vector{
|
mat: blas64.Vector{
|
||||||
@@ -267,7 +266,7 @@ func (m *Dense) RowView(i int) *Vector {
|
|||||||
// receiver.
|
// receiver.
|
||||||
func (m *Dense) RawRowView(i int) []float64 {
|
func (m *Dense) RawRowView(i int) []float64 {
|
||||||
if i >= m.mat.Rows || i < 0 {
|
if i >= m.mat.Rows || i < 0 {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
return m.rawRowView(i)
|
return m.rawRowView(i)
|
||||||
}
|
}
|
||||||
@@ -294,7 +293,7 @@ func (m *Dense) View(i, j, r, c int) Matrix {
|
|||||||
func (m *Dense) Slice(i, k, j, l int) Matrix {
|
func (m *Dense) Slice(i, k, j, l int) Matrix {
|
||||||
mr, mc := m.Dims()
|
mr, mc := m.Dims()
|
||||||
if i < 0 || mr <= i || j < 0 || mc <= j || k <= i || mr < k || l <= j || mc < l {
|
if i < 0 || mr <= i || j < 0 || mc <= j || k <= i || mr < k || l <= j || mc < l {
|
||||||
panic(matrix.ErrIndexOutOfRange)
|
panic(ErrIndexOutOfRange)
|
||||||
}
|
}
|
||||||
t := *m
|
t := *m
|
||||||
t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (k-1)*t.mat.Stride+l]
|
t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (k-1)*t.mat.Stride+l]
|
||||||
@@ -311,7 +310,7 @@ func (m *Dense) Slice(i, k, j, l int) Matrix {
|
|||||||
// during the call to Grow.
|
// during the call to Grow.
|
||||||
func (m *Dense) Grow(r, c int) Matrix {
|
func (m *Dense) Grow(r, c int) Matrix {
|
||||||
if r < 0 || c < 0 {
|
if r < 0 || c < 0 {
|
||||||
panic(matrix.ErrIndexOutOfRange)
|
panic(ErrIndexOutOfRange)
|
||||||
}
|
}
|
||||||
if r == 0 && c == 0 {
|
if r == 0 && c == 0 {
|
||||||
return m
|
return m
|
||||||
@@ -514,7 +513,7 @@ func (m *Dense) Stack(a, b Matrix) {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ac != bc || m == a || m == b {
|
if ac != bc || m == a || m == b {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.reuseAs(ar+br, ac)
|
m.reuseAs(ar+br, ac)
|
||||||
@@ -532,7 +531,7 @@ func (m *Dense) Augment(a, b Matrix) {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ar != br || m == a || m == b {
|
if ar != br || m == a || m == b {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.reuseAs(ar, ac+bc)
|
m.reuseAs(ar, ac+bc)
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add adds a and b element-wise, placing the result in the receiver. Add
|
// Add adds a and b element-wise, placing the result in the receiver. Add
|
||||||
@@ -19,7 +18,7 @@ func (m *Dense) Add(a, b Matrix) {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ar != br || ac != bc {
|
if ar != br || ac != bc {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
||||||
@@ -66,7 +65,7 @@ func (m *Dense) Sub(a, b Matrix) {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ar != br || ac != bc {
|
if ar != br || ac != bc {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
||||||
@@ -114,7 +113,7 @@ func (m *Dense) MulElem(a, b Matrix) {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ar != br || ac != bc {
|
if ar != br || ac != bc {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
||||||
@@ -162,7 +161,7 @@ func (m *Dense) DivElem(a, b Matrix) {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ar != br || ac != bc {
|
if ar != br || ac != bc {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
||||||
@@ -211,7 +210,7 @@ func (m *Dense) Inverse(a Matrix) error {
|
|||||||
// TODO(btracey): Special case for RawTriangular, etc.
|
// TODO(btracey): Special case for RawTriangular, etc.
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrSquare)
|
panic(ErrSquare)
|
||||||
}
|
}
|
||||||
m.reuseAs(a.Dims())
|
m.reuseAs(a.Dims())
|
||||||
aU, aTrans := untranspose(a)
|
aU, aTrans := untranspose(a)
|
||||||
@@ -234,7 +233,7 @@ func (m *Dense) Inverse(a Matrix) error {
|
|||||||
defer putInts(ipiv)
|
defer putInts(ipiv)
|
||||||
ok := lapack64.Getrf(m.mat, ipiv)
|
ok := lapack64.Getrf(m.mat, ipiv)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
work := getFloats(4*r, false) // must be at least 4*r for cond.
|
work := getFloats(4*r, false) // must be at least 4*r for cond.
|
||||||
lapack64.Getri(m.mat, ipiv, work, -1)
|
lapack64.Getri(m.mat, ipiv, work, -1)
|
||||||
@@ -247,14 +246,14 @@ func (m *Dense) Inverse(a Matrix) error {
|
|||||||
}
|
}
|
||||||
defer putFloats(work)
|
defer putFloats(work)
|
||||||
lapack64.Getri(m.mat, ipiv, work, len(work))
|
lapack64.Getri(m.mat, ipiv, work, len(work))
|
||||||
norm := lapack64.Lange(matrix.CondNorm, m.mat, work)
|
norm := lapack64.Lange(CondNorm, m.mat, work)
|
||||||
rcond := lapack64.Gecon(matrix.CondNorm, m.mat, norm, work, ipiv) // reuse ipiv
|
rcond := lapack64.Gecon(CondNorm, m.mat, norm, work, ipiv) // reuse ipiv
|
||||||
if rcond == 0 {
|
if rcond == 0 {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
cond := 1 / rcond
|
cond := 1 / rcond
|
||||||
if cond > matrix.ConditionTolerance {
|
if cond > ConditionTolerance {
|
||||||
return matrix.Condition(cond)
|
return Condition(cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -266,7 +265,7 @@ func (m *Dense) Mul(a, b Matrix) {
|
|||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
|
|
||||||
if ac != br {
|
if ac != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, aTrans := untranspose(a)
|
aU, aTrans := untranspose(a)
|
||||||
@@ -452,7 +451,7 @@ func strictCopy(m *Dense, a Matrix) {
|
|||||||
if r != m.mat.Rows || c != m.mat.Cols {
|
if r != m.mat.Rows || c != m.mat.Cols {
|
||||||
// Panic with a string since this
|
// Panic with a string since this
|
||||||
// is not a user-facing panic.
|
// is not a user-facing panic.
|
||||||
panic(matrix.ErrShape.Error())
|
panic(ErrShape.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +463,7 @@ func strictCopy(m *Dense, a Matrix) {
|
|||||||
func (m *Dense) Exp(a Matrix) {
|
func (m *Dense) Exp(a Matrix) {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
var w *Dense
|
var w *Dense
|
||||||
@@ -530,7 +529,7 @@ func (m *Dense) Pow(a Matrix, n int) {
|
|||||||
}
|
}
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.reuseAs(r, c)
|
m.reuseAs(r, c)
|
||||||
@@ -657,10 +656,10 @@ func (m *Dense) Apply(fn func(i, j int, v float64) float64, a Matrix) {
|
|||||||
func (m *Dense) RankOne(a Matrix, alpha float64, x, y *Vector) {
|
func (m *Dense) RankOne(a Matrix, alpha float64, x, y *Vector) {
|
||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
if x.Len() != ar {
|
if x.Len() != ar {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if y.Len() != ac {
|
if y.Len() != ac {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.checkOverlap(x.asGeneral())
|
m.checkOverlap(x.asGeneral())
|
||||||
@@ -707,7 +706,7 @@ func (m *Dense) Outer(alpha float64, x, y *Vector) {
|
|||||||
m.capRows = r
|
m.capRows = r
|
||||||
m.capCols = c
|
m.capCols = c
|
||||||
} else if r != m.mat.Rows || c != m.mat.Cols {
|
} else if r != m.mat.Rows || c != m.mat.Cols {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
} else {
|
} else {
|
||||||
m.checkOverlap(x.asGeneral())
|
m.checkOverlap(x.asGeneral())
|
||||||
m.checkOverlap(y.asGeneral())
|
m.checkOverlap(y.asGeneral())
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func asBasicMatrix(d *Dense) Matrix { return (*basicMatrix)(d) }
|
func asBasicMatrix(d *Dense) Matrix { return (*basicMatrix)(d) }
|
||||||
@@ -188,13 +187,13 @@ func TestAtSet(t *testing.T) {
|
|||||||
// Check access out of bounds fails
|
// Check access out of bounds fails
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { m.At(row, 0) })
|
panicked, message := panics(func() { m.At(row, 0) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { m.At(0, col) })
|
panicked, message := panics(func() { m.At(0, col) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,13 +201,13 @@ func TestAtSet(t *testing.T) {
|
|||||||
// Check Set out of bounds
|
// Check Set out of bounds
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { m.Set(row, 0, 1.2) })
|
panicked, message := panics(func() { m.Set(row, 0, 1.2) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { m.Set(0, col, 1.2) })
|
panicked, message := panics(func() { m.Set(0, col, 1.2) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,13 +292,13 @@ func TestRowColView(t *testing.T) {
|
|||||||
|
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { m.At(row, 0) })
|
panicked, message := panics(func() { m.At(row, 0) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access rows=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access rows=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { m.At(0, col) })
|
panicked, message := panics(func() { m.At(0, col) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access cols=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access cols=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -870,7 +869,7 @@ func TestMul(t *testing.T) {
|
|||||||
|
|
||||||
func randDense(size int, rho float64, rnd func() float64) (*Dense, error) {
|
func randDense(size int, rho float64, rnd func() float64) (*Dense, error) {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return nil, matrix.ErrZeroLength
|
return nil, ErrZeroLength
|
||||||
}
|
}
|
||||||
d := &Dense{
|
d := &Dense{
|
||||||
mat: blas64.General{
|
mat: blas64.General{
|
@@ -1,29 +1,26 @@
|
|||||||
// Generated by running
|
|
||||||
// go generate github.com/gonum/matrix
|
|
||||||
// DO NOT EDIT.
|
|
||||||
|
|
||||||
// Copyright ©2015 The gonum Authors. All rights reserved.
|
// Copyright ©2015 The gonum Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Package mat64 provides implementations of float64 matrix structures and
|
// Package mat provides implementations of float64 and complex128 matrix
|
||||||
// linear algebra operations on them.
|
// structures and linear algebra operations on them.
|
||||||
//
|
//
|
||||||
// Overview
|
// Overview
|
||||||
//
|
//
|
||||||
// This section provides a quick overview of the mat64 package. The following
|
// This section provides a quick overview of the mat package. The following
|
||||||
// sections provide more in depth commentary.
|
// sections provide more in depth commentary.
|
||||||
//
|
//
|
||||||
// mat64 provides:
|
// mat provides:
|
||||||
// - Interfaces for Matrix classes (Matrix, Symmetric, Triangular)
|
// - Interfaces for Matrix classes (Matrix, Symmetric, Triangular)
|
||||||
// - Concrete implementations (Dense, SymDense, TriDense)
|
// - Concrete implementations (Dense, SymDense, TriDense)
|
||||||
// - Methods and functions for using matrix data (Add, Trace, SymRankOne)
|
// - Methods and functions for using matrix data (Add, Trace, SymRankOne)
|
||||||
// - Types for constructing and using matrix factorizations (QR, LU)
|
// - Types for constructing and using matrix factorizations (QR, LU)
|
||||||
|
// - The complementary types for complex matrices, CMatrix, CSymDense, etc.
|
||||||
//
|
//
|
||||||
// A matrix may be constructed through the corresponding New function. If no
|
// A matrix may be constructed through the corresponding New function. If no
|
||||||
// backing array is provided the matrix will be initialized to all zeros.
|
// backing array is provided the matrix will be initialized to all zeros.
|
||||||
// // Allocate a zeroed matrix of size 3×5
|
// // Allocate a zeroed real matrix of size 3×5
|
||||||
// zero := mat64.NewDense(3, 5, nil)
|
// zero := mat.NewDense(3, 5, nil)
|
||||||
// If a backing data slice is provided, the matrix will have those elements.
|
// If a backing data slice is provided, the matrix will have those elements.
|
||||||
// Matrices are all stored in row-major format.
|
// Matrices are all stored in row-major format.
|
||||||
// // Generate a 6×6 matrix of random values.
|
// // Generate a 6×6 matrix of random values.
|
||||||
@@ -32,7 +29,6 @@
|
|||||||
// data[i] = rand.NormFloat64()
|
// data[i] = rand.NormFloat64()
|
||||||
// }
|
// }
|
||||||
// a := mat64.NewDense(6, 6, data)
|
// a := mat64.NewDense(6, 6, data)
|
||||||
//
|
|
||||||
// Operations involving matrix data are implemented as functions when the values
|
// Operations involving matrix data are implemented as functions when the values
|
||||||
// of the matrix remain unchanged
|
// of the matrix remain unchanged
|
||||||
// tr := mat64.Trace(a)
|
// tr := mat64.Trace(a)
|
||||||
@@ -42,17 +38,17 @@
|
|||||||
// Receivers must be the correct size for the matrix operations, otherwise the
|
// Receivers must be the correct size for the matrix operations, otherwise the
|
||||||
// operation will panic. As a special case for convenience, a zero-sized matrix
|
// operation will panic. As a special case for convenience, a zero-sized matrix
|
||||||
// will be modified to have the correct size, allocating data if necessary.
|
// will be modified to have the correct size, allocating data if necessary.
|
||||||
// var c mat64.Dense // construct a new zero-sized matrix
|
// var c mat.Dense // construct a new zero-sized matrix
|
||||||
// c.Mul(a, a) // c is automatically adjusted to be 6×6
|
// c.Mul(a, a) // c is automatically adjusted to be 6×6
|
||||||
//
|
//
|
||||||
// The Matrix Interfaces
|
// The Matrix Interfaces
|
||||||
//
|
//
|
||||||
// The Matrix interface is the common link between the concrete types. The Matrix
|
// The Matrix interface is the common link between the concrete types of real
|
||||||
// interface is defined by three functions: Dims, which returns the dimensions
|
// matrices, The Matrix interface is defined by three functions: Dims, which
|
||||||
// of the Matrix, At, which returns the element in the specified location, and
|
// returns the dimensions of the Matrix, At, which returns the element in the
|
||||||
// T for returning a Transpose (discussed later). All of the concrete types can
|
// specified location, and T for returning a Transpose (discussed later). All of
|
||||||
// perform these behaviors and so implement the interface. Methods and functions
|
// the concrete types can perform these behaviors and so implement the interface.
|
||||||
// are designed to use this interface, so in particular the method
|
// Methods and functions are designed to use this interface, so in particular the method
|
||||||
// func (m *Dense) Mul(a, b Matrix)
|
// func (m *Dense) Mul(a, b Matrix)
|
||||||
// constructs a *Dense from the result of a multiplication with any Matrix types,
|
// constructs a *Dense from the result of a multiplication with any Matrix types,
|
||||||
// not just *Dense. Where more restrictive requirements must be met, there are also the
|
// not just *Dense. Where more restrictive requirements must be met, there are also the
|
||||||
@@ -60,12 +56,17 @@
|
|||||||
// func (s *SymDense) AddSym(a, b Symmetric)
|
// func (s *SymDense) AddSym(a, b Symmetric)
|
||||||
// the Symmetric interface guarantees a symmetric result.
|
// the Symmetric interface guarantees a symmetric result.
|
||||||
//
|
//
|
||||||
// Transposes
|
// The CMatrix interface plays the same role for complex matrices. The difference
|
||||||
|
// is that the CMatrix type has the H method instead T, for returning the conjugate
|
||||||
|
// transpose.
|
||||||
//
|
//
|
||||||
// The T method is used for transposition. For example, c.Mul(a.T(), b) computes
|
// (Conjugate) Transposes
|
||||||
// c = a^T * b. The mat64 types implement this method using an implicit transpose —
|
//
|
||||||
// see the Transpose type for more details. Note that some operations have a
|
// The T method is used for transposition on real matrices, and H is used for
|
||||||
// transpose as part of their definition, as in *SymDense.SymOuterK.
|
// conjugate transposition on complex matrices. For example, c.Mul(a.T(), b) computes
|
||||||
|
// c = a^T * b. The mat types implement this method implicitly —
|
||||||
|
// see the Transpose and Conjugate types for more details. Note that some
|
||||||
|
// operations have a transpose as part of their definition, as in *SymDense.SymOuterK.
|
||||||
//
|
//
|
||||||
// Matrix Factorization
|
// Matrix Factorization
|
||||||
//
|
//
|
||||||
@@ -75,19 +76,20 @@
|
|||||||
// var lu mat64.LU
|
// var lu mat64.LU
|
||||||
// lu.Factorize(a)
|
// lu.Factorize(a)
|
||||||
// The elements of the factorization can be extracted through methods on the
|
// The elements of the factorization can be extracted through methods on the
|
||||||
// appropriate type, i.e. *TriDense.LFromLU and *TriDense.UFromLU. Alternatively,
|
// factorized type, i.e. *LU.UTo. The factorization types can also be used directly,
|
||||||
// they can be used directly, as in *Dense.SolveLU. Some factorizations can be
|
// as in *Dense.SolveCholesky. Some factorizations can be updated directly,
|
||||||
// updated directly, without needing to update the original matrix and refactorize,
|
// without needing to update the original matrix and refactorize,
|
||||||
// as in *LU.RankOne.
|
// as in *LU.RankOne.
|
||||||
//
|
//
|
||||||
// BLAS and LAPACK
|
// BLAS and LAPACK
|
||||||
//
|
//
|
||||||
// BLAS and LAPACK are the standard APIs for linear algebra routines. Many
|
// BLAS and LAPACK are the standard APIs for linear algebra routines. Many
|
||||||
// operations in mat64 are implemented using calls to the wrapper functions
|
// operations in mat are implemented using calls to the wrapper functions
|
||||||
// in gonum/blas/blas64 and gonum/lapack/lapack64. By default, blas64 and
|
// in gonum/blas/blas64 and gonum/lapack/lapack64 and their complex equivalents.
|
||||||
// lapack64 call the native Go implementations of the routines. Alternatively,
|
// By default, blas64 and lapack64 call the native Go implementations of the
|
||||||
// it is possible to use C-based implementations of the APIs through the respective
|
// routines. Alternatively, it is possible to use C-based implementations of the
|
||||||
// cgo packages and "Use" functions. The Go implementation of LAPACK makes calls
|
// APIs through the respective cgo packages and "Use" functions. The Go
|
||||||
|
// implementation of LAPACK (used by default) makes calls
|
||||||
// through blas64, so if a cgo BLAS implementation is registered, the lapack64
|
// through blas64, so if a cgo BLAS implementation is registered, the lapack64
|
||||||
// calls will be partially executed in Go and partially executed in C.
|
// calls will be partially executed in Go and partially executed in C.
|
||||||
//
|
//
|
||||||
@@ -121,7 +123,7 @@
|
|||||||
//
|
//
|
||||||
// Element Aliasing
|
// Element Aliasing
|
||||||
//
|
//
|
||||||
// Most methods in mat64 modify receiver data. It is forbidden for the modified
|
// Most methods in mat modify receiver data. It is forbidden for the modified
|
||||||
// data region of the receiver to overlap the used data area of the input
|
// data region of the receiver to overlap the used data area of the input
|
||||||
// arguments. The exception to this rule is when the method receiver is equal to one
|
// arguments. The exception to this rule is when the method receiver is equal to one
|
||||||
// of the input arguments, as in the a.Pow(a, 6) call above, or its implicit transpose.
|
// of the input arguments, as in the a.Pow(a, 6) call above, or its implicit transpose.
|
||||||
@@ -136,7 +138,7 @@
|
|||||||
// your program, you are being clever. Don't be clever. If you must be clever,
|
// your program, you are being clever. Don't be clever. If you must be clever,
|
||||||
// blas64 and lapack64 may be used to call the behavior directly.
|
// blas64 and lapack64 may be used to call the behavior directly.
|
||||||
//
|
//
|
||||||
// mat64 will use the following rules to detect overlap between the receiver and one
|
// mat will use the following rules to detect overlap between the receiver and one
|
||||||
// of the inputs:
|
// of the inputs:
|
||||||
// - the input implements one of the Raw methods, and
|
// - the input implements one of the Raw methods, and
|
||||||
// - the Raw type matches that of the receiver or
|
// - the Raw type matches that of the receiver or
|
||||||
@@ -150,9 +152,9 @@
|
|||||||
// - there is pointer identity between the receiver and input values after
|
// - there is pointer identity between the receiver and input values after
|
||||||
// the value has been untransposed if necessary.
|
// the value has been untransposed if necessary.
|
||||||
//
|
//
|
||||||
// mat64 will not attempt to detect element overlap if the input does not implement a
|
// mat will not attempt to detect element overlap if the input does not implement a
|
||||||
// Raw method, or if the Raw method differs from that of the receiver except when a
|
// Raw method, or if the Raw method differs from that of the receiver except when a
|
||||||
// conversion has occurred through a mat64 API function. Method behavior is undefined
|
// conversion has occurred through a mat API function. Method behavior is undefined
|
||||||
// if there is undetected overlap.
|
// if there is undetected overlap.
|
||||||
//
|
//
|
||||||
package mat64 // import "gonum.org/v1/gonum/matrix/mat64"
|
package mat // import "gonum.org/v1/gonum/mat"
|
@@ -3,12 +3,11 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Based on the EigenvalueDecomposition class from Jama 1.0.3.
|
// Based on the EigenvalueDecomposition class from Jama 1.0.3.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/lapack"
|
"gonum.org/v1/gonum/lapack"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -82,7 +81,7 @@ func (e *EigenSym) Values(dst []float64) []float64 {
|
|||||||
dst = make([]float64, len(e.values))
|
dst = make([]float64, len(e.values))
|
||||||
}
|
}
|
||||||
if len(dst) != len(e.values) {
|
if len(dst) != len(e.values) {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
copy(dst, e.values)
|
copy(dst, e.values)
|
||||||
return dst
|
return dst
|
||||||
@@ -149,7 +148,7 @@ func (e *Eigen) Factorize(a Matrix, left, right bool) (ok bool) {
|
|||||||
// Copy a because it is modified during the Lapack call.
|
// Copy a because it is modified during the Lapack call.
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var sd Dense
|
var sd Dense
|
||||||
sd.Clone(a)
|
sd.Clone(a)
|
||||||
@@ -209,7 +208,7 @@ func (e *Eigen) Values(dst []complex128) []complex128 {
|
|||||||
dst = make([]complex128, e.n)
|
dst = make([]complex128, e.n)
|
||||||
}
|
}
|
||||||
if len(dst) != e.n {
|
if len(dst) != e.n {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
copy(dst, e.values)
|
copy(dst, e.values)
|
||||||
return dst
|
return dst
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package matrix
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package matrix
|
package mat
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
@@ -2,20 +2,20 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64_test
|
package mat_test
|
||||||
|
|
||||||
import "gonum.org/v1/gonum/matrix/mat64"
|
import "gonum.org/v1/gonum/mat"
|
||||||
|
|
||||||
// FAO is a dataset extracted from Food and Agriculture Organization of the
|
// FAO is a dataset extracted from Food and Agriculture Organization of the
|
||||||
// United Nations "FAO Statistical Pocketbook: World Food and Agriculture 2015".
|
// United Nations "FAO Statistical Pocketbook: World Food and Agriculture 2015".
|
||||||
// pp49-52.
|
// pp49-52.
|
||||||
var FAO = struct {
|
var FAO = struct {
|
||||||
Africa *mat64.Dense
|
Africa *mat.Dense
|
||||||
Asia *mat64.Dense
|
Asia *mat.Dense
|
||||||
LatinAmericaCaribbean *mat64.Dense
|
LatinAmericaCaribbean *mat.Dense
|
||||||
Oceania *mat64.Dense
|
Oceania *mat.Dense
|
||||||
}{
|
}{
|
||||||
Africa: mat64.NewDense(21, 3, []float64{
|
Africa: mat.NewDense(21, 3, []float64{
|
||||||
// 1990, 2000, 2014
|
// 1990, 2000, 2014
|
||||||
35.3, 38, 30.7, // Employment in agriculture (%)
|
35.3, 38, 30.7, // Employment in agriculture (%)
|
||||||
9.2, 20.3, 25.2, // Employment in agriculture, female (%)
|
9.2, 20.3, 25.2, // Employment in agriculture, female (%)
|
||||||
@@ -43,7 +43,7 @@ var FAO = struct {
|
|||||||
72, 92, 119, // Fish
|
72, 92, 119, // Fish
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Asia: mat64.NewDense(21, 3, []float64{
|
Asia: mat.NewDense(21, 3, []float64{
|
||||||
// 1990, 2000, 2014
|
// 1990, 2000, 2014
|
||||||
30.9, 24.5, 27.6, // Employment in agriculture (%)
|
30.9, 24.5, 27.6, // Employment in agriculture (%)
|
||||||
40.9, 29.4, 31.1, // Employment in agriculture, female (%)
|
40.9, 29.4, 31.1, // Employment in agriculture, female (%)
|
||||||
@@ -71,7 +71,7 @@ var FAO = struct {
|
|||||||
65, 90, 119, // Fish
|
65, 90, 119, // Fish
|
||||||
}),
|
}),
|
||||||
|
|
||||||
LatinAmericaCaribbean: mat64.NewDense(14, 3, []float64{
|
LatinAmericaCaribbean: mat.NewDense(14, 3, []float64{
|
||||||
// 1990, 2000, 2014
|
// 1990, 2000, 2014
|
||||||
19.5, 14.2, 15.8, // Employment in agriculture (%)
|
19.5, 14.2, 15.8, // Employment in agriculture (%)
|
||||||
13.7, 6.2, 7.6, // Employment in agriculture, female (%)
|
13.7, 6.2, 7.6, // Employment in agriculture, female (%)
|
||||||
@@ -92,7 +92,7 @@ var FAO = struct {
|
|||||||
82, 107, 71, // Fish
|
82, 107, 71, // Fish
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Oceania: mat64.NewDense(21, 3, []float64{
|
Oceania: mat.NewDense(21, 3, []float64{
|
||||||
// 1990, 2000, 2014
|
// 1990, 2000, 2014
|
||||||
6.2, 17.1, 3.8, // Employment in agriculture (%)
|
6.2, 17.1, 3.8, // Employment in agriculture (%)
|
||||||
4.5, 3.9, 4.4, // Employment in agriculture, female (%)
|
4.5, 3.9, 4.4, // Employment in agriculture, female (%)
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@@ -2,20 +2,20 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64_test
|
package mat_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleFormatted() {
|
func ExampleFormatted() {
|
||||||
a := mat64.NewDense(3, 3, []float64{1, 2, 3, 0, 4, 5, 0, 0, 6})
|
a := mat.NewDense(3, 3, []float64{1, 2, 3, 0, 4, 5, 0, 0, 6})
|
||||||
|
|
||||||
// Create a matrix formatting value with a prefix and calculating each column
|
// Create a matrix formatting value with a prefix and calculating each column
|
||||||
// width individually...
|
// width individually...
|
||||||
fa := mat64.Formatted(a, mat64.Prefix(" "), mat64.Squeeze())
|
fa := mat.Formatted(a, mat.Prefix(" "), mat.Squeeze())
|
||||||
|
|
||||||
// and then print with and without zero value elements.
|
// and then print with and without zero value elements.
|
||||||
fmt.Printf("with all values:\na = %v\n\n", fa)
|
fmt.Printf("with all values:\na = %v\n\n", fa)
|
||||||
@@ -61,27 +61,27 @@ func ExampleExcerpt() {
|
|||||||
// matrices and vectors.
|
// matrices and vectors.
|
||||||
|
|
||||||
// The big matrix is too large to properly print...
|
// The big matrix is too large to properly print...
|
||||||
big := mat64.NewDense(100, 100, nil)
|
big := mat.NewDense(100, 100, nil)
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
big.Set(i, i, 1)
|
big.Set(i, i, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// so only print corner excerpts of the matrix.
|
// so only print corner excerpts of the matrix.
|
||||||
fmt.Printf("excerpt big identity matrix: %v\n\n",
|
fmt.Printf("excerpt big identity matrix: %v\n\n",
|
||||||
mat64.Formatted(big, mat64.Prefix(" "), mat64.Excerpt(3)))
|
mat.Formatted(big, mat.Prefix(" "), mat.Excerpt(3)))
|
||||||
|
|
||||||
// The long vector is also too large, ...
|
// The long vector is also too large, ...
|
||||||
long := mat64.NewVector(100, nil)
|
long := mat.NewVector(100, nil)
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
long.SetVec(i, float64(i))
|
long.SetVec(i, float64(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... so print end excerpts of the vector,
|
// ... so print end excerpts of the vector,
|
||||||
fmt.Printf("excerpt long column vector: %v\n\n",
|
fmt.Printf("excerpt long column vector: %v\n\n",
|
||||||
mat64.Formatted(long, mat64.Prefix(" "), mat64.Excerpt(3)))
|
mat.Formatted(long, mat.Prefix(" "), mat.Excerpt(3)))
|
||||||
// or its transpose.
|
// or its transpose.
|
||||||
fmt.Printf("excerpt long row vector: %v\n",
|
fmt.Printf("excerpt long row vector: %v\n",
|
||||||
mat64.Formatted(long.T(), mat64.Prefix(" "), mat64.Excerpt(3)))
|
mat.Formatted(long.T(), mat.Prefix(" "), mat.Excerpt(3)))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// excerpt big identity matrix: Dims(100, 100)
|
// excerpt big identity matrix: Dims(100, 100)
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -26,8 +26,8 @@ func TestFormat(t *testing.T) {
|
|||||||
[]rp{
|
[]rp{
|
||||||
{"%v", "⎡0 0 0⎤\n⎢0 0 0⎥\n⎣0 0 0⎦"},
|
{"%v", "⎡0 0 0⎤\n⎢0 0 0⎥\n⎣0 0 0⎦"},
|
||||||
{"% f", "⎡. . .⎤\n⎢. . .⎥\n⎣. . .⎦"},
|
{"% f", "⎡. . .⎤\n⎢. . .⎥\n⎣. . .⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{0, 0, 0, 0, 0, 0, 0, 0, 0}}, capRows:3, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{0, 0, 0, 0, 0, 0, 0, 0, 0}}, capRows:3, capCols:3}"},
|
||||||
{"%s", "%!s(*mat64.Dense=Dims(3, 3))"},
|
{"%s", "%!s(*mat.Dense=Dims(3, 3))"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -35,7 +35,7 @@ func TestFormat(t *testing.T) {
|
|||||||
[]rp{
|
[]rp{
|
||||||
{"%v", "⎡1 1 1⎤\n⎢1 1 1⎥\n⎣1 1 1⎦"},
|
{"%v", "⎡1 1 1⎤\n⎢1 1 1⎥\n⎣1 1 1⎦"},
|
||||||
{"% f", "⎡1 1 1⎤\n⎢1 1 1⎥\n⎣1 1 1⎦"},
|
{"% f", "⎡1 1 1⎤\n⎢1 1 1⎥\n⎣1 1 1⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{1, 1, 1, 1, 1, 1, 1, 1, 1}}, capRows:3, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{1, 1, 1, 1, 1, 1, 1, 1, 1}}, capRows:3, capCols:3}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -43,7 +43,7 @@ func TestFormat(t *testing.T) {
|
|||||||
[]rp{
|
[]rp{
|
||||||
{"%v", "⎡1 1 1⎤\n\t⎢1 1 1⎥\n\t⎣1 1 1⎦"},
|
{"%v", "⎡1 1 1⎤\n\t⎢1 1 1⎥\n\t⎣1 1 1⎦"},
|
||||||
{"% f", "⎡1 1 1⎤\n\t⎢1 1 1⎥\n\t⎣1 1 1⎦"},
|
{"% f", "⎡1 1 1⎤\n\t⎢1 1 1⎥\n\t⎣1 1 1⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{1, 1, 1, 1, 1, 1, 1, 1, 1}}, capRows:3, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{1, 1, 1, 1, 1, 1, 1, 1, 1}}, capRows:3, capCols:3}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,7 @@ func TestFormat(t *testing.T) {
|
|||||||
[]rp{
|
[]rp{
|
||||||
{"%v", "⎡1 0 0⎤\n⎢0 1 0⎥\n⎣0 0 1⎦"},
|
{"%v", "⎡1 0 0⎤\n⎢0 1 0⎥\n⎣0 0 1⎦"},
|
||||||
{"% f", "⎡1 . .⎤\n⎢. 1 .⎥\n⎣. . 1⎦"},
|
{"% f", "⎡1 . .⎤\n⎢. 1 .⎥\n⎣. . 1⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{1, 0, 0, 0, 1, 0, 0, 0, 1}}, capRows:3, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:3, Cols:3, Stride:3, Data:[]float64{1, 0, 0, 0, 1, 0, 0, 0, 1}}, capRows:3, capCols:3}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -59,7 +59,7 @@ func TestFormat(t *testing.T) {
|
|||||||
[]rp{
|
[]rp{
|
||||||
{"%v", "⎡1 2 3⎤\n⎣4 5 6⎦"},
|
{"%v", "⎡1 2 3⎤\n⎣4 5 6⎦"},
|
||||||
{"% f", "⎡1 2 3⎤\n⎣4 5 6⎦"},
|
{"% f", "⎡1 2 3⎤\n⎣4 5 6⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:2, Cols:3, Stride:3, Data:[]float64{1, 2, 3, 4, 5, 6}}, capRows:2, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:2, Cols:3, Stride:3, Data:[]float64{1, 2, 3, 4, 5, 6}}, capRows:2, capCols:3}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -67,7 +67,7 @@ func TestFormat(t *testing.T) {
|
|||||||
[]rp{
|
[]rp{
|
||||||
{"%v", "⎡1 2⎤\n⎢3 4⎥\n⎣5 6⎦"},
|
{"%v", "⎡1 2⎤\n⎢3 4⎥\n⎣5 6⎦"},
|
||||||
{"% f", "⎡1 2⎤\n⎢3 4⎥\n⎣5 6⎦"},
|
{"% f", "⎡1 2⎤\n⎢3 4⎥\n⎣5 6⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:3, Cols:2, Stride:2, Data:[]float64{1, 2, 3, 4, 5, 6}}, capRows:3, capCols:2}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:3, Cols:2, Stride:2, Data:[]float64{1, 2, 3, 4, 5, 6}}, capRows:3, capCols:2}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -80,7 +80,7 @@ func TestFormat(t *testing.T) {
|
|||||||
{"%v", "⎡ 0 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
{"%v", "⎡ 0 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
||||||
{"%.2f", "⎡0.00 1.00 1.41⎤\n⎣1.73 2.00 2.24⎦"},
|
{"%.2f", "⎡0.00 1.00 1.41⎤\n⎣1.73 2.00 2.24⎦"},
|
||||||
{"% f", "⎡ . 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
{"% f", "⎡ . 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:2, Cols:3, Stride:3, Data:[]float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}}, capRows:2, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:2, Cols:3, Stride:3, Data:[]float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}}, capRows:2, capCols:3}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ func TestFormat(t *testing.T) {
|
|||||||
{"%v", "⎡ 0 1⎤\n⎢1.4142135623730951 1.7320508075688772⎥\n⎣ 2 2.23606797749979⎦"},
|
{"%v", "⎡ 0 1⎤\n⎢1.4142135623730951 1.7320508075688772⎥\n⎣ 2 2.23606797749979⎦"},
|
||||||
{"%.2f", "⎡0.00 1.00⎤\n⎢1.41 1.73⎥\n⎣2.00 2.24⎦"},
|
{"%.2f", "⎡0.00 1.00⎤\n⎢1.41 1.73⎥\n⎣2.00 2.24⎦"},
|
||||||
{"% f", "⎡ . 1⎤\n⎢1.4142135623730951 1.7320508075688772⎥\n⎣ 2 2.23606797749979⎦"},
|
{"% f", "⎡ . 1⎤\n⎢1.4142135623730951 1.7320508075688772⎥\n⎣ 2 2.23606797749979⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:3, Cols:2, Stride:2, Data:[]float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}}, capRows:3, capCols:2}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:3, Cols:2, Stride:2, Data:[]float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}}, capRows:3, capCols:2}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@ func TestFormat(t *testing.T) {
|
|||||||
{"%v", "⎡ 0 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
{"%v", "⎡ 0 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
||||||
{"%.2f", "⎡0.00 1.00 1.41⎤\n⎣1.73 2.00 2.24⎦"},
|
{"%.2f", "⎡0.00 1.00 1.41⎤\n⎣1.73 2.00 2.24⎦"},
|
||||||
{"% f", "⎡ . 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
{"% f", "⎡ . 1 1.4142135623730951⎤\n⎣1.7320508075688772 2 2.23606797749979⎦"},
|
||||||
{"%#v", "&mat64.Dense{mat:blas64.General{Rows:2, Cols:3, Stride:3, Data:[]float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}}, capRows:2, capCols:3}"},
|
{"%#v", "&mat.Dense{mat:blas64.General{Rows:2, Cols:3, Stride:3, Data:[]float64{0, 1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979}}, capRows:2, capCols:3}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
@@ -3,14 +3,13 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Based on the SingularValueDecomposition class from Jama 1.0.3.
|
// Based on the SingularValueDecomposition class from Jama 1.0.3.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/lapack"
|
"gonum.org/v1/gonum/lapack"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GSVD is a type for creating and using the Generalized Singular Value Decomposition
|
// GSVD is a type for creating and using the Generalized Singular Value Decomposition
|
||||||
@@ -20,7 +19,7 @@ import (
|
|||||||
// variable×sample spaces to reduced and diagonalized "eigenvariable"×"eigensample"
|
// variable×sample spaces to reduced and diagonalized "eigenvariable"×"eigensample"
|
||||||
// spaces.
|
// spaces.
|
||||||
type GSVD struct {
|
type GSVD struct {
|
||||||
kind matrix.GSVDKind
|
kind GSVDKind
|
||||||
|
|
||||||
r, p, c, k, l int
|
r, p, c, k, l int
|
||||||
s1, s2 []float64
|
s1, s2 []float64
|
||||||
@@ -50,24 +49,24 @@ type GSVD struct {
|
|||||||
//
|
//
|
||||||
// Factorize returns whether the decomposition succeeded. If the decomposition
|
// Factorize returns whether the decomposition succeeded. If the decomposition
|
||||||
// failed, routines that require a successful factorization will panic.
|
// failed, routines that require a successful factorization will panic.
|
||||||
func (gsvd *GSVD) Factorize(a, b Matrix, kind matrix.GSVDKind) (ok bool) {
|
func (gsvd *GSVD) Factorize(a, b Matrix, kind GSVDKind) (ok bool) {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
gsvd.r, gsvd.c = r, c
|
gsvd.r, gsvd.c = r, c
|
||||||
p, c := b.Dims()
|
p, c := b.Dims()
|
||||||
gsvd.p = p
|
gsvd.p = p
|
||||||
if gsvd.c != c {
|
if gsvd.c != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var jobU, jobV, jobQ lapack.GSVDJob
|
var jobU, jobV, jobQ lapack.GSVDJob
|
||||||
switch {
|
switch {
|
||||||
default:
|
default:
|
||||||
panic("gsvd: bad input kind")
|
panic("gsvd: bad input kind")
|
||||||
case kind == matrix.GSVDNone:
|
case kind == GSVDNone:
|
||||||
jobU = lapack.GSVDNone
|
jobU = lapack.GSVDNone
|
||||||
jobV = lapack.GSVDNone
|
jobV = lapack.GSVDNone
|
||||||
jobQ = lapack.GSVDNone
|
jobQ = lapack.GSVDNone
|
||||||
case (matrix.GSVDU|matrix.GSVDV|matrix.GSVDQ)&kind != 0:
|
case (GSVDU|GSVDV|GSVDQ)&kind != 0:
|
||||||
if matrix.GSVDU&kind != 0 {
|
if GSVDU&kind != 0 {
|
||||||
jobU = lapack.GSVDU
|
jobU = lapack.GSVDU
|
||||||
gsvd.u = blas64.General{
|
gsvd.u = blas64.General{
|
||||||
Rows: r,
|
Rows: r,
|
||||||
@@ -76,7 +75,7 @@ func (gsvd *GSVD) Factorize(a, b Matrix, kind matrix.GSVDKind) (ok bool) {
|
|||||||
Data: use(gsvd.u.Data, r*r),
|
Data: use(gsvd.u.Data, r*r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matrix.GSVDV&kind != 0 {
|
if GSVDV&kind != 0 {
|
||||||
jobV = lapack.GSVDV
|
jobV = lapack.GSVDV
|
||||||
gsvd.v = blas64.General{
|
gsvd.v = blas64.General{
|
||||||
Rows: p,
|
Rows: p,
|
||||||
@@ -85,7 +84,7 @@ func (gsvd *GSVD) Factorize(a, b Matrix, kind matrix.GSVDKind) (ok bool) {
|
|||||||
Data: use(gsvd.v.Data, p*p),
|
Data: use(gsvd.v.Data, p*p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matrix.GSVDQ&kind != 0 {
|
if GSVDQ&kind != 0 {
|
||||||
jobQ = lapack.GSVDQ
|
jobQ = lapack.GSVDQ
|
||||||
gsvd.q = blas64.General{
|
gsvd.q = blas64.General{
|
||||||
Rows: c,
|
Rows: c,
|
||||||
@@ -119,7 +118,7 @@ func (gsvd *GSVD) Factorize(a, b Matrix, kind matrix.GSVDKind) (ok bool) {
|
|||||||
|
|
||||||
// Kind returns the matrix.GSVDKind of the decomposition. If no decomposition has been
|
// Kind returns the matrix.GSVDKind of the decomposition. If no decomposition has been
|
||||||
// computed, Kind returns 0.
|
// computed, Kind returns 0.
|
||||||
func (gsvd *GSVD) Kind() matrix.GSVDKind {
|
func (gsvd *GSVD) Kind() GSVDKind {
|
||||||
return gsvd.kind
|
return gsvd.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +146,7 @@ func (gsvd *GSVD) GeneralizedValues(v []float64) []float64 {
|
|||||||
v = make([]float64, d-k)
|
v = make([]float64, d-k)
|
||||||
}
|
}
|
||||||
if len(v) != d-k {
|
if len(v) != d-k {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
floats.DivTo(v, gsvd.s1[k:d], gsvd.s2[k:d])
|
floats.DivTo(v, gsvd.s1[k:d], gsvd.s2[k:d])
|
||||||
return v
|
return v
|
||||||
@@ -172,7 +171,7 @@ func (gsvd *GSVD) ValuesA(s []float64) []float64 {
|
|||||||
s = make([]float64, d-k)
|
s = make([]float64, d-k)
|
||||||
}
|
}
|
||||||
if len(s) != d-k {
|
if len(s) != d-k {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
copy(s, gsvd.s1[k:min(r, c)])
|
copy(s, gsvd.s1[k:min(r, c)])
|
||||||
return s
|
return s
|
||||||
@@ -197,7 +196,7 @@ func (gsvd *GSVD) ValuesB(s []float64) []float64 {
|
|||||||
s = make([]float64, d-k)
|
s = make([]float64, d-k)
|
||||||
}
|
}
|
||||||
if len(s) != d-k {
|
if len(s) != d-k {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
copy(s, gsvd.s2[k:d])
|
copy(s, gsvd.s2[k:d])
|
||||||
return s
|
return s
|
||||||
@@ -300,7 +299,7 @@ func (gsvd *GSVD) SigmaBTo(dst *Dense) *Dense {
|
|||||||
//
|
//
|
||||||
// UTo will panic if the receiver does not contain a successful factorization.
|
// UTo will panic if the receiver does not contain a successful factorization.
|
||||||
func (gsvd *GSVD) UTo(dst *Dense) *Dense {
|
func (gsvd *GSVD) UTo(dst *Dense) *Dense {
|
||||||
if gsvd.kind&matrix.GSVDU == 0 {
|
if gsvd.kind&GSVDU == 0 {
|
||||||
panic("mat64: improper GSVD kind")
|
panic("mat64: improper GSVD kind")
|
||||||
}
|
}
|
||||||
r := gsvd.u.Rows
|
r := gsvd.u.Rows
|
||||||
@@ -326,7 +325,7 @@ func (gsvd *GSVD) UTo(dst *Dense) *Dense {
|
|||||||
//
|
//
|
||||||
// VTo will panic if the receiver does not contain a successful factorization.
|
// VTo will panic if the receiver does not contain a successful factorization.
|
||||||
func (gsvd *GSVD) VTo(dst *Dense) *Dense {
|
func (gsvd *GSVD) VTo(dst *Dense) *Dense {
|
||||||
if gsvd.kind&matrix.GSVDV == 0 {
|
if gsvd.kind&GSVDV == 0 {
|
||||||
panic("mat64: improper GSVD kind")
|
panic("mat64: improper GSVD kind")
|
||||||
}
|
}
|
||||||
r := gsvd.v.Rows
|
r := gsvd.v.Rows
|
||||||
@@ -352,7 +351,7 @@ func (gsvd *GSVD) VTo(dst *Dense) *Dense {
|
|||||||
//
|
//
|
||||||
// QTo will panic if the receiver does not contain a successful factorization.
|
// QTo will panic if the receiver does not contain a successful factorization.
|
||||||
func (gsvd *GSVD) QTo(dst *Dense) *Dense {
|
func (gsvd *GSVD) QTo(dst *Dense) *Dense {
|
||||||
if gsvd.kind&matrix.GSVDQ == 0 {
|
if gsvd.kind&GSVDQ == 0 {
|
||||||
panic("mat64: improper GSVD kind")
|
panic("mat64: improper GSVD kind")
|
||||||
}
|
}
|
||||||
r := gsvd.q.Rows
|
r := gsvd.q.Rows
|
@@ -2,15 +2,14 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64_test
|
package mat_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleGSVD() {
|
func ExampleGSVD() {
|
||||||
@@ -19,8 +18,8 @@ func ExampleGSVD() {
|
|||||||
//
|
//
|
||||||
// See Lee et al. doi:10.1371/journal.pone.0030098 and
|
// See Lee et al. doi:10.1371/journal.pone.0030098 and
|
||||||
// Alter at al. doi:10.1073/pnas.0530258100 for more details.
|
// Alter at al. doi:10.1073/pnas.0530258100 for more details.
|
||||||
var gsvd mat64.GSVD
|
var gsvd mat.GSVD
|
||||||
ok := gsvd.Factorize(FAO.Africa, FAO.LatinAmericaCaribbean, matrix.GSVDU|matrix.GSVDV|matrix.GSVDQ)
|
ok := gsvd.Factorize(FAO.Africa, FAO.LatinAmericaCaribbean, mat.GSVDU|mat.GSVDV|mat.GSVDQ)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("GSVD factorization failed")
|
log.Fatal("GSVD factorization failed")
|
||||||
}
|
}
|
||||||
@@ -32,14 +31,14 @@ func ExampleGSVD() {
|
|||||||
s2 := gsvd.ValuesB(nil)
|
s2 := gsvd.ValuesB(nil)
|
||||||
|
|
||||||
fmt.Printf("Africa\n\ts1 = %.4f\n\n\tU = %.4f\n\n",
|
fmt.Printf("Africa\n\ts1 = %.4f\n\n\tU = %.4f\n\n",
|
||||||
s1, mat64.Formatted(u, mat64.Prefix("\t "), mat64.Excerpt(2)))
|
s1, mat.Formatted(u, mat.Prefix("\t "), mat.Excerpt(2)))
|
||||||
fmt.Printf("Latin America/Caribbean\n\ts2 = %.4f\n\n\tV = %.4f\n",
|
fmt.Printf("Latin America/Caribbean\n\ts2 = %.4f\n\n\tV = %.4f\n",
|
||||||
s2, mat64.Formatted(v, mat64.Prefix("\t "), mat64.Excerpt(2)))
|
s2, mat.Formatted(v, mat.Prefix("\t "), mat.Excerpt(2)))
|
||||||
|
|
||||||
var q mat64.Dense
|
var q mat.Dense
|
||||||
q.Mul(gsvd.ZeroRTo(nil), gsvd.QTo(nil))
|
q.Mul(gsvd.ZeroRTo(nil), gsvd.QTo(nil))
|
||||||
fmt.Printf("\nCommon basis vectors\n\n\tQ^T = %.4f\n",
|
fmt.Printf("\nCommon basis vectors\n\n\tQ^T = %.4f\n",
|
||||||
mat64.Formatted(q.T(), mat64.Prefix("\t ")))
|
mat.Formatted(q.T(), mat.Prefix("\t ")))
|
||||||
|
|
||||||
// Calculate the antisymmetric angular distances for each eigenvariable.
|
// Calculate the antisymmetric angular distances for each eigenvariable.
|
||||||
fmt.Println("\nSignificance:")
|
fmt.Println("\nSignificance:")
|
@@ -2,14 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGSVD(t *testing.T) {
|
func TestGSVD(t *testing.T) {
|
||||||
@@ -49,7 +48,7 @@ func TestGSVD(t *testing.T) {
|
|||||||
|
|
||||||
// Test Full decomposition.
|
// Test Full decomposition.
|
||||||
var gsvd GSVD
|
var gsvd GSVD
|
||||||
ok := gsvd.Factorize(a, b, matrix.GSVDU|matrix.GSVDV|matrix.GSVDQ)
|
ok := gsvd.Factorize(a, b, GSVDU|GSVDV|GSVDQ)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("GSVD factorization failed")
|
t.Errorf("GSVD factorization failed")
|
||||||
}
|
}
|
||||||
@@ -83,7 +82,7 @@ func TestGSVD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test None decomposition.
|
// Test None decomposition.
|
||||||
ok = gsvd.Factorize(a, b, matrix.GSVDNone)
|
ok = gsvd.Factorize(a, b, GSVDNone)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("GSVD factorization failed")
|
t.Errorf("GSVD factorization failed")
|
||||||
}
|
}
|
@@ -3,13 +3,12 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Based on the SingularValueDecomposition class from Jama 1.0.3.
|
// Based on the SingularValueDecomposition class from Jama 1.0.3.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HOGSVD is a type for creating and using the Higher Order Generalized Singular Value
|
// HOGSVD is a type for creating and using the Higher Order Generalized Singular Value
|
||||||
@@ -58,14 +57,14 @@ func (gsvd *HOGSVD) Factorize(m ...Matrix) (ok bool) {
|
|||||||
for i, d := range m {
|
for i, d := range m {
|
||||||
rd, cd := d.Dims()
|
rd, cd := d.Dims()
|
||||||
if rd < cd {
|
if rd < cd {
|
||||||
gsvd.err = matrix.ErrShape
|
gsvd.err = ErrShape
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if rd > r {
|
if rd > r {
|
||||||
r = rd
|
r = rd
|
||||||
}
|
}
|
||||||
if cd != c {
|
if cd != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
ts.Reset()
|
ts.Reset()
|
||||||
ts.SymOuterK(1, d.T())
|
ts.SymOuterK(1, d.T())
|
||||||
@@ -187,7 +186,7 @@ func (gsvd *HOGSVD) Values(s []float64, n int) []float64 {
|
|||||||
if s == nil {
|
if s == nil {
|
||||||
s = make([]float64, c)
|
s = make([]float64, c)
|
||||||
} else if len(s) != c {
|
} else if len(s) != c {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
for j := 0; j < c; j++ {
|
for j := 0; j < c; j++ {
|
||||||
s[j] = blas64.Nrm2(r, gsvd.b[n].ColView(j).mat)
|
s[j] = blas64.Nrm2(r, gsvd.b[n].ColView(j).mat)
|
@@ -2,13 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64_test
|
package mat_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleHOGSVD() {
|
func ExampleHOGSVD() {
|
||||||
@@ -17,7 +17,7 @@ func ExampleHOGSVD() {
|
|||||||
//
|
//
|
||||||
// See Ponnapalli et al. doi:10.1371/journal.pone.0028072 and
|
// See Ponnapalli et al. doi:10.1371/journal.pone.0028072 and
|
||||||
// Alter at al. doi:10.1073/pnas.0530258100 for more details.
|
// Alter at al. doi:10.1073/pnas.0530258100 for more details.
|
||||||
var gsvd mat64.HOGSVD
|
var gsvd mat.HOGSVD
|
||||||
ok := gsvd.Factorize(FAO.Africa, FAO.Asia, FAO.LatinAmericaCaribbean, FAO.Oceania)
|
ok := gsvd.Factorize(FAO.Africa, FAO.Asia, FAO.LatinAmericaCaribbean, FAO.Oceania)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("HOGSVD factorization failed: %v", gsvd.Err())
|
log.Fatal("HOGSVD factorization failed: %v", gsvd.Err())
|
||||||
@@ -27,12 +27,12 @@ func ExampleHOGSVD() {
|
|||||||
u := gsvd.UTo(nil, i)
|
u := gsvd.UTo(nil, i)
|
||||||
s := gsvd.Values(nil, i)
|
s := gsvd.Values(nil, i)
|
||||||
fmt.Printf("%s\n\ts_%d = %.4f\n\n\tU_%[2]d = %.4[4]f\n",
|
fmt.Printf("%s\n\ts_%d = %.4f\n\n\tU_%[2]d = %.4[4]f\n",
|
||||||
n, i, s, mat64.Formatted(u, mat64.Prefix("\t ")))
|
n, i, s, mat.Formatted(u, mat.Prefix("\t ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
v := gsvd.VTo(nil)
|
v := gsvd.VTo(nil)
|
||||||
fmt.Printf("\nCommon basis vectors\n\n\tV^T = %.4f",
|
fmt.Printf("\nCommon basis vectors\n\n\tV^T = %.4f",
|
||||||
mat64.Formatted(v.T(), mat64.Prefix("\t ")))
|
mat.Formatted(v.T(), mat.Prefix("\t ")))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
//
|
//
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
@@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
//+build bounds
|
//+build bounds
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import "gonum.org/v1/gonum/matrix"
|
|
||||||
|
|
||||||
// At returns the element at row i, column j.
|
// At returns the element at row i, column j.
|
||||||
func (m *Dense) At(i, j int) float64 {
|
func (m *Dense) At(i, j int) float64 {
|
||||||
@@ -17,10 +15,10 @@ func (m *Dense) At(i, j int) float64 {
|
|||||||
|
|
||||||
func (m *Dense) at(i, j int) float64 {
|
func (m *Dense) at(i, j int) float64 {
|
||||||
if uint(i) >= uint(m.mat.Rows) {
|
if uint(i) >= uint(m.mat.Rows) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(m.mat.Cols) {
|
if uint(j) >= uint(m.mat.Cols) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return m.mat.Data[i*m.mat.Stride+j]
|
return m.mat.Data[i*m.mat.Stride+j]
|
||||||
}
|
}
|
||||||
@@ -32,10 +30,10 @@ func (m *Dense) Set(i, j int, v float64) {
|
|||||||
|
|
||||||
func (m *Dense) set(i, j int, v float64) {
|
func (m *Dense) set(i, j int, v float64) {
|
||||||
if uint(i) >= uint(m.mat.Rows) {
|
if uint(i) >= uint(m.mat.Rows) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(m.mat.Cols) {
|
if uint(j) >= uint(m.mat.Cols) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
m.mat.Data[i*m.mat.Stride+j] = v
|
m.mat.Data[i*m.mat.Stride+j] = v
|
||||||
}
|
}
|
||||||
@@ -44,14 +42,14 @@ func (m *Dense) set(i, j int, v float64) {
|
|||||||
// It panics if i is out of bounds or if j is not zero.
|
// It panics if i is out of bounds or if j is not zero.
|
||||||
func (v *Vector) At(i, j int) float64 {
|
func (v *Vector) At(i, j int) float64 {
|
||||||
if j != 0 {
|
if j != 0 {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return v.at(i)
|
return v.at(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Vector) at(i int) float64 {
|
func (v *Vector) at(i int) float64 {
|
||||||
if uint(i) >= uint(v.n) {
|
if uint(i) >= uint(v.n) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
return v.mat.Data[i*v.mat.Inc]
|
return v.mat.Data[i*v.mat.Inc]
|
||||||
}
|
}
|
||||||
@@ -64,7 +62,7 @@ func (v *Vector) SetVec(i int, val float64) {
|
|||||||
|
|
||||||
func (v *Vector) setVec(i int, val float64) {
|
func (v *Vector) setVec(i int, val float64) {
|
||||||
if uint(i) >= uint(v.n) {
|
if uint(i) >= uint(v.n) {
|
||||||
panic(matrix.ErrVectorAccess)
|
panic(ErrVectorAccess)
|
||||||
}
|
}
|
||||||
v.mat.Data[i*v.mat.Inc] = val
|
v.mat.Data[i*v.mat.Inc] = val
|
||||||
}
|
}
|
||||||
@@ -76,10 +74,10 @@ func (t *SymDense) At(i, j int) float64 {
|
|||||||
|
|
||||||
func (t *SymDense) at(i, j int) float64 {
|
func (t *SymDense) at(i, j int) float64 {
|
||||||
if uint(i) >= uint(t.mat.N) {
|
if uint(i) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(t.mat.N) {
|
if uint(j) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
if i > j {
|
if i > j {
|
||||||
i, j = j, i
|
i, j = j, i
|
||||||
@@ -94,10 +92,10 @@ func (t *SymDense) SetSym(i, j int, v float64) {
|
|||||||
|
|
||||||
func (t *SymDense) set(i, j int, v float64) {
|
func (t *SymDense) set(i, j int, v float64) {
|
||||||
if uint(i) >= uint(t.mat.N) {
|
if uint(i) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(t.mat.N) {
|
if uint(j) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
if i > j {
|
if i > j {
|
||||||
i, j = j, i
|
i, j = j, i
|
||||||
@@ -112,10 +110,10 @@ func (t *TriDense) At(i, j int) float64 {
|
|||||||
|
|
||||||
func (t *TriDense) at(i, j int) float64 {
|
func (t *TriDense) at(i, j int) float64 {
|
||||||
if uint(i) >= uint(t.mat.N) {
|
if uint(i) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(t.mat.N) {
|
if uint(j) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
isUpper := t.isUpper()
|
isUpper := t.isUpper()
|
||||||
if (isUpper && i > j) || (!isUpper && i < j) {
|
if (isUpper && i > j) || (!isUpper && i < j) {
|
||||||
@@ -132,14 +130,14 @@ func (t *TriDense) SetTri(i, j int, v float64) {
|
|||||||
|
|
||||||
func (t *TriDense) set(i, j int, v float64) {
|
func (t *TriDense) set(i, j int, v float64) {
|
||||||
if uint(i) >= uint(t.mat.N) {
|
if uint(i) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(t.mat.N) {
|
if uint(j) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
isUpper := t.isUpper()
|
isUpper := t.isUpper()
|
||||||
if (isUpper && i > j) || (!isUpper && i < j) {
|
if (isUpper && i > j) || (!isUpper && i < j) {
|
||||||
panic(matrix.ErrTriangleSet)
|
panic(ErrTriangleSet)
|
||||||
}
|
}
|
||||||
t.mat.Data[i*t.mat.Stride+j] = v
|
t.mat.Data[i*t.mat.Stride+j] = v
|
||||||
}
|
}
|
@@ -6,17 +6,15 @@
|
|||||||
|
|
||||||
//+build !bounds
|
//+build !bounds
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import "gonum.org/v1/gonum/matrix"
|
|
||||||
|
|
||||||
// At returns the element at row i, column j.
|
// At returns the element at row i, column j.
|
||||||
func (m *Dense) At(i, j int) float64 {
|
func (m *Dense) At(i, j int) float64 {
|
||||||
if uint(i) >= uint(m.mat.Rows) {
|
if uint(i) >= uint(m.mat.Rows) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(m.mat.Cols) {
|
if uint(j) >= uint(m.mat.Cols) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return m.at(i, j)
|
return m.at(i, j)
|
||||||
}
|
}
|
||||||
@@ -28,10 +26,10 @@ func (m *Dense) at(i, j int) float64 {
|
|||||||
// Set sets the element at row i, column j to the value v.
|
// Set sets the element at row i, column j to the value v.
|
||||||
func (m *Dense) Set(i, j int, v float64) {
|
func (m *Dense) Set(i, j int, v float64) {
|
||||||
if uint(i) >= uint(m.mat.Rows) {
|
if uint(i) >= uint(m.mat.Rows) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(m.mat.Cols) {
|
if uint(j) >= uint(m.mat.Cols) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
m.set(i, j, v)
|
m.set(i, j, v)
|
||||||
}
|
}
|
||||||
@@ -44,10 +42,10 @@ func (m *Dense) set(i, j int, v float64) {
|
|||||||
// It panics if i is out of bounds or if j is not zero.
|
// It panics if i is out of bounds or if j is not zero.
|
||||||
func (v *Vector) At(i, j int) float64 {
|
func (v *Vector) At(i, j int) float64 {
|
||||||
if uint(i) >= uint(v.n) {
|
if uint(i) >= uint(v.n) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if j != 0 {
|
if j != 0 {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return v.at(i)
|
return v.at(i)
|
||||||
}
|
}
|
||||||
@@ -60,7 +58,7 @@ func (v *Vector) at(i int) float64 {
|
|||||||
// It panics if i is out of bounds.
|
// It panics if i is out of bounds.
|
||||||
func (v *Vector) SetVec(i int, val float64) {
|
func (v *Vector) SetVec(i int, val float64) {
|
||||||
if uint(i) >= uint(v.n) {
|
if uint(i) >= uint(v.n) {
|
||||||
panic(matrix.ErrVectorAccess)
|
panic(ErrVectorAccess)
|
||||||
}
|
}
|
||||||
v.setVec(i, val)
|
v.setVec(i, val)
|
||||||
}
|
}
|
||||||
@@ -72,10 +70,10 @@ func (v *Vector) setVec(i int, val float64) {
|
|||||||
// At returns the element at row i and column j.
|
// At returns the element at row i and column j.
|
||||||
func (s *SymDense) At(i, j int) float64 {
|
func (s *SymDense) At(i, j int) float64 {
|
||||||
if uint(i) >= uint(s.mat.N) {
|
if uint(i) >= uint(s.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(s.mat.N) {
|
if uint(j) >= uint(s.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return s.at(i, j)
|
return s.at(i, j)
|
||||||
}
|
}
|
||||||
@@ -90,10 +88,10 @@ func (s *SymDense) at(i, j int) float64 {
|
|||||||
// SetSym sets the elements at (i,j) and (j,i) to the value v.
|
// SetSym sets the elements at (i,j) and (j,i) to the value v.
|
||||||
func (s *SymDense) SetSym(i, j int, v float64) {
|
func (s *SymDense) SetSym(i, j int, v float64) {
|
||||||
if uint(i) >= uint(s.mat.N) {
|
if uint(i) >= uint(s.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(s.mat.N) {
|
if uint(j) >= uint(s.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
s.set(i, j, v)
|
s.set(i, j, v)
|
||||||
}
|
}
|
||||||
@@ -108,10 +106,10 @@ func (s *SymDense) set(i, j int, v float64) {
|
|||||||
// At returns the element at row i, column j.
|
// At returns the element at row i, column j.
|
||||||
func (t *TriDense) At(i, j int) float64 {
|
func (t *TriDense) At(i, j int) float64 {
|
||||||
if uint(i) >= uint(t.mat.N) {
|
if uint(i) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(t.mat.N) {
|
if uint(j) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
return t.at(i, j)
|
return t.at(i, j)
|
||||||
}
|
}
|
||||||
@@ -128,14 +126,14 @@ func (t *TriDense) at(i, j int) float64 {
|
|||||||
// It panics if the location is outside the appropriate half of the matrix.
|
// It panics if the location is outside the appropriate half of the matrix.
|
||||||
func (t *TriDense) SetTri(i, j int, v float64) {
|
func (t *TriDense) SetTri(i, j int, v float64) {
|
||||||
if uint(i) >= uint(t.mat.N) {
|
if uint(i) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
if uint(j) >= uint(t.mat.N) {
|
if uint(j) >= uint(t.mat.N) {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
isUpper := t.isUpper()
|
isUpper := t.isUpper()
|
||||||
if (isUpper && i > j) || (!isUpper && i < j) {
|
if (isUpper && i > j) || (!isUpper && i < j) {
|
||||||
panic(matrix.ErrTriangleSet)
|
panic(ErrTriangleSet)
|
||||||
}
|
}
|
||||||
t.set(i, j, v)
|
t.set(i, j, v)
|
||||||
}
|
}
|
@@ -2,12 +2,11 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/internal/asm/f64"
|
"gonum.org/v1/gonum/internal/asm/f64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Inner computes the generalized inner product
|
// Inner computes the generalized inner product
|
||||||
@@ -19,10 +18,10 @@ import (
|
|||||||
func Inner(x *Vector, A Matrix, y *Vector) float64 {
|
func Inner(x *Vector, A Matrix, y *Vector) float64 {
|
||||||
m, n := A.Dims()
|
m, n := A.Dims()
|
||||||
if x.Len() != m {
|
if x.Len() != m {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if y.Len() != n {
|
if y.Len() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if m == 0 || n == 0 {
|
if m == 0 || n == 0 {
|
||||||
return 0
|
return 0
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// legalSizeSameRectangular returns whether the two matrices have the same rectangular shape.
|
// legalSizeSameRectangular returns whether the two matrices have the same rectangular shape.
|
||||||
@@ -301,7 +300,7 @@ func makeRandOf(a Matrix, m, n int) Matrix {
|
|||||||
// This is necessary because we are making
|
// This is necessary because we are making
|
||||||
// a triangle from the zero value, which
|
// a triangle from the zero value, which
|
||||||
// always returns upper as true.
|
// always returns upper as true.
|
||||||
var triKind matrix.TriKind
|
var triKind TriKind
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
case *TriDense:
|
case *TriDense:
|
||||||
triKind = t.triKind()
|
triKind = t.triKind()
|
||||||
@@ -310,7 +309,7 @@ func makeRandOf(a Matrix, m, n int) Matrix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mat := NewTriDense(n, triKind, nil)
|
mat := NewTriDense(n, triKind, nil)
|
||||||
if triKind == matrix.Upper {
|
if triKind == Upper {
|
||||||
for i := 0; i < m; i++ {
|
for i := 0; i < m; i++ {
|
||||||
for j := i; j < n; j++ {
|
for j := i; j < n; j++ {
|
||||||
mat.SetTri(i, j, rand.NormFloat64())
|
mat.SetTri(i, j, rand.NormFloat64())
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LQ is a type for creating and using the LQ factorization of a matrix.
|
// LQ is a type for creating and using the LQ factorization of a matrix.
|
||||||
@@ -27,7 +26,7 @@ func (lq *LQ) updateCond() {
|
|||||||
work := getFloats(3*m, false)
|
work := getFloats(3*m, false)
|
||||||
iwork := getInts(m, false)
|
iwork := getInts(m, false)
|
||||||
l := lq.lq.asTriDense(m, blas.NonUnit, blas.Lower)
|
l := lq.lq.asTriDense(m, blas.NonUnit, blas.Lower)
|
||||||
v := lapack64.Trcon(matrix.CondNorm, l.mat, work, iwork)
|
v := lapack64.Trcon(CondNorm, l.mat, work, iwork)
|
||||||
lq.cond = 1 / v
|
lq.cond = 1 / v
|
||||||
putFloats(work)
|
putFloats(work)
|
||||||
putInts(iwork)
|
putInts(iwork)
|
||||||
@@ -42,7 +41,7 @@ func (lq *LQ) updateCond() {
|
|||||||
func (lq *LQ) Factorize(a Matrix) {
|
func (lq *LQ) Factorize(a Matrix) {
|
||||||
m, n := a.Dims()
|
m, n := a.Dims()
|
||||||
if m > n {
|
if m > n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
k := min(m, n)
|
k := min(m, n)
|
||||||
if lq.lq == nil {
|
if lq.lq == nil {
|
||||||
@@ -141,12 +140,12 @@ func (m *Dense) SolveLQ(lq *LQ, trans bool, b Matrix) error {
|
|||||||
// copy the result into m at the end.
|
// copy the result into m at the end.
|
||||||
if trans {
|
if trans {
|
||||||
if c != br {
|
if c != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
m.reuseAs(r, bc)
|
m.reuseAs(r, bc)
|
||||||
} else {
|
} else {
|
||||||
if r != br {
|
if r != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
m.reuseAs(c, bc)
|
m.reuseAs(c, bc)
|
||||||
}
|
}
|
||||||
@@ -164,12 +163,12 @@ func (m *Dense) SolveLQ(lq *LQ, trans bool, b Matrix) error {
|
|||||||
|
|
||||||
ok := lapack64.Trtrs(blas.Trans, t, x.mat)
|
ok := lapack64.Trtrs(blas.Trans, t, x.mat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ok := lapack64.Trtrs(blas.NoTrans, t, x.mat)
|
ok := lapack64.Trtrs(blas.NoTrans, t, x.mat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
for i := r; i < c; i++ {
|
for i := r; i < c; i++ {
|
||||||
zero(x.mat.Data[i*x.mat.Stride : i*x.mat.Stride+bc])
|
zero(x.mat.Data[i*x.mat.Stride : i*x.mat.Stride+bc])
|
||||||
@@ -183,8 +182,8 @@ func (m *Dense) SolveLQ(lq *LQ, trans bool, b Matrix) error {
|
|||||||
// M was set above to be the correct size for the result.
|
// M was set above to be the correct size for the result.
|
||||||
m.Copy(x)
|
m.Copy(x)
|
||||||
putWorkspace(x)
|
putWorkspace(x)
|
||||||
if lq.cond > matrix.ConditionTolerance {
|
if lq.cond > ConditionTolerance {
|
||||||
return matrix.Condition(lq.cond)
|
return Condition(lq.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const badSliceLength = "mat64: improper slice length"
|
const badSliceLength = "mat64: improper slice length"
|
||||||
@@ -39,11 +38,11 @@ func (lu *LU) updateCond(norm float64) {
|
|||||||
// update possibilities, e.g. RankOne.
|
// update possibilities, e.g. RankOne.
|
||||||
u := lu.lu.asTriDense(n, blas.NonUnit, blas.Upper)
|
u := lu.lu.asTriDense(n, blas.NonUnit, blas.Upper)
|
||||||
l := lu.lu.asTriDense(n, blas.Unit, blas.Lower)
|
l := lu.lu.asTriDense(n, blas.Unit, blas.Lower)
|
||||||
unorm := lapack64.Lantr(matrix.CondNorm, u.mat, work)
|
unorm := lapack64.Lantr(CondNorm, u.mat, work)
|
||||||
lnorm := lapack64.Lantr(matrix.CondNorm, l.mat, work)
|
lnorm := lapack64.Lantr(CondNorm, l.mat, work)
|
||||||
norm = unorm * lnorm
|
norm = unorm * lnorm
|
||||||
}
|
}
|
||||||
v := lapack64.Gecon(matrix.CondNorm, lu.lu.mat, norm, work, iwork)
|
v := lapack64.Gecon(CondNorm, lu.lu.mat, norm, work, iwork)
|
||||||
lu.cond = 1 / v
|
lu.cond = 1 / v
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ func (lu *LU) updateCond(norm float64) {
|
|||||||
func (lu *LU) Factorize(a Matrix) {
|
func (lu *LU) Factorize(a Matrix) {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrSquare)
|
panic(ErrSquare)
|
||||||
}
|
}
|
||||||
if lu.lu == nil {
|
if lu.lu == nil {
|
||||||
lu.lu = NewDense(r, r, nil)
|
lu.lu = NewDense(r, r, nil)
|
||||||
@@ -71,7 +70,7 @@ func (lu *LU) Factorize(a Matrix) {
|
|||||||
}
|
}
|
||||||
lu.pivot = lu.pivot[:r]
|
lu.pivot = lu.pivot[:r]
|
||||||
work := getFloats(r, false)
|
work := getFloats(r, false)
|
||||||
anorm := lapack64.Lange(matrix.CondNorm, lu.lu.mat, work)
|
anorm := lapack64.Lange(CondNorm, lu.lu.mat, work)
|
||||||
putFloats(work)
|
putFloats(work)
|
||||||
lapack64.Getrf(lu.lu.mat, lu.pivot)
|
lapack64.Getrf(lu.lu.mat, lu.pivot)
|
||||||
lu.updateCond(anorm)
|
lu.updateCond(anorm)
|
||||||
@@ -152,10 +151,10 @@ func (lu *LU) RankOne(orig *LU, alpha float64, x, y *Vector) {
|
|||||||
// http://web.stanford.edu/group/SOL/dissertations/Linzhong-Deng-thesis.pdf
|
// http://web.stanford.edu/group/SOL/dissertations/Linzhong-Deng-thesis.pdf
|
||||||
_, n := orig.lu.Dims()
|
_, n := orig.lu.Dims()
|
||||||
if x.Len() != n {
|
if x.Len() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if y.Len() != n {
|
if y.Len() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if orig != lu {
|
if orig != lu {
|
||||||
if lu.isZero() {
|
if lu.isZero() {
|
||||||
@@ -169,7 +168,7 @@ func (lu *LU) RankOne(orig *LU, alpha float64, x, y *Vector) {
|
|||||||
lu.lu.reuseAs(n, n)
|
lu.lu.reuseAs(n, n)
|
||||||
}
|
}
|
||||||
} else if len(lu.pivot) != n {
|
} else if len(lu.pivot) != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
copy(lu.pivot, orig.pivot)
|
copy(lu.pivot, orig.pivot)
|
||||||
lu.lu.Copy(orig.lu)
|
lu.lu.Copy(orig.lu)
|
||||||
@@ -215,9 +214,9 @@ func (lu *LU) RankOne(orig *LU, alpha float64, x, y *Vector) {
|
|||||||
func (lu *LU) LTo(dst *TriDense) *TriDense {
|
func (lu *LU) LTo(dst *TriDense) *TriDense {
|
||||||
_, n := lu.lu.Dims()
|
_, n := lu.lu.Dims()
|
||||||
if dst == nil {
|
if dst == nil {
|
||||||
dst = NewTriDense(n, matrix.Lower, nil)
|
dst = NewTriDense(n, Lower, nil)
|
||||||
} else {
|
} else {
|
||||||
dst.reuseAs(n, matrix.Lower)
|
dst.reuseAs(n, Lower)
|
||||||
}
|
}
|
||||||
// Extract the lower triangular elements.
|
// Extract the lower triangular elements.
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
@@ -237,9 +236,9 @@ func (lu *LU) LTo(dst *TriDense) *TriDense {
|
|||||||
func (lu *LU) UTo(dst *TriDense) *TriDense {
|
func (lu *LU) UTo(dst *TriDense) *TriDense {
|
||||||
_, n := lu.lu.Dims()
|
_, n := lu.lu.Dims()
|
||||||
if dst == nil {
|
if dst == nil {
|
||||||
dst = NewTriDense(n, matrix.Upper, nil)
|
dst = NewTriDense(n, Upper, nil)
|
||||||
} else {
|
} else {
|
||||||
dst.reuseAs(n, matrix.Upper)
|
dst.reuseAs(n, Upper)
|
||||||
}
|
}
|
||||||
// Extract the upper triangular elements.
|
// Extract the upper triangular elements.
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
@@ -260,7 +259,7 @@ func (m *Dense) Permutation(r int, swaps []int) {
|
|||||||
zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+r])
|
zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+r])
|
||||||
v := swaps[i]
|
v := swaps[i]
|
||||||
if v < 0 || v >= r {
|
if v < 0 || v >= r {
|
||||||
panic(matrix.ErrRowAccess)
|
panic(ErrRowAccess)
|
||||||
}
|
}
|
||||||
m.mat.Data[i*m.mat.Stride+v] = 1
|
m.mat.Data[i*m.mat.Stride+v] = 1
|
||||||
}
|
}
|
||||||
@@ -279,12 +278,12 @@ func (m *Dense) SolveLU(lu *LU, trans bool, b Matrix) error {
|
|||||||
_, n := lu.lu.Dims()
|
_, n := lu.lu.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if br != n {
|
if br != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
// TODO(btracey): Should test the condition number instead of testing that
|
// TODO(btracey): Should test the condition number instead of testing that
|
||||||
// the determinant is exactly zero.
|
// the determinant is exactly zero.
|
||||||
if lu.Det() == 0 {
|
if lu.Det() == 0 {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
m.reuseAs(n, bc)
|
m.reuseAs(n, bc)
|
||||||
@@ -303,8 +302,8 @@ func (m *Dense) SolveLU(lu *LU, trans bool, b Matrix) error {
|
|||||||
t = blas.Trans
|
t = blas.Trans
|
||||||
}
|
}
|
||||||
lapack64.Getrs(t, lu.lu.mat, m.mat, lu.pivot)
|
lapack64.Getrs(t, lu.lu.mat, m.mat, lu.pivot)
|
||||||
if lu.cond > matrix.ConditionTolerance {
|
if lu.cond > ConditionTolerance {
|
||||||
return matrix.Condition(lu.cond)
|
return Condition(lu.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -322,7 +321,7 @@ func (v *Vector) SolveLUVec(lu *LU, trans bool, b *Vector) error {
|
|||||||
_, n := lu.lu.Dims()
|
_, n := lu.lu.Dims()
|
||||||
bn := b.Len()
|
bn := b.Len()
|
||||||
if bn != n {
|
if bn != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if v != b {
|
if v != b {
|
||||||
v.checkOverlap(b.mat)
|
v.checkOverlap(b.mat)
|
||||||
@@ -330,7 +329,7 @@ func (v *Vector) SolveLUVec(lu *LU, trans bool, b *Vector) error {
|
|||||||
// TODO(btracey): Should test the condition number instead of testing that
|
// TODO(btracey): Should test the condition number instead of testing that
|
||||||
// the determinant is exactly zero.
|
// the determinant is exactly zero.
|
||||||
if lu.Det() == 0 {
|
if lu.Det() == 0 {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
v.reuseAs(n)
|
v.reuseAs(n)
|
||||||
@@ -351,8 +350,8 @@ func (v *Vector) SolveLUVec(lu *LU, trans bool, b *Vector) error {
|
|||||||
t = blas.Trans
|
t = blas.Trans
|
||||||
}
|
}
|
||||||
lapack64.Getrs(t, lu.lu.mat, vMat, lu.pivot)
|
lapack64.Getrs(t, lu.lu.mat, vMat, lu.pivot)
|
||||||
if lu.cond > matrix.ConditionTolerance {
|
if lu.cond > ConditionTolerance {
|
||||||
return matrix.Condition(lu.cond)
|
return Condition(lu.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/lapack"
|
"gonum.org/v1/gonum/lapack"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Matrix is the basic matrix interface type.
|
// Matrix is the basic matrix interface type.
|
||||||
@@ -196,13 +195,13 @@ type RawVectorer interface {
|
|||||||
func Col(dst []float64, j int, a Matrix) []float64 {
|
func Col(dst []float64, j int, a Matrix) []float64 {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if j < 0 || j >= c {
|
if j < 0 || j >= c {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
if dst == nil {
|
if dst == nil {
|
||||||
dst = make([]float64, r)
|
dst = make([]float64, r)
|
||||||
} else {
|
} else {
|
||||||
if len(dst) != r {
|
if len(dst) != r {
|
||||||
panic(matrix.ErrColLength)
|
panic(ErrColLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aU, aTrans := untranspose(a)
|
aU, aTrans := untranspose(a)
|
||||||
@@ -230,13 +229,13 @@ func Col(dst []float64, j int, a Matrix) []float64 {
|
|||||||
func Row(dst []float64, i int, a Matrix) []float64 {
|
func Row(dst []float64, i int, a Matrix) []float64 {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if i < 0 || i >= r {
|
if i < 0 || i >= r {
|
||||||
panic(matrix.ErrColAccess)
|
panic(ErrColAccess)
|
||||||
}
|
}
|
||||||
if dst == nil {
|
if dst == nil {
|
||||||
dst = make([]float64, c)
|
dst = make([]float64, c)
|
||||||
} else {
|
} else {
|
||||||
if len(dst) != c {
|
if len(dst) != c {
|
||||||
panic(matrix.ErrRowLength)
|
panic(ErrRowLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aU, aTrans := untranspose(a)
|
aU, aTrans := untranspose(a)
|
||||||
@@ -270,7 +269,7 @@ func Row(dst []float64, i int, a Matrix) []float64 {
|
|||||||
func Cond(a Matrix, norm float64) float64 {
|
func Cond(a Matrix, norm float64) float64 {
|
||||||
m, n := a.Dims()
|
m, n := a.Dims()
|
||||||
if m == 0 || n == 0 {
|
if m == 0 || n == 0 {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var lnorm lapack.MatrixNorm
|
var lnorm lapack.MatrixNorm
|
||||||
switch norm {
|
switch norm {
|
||||||
@@ -280,7 +279,7 @@ func Cond(a Matrix, norm float64) float64 {
|
|||||||
lnorm = lapack.MaxColumnSum
|
lnorm = lapack.MaxColumnSum
|
||||||
case 2:
|
case 2:
|
||||||
var svd SVD
|
var svd SVD
|
||||||
ok := svd.Factorize(a, matrix.SVDNone)
|
ok := svd.Factorize(a, SVDNone)
|
||||||
if !ok {
|
if !ok {
|
||||||
return math.Inf(1)
|
return math.Inf(1)
|
||||||
}
|
}
|
||||||
@@ -360,7 +359,7 @@ func Dot(a, b *Vector) float64 {
|
|||||||
la := a.Len()
|
la := a.Len()
|
||||||
lb := b.Len()
|
lb := b.Len()
|
||||||
if la != lb {
|
if la != lb {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
return blas64.Dot(la, a.mat, b.mat)
|
return blas64.Dot(la, a.mat, b.mat)
|
||||||
}
|
}
|
||||||
@@ -523,7 +522,7 @@ func LogDet(a Matrix) (det float64, sign float64) {
|
|||||||
func Max(a Matrix) float64 {
|
func Max(a Matrix) float64 {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r == 0 || c == 0 {
|
if r == 0 || c == 0 {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
// Max(A) = Max(A^T)
|
// Max(A) = Max(A^T)
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
||||||
@@ -598,7 +597,7 @@ func Max(a Matrix) float64 {
|
|||||||
func Min(a Matrix) float64 {
|
func Min(a Matrix) float64 {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r == 0 || c == 0 {
|
if r == 0 || c == 0 {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
// Min(A) = Min(A^T)
|
// Min(A) = Min(A^T)
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
||||||
@@ -680,7 +679,7 @@ func Min(a Matrix) float64 {
|
|||||||
func Norm(a Matrix, norm float64) float64 {
|
func Norm(a Matrix, norm float64) float64 {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r == 0 || c == 0 {
|
if r == 0 || c == 0 {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
aU, aTrans := untranspose(a)
|
aU, aTrans := untranspose(a)
|
||||||
var work []float64
|
var work []float64
|
||||||
@@ -787,7 +786,7 @@ func normLapack(norm float64, aTrans bool) lapack.MatrixNorm {
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
default:
|
default:
|
||||||
panic(matrix.ErrNormOrder)
|
panic(ErrNormOrder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,7 +819,7 @@ func Sum(a Matrix) float64 {
|
|||||||
func Trace(a Matrix) float64 {
|
func Trace(a Matrix) float64 {
|
||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrSquare)
|
panic(ErrSquare)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, _ := untranspose(a)
|
aU, _ := untranspose(a)
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func panics(fn func()) (panicked bool, message string) {
|
func panics(fn func()) (panicked bool, message string) {
|
||||||
@@ -335,7 +334,7 @@ func TestDet(t *testing.T) {
|
|||||||
f = func(a Matrix) interface{} {
|
f = func(a Matrix) interface{} {
|
||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
if !isWide(ar, ac) {
|
if !isWide(ar, ac) {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var tmp Dense
|
var tmp Dense
|
||||||
tmp.Mul(a, a.T())
|
tmp.Mul(a, a.T())
|
||||||
@@ -344,7 +343,7 @@ func TestDet(t *testing.T) {
|
|||||||
denseComparison = func(a *Dense) interface{} {
|
denseComparison = func(a *Dense) interface{} {
|
||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
if !isWide(ar, ac) {
|
if !isWide(ar, ac) {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var tmp SymDense
|
var tmp SymDense
|
||||||
tmp.SymOuterK(1, a)
|
tmp.SymOuterK(1, a)
|
||||||
@@ -366,7 +365,7 @@ func TestDot(t *testing.T) {
|
|||||||
ra, ca := a.Dims()
|
ra, ca := a.Dims()
|
||||||
rb, cb := b.Dims()
|
rb, cb := b.Dims()
|
||||||
if ra != rb || ca != cb {
|
if ra != rb || ca != cb {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var sum float64
|
var sum float64
|
||||||
for i := 0; i < ra; i++ {
|
for i := 0; i < ra; i++ {
|
||||||
@@ -481,9 +480,9 @@ func TestNormZero(t *testing.T) {
|
|||||||
if !panicked {
|
if !panicked {
|
||||||
t.Errorf("expected panic for Norm(&%T{}, %v)", a, norm)
|
t.Errorf("expected panic for Norm(&%T{}, %v)", a, norm)
|
||||||
}
|
}
|
||||||
if message != matrix.ErrShape.Error() {
|
if message != ErrShape.Error() {
|
||||||
t.Errorf("unexpected panic string for Norm(&%T{}, %v): got:%s want:%s",
|
t.Errorf("unexpected panic string for Norm(&%T{}, %v): got:%s want:%s",
|
||||||
a, norm, message, matrix.ErrShape.Error())
|
a, norm, message, ErrShape.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Need to add tests where one is overwritten.
|
// TODO: Need to add tests where one is overwritten.
|
||||||
@@ -247,7 +246,7 @@ func (m *basicTriangular) T() Matrix {
|
|||||||
return Transpose{m}
|
return Transpose{m}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *basicTriangular) Triangle() (int, matrix.TriKind) {
|
func (m *basicTriangular) Triangle() (int, TriKind) {
|
||||||
return (*TriDense)(m).Triangle()
|
return (*TriDense)(m).Triangle()
|
||||||
}
|
}
|
||||||
|
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
//+build !appengine
|
//+build !appengine
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
//+build appengine
|
//+build appengine
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import "reflect"
|
import "reflect"
|
||||||
|
|
@@ -2,14 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var tab64 = [64]byte{
|
var tab64 = [64]byte{
|
||||||
@@ -148,7 +147,7 @@ func putWorkspaceSym(s *SymDense) {
|
|||||||
// getWorkspaceTri returns a *TriDense of size n and a cap that
|
// getWorkspaceTri returns a *TriDense of size n and a cap that
|
||||||
// is less than 2*n. If clear is true, the data slice visible
|
// is less than 2*n. If clear is true, the data slice visible
|
||||||
// through the Matrix interface is zeroed.
|
// through the Matrix interface is zeroed.
|
||||||
func getWorkspaceTri(n int, kind matrix.TriKind, clear bool) *TriDense {
|
func getWorkspaceTri(n int, kind TriKind, clear bool) *TriDense {
|
||||||
l := uint64(n)
|
l := uint64(n)
|
||||||
l *= l
|
l *= l
|
||||||
t := poolTri[bits(l)].Get().(*TriDense)
|
t := poolTri[bits(l)].Get().(*TriDense)
|
||||||
@@ -158,12 +157,12 @@ func getWorkspaceTri(n int, kind matrix.TriKind, clear bool) *TriDense {
|
|||||||
}
|
}
|
||||||
t.mat.N = n
|
t.mat.N = n
|
||||||
t.mat.Stride = n
|
t.mat.Stride = n
|
||||||
if kind == matrix.Upper {
|
if kind == Upper {
|
||||||
t.mat.Uplo = blas.Upper
|
t.mat.Uplo = blas.Upper
|
||||||
} else if kind == matrix.Lower {
|
} else if kind == Lower {
|
||||||
t.mat.Uplo = blas.Lower
|
t.mat.Uplo = blas.Lower
|
||||||
} else {
|
} else {
|
||||||
panic(matrix.ErrTriangle)
|
panic(ErrTriangle)
|
||||||
}
|
}
|
||||||
t.mat.Diag = blas.NonUnit
|
t.mat.Diag = blas.NonUnit
|
||||||
t.cap = n
|
t.cap = n
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
@@ -2,13 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Product calculates the product of the given factors and places the result in
|
// Product calculates the product of the given factors and places the result in
|
||||||
// the receiver. The order of multiplication operations is optimized to minimize
|
// the receiver. The order of multiplication operations is optimized to minimize
|
||||||
@@ -31,7 +27,7 @@ func (m *Dense) Product(factors ...Matrix) {
|
|||||||
switch len(factors) {
|
switch len(factors) {
|
||||||
case 0:
|
case 0:
|
||||||
if r != 0 || c != 0 {
|
if r != 0 || c != 0 {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case 1:
|
case 1:
|
||||||
@@ -77,10 +73,10 @@ func newMultiplier(m *Dense, factors []Matrix) *multiplier {
|
|||||||
fr, fc := factors[0].Dims() // newMultiplier is only called with len(factors) > 2.
|
fr, fc := factors[0].Dims() // newMultiplier is only called with len(factors) > 2.
|
||||||
if !m.isZero() {
|
if !m.isZero() {
|
||||||
if fr != r {
|
if fr != r {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if _, lc := factors[len(factors)-1].Dims(); lc != c {
|
if _, lc := factors[len(factors)-1].Dims(); lc != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +88,7 @@ func newMultiplier(m *Dense, factors []Matrix) *multiplier {
|
|||||||
cr, cc := f.Dims()
|
cr, cc := f.Dims()
|
||||||
dims[i+1] = cr
|
dims[i+1] = cr
|
||||||
if pc != cr {
|
if pc != cr {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
pc = cc
|
pc = cc
|
||||||
}
|
}
|
||||||
@@ -150,7 +146,7 @@ func (p *multiplier) multiplySubchain(i, j int) (m Matrix, intermediate bool) {
|
|||||||
if ac != br {
|
if ac != br {
|
||||||
// Panic with a string since this
|
// Panic with a string since this
|
||||||
// is not a user-facing panic.
|
// is not a user-facing panic.
|
||||||
panic(matrix.ErrShape.Error())
|
panic(ErrShape.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if debugProductWalk {
|
if debugProductWalk {
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@@ -3,7 +3,7 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Based on the QRDecomposition class from Jama 1.0.3.
|
// Based on the QRDecomposition class from Jama 1.0.3.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// QR is a type for creating and using the QR factorization of a matrix.
|
// QR is a type for creating and using the QR factorization of a matrix.
|
||||||
@@ -28,7 +27,7 @@ func (qr *QR) updateCond() {
|
|||||||
work := getFloats(3*n, false)
|
work := getFloats(3*n, false)
|
||||||
iwork := getInts(n, false)
|
iwork := getInts(n, false)
|
||||||
r := qr.qr.asTriDense(n, blas.NonUnit, blas.Upper)
|
r := qr.qr.asTriDense(n, blas.NonUnit, blas.Upper)
|
||||||
v := lapack64.Trcon(matrix.CondNorm, r.mat, work, iwork)
|
v := lapack64.Trcon(CondNorm, r.mat, work, iwork)
|
||||||
putFloats(work)
|
putFloats(work)
|
||||||
putInts(iwork)
|
putInts(iwork)
|
||||||
qr.cond = 1 / v
|
qr.cond = 1 / v
|
||||||
@@ -43,7 +42,7 @@ func (qr *QR) updateCond() {
|
|||||||
func (qr *QR) Factorize(a Matrix) {
|
func (qr *QR) Factorize(a Matrix) {
|
||||||
m, n := a.Dims()
|
m, n := a.Dims()
|
||||||
if m < n {
|
if m < n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
k := min(m, n)
|
k := min(m, n)
|
||||||
if qr.qr == nil {
|
if qr.qr == nil {
|
||||||
@@ -138,12 +137,12 @@ func (m *Dense) SolveQR(qr *QR, trans bool, b Matrix) error {
|
|||||||
// copy the result into m at the end.
|
// copy the result into m at the end.
|
||||||
if trans {
|
if trans {
|
||||||
if c != br {
|
if c != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
m.reuseAs(r, bc)
|
m.reuseAs(r, bc)
|
||||||
} else {
|
} else {
|
||||||
if r != br {
|
if r != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
m.reuseAs(c, bc)
|
m.reuseAs(c, bc)
|
||||||
}
|
}
|
||||||
@@ -155,7 +154,7 @@ func (m *Dense) SolveQR(qr *QR, trans bool, b Matrix) error {
|
|||||||
if trans {
|
if trans {
|
||||||
ok := lapack64.Trtrs(blas.Trans, t, x.mat)
|
ok := lapack64.Trtrs(blas.Trans, t, x.mat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
for i := c; i < r; i++ {
|
for i := c; i < r; i++ {
|
||||||
zero(x.mat.Data[i*x.mat.Stride : i*x.mat.Stride+bc])
|
zero(x.mat.Data[i*x.mat.Stride : i*x.mat.Stride+bc])
|
||||||
@@ -174,14 +173,14 @@ func (m *Dense) SolveQR(qr *QR, trans bool, b Matrix) error {
|
|||||||
|
|
||||||
ok := lapack64.Trtrs(blas.NoTrans, t, x.mat)
|
ok := lapack64.Trtrs(blas.NoTrans, t, x.mat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// M was set above to be the correct size for the result.
|
// M was set above to be the correct size for the result.
|
||||||
m.Copy(x)
|
m.Copy(x)
|
||||||
putWorkspace(x)
|
putWorkspace(x)
|
||||||
if qr.cond > matrix.ConditionTolerance {
|
if qr.cond > ConditionTolerance {
|
||||||
return matrix.Condition(qr.cond)
|
return Condition(qr.cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDenseOverlaps(t *testing.T) {
|
func TestDenseOverlaps(t *testing.T) {
|
||||||
@@ -94,7 +93,7 @@ func TestTriDenseOverlaps(t *testing.T) {
|
|||||||
|
|
||||||
rnd := rand.New(rand.NewSource(1))
|
rnd := rand.New(rand.NewSource(1))
|
||||||
|
|
||||||
for _, parentKind := range []matrix.TriKind{matrix.Upper, matrix.Lower} {
|
for _, parentKind := range []TriKind{Upper, Lower} {
|
||||||
for n := 1; n < 20; n++ {
|
for n := 1; n < 20; n++ {
|
||||||
data := make([]float64, n*n)
|
data := make([]float64, n*n)
|
||||||
for i := range data {
|
for i := range data {
|
||||||
@@ -120,7 +119,7 @@ func TestTriDenseOverlaps(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
views[k].n = 1
|
views[k].n = 1
|
||||||
}
|
}
|
||||||
viewKind := []matrix.TriKind{matrix.Upper, matrix.Lower}[rnd.Intn(2)]
|
viewKind := []TriKind{Upper, Lower}[rnd.Intn(2)]
|
||||||
views[k].TriDense = denseAsTriDense(
|
views[k].TriDense = denseAsTriDense(
|
||||||
m.Slice(views[k].i, views[k].i+views[k].n, views[k].j, views[k].j+views[k].n).(*Dense),
|
m.Slice(views[k].i, views[k].i+views[k].n, views[k].j, views[k].j+views[k].n).(*Dense),
|
||||||
viewKind)
|
viewKind)
|
||||||
@@ -172,21 +171,21 @@ func intervalsOverlap(a, b interval) bool {
|
|||||||
return a.to > b.from && b.to > a.from
|
return a.to > b.from && b.to > a.from
|
||||||
}
|
}
|
||||||
|
|
||||||
func overlapsParentTriangle(i, j, n int, parent, view matrix.TriKind) bool {
|
func overlapsParentTriangle(i, j, n int, parent, view TriKind) bool {
|
||||||
switch parent {
|
switch parent {
|
||||||
case matrix.Upper:
|
case Upper:
|
||||||
if i <= j {
|
if i <= j {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if view == matrix.Upper {
|
if view == Upper {
|
||||||
return i < j+n
|
return i < j+n
|
||||||
}
|
}
|
||||||
|
|
||||||
case matrix.Lower:
|
case Lower:
|
||||||
if i >= j {
|
if i >= j {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if view == matrix.Lower {
|
if view == Lower {
|
||||||
return i+n > j
|
return i+n > j
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,17 +193,17 @@ func overlapsParentTriangle(i, j, n int, parent, view matrix.TriKind) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func overlapSiblingTriangles(ai, aj, an int, aKind matrix.TriKind, bi, bj, bn int, bKind matrix.TriKind) bool {
|
func overlapSiblingTriangles(ai, aj, an int, aKind TriKind, bi, bj, bn int, bKind TriKind) bool {
|
||||||
for i := max(ai, bi); i < min(ai+an, bi+bn); i++ {
|
for i := max(ai, bi); i < min(ai+an, bi+bn); i++ {
|
||||||
var a, b interval
|
var a, b interval
|
||||||
|
|
||||||
if aKind == matrix.Upper {
|
if aKind == Upper {
|
||||||
a = interval{from: aj - ai + i, to: aj + an}
|
a = interval{from: aj - ai + i, to: aj + an}
|
||||||
} else {
|
} else {
|
||||||
a = interval{from: aj, to: aj - ai + i + 1}
|
a = interval{from: aj, to: aj - ai + i + 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bKind == matrix.Upper {
|
if bKind == Upper {
|
||||||
b = interval{from: bj - bi + i, to: bj + bn}
|
b = interval{from: bj - bi + i, to: bj + bn}
|
||||||
} else {
|
} else {
|
||||||
b = interval{from: bj, to: bj - bi + i + 1}
|
b = interval{from: bj, to: bj - bi + i + 1}
|
||||||
@@ -217,8 +216,8 @@ func overlapSiblingTriangles(ai, aj, an int, aKind matrix.TriKind, bi, bj, bn in
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func kindString(k matrix.TriKind) string {
|
func kindString(k TriKind) string {
|
||||||
if k == matrix.Upper {
|
if k == Upper {
|
||||||
return "U"
|
return "U"
|
||||||
}
|
}
|
||||||
return "L"
|
return "L"
|
||||||
@@ -252,14 +251,14 @@ func TestIssue359(t *testing.T) {
|
|||||||
|
|
||||||
// denseAsTriDense returns a triangular matrix derived from the
|
// denseAsTriDense returns a triangular matrix derived from the
|
||||||
// square matrix m, with the orientation specified by kind.
|
// square matrix m, with the orientation specified by kind.
|
||||||
func denseAsTriDense(m *Dense, kind matrix.TriKind) *TriDense {
|
func denseAsTriDense(m *Dense, kind TriKind) *TriDense {
|
||||||
r, c := m.Dims()
|
r, c := m.Dims()
|
||||||
if r != c {
|
if r != c {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
n := r
|
n := r
|
||||||
uplo := blas.Lower
|
uplo := blas.Lower
|
||||||
if kind == matrix.Upper {
|
if kind == Upper {
|
||||||
uplo = blas.Upper
|
uplo = blas.Upper
|
||||||
}
|
}
|
||||||
return &TriDense{
|
return &TriDense{
|
@@ -2,13 +2,12 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Solve finds a minimum-norm solution to a system of linear equations defined
|
// Solve finds a minimum-norm solution to a system of linear equations defined
|
||||||
@@ -23,7 +22,7 @@ func (m *Dense) Solve(a, b Matrix) error {
|
|||||||
ar, ac := a.Dims()
|
ar, ac := a.Dims()
|
||||||
br, bc := b.Dims()
|
br, bc := b.Dims()
|
||||||
if ar != br {
|
if ar != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
m.reuseAs(ac, bc)
|
m.reuseAs(ac, bc)
|
||||||
|
|
||||||
@@ -66,11 +65,11 @@ func (m *Dense) Solve(a, b Matrix) error {
|
|||||||
blas64.Trsm(side, tA, 1, rm, m.mat)
|
blas64.Trsm(side, tA, 1, rm, m.mat)
|
||||||
work := getFloats(3*rm.N, false)
|
work := getFloats(3*rm.N, false)
|
||||||
iwork := getInts(rm.N, false)
|
iwork := getInts(rm.N, false)
|
||||||
cond := lapack64.Trcon(matrix.CondNorm, rm, work, iwork)
|
cond := lapack64.Trcon(CondNorm, rm, work, iwork)
|
||||||
putFloats(work)
|
putFloats(work)
|
||||||
putInts(iwork)
|
putInts(iwork)
|
||||||
if cond > matrix.ConditionTolerance {
|
if cond > ConditionTolerance {
|
||||||
return matrix.Condition(cond)
|
return Condition(cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
@@ -3,19 +3,18 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Based on the SingularValueDecomposition class from Jama 1.0.3.
|
// Based on the SingularValueDecomposition class from Jama 1.0.3.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack"
|
"gonum.org/v1/gonum/lapack"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SVD is a type for creating and using the Singular Value Decomposition (SVD)
|
// SVD is a type for creating and using the Singular Value Decomposition (SVD)
|
||||||
// of a matrix.
|
// of a matrix.
|
||||||
type SVD struct {
|
type SVD struct {
|
||||||
kind matrix.SVDKind
|
kind SVDKind
|
||||||
|
|
||||||
s []float64
|
s []float64
|
||||||
u blas64.General
|
u blas64.General
|
||||||
@@ -40,16 +39,16 @@ type SVD struct {
|
|||||||
//
|
//
|
||||||
// Factorize returns whether the decomposition succeeded. If the decomposition
|
// Factorize returns whether the decomposition succeeded. If the decomposition
|
||||||
// failed, routines that require a successful factorization will panic.
|
// failed, routines that require a successful factorization will panic.
|
||||||
func (svd *SVD) Factorize(a Matrix, kind matrix.SVDKind) (ok bool) {
|
func (svd *SVD) Factorize(a Matrix, kind SVDKind) (ok bool) {
|
||||||
m, n := a.Dims()
|
m, n := a.Dims()
|
||||||
var jobU, jobVT lapack.SVDJob
|
var jobU, jobVT lapack.SVDJob
|
||||||
switch kind {
|
switch kind {
|
||||||
default:
|
default:
|
||||||
panic("svd: bad input kind")
|
panic("svd: bad input kind")
|
||||||
case matrix.SVDNone:
|
case SVDNone:
|
||||||
jobU = lapack.SVDNone
|
jobU = lapack.SVDNone
|
||||||
jobVT = lapack.SVDNone
|
jobVT = lapack.SVDNone
|
||||||
case matrix.SVDFull:
|
case SVDFull:
|
||||||
// TODO(btracey): This code should be modified to have the smaller
|
// TODO(btracey): This code should be modified to have the smaller
|
||||||
// matrix written in-place into aCopy when the lapack/native/dgesvd
|
// matrix written in-place into aCopy when the lapack/native/dgesvd
|
||||||
// implementation is complete.
|
// implementation is complete.
|
||||||
@@ -67,7 +66,7 @@ func (svd *SVD) Factorize(a Matrix, kind matrix.SVDKind) (ok bool) {
|
|||||||
}
|
}
|
||||||
jobU = lapack.SVDAll
|
jobU = lapack.SVDAll
|
||||||
jobVT = lapack.SVDAll
|
jobVT = lapack.SVDAll
|
||||||
case matrix.SVDThin:
|
case SVDThin:
|
||||||
// TODO(btracey): This code should be modified to have the larger
|
// TODO(btracey): This code should be modified to have the larger
|
||||||
// matrix written in-place into aCopy when the lapack/native/dgesvd
|
// matrix written in-place into aCopy when the lapack/native/dgesvd
|
||||||
// implementation is complete.
|
// implementation is complete.
|
||||||
@@ -105,7 +104,7 @@ func (svd *SVD) Factorize(a Matrix, kind matrix.SVDKind) (ok bool) {
|
|||||||
|
|
||||||
// Kind returns the matrix.SVDKind of the decomposition. If no decomposition has been
|
// Kind returns the matrix.SVDKind of the decomposition. If no decomposition has been
|
||||||
// computed, Kind returns 0.
|
// computed, Kind returns 0.
|
||||||
func (svd *SVD) Kind() matrix.SVDKind {
|
func (svd *SVD) Kind() SVDKind {
|
||||||
return svd.kind
|
return svd.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +132,7 @@ func (svd *SVD) Values(s []float64) []float64 {
|
|||||||
s = make([]float64, len(svd.s))
|
s = make([]float64, len(svd.s))
|
||||||
}
|
}
|
||||||
if len(s) != len(svd.s) {
|
if len(s) != len(svd.s) {
|
||||||
panic(matrix.ErrSliceLengthMismatch)
|
panic(ErrSliceLengthMismatch)
|
||||||
}
|
}
|
||||||
copy(s, svd.s)
|
copy(s, svd.s)
|
||||||
return s
|
return s
|
||||||
@@ -144,7 +143,7 @@ func (svd *SVD) Values(s []float64) []float64 {
|
|||||||
// of size m×min(m,n) if svd.Kind() == SVDThin, and UTo panics otherwise.
|
// of size m×min(m,n) if svd.Kind() == SVDThin, and UTo panics otherwise.
|
||||||
func (svd *SVD) UTo(dst *Dense) *Dense {
|
func (svd *SVD) UTo(dst *Dense) *Dense {
|
||||||
kind := svd.kind
|
kind := svd.kind
|
||||||
if kind != matrix.SVDFull && kind != matrix.SVDThin {
|
if kind != SVDFull && kind != SVDThin {
|
||||||
panic("mat64: improper SVD kind")
|
panic("mat64: improper SVD kind")
|
||||||
}
|
}
|
||||||
r := svd.u.Rows
|
r := svd.u.Rows
|
||||||
@@ -170,7 +169,7 @@ func (svd *SVD) UTo(dst *Dense) *Dense {
|
|||||||
// of size n×min(m,n) if svd.Kind() == SVDThin, and VTo panics otherwise.
|
// of size n×min(m,n) if svd.Kind() == SVDThin, and VTo panics otherwise.
|
||||||
func (svd *SVD) VTo(dst *Dense) *Dense {
|
func (svd *SVD) VTo(dst *Dense) *Dense {
|
||||||
kind := svd.kind
|
kind := svd.kind
|
||||||
if kind != matrix.SVDFull && kind != matrix.SVDThin {
|
if kind != SVDFull && kind != SVDThin {
|
||||||
panic("mat64: improper SVD kind")
|
panic("mat64: improper SVD kind")
|
||||||
}
|
}
|
||||||
r := svd.vt.Rows
|
r := svd.vt.Rows
|
@@ -2,14 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSVD(t *testing.T) {
|
func TestSVD(t *testing.T) {
|
||||||
@@ -63,7 +62,7 @@ func TestSVD(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
var svd SVD
|
var svd SVD
|
||||||
ok := svd.Factorize(test.a, matrix.SVDThin)
|
ok := svd.Factorize(test.a, SVDThin)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("SVD failed")
|
t.Errorf("SVD failed")
|
||||||
}
|
}
|
||||||
@@ -111,7 +110,7 @@ func TestSVD(t *testing.T) {
|
|||||||
|
|
||||||
// Test Full decomposition.
|
// Test Full decomposition.
|
||||||
var svd SVD
|
var svd SVD
|
||||||
ok := svd.Factorize(a, matrix.SVDFull)
|
ok := svd.Factorize(a, SVDFull)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("SVD factorization failed")
|
t.Errorf("SVD factorization failed")
|
||||||
}
|
}
|
||||||
@@ -130,7 +129,7 @@ func TestSVD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test Thin decomposition.
|
// Test Thin decomposition.
|
||||||
ok = svd.Factorize(a, matrix.SVDThin)
|
ok = svd.Factorize(a, SVDThin)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("SVD factorization failed")
|
t.Errorf("SVD factorization failed")
|
||||||
}
|
}
|
||||||
@@ -152,7 +151,7 @@ func TestSVD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test None decomposition.
|
// Test None decomposition.
|
||||||
ok = svd.Factorize(a, matrix.SVDNone)
|
ok = svd.Factorize(a, SVDNone)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("SVD factorization failed")
|
t.Errorf("SVD factorization failed")
|
||||||
}
|
}
|
@@ -2,14 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -64,7 +63,7 @@ func NewSymDense(n int, data []float64) *SymDense {
|
|||||||
panic("mat64: negative dimension")
|
panic("mat64: negative dimension")
|
||||||
}
|
}
|
||||||
if data != nil && n*n != len(data) {
|
if data != nil && n*n != len(data) {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = make([]float64, n*n)
|
data = make([]float64, n*n)
|
||||||
@@ -147,7 +146,7 @@ func (s *SymDense) reuseAs(n int) {
|
|||||||
panic(badSymTriangle)
|
panic(badSymTriangle)
|
||||||
}
|
}
|
||||||
if s.mat.N != n {
|
if s.mat.N != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +162,7 @@ func (s *SymDense) isolatedWorkspace(a Symmetric) (w *SymDense, restore func())
|
|||||||
func (s *SymDense) AddSym(a, b Symmetric) {
|
func (s *SymDense) AddSym(a, b Symmetric) {
|
||||||
n := a.Symmetric()
|
n := a.Symmetric()
|
||||||
if n != b.Symmetric() {
|
if n != b.Symmetric() {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
s.reuseAs(n)
|
s.reuseAs(n)
|
||||||
|
|
||||||
@@ -227,7 +226,7 @@ func (s *SymDense) CopySym(a Symmetric) int {
|
|||||||
func (s *SymDense) SymRankOne(a Symmetric, alpha float64, x *Vector) {
|
func (s *SymDense) SymRankOne(a Symmetric, alpha float64, x *Vector) {
|
||||||
n := x.Len()
|
n := x.Len()
|
||||||
if a.Symmetric() != n {
|
if a.Symmetric() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
s.reuseAs(n)
|
s.reuseAs(n)
|
||||||
if s != a {
|
if s != a {
|
||||||
@@ -246,7 +245,7 @@ func (s *SymDense) SymRankK(a Symmetric, alpha float64, x Matrix) {
|
|||||||
n := a.Symmetric()
|
n := a.Symmetric()
|
||||||
r, _ := x.Dims()
|
r, _ := x.Dims()
|
||||||
if r != n {
|
if r != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
xMat, aTrans := untranspose(x)
|
xMat, aTrans := untranspose(x)
|
||||||
var g blas64.General
|
var g blas64.General
|
||||||
@@ -307,7 +306,7 @@ func (s *SymDense) SymOuterK(alpha float64, x Matrix) {
|
|||||||
s.SymRankK(s, alpha, x)
|
s.SymRankK(s, alpha, x)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,10 +316,10 @@ func (s *SymDense) SymOuterK(alpha float64, x Matrix) {
|
|||||||
func (s *SymDense) RankTwo(a Symmetric, alpha float64, x, y *Vector) {
|
func (s *SymDense) RankTwo(a Symmetric, alpha float64, x, y *Vector) {
|
||||||
n := s.mat.N
|
n := s.mat.N
|
||||||
if x.Len() != n {
|
if x.Len() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if y.Len() != n {
|
if y.Len() != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
var w SymDense
|
var w SymDense
|
||||||
if s == a {
|
if s == a {
|
||||||
@@ -419,7 +418,7 @@ func (s *SymDense) ViewSquare(i, n int) Matrix {
|
|||||||
func (s *SymDense) SliceSquare(i, k int) Matrix {
|
func (s *SymDense) SliceSquare(i, k int) Matrix {
|
||||||
sz := s.Symmetric()
|
sz := s.Symmetric()
|
||||||
if i < 0 || sz < i || k < i || sz < k {
|
if i < 0 || sz < i || k < i || sz < k {
|
||||||
panic(matrix.ErrIndexOutOfRange)
|
panic(ErrIndexOutOfRange)
|
||||||
}
|
}
|
||||||
v := *s
|
v := *s
|
||||||
v.mat.Data = s.mat.Data[i*s.mat.Stride+i : (k-1)*s.mat.Stride+k]
|
v.mat.Data = s.mat.Data[i*s.mat.Stride+i : (k-1)*s.mat.Stride+k]
|
||||||
@@ -434,7 +433,7 @@ func (s *SymDense) SliceSquare(i, k int) Matrix {
|
|||||||
// not modified during the call to GrowSquare.
|
// not modified during the call to GrowSquare.
|
||||||
func (s *SymDense) GrowSquare(n int) Matrix {
|
func (s *SymDense) GrowSquare(n int) Matrix {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
panic(matrix.ErrIndexOutOfRange)
|
panic(ErrIndexOutOfRange)
|
||||||
}
|
}
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return s
|
return s
|
||||||
@@ -483,12 +482,12 @@ func (s *SymDense) PowPSD(a Symmetric, pow float64) error {
|
|||||||
var eigen EigenSym
|
var eigen EigenSym
|
||||||
ok := eigen.Factorize(a, true)
|
ok := eigen.Factorize(a, true)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.ErrFailedEigen
|
return ErrFailedEigen
|
||||||
}
|
}
|
||||||
values := eigen.Values(nil)
|
values := eigen.Values(nil)
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
if v <= 0 {
|
if v <= 0 {
|
||||||
return matrix.ErrNotPSD
|
return ErrNotPSD
|
||||||
}
|
}
|
||||||
values[i] = math.Pow(v, pow)
|
values[i] = math.Pow(v, pow)
|
||||||
}
|
}
|
@@ -1,14 +1,14 @@
|
|||||||
package mat64_test
|
package mat_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleSymDense_SubsetSym() {
|
func ExampleSymDense_SubsetSym() {
|
||||||
n := 5
|
n := 5
|
||||||
s := mat64.NewSymDense(5, nil)
|
s := mat.NewSymDense(5, nil)
|
||||||
count := 1.0
|
count := 1.0
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
for j := i; j < n; j++ {
|
for j := i; j < n; j++ {
|
||||||
@@ -17,18 +17,18 @@ func ExampleSymDense_SubsetSym() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("Original matrix:")
|
fmt.Println("Original matrix:")
|
||||||
fmt.Printf("%0.4v\n\n", mat64.Formatted(s))
|
fmt.Printf("%0.4v\n\n", mat.Formatted(s))
|
||||||
|
|
||||||
// Take the subset {0, 2, 4}
|
// Take the subset {0, 2, 4}
|
||||||
var sub mat64.SymDense
|
var sub mat.SymDense
|
||||||
sub.SubsetSym(s, []int{0, 2, 4})
|
sub.SubsetSym(s, []int{0, 2, 4})
|
||||||
fmt.Println("Subset {0, 2, 4}")
|
fmt.Println("Subset {0, 2, 4}")
|
||||||
fmt.Printf("%0.4v\n\n", mat64.Formatted(&sub))
|
fmt.Printf("%0.4v\n\n", mat.Formatted(&sub))
|
||||||
|
|
||||||
// Take the subset {0, 0, 4}
|
// Take the subset {0, 0, 4}
|
||||||
sub.SubsetSym(s, []int{0, 0, 4})
|
sub.SubsetSym(s, []int{0, 0, 4})
|
||||||
fmt.Println("Subset {0, 0, 4}")
|
fmt.Println("Subset {0, 0, 4}")
|
||||||
fmt.Printf("%0.4v\n\n", mat64.Formatted(&sub))
|
fmt.Printf("%0.4v\n\n", mat.Formatted(&sub))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Original matrix:
|
// Original matrix:
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewSymmetric(t *testing.T) {
|
func TestNewSymmetric(t *testing.T) {
|
||||||
@@ -61,7 +60,7 @@ func TestNewSymmetric(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
panicked, message := panics(func() { NewSymDense(3, []float64{1, 2}) })
|
panicked, message := panics(func() { NewSymDense(3, []float64{1, 2}) })
|
||||||
if !panicked || message != matrix.ErrShape.Error() {
|
if !panicked || message != ErrShape.Error() {
|
||||||
t.Error("expected panic for invalid data slice length")
|
t.Error("expected panic for invalid data slice length")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,13 +80,13 @@ func TestSymAtSet(t *testing.T) {
|
|||||||
// Check At out of bounds
|
// Check At out of bounds
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { sym.At(row, 0) })
|
panicked, message := panics(func() { sym.At(row, 0) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { sym.At(0, col) })
|
panicked, message := panics(func() { sym.At(0, col) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,13 +94,13 @@ func TestSymAtSet(t *testing.T) {
|
|||||||
// Check Set out of bounds
|
// Check Set out of bounds
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { sym.SetSym(row, 0, 1.2) })
|
panicked, message := panics(func() { sym.SetSym(row, 0, 1.2) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { sym.SetSym(0, col, 1.2) })
|
panicked, message := panics(func() { sym.SetSym(0, col, 1.2) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/lapack/lapack64"
|
"gonum.org/v1/gonum/lapack/lapack64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -29,7 +28,7 @@ type Triangular interface {
|
|||||||
Matrix
|
Matrix
|
||||||
// Triangular returns the number of rows/columns in the matrix and its
|
// Triangular returns the number of rows/columns in the matrix and its
|
||||||
// orientation.
|
// orientation.
|
||||||
Triangle() (n int, kind matrix.TriKind)
|
Triangle() (n int, kind TriKind)
|
||||||
|
|
||||||
// TTri is the equivalent of the T() method in the Matrix interface but
|
// TTri is the equivalent of the T() method in the Matrix interface but
|
||||||
// guarantees the transpose is of triangular type.
|
// guarantees the transpose is of triangular type.
|
||||||
@@ -72,7 +71,7 @@ func (t TransposeTri) T() Matrix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Triangle returns the number of rows/columns in the matrix and its orientation.
|
// Triangle returns the number of rows/columns in the matrix and its orientation.
|
||||||
func (t TransposeTri) Triangle() (int, matrix.TriKind) {
|
func (t TransposeTri) Triangle() (int, TriKind) {
|
||||||
n, upper := t.Triangular.Triangle()
|
n, upper := t.Triangular.Triangle()
|
||||||
return n, !upper
|
return n, !upper
|
||||||
}
|
}
|
||||||
@@ -99,18 +98,18 @@ func (t TransposeTri) UntransposeTri() Triangular {
|
|||||||
// The data must be arranged in row-major order, i.e. the (i*c + j)-th
|
// The data must be arranged in row-major order, i.e. the (i*c + j)-th
|
||||||
// element in the data slice is the {i, j}-th element in the matrix.
|
// element in the data slice is the {i, j}-th element in the matrix.
|
||||||
// Only the values in the triangular portion corresponding to kind are used.
|
// Only the values in the triangular portion corresponding to kind are used.
|
||||||
func NewTriDense(n int, kind matrix.TriKind, data []float64) *TriDense {
|
func NewTriDense(n int, kind TriKind, data []float64) *TriDense {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
panic("mat64: negative dimension")
|
panic("mat64: negative dimension")
|
||||||
}
|
}
|
||||||
if data != nil && len(data) != n*n {
|
if data != nil && len(data) != n*n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = make([]float64, n*n)
|
data = make([]float64, n*n)
|
||||||
}
|
}
|
||||||
uplo := blas.Lower
|
uplo := blas.Lower
|
||||||
if kind == matrix.Upper {
|
if kind == Upper {
|
||||||
uplo = blas.Upper
|
uplo = blas.Upper
|
||||||
}
|
}
|
||||||
return &TriDense{
|
return &TriDense{
|
||||||
@@ -131,16 +130,16 @@ func (t *TriDense) Dims() (r, c int) {
|
|||||||
|
|
||||||
// Triangle returns the dimension of t and its orientation. The returned
|
// Triangle returns the dimension of t and its orientation. The returned
|
||||||
// orientation is only valid when n is not zero.
|
// orientation is only valid when n is not zero.
|
||||||
func (t *TriDense) Triangle() (n int, kind matrix.TriKind) {
|
func (t *TriDense) Triangle() (n int, kind TriKind) {
|
||||||
return t.mat.N, matrix.TriKind(!t.isZero()) && t.triKind()
|
return t.mat.N, TriKind(!t.isZero()) && t.triKind()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TriDense) isUpper() bool {
|
func (t *TriDense) isUpper() bool {
|
||||||
return isUpperUplo(t.mat.Uplo)
|
return isUpperUplo(t.mat.Uplo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TriDense) triKind() matrix.TriKind {
|
func (t *TriDense) triKind() TriKind {
|
||||||
return matrix.TriKind(isUpperUplo(t.mat.Uplo))
|
return TriKind(isUpperUplo(t.mat.Uplo))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUpperUplo(u blas.Uplo) bool {
|
func isUpperUplo(u blas.Uplo) bool {
|
||||||
@@ -216,9 +215,9 @@ func untransposeTri(a Triangular) (Triangular, bool) {
|
|||||||
// reuseAs resizes a zero receiver to an n×n triangular matrix with the given
|
// reuseAs resizes a zero receiver to an n×n triangular matrix with the given
|
||||||
// orientation. If the receiver is non-zero, reuseAs checks that the receiver
|
// orientation. If the receiver is non-zero, reuseAs checks that the receiver
|
||||||
// is the correct size and orientation.
|
// is the correct size and orientation.
|
||||||
func (t *TriDense) reuseAs(n int, kind matrix.TriKind) {
|
func (t *TriDense) reuseAs(n int, kind TriKind) {
|
||||||
ul := blas.Lower
|
ul := blas.Lower
|
||||||
if kind == matrix.Upper {
|
if kind == Upper {
|
||||||
ul = blas.Upper
|
ul = blas.Upper
|
||||||
}
|
}
|
||||||
if t.mat.N > t.cap {
|
if t.mat.N > t.cap {
|
||||||
@@ -236,10 +235,10 @@ func (t *TriDense) reuseAs(n int, kind matrix.TriKind) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.mat.N != n {
|
if t.mat.N != n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if t.mat.Uplo != ul {
|
if t.mat.Uplo != ul {
|
||||||
panic(matrix.ErrTriangle)
|
panic(ErrTriangle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,18 +332,18 @@ func (t *TriDense) InverseTri(a Triangular) error {
|
|||||||
t.Copy(a)
|
t.Copy(a)
|
||||||
work := getFloats(3*n, false)
|
work := getFloats(3*n, false)
|
||||||
iwork := getInts(n, false)
|
iwork := getInts(n, false)
|
||||||
cond := lapack64.Trcon(matrix.CondNorm, t.mat, work, iwork)
|
cond := lapack64.Trcon(CondNorm, t.mat, work, iwork)
|
||||||
putFloats(work)
|
putFloats(work)
|
||||||
putInts(iwork)
|
putInts(iwork)
|
||||||
if math.IsInf(cond, 1) {
|
if math.IsInf(cond, 1) {
|
||||||
return matrix.Condition(cond)
|
return Condition(cond)
|
||||||
}
|
}
|
||||||
ok := lapack64.Trtri(t.mat)
|
ok := lapack64.Trtri(t.mat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return matrix.Condition(math.Inf(1))
|
return Condition(math.Inf(1))
|
||||||
}
|
}
|
||||||
if cond > matrix.ConditionTolerance {
|
if cond > ConditionTolerance {
|
||||||
return matrix.Condition(cond)
|
return Condition(cond)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -356,10 +355,10 @@ func (t *TriDense) MulTri(a, b Triangular) {
|
|||||||
n, kind := a.Triangle()
|
n, kind := a.Triangle()
|
||||||
nb, kindb := b.Triangle()
|
nb, kindb := b.Triangle()
|
||||||
if n != nb {
|
if n != nb {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if kind != kindb {
|
if kind != kindb {
|
||||||
panic(matrix.ErrTriangle)
|
panic(ErrTriangle)
|
||||||
}
|
}
|
||||||
|
|
||||||
aU, _ := untransposeTri(a)
|
aU, _ := untransposeTri(a)
|
||||||
@@ -375,7 +374,7 @@ func (t *TriDense) MulTri(a, b Triangular) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(btracey): Improve the set of fast-paths.
|
// TODO(btracey): Improve the set of fast-paths.
|
||||||
if kind == matrix.Upper {
|
if kind == Upper {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
for j := i; j < n; j++ {
|
for j := i; j < n; j++ {
|
||||||
var v float64
|
var v float64
|
@@ -1,4 +1,4 @@
|
|||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -8,14 +8,13 @@ import (
|
|||||||
|
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewTriangular(t *testing.T) {
|
func TestNewTriangular(t *testing.T) {
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
data []float64
|
data []float64
|
||||||
n int
|
n int
|
||||||
kind matrix.TriKind
|
kind TriKind
|
||||||
mat *TriDense
|
mat *TriDense
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -25,7 +24,7 @@ func TestNewTriangular(t *testing.T) {
|
|||||||
7, 8, 9,
|
7, 8, 9,
|
||||||
},
|
},
|
||||||
n: 3,
|
n: 3,
|
||||||
kind: matrix.Upper,
|
kind: Upper,
|
||||||
mat: &TriDense{
|
mat: &TriDense{
|
||||||
mat: blas64.Triangular{
|
mat: blas64.Triangular{
|
||||||
N: 3,
|
N: 3,
|
||||||
@@ -52,9 +51,9 @@ func TestNewTriangular(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, kind := range []matrix.TriKind{matrix.Lower, matrix.Upper} {
|
for _, kind := range []TriKind{Lower, Upper} {
|
||||||
panicked, message := panics(func() { NewTriDense(3, kind, []float64{1, 2}) })
|
panicked, message := panics(func() { NewTriDense(3, kind, []float64{1, 2}) })
|
||||||
if !panicked || message != matrix.ErrShape.Error() {
|
if !panicked || message != ErrShape.Error() {
|
||||||
t.Errorf("expected panic for invalid data slice length for upper=%t", kind)
|
t.Errorf("expected panic for invalid data slice length for upper=%t", kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,13 +76,13 @@ func TestTriAtSet(t *testing.T) {
|
|||||||
// Check At out of bounds
|
// Check At out of bounds
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { tri.At(row, 0) })
|
panicked, message := panics(func() { tri.At(row, 0) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { tri.At(0, col) })
|
panicked, message := panics(func() { tri.At(0, col) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,13 +90,13 @@ func TestTriAtSet(t *testing.T) {
|
|||||||
// Check Set out of bounds
|
// Check Set out of bounds
|
||||||
for _, row := range []int{-1, rows, rows + 1} {
|
for _, row := range []int{-1, rows, rows + 1} {
|
||||||
panicked, message := panics(func() { tri.SetTri(row, 0, 1.2) })
|
panicked, message := panics(func() { tri.SetTri(row, 0, 1.2) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, cols, cols + 1} {
|
for _, col := range []int{-1, cols, cols + 1} {
|
||||||
panicked, message := panics(func() { tri.SetTri(0, col, 1.2) })
|
panicked, message := panics(func() { tri.SetTri(0, col, 1.2) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +110,7 @@ func TestTriAtSet(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
tri.mat.Uplo = st.uplo
|
tri.mat.Uplo = st.uplo
|
||||||
panicked, message := panics(func() { tri.SetTri(st.row, st.col, 1.2) })
|
panicked, message := panics(func() { tri.SetTri(st.row, st.col, 1.2) })
|
||||||
if !panicked || message != matrix.ErrTriangleSet.Error() {
|
if !panicked || message != ErrTriangleSet.Error() {
|
||||||
t.Errorf("expected panic for %+v", st)
|
t.Errorf("expected panic for %+v", st)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,8 +139,8 @@ func TestTriDenseCopy(t *testing.T) {
|
|||||||
size := rand.Intn(100)
|
size := rand.Intn(100)
|
||||||
r, err := randDense(size, 0.9, rand.NormFloat64)
|
r, err := randDense(size, 0.9, rand.NormFloat64)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
if err != matrix.ErrZeroLength {
|
if err != ErrZeroLength {
|
||||||
t.Fatalf("expected error %v: got: %v", matrix.ErrZeroLength, err)
|
t.Fatalf("expected error %v: got: %v", ErrZeroLength, err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -190,8 +189,8 @@ func TestTriTriDenseCopy(t *testing.T) {
|
|||||||
size := rand.Intn(100)
|
size := rand.Intn(100)
|
||||||
r, err := randDense(size, 1, rand.NormFloat64)
|
r, err := randDense(size, 1, rand.NormFloat64)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
if err != matrix.ErrZeroLength {
|
if err != ErrZeroLength {
|
||||||
t.Fatalf("expected error %v: got: %v", matrix.ErrZeroLength, err)
|
t.Fatalf("expected error %v: got: %v", ErrZeroLength, err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -238,7 +237,7 @@ func TestTriTriDenseCopy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTriInverse(t *testing.T) {
|
func TestTriInverse(t *testing.T) {
|
||||||
for _, kind := range []matrix.TriKind{matrix.Upper, matrix.Lower} {
|
for _, kind := range []TriKind{Upper, Lower} {
|
||||||
for _, n := range []int{1, 3, 5, 9} {
|
for _, n := range []int{1, 3, 5, 9} {
|
||||||
data := make([]float64, n*n)
|
data := make([]float64, n*n)
|
||||||
for i := range data {
|
for i := range data {
|
||||||
@@ -297,10 +296,10 @@ func TestTriMul(t *testing.T) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, kind := a.(Triangular).Triangle()
|
_, kind := a.(Triangular).Triangle()
|
||||||
r := kind == matrix.Lower
|
r := kind == Lower
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
receiver := NewTriDense(3, matrix.Lower, nil)
|
receiver := NewTriDense(3, Lower, nil)
|
||||||
testTwoInput(t, "TriMul", receiver, method, denseComparison, legalTypesLower, legalSizeTriMul, 1e-14)
|
testTwoInput(t, "TriMul", receiver, method, denseComparison, legalTypesLower, legalSizeTriMul, 1e-14)
|
||||||
|
|
||||||
legalTypesUpper := func(a, b Matrix) bool {
|
legalTypesUpper := func(a, b Matrix) bool {
|
||||||
@@ -309,10 +308,10 @@ func TestTriMul(t *testing.T) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, kind := a.(Triangular).Triangle()
|
_, kind := a.(Triangular).Triangle()
|
||||||
r := kind == matrix.Upper
|
r := kind == Upper
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
receiver = NewTriDense(3, matrix.Upper, nil)
|
receiver = NewTriDense(3, Upper, nil)
|
||||||
testTwoInput(t, "TriMul", receiver, method, denseComparison, legalTypesUpper, legalSizeTriMul, 1e-14)
|
testTwoInput(t, "TriMul", receiver, method, denseComparison, legalTypesUpper, legalSizeTriMul, 1e-14)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +322,7 @@ func TestCopySymIntoTriangle(t *testing.T) {
|
|||||||
sUplo blas.Uplo
|
sUplo blas.Uplo
|
||||||
s []float64
|
s []float64
|
||||||
|
|
||||||
tUplo matrix.TriKind
|
tUplo TriKind
|
||||||
want []float64
|
want []float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -334,7 +333,7 @@ func TestCopySymIntoTriangle(t *testing.T) {
|
|||||||
nan, 4, 5,
|
nan, 4, 5,
|
||||||
nan, nan, 6,
|
nan, nan, 6,
|
||||||
},
|
},
|
||||||
tUplo: matrix.Upper,
|
tUplo: Upper,
|
||||||
want: []float64{
|
want: []float64{
|
||||||
1, 2, 3,
|
1, 2, 3,
|
||||||
0, 4, 5,
|
0, 4, 5,
|
||||||
@@ -349,7 +348,7 @@ func TestCopySymIntoTriangle(t *testing.T) {
|
|||||||
2, 3, nan,
|
2, 3, nan,
|
||||||
4, 5, 6,
|
4, 5, 6,
|
||||||
},
|
},
|
||||||
tUplo: matrix.Upper,
|
tUplo: Upper,
|
||||||
want: []float64{
|
want: []float64{
|
||||||
1, 2, 4,
|
1, 2, 4,
|
||||||
0, 3, 5,
|
0, 3, 5,
|
||||||
@@ -364,7 +363,7 @@ func TestCopySymIntoTriangle(t *testing.T) {
|
|||||||
nan, 4, 5,
|
nan, 4, 5,
|
||||||
nan, nan, 6,
|
nan, nan, 6,
|
||||||
},
|
},
|
||||||
tUplo: matrix.Lower,
|
tUplo: Lower,
|
||||||
want: []float64{
|
want: []float64{
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
2, 4, 0,
|
2, 4, 0,
|
||||||
@@ -379,7 +378,7 @@ func TestCopySymIntoTriangle(t *testing.T) {
|
|||||||
2, 3, nan,
|
2, 3, nan,
|
||||||
4, 5, 6,
|
4, 5, 6,
|
||||||
},
|
},
|
||||||
tUplo: matrix.Lower,
|
tUplo: Lower,
|
||||||
want: []float64{
|
want: []float64{
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
2, 3, 0,
|
2, 3, 0,
|
@@ -2,13 +2,12 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/blas"
|
"gonum.org/v1/gonum/blas"
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/internal/asm/f64"
|
"gonum.org/v1/gonum/internal/asm/f64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -34,7 +33,7 @@ type Vector struct {
|
|||||||
// will be reflected in data. If neither of these is true, NewVector will panic.
|
// will be reflected in data. If neither of these is true, NewVector will panic.
|
||||||
func NewVector(n int, data []float64) *Vector {
|
func NewVector(n int, data []float64) *Vector {
|
||||||
if len(data) != n && data != nil {
|
if len(data) != n && data != nil {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = make([]float64, n)
|
data = make([]float64, n)
|
||||||
@@ -64,7 +63,7 @@ func (v *Vector) ViewVec(i, n int) *Vector {
|
|||||||
// of the receiver.
|
// of the receiver.
|
||||||
func (v *Vector) SliceVec(i, k int) *Vector {
|
func (v *Vector) SliceVec(i, k int) *Vector {
|
||||||
if i < 0 || k <= i || v.n < k {
|
if i < 0 || k <= i || v.n < k {
|
||||||
panic(matrix.ErrIndexOutOfRange)
|
panic(ErrIndexOutOfRange)
|
||||||
}
|
}
|
||||||
return &Vector{
|
return &Vector{
|
||||||
n: k - i,
|
n: k - i,
|
||||||
@@ -168,7 +167,7 @@ func (v *Vector) AddScaledVec(a *Vector, alpha float64, b *Vector) {
|
|||||||
br := b.Len()
|
br := b.Len()
|
||||||
|
|
||||||
if ar != br {
|
if ar != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != a {
|
if v != a {
|
||||||
@@ -211,7 +210,7 @@ func (v *Vector) AddVec(a, b *Vector) {
|
|||||||
br := b.Len()
|
br := b.Len()
|
||||||
|
|
||||||
if ar != br {
|
if ar != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != a {
|
if v != a {
|
||||||
@@ -239,7 +238,7 @@ func (v *Vector) SubVec(a, b *Vector) {
|
|||||||
br := b.Len()
|
br := b.Len()
|
||||||
|
|
||||||
if ar != br {
|
if ar != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != a {
|
if v != a {
|
||||||
@@ -268,7 +267,7 @@ func (v *Vector) MulElemVec(a, b *Vector) {
|
|||||||
br := b.Len()
|
br := b.Len()
|
||||||
|
|
||||||
if ar != br {
|
if ar != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != a {
|
if v != a {
|
||||||
@@ -293,7 +292,7 @@ func (v *Vector) DivElemVec(a, b *Vector) {
|
|||||||
br := b.Len()
|
br := b.Len()
|
||||||
|
|
||||||
if ar != br {
|
if ar != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != a {
|
if v != a {
|
||||||
@@ -317,7 +316,7 @@ func (v *Vector) MulVec(a Matrix, b *Vector) {
|
|||||||
r, c := a.Dims()
|
r, c := a.Dims()
|
||||||
br := b.Len()
|
br := b.Len()
|
||||||
if c != br {
|
if c != br {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != b {
|
if v != b {
|
||||||
@@ -427,7 +426,7 @@ func (v *Vector) reuseAs(r int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r != v.n {
|
if r != v.n {
|
||||||
panic(matrix.ErrShape)
|
panic(ErrShape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
package mat64
|
package mat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/blas/blas64"
|
"gonum.org/v1/gonum/blas/blas64"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewVector(t *testing.T) {
|
func TestNewVector(t *testing.T) {
|
||||||
@@ -80,13 +79,13 @@ func TestVectorAtSet(t *testing.T) {
|
|||||||
|
|
||||||
for _, row := range []int{-1, n} {
|
for _, row := range []int{-1, n} {
|
||||||
panicked, message := panics(func() { v.At(row, 0) })
|
panicked, message := panics(func() { v.At(row, 0) })
|
||||||
if !panicked || message != matrix.ErrRowAccess.Error() {
|
if !panicked || message != ErrRowAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access for test %d n=%d r=%d", i, n, row)
|
t.Errorf("expected panic for invalid row access for test %d n=%d r=%d", i, n, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, col := range []int{-1, 1} {
|
for _, col := range []int{-1, 1} {
|
||||||
panicked, message := panics(func() { v.At(0, col) })
|
panicked, message := panics(func() { v.At(0, col) })
|
||||||
if !panicked || message != matrix.ErrColAccess.Error() {
|
if !panicked || message != ErrColAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid column access for test %d n=%d c=%d", i, n, col)
|
t.Errorf("expected panic for invalid column access for test %d n=%d c=%d", i, n, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +98,7 @@ func TestVectorAtSet(t *testing.T) {
|
|||||||
|
|
||||||
for _, row := range []int{-1, n} {
|
for _, row := range []int{-1, n} {
|
||||||
panicked, message := panics(func() { v.SetVec(row, 100) })
|
panicked, message := panics(func() { v.SetVec(row, 100) })
|
||||||
if !panicked || message != matrix.ErrVectorAccess.Error() {
|
if !panicked || message != ErrVectorAccess.Error() {
|
||||||
t.Errorf("expected panic for invalid row access for test %d n=%d r=%d", i, n, row)
|
t.Errorf("expected panic for invalid row access for test %d n=%d r=%d", i, n, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,95 +0,0 @@
|
|||||||
// Generated by running
|
|
||||||
// go generate github.com/gonum/matrix
|
|
||||||
// DO NOT EDIT.
|
|
||||||
|
|
||||||
// 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 cmat128 provides implementations of complex128 matrix structures and
|
|
||||||
// linear algebra operations on them.
|
|
||||||
//
|
|
||||||
// Overview
|
|
||||||
//
|
|
||||||
// This section provides a quick overview of the cmat128 package. The following
|
|
||||||
// sections provide more in depth commentary.
|
|
||||||
//
|
|
||||||
// cmat128 provides:
|
|
||||||
// - Interfaces for a complex Matrix
|
|
||||||
//
|
|
||||||
// BLAS and LAPACK
|
|
||||||
//
|
|
||||||
// BLAS and LAPACK are the standard APIs for linear algebra routines. Many
|
|
||||||
// operations in cmat128 are implemented using calls to the wrapper functions
|
|
||||||
// in gonum/blas/cblas128 and gonum/lapack/clapack128. By default, cblas128 and
|
|
||||||
// clapack128 call the native Go implementations of the routines. Alternatively,
|
|
||||||
// it is possible to use C-based implementations of the APIs through the respective
|
|
||||||
// cgo packages and "Use" functions. The Go implementation of LAPACK makes calls
|
|
||||||
// through cblas128, so if a cgo BLAS implementation is registered, the clapack128
|
|
||||||
// calls will be partially executed in Go and partially executed in C.
|
|
||||||
//
|
|
||||||
// Type Switching
|
|
||||||
//
|
|
||||||
// The Matrix abstraction enables efficiency as well as interoperability. Go's
|
|
||||||
// type reflection capabilities are used to choose the most efficient routine
|
|
||||||
// given the specific concrete types. For example, in
|
|
||||||
// c.Mul(a, b)
|
|
||||||
// if a and b both implement RawMatrixer, that is, they can be represented as a
|
|
||||||
// cblas128.General, cblas128.Gemm (general matrix multiplication) is called, while
|
|
||||||
// instead if b is a RawSymmetricer cblas128.Symm is used (general-symmetric
|
|
||||||
// multiplication), and if b is a *Vector cblas128.Gemv is used.
|
|
||||||
//
|
|
||||||
// There are many possible type combinations and special cases. No specific guarantees
|
|
||||||
// are made about the performance of any method, and in particular, note that an
|
|
||||||
// abstract matrix type may be copied into a concrete type of the corresponding
|
|
||||||
// value. If there are specific special cases that are needed, please submit a
|
|
||||||
// pull-request or file an issue.
|
|
||||||
//
|
|
||||||
// Invariants
|
|
||||||
//
|
|
||||||
// Matrix input arguments to functions are never directly modified. If an operation
|
|
||||||
// changes Matrix data, the mutated matrix will be the receiver of a function.
|
|
||||||
//
|
|
||||||
// For convenience, a matrix may be used as both a receiver and as an input, e.g.
|
|
||||||
// a.Pow(a, 6)
|
|
||||||
// v.SolveVec(a.T(), v)
|
|
||||||
// though in many cases this will cause an allocation (see Element Aliasing).
|
|
||||||
// An exception to this rule is Copy, which does not allow a.Copy(a.T()).
|
|
||||||
//
|
|
||||||
// Element Aliasing
|
|
||||||
//
|
|
||||||
// Most methods in cmat128 modify receiver data. It is forbidden for the modified
|
|
||||||
// data region of the receiver to overlap the used data area of the input
|
|
||||||
// arguments. The exception to this rule is when the method receiver is equal to one
|
|
||||||
// of the input arguments, as in the a.Pow(a, 6) call above, or its implicit transpose.
|
|
||||||
//
|
|
||||||
// This prohibition is to help avoid subtle mistakes when the method needs to read
|
|
||||||
// from and write to the same data region. There are ways to make mistakes using the
|
|
||||||
// cmat128 API, and cmat128 functions will detect and complain about those.
|
|
||||||
// There are many ways to make mistakes by excursion from the cmat128 API via
|
|
||||||
// interaction with raw matrix values.
|
|
||||||
//
|
|
||||||
// If you need to read the rest of this section to understand the behavior of
|
|
||||||
// your program, you are being clever. Don't be clever. If you must be clever,
|
|
||||||
// cblas128 and clapack128 may be used to call the behavior directly.
|
|
||||||
//
|
|
||||||
// cmat128 will use the following rules to detect overlap between the receiver and one
|
|
||||||
// of the inputs:
|
|
||||||
// - the input implements one of the Raw methods, and
|
|
||||||
// - the Raw type matches that of the receiver or
|
|
||||||
// one is a RawMatrixer and the other is a RawVectorer, and
|
|
||||||
// - the address ranges of the backing data slices overlap, and
|
|
||||||
// - the strides differ or there is an overlap in the used data elements.
|
|
||||||
// If such an overlap is detected, the method will panic.
|
|
||||||
//
|
|
||||||
// The following cases will not panic:
|
|
||||||
// - the data slices do not overlap,
|
|
||||||
// - there is pointer identity between the receiver and input values after
|
|
||||||
// the value has been untransposed if necessary.
|
|
||||||
//
|
|
||||||
// cmat128 will not attempt to detect element overlap if the input does not implement a
|
|
||||||
// Raw method, or if the Raw method differs from that of the receiver except when a
|
|
||||||
// conversion has occurred through a cmat128 API function. Method behavior is undefined
|
|
||||||
// if there is undetected overlap.
|
|
||||||
//
|
|
||||||
package cmat128 // import "gonum.org/v1/gonum/matrix/cmat128"
|
|
@@ -1,142 +0,0 @@
|
|||||||
// 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 conv provides matrix type interconversion utilities.
|
|
||||||
package conv // import "gonum.org/v1/gonum/matrix/conv"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
"gonum.org/v1/gonum/matrix/cmat128"
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Complex is a complex matrix constructed from two real matrices.
|
|
||||||
type Complex struct {
|
|
||||||
// r and i are not exposed to ensure that
|
|
||||||
// their dimensions can not be altered by
|
|
||||||
// clients behind our back.
|
|
||||||
r, i mat64.Matrix
|
|
||||||
|
|
||||||
// imagSign holds the sign of the imaginary
|
|
||||||
// part of the Complex. Valid values are 1 and -1.
|
|
||||||
imagSign float64
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ Realer = Complex{}
|
|
||||||
_ Imager = Complex{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewComplex returns a complex matrix constructed from r and i. At least one of
|
|
||||||
// r or i must be non-nil otherwise NewComplex will panic. If one of the inputs
|
|
||||||
// is nil, that part of the complex number will be zero when returned by At.
|
|
||||||
// If both are non-nil but differ in their sizes, NewComplex will panic.
|
|
||||||
func NewComplex(r, i mat64.Matrix) Complex {
|
|
||||||
if r == nil && i == nil {
|
|
||||||
panic("conv: no matrix")
|
|
||||||
} else if r != nil && i != nil {
|
|
||||||
rr, rc := r.Dims()
|
|
||||||
ir, ic := i.Dims()
|
|
||||||
if rr != ir || rc != ic {
|
|
||||||
panic(matrix.ErrShape)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Complex{r: r, i: i, imagSign: 1}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dims returns the number of rows and columns in the matrix.
|
|
||||||
func (m Complex) Dims() (r, c int) {
|
|
||||||
if m.r == nil {
|
|
||||||
return m.i.Dims()
|
|
||||||
}
|
|
||||||
return m.r.Dims()
|
|
||||||
}
|
|
||||||
|
|
||||||
// At returns the element at row i, column j.
|
|
||||||
func (m Complex) At(i, j int) complex128 {
|
|
||||||
if m.i == nil {
|
|
||||||
return complex(m.r.At(i, j), 0)
|
|
||||||
}
|
|
||||||
if m.r == nil {
|
|
||||||
return complex(0, m.imagSign*m.i.At(i, j))
|
|
||||||
}
|
|
||||||
return complex(m.r.At(i, j), m.imagSign*m.i.At(i, j))
|
|
||||||
}
|
|
||||||
|
|
||||||
// H performs an implicit transpose.
|
|
||||||
func (m Complex) H() cmat128.Matrix {
|
|
||||||
if m.i == nil {
|
|
||||||
return Complex{r: m.r.T()}
|
|
||||||
}
|
|
||||||
if m.r == nil {
|
|
||||||
return Complex{i: m.i.T(), imagSign: -m.imagSign}
|
|
||||||
}
|
|
||||||
return Complex{r: m.r.T(), i: m.i.T(), imagSign: -m.imagSign}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Real returns the real part of the receiver.
|
|
||||||
func (m Complex) Real() mat64.Matrix { return m.r }
|
|
||||||
|
|
||||||
// Imag returns the imaginary part of the receiver.
|
|
||||||
func (m Complex) Imag() mat64.Matrix { return m.i }
|
|
||||||
|
|
||||||
// Realer is a complex matrix that can return its real part.
|
|
||||||
type Realer interface {
|
|
||||||
Real() mat64.Matrix
|
|
||||||
}
|
|
||||||
|
|
||||||
// Imager is a complex matrix that can return its imaginary part.
|
|
||||||
type Imager interface {
|
|
||||||
Imag() mat64.Matrix
|
|
||||||
}
|
|
||||||
|
|
||||||
// Real is the real part of a complex matrix.
|
|
||||||
type Real struct {
|
|
||||||
matrix cmat128.Matrix
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReal returns a mat64.Matrix representing the real part of m. If m is a Realer,
|
|
||||||
// the real part is returned.
|
|
||||||
func NewReal(m cmat128.Matrix) mat64.Matrix {
|
|
||||||
if m, ok := m.(Realer); ok {
|
|
||||||
return m.Real()
|
|
||||||
}
|
|
||||||
return Real{m}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dims returns the number of rows and columns in the matrix.
|
|
||||||
func (m Real) Dims() (r, c int) { return m.matrix.Dims() }
|
|
||||||
|
|
||||||
// At returns the element at row i, column j.
|
|
||||||
func (m Real) At(i, j int) float64 { return real(m.matrix.At(i, j)) }
|
|
||||||
|
|
||||||
// T performs an implicit transpose.
|
|
||||||
func (m Real) T() mat64.Matrix { return Real{m.matrix.H()} }
|
|
||||||
|
|
||||||
// Imag is the imaginary part of a complex matrix.
|
|
||||||
type Imag struct {
|
|
||||||
matrix cmat128.Matrix
|
|
||||||
|
|
||||||
// conjSign holds the sign of the matrix.
|
|
||||||
// Valid values are 1 and -1.
|
|
||||||
conjSign float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewImag returns a mat64.Matrix representing the imaginary part of m. If m is an Imager,
|
|
||||||
// the imaginary part is returned.
|
|
||||||
func NewImag(m cmat128.Matrix) mat64.Matrix {
|
|
||||||
if m, ok := m.(Imager); ok {
|
|
||||||
return m.Imag()
|
|
||||||
}
|
|
||||||
return Imag{matrix: m, conjSign: 1}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dims returns the number of rows and columns in the matrix.
|
|
||||||
func (m Imag) Dims() (r, c int) { return m.matrix.Dims() }
|
|
||||||
|
|
||||||
// At returns the element at row i, column j.
|
|
||||||
func (m Imag) At(i, j int) float64 { return m.conjSign * imag(m.matrix.At(i, j)) }
|
|
||||||
|
|
||||||
// T performs an implicit transpose.
|
|
||||||
func (m Imag) T() mat64.Matrix { return Imag{matrix: m.matrix.H(), conjSign: -m.conjSign} }
|
|
103
matrix/doc.go
103
matrix/doc.go
@@ -1,103 +0,0 @@
|
|||||||
// Generated by running
|
|
||||||
// go generate github.com/gonum/matrix
|
|
||||||
// DO NOT EDIT.
|
|
||||||
|
|
||||||
// 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 matrix provides common error handling mechanisms for matrix operations
|
|
||||||
// in mat64 and cmat128.
|
|
||||||
//
|
|
||||||
// Overview
|
|
||||||
//
|
|
||||||
// This section provides a quick overview of the matrix package. The following
|
|
||||||
// sections provide more in depth commentary.
|
|
||||||
//
|
|
||||||
// matrix provides:
|
|
||||||
// - Error type definitions
|
|
||||||
// - Error recovery mechanisms
|
|
||||||
// - Common constants used by mat64 and cmat128
|
|
||||||
//
|
|
||||||
// Errors
|
|
||||||
//
|
|
||||||
// The mat64 and cmat128 matrix packages share a common set of errors
|
|
||||||
// provided by matrix via the matrix.Error type.
|
|
||||||
//
|
|
||||||
// Errors are either returned directly or used as the parameter of a panic
|
|
||||||
// depending on the class of error encountered. Returned errors indicate
|
|
||||||
// that a call was not able to complete successfully while panics generally
|
|
||||||
// indicate a programmer or unrecoverable error.
|
|
||||||
//
|
|
||||||
// Examples of each type are found in the mat64 Solve methods, which find
|
|
||||||
// x such that A*x = b.
|
|
||||||
//
|
|
||||||
// An error value is returned from the function or method when the operation
|
|
||||||
// can meaningfully fail. The Solve operation cannot complete if A is
|
|
||||||
// singular. However, determining the singularity of A is most easily
|
|
||||||
// discovered during the Solve procedure itself and is a valid result from
|
|
||||||
// the operation, so in this case an error is returned.
|
|
||||||
//
|
|
||||||
// A function will panic when the input parameters are inappropriate for
|
|
||||||
// the function. In Solve, for example, the number of rows of each input
|
|
||||||
// matrix must be equal because of the rules of matrix multiplication.
|
|
||||||
// Similarly, for solving A*x = b, a non-zero receiver must have the same
|
|
||||||
// number of rows as A has columns and must have the same number of columns
|
|
||||||
// as b. In all cases where a function will panic, conditions that would
|
|
||||||
// lead to a panic can easily be checked prior to a call.
|
|
||||||
//
|
|
||||||
// Error Recovery
|
|
||||||
//
|
|
||||||
// When a matrix.Error is the parameter of a panic, the panic can be
|
|
||||||
// recovered by a Maybe function, which will then return the error.
|
|
||||||
// Panics that are not of type matrix.Error are re-panicked by the
|
|
||||||
// Maybe functions.
|
|
||||||
//
|
|
||||||
// Invariants
|
|
||||||
//
|
|
||||||
// Matrix input arguments to functions are never directly modified. If an operation
|
|
||||||
// changes Matrix data, the mutated matrix will be the receiver of a function.
|
|
||||||
//
|
|
||||||
// For convenience, a matrix may be used as both a receiver and as an input, e.g.
|
|
||||||
// a.Pow(a, 6)
|
|
||||||
// v.SolveVec(a.T(), v)
|
|
||||||
// though in many cases this will cause an allocation (see Element Aliasing).
|
|
||||||
// An exception to this rule is Copy, which does not allow a.Copy(a.T()).
|
|
||||||
//
|
|
||||||
// Element Aliasing
|
|
||||||
//
|
|
||||||
// Most methods in the matrix packages modify receiver data. It is forbidden for the modified
|
|
||||||
// data region of the receiver to overlap the used data area of the input
|
|
||||||
// arguments. The exception to this rule is when the method receiver is equal to one
|
|
||||||
// of the input arguments, as in the a.Pow(a, 6) call above, or its implicit transpose.
|
|
||||||
//
|
|
||||||
// This prohibition is to help avoid subtle mistakes when the method needs to read
|
|
||||||
// from and write to the same data region. There are ways to make mistakes using the
|
|
||||||
// matrix API, and matrix functions will detect and complain about those.
|
|
||||||
// There are many ways to make mistakes by excursion from the matrix API via
|
|
||||||
// interaction with raw matrix values.
|
|
||||||
//
|
|
||||||
// If you need to read the rest of this section to understand the behavior of
|
|
||||||
// your program, you are being clever. Don't be clever. If you must be clever,
|
|
||||||
// blas64/cblas128 and lapack64/clapack128 may be used to call the behavior directly.
|
|
||||||
//
|
|
||||||
// The matrix packages will use the following rules to detect overlap between the receiver and one
|
|
||||||
// of the inputs:
|
|
||||||
// - the input implements one of the Raw methods, and
|
|
||||||
// - the Raw type matches that of the receiver or
|
|
||||||
// one is a RawMatrixer and the other is a RawVectorer, and
|
|
||||||
// - the address ranges of the backing data slices overlap, and
|
|
||||||
// - the strides differ or there is an overlap in the used data elements.
|
|
||||||
// If such an overlap is detected, the method will panic.
|
|
||||||
//
|
|
||||||
// The following cases will not panic:
|
|
||||||
// - the data slices do not overlap,
|
|
||||||
// - there is pointer identity between the receiver and input values after
|
|
||||||
// the value has been untransposed if necessary.
|
|
||||||
//
|
|
||||||
// The matrix packages will not attempt to detect element overlap if the input does not implement a
|
|
||||||
// Raw method, or if the Raw method differs from that of the receiver except when a
|
|
||||||
// conversion has occurred through a matrix API function. Method behavior is undefined
|
|
||||||
// if there is undetected overlap.
|
|
||||||
//
|
|
||||||
package matrix // import "gonum.org/v1/gonum/matrix"
|
|
343
matrix/gendoc.go
343
matrix/gendoc.go
@@ -1,343 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
//+build ignore
|
|
||||||
|
|
||||||
// gendoc creates the matrix, mat64 and cmat128 package doc comments.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
var docs = template.Must(template.New("docs").Funcs(funcs).Parse(`{{define "common"}}// Generated by running
|
|
||||||
// go generate github.com/gonum/matrix
|
|
||||||
// DO NOT EDIT.
|
|
||||||
|
|
||||||
// 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 {{.Name}} provides {{.Provides}}
|
|
||||||
//
|
|
||||||
// Overview
|
|
||||||
//
|
|
||||||
// This section provides a quick overview of the {{.Name}} package. The following
|
|
||||||
// sections provide more in depth commentary.
|
|
||||||
//
|
|
||||||
{{.Overview}}
|
|
||||||
//{{end}}
|
|
||||||
{{define "interfaces"}}// The Matrix Interfaces
|
|
||||||
//
|
|
||||||
// The Matrix interface is the common link between the concrete types. The Matrix
|
|
||||||
// interface is defined by three functions: Dims, which returns the dimensions
|
|
||||||
// of the Matrix, At, which returns the element in the specified location, and
|
|
||||||
// T for returning a Transpose (discussed later). All of the concrete types can
|
|
||||||
// perform these behaviors and so implement the interface. Methods and functions
|
|
||||||
// are designed to use this interface, so in particular the method
|
|
||||||
// func (m *Dense) Mul(a, b Matrix)
|
|
||||||
// constructs a *Dense from the result of a multiplication with any Matrix types,
|
|
||||||
// not just *Dense. Where more restrictive requirements must be met, there are also the
|
|
||||||
// Symmetric and Triangular interfaces. For example, in
|
|
||||||
// func (s *SymDense) AddSym(a, b Symmetric)
|
|
||||||
// the Symmetric interface guarantees a symmetric result.
|
|
||||||
//
|
|
||||||
// Transposes
|
|
||||||
//
|
|
||||||
// The T method is used for transposition. For example, c.Mul(a.T(), b) computes
|
|
||||||
// c = a^T * b. The {{if .ExamplePackage}}{{.ExamplePackage}}{{else}}{{.Name}}{{end}} types implement this method using an implicit transpose —
|
|
||||||
// see the Transpose type for more details. Note that some operations have a
|
|
||||||
// transpose as part of their definition, as in *SymDense.SymOuterK.
|
|
||||||
//{{end}}
|
|
||||||
{{define "factorization"}}// Matrix Factorization
|
|
||||||
//
|
|
||||||
// Matrix factorizations, such as the LU decomposition, typically have their own
|
|
||||||
// specific data storage, and so are each implemented as a specific type. The
|
|
||||||
// factorization can be computed through a call to Factorize
|
|
||||||
// var lu {{if .ExamplePackage}}{{.ExamplePackage}}{{else}}{{.Name}}{{end}}.LU
|
|
||||||
// lu.Factorize(a)
|
|
||||||
// The elements of the factorization can be extracted through methods on the
|
|
||||||
// appropriate type, i.e. *TriDense.LFromLU and *TriDense.UFromLU. Alternatively,
|
|
||||||
// they can be used directly, as in *Dense.SolveLU. Some factorizations can be
|
|
||||||
// updated directly, without needing to update the original matrix and refactorize,
|
|
||||||
// as in *LU.RankOne.
|
|
||||||
//{{end}}
|
|
||||||
{{define "blas"}}// BLAS and LAPACK
|
|
||||||
//
|
|
||||||
// BLAS and LAPACK are the standard APIs for linear algebra routines. Many
|
|
||||||
// operations in {{if .Description}}{{.Description}}{{else}}{{.Name}}{{end}} are implemented using calls to the wrapper functions
|
|
||||||
// in gonum/blas/{{.BLAS|alts}} and gonum/lapack/{{.LAPACK|alts}}. By default, {{.BLAS|join "/"}} and
|
|
||||||
// {{.LAPACK|join "/"}} call the native Go implementations of the routines. Alternatively,
|
|
||||||
// it is possible to use C-based implementations of the APIs through the respective
|
|
||||||
// cgo packages and "Use" functions. The Go implementation of LAPACK makes calls
|
|
||||||
// through {{.BLAS|join "/"}}, so if a cgo BLAS implementation is registered, the {{.LAPACK|join "/"}}
|
|
||||||
// calls will be partially executed in Go and partially executed in C.
|
|
||||||
//{{end}}
|
|
||||||
{{define "switching"}}// Type Switching
|
|
||||||
//
|
|
||||||
// The Matrix abstraction enables efficiency as well as interoperability. Go's
|
|
||||||
// type reflection capabilities are used to choose the most efficient routine
|
|
||||||
// given the specific concrete types. For example, in
|
|
||||||
// c.Mul(a, b)
|
|
||||||
// if a and b both implement RawMatrixer, that is, they can be represented as a
|
|
||||||
// {{.BLAS|alts}}.General, {{.BLAS|alts}}.Gemm (general matrix multiplication) is called, while
|
|
||||||
// instead if b is a RawSymmetricer {{.BLAS|alts}}.Symm is used (general-symmetric
|
|
||||||
// multiplication), and if b is a *Vector {{.BLAS|alts}}.Gemv is used.
|
|
||||||
//
|
|
||||||
// There are many possible type combinations and special cases. No specific guarantees
|
|
||||||
// are made about the performance of any method, and in particular, note that an
|
|
||||||
// abstract matrix type may be copied into a concrete type of the corresponding
|
|
||||||
// value. If there are specific special cases that are needed, please submit a
|
|
||||||
// pull-request or file an issue.
|
|
||||||
//{{end}}
|
|
||||||
{{define "invariants"}}// Invariants
|
|
||||||
//
|
|
||||||
// Matrix input arguments to functions are never directly modified. If an operation
|
|
||||||
// changes Matrix data, the mutated matrix will be the receiver of a function.
|
|
||||||
//
|
|
||||||
// For convenience, a matrix may be used as both a receiver and as an input, e.g.
|
|
||||||
// a.Pow(a, 6)
|
|
||||||
// v.SolveVec(a.T(), v)
|
|
||||||
// though in many cases this will cause an allocation (see Element Aliasing).
|
|
||||||
// An exception to this rule is Copy, which does not allow a.Copy(a.T()).
|
|
||||||
//{{end}}
|
|
||||||
{{define "aliasing"}}// Element Aliasing
|
|
||||||
//
|
|
||||||
// Most methods in {{if .Description}}{{.Description}}{{else}}{{.Name}}{{end}} modify receiver data. It is forbidden for the modified
|
|
||||||
// data region of the receiver to overlap the used data area of the input
|
|
||||||
// arguments. The exception to this rule is when the method receiver is equal to one
|
|
||||||
// of the input arguments, as in the a.Pow(a, 6) call above, or its implicit transpose.
|
|
||||||
//
|
|
||||||
// This prohibition is to help avoid subtle mistakes when the method needs to read
|
|
||||||
// from and write to the same data region. There are ways to make mistakes using the
|
|
||||||
// {{.Name}} API, and {{.Name}} functions will detect and complain about those.
|
|
||||||
// There are many ways to make mistakes by excursion from the {{.Name}} API via
|
|
||||||
// interaction with raw matrix values.
|
|
||||||
//
|
|
||||||
// If you need to read the rest of this section to understand the behavior of
|
|
||||||
// your program, you are being clever. Don't be clever. If you must be clever,
|
|
||||||
// {{.BLAS|join "/"}} and {{.LAPACK|join "/"}} may be used to call the behavior directly.
|
|
||||||
//
|
|
||||||
// {{if .Description}}{{.Description|sentence}}{{else}}{{.Name}}{{end}} will use the following rules to detect overlap between the receiver and one
|
|
||||||
// of the inputs:
|
|
||||||
// - the input implements one of the Raw methods, and
|
|
||||||
// - the Raw type matches that of the receiver or
|
|
||||||
// one is a RawMatrixer and the other is a RawVectorer, and
|
|
||||||
// - the address ranges of the backing data slices overlap, and
|
|
||||||
// - the strides differ or there is an overlap in the used data elements.
|
|
||||||
// If such an overlap is detected, the method will panic.
|
|
||||||
//
|
|
||||||
// The following cases will not panic:
|
|
||||||
// - the data slices do not overlap,
|
|
||||||
// - there is pointer identity between the receiver and input values after
|
|
||||||
// the value has been untransposed if necessary.
|
|
||||||
//
|
|
||||||
// {{if .Description}}{{.Description|sentence}}{{else}}{{.Name}}{{end}} will not attempt to detect element overlap if the input does not implement a
|
|
||||||
// Raw method, or if the Raw method differs from that of the receiver except when a
|
|
||||||
// conversion has occurred through a {{.Name}} API function. Method behavior is undefined
|
|
||||||
// if there is undetected overlap.
|
|
||||||
//{{end}}`))
|
|
||||||
|
|
||||||
type Package struct {
|
|
||||||
path string
|
|
||||||
|
|
||||||
Name string
|
|
||||||
Provides string
|
|
||||||
Description string
|
|
||||||
ExamplePackage string
|
|
||||||
Overview string
|
|
||||||
|
|
||||||
BLAS []string
|
|
||||||
LAPACK []string
|
|
||||||
|
|
||||||
template string
|
|
||||||
}
|
|
||||||
|
|
||||||
var pkgs = []Package{
|
|
||||||
{
|
|
||||||
path: ".",
|
|
||||||
|
|
||||||
Name: "matrix",
|
|
||||||
Description: "the matrix packages",
|
|
||||||
Provides: `common error handling mechanisms for matrix operations
|
|
||||||
// in mat64 and cmat128.`,
|
|
||||||
ExamplePackage: "mat64",
|
|
||||||
|
|
||||||
Overview: `// matrix provides:
|
|
||||||
// - Error type definitions
|
|
||||||
// - Error recovery mechanisms
|
|
||||||
// - Common constants used by mat64 and cmat128
|
|
||||||
//
|
|
||||||
// Errors
|
|
||||||
//
|
|
||||||
// The mat64 and cmat128 matrix packages share a common set of errors
|
|
||||||
// provided by matrix via the matrix.Error type.
|
|
||||||
//
|
|
||||||
// Errors are either returned directly or used as the parameter of a panic
|
|
||||||
// depending on the class of error encountered. Returned errors indicate
|
|
||||||
// that a call was not able to complete successfully while panics generally
|
|
||||||
// indicate a programmer or unrecoverable error.
|
|
||||||
//
|
|
||||||
// Examples of each type are found in the mat64 Solve methods, which find
|
|
||||||
// x such that A*x = b.
|
|
||||||
//
|
|
||||||
// An error value is returned from the function or method when the operation
|
|
||||||
// can meaningfully fail. The Solve operation cannot complete if A is
|
|
||||||
// singular. However, determining the singularity of A is most easily
|
|
||||||
// discovered during the Solve procedure itself and is a valid result from
|
|
||||||
// the operation, so in this case an error is returned.
|
|
||||||
//
|
|
||||||
// A function will panic when the input parameters are inappropriate for
|
|
||||||
// the function. In Solve, for example, the number of rows of each input
|
|
||||||
// matrix must be equal because of the rules of matrix multiplication.
|
|
||||||
// Similarly, for solving A*x = b, a non-zero receiver must have the same
|
|
||||||
// number of rows as A has columns and must have the same number of columns
|
|
||||||
// as b. In all cases where a function will panic, conditions that would
|
|
||||||
// lead to a panic can easily be checked prior to a call.
|
|
||||||
//
|
|
||||||
// Error Recovery
|
|
||||||
//
|
|
||||||
// When a matrix.Error is the parameter of a panic, the panic can be
|
|
||||||
// recovered by a Maybe function, which will then return the error.
|
|
||||||
// Panics that are not of type matrix.Error are re-panicked by the
|
|
||||||
// Maybe functions.`,
|
|
||||||
BLAS: []string{"blas64", "cblas128"},
|
|
||||||
LAPACK: []string{"lapack64", "clapack128"},
|
|
||||||
|
|
||||||
template: `{{template "common" .}}
|
|
||||||
{{template "invariants" .}}
|
|
||||||
{{template "aliasing" .}}
|
|
||||||
package {{.Name}} // import "gonum.org/v1/gonum/{{.Name}}"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "mat64",
|
|
||||||
|
|
||||||
Name: "mat64",
|
|
||||||
Provides: `implementations of float64 matrix structures and
|
|
||||||
// linear algebra operations on them.`,
|
|
||||||
|
|
||||||
Overview: `// mat64 provides:
|
|
||||||
// - Interfaces for Matrix classes (Matrix, Symmetric, Triangular)
|
|
||||||
// - Concrete implementations (Dense, SymDense, TriDense)
|
|
||||||
// - Methods and functions for using matrix data (Add, Trace, SymRankOne)
|
|
||||||
// - Types for constructing and using matrix factorizations (QR, LU)
|
|
||||||
//
|
|
||||||
// A matrix may be constructed through the corresponding New function. If no
|
|
||||||
// backing array is provided the matrix will be initialized to all zeros.
|
|
||||||
// // Allocate a zeroed matrix of size 3×5
|
|
||||||
// zero := mat64.NewDense(3, 5, nil)
|
|
||||||
// If a backing data slice is provided, the matrix will have those elements.
|
|
||||||
// Matrices are all stored in row-major format.
|
|
||||||
// // Generate a 6×6 matrix of random values.
|
|
||||||
// data := make([]float64, 36)
|
|
||||||
// for i := range data {
|
|
||||||
// data[i] = rand.NormFloat64()
|
|
||||||
// }
|
|
||||||
// a := mat64.NewDense(6, 6, data)
|
|
||||||
//
|
|
||||||
// Operations involving matrix data are implemented as functions when the values
|
|
||||||
// of the matrix remain unchanged
|
|
||||||
// tr := mat64.Trace(a)
|
|
||||||
// and are implemented as methods when the operation modifies the receiver.
|
|
||||||
// zero.Copy(a)
|
|
||||||
//
|
|
||||||
// Receivers must be the correct size for the matrix operations, otherwise the
|
|
||||||
// operation will panic. As a special case for convenience, a zero-sized matrix
|
|
||||||
// will be modified to have the correct size, allocating data if necessary.
|
|
||||||
// var c mat64.Dense // construct a new zero-sized matrix
|
|
||||||
// c.Mul(a, a) // c is automatically adjusted to be 6×6`,
|
|
||||||
|
|
||||||
BLAS: []string{"blas64"},
|
|
||||||
LAPACK: []string{"lapack64"},
|
|
||||||
|
|
||||||
template: `{{template "common" .}}
|
|
||||||
{{template "interfaces" .}}
|
|
||||||
{{template "factorization" .}}
|
|
||||||
{{template "blas" .}}
|
|
||||||
{{template "switching" .}}
|
|
||||||
{{template "invariants" .}}
|
|
||||||
{{template "aliasing" .}}
|
|
||||||
package {{.Name}} // import "gonum.org/v1/gonum/matrix/{{.Name}}"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "cmat128",
|
|
||||||
|
|
||||||
Name: "cmat128",
|
|
||||||
Provides: `implementations of complex128 matrix structures and
|
|
||||||
// linear algebra operations on them.`,
|
|
||||||
|
|
||||||
Overview: `// cmat128 provides:
|
|
||||||
// - Interfaces for a complex Matrix`,
|
|
||||||
|
|
||||||
BLAS: []string{"cblas128"},
|
|
||||||
LAPACK: []string{"clapack128"},
|
|
||||||
|
|
||||||
template: `{{template "common" . }}
|
|
||||||
{{template "blas" .}}
|
|
||||||
{{template "switching" .}}
|
|
||||||
{{template "invariants" .}}
|
|
||||||
{{template "aliasing" .}}
|
|
||||||
package {{.Name}} // import "gonum.org/v1/gonum/matrix/{{.Name}}"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var funcs = template.FuncMap{
|
|
||||||
"sentence": sentence,
|
|
||||||
"alts": alts,
|
|
||||||
"join": join,
|
|
||||||
}
|
|
||||||
|
|
||||||
// sentence converts a string to sentence case where the string is the prefix of the sentence.
|
|
||||||
func sentence(s string) string {
|
|
||||||
if len(s) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
_, size := utf8.DecodeRune([]byte(s))
|
|
||||||
return strings.ToUpper(s[:size]) + s[size:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// alts renders a []string as a glob alternatives list.
|
|
||||||
func alts(s []string) string {
|
|
||||||
switch len(s) {
|
|
||||||
case 0:
|
|
||||||
return ""
|
|
||||||
case 1:
|
|
||||||
return s[0]
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("{%s}", strings.Join(s, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// join is strings.Join with the parameter order changed.
|
|
||||||
func join(sep string, s []string) string {
|
|
||||||
return strings.Join(s, sep)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
for _, pkg := range pkgs {
|
|
||||||
t, err := template.Must(docs.Clone()).Parse(pkg.template)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to parse template: %v", err)
|
|
||||||
}
|
|
||||||
file := filepath.Join(pkg.path, "doc.go")
|
|
||||||
f, err := os.Create(file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to create %q: %v", file, err)
|
|
||||||
}
|
|
||||||
err = t.Execute(f, pkg)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to execute template: %v", err)
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
//go:generate go run gendoc.go
|
|
||||||
|
|
||||||
package matrix
|
|
@@ -7,7 +7,7 @@ package optimize
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BFGS implements the Broyden–Fletcher–Goldfarb–Shanno optimization method. It
|
// BFGS implements the Broyden–Fletcher–Goldfarb–Shanno optimization method. It
|
||||||
@@ -24,13 +24,13 @@ type BFGS struct {
|
|||||||
ls *LinesearchMethod
|
ls *LinesearchMethod
|
||||||
|
|
||||||
dim int
|
dim int
|
||||||
x mat64.Vector // Location of the last major iteration.
|
x mat.Vector // Location of the last major iteration.
|
||||||
grad mat64.Vector // Gradient at the last major iteration.
|
grad mat.Vector // Gradient at the last major iteration.
|
||||||
s mat64.Vector // Difference between locations in this and the previous iteration.
|
s mat.Vector // Difference between locations in this and the previous iteration.
|
||||||
y mat64.Vector // Difference between gradients in this and the previous iteration.
|
y mat.Vector // Difference between gradients in this and the previous iteration.
|
||||||
tmp mat64.Vector
|
tmp mat.Vector
|
||||||
|
|
||||||
invHess *mat64.SymDense
|
invHess *mat.SymDense
|
||||||
|
|
||||||
first bool // Indicator of the first iteration.
|
first bool // Indicator of the first iteration.
|
||||||
}
|
}
|
||||||
@@ -57,8 +57,8 @@ func (b *BFGS) InitDirection(loc *Location, dir []float64) (stepSize float64) {
|
|||||||
b.dim = dim
|
b.dim = dim
|
||||||
b.first = true
|
b.first = true
|
||||||
|
|
||||||
x := mat64.NewVector(dim, loc.X)
|
x := mat.NewVector(dim, loc.X)
|
||||||
grad := mat64.NewVector(dim, loc.Gradient)
|
grad := mat.NewVector(dim, loc.Gradient)
|
||||||
b.x.CloneVec(x)
|
b.x.CloneVec(x)
|
||||||
b.grad.CloneVec(grad)
|
b.grad.CloneVec(grad)
|
||||||
|
|
||||||
@@ -67,18 +67,18 @@ func (b *BFGS) InitDirection(loc *Location, dir []float64) (stepSize float64) {
|
|||||||
b.tmp.Reset()
|
b.tmp.Reset()
|
||||||
|
|
||||||
if b.invHess == nil || cap(b.invHess.RawSymmetric().Data) < dim*dim {
|
if b.invHess == nil || cap(b.invHess.RawSymmetric().Data) < dim*dim {
|
||||||
b.invHess = mat64.NewSymDense(dim, nil)
|
b.invHess = mat.NewSymDense(dim, nil)
|
||||||
} else {
|
} else {
|
||||||
b.invHess = mat64.NewSymDense(dim, b.invHess.RawSymmetric().Data[:dim*dim])
|
b.invHess = mat.NewSymDense(dim, b.invHess.RawSymmetric().Data[:dim*dim])
|
||||||
}
|
}
|
||||||
// The values of the inverse Hessian are initialized in the first call to
|
// The values of the inverse Hessian are initialized in the first call to
|
||||||
// NextDirection.
|
// NextDirection.
|
||||||
|
|
||||||
// Initial direction is just negative of the gradient because the Hessian
|
// Initial direction is just negative of the gradient because the Hessian
|
||||||
// is an identity matrix.
|
// is an identity matrix.
|
||||||
d := mat64.NewVector(dim, dir)
|
d := mat.NewVector(dim, dir)
|
||||||
d.ScaleVec(-1, grad)
|
d.ScaleVec(-1, grad)
|
||||||
return 1 / mat64.Norm(d, 2)
|
return 1 / mat.Norm(d, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
|
func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
|
||||||
@@ -93,21 +93,21 @@ func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
|
|||||||
panic("bfgs: unexpected size mismatch")
|
panic("bfgs: unexpected size mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
x := mat64.NewVector(dim, loc.X)
|
x := mat.NewVector(dim, loc.X)
|
||||||
grad := mat64.NewVector(dim, loc.Gradient)
|
grad := mat.NewVector(dim, loc.Gradient)
|
||||||
|
|
||||||
// s = x_{k+1} - x_{k}
|
// s = x_{k+1} - x_{k}
|
||||||
b.s.SubVec(x, &b.x)
|
b.s.SubVec(x, &b.x)
|
||||||
// y = g_{k+1} - g_{k}
|
// y = g_{k+1} - g_{k}
|
||||||
b.y.SubVec(grad, &b.grad)
|
b.y.SubVec(grad, &b.grad)
|
||||||
|
|
||||||
sDotY := mat64.Dot(&b.s, &b.y)
|
sDotY := mat.Dot(&b.s, &b.y)
|
||||||
|
|
||||||
if b.first {
|
if b.first {
|
||||||
// Rescale the initial Hessian.
|
// Rescale the initial Hessian.
|
||||||
// From: Nocedal, J., Wright, S.: Numerical Optimization (2nd ed).
|
// From: Nocedal, J., Wright, S.: Numerical Optimization (2nd ed).
|
||||||
// Springer (2006), page 143, eq. 6.20.
|
// Springer (2006), page 143, eq. 6.20.
|
||||||
yDotY := mat64.Dot(&b.y, &b.y)
|
yDotY := mat.Dot(&b.y, &b.y)
|
||||||
scale := sDotY / yDotY
|
scale := sDotY / yDotY
|
||||||
for i := 0; i < dim; i++ {
|
for i := 0; i < dim; i++ {
|
||||||
for j := i; j < dim; j++ {
|
for j := i; j < dim; j++ {
|
||||||
@@ -130,7 +130,7 @@ func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
|
|||||||
//
|
//
|
||||||
// Note that y_k^T B_k^-1 y_k is a scalar, and that the third term is a
|
// Note that y_k^T B_k^-1 y_k is a scalar, and that the third term is a
|
||||||
// rank-two update where B_k^-1 y_k is one vector and s_k is the other.
|
// rank-two update where B_k^-1 y_k is one vector and s_k is the other.
|
||||||
yBy := mat64.Inner(&b.y, b.invHess, &b.y)
|
yBy := mat.Inner(&b.y, b.invHess, &b.y)
|
||||||
b.tmp.MulVec(b.invHess, &b.y)
|
b.tmp.MulVec(b.invHess, &b.y)
|
||||||
scale := (1 + yBy/sDotY) / sDotY
|
scale := (1 + yBy/sDotY) / sDotY
|
||||||
b.invHess.SymRankOne(b.invHess, scale, &b.s)
|
b.invHess.SymRankOne(b.invHess, scale, &b.s)
|
||||||
@@ -142,7 +142,7 @@ func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
|
|||||||
b.grad.CopyVec(grad)
|
b.grad.CopyVec(grad)
|
||||||
|
|
||||||
// New direction is stored in dir.
|
// New direction is stored in dir.
|
||||||
d := mat64.NewVector(dim, dir)
|
d := mat.NewVector(dim, dir)
|
||||||
d.MulVec(b.invHess, grad)
|
d.MulVec(b.invHess, grad)
|
||||||
d.ScaleVec(-1, d)
|
d.ScaleVec(-1, d)
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ package lp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(btracey): Have some sort of preprocessing step for helping to fix A to make it
|
// TODO(btracey): Have some sort of preprocessing step for helping to fix A to make it
|
||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
// s.t aNew * x = bNew
|
// s.t aNew * x = bNew
|
||||||
// x >= 0
|
// x >= 0
|
||||||
// If there are no constraints of the given type, the inputs may be nil.
|
// If there are no constraints of the given type, the inputs may be nil.
|
||||||
func Convert(c []float64, g mat64.Matrix, h []float64, a mat64.Matrix, b []float64) (cNew []float64, aNew *mat64.Dense, bNew []float64) {
|
func Convert(c []float64, g mat.Matrix, h []float64, a mat.Matrix, b []float64) (cNew []float64, aNew *mat.Dense, bNew []float64) {
|
||||||
nVar := len(c)
|
nVar := len(c)
|
||||||
nIneq := len(h)
|
nIneq := len(h)
|
||||||
|
|
||||||
@@ -120,21 +120,21 @@ func Convert(c []float64, g mat64.Matrix, h []float64, a mat64.Matrix, b []float
|
|||||||
copy(bNew[nIneq:], b)
|
copy(bNew[nIneq:], b)
|
||||||
|
|
||||||
// Construct aNew = [G, -G, I; A, -A, 0].
|
// Construct aNew = [G, -G, I; A, -A, 0].
|
||||||
aNew = mat64.NewDense(nNewEq, nNewVar, nil)
|
aNew = mat.NewDense(nNewEq, nNewVar, nil)
|
||||||
if nIneq != 0 {
|
if nIneq != 0 {
|
||||||
aView := (aNew.View(0, 0, nIneq, nVar)).(*mat64.Dense)
|
aView := (aNew.View(0, 0, nIneq, nVar)).(*mat.Dense)
|
||||||
aView.Copy(g)
|
aView.Copy(g)
|
||||||
aView = (aNew.View(0, nVar, nIneq, nVar)).(*mat64.Dense)
|
aView = (aNew.View(0, nVar, nIneq, nVar)).(*mat.Dense)
|
||||||
aView.Scale(-1, g)
|
aView.Scale(-1, g)
|
||||||
aView = (aNew.View(0, 2*nVar, nIneq, nIneq)).(*mat64.Dense)
|
aView = (aNew.View(0, 2*nVar, nIneq, nIneq)).(*mat.Dense)
|
||||||
for i := 0; i < nIneq; i++ {
|
for i := 0; i < nIneq; i++ {
|
||||||
aView.Set(i, i, 1)
|
aView.Set(i, i, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nEq != 0 {
|
if nEq != 0 {
|
||||||
aView := (aNew.View(nIneq, 0, nEq, nVar)).(*mat64.Dense)
|
aView := (aNew.View(nIneq, 0, nEq, nVar)).(*mat.Dense)
|
||||||
aView.Copy(a)
|
aView.Copy(a)
|
||||||
aView = (aNew.View(nIneq, nVar, nEq, nVar)).(*mat64.Dense)
|
aView = (aNew.View(nIneq, nVar, nEq, nVar)).(*mat.Dense)
|
||||||
aView.Scale(-1, a)
|
aView.Scale(-1, a)
|
||||||
}
|
}
|
||||||
return cNew, aNew, bNew
|
return cNew, aNew, bNew
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(btracey): Could have a solver structure with an abstract factorizer. With
|
// TODO(btracey): Could have a solver structure with an abstract factorizer. With
|
||||||
@@ -85,12 +85,12 @@ const (
|
|||||||
// Strang, Gilbert. "Linear Algebra and Applications." Academic, New York (1976).
|
// Strang, Gilbert. "Linear Algebra and Applications." Academic, New York (1976).
|
||||||
// For a detailed video introduction, see lectures 11-13 of UC Math 352
|
// For a detailed video introduction, see lectures 11-13 of UC Math 352
|
||||||
// https://www.youtube.com/watch?v=ESzYPFkY3og&index=11&list=PLh464gFUoJWOmBYla3zbZbc4nv2AXez6X.
|
// https://www.youtube.com/watch?v=ESzYPFkY3og&index=11&list=PLh464gFUoJWOmBYla3zbZbc4nv2AXez6X.
|
||||||
func Simplex(c []float64, A mat64.Matrix, b []float64, tol float64, initialBasic []int) (optF float64, optX []float64, err error) {
|
func Simplex(c []float64, A mat.Matrix, b []float64, tol float64, initialBasic []int) (optF float64, optX []float64, err error) {
|
||||||
ans, x, _, err := simplex(initialBasic, c, A, b, tol)
|
ans, x, _, err := simplex(initialBasic, c, A, b, tol)
|
||||||
return ans, x, err
|
return ans, x, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol float64) (float64, []float64, []int, error) {
|
func simplex(initialBasic []int, c []float64, A mat.Matrix, b []float64, tol float64) (float64, []float64, []int, error) {
|
||||||
err := verifyInputs(initialBasic, c, A, b)
|
err := verifyInputs(initialBasic, c, A, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrUnbounded {
|
if err == ErrUnbounded {
|
||||||
@@ -123,7 +123,7 @@ func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol f
|
|||||||
// solution.
|
// solution.
|
||||||
|
|
||||||
var basicIdxs []int // The indices of the non-zero x values.
|
var basicIdxs []int // The indices of the non-zero x values.
|
||||||
var ab *mat64.Dense // The subset of columns of A listed in basicIdxs.
|
var ab *mat.Dense // The subset of columns of A listed in basicIdxs.
|
||||||
var xb []float64 // The non-zero elements of x. xb = ab^-1 b
|
var xb []float64 // The non-zero elements of x. xb = ab^-1 b
|
||||||
|
|
||||||
if initialBasic != nil {
|
if initialBasic != nil {
|
||||||
@@ -131,7 +131,7 @@ func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol f
|
|||||||
if len(initialBasic) != m {
|
if len(initialBasic) != m {
|
||||||
panic("lp: incorrect number of initial vectors")
|
panic("lp: incorrect number of initial vectors")
|
||||||
}
|
}
|
||||||
ab = mat64.NewDense(m, len(initialBasic), nil)
|
ab = mat.NewDense(m, len(initialBasic), nil)
|
||||||
extractColumns(ab, A, initialBasic)
|
extractColumns(ab, A, initialBasic)
|
||||||
xb = make([]float64, m)
|
xb = make([]float64, m)
|
||||||
err = initializeFromBasic(xb, ab, b)
|
err = initializeFromBasic(xb, ab, b)
|
||||||
@@ -175,11 +175,11 @@ func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol f
|
|||||||
for i, idx := range nonBasicIdx {
|
for i, idx := range nonBasicIdx {
|
||||||
cn[i] = c[idx]
|
cn[i] = c[idx]
|
||||||
}
|
}
|
||||||
an := mat64.NewDense(m, len(nonBasicIdx), nil)
|
an := mat.NewDense(m, len(nonBasicIdx), nil)
|
||||||
extractColumns(an, A, nonBasicIdx)
|
extractColumns(an, A, nonBasicIdx)
|
||||||
|
|
||||||
bVec := mat64.NewVector(len(b), b)
|
bVec := mat.NewVector(len(b), b)
|
||||||
cbVec := mat64.NewVector(len(cb), cb)
|
cbVec := mat.NewVector(len(cb), cb)
|
||||||
|
|
||||||
// Temporary data needed each iteration. (Described later)
|
// Temporary data needed each iteration. (Described later)
|
||||||
r := make([]float64, n-m)
|
r := make([]float64, n-m)
|
||||||
@@ -214,13 +214,13 @@ func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol f
|
|||||||
// of the rule in step 4 to avoid cycling.
|
// of the rule in step 4 to avoid cycling.
|
||||||
for {
|
for {
|
||||||
// Compute reduced costs -- r = cn - an^T ab^-T cb
|
// Compute reduced costs -- r = cn - an^T ab^-T cb
|
||||||
var tmp mat64.Vector
|
var tmp mat.Vector
|
||||||
err = tmp.SolveVec(ab.T(), cbVec)
|
err = tmp.SolveVec(ab.T(), cbVec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
data := make([]float64, n-m)
|
data := make([]float64, n-m)
|
||||||
tmp2 := mat64.NewVector(n-m, data)
|
tmp2 := mat.NewVector(n-m, data)
|
||||||
tmp2.MulVec(an.T(), &tmp)
|
tmp2.MulVec(an.T(), &tmp)
|
||||||
floats.SubTo(r, cn, data)
|
floats.SubTo(r, cn, data)
|
||||||
|
|
||||||
@@ -261,13 +261,13 @@ func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol f
|
|||||||
// Replace the constrained basicIdx with the newIdx.
|
// Replace the constrained basicIdx with the newIdx.
|
||||||
basicIdxs[replace], nonBasicIdx[minIdx] = nonBasicIdx[minIdx], basicIdxs[replace]
|
basicIdxs[replace], nonBasicIdx[minIdx] = nonBasicIdx[minIdx], basicIdxs[replace]
|
||||||
cb[replace], cn[minIdx] = cn[minIdx], cb[replace]
|
cb[replace], cn[minIdx] = cn[minIdx], cb[replace]
|
||||||
tmpCol1 := mat64.Col(nil, replace, ab)
|
tmpCol1 := mat.Col(nil, replace, ab)
|
||||||
tmpCol2 := mat64.Col(nil, minIdx, an)
|
tmpCol2 := mat.Col(nil, minIdx, an)
|
||||||
ab.SetCol(replace, tmpCol2)
|
ab.SetCol(replace, tmpCol2)
|
||||||
an.SetCol(minIdx, tmpCol1)
|
an.SetCol(minIdx, tmpCol1)
|
||||||
|
|
||||||
// Compute the new xb.
|
// Compute the new xb.
|
||||||
xbVec := mat64.NewVector(len(xb), xb)
|
xbVec := mat.NewVector(len(xb), xb)
|
||||||
err = xbVec.SolveVec(ab, bVec)
|
err = xbVec.SolveVec(ab, bVec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
@@ -285,15 +285,15 @@ func simplex(initialBasic []int, c []float64, A mat64.Matrix, b []float64, tol f
|
|||||||
|
|
||||||
// computeMove computes how far can be moved replacing each index. The results
|
// computeMove computes how far can be moved replacing each index. The results
|
||||||
// are stored into move.
|
// are stored into move.
|
||||||
func computeMove(move []float64, minIdx int, A mat64.Matrix, ab *mat64.Dense, xb []float64, nonBasicIdx []int) error {
|
func computeMove(move []float64, minIdx int, A mat.Matrix, ab *mat.Dense, xb []float64, nonBasicIdx []int) error {
|
||||||
// Find ae.
|
// Find ae.
|
||||||
col := mat64.Col(nil, nonBasicIdx[minIdx], A)
|
col := mat.Col(nil, nonBasicIdx[minIdx], A)
|
||||||
aCol := mat64.NewVector(len(col), col)
|
aCol := mat.NewVector(len(col), col)
|
||||||
|
|
||||||
// d = - Ab^-1 Ae
|
// d = - Ab^-1 Ae
|
||||||
nb, _ := ab.Dims()
|
nb, _ := ab.Dims()
|
||||||
d := make([]float64, nb)
|
d := make([]float64, nb)
|
||||||
dVec := mat64.NewVector(nb, d)
|
dVec := mat.NewVector(nb, d)
|
||||||
err := dVec.SolveVec(ab, aCol)
|
err := dVec.SolveVec(ab, aCol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrLinSolve
|
return ErrLinSolve
|
||||||
@@ -326,7 +326,7 @@ func computeMove(move []float64, minIdx int, A mat64.Matrix, ab *mat64.Dense, xb
|
|||||||
// replaceBland uses the Bland rule to find the indices to swap if the minimum
|
// replaceBland uses the Bland rule to find the indices to swap if the minimum
|
||||||
// move is 0. The indices to be swapped are replace and minIdx (following the
|
// move is 0. The indices to be swapped are replace and minIdx (following the
|
||||||
// nomenclature in the main routine).
|
// nomenclature in the main routine).
|
||||||
func replaceBland(A mat64.Matrix, ab *mat64.Dense, xb []float64, basicIdxs, nonBasicIdx []int, r, move []float64) (replace, minIdx int, err error) {
|
func replaceBland(A mat.Matrix, ab *mat.Dense, xb []float64, basicIdxs, nonBasicIdx []int, r, move []float64) (replace, minIdx int, err error) {
|
||||||
m, _ := A.Dims()
|
m, _ := A.Dims()
|
||||||
// Use the traditional bland rule, except don't replace a constraint which
|
// Use the traditional bland rule, except don't replace a constraint which
|
||||||
// causes the new ab to be singular.
|
// causes the new ab to be singular.
|
||||||
@@ -353,10 +353,10 @@ func replaceBland(A mat64.Matrix, ab *mat64.Dense, xb []float64, basicIdxs, nonB
|
|||||||
}
|
}
|
||||||
copy(biCopy, basicIdxs)
|
copy(biCopy, basicIdxs)
|
||||||
biCopy[replace] = nonBasicIdx[minIdx]
|
biCopy[replace] = nonBasicIdx[minIdx]
|
||||||
abTmp := mat64.NewDense(m, len(biCopy), nil)
|
abTmp := mat.NewDense(m, len(biCopy), nil)
|
||||||
extractColumns(abTmp, A, biCopy)
|
extractColumns(abTmp, A, biCopy)
|
||||||
// If the condition number is reasonable, use this index.
|
// If the condition number is reasonable, use this index.
|
||||||
if mat64.Cond(abTmp, 1) < 1e16 {
|
if mat.Cond(abTmp, 1) < 1e16 {
|
||||||
return replace, minIdx, nil
|
return replace, minIdx, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,7 +364,7 @@ func replaceBland(A mat64.Matrix, ab *mat64.Dense, xb []float64, basicIdxs, nonB
|
|||||||
return -1, -1, ErrBland
|
return -1, -1, ErrBland
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyInputs(initialBasic []int, c []float64, A mat64.Matrix, b []float64) error {
|
func verifyInputs(initialBasic []int, c []float64, A mat.Matrix, b []float64) error {
|
||||||
m, n := A.Dims()
|
m, n := A.Dims()
|
||||||
if len(c) != n {
|
if len(c) != n {
|
||||||
panic("lp: c vector incorrect length")
|
panic("lp: c vector incorrect length")
|
||||||
@@ -426,14 +426,14 @@ func verifyInputs(initialBasic []int, c []float64, A mat64.Matrix, b []float64)
|
|||||||
//
|
//
|
||||||
// If the columns of A are not linearly independent or if the initial set is not
|
// If the columns of A are not linearly independent or if the initial set is not
|
||||||
// feasible, an error is returned.
|
// feasible, an error is returned.
|
||||||
func initializeFromBasic(xb []float64, ab *mat64.Dense, b []float64) error {
|
func initializeFromBasic(xb []float64, ab *mat.Dense, b []float64) error {
|
||||||
m, _ := ab.Dims()
|
m, _ := ab.Dims()
|
||||||
if len(xb) != m {
|
if len(xb) != m {
|
||||||
panic("simplex: bad xb length")
|
panic("simplex: bad xb length")
|
||||||
}
|
}
|
||||||
xbMat := mat64.NewVector(m, xb)
|
xbMat := mat.NewVector(m, xb)
|
||||||
|
|
||||||
err := xbMat.SolveVec(ab, mat64.NewVector(m, b))
|
err := xbMat.SolveVec(ab, mat.NewVector(m, b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("lp: subcolumns of A for supplied initial basic singular")
|
return errors.New("lp: subcolumns of A for supplied initial basic singular")
|
||||||
}
|
}
|
||||||
@@ -453,7 +453,7 @@ func initializeFromBasic(xb []float64, ab *mat64.Dense, b []float64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extractColumns copies the columns specified by cols into the columns of dst.
|
// extractColumns copies the columns specified by cols into the columns of dst.
|
||||||
func extractColumns(dst *mat64.Dense, A mat64.Matrix, cols []int) {
|
func extractColumns(dst *mat.Dense, A mat.Matrix, cols []int) {
|
||||||
r, c := dst.Dims()
|
r, c := dst.Dims()
|
||||||
ra, _ := A.Dims()
|
ra, _ := A.Dims()
|
||||||
if ra != r {
|
if ra != r {
|
||||||
@@ -464,14 +464,14 @@ func extractColumns(dst *mat64.Dense, A mat64.Matrix, cols []int) {
|
|||||||
}
|
}
|
||||||
col := make([]float64, r)
|
col := make([]float64, r)
|
||||||
for j, idx := range cols {
|
for j, idx := range cols {
|
||||||
mat64.Col(col, idx, A)
|
mat.Col(col, idx, A)
|
||||||
dst.SetCol(j, col)
|
dst.SetCol(j, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// findInitialBasic finds an initial basic solution, and returns the basic
|
// findInitialBasic finds an initial basic solution, and returns the basic
|
||||||
// indices, ab, and xb.
|
// indices, ab, and xb.
|
||||||
func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float64, error) {
|
func findInitialBasic(A mat.Matrix, b []float64) ([]int, *mat.Dense, []float64, error) {
|
||||||
m, n := A.Dims()
|
m, n := A.Dims()
|
||||||
basicIdxs := findLinearlyIndependent(A)
|
basicIdxs := findLinearlyIndependent(A)
|
||||||
if len(basicIdxs) != m {
|
if len(basicIdxs) != m {
|
||||||
@@ -480,7 +480,7 @@ func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float
|
|||||||
|
|
||||||
// It may be that this linearly independent basis is also a feasible set. If
|
// It may be that this linearly independent basis is also a feasible set. If
|
||||||
// so, the Phase I problem can be avoided.
|
// so, the Phase I problem can be avoided.
|
||||||
ab := mat64.NewDense(m, len(basicIdxs), nil)
|
ab := mat.NewDense(m, len(basicIdxs), nil)
|
||||||
extractColumns(ab, A, basicIdxs)
|
extractColumns(ab, A, basicIdxs)
|
||||||
xb := make([]float64, m)
|
xb := make([]float64, m)
|
||||||
err := initializeFromBasic(xb, ab, b)
|
err := initializeFromBasic(xb, ab, b)
|
||||||
@@ -519,7 +519,7 @@ func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float
|
|||||||
if i == minIdx {
|
if i == minIdx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mat64.Col(col, v, A)
|
mat.Col(col, v, A)
|
||||||
floats.Sub(aX1, col)
|
floats.Sub(aX1, col)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +527,7 @@ func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float
|
|||||||
// aNew = [A, a_{n+1}]
|
// aNew = [A, a_{n+1}]
|
||||||
// bNew = b
|
// bNew = b
|
||||||
// cNew = 1 for x_{n+1}
|
// cNew = 1 for x_{n+1}
|
||||||
aNew := mat64.NewDense(m, n+1, nil)
|
aNew := mat.NewDense(m, n+1, nil)
|
||||||
aNew.Copy(A)
|
aNew.Copy(A)
|
||||||
aNew.SetCol(n, aX1)
|
aNew.SetCol(n, aX1)
|
||||||
basicIdxs[minIdx] = n // swap minIdx with n in the basic set.
|
basicIdxs[minIdx] = n // swap minIdx with n in the basic set.
|
||||||
@@ -574,7 +574,7 @@ func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float
|
|||||||
}
|
}
|
||||||
newBasic[addedIdx] = i
|
newBasic[addedIdx] = i
|
||||||
if set {
|
if set {
|
||||||
mat64.Col(col, i, A)
|
mat.Col(col, i, A)
|
||||||
ab.SetCol(addedIdx, col)
|
ab.SetCol(addedIdx, col)
|
||||||
} else {
|
} else {
|
||||||
extractColumns(ab, A, newBasic)
|
extractColumns(ab, A, newBasic)
|
||||||
@@ -590,10 +590,10 @@ func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float
|
|||||||
|
|
||||||
// findLinearlyIndependnt finds a set of linearly independent columns of A, and
|
// findLinearlyIndependnt finds a set of linearly independent columns of A, and
|
||||||
// returns the column indexes of the linearly independent columns.
|
// returns the column indexes of the linearly independent columns.
|
||||||
func findLinearlyIndependent(A mat64.Matrix) []int {
|
func findLinearlyIndependent(A mat.Matrix) []int {
|
||||||
m, n := A.Dims()
|
m, n := A.Dims()
|
||||||
idxs := make([]int, 0, m)
|
idxs := make([]int, 0, m)
|
||||||
columns := mat64.NewDense(m, m, nil)
|
columns := mat.NewDense(m, m, nil)
|
||||||
newCol := make([]float64, m)
|
newCol := make([]float64, m)
|
||||||
// Walk in reverse order because slack variables are typically the last columns
|
// Walk in reverse order because slack variables are typically the last columns
|
||||||
// of A.
|
// of A.
|
||||||
@@ -601,7 +601,7 @@ func findLinearlyIndependent(A mat64.Matrix) []int {
|
|||||||
if len(idxs) == m {
|
if len(idxs) == m {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
mat64.Col(newCol, i, A)
|
mat.Col(newCol, i, A)
|
||||||
columns.SetCol(len(idxs), newCol)
|
columns.SetCol(len(idxs), newCol)
|
||||||
if len(idxs) == 0 {
|
if len(idxs) == 0 {
|
||||||
// A column is linearly independent from the null set.
|
// A column is linearly independent from the null set.
|
||||||
@@ -609,7 +609,7 @@ func findLinearlyIndependent(A mat64.Matrix) []int {
|
|||||||
idxs = append(idxs, i)
|
idxs = append(idxs, i)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if mat64.Cond(columns.View(0, 0, m, len(idxs)+1), 1) > 1e12 {
|
if mat.Cond(columns.View(0, 0, m, len(idxs)+1), 1) > 1e12 {
|
||||||
// Not linearly independent.
|
// Not linearly independent.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -8,13 +8,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/optimize/convex/lp"
|
"gonum.org/v1/gonum/optimize/convex/lp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleSimplex() {
|
func ExampleSimplex() {
|
||||||
c := []float64{-1, -2, 0, 0}
|
c := []float64{-1, -2, 0, 0}
|
||||||
A := mat64.NewDense(2, 4, []float64{-1, 2, 1, 0, 3, 1, 0, 1})
|
A := mat.NewDense(2, 4, []float64{-1, 2, 1, 0, 3, 1, 0, 1})
|
||||||
b := []float64{4, 9}
|
b := []float64{4, 9}
|
||||||
|
|
||||||
opt, x, err := lp.Simplex(c, A, b, 0, nil)
|
opt, x, err := lp.Simplex(c, A, b, 0, nil)
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Beale implements the Beale's function.
|
// Beale implements the Beale's function.
|
||||||
@@ -56,7 +56,7 @@ func (Beale) Grad(grad, x []float64) {
|
|||||||
grad[1] = 2 * x[0] * (f1 + 2*f2*x[1] + 3*f3*x[1]*x[1])
|
grad[1] = 2 * x[0] * (f1 + 2*f2*x[1] + 3*f3*x[1]*x[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Beale) Hess(hess mat64.MutableSymmetric, x []float64) {
|
func (Beale) Hess(hess mat.MutableSymmetric, x []float64) {
|
||||||
if len(x) != 2 {
|
if len(x) != 2 {
|
||||||
panic("dimension of the problem must be 2")
|
panic("dimension of the problem must be 2")
|
||||||
}
|
}
|
||||||
@@ -558,7 +558,7 @@ func (BrownBadlyScaled) Grad(grad, x []float64) {
|
|||||||
grad[1] = 2*f2 + 2*f3*x[0]
|
grad[1] = 2*f2 + 2*f3*x[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (BrownBadlyScaled) Hess(hess mat64.MutableSymmetric, x []float64) {
|
func (BrownBadlyScaled) Hess(hess mat.MutableSymmetric, x []float64) {
|
||||||
if len(x) != 2 {
|
if len(x) != 2 {
|
||||||
panic("dimension of the problem must be 2")
|
panic("dimension of the problem must be 2")
|
||||||
}
|
}
|
||||||
@@ -635,7 +635,7 @@ func (BrownAndDennis) Grad(grad, x []float64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (BrownAndDennis) Hess(hess mat64.MutableSymmetric, x []float64) {
|
func (BrownAndDennis) Hess(hess mat.MutableSymmetric, x []float64) {
|
||||||
if len(x) != 4 {
|
if len(x) != 4 {
|
||||||
panic("dimension of the problem must be 4")
|
panic("dimension of the problem must be 4")
|
||||||
}
|
}
|
||||||
@@ -1268,7 +1268,7 @@ func (PowellBadlyScaled) Grad(grad, x []float64) {
|
|||||||
grad[1] = 2 * (1e4*f1*x[0] - f2*math.Exp(-x[1]))
|
grad[1] = 2 * (1e4*f1*x[0] - f2*math.Exp(-x[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (PowellBadlyScaled) Hess(hess mat64.MutableSymmetric, x []float64) {
|
func (PowellBadlyScaled) Hess(hess mat.MutableSymmetric, x []float64) {
|
||||||
if len(x) != 2 {
|
if len(x) != 2 {
|
||||||
panic("dimension of the problem must be 2")
|
panic("dimension of the problem must be 2")
|
||||||
}
|
}
|
||||||
@@ -1518,7 +1518,7 @@ func (Watson) Grad(grad, x []float64) {
|
|||||||
grad[1] += 2 * t
|
grad[1] += 2 * t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Watson) Hess(hess mat64.MutableSymmetric, x []float64) {
|
func (Watson) Hess(hess mat.MutableSymmetric, x []float64) {
|
||||||
dim := len(x)
|
dim := len(x)
|
||||||
if dim != hess.Symmetric() {
|
if dim != hess.Symmetric() {
|
||||||
panic("incorrect size of the Hessian")
|
panic("incorrect size of the Hessian")
|
||||||
@@ -1638,7 +1638,7 @@ func (Wood) Grad(grad, x []float64) {
|
|||||||
grad[3] = 2 * (90*f3 + 10*f5 - 0.1*f6)
|
grad[3] = 2 * (90*f3 + 10*f5 - 0.1*f6)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Wood) Hess(hess mat64.MutableSymmetric, x []float64) {
|
func (Wood) Hess(hess mat.MutableSymmetric, x []float64) {
|
||||||
if len(x) != 4 {
|
if len(x) != 4 {
|
||||||
panic("dimension of the problem must be 4")
|
panic("dimension of the problem must be 4")
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ package optimize
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/optimize/functions"
|
"gonum.org/v1/gonum/optimize/functions"
|
||||||
"gonum.org/v1/gonum/stat/distmv"
|
"gonum.org/v1/gonum/stat/distmv"
|
||||||
)
|
)
|
||||||
@@ -18,7 +18,7 @@ func TestGuessAndCheck(t *testing.T) {
|
|||||||
Func: functions.ExtendedRosenbrock{}.Func,
|
Func: functions.ExtendedRosenbrock{}.Func,
|
||||||
}
|
}
|
||||||
mu := make([]float64, dim)
|
mu := make([]float64, dim)
|
||||||
sigma := mat64.NewSymDense(dim, nil)
|
sigma := mat.NewSymDense(dim, nil)
|
||||||
for i := 0; i < dim; i++ {
|
for i := 0; i < dim; i++ {
|
||||||
sigma.SetSym(i, i, 1)
|
sigma.SetSym(i, i, 1)
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newLocation allocates a new locatian structure of the appropriate size. It
|
// newLocation allocates a new locatian structure of the appropriate size. It
|
||||||
@@ -26,7 +26,7 @@ func newLocation(dim int, method Needser) *Location {
|
|||||||
loc.Gradient = make([]float64, dim)
|
loc.Gradient = make([]float64, dim)
|
||||||
}
|
}
|
||||||
if method.Needs().Hessian {
|
if method.Needs().Hessian {
|
||||||
loc.Hessian = mat64.NewSymDense(dim, nil)
|
loc.Hessian = mat.NewSymDense(dim, nil)
|
||||||
}
|
}
|
||||||
return loc
|
return loc
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ func copyLocation(dst, src *Location) {
|
|||||||
|
|
||||||
if src.Hessian != nil {
|
if src.Hessian != nil {
|
||||||
if dst.Hessian == nil || dst.Hessian.Symmetric() != len(src.X) {
|
if dst.Hessian == nil || dst.Hessian.Symmetric() != len(src.X) {
|
||||||
dst.Hessian = mat64.NewSymDense(len(src.X), nil)
|
dst.Hessian = mat.NewSymDense(len(src.X), nil)
|
||||||
}
|
}
|
||||||
dst.Hessian.CopySym(src.Hessian)
|
dst.Hessian.CopySym(src.Hessian)
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ package optimize
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxNewtonModifications = 20
|
const maxNewtonModifications = 20
|
||||||
@@ -48,8 +48,8 @@ type Newton struct {
|
|||||||
|
|
||||||
ls *LinesearchMethod
|
ls *LinesearchMethod
|
||||||
|
|
||||||
hess *mat64.SymDense // Storage for a copy of the Hessian matrix.
|
hess *mat.SymDense // Storage for a copy of the Hessian matrix.
|
||||||
chol mat64.Cholesky // Storage for the Cholesky factorization.
|
chol mat.Cholesky // Storage for the Cholesky factorization.
|
||||||
tau float64
|
tau float64
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,8 +88,8 @@ func (n *Newton) NextDirection(loc *Location, dir []float64) (stepSize float64)
|
|||||||
// the Identity) from Nocedal, Wright (2006), 2nd edition.
|
// the Identity) from Nocedal, Wright (2006), 2nd edition.
|
||||||
|
|
||||||
dim := len(loc.X)
|
dim := len(loc.X)
|
||||||
d := mat64.NewVector(dim, dir)
|
d := mat.NewVector(dim, dir)
|
||||||
grad := mat64.NewVector(dim, loc.Gradient)
|
grad := mat.NewVector(dim, loc.Gradient)
|
||||||
n.hess.CopySym(loc.Hessian)
|
n.hess.CopySym(loc.Hessian)
|
||||||
|
|
||||||
// Find the smallest diagonal entry of the Hessian.
|
// Find the smallest diagonal entry of the Hessian.
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultGradientAbsTol = 1e-6
|
const defaultGradientAbsTol = 1e-6
|
||||||
@@ -83,7 +83,7 @@ type Location struct {
|
|||||||
X []float64
|
X []float64
|
||||||
F float64
|
F float64
|
||||||
Gradient []float64
|
Gradient []float64
|
||||||
Hessian *mat64.SymDense
|
Hessian *mat.SymDense
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result represents the answer of an optimization run. It contains the optimum
|
// Result represents the answer of an optimization run. It contains the optimum
|
||||||
@@ -131,7 +131,7 @@ type Problem struct {
|
|||||||
|
|
||||||
// Hess evaluates the Hessian at x and stores the result in-place in hess.
|
// Hess evaluates the Hessian at x and stores the result in-place in hess.
|
||||||
// Hess must not modify x.
|
// Hess must not modify x.
|
||||||
Hess func(hess mat64.MutableSymmetric, x []float64)
|
Hess func(hess mat.MutableSymmetric, x []float64)
|
||||||
|
|
||||||
// Status reports the status of the objective function being optimized and any
|
// Status reports the status of the objective function being optimized and any
|
||||||
// error. This can be used to terminate early, for example when the function is
|
// error. This can be used to terminate early, for example when the function is
|
||||||
@@ -164,7 +164,7 @@ type Settings struct {
|
|||||||
UseInitialData bool // Use supplied information about the conditions at the initial x.
|
UseInitialData bool // Use supplied information about the conditions at the initial x.
|
||||||
InitialValue float64 // Function value at the initial x.
|
InitialValue float64 // Function value at the initial x.
|
||||||
InitialGradient []float64 // Gradient at the initial x.
|
InitialGradient []float64 // Gradient at the initial x.
|
||||||
InitialHessian *mat64.SymDense // Hessian at the initial x.
|
InitialHessian *mat.SymDense // Hessian at the initial x.
|
||||||
|
|
||||||
// FunctionThreshold is the threshold for acceptably small values of the
|
// FunctionThreshold is the threshold for acceptably small values of the
|
||||||
// objective function. FunctionThreshold status is returned if
|
// objective function. FunctionThreshold status is returned if
|
||||||
@@ -254,9 +254,9 @@ func resize(x []float64, dim int) []float64 {
|
|||||||
return x[:dim]
|
return x[:dim]
|
||||||
}
|
}
|
||||||
|
|
||||||
func resizeSymDense(m *mat64.SymDense, dim int) *mat64.SymDense {
|
func resizeSymDense(m *mat.SymDense, dim int) *mat.SymDense {
|
||||||
if m == nil || cap(m.RawSymmetric().Data) < dim*dim {
|
if m == nil || cap(m.RawSymmetric().Data) < dim*dim {
|
||||||
return mat64.NewSymDense(dim, nil)
|
return mat.NewSymDense(dim, nil)
|
||||||
}
|
}
|
||||||
return mat64.NewSymDense(dim, m.RawSymmetric().Data[:dim*dim])
|
return mat.NewSymDense(dim, m.RawSymmetric().Data[:dim*dim])
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/optimize/functions"
|
"gonum.org/v1/gonum/optimize/functions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1237,7 +1237,7 @@ func testLocal(t *testing.T, tests []unconstrainedTest, method Method) {
|
|||||||
test.p.Grad(settings.InitialGradient, test.x)
|
test.p.Grad(settings.InitialGradient, test.x)
|
||||||
}
|
}
|
||||||
if method.Needs().Hessian {
|
if method.Needs().Hessian {
|
||||||
settings.InitialHessian = mat64.NewSymDense(len(test.x), nil)
|
settings.InitialHessian = mat.NewSymDense(len(test.x), nil)
|
||||||
test.p.Hess(settings.InitialHessian, test.x)
|
test.p.Hess(settings.InitialHessian, test.x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
package stat_test
|
package stat_test
|
||||||
|
|
||||||
import "gonum.org/v1/gonum/matrix/mat64"
|
import "gonum.org/v1/gonum/mat"
|
||||||
|
|
||||||
// Boston Housing Data of Harrison and Rubinfeld (1978)
|
// Boston Housing Data of Harrison and Rubinfeld (1978)
|
||||||
// http://dx.doi.org/10.1016/0095-0696(78)90006-2
|
// http://dx.doi.org/10.1016/0095-0696(78)90006-2
|
||||||
@@ -21,7 +21,7 @@ import "gonum.org/v1/gonum/matrix/mat64"
|
|||||||
// proportion of owner-occupied units built prior to 1940,
|
// proportion of owner-occupied units built prior to 1940,
|
||||||
// full-value property-tax rate per $10000,
|
// full-value property-tax rate per $10000,
|
||||||
// median value of owner-occupied homes in $1000s.
|
// median value of owner-occupied homes in $1000s.
|
||||||
var bostonData = mat64.NewDense(506, 11, []float64{
|
var bostonData = mat.NewDense(506, 11, []float64{
|
||||||
0.00632, 2.31000, 0.53800, 4.09000, 1.00000, 15.30000, 396.90000, 6.57500, 65.20000, 296.00000, 24.00000,
|
0.00632, 2.31000, 0.53800, 4.09000, 1.00000, 15.30000, 396.90000, 6.57500, 65.20000, 296.00000, 24.00000,
|
||||||
0.02731, 7.07000, 0.46900, 4.96710, 2.00000, 17.80000, 396.90000, 6.42100, 78.90000, 242.00000, 21.60000,
|
0.02731, 7.07000, 0.46900, 4.96710, 2.00000, 17.80000, 396.90000, 6.42100, 78.90000, 242.00000, 21.60000,
|
||||||
0.02729, 7.07000, 0.46900, 4.96710, 2.00000, 17.80000, 392.83000, 7.18500, 61.10000, 242.00000, 34.70000,
|
0.02729, 7.07000, 0.46900, 4.96710, 2.00000, 17.80000, 392.83000, 7.18500, 61.10000, 242.00000, 34.70000,
|
||||||
|
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
package stat_test
|
package stat_test
|
||||||
|
|
||||||
import "gonum.org/v1/gonum/matrix/mat64"
|
import "gonum.org/v1/gonum/mat"
|
||||||
|
|
||||||
// ASA Car Exposition Data of Ramos and Donoho (1983)
|
// ASA Car Exposition Data of Ramos and Donoho (1983)
|
||||||
// http://lib.stat.cmu.edu/datasets/cars.desc
|
// http://lib.stat.cmu.edu/datasets/cars.desc
|
||||||
// http://lib.stat.cmu.edu/datasets/cars.data
|
// http://lib.stat.cmu.edu/datasets/cars.data
|
||||||
// Columns are: displacement, horsepower, weight, acceleration, MPG.
|
// Columns are: displacement, horsepower, weight, acceleration, MPG.
|
||||||
var carData = mat64.NewDense(392, 5, []float64{
|
var carData = mat.NewDense(392, 5, []float64{
|
||||||
307.0, 130.0, 3504.0, 12.0, 18.0,
|
307.0, 130.0, 3504.0, 12.0, 18.0,
|
||||||
350.0, 165.0, 3693.0, 11.5, 15.0,
|
350.0, 165.0, 3693.0, 11.5, 15.0,
|
||||||
318.0, 150.0, 3436.0, 11.0, 18.0,
|
318.0, 150.0, 3436.0, 11.0, 18.0,
|
||||||
|
@@ -9,13 +9,13 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// symView is a helper for getting a View of a SymDense.
|
// symView is a helper for getting a View of a SymDense.
|
||||||
type symView struct {
|
type symView struct {
|
||||||
sym *mat64.SymDense
|
sym *mat.SymDense
|
||||||
|
|
||||||
i, j, r, c int
|
i, j, r, c int
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ func (s symView) At(i, j int) float64 {
|
|||||||
return s.sym.At(s.i+i, s.j+j)
|
return s.sym.At(s.i+i, s.j+j)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s symView) T() mat64.Matrix { return mat64.Transpose{s} }
|
func (s symView) T() mat.Matrix { return mat.Transpose{s} }
|
||||||
|
|
||||||
func ExampleCC() {
|
func ExampleCC() {
|
||||||
// This example is directly analogous to Example 3.5 on page 87 of
|
// This example is directly analogous to Example 3.5 on page 87 of
|
||||||
@@ -65,7 +65,7 @@ func ExampleCC() {
|
|||||||
ydata := bostonData.Slice(0, n, xd, xd+yd)
|
ydata := bostonData.Slice(0, n, xd, xd+yd)
|
||||||
|
|
||||||
// For comparison, calculate the correlation matrix for the original data.
|
// For comparison, calculate the correlation matrix for the original data.
|
||||||
var cor mat64.SymDense
|
var cor mat.SymDense
|
||||||
stat.CorrelationMatrix(&cor, bostonData, nil)
|
stat.CorrelationMatrix(&cor, bostonData, nil)
|
||||||
|
|
||||||
// Extract just those correlations that are between xdata and ydata.
|
// Extract just those correlations that are between xdata and ydata.
|
||||||
@@ -75,7 +75,7 @@ func ExampleCC() {
|
|||||||
// between the 5th variable of xdata (index of accessibility to radial
|
// between the 5th variable of xdata (index of accessibility to radial
|
||||||
// highways) and the 3rd variable of ydata (full-value property-tax rate per
|
// highways) and the 3rd variable of ydata (full-value property-tax rate per
|
||||||
// $10000).
|
// $10000).
|
||||||
fmt.Printf("corRaw = %.4f", mat64.Formatted(corRaw, mat64.Prefix(" ")))
|
fmt.Printf("corRaw = %.4f", mat.Formatted(corRaw, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Calculate the canonical correlations.
|
// Calculate the canonical correlations.
|
||||||
var cc stat.CC
|
var cc stat.CC
|
||||||
@@ -93,16 +93,16 @@ func ExampleCC() {
|
|||||||
|
|
||||||
// Canonical Correlation Matrix, or the correlations between the sphered
|
// Canonical Correlation Matrix, or the correlations between the sphered
|
||||||
// data.
|
// data.
|
||||||
var corSph mat64.Dense
|
var corSph mat.Dense
|
||||||
corSph.Clone(pVecs)
|
corSph.Clone(pVecs)
|
||||||
col := make([]float64, xd)
|
col := make([]float64, xd)
|
||||||
for j := 0; j < yd; j++ {
|
for j := 0; j < yd; j++ {
|
||||||
mat64.Col(col, j, &corSph)
|
mat.Col(col, j, &corSph)
|
||||||
floats.Scale(ccors[j], col)
|
floats.Scale(ccors[j], col)
|
||||||
corSph.SetCol(j, col)
|
corSph.SetCol(j, col)
|
||||||
}
|
}
|
||||||
corSph.Product(&corSph, qVecs.T())
|
corSph.Product(&corSph, qVecs.T())
|
||||||
fmt.Printf("\n\ncorSph = %.4f", mat64.Formatted(&corSph, mat64.Prefix(" ")))
|
fmt.Printf("\n\ncorSph = %.4f", mat.Formatted(&corSph, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Canonical Correlations. Note that the first canonical correlation is
|
// Canonical Correlations. Note that the first canonical correlation is
|
||||||
// 0.95, stronger than the greatest correlation in the original data, and
|
// 0.95, stronger than the greatest correlation in the original data, and
|
||||||
@@ -110,13 +110,13 @@ func ExampleCC() {
|
|||||||
fmt.Printf("\n\nccors = %.4f", ccors)
|
fmt.Printf("\n\nccors = %.4f", ccors)
|
||||||
|
|
||||||
// Left and right eigenvectors of the canonical correlation matrix.
|
// Left and right eigenvectors of the canonical correlation matrix.
|
||||||
fmt.Printf("\n\npVecs = %.4f", mat64.Formatted(pVecs, mat64.Prefix(" ")))
|
fmt.Printf("\n\npVecs = %.4f", mat.Formatted(pVecs, mat.Prefix(" ")))
|
||||||
fmt.Printf("\n\nqVecs = %.4f", mat64.Formatted(qVecs, mat64.Prefix(" ")))
|
fmt.Printf("\n\nqVecs = %.4f", mat.Formatted(qVecs, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Canonical Correlation Transforms. These can be useful as they represent
|
// Canonical Correlation Transforms. These can be useful as they represent
|
||||||
// the canonical variables as linear combinations of the original variables.
|
// the canonical variables as linear combinations of the original variables.
|
||||||
fmt.Printf("\n\nphiVs = %.4f", mat64.Formatted(phiVs, mat64.Prefix(" ")))
|
fmt.Printf("\n\nphiVs = %.4f", mat.Formatted(phiVs, mat.Prefix(" ")))
|
||||||
fmt.Printf("\n\npsiVs = %.4f", mat64.Formatted(psiVs, mat64.Prefix(" ")))
|
fmt.Printf("\n\npsiVs = %.4f", mat.Formatted(psiVs, mat.Prefix(" ")))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// corRaw = ⎡-0.2192 0.3527 0.5828 -0.3883⎤
|
// corRaw = ⎡-0.2192 0.3527 0.5828 -0.3883⎤
|
||||||
|
@@ -8,26 +8,26 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCanonicalCorrelations(t *testing.T) {
|
func TestCanonicalCorrelations(t *testing.T) {
|
||||||
tests:
|
tests:
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
xdata mat64.Matrix
|
xdata mat.Matrix
|
||||||
ydata mat64.Matrix
|
ydata mat.Matrix
|
||||||
weights []float64
|
weights []float64
|
||||||
wantCorrs []float64
|
wantCorrs []float64
|
||||||
wantpVecs *mat64.Dense
|
wantpVecs *mat.Dense
|
||||||
wantqVecs *mat64.Dense
|
wantqVecs *mat.Dense
|
||||||
wantphiVs *mat64.Dense
|
wantphiVs *mat.Dense
|
||||||
wantpsiVs *mat64.Dense
|
wantpsiVs *mat.Dense
|
||||||
epsilon float64
|
epsilon float64
|
||||||
}{
|
}{
|
||||||
// Test results verified using R.
|
// Test results verified using R.
|
||||||
{ // Truncated iris data, Sepal vs Petal measurements.
|
{ // Truncated iris data, Sepal vs Petal measurements.
|
||||||
xdata: mat64.NewDense(10, 2, []float64{
|
xdata: mat.NewDense(10, 2, []float64{
|
||||||
5.1, 3.5,
|
5.1, 3.5,
|
||||||
4.9, 3.0,
|
4.9, 3.0,
|
||||||
4.7, 3.2,
|
4.7, 3.2,
|
||||||
@@ -39,7 +39,7 @@ tests:
|
|||||||
4.4, 2.9,
|
4.4, 2.9,
|
||||||
4.9, 3.1,
|
4.9, 3.1,
|
||||||
}),
|
}),
|
||||||
ydata: mat64.NewDense(10, 2, []float64{
|
ydata: mat.NewDense(10, 2, []float64{
|
||||||
1.4, 0.2,
|
1.4, 0.2,
|
||||||
1.4, 0.2,
|
1.4, 0.2,
|
||||||
1.3, 0.2,
|
1.3, 0.2,
|
||||||
@@ -52,19 +52,19 @@ tests:
|
|||||||
1.5, 0.1,
|
1.5, 0.1,
|
||||||
}),
|
}),
|
||||||
wantCorrs: []float64{0.7250624174504773, 0.5547679185730191},
|
wantCorrs: []float64{0.7250624174504773, 0.5547679185730191},
|
||||||
wantpVecs: mat64.NewDense(2, 2, []float64{
|
wantpVecs: mat.NewDense(2, 2, []float64{
|
||||||
0.0765914610875867, 0.9970625597666721,
|
0.0765914610875867, 0.9970625597666721,
|
||||||
0.9970625597666721, -0.0765914610875868,
|
0.9970625597666721, -0.0765914610875868,
|
||||||
}),
|
}),
|
||||||
wantqVecs: mat64.NewDense(2, 2, []float64{
|
wantqVecs: mat.NewDense(2, 2, []float64{
|
||||||
0.3075184850910837, 0.9515421069649439,
|
0.3075184850910837, 0.9515421069649439,
|
||||||
0.9515421069649439, -0.3075184850910837,
|
0.9515421069649439, -0.3075184850910837,
|
||||||
}),
|
}),
|
||||||
wantphiVs: mat64.NewDense(2, 2, []float64{
|
wantphiVs: mat.NewDense(2, 2, []float64{
|
||||||
-1.9794877596804641, 5.2016325219025124,
|
-1.9794877596804641, 5.2016325219025124,
|
||||||
4.5211829944066553, -2.7263663170835697,
|
4.5211829944066553, -2.7263663170835697,
|
||||||
}),
|
}),
|
||||||
wantpsiVs: mat64.NewDense(2, 2, []float64{
|
wantpsiVs: mat.NewDense(2, 2, []float64{
|
||||||
-0.0613084818030103, 10.8514169865438941,
|
-0.0613084818030103, 10.8514169865438941,
|
||||||
12.7209032660734298, -7.6793888180353775,
|
12.7209032660734298, -7.6793888180353775,
|
||||||
}),
|
}),
|
||||||
@@ -79,21 +79,21 @@ tests:
|
|||||||
// Acceleration, MPG
|
// Acceleration, MPG
|
||||||
ydata: carData.Slice(0, 392, 3, 5),
|
ydata: carData.Slice(0, 392, 3, 5),
|
||||||
wantCorrs: []float64{0.8782187384352336, 0.6328187219216761},
|
wantCorrs: []float64{0.8782187384352336, 0.6328187219216761},
|
||||||
wantpVecs: mat64.NewDense(3, 2, []float64{
|
wantpVecs: mat.NewDense(3, 2, []float64{
|
||||||
0.3218296374829181, 0.3947540257657075,
|
0.3218296374829181, 0.3947540257657075,
|
||||||
0.4162807660635797, 0.7573719053303306,
|
0.4162807660635797, 0.7573719053303306,
|
||||||
0.8503740401982725, -0.5201509936144236,
|
0.8503740401982725, -0.5201509936144236,
|
||||||
}),
|
}),
|
||||||
wantqVecs: mat64.NewDense(2, 2, []float64{
|
wantqVecs: mat.NewDense(2, 2, []float64{
|
||||||
-0.5161984172278830, -0.8564690269072364,
|
-0.5161984172278830, -0.8564690269072364,
|
||||||
-0.8564690269072364, 0.5161984172278830,
|
-0.8564690269072364, 0.5161984172278830,
|
||||||
}),
|
}),
|
||||||
wantphiVs: mat64.NewDense(3, 2, []float64{
|
wantphiVs: mat.NewDense(3, 2, []float64{
|
||||||
0.0025033152994308, 0.0047795464118615,
|
0.0025033152994308, 0.0047795464118615,
|
||||||
0.0201923608080173, 0.0409150208725958,
|
0.0201923608080173, 0.0409150208725958,
|
||||||
-0.0000247374128745, -0.0026766435161875,
|
-0.0000247374128745, -0.0026766435161875,
|
||||||
}),
|
}),
|
||||||
wantpsiVs: mat64.NewDense(2, 2, []float64{
|
wantpsiVs: mat.NewDense(2, 2, []float64{
|
||||||
-0.1666196759760772, -0.3637393866139658,
|
-0.1666196759760772, -0.3637393866139658,
|
||||||
-0.0915512109649727, 0.1077863777929168,
|
-0.0915512109649727, 0.1077863777929168,
|
||||||
}),
|
}),
|
||||||
@@ -116,7 +116,7 @@ tests:
|
|||||||
// Median value of owner-occupied homes in $1000s
|
// Median value of owner-occupied homes in $1000s
|
||||||
ydata: bostonData.Slice(0, 506, 7, 11),
|
ydata: bostonData.Slice(0, 506, 7, 11),
|
||||||
wantCorrs: []float64{0.9451239443886021, 0.6786622733370654, 0.5714338361583764, 0.2009739704710440},
|
wantCorrs: []float64{0.9451239443886021, 0.6786622733370654, 0.5714338361583764, 0.2009739704710440},
|
||||||
wantpVecs: mat64.NewDense(7, 4, []float64{
|
wantpVecs: mat.NewDense(7, 4, []float64{
|
||||||
-0.2574391924541903, 0.0158477516621194, 0.2122169934631024, -0.0945733803894706,
|
-0.2574391924541903, 0.0158477516621194, 0.2122169934631024, -0.0945733803894706,
|
||||||
-0.4836594430018478, 0.3837101908138468, 0.1474448317415911, 0.6597324886718275,
|
-0.4836594430018478, 0.3837101908138468, 0.1474448317415911, 0.6597324886718275,
|
||||||
-0.0800776365873296, 0.3493556742809252, 0.3287336458109373, -0.2862040444334655,
|
-0.0800776365873296, 0.3493556742809252, 0.3287336458109373, -0.2862040444334655,
|
||||||
@@ -125,13 +125,13 @@ tests:
|
|||||||
-0.0990903250057199, 0.0503411215453873, 0.6384330631742202, 0.1022367136218303,
|
-0.0990903250057199, 0.0503411215453873, 0.6384330631742202, 0.1022367136218303,
|
||||||
0.4260459963765036, 0.0323334351308141, -0.2289527516030810, 0.6419232947608805,
|
0.4260459963765036, 0.0323334351308141, -0.2289527516030810, 0.6419232947608805,
|
||||||
}),
|
}),
|
||||||
wantqVecs: mat64.NewDense(4, 4, []float64{
|
wantqVecs: mat.NewDense(4, 4, []float64{
|
||||||
0.0181660502363264, -0.1583489460479038, -0.0066723577642883, -0.9871935400650649,
|
0.0181660502363264, -0.1583489460479038, -0.0066723577642883, -0.9871935400650649,
|
||||||
-0.2347699045986119, 0.9483314614936594, -0.1462420505631345, -0.1554470767919033,
|
-0.2347699045986119, 0.9483314614936594, -0.1462420505631345, -0.1554470767919033,
|
||||||
-0.9700704038477141, -0.2406071741000039, -0.0251838984227037, 0.0209134074358349,
|
-0.9700704038477141, -0.2406071741000039, -0.0251838984227037, 0.0209134074358349,
|
||||||
0.0593000682318482, -0.1330460003097728, -0.9889057151969489, 0.0291161494720761,
|
0.0593000682318482, -0.1330460003097728, -0.9889057151969489, 0.0291161494720761,
|
||||||
}),
|
}),
|
||||||
wantphiVs: mat64.NewDense(7, 4, []float64{
|
wantphiVs: mat.NewDense(7, 4, []float64{
|
||||||
-0.0027462234108197, 0.0093444513500898, 0.0489643932714296, -0.0154967189805819,
|
-0.0027462234108197, 0.0093444513500898, 0.0489643932714296, -0.0154967189805819,
|
||||||
-0.0428564455279537, -0.0241708702119420, 0.0360723472093996, 0.1838983230588095,
|
-0.0428564455279537, -0.0241708702119420, 0.0360723472093996, 0.1838983230588095,
|
||||||
-1.2248435648802380, 5.6030921364723980, 5.8094144583797025, -4.7926812190419676,
|
-1.2248435648802380, 5.6030921364723980, 5.8094144583797025, -4.7926812190419676,
|
||||||
@@ -140,7 +140,7 @@ tests:
|
|||||||
-0.0233270323101624, 0.1046330818178399, 0.3853045975077387, -0.0160927870102877,
|
-0.0233270323101624, 0.1046330818178399, 0.3853045975077387, -0.0160927870102877,
|
||||||
0.0001293051387859, 0.0004540746921446, -0.0030296315865440, 0.0081895477974654,
|
0.0001293051387859, 0.0004540746921446, -0.0030296315865440, 0.0081895477974654,
|
||||||
}),
|
}),
|
||||||
wantpsiVs: mat64.NewDense(4, 4, []float64{
|
wantpsiVs: mat.NewDense(4, 4, []float64{
|
||||||
0.0301593362017375, -0.3002219289647127, 0.0878217377593682, -1.9583226531517062,
|
0.0301593362017375, -0.3002219289647127, 0.0878217377593682, -1.9583226531517062,
|
||||||
-0.0065483104073892, 0.0392212086716247, -0.0117570776209991, -0.0061113064481860,
|
-0.0065483104073892, 0.0392212086716247, -0.0117570776209991, -0.0061113064481860,
|
||||||
-0.0052075523350125, -0.0045770200452960, -0.0022762313289592, 0.0008441873006821,
|
-0.0052075523350125, -0.0045770200452960, -0.0022762313289592, 0.0008441873006821,
|
||||||
@@ -151,8 +151,8 @@ tests:
|
|||||||
} {
|
} {
|
||||||
var cc stat.CC
|
var cc stat.CC
|
||||||
var corrs []float64
|
var corrs []float64
|
||||||
var pVecs, qVecs *mat64.Dense
|
var pVecs, qVecs *mat.Dense
|
||||||
var phiVs, psiVs *mat64.Dense
|
var phiVs, psiVs *mat.Dense
|
||||||
for j := 0; j < 2; j++ {
|
for j := 0; j < 2; j++ {
|
||||||
err := cc.CanonicalCorrelations(test.xdata, test.ydata, test.weights)
|
err := cc.CanonicalCorrelations(test.xdata, test.ydata, test.weights)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -170,21 +170,21 @@ tests:
|
|||||||
t.Errorf("%d use %d: unexpected variance result got:%v, want:%v",
|
t.Errorf("%d use %d: unexpected variance result got:%v, want:%v",
|
||||||
i, j, corrs, test.wantCorrs)
|
i, j, corrs, test.wantCorrs)
|
||||||
}
|
}
|
||||||
if !mat64.EqualApprox(pVecs, test.wantpVecs, test.epsilon) {
|
if !mat.EqualApprox(pVecs, test.wantpVecs, test.epsilon) {
|
||||||
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
||||||
i, j, mat64.Formatted(pVecs), mat64.Formatted(test.wantpVecs))
|
i, j, mat.Formatted(pVecs), mat.Formatted(test.wantpVecs))
|
||||||
}
|
}
|
||||||
if !mat64.EqualApprox(qVecs, test.wantqVecs, test.epsilon) {
|
if !mat.EqualApprox(qVecs, test.wantqVecs, test.epsilon) {
|
||||||
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
||||||
i, j, mat64.Formatted(qVecs), mat64.Formatted(test.wantqVecs))
|
i, j, mat.Formatted(qVecs), mat.Formatted(test.wantqVecs))
|
||||||
}
|
}
|
||||||
if !mat64.EqualApprox(phiVs, test.wantphiVs, test.epsilon) {
|
if !mat.EqualApprox(phiVs, test.wantphiVs, test.epsilon) {
|
||||||
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
||||||
i, j, mat64.Formatted(phiVs), mat64.Formatted(test.wantphiVs))
|
i, j, mat.Formatted(phiVs), mat.Formatted(test.wantphiVs))
|
||||||
}
|
}
|
||||||
if !mat64.EqualApprox(psiVs, test.wantpsiVs, test.epsilon) {
|
if !mat.EqualApprox(psiVs, test.wantpsiVs, test.epsilon) {
|
||||||
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
|
||||||
i, j, mat64.Formatted(psiVs), mat64.Formatted(test.wantpsiVs))
|
i, j, mat.Formatted(psiVs), mat.Formatted(test.wantpsiVs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,9 +9,8 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/mathext"
|
"gonum.org/v1/gonum/mathext"
|
||||||
"gonum.org/v1/gonum/matrix"
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
|
||||||
"gonum.org/v1/gonum/stat/distuv"
|
"gonum.org/v1/gonum/stat/distuv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,12 +29,12 @@ type Wishart struct {
|
|||||||
src *rand.Rand
|
src *rand.Rand
|
||||||
|
|
||||||
dim int
|
dim int
|
||||||
cholv mat64.Cholesky
|
cholv mat.Cholesky
|
||||||
logdetv float64
|
logdetv float64
|
||||||
upper mat64.TriDense
|
upper mat.TriDense
|
||||||
|
|
||||||
once sync.Once
|
once sync.Once
|
||||||
v *mat64.SymDense // only stored if needed
|
v *mat.SymDense // only stored if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWishart returns a new Wishart distribution with the given shape matrix and
|
// NewWishart returns a new Wishart distribution with the given shape matrix and
|
||||||
@@ -43,18 +42,18 @@ type Wishart struct {
|
|||||||
// successful.
|
// successful.
|
||||||
//
|
//
|
||||||
// NewWishart panics if nu <= d - 1 where d is the order of v.
|
// NewWishart panics if nu <= d - 1 where d is the order of v.
|
||||||
func NewWishart(v mat64.Symmetric, nu float64, src *rand.Rand) (*Wishart, bool) {
|
func NewWishart(v mat.Symmetric, nu float64, src *rand.Rand) (*Wishart, bool) {
|
||||||
dim := v.Symmetric()
|
dim := v.Symmetric()
|
||||||
if nu <= float64(dim-1) {
|
if nu <= float64(dim-1) {
|
||||||
panic("wishart: nu must be greater than dim-1")
|
panic("wishart: nu must be greater than dim-1")
|
||||||
}
|
}
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
ok := chol.Factorize(v)
|
ok := chol.Factorize(v)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
var u mat64.TriDense
|
var u mat.TriDense
|
||||||
u.UFromCholesky(&chol)
|
u.UFromCholesky(&chol)
|
||||||
|
|
||||||
w := &Wishart{
|
w := &Wishart{
|
||||||
@@ -73,9 +72,9 @@ func NewWishart(v mat64.Symmetric, nu float64, src *rand.Rand) (*Wishart, bool)
|
|||||||
// If x is nil, a new matrix is allocated and returned. If x is not nil, the
|
// If x is nil, a new matrix is allocated and returned. If x is not nil, the
|
||||||
// result is stored in-place into x and MeanSym will panic if the order of x
|
// result is stored in-place into x and MeanSym will panic if the order of x
|
||||||
// is not equal to the order of the receiver.
|
// is not equal to the order of the receiver.
|
||||||
func (w *Wishart) MeanSym(x *mat64.SymDense) *mat64.SymDense {
|
func (w *Wishart) MeanSym(x *mat.SymDense) *mat.SymDense {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
x = mat64.NewSymDense(w.dim, nil)
|
x = mat.NewSymDense(w.dim, nil)
|
||||||
}
|
}
|
||||||
d := x.Symmetric()
|
d := x.Symmetric()
|
||||||
if d != w.dim {
|
if d != w.dim {
|
||||||
@@ -89,7 +88,7 @@ func (w *Wishart) MeanSym(x *mat64.SymDense) *mat64.SymDense {
|
|||||||
|
|
||||||
// ProbSym returns the probability of the symmetric matrix x. If x is not positive
|
// ProbSym returns the probability of the symmetric matrix x. If x is not positive
|
||||||
// definite (the Cholesky decomposition fails), it has 0 probability.
|
// definite (the Cholesky decomposition fails), it has 0 probability.
|
||||||
func (w *Wishart) ProbSym(x mat64.Symmetric) float64 {
|
func (w *Wishart) ProbSym(x mat.Symmetric) float64 {
|
||||||
return math.Exp(w.LogProbSym(x))
|
return math.Exp(w.LogProbSym(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,12 +96,12 @@ func (w *Wishart) ProbSym(x mat64.Symmetric) float64 {
|
|||||||
//
|
//
|
||||||
// LogProbSym returns -∞ if the input matrix is not positive definite (the Cholesky
|
// LogProbSym returns -∞ if the input matrix is not positive definite (the Cholesky
|
||||||
// decomposition fails).
|
// decomposition fails).
|
||||||
func (w *Wishart) LogProbSym(x mat64.Symmetric) float64 {
|
func (w *Wishart) LogProbSym(x mat.Symmetric) float64 {
|
||||||
dim := x.Symmetric()
|
dim := x.Symmetric()
|
||||||
if dim != w.dim {
|
if dim != w.dim {
|
||||||
panic(badDim)
|
panic(badDim)
|
||||||
}
|
}
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
ok := chol.Factorize(x)
|
ok := chol.Factorize(x)
|
||||||
if !ok {
|
if !ok {
|
||||||
return math.Inf(-1)
|
return math.Inf(-1)
|
||||||
@@ -112,7 +111,7 @@ func (w *Wishart) LogProbSym(x mat64.Symmetric) float64 {
|
|||||||
|
|
||||||
// LogProbSymChol returns the log of the probability of the input symmetric matrix
|
// LogProbSymChol returns the log of the probability of the input symmetric matrix
|
||||||
// given its Cholesky decomposition.
|
// given its Cholesky decomposition.
|
||||||
func (w *Wishart) LogProbSymChol(cholX *mat64.Cholesky) float64 {
|
func (w *Wishart) LogProbSymChol(cholX *mat.Cholesky) float64 {
|
||||||
dim := cholX.Size()
|
dim := cholX.Size()
|
||||||
if dim != w.dim {
|
if dim != w.dim {
|
||||||
panic(badDim)
|
panic(badDim)
|
||||||
@@ -120,7 +119,7 @@ func (w *Wishart) LogProbSymChol(cholX *mat64.Cholesky) float64 {
|
|||||||
return w.logProbSymChol(cholX)
|
return w.logProbSymChol(cholX)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wishart) logProbSymChol(cholX *mat64.Cholesky) float64 {
|
func (w *Wishart) logProbSymChol(cholX *mat.Cholesky) float64 {
|
||||||
// The PDF is
|
// The PDF is
|
||||||
// p(X) = [|X|^((ν-d-1)/2) * exp(-tr(V^-1 * X)/2)] / [2^(ν*d/2) * |V|^(ν/2) * Γ_d(ν/2)]
|
// p(X) = [|X|^((ν-d-1)/2) * exp(-tr(V^-1 * X)/2)] / [2^(ν*d/2) * |V|^(ν/2) * Γ_d(ν/2)]
|
||||||
// The LogPDF is thus
|
// The LogPDF is thus
|
||||||
@@ -128,16 +127,16 @@ func (w *Wishart) logProbSymChol(cholX *mat64.Cholesky) float64 {
|
|||||||
logdetx := cholX.LogDet()
|
logdetx := cholX.LogDet()
|
||||||
|
|
||||||
// Compute tr(V^-1 * X), using the fact that X = U^T * U.
|
// Compute tr(V^-1 * X), using the fact that X = U^T * U.
|
||||||
var u mat64.TriDense
|
var u mat.TriDense
|
||||||
u.UFromCholesky(cholX)
|
u.UFromCholesky(cholX)
|
||||||
|
|
||||||
var vinvx mat64.Dense
|
var vinvx mat.Dense
|
||||||
err := vinvx.SolveCholesky(&w.cholv, u.T())
|
err := vinvx.SolveCholesky(&w.cholv, u.T())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return math.Inf(-1)
|
return math.Inf(-1)
|
||||||
}
|
}
|
||||||
vinvx.Mul(&vinvx, &u)
|
vinvx.Mul(&vinvx, &u)
|
||||||
tr := mat64.Trace(&vinvx)
|
tr := mat.Trace(&vinvx)
|
||||||
|
|
||||||
fnu := float64(w.nu)
|
fnu := float64(w.nu)
|
||||||
fdim := float64(w.dim)
|
fdim := float64(w.dim)
|
||||||
@@ -146,18 +145,18 @@ func (w *Wishart) logProbSymChol(cholX *mat64.Cholesky) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RandSym generates a random symmetric matrix from the distribution.
|
// RandSym generates a random symmetric matrix from the distribution.
|
||||||
func (w *Wishart) RandSym(x *mat64.SymDense) *mat64.SymDense {
|
func (w *Wishart) RandSym(x *mat.SymDense) *mat.SymDense {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
x = &mat64.SymDense{}
|
x = &mat.SymDense{}
|
||||||
}
|
}
|
||||||
var c mat64.Cholesky
|
var c mat.Cholesky
|
||||||
w.RandChol(&c)
|
w.RandChol(&c)
|
||||||
x.FromCholesky(&c)
|
x.FromCholesky(&c)
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandChol generates the Cholesky decomposition of a random matrix from the distribution.
|
// RandChol generates the Cholesky decomposition of a random matrix from the distribution.
|
||||||
func (w *Wishart) RandChol(c *mat64.Cholesky) *mat64.Cholesky {
|
func (w *Wishart) RandChol(c *mat.Cholesky) *mat.Cholesky {
|
||||||
// TODO(btracey): Modify the code if the underlying data from c is exposed
|
// TODO(btracey): Modify the code if the underlying data from c is exposed
|
||||||
// to avoid the dim^2 allocation here.
|
// to avoid the dim^2 allocation here.
|
||||||
|
|
||||||
@@ -179,7 +178,7 @@ func (w *Wishart) RandChol(c *mat64.Cholesky) *mat64.Cholesky {
|
|||||||
Source: w.src,
|
Source: w.src,
|
||||||
}
|
}
|
||||||
|
|
||||||
t := mat64.NewTriDense(w.dim, matrix.Upper, nil)
|
t := mat.NewTriDense(w.dim, mat.Upper, nil)
|
||||||
for i := 0; i < w.dim; i++ {
|
for i := 0; i < w.dim; i++ {
|
||||||
v := distuv.ChiSquared{
|
v := distuv.ChiSquared{
|
||||||
K: w.nu - float64(i),
|
K: w.nu - float64(i),
|
||||||
@@ -195,7 +194,7 @@ func (w *Wishart) RandChol(c *mat64.Cholesky) *mat64.Cholesky {
|
|||||||
|
|
||||||
t.MulTri(t, &w.upper)
|
t.MulTri(t, &w.upper)
|
||||||
if c == nil {
|
if c == nil {
|
||||||
c = &mat64.Cholesky{}
|
c = &mat.Cholesky{}
|
||||||
}
|
}
|
||||||
c.SetFromU(t)
|
c.SetFromU(t)
|
||||||
return c
|
return c
|
||||||
@@ -204,7 +203,7 @@ func (w *Wishart) RandChol(c *mat64.Cholesky) *mat64.Cholesky {
|
|||||||
// setV computes and stores the covariance matrix of the distribution.
|
// setV computes and stores the covariance matrix of the distribution.
|
||||||
func (w *Wishart) setV() {
|
func (w *Wishart) setV() {
|
||||||
w.once.Do(func() {
|
w.once.Do(func() {
|
||||||
w.v = mat64.NewSymDense(w.dim, nil)
|
w.v = mat.NewSymDense(w.dim, nil)
|
||||||
w.v.FromCholesky(&w.cholv)
|
w.v.FromCholesky(&w.cholv)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -10,39 +10,39 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWishart(t *testing.T) {
|
func TestWishart(t *testing.T) {
|
||||||
for c, test := range []struct {
|
for c, test := range []struct {
|
||||||
v *mat64.SymDense
|
v *mat.SymDense
|
||||||
nu float64
|
nu float64
|
||||||
xs []*mat64.SymDense
|
xs []*mat.SymDense
|
||||||
lps []float64
|
lps []float64
|
||||||
}{
|
}{
|
||||||
// Logprob data compared with scipy.
|
// Logprob data compared with scipy.
|
||||||
{
|
{
|
||||||
v: mat64.NewSymDense(2, []float64{1, 0, 0, 1}),
|
v: mat.NewSymDense(2, []float64{1, 0, 0, 1}),
|
||||||
nu: 4,
|
nu: 4,
|
||||||
xs: []*mat64.SymDense{
|
xs: []*mat.SymDense{
|
||||||
mat64.NewSymDense(2, []float64{0.9, 0.1, 0.1, 0.9}),
|
mat.NewSymDense(2, []float64{0.9, 0.1, 0.1, 0.9}),
|
||||||
},
|
},
|
||||||
lps: []float64{-4.2357432031863409},
|
lps: []float64{-4.2357432031863409},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: mat64.NewSymDense(2, []float64{0.8, -0.2, -0.2, 0.7}),
|
v: mat.NewSymDense(2, []float64{0.8, -0.2, -0.2, 0.7}),
|
||||||
nu: 5,
|
nu: 5,
|
||||||
xs: []*mat64.SymDense{
|
xs: []*mat.SymDense{
|
||||||
mat64.NewSymDense(2, []float64{0.9, 0.1, 0.1, 0.9}),
|
mat.NewSymDense(2, []float64{0.9, 0.1, 0.1, 0.9}),
|
||||||
mat64.NewSymDense(2, []float64{0.3, -0.1, -0.1, 0.7}),
|
mat.NewSymDense(2, []float64{0.3, -0.1, -0.1, 0.7}),
|
||||||
},
|
},
|
||||||
lps: []float64{-4.2476495605333575, -4.9993285370378633},
|
lps: []float64{-4.2476495605333575, -4.9993285370378633},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: mat64.NewSymDense(3, []float64{0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}),
|
v: mat.NewSymDense(3, []float64{0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}),
|
||||||
nu: 5,
|
nu: 5,
|
||||||
xs: []*mat64.SymDense{
|
xs: []*mat.SymDense{
|
||||||
mat64.NewSymDense(3, []float64{1, 0.2, -0.3, 0.2, 0.6, -0.2, -0.3, -0.2, 6}),
|
mat.NewSymDense(3, []float64{1, 0.2, -0.3, 0.2, 0.6, -0.2, -0.3, -0.2, 6}),
|
||||||
},
|
},
|
||||||
lps: []float64{-11.010982249229421},
|
lps: []float64{-11.010982249229421},
|
||||||
},
|
},
|
||||||
@@ -54,7 +54,7 @@ func TestWishart(t *testing.T) {
|
|||||||
for i, x := range test.xs {
|
for i, x := range test.xs {
|
||||||
lp := w.LogProbSym(x)
|
lp := w.LogProbSym(x)
|
||||||
|
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
ok := chol.Factorize(x)
|
ok := chol.Factorize(x)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("bad test")
|
panic("bad test")
|
||||||
@@ -80,25 +80,25 @@ func TestWishart(t *testing.T) {
|
|||||||
|
|
||||||
func TestWishartRand(t *testing.T) {
|
func TestWishartRand(t *testing.T) {
|
||||||
for c, test := range []struct {
|
for c, test := range []struct {
|
||||||
v *mat64.SymDense
|
v *mat.SymDense
|
||||||
nu float64
|
nu float64
|
||||||
samples int
|
samples int
|
||||||
tol float64
|
tol float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
v: mat64.NewSymDense(2, []float64{0.8, -0.2, -0.2, 0.7}),
|
v: mat.NewSymDense(2, []float64{0.8, -0.2, -0.2, 0.7}),
|
||||||
nu: 5,
|
nu: 5,
|
||||||
samples: 30000,
|
samples: 30000,
|
||||||
tol: 3e-2,
|
tol: 3e-2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: mat64.NewSymDense(3, []float64{0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}),
|
v: mat.NewSymDense(3, []float64{0.8, 0.3, 0.1, 0.3, 0.7, -0.1, 0.1, -0.1, 7}),
|
||||||
nu: 5,
|
nu: 5,
|
||||||
samples: 300000,
|
samples: 300000,
|
||||||
tol: 3e-2,
|
tol: 3e-2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: mat64.NewSymDense(4, []float64{
|
v: mat.NewSymDense(4, []float64{
|
||||||
0.8, 0.3, 0.1, -0.2,
|
0.8, 0.3, 0.1, -0.2,
|
||||||
0.3, 0.7, -0.1, 0.4,
|
0.3, 0.7, -0.1, 0.4,
|
||||||
0.1, -0.1, 7, 1,
|
0.1, -0.1, 7, 1,
|
||||||
@@ -114,16 +114,16 @@ func TestWishartRand(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
panic("bad test")
|
panic("bad test")
|
||||||
}
|
}
|
||||||
mean := mat64.NewSymDense(dim, nil)
|
mean := mat.NewSymDense(dim, nil)
|
||||||
x := mat64.NewSymDense(dim, nil)
|
x := mat.NewSymDense(dim, nil)
|
||||||
for i := 0; i < test.samples; i++ {
|
for i := 0; i < test.samples; i++ {
|
||||||
w.RandSym(x)
|
w.RandSym(x)
|
||||||
x.ScaleSym(1/float64(test.samples), x)
|
x.ScaleSym(1/float64(test.samples), x)
|
||||||
mean.AddSym(mean, x)
|
mean.AddSym(mean, x)
|
||||||
}
|
}
|
||||||
trueMean := w.MeanSym(nil)
|
trueMean := w.MeanSym(nil)
|
||||||
if !mat64.EqualApprox(trueMean, mean, test.tol) {
|
if !mat.EqualApprox(trueMean, mean, test.tol) {
|
||||||
t.Errorf("Case %d: Mismatch between estimated and true mean. Got\n%0.4v\nWant\n%0.4v\n", c, mat64.Formatted(mean), mat64.Formatted(trueMean))
|
t.Errorf("Case %d: Mismatch between estimated and true mean. Got\n%0.4v\nWant\n%0.4v\n", c, mat.Formatted(mean), mat.Formatted(trueMean))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat/distuv"
|
"gonum.org/v1/gonum/stat/distuv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -61,11 +61,11 @@ func NewDirichlet(alpha []float64, src *rand.Rand) *Dirichlet {
|
|||||||
// covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
|
// covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
|
||||||
// If the input matrix is nil a new matrix is allocated, otherwise the result
|
// If the input matrix is nil a new matrix is allocated, otherwise the result
|
||||||
// is stored in-place into the input.
|
// is stored in-place into the input.
|
||||||
func (d *Dirichlet) CovarianceMatrix(cov *mat64.SymDense) *mat64.SymDense {
|
func (d *Dirichlet) CovarianceMatrix(cov *mat.SymDense) *mat.SymDense {
|
||||||
if cov == nil {
|
if cov == nil {
|
||||||
cov = mat64.NewSymDense(d.Dim(), nil)
|
cov = mat.NewSymDense(d.Dim(), nil)
|
||||||
} else if cov.Symmetric() == 0 {
|
} else if cov.Symmetric() == 0 {
|
||||||
*cov = *(cov.GrowSquare(d.dim).(*mat64.SymDense))
|
*cov = *(cov.GrowSquare(d.dim).(*mat.SymDense))
|
||||||
} else if cov.Symmetric() != d.dim {
|
} else if cov.Symmetric() != d.dim {
|
||||||
panic("normal: input matrix size mismatch")
|
panic("normal: input matrix size mismatch")
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDirichlet(t *testing.T) {
|
func TestDirichlet(t *testing.T) {
|
||||||
@@ -64,7 +64,7 @@ func TestDirichlet(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
d := test.Dir
|
d := test.Dir
|
||||||
dim := d.Dim()
|
dim := d.Dim()
|
||||||
x := mat64.NewDense(test.N, dim, nil)
|
x := mat.NewDense(test.N, dim, nil)
|
||||||
generateSamples(x, d)
|
generateSamples(x, d)
|
||||||
checkMean(t, cas, x, d, 1e-3)
|
checkMean(t, cas, x, d, 1e-3)
|
||||||
checkCov(t, cas, x, d, 1e-3)
|
checkCov(t, cas, x, d, 1e-3)
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ func testProbability(t *testing.T, cases []probCase) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSamples(x *mat64.Dense, r Rander) {
|
func generateSamples(x *mat.Dense, r Rander) {
|
||||||
n, _ := x.Dims()
|
n, _ := x.Dims()
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
r.Rand(x.RawRowView(i))
|
r.Rand(x.RawRowView(i))
|
||||||
@@ -48,7 +48,7 @@ type Meaner interface {
|
|||||||
Mean([]float64) []float64
|
Mean([]float64) []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMean(t *testing.T, cas int, x *mat64.Dense, m Meaner, tol float64) {
|
func checkMean(t *testing.T, cas int, x *mat.Dense, m Meaner, tol float64) {
|
||||||
mean := m.Mean(nil)
|
mean := m.Mean(nil)
|
||||||
|
|
||||||
// Check that the answer is identical when using nil or non-nil.
|
// Check that the answer is identical when using nil or non-nil.
|
||||||
@@ -63,7 +63,7 @@ func checkMean(t *testing.T, cas int, x *mat64.Dense, m Meaner, tol float64) {
|
|||||||
col := make([]float64, r)
|
col := make([]float64, r)
|
||||||
meanEst := make([]float64, len(mean))
|
meanEst := make([]float64, len(mean))
|
||||||
for i := range meanEst {
|
for i := range meanEst {
|
||||||
meanEst[i] = stat.Mean(mat64.Col(col, i, x), nil)
|
meanEst[i] = stat.Mean(mat.Col(col, i, x), nil)
|
||||||
}
|
}
|
||||||
if !floats.EqualApprox(mean, meanEst, tol) {
|
if !floats.EqualApprox(mean, meanEst, tol) {
|
||||||
t.Errorf("Returned mean and sample mean mismatch. Case %v. Empirical %v, returned %v", cas, meanEst, mean)
|
t.Errorf("Returned mean and sample mean mismatch. Case %v. Empirical %v, returned %v", cas, meanEst, mean)
|
||||||
@@ -71,26 +71,26 @@ func checkMean(t *testing.T, cas int, x *mat64.Dense, m Meaner, tol float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Cover interface {
|
type Cover interface {
|
||||||
CovarianceMatrix(*mat64.SymDense) *mat64.SymDense
|
CovarianceMatrix(*mat.SymDense) *mat.SymDense
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkCov(t *testing.T, cas int, x *mat64.Dense, c Cover, tol float64) {
|
func checkCov(t *testing.T, cas int, x *mat.Dense, c Cover, tol float64) {
|
||||||
cov := c.CovarianceMatrix(nil)
|
cov := c.CovarianceMatrix(nil)
|
||||||
n := cov.Symmetric()
|
n := cov.Symmetric()
|
||||||
cov2 := mat64.NewSymDense(n, nil)
|
cov2 := mat.NewSymDense(n, nil)
|
||||||
c.CovarianceMatrix(cov2)
|
c.CovarianceMatrix(cov2)
|
||||||
if !mat64.Equal(cov, cov2) {
|
if !mat.Equal(cov, cov2) {
|
||||||
t.Errorf("Cov mismatch when providing nil and matrix. Case %v", cas)
|
t.Errorf("Cov mismatch when providing nil and matrix. Case %v", cas)
|
||||||
}
|
}
|
||||||
var cov3 mat64.SymDense
|
var cov3 mat.SymDense
|
||||||
c.CovarianceMatrix(&cov3)
|
c.CovarianceMatrix(&cov3)
|
||||||
if !mat64.Equal(cov, &cov3) {
|
if !mat.Equal(cov, &cov3) {
|
||||||
t.Errorf("Cov mismatch when providing zero matrix. Case %v", cas)
|
t.Errorf("Cov mismatch when providing zero matrix. Case %v", cas)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the covariance matrix matches the samples
|
// Check that the covariance matrix matches the samples
|
||||||
covEst := stat.CovarianceMatrix(nil, x, nil)
|
covEst := stat.CovarianceMatrix(nil, x, nil)
|
||||||
if !mat64.EqualApprox(covEst, cov, tol) {
|
if !mat.EqualApprox(covEst, cov, tol) {
|
||||||
t.Errorf("Return cov and sample cov mismatch. Cas %v.\nGot:\n%0.4v\nWant:\n%0.4v", cas, mat64.Formatted(cov), mat64.Formatted(covEst))
|
t.Errorf("Return cov and sample cov mismatch. Cas %v.\nGot:\n%0.4v\nWant:\n%0.4v", cas, mat.Formatted(cov), mat.Formatted(covEst))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
"gonum.org/v1/gonum/stat/distuv"
|
"gonum.org/v1/gonum/stat/distuv"
|
||||||
)
|
)
|
||||||
@@ -26,10 +26,10 @@ var (
|
|||||||
type Normal struct {
|
type Normal struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
|
|
||||||
sigma mat64.SymDense
|
sigma mat.SymDense
|
||||||
|
|
||||||
chol mat64.Cholesky
|
chol mat.Cholesky
|
||||||
lower mat64.TriDense
|
lower mat.TriDense
|
||||||
logSqrtDet float64
|
logSqrtDet float64
|
||||||
dim int
|
dim int
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ type Normal struct {
|
|||||||
// NewNormal creates a new Normal with the given mean and covariance matrix.
|
// NewNormal creates a new Normal with the given mean and covariance matrix.
|
||||||
// NewNormal panics if len(mu) == 0, or if len(mu) != sigma.N. If the covariance
|
// NewNormal panics if len(mu) == 0, or if len(mu) != sigma.N. If the covariance
|
||||||
// matrix is not positive-definite, the returned boolean is false.
|
// matrix is not positive-definite, the returned boolean is false.
|
||||||
func NewNormal(mu []float64, sigma mat64.Symmetric, src *rand.Rand) (*Normal, bool) {
|
func NewNormal(mu []float64, sigma mat.Symmetric, src *rand.Rand) (*Normal, bool) {
|
||||||
if len(mu) == 0 {
|
if len(mu) == 0 {
|
||||||
panic(badZeroDimension)
|
panic(badZeroDimension)
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ func NewNormal(mu []float64, sigma mat64.Symmetric, src *rand.Rand) (*Normal, bo
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
n.sigma = *mat64.NewSymDense(dim, nil)
|
n.sigma = *mat.NewSymDense(dim, nil)
|
||||||
n.sigma.CopySym(sigma)
|
n.sigma.CopySym(sigma)
|
||||||
n.lower.LFromCholesky(&n.chol)
|
n.lower.LFromCholesky(&n.chol)
|
||||||
n.logSqrtDet = 0.5 * n.chol.LogDet()
|
n.logSqrtDet = 0.5 * n.chol.LogDet()
|
||||||
@@ -67,7 +67,7 @@ func NewNormal(mu []float64, sigma mat64.Symmetric, src *rand.Rand) (*Normal, bo
|
|||||||
// NewNormalChol creates a new Normal distribution with the given mean and
|
// NewNormalChol creates a new Normal distribution with the given mean and
|
||||||
// covariance matrix represented by its Cholesky decomposition. NewNormalChol
|
// covariance matrix represented by its Cholesky decomposition. NewNormalChol
|
||||||
// panics if len(mu) is not equal to chol.Size().
|
// panics if len(mu) is not equal to chol.Size().
|
||||||
func NewNormalChol(mu []float64, chol *mat64.Cholesky, src *rand.Rand) *Normal {
|
func NewNormalChol(mu []float64, chol *mat.Cholesky, src *rand.Rand) *Normal {
|
||||||
dim := len(mu)
|
dim := len(mu)
|
||||||
if dim != chol.Size() {
|
if dim != chol.Size() {
|
||||||
panic(badSizeMismatch)
|
panic(badSizeMismatch)
|
||||||
@@ -89,7 +89,7 @@ func NewNormalChol(mu []float64, chol *mat64.Cholesky, src *rand.Rand) *Normal {
|
|||||||
// panics if len(mu) is not equal to prec.Symmetric(). If the precision matrix
|
// panics if len(mu) is not equal to prec.Symmetric(). If the precision matrix
|
||||||
// is not positive-definite, NewNormalPrecision returns nil for norm and false
|
// is not positive-definite, NewNormalPrecision returns nil for norm and false
|
||||||
// for ok.
|
// for ok.
|
||||||
func NewNormalPrecision(mu []float64, prec *mat64.SymDense, src *rand.Rand) (norm *Normal, ok bool) {
|
func NewNormalPrecision(mu []float64, prec *mat.SymDense, src *rand.Rand) (norm *Normal, ok bool) {
|
||||||
if len(mu) == 0 {
|
if len(mu) == 0 {
|
||||||
panic(badZeroDimension)
|
panic(badZeroDimension)
|
||||||
}
|
}
|
||||||
@@ -102,12 +102,12 @@ func NewNormalPrecision(mu []float64, prec *mat64.SymDense, src *rand.Rand) (nor
|
|||||||
// is much better, but this still loses precision. It is worth considering if
|
// is much better, but this still loses precision. It is worth considering if
|
||||||
// instead the precision matrix should be stored explicitly and used instead
|
// instead the precision matrix should be stored explicitly and used instead
|
||||||
// of the Cholesky decomposition of the covariance matrix where appropriate.
|
// of the Cholesky decomposition of the covariance matrix where appropriate.
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
ok = chol.Factorize(prec)
|
ok = chol.Factorize(prec)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
var sigma mat64.SymDense
|
var sigma mat.SymDense
|
||||||
sigma.InverseCholesky(&chol)
|
sigma.InverseCholesky(&chol)
|
||||||
return NewNormal(mu, &sigma, src)
|
return NewNormal(mu, &sigma, src)
|
||||||
}
|
}
|
||||||
@@ -154,9 +154,9 @@ func (n *Normal) ConditionNormal(observed []int, values []float64, src *rand.Ran
|
|||||||
// covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
|
// covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
|
||||||
// If the input matrix is nil a new matrix is allocated, otherwise the result
|
// If the input matrix is nil a new matrix is allocated, otherwise the result
|
||||||
// is stored in-place into the input.
|
// is stored in-place into the input.
|
||||||
func (n *Normal) CovarianceMatrix(s *mat64.SymDense) *mat64.SymDense {
|
func (n *Normal) CovarianceMatrix(s *mat.SymDense) *mat.SymDense {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
s = mat64.NewSymDense(n.Dim(), nil)
|
s = mat.NewSymDense(n.Dim(), nil)
|
||||||
}
|
}
|
||||||
sn := s.Symmetric()
|
sn := s.Symmetric()
|
||||||
if sn != n.Dim() {
|
if sn != n.Dim() {
|
||||||
@@ -183,7 +183,7 @@ func (n *Normal) LogProb(x []float64) float64 {
|
|||||||
panic(badSizeMismatch)
|
panic(badSizeMismatch)
|
||||||
}
|
}
|
||||||
c := -0.5*float64(dim)*logTwoPi - n.logSqrtDet
|
c := -0.5*float64(dim)*logTwoPi - n.logSqrtDet
|
||||||
dst := stat.Mahalanobis(mat64.NewVector(dim, x), mat64.NewVector(dim, n.mu), &n.chol)
|
dst := stat.Mahalanobis(mat.NewVector(dim, x), mat.NewVector(dim, n.mu), &n.chol)
|
||||||
return c - 0.5*dst*dst
|
return c - 0.5*dst*dst
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ func (n *Normal) MarginalNormal(vars []int, src *rand.Rand) (*Normal, bool) {
|
|||||||
for i, v := range vars {
|
for i, v := range vars {
|
||||||
newMean[i] = n.mu[v]
|
newMean[i] = n.mu[v]
|
||||||
}
|
}
|
||||||
var s mat64.SymDense
|
var s mat.SymDense
|
||||||
s.SubsetSym(&n.sigma, vars)
|
s.SubsetSym(&n.sigma, vars)
|
||||||
return NewNormal(newMean, &s, src)
|
return NewNormal(newMean, &s, src)
|
||||||
}
|
}
|
||||||
@@ -308,8 +308,8 @@ func (n *Normal) TransformNormal(dst, normal []float64) []float64 {
|
|||||||
// transformNormal performs the same operation as TransformNormal except no
|
// transformNormal performs the same operation as TransformNormal except no
|
||||||
// safety checks are performed and both input slices must be non-nil.
|
// safety checks are performed and both input slices must be non-nil.
|
||||||
func (n *Normal) transformNormal(dst, normal []float64) []float64 {
|
func (n *Normal) transformNormal(dst, normal []float64) []float64 {
|
||||||
srcVec := mat64.NewVector(n.dim, normal)
|
srcVec := mat.NewVector(n.dim, normal)
|
||||||
dstVec := mat64.NewVector(n.dim, dst)
|
dstVec := mat.NewVector(n.dim, dst)
|
||||||
dstVec.MulVec(&n.lower, srcVec)
|
dstVec.MulVec(&n.lower, srcVec)
|
||||||
floats.Add(dst, n.mu)
|
floats.Add(dst, n.mu)
|
||||||
return dst
|
return dst
|
||||||
|
@@ -10,24 +10,24 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mvTest struct {
|
type mvTest struct {
|
||||||
Mu []float64
|
Mu []float64
|
||||||
Sigma *mat64.SymDense
|
Sigma *mat.SymDense
|
||||||
Loc []float64
|
Loc []float64
|
||||||
Logprob float64
|
Logprob float64
|
||||||
Prob float64
|
Prob float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNormProbs(t *testing.T) {
|
func TestNormProbs(t *testing.T) {
|
||||||
dist1, ok := NewNormal([]float64{0, 0}, mat64.NewSymDense(2, []float64{1, 0, 0, 1}), nil)
|
dist1, ok := NewNormal([]float64{0, 0}, mat.NewSymDense(2, []float64{1, 0, 0, 1}), nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("bad test")
|
t.Errorf("bad test")
|
||||||
}
|
}
|
||||||
dist2, ok := NewNormal([]float64{6, 7}, mat64.NewSymDense(2, []float64{8, 2, 0, 4}), nil)
|
dist2, ok := NewNormal([]float64{6, 7}, mat.NewSymDense(2, []float64{8, 2, 0, 4}), nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("bad test")
|
t.Errorf("bad test")
|
||||||
}
|
}
|
||||||
@@ -53,14 +53,14 @@ func TestNormProbs(t *testing.T) {
|
|||||||
func TestNewNormalChol(t *testing.T) {
|
func TestNewNormalChol(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mean []float64
|
mean []float64
|
||||||
cov *mat64.SymDense
|
cov *mat.SymDense
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mean: []float64{2, 3},
|
mean: []float64{2, 3},
|
||||||
cov: mat64.NewSymDense(2, []float64{1, 0.1, 0.1, 1}),
|
cov: mat.NewSymDense(2, []float64{1, 0.1, 0.1, 1}),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
ok := chol.Factorize(test.cov)
|
ok := chol.Factorize(test.cov)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("bad test")
|
panic("bad test")
|
||||||
@@ -101,26 +101,26 @@ func TestNormRand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
dim := len(test.mean)
|
dim := len(test.mean)
|
||||||
cov := mat64.NewSymDense(dim, test.cov)
|
cov := mat.NewSymDense(dim, test.cov)
|
||||||
n, ok := NewNormal(test.mean, cov, nil)
|
n, ok := NewNormal(test.mean, cov, nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("bad covariance matrix")
|
t.Errorf("bad covariance matrix")
|
||||||
}
|
}
|
||||||
|
|
||||||
nSamples := 1000000
|
nSamples := 1000000
|
||||||
samps := mat64.NewDense(nSamples, dim, nil)
|
samps := mat.NewDense(nSamples, dim, nil)
|
||||||
for i := 0; i < nSamples; i++ {
|
for i := 0; i < nSamples; i++ {
|
||||||
n.Rand(samps.RawRowView(i))
|
n.Rand(samps.RawRowView(i))
|
||||||
}
|
}
|
||||||
estMean := make([]float64, dim)
|
estMean := make([]float64, dim)
|
||||||
for i := range estMean {
|
for i := range estMean {
|
||||||
estMean[i] = stat.Mean(mat64.Col(nil, i, samps), nil)
|
estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil)
|
||||||
}
|
}
|
||||||
if !floats.EqualApprox(estMean, test.mean, 1e-2) {
|
if !floats.EqualApprox(estMean, test.mean, 1e-2) {
|
||||||
t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean)
|
t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean)
|
||||||
}
|
}
|
||||||
estCov := stat.CovarianceMatrix(nil, samps, nil)
|
estCov := stat.CovarianceMatrix(nil, samps, nil)
|
||||||
if !mat64.EqualApprox(estCov, cov, 1e-2) {
|
if !mat.EqualApprox(estCov, cov, 1e-2) {
|
||||||
t.Errorf("Cov mismatch: want: %v, got %v", cov, estCov)
|
t.Errorf("Cov mismatch: want: %v, got %v", cov, estCov)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ func TestNormalQuantile(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
dim := len(test.mean)
|
dim := len(test.mean)
|
||||||
cov := mat64.NewSymDense(dim, test.cov)
|
cov := mat.NewSymDense(dim, test.cov)
|
||||||
n, ok := NewNormal(test.mean, cov, nil)
|
n, ok := NewNormal(test.mean, cov, nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("bad covariance matrix")
|
t.Errorf("bad covariance matrix")
|
||||||
@@ -148,7 +148,7 @@ func TestNormalQuantile(t *testing.T) {
|
|||||||
|
|
||||||
nSamples := 1000000
|
nSamples := 1000000
|
||||||
rnd := rand.New(rand.NewSource(1))
|
rnd := rand.New(rand.NewSource(1))
|
||||||
samps := mat64.NewDense(nSamples, dim, nil)
|
samps := mat.NewDense(nSamples, dim, nil)
|
||||||
tmp := make([]float64, dim)
|
tmp := make([]float64, dim)
|
||||||
for i := 0; i < nSamples; i++ {
|
for i := 0; i < nSamples; i++ {
|
||||||
for j := range tmp {
|
for j := range tmp {
|
||||||
@@ -158,13 +158,13 @@ func TestNormalQuantile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
estMean := make([]float64, dim)
|
estMean := make([]float64, dim)
|
||||||
for i := range estMean {
|
for i := range estMean {
|
||||||
estMean[i] = stat.Mean(mat64.Col(nil, i, samps), nil)
|
estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil)
|
||||||
}
|
}
|
||||||
if !floats.EqualApprox(estMean, test.mean, 1e-2) {
|
if !floats.EqualApprox(estMean, test.mean, 1e-2) {
|
||||||
t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean)
|
t.Errorf("Mean mismatch: want: %v, got %v", test.mean, estMean)
|
||||||
}
|
}
|
||||||
estCov := stat.CovarianceMatrix(nil, samps, nil)
|
estCov := stat.CovarianceMatrix(nil, samps, nil)
|
||||||
if !mat64.EqualApprox(estCov, cov, 1e-2) {
|
if !mat.EqualApprox(estCov, cov, 1e-2) {
|
||||||
t.Errorf("Cov mismatch: want: %v, got %v", cov, estCov)
|
t.Errorf("Cov mismatch: want: %v, got %v", cov, estCov)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,57 +174,57 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
// Uncorrelated values shouldn't influence the updated values.
|
// Uncorrelated values shouldn't influence the updated values.
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
observed []int
|
observed []int
|
||||||
values []float64
|
values []float64
|
||||||
|
|
||||||
newMu []float64
|
newMu []float64
|
||||||
newSigma *mat64.SymDense
|
newSigma *mat.SymDense
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3},
|
mu: []float64{2, 3},
|
||||||
sigma: mat64.NewSymDense(2, []float64{2, 0, 0, 5}),
|
sigma: mat.NewSymDense(2, []float64{2, 0, 0, 5}),
|
||||||
observed: []int{0},
|
observed: []int{0},
|
||||||
values: []float64{10},
|
values: []float64{10},
|
||||||
|
|
||||||
newMu: []float64{3},
|
newMu: []float64{3},
|
||||||
newSigma: mat64.NewSymDense(1, []float64{5}),
|
newSigma: mat.NewSymDense(1, []float64{5}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3},
|
mu: []float64{2, 3},
|
||||||
sigma: mat64.NewSymDense(2, []float64{2, 0, 0, 5}),
|
sigma: mat.NewSymDense(2, []float64{2, 0, 0, 5}),
|
||||||
observed: []int{1},
|
observed: []int{1},
|
||||||
values: []float64{10},
|
values: []float64{10},
|
||||||
|
|
||||||
newMu: []float64{2},
|
newMu: []float64{2},
|
||||||
newSigma: mat64.NewSymDense(1, []float64{2}),
|
newSigma: mat.NewSymDense(1, []float64{2}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0, 0, 0, 5, 0, 0, 0, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0, 0, 0, 5, 0, 0, 0, 10}),
|
||||||
observed: []int{1},
|
observed: []int{1},
|
||||||
values: []float64{10},
|
values: []float64{10},
|
||||||
|
|
||||||
newMu: []float64{2, 4},
|
newMu: []float64{2, 4},
|
||||||
newSigma: mat64.NewSymDense(2, []float64{2, 0, 0, 10}),
|
newSigma: mat.NewSymDense(2, []float64{2, 0, 0, 10}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0, 0, 0, 5, 0, 0, 0, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0, 0, 0, 5, 0, 0, 0, 10}),
|
||||||
observed: []int{0, 1},
|
observed: []int{0, 1},
|
||||||
values: []float64{10, 15},
|
values: []float64{10, 15},
|
||||||
|
|
||||||
newMu: []float64{4},
|
newMu: []float64{4},
|
||||||
newSigma: mat64.NewSymDense(1, []float64{10}),
|
newSigma: mat.NewSymDense(1, []float64{10}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4, 5},
|
mu: []float64{2, 3, 4, 5},
|
||||||
sigma: mat64.NewSymDense(4, []float64{2, 0.5, 0, 0, 0.5, 5, 0, 0, 0, 0, 10, 2, 0, 0, 2, 3}),
|
sigma: mat.NewSymDense(4, []float64{2, 0.5, 0, 0, 0.5, 5, 0, 0, 0, 0, 10, 2, 0, 0, 2, 3}),
|
||||||
observed: []int{0, 1},
|
observed: []int{0, 1},
|
||||||
values: []float64{10, 15},
|
values: []float64{10, 15},
|
||||||
|
|
||||||
newMu: []float64{4, 5},
|
newMu: []float64{4, 5},
|
||||||
newSigma: mat64.NewSymDense(2, []float64{10, 2, 2, 3}),
|
newSigma: mat.NewSymDense(2, []float64{10, 2, 2, 3}),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
||||||
@@ -240,9 +240,9 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
t.Errorf("Updated mean mismatch. Want %v, got %v.", test.newMu, newNormal.mu)
|
t.Errorf("Updated mean mismatch. Want %v, got %v.", test.newMu, newNormal.mu)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sigma mat64.SymDense
|
var sigma mat.SymDense
|
||||||
sigma.FromCholesky(&newNormal.chol)
|
sigma.FromCholesky(&newNormal.chol)
|
||||||
if !mat64.EqualApprox(test.newSigma, &sigma, 1e-12) {
|
if !mat.EqualApprox(test.newSigma, &sigma, 1e-12) {
|
||||||
t.Errorf("Updated sigma mismatch\n.Want:\n% v\nGot:\n% v\n", test.newSigma, sigma)
|
t.Errorf("Updated sigma mismatch\n.Want:\n% v\nGot:\n% v\n", test.newSigma, sigma)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
std := test.std
|
std := test.std
|
||||||
rho := test.rho
|
rho := test.rho
|
||||||
sigma := mat64.NewSymDense(2, []float64{std[0] * std[0], std[0] * std[1] * rho, std[0] * std[1] * rho, std[1] * std[1]})
|
sigma := mat.NewSymDense(2, []float64{std[0] * std[0], std[0] * std[1] * rho, std[0] * std[1] * rho, std[1] * std[1]})
|
||||||
normal, ok := NewNormal(test.mu, sigma, nil)
|
normal, ok := NewNormal(test.mu, sigma, nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("Bad test, original sigma not positive definite")
|
t.Fatalf("Bad test, original sigma not positive definite")
|
||||||
@@ -278,7 +278,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("Bad test, update failed")
|
t.Fatalf("Bad test, update failed")
|
||||||
}
|
}
|
||||||
var newSigma mat64.SymDense
|
var newSigma mat.SymDense
|
||||||
newSigma.FromCholesky(&newNormal.chol)
|
newSigma.FromCholesky(&newNormal.chol)
|
||||||
trueMean := test.mu[0] + rho*(std[0]/std[1])*(test.value-test.mu[1])
|
trueMean := test.mu[0] + rho*(std[0]/std[1])*(test.value-test.mu[1])
|
||||||
if math.Abs(trueMean-newNormal.mu[0]) > 1e-14 {
|
if math.Abs(trueMean-newNormal.mu[0]) > 1e-14 {
|
||||||
@@ -293,7 +293,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
// Test via sampling.
|
// Test via sampling.
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
observed []int
|
observed []int
|
||||||
unobserved []int
|
unobserved []int
|
||||||
value []float64
|
value []float64
|
||||||
@@ -301,7 +301,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
// The indices in unobserved must be in ascending order for this test.
|
// The indices in unobserved must be in ascending order for this test.
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
||||||
|
|
||||||
observed: []int{0},
|
observed: []int{0},
|
||||||
unobserved: []int{1, 2},
|
unobserved: []int{1, 2},
|
||||||
@@ -309,7 +309,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4, 5},
|
mu: []float64{2, 3, 4, 5},
|
||||||
sigma: mat64.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
||||||
|
|
||||||
observed: []int{0, 3},
|
observed: []int{0, 3},
|
||||||
unobserved: []int{1, 2},
|
unobserved: []int{1, 2},
|
||||||
@@ -318,7 +318,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
totalSamp := 4000000
|
totalSamp := 4000000
|
||||||
var nSamp int
|
var nSamp int
|
||||||
samples := mat64.NewDense(totalSamp, len(test.mu), nil)
|
samples := mat.NewDense(totalSamp, len(test.mu), nil)
|
||||||
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("bad test")
|
t.Errorf("bad test")
|
||||||
@@ -343,12 +343,12 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
t.Errorf("bad test, not enough samples")
|
t.Errorf("bad test, not enough samples")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
samples = samples.View(0, 0, nSamp, len(test.mu)).(*mat64.Dense)
|
samples = samples.View(0, 0, nSamp, len(test.mu)).(*mat.Dense)
|
||||||
|
|
||||||
// Compute mean and covariance matrix.
|
// Compute mean and covariance matrix.
|
||||||
estMean := make([]float64, len(test.mu))
|
estMean := make([]float64, len(test.mu))
|
||||||
for i := range estMean {
|
for i := range estMean {
|
||||||
estMean[i] = stat.Mean(mat64.Col(nil, i, samples), nil)
|
estMean[i] = stat.Mean(mat.Col(nil, i, samples), nil)
|
||||||
}
|
}
|
||||||
estCov := stat.CovarianceMatrix(nil, samples, nil)
|
estCov := stat.CovarianceMatrix(nil, samples, nil)
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
|
|
||||||
subEstMean = append(subEstMean, estMean[v])
|
subEstMean = append(subEstMean, estMean[v])
|
||||||
}
|
}
|
||||||
subEstCov := mat64.NewSymDense(len(test.unobserved), nil)
|
subEstCov := mat.NewSymDense(len(test.unobserved), nil)
|
||||||
for i := 0; i < len(test.unobserved); i++ {
|
for i := 0; i < len(test.unobserved); i++ {
|
||||||
for j := i; j < len(test.unobserved); j++ {
|
for j := i; j < len(test.unobserved); j++ {
|
||||||
subEstCov.SetSym(i, j, estCov.At(test.unobserved[i], test.unobserved[j]))
|
subEstCov.SetSym(i, j, estCov.At(test.unobserved[i], test.unobserved[j]))
|
||||||
@@ -375,9 +375,9 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
t.Errorf("Mean mismatch. Want %v, got %v.", newNormal.mu[i], v)
|
t.Errorf("Mean mismatch. Want %v, got %v.", newNormal.mu[i], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sigma mat64.SymDense
|
var sigma mat.SymDense
|
||||||
sigma.FromCholesky(&newNormal.chol)
|
sigma.FromCholesky(&newNormal.chol)
|
||||||
if !mat64.EqualApprox(&sigma, subEstCov, 1e-1) {
|
if !mat.EqualApprox(&sigma, subEstCov, 1e-1) {
|
||||||
t.Errorf("Covariance mismatch. Want:\n%0.8v\nGot:\n%0.8v\n", subEstCov, sigma)
|
t.Errorf("Covariance mismatch. Want:\n%0.8v\nGot:\n%0.8v\n", subEstCov, sigma)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -386,11 +386,11 @@ func TestConditionNormal(t *testing.T) {
|
|||||||
func TestCovarianceMatrix(t *testing.T) {
|
func TestCovarianceMatrix(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{1, 0.5, 3, 0.5, 8, -1, 3, -1, 15}),
|
sigma: mat.NewSymDense(3, []float64{1, 0.5, 3, 0.5, 8, -1, 3, -1, 15}),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
||||||
@@ -398,13 +398,13 @@ func TestCovarianceMatrix(t *testing.T) {
|
|||||||
t.Fatalf("Bad test, covariance matrix not positive definite")
|
t.Fatalf("Bad test, covariance matrix not positive definite")
|
||||||
}
|
}
|
||||||
cov := normal.CovarianceMatrix(nil)
|
cov := normal.CovarianceMatrix(nil)
|
||||||
if !mat64.EqualApprox(cov, test.sigma, 1e-14) {
|
if !mat.EqualApprox(cov, test.sigma, 1e-14) {
|
||||||
t.Errorf("Covariance mismatch with nil input")
|
t.Errorf("Covariance mismatch with nil input")
|
||||||
}
|
}
|
||||||
dim := test.sigma.Symmetric()
|
dim := test.sigma.Symmetric()
|
||||||
cov = mat64.NewSymDense(dim, nil)
|
cov = mat.NewSymDense(dim, nil)
|
||||||
normal.CovarianceMatrix(cov)
|
normal.CovarianceMatrix(cov)
|
||||||
if !mat64.EqualApprox(cov, test.sigma, 1e-14) {
|
if !mat.EqualApprox(cov, test.sigma, 1e-14) {
|
||||||
t.Errorf("Covariance mismatch with supplied input")
|
t.Errorf("Covariance mismatch with supplied input")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -413,22 +413,22 @@ func TestCovarianceMatrix(t *testing.T) {
|
|||||||
func TestMarginal(t *testing.T) {
|
func TestMarginal(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
marginal []int
|
marginal []int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
||||||
marginal: []int{0},
|
marginal: []int{0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
||||||
marginal: []int{0, 2},
|
marginal: []int{0, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4, 5},
|
mu: []float64{2, 3, 4, 5},
|
||||||
sigma: mat64.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
||||||
|
|
||||||
marginal: []int{0, 3},
|
marginal: []int{0, 3},
|
||||||
},
|
},
|
||||||
@@ -443,13 +443,13 @@ func TestMarginal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
dim := normal.Dim()
|
dim := normal.Dim()
|
||||||
nSamples := 1000000
|
nSamples := 1000000
|
||||||
samps := mat64.NewDense(nSamples, dim, nil)
|
samps := mat.NewDense(nSamples, dim, nil)
|
||||||
for i := 0; i < nSamples; i++ {
|
for i := 0; i < nSamples; i++ {
|
||||||
normal.Rand(samps.RawRowView(i))
|
normal.Rand(samps.RawRowView(i))
|
||||||
}
|
}
|
||||||
estMean := make([]float64, dim)
|
estMean := make([]float64, dim)
|
||||||
for i := range estMean {
|
for i := range estMean {
|
||||||
estMean[i] = stat.Mean(mat64.Col(nil, i, samps), nil)
|
estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil)
|
||||||
}
|
}
|
||||||
for i, v := range test.marginal {
|
for i, v := range test.marginal {
|
||||||
if math.Abs(marginal.mu[i]-estMean[v]) > 1e-2 {
|
if math.Abs(marginal.mu[i]-estMean[v]) > 1e-2 {
|
||||||
@@ -474,15 +474,15 @@ func TestMarginal(t *testing.T) {
|
|||||||
func TestMarginalSingle(t *testing.T) {
|
func TestMarginalSingle(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4, 5},
|
mu: []float64{2, 3, 4, 5},
|
||||||
sigma: mat64.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
normal, ok := NewNormal(test.mu, test.sigma, nil)
|
||||||
@@ -513,9 +513,9 @@ func TestMarginalSingle(t *testing.T) {
|
|||||||
for i := range x {
|
for i := range x {
|
||||||
x[i] = rnd.Float64()
|
x[i] = rnd.Float64()
|
||||||
}
|
}
|
||||||
mat := mat64.NewDense(dim, dim, x)
|
matrix := mat.NewDense(dim, dim, x)
|
||||||
var sigma mat64.SymDense
|
var sigma mat.SymDense
|
||||||
sigma.SymOuterK(1, mat)
|
sigma.SymOuterK(1, matrix)
|
||||||
|
|
||||||
normal, ok := NewNormal(mu, &sigma, nil)
|
normal, ok := NewNormal(mu, &sigma, nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkMarginalNormal10(b *testing.B) {
|
func BenchmarkMarginalNormal10(b *testing.B) {
|
||||||
@@ -61,8 +61,8 @@ func randomNormal(sz int, rnd *rand.Rand) *Normal {
|
|||||||
for i := range data {
|
for i := range data {
|
||||||
data[i] = rnd.Float64()
|
data[i] = rnd.Float64()
|
||||||
}
|
}
|
||||||
dM := mat64.NewDense(sz, sz, data)
|
dM := mat.NewDense(sz, sz, data)
|
||||||
var sigma mat64.SymDense
|
var sigma mat.SymDense
|
||||||
sigma.SymOuterK(1, dM)
|
sigma.SymOuterK(1, dM)
|
||||||
|
|
||||||
normal, ok := NewNormal(mu, &sigma, nil)
|
normal, ok := NewNormal(mu, &sigma, nil)
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,14 +37,14 @@ func (Bhattacharyya) DistNormal(l, r *Normal) float64 {
|
|||||||
panic(badSizeMismatch)
|
panic(badSizeMismatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sigma mat64.SymDense
|
var sigma mat.SymDense
|
||||||
sigma.AddSym(&l.sigma, &r.sigma)
|
sigma.AddSym(&l.sigma, &r.sigma)
|
||||||
sigma.ScaleSym(0.5, &sigma)
|
sigma.ScaleSym(0.5, &sigma)
|
||||||
|
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
chol.Factorize(&sigma)
|
chol.Factorize(&sigma)
|
||||||
|
|
||||||
mahalanobis := stat.Mahalanobis(mat64.NewVector(dim, l.mu), mat64.NewVector(dim, r.mu), &chol)
|
mahalanobis := stat.Mahalanobis(mat.NewVector(dim, l.mu), mat.NewVector(dim, r.mu), &chol)
|
||||||
mahalanobisSq := mahalanobis * mahalanobis
|
mahalanobisSq := mahalanobis * mahalanobis
|
||||||
|
|
||||||
dl := l.chol.LogDet()
|
dl := l.chol.LogDet()
|
||||||
@@ -154,21 +154,21 @@ func (KullbackLeibler) DistNormal(l, r *Normal) float64 {
|
|||||||
panic(badSizeMismatch)
|
panic(badSizeMismatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
mahalanobis := stat.Mahalanobis(mat64.NewVector(dim, l.mu), mat64.NewVector(dim, r.mu), &r.chol)
|
mahalanobis := stat.Mahalanobis(mat.NewVector(dim, l.mu), mat.NewVector(dim, r.mu), &r.chol)
|
||||||
mahalanobisSq := mahalanobis * mahalanobis
|
mahalanobisSq := mahalanobis * mahalanobis
|
||||||
|
|
||||||
// TODO(btracey): Optimize where there is a SolveCholeskySym
|
// TODO(btracey): Optimize where there is a SolveCholeskySym
|
||||||
// TODO(btracey): There may be a more efficient way to just compute the trace
|
// TODO(btracey): There may be a more efficient way to just compute the trace
|
||||||
// Compute tr(Σ_r^-1*Σ_l) using the fact that Σ_l = U^T * U
|
// Compute tr(Σ_r^-1*Σ_l) using the fact that Σ_l = U^T * U
|
||||||
var u mat64.TriDense
|
var u mat.TriDense
|
||||||
u.UFromCholesky(&l.chol)
|
u.UFromCholesky(&l.chol)
|
||||||
var m mat64.Dense
|
var m mat.Dense
|
||||||
err := m.SolveCholesky(&r.chol, u.T())
|
err := m.SolveCholesky(&r.chol, u.T())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return math.NaN()
|
return math.NaN()
|
||||||
}
|
}
|
||||||
m.Mul(&m, &u)
|
m.Mul(&m, &u)
|
||||||
tr := mat64.Trace(&m)
|
tr := mat.Trace(&m)
|
||||||
|
|
||||||
return r.logSqrtDet - l.logSqrtDet + 0.5*(mahalanobisSq+tr-float64(l.dim))
|
return r.logSqrtDet - l.logSqrtDet + 0.5*(mahalanobisSq+tr-float64(l.dim))
|
||||||
}
|
}
|
||||||
@@ -233,20 +233,20 @@ func (Wasserstein) DistNormal(l, r *Normal) float64 {
|
|||||||
d = d * d
|
d = d * d
|
||||||
|
|
||||||
// Compute Σ_l^(1/2)
|
// Compute Σ_l^(1/2)
|
||||||
var ssl mat64.SymDense
|
var ssl mat.SymDense
|
||||||
ssl.PowPSD(&l.sigma, 0.5)
|
ssl.PowPSD(&l.sigma, 0.5)
|
||||||
// Compute Σ_l^(1/2)*Σ_r*Σ_l^(1/2)
|
// Compute Σ_l^(1/2)*Σ_r*Σ_l^(1/2)
|
||||||
var mean mat64.Dense
|
var mean mat.Dense
|
||||||
mean.Mul(&ssl, &r.sigma)
|
mean.Mul(&ssl, &r.sigma)
|
||||||
mean.Mul(&mean, &ssl)
|
mean.Mul(&mean, &ssl)
|
||||||
|
|
||||||
// Reinterpret as symdense, and take Σ^(1/2)
|
// Reinterpret as symdense, and take Σ^(1/2)
|
||||||
meanSym := mat64.NewSymDense(dim, mean.RawMatrix().Data)
|
meanSym := mat.NewSymDense(dim, mean.RawMatrix().Data)
|
||||||
ssl.PowPSD(meanSym, 0.5)
|
ssl.PowPSD(meanSym, 0.5)
|
||||||
|
|
||||||
tr := mat64.Trace(&r.sigma)
|
tr := mat.Trace(&r.sigma)
|
||||||
tl := mat64.Trace(&l.sigma)
|
tl := mat.Trace(&l.sigma)
|
||||||
tm := mat64.Trace(&ssl)
|
tm := mat.Trace(&ssl)
|
||||||
|
|
||||||
return d + tl + tr - 2*tm
|
return d + tl + tr - 2*tm
|
||||||
}
|
}
|
||||||
|
@@ -10,21 +10,21 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBhattacharyyaNormal(t *testing.T) {
|
func TestBhattacharyyaNormal(t *testing.T) {
|
||||||
for cas, test := range []struct {
|
for cas, test := range []struct {
|
||||||
am, bm []float64
|
am, bm []float64
|
||||||
ac, bc *mat64.SymDense
|
ac, bc *mat.SymDense
|
||||||
samples int
|
samples int
|
||||||
tol float64
|
tol float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
am: []float64{2, 3},
|
am: []float64{2, 3},
|
||||||
ac: mat64.NewSymDense(2, []float64{3, -1, -1, 2}),
|
ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}),
|
||||||
bm: []float64{-1, 1},
|
bm: []float64{-1, 1},
|
||||||
bc: mat64.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
||||||
samples: 100000,
|
samples: 100000,
|
||||||
tol: 1e-2,
|
tol: 1e-2,
|
||||||
},
|
},
|
||||||
@@ -105,15 +105,15 @@ func bhattacharyyaSample(dim, samples int, l RandLogProber, r LogProber) float64
|
|||||||
func TestCrossEntropyNormal(t *testing.T) {
|
func TestCrossEntropyNormal(t *testing.T) {
|
||||||
for cas, test := range []struct {
|
for cas, test := range []struct {
|
||||||
am, bm []float64
|
am, bm []float64
|
||||||
ac, bc *mat64.SymDense
|
ac, bc *mat.SymDense
|
||||||
samples int
|
samples int
|
||||||
tol float64
|
tol float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
am: []float64{2, 3},
|
am: []float64{2, 3},
|
||||||
ac: mat64.NewSymDense(2, []float64{3, -1, -1, 2}),
|
ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}),
|
||||||
bm: []float64{-1, 1},
|
bm: []float64{-1, 1},
|
||||||
bc: mat64.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
||||||
samples: 100000,
|
samples: 100000,
|
||||||
tol: 1e-2,
|
tol: 1e-2,
|
||||||
},
|
},
|
||||||
@@ -144,15 +144,15 @@ func TestCrossEntropyNormal(t *testing.T) {
|
|||||||
func TestHellingerNormal(t *testing.T) {
|
func TestHellingerNormal(t *testing.T) {
|
||||||
for cas, test := range []struct {
|
for cas, test := range []struct {
|
||||||
am, bm []float64
|
am, bm []float64
|
||||||
ac, bc *mat64.SymDense
|
ac, bc *mat.SymDense
|
||||||
samples int
|
samples int
|
||||||
tol float64
|
tol float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
am: []float64{2, 3},
|
am: []float64{2, 3},
|
||||||
ac: mat64.NewSymDense(2, []float64{3, -1, -1, 2}),
|
ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}),
|
||||||
bm: []float64{-1, 1},
|
bm: []float64{-1, 1},
|
||||||
bc: mat64.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
||||||
samples: 100000,
|
samples: 100000,
|
||||||
tol: 5e-1,
|
tol: 5e-1,
|
||||||
},
|
},
|
||||||
@@ -188,15 +188,15 @@ func TestHellingerNormal(t *testing.T) {
|
|||||||
func TestKullbackLeiblerNormal(t *testing.T) {
|
func TestKullbackLeiblerNormal(t *testing.T) {
|
||||||
for cas, test := range []struct {
|
for cas, test := range []struct {
|
||||||
am, bm []float64
|
am, bm []float64
|
||||||
ac, bc *mat64.SymDense
|
ac, bc *mat.SymDense
|
||||||
samples int
|
samples int
|
||||||
tol float64
|
tol float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
am: []float64{2, 3},
|
am: []float64{2, 3},
|
||||||
ac: mat64.NewSymDense(2, []float64{3, -1, -1, 2}),
|
ac: mat.NewSymDense(2, []float64{3, -1, -1, 2}),
|
||||||
bm: []float64{-1, 1},
|
bm: []float64{-1, 1},
|
||||||
bc: mat64.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
bc: mat.NewSymDense(2, []float64{1.5, 0.2, 0.2, 0.9}),
|
||||||
samples: 10000,
|
samples: 10000,
|
||||||
tol: 1e-2,
|
tol: 1e-2,
|
||||||
},
|
},
|
||||||
|
@@ -12,7 +12,7 @@ import (
|
|||||||
"golang.org/x/tools/container/intsets"
|
"golang.org/x/tools/container/intsets"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat/distuv"
|
"gonum.org/v1/gonum/stat/distuv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,10 +35,10 @@ type StudentsT struct {
|
|||||||
mu []float64
|
mu []float64
|
||||||
src *rand.Rand
|
src *rand.Rand
|
||||||
|
|
||||||
sigma mat64.SymDense // only stored if needed
|
sigma mat.SymDense // only stored if needed
|
||||||
|
|
||||||
chol mat64.Cholesky
|
chol mat.Cholesky
|
||||||
lower mat64.TriDense
|
lower mat.TriDense
|
||||||
logSqrtDet float64
|
logSqrtDet float64
|
||||||
dim int
|
dim int
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ type StudentsT struct {
|
|||||||
//
|
//
|
||||||
// NewStudentsT panics if len(mu) == 0, or if len(mu) != sigma.Symmetric(). If
|
// NewStudentsT panics if len(mu) == 0, or if len(mu) != sigma.Symmetric(). If
|
||||||
// the covariance matrix is not positive-definite, nil is returned and ok is false.
|
// the covariance matrix is not positive-definite, nil is returned and ok is false.
|
||||||
func NewStudentsT(mu []float64, sigma mat64.Symmetric, nu float64, src *rand.Rand) (dist *StudentsT, ok bool) {
|
func NewStudentsT(mu []float64, sigma mat.Symmetric, nu float64, src *rand.Rand) (dist *StudentsT, ok bool) {
|
||||||
if len(mu) == 0 {
|
if len(mu) == 0 {
|
||||||
panic(badZeroDimension)
|
panic(badZeroDimension)
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ func NewStudentsT(mu []float64, sigma mat64.Symmetric, nu float64, src *rand.Ran
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
s.sigma = *mat64.NewSymDense(dim, nil)
|
s.sigma = *mat.NewSymDense(dim, nil)
|
||||||
s.sigma.CopySym(sigma)
|
s.sigma.CopySym(sigma)
|
||||||
s.lower.LFromCholesky(&s.chol)
|
s.lower.LFromCholesky(&s.chol)
|
||||||
s.logSqrtDet = 0.5 * s.chol.LogDet()
|
s.logSqrtDet = 0.5 * s.chol.LogDet()
|
||||||
@@ -113,7 +113,7 @@ func (s *StudentsT) ConditionStudentsT(observed []int, values []float64, src *ra
|
|||||||
// studentsTConditional updates a Student's T distribution based on the observed samples
|
// studentsTConditional updates a Student's T distribution based on the observed samples
|
||||||
// (see documentation for the public function). The Gaussian conditional update
|
// (see documentation for the public function). The Gaussian conditional update
|
||||||
// is treated as a special case when nu == math.Inf(1).
|
// is treated as a special case when nu == math.Inf(1).
|
||||||
func studentsTConditional(observed []int, values []float64, nu float64, mu []float64, sigma mat64.Symmetric) (newNu float64, newMean []float64, newSigma *mat64.SymDense) {
|
func studentsTConditional(observed []int, values []float64, nu float64, mu []float64, sigma mat.Symmetric) (newNu float64, newMean []float64, newSigma *mat.SymDense) {
|
||||||
dim := len(mu)
|
dim := len(mu)
|
||||||
ob := len(observed)
|
ob := len(observed)
|
||||||
|
|
||||||
@@ -133,11 +133,11 @@ func studentsTConditional(observed []int, values []float64, nu float64, mu []flo
|
|||||||
mu2[i] = values[i] - mu[v]
|
mu2[i] = values[i] - mu[v]
|
||||||
}
|
}
|
||||||
|
|
||||||
var sigma11, sigma22 mat64.SymDense
|
var sigma11, sigma22 mat.SymDense
|
||||||
sigma11.SubsetSym(sigma, unobserved)
|
sigma11.SubsetSym(sigma, unobserved)
|
||||||
sigma22.SubsetSym(sigma, observed)
|
sigma22.SubsetSym(sigma, observed)
|
||||||
|
|
||||||
sigma21 := mat64.NewDense(ob, unob, nil)
|
sigma21 := mat.NewDense(ob, unob, nil)
|
||||||
for i, r := range observed {
|
for i, r := range observed {
|
||||||
for j, c := range unobserved {
|
for j, c := range unobserved {
|
||||||
v := sigma.At(r, c)
|
v := sigma.At(r, c)
|
||||||
@@ -145,15 +145,15 @@ func studentsTConditional(observed []int, values []float64, nu float64, mu []flo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var chol mat64.Cholesky
|
var chol mat.Cholesky
|
||||||
ok := chol.Factorize(&sigma22)
|
ok := chol.Factorize(&sigma22)
|
||||||
if !ok {
|
if !ok {
|
||||||
return math.NaN(), nil, nil
|
return math.NaN(), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute mu_1 + sigma_{2,1}^T * sigma_{2,2}^-1 (v - mu_2).
|
// Compute mu_1 + sigma_{2,1}^T * sigma_{2,2}^-1 (v - mu_2).
|
||||||
v := mat64.NewVector(ob, mu2)
|
v := mat.NewVector(ob, mu2)
|
||||||
var tmp, tmp2 mat64.Vector
|
var tmp, tmp2 mat.Vector
|
||||||
err := tmp.SolveCholeskyVec(&chol, v)
|
err := tmp.SolveCholeskyVec(&chol, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return math.NaN(), nil, nil
|
return math.NaN(), nil, nil
|
||||||
@@ -166,7 +166,7 @@ func studentsTConditional(observed []int, values []float64, nu float64, mu []flo
|
|||||||
|
|
||||||
// Compute tmp4 = sigma_{2,1}^T * sigma_{2,2}^-1 * sigma_{2,1}.
|
// Compute tmp4 = sigma_{2,1}^T * sigma_{2,2}^-1 * sigma_{2,1}.
|
||||||
// TODO(btracey): Should this be a method of SymDense?
|
// TODO(btracey): Should this be a method of SymDense?
|
||||||
var tmp3, tmp4 mat64.Dense
|
var tmp3, tmp4 mat.Dense
|
||||||
err = tmp3.SolveCholesky(&chol, sigma21)
|
err = tmp3.SolveCholesky(&chol, sigma21)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return math.NaN(), nil, nil
|
return math.NaN(), nil, nil
|
||||||
@@ -189,7 +189,7 @@ func studentsTConditional(observed []int, values []float64, nu float64, mu []flo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute beta = (v - mu_2)^T * sigma_{2,2}^-1 * (v - mu_2)^T
|
// Compute beta = (v - mu_2)^T * sigma_{2,2}^-1 * (v - mu_2)^T
|
||||||
beta := mat64.Dot(v, &tmp)
|
beta := mat.Dot(v, &tmp)
|
||||||
|
|
||||||
// Scale the covariance matrix
|
// Scale the covariance matrix
|
||||||
sigma11.ScaleSym((nu+beta)/(nu+float64(ob)), &sigma11)
|
sigma11.ScaleSym((nu+beta)/(nu+float64(ob)), &sigma11)
|
||||||
@@ -221,9 +221,9 @@ func findUnob(observed []int, dim int) (unobserved []int) {
|
|||||||
// covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
|
// covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
|
||||||
// If the input matrix is nil a new matrix is allocated, otherwise the result
|
// If the input matrix is nil a new matrix is allocated, otherwise the result
|
||||||
// is stored in-place into the input.
|
// is stored in-place into the input.
|
||||||
func (st *StudentsT) CovarianceMatrix(s *mat64.SymDense) *mat64.SymDense {
|
func (st *StudentsT) CovarianceMatrix(s *mat.SymDense) *mat.SymDense {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
s = mat64.NewSymDense(st.dim, nil)
|
s = mat.NewSymDense(st.dim, nil)
|
||||||
}
|
}
|
||||||
sn := s.Symmetric()
|
sn := s.Symmetric()
|
||||||
if sn != st.dim {
|
if sn != st.dim {
|
||||||
@@ -256,12 +256,12 @@ func (s *StudentsT) LogProb(y []float64) float64 {
|
|||||||
copy(shift, y)
|
copy(shift, y)
|
||||||
floats.Sub(shift, s.mu)
|
floats.Sub(shift, s.mu)
|
||||||
|
|
||||||
x := mat64.NewVector(s.dim, shift)
|
x := mat.NewVector(s.dim, shift)
|
||||||
|
|
||||||
var tmp mat64.Vector
|
var tmp mat.Vector
|
||||||
tmp.SolveCholeskyVec(&s.chol, x)
|
tmp.SolveCholeskyVec(&s.chol, x)
|
||||||
|
|
||||||
dot := mat64.Dot(&tmp, x)
|
dot := mat.Dot(&tmp, x)
|
||||||
|
|
||||||
return t1 - ((nu+n)/2)*math.Log(1+dot/nu)
|
return t1 - ((nu+n)/2)*math.Log(1+dot/nu)
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,7 @@ func (s *StudentsT) MarginalStudentsT(vars []int, src *rand.Rand) (dist *Student
|
|||||||
for i, v := range vars {
|
for i, v := range vars {
|
||||||
newMean[i] = s.mu[v]
|
newMean[i] = s.mu[v]
|
||||||
}
|
}
|
||||||
var newSigma mat64.SymDense
|
var newSigma mat.SymDense
|
||||||
newSigma.SubsetSym(&s.sigma, vars)
|
newSigma.SubsetSym(&s.sigma, vars)
|
||||||
return NewStudentsT(newMean, &newSigma, s.nu, src)
|
return NewStudentsT(newMean, &newSigma, s.nu, src)
|
||||||
}
|
}
|
||||||
@@ -342,8 +342,8 @@ func (s *StudentsT) Rand(x []float64) []float64 {
|
|||||||
tmp[i] = s.src.NormFloat64()
|
tmp[i] = s.src.NormFloat64()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xVec := mat64.NewVector(s.dim, x)
|
xVec := mat.NewVector(s.dim, x)
|
||||||
tmpVec := mat64.NewVector(s.dim, tmp)
|
tmpVec := mat.NewVector(s.dim, tmp)
|
||||||
xVec.MulVec(&s.lower, tmpVec)
|
xVec.MulVec(&s.lower, tmpVec)
|
||||||
|
|
||||||
u := distuv.ChiSquared{K: s.nu, Src: s.src}.Rand()
|
u := distuv.ChiSquared{K: s.nu, Src: s.src}.Rand()
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
"gonum.org/v1/gonum/matrix/mat64"
|
"gonum.org/v1/gonum/mat"
|
||||||
"gonum.org/v1/gonum/stat"
|
"gonum.org/v1/gonum/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ func TestStudentTProbs(t *testing.T) {
|
|||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
nu float64
|
nu float64
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
|
|
||||||
x [][]float64
|
x [][]float64
|
||||||
probs []float64
|
probs []float64
|
||||||
@@ -27,7 +27,7 @@ func TestStudentTProbs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
nu: 3,
|
nu: 3,
|
||||||
mu: []float64{0, 0},
|
mu: []float64{0, 0},
|
||||||
sigma: mat64.NewSymDense(2, []float64{1, 0, 0, 1}),
|
sigma: mat.NewSymDense(2, []float64{1, 0, 0, 1}),
|
||||||
|
|
||||||
x: [][]float64{
|
x: [][]float64{
|
||||||
{0, 0},
|
{0, 0},
|
||||||
@@ -46,7 +46,7 @@ func TestStudentTProbs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
nu: 4,
|
nu: 4,
|
||||||
mu: []float64{2, -3},
|
mu: []float64{2, -3},
|
||||||
sigma: mat64.NewSymDense(2, []float64{8, -1, -1, 5}),
|
sigma: mat.NewSymDense(2, []float64{8, -1, -1, 5}),
|
||||||
|
|
||||||
x: [][]float64{
|
x: [][]float64{
|
||||||
{0, 0},
|
{0, 0},
|
||||||
@@ -87,25 +87,25 @@ func TestStudentsTRand(t *testing.T) {
|
|||||||
src := rand.New(rand.NewSource(1))
|
src := rand.New(rand.NewSource(1))
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mean []float64
|
mean []float64
|
||||||
cov *mat64.SymDense
|
cov *mat.SymDense
|
||||||
nu float64
|
nu float64
|
||||||
tolcov float64
|
tolcov float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mean: []float64{0, 0},
|
mean: []float64{0, 0},
|
||||||
cov: mat64.NewSymDense(2, []float64{1, 0, 0, 1}),
|
cov: mat.NewSymDense(2, []float64{1, 0, 0, 1}),
|
||||||
nu: 3,
|
nu: 3,
|
||||||
tolcov: 1e-2,
|
tolcov: 1e-2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mean: []float64{3, 4},
|
mean: []float64{3, 4},
|
||||||
cov: mat64.NewSymDense(2, []float64{5, 1.2, 1.2, 6}),
|
cov: mat.NewSymDense(2, []float64{5, 1.2, 1.2, 6}),
|
||||||
nu: 8,
|
nu: 8,
|
||||||
tolcov: 1e-2,
|
tolcov: 1e-2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mean: []float64{3, 4, -2},
|
mean: []float64{3, 4, -2},
|
||||||
cov: mat64.NewSymDense(3, []float64{5, 1.2, -0.8, 1.2, 6, 0.4, -0.8, 0.4, 2}),
|
cov: mat.NewSymDense(3, []float64{5, 1.2, -0.8, 1.2, 6, 0.4, -0.8, 0.4, 2}),
|
||||||
nu: 8,
|
nu: 8,
|
||||||
tolcov: 1e-2,
|
tolcov: 1e-2,
|
||||||
},
|
},
|
||||||
@@ -116,13 +116,13 @@ func TestStudentsTRand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
nSamples := 10000000
|
nSamples := 10000000
|
||||||
dim := len(test.mean)
|
dim := len(test.mean)
|
||||||
samps := mat64.NewDense(nSamples, dim, nil)
|
samps := mat.NewDense(nSamples, dim, nil)
|
||||||
for i := 0; i < nSamples; i++ {
|
for i := 0; i < nSamples; i++ {
|
||||||
s.Rand(samps.RawRowView(i))
|
s.Rand(samps.RawRowView(i))
|
||||||
}
|
}
|
||||||
estMean := make([]float64, dim)
|
estMean := make([]float64, dim)
|
||||||
for i := range estMean {
|
for i := range estMean {
|
||||||
estMean[i] = stat.Mean(mat64.Col(nil, i, samps), nil)
|
estMean[i] = stat.Mean(mat.Col(nil, i, samps), nil)
|
||||||
}
|
}
|
||||||
mean := s.Mean(nil)
|
mean := s.Mean(nil)
|
||||||
if !floats.EqualApprox(estMean, mean, 1e-2) {
|
if !floats.EqualApprox(estMean, mean, 1e-2) {
|
||||||
@@ -130,7 +130,7 @@ func TestStudentsTRand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
cov := s.CovarianceMatrix(nil)
|
cov := s.CovarianceMatrix(nil)
|
||||||
estCov := stat.CovarianceMatrix(nil, samps, nil)
|
estCov := stat.CovarianceMatrix(nil, samps, nil)
|
||||||
if !mat64.EqualApprox(estCov, cov, test.tolcov) {
|
if !mat.EqualApprox(estCov, cov, test.tolcov) {
|
||||||
t.Errorf("Cov mismatch: want: %v, got %v", cov, estCov)
|
t.Errorf("Cov mismatch: want: %v, got %v", cov, estCov)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ func TestStudentsTConditional(t *testing.T) {
|
|||||||
src := rand.New(rand.NewSource(1))
|
src := rand.New(rand.NewSource(1))
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mean []float64
|
mean []float64
|
||||||
cov *mat64.SymDense
|
cov *mat.SymDense
|
||||||
nu float64
|
nu float64
|
||||||
|
|
||||||
idx []int
|
idx []int
|
||||||
@@ -149,7 +149,7 @@ func TestStudentsTConditional(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mean: []float64{3, 4, -2},
|
mean: []float64{3, 4, -2},
|
||||||
cov: mat64.NewSymDense(3, []float64{5, 1.2, -0.8, 1.2, 6, 0.4, -0.8, 0.4, 2}),
|
cov: mat.NewSymDense(3, []float64{5, 1.2, -0.8, 1.2, 6, 0.4, -0.8, 0.4, 2}),
|
||||||
nu: 8,
|
nu: 8,
|
||||||
idx: []int{0},
|
idx: []int{0},
|
||||||
value: []float64{6},
|
value: []float64{6},
|
||||||
@@ -182,11 +182,11 @@ func TestStudentsTConditional(t *testing.T) {
|
|||||||
muOb[i] = test.mean[v]
|
muOb[i] = test.mean[v]
|
||||||
}
|
}
|
||||||
|
|
||||||
var sig11, sig22 mat64.SymDense
|
var sig11, sig22 mat.SymDense
|
||||||
sig11.SubsetSym(&s.sigma, unob)
|
sig11.SubsetSym(&s.sigma, unob)
|
||||||
sig22.SubsetSym(&s.sigma, ob)
|
sig22.SubsetSym(&s.sigma, ob)
|
||||||
|
|
||||||
sig12 := mat64.NewDense(len(unob), len(ob), nil)
|
sig12 := mat.NewDense(len(unob), len(ob), nil)
|
||||||
for i := range unob {
|
for i := range unob {
|
||||||
for j := range ob {
|
for j := range ob {
|
||||||
sig12.Set(i, j, s.sigma.At(unob[i], ob[j]))
|
sig12.Set(i, j, s.sigma.At(unob[i], ob[j]))
|
||||||
@@ -198,9 +198,9 @@ func TestStudentsTConditional(t *testing.T) {
|
|||||||
floats.Sub(shift, muOb)
|
floats.Sub(shift, muOb)
|
||||||
|
|
||||||
newMu := make([]float64, len(muUnob))
|
newMu := make([]float64, len(muUnob))
|
||||||
newMuVec := mat64.NewVector(len(muUnob), newMu)
|
newMuVec := mat.NewVector(len(muUnob), newMu)
|
||||||
shiftVec := mat64.NewVector(len(shift), shift)
|
shiftVec := mat.NewVector(len(shift), shift)
|
||||||
var tmp mat64.Vector
|
var tmp mat.Vector
|
||||||
tmp.SolveVec(&sig22, shiftVec)
|
tmp.SolveVec(&sig22, shiftVec)
|
||||||
newMuVec.MulVec(sig12, &tmp)
|
newMuVec.MulVec(sig12, &tmp)
|
||||||
floats.Add(newMu, muUnob)
|
floats.Add(newMu, muUnob)
|
||||||
@@ -209,16 +209,16 @@ func TestStudentsTConditional(t *testing.T) {
|
|||||||
t.Errorf("Mu mismatch. Got %v, want %v", sUp.mu, newMu)
|
t.Errorf("Mu mismatch. Got %v, want %v", sUp.mu, newMu)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tmp2 mat64.Dense
|
var tmp2 mat.Dense
|
||||||
tmp2.Solve(&sig22, sig12.T())
|
tmp2.Solve(&sig22, sig12.T())
|
||||||
|
|
||||||
var tmp3 mat64.Dense
|
var tmp3 mat.Dense
|
||||||
tmp3.Mul(sig12, &tmp2)
|
tmp3.Mul(sig12, &tmp2)
|
||||||
tmp3.Sub(&sig11, &tmp3)
|
tmp3.Sub(&sig11, &tmp3)
|
||||||
|
|
||||||
dot := mat64.Dot(shiftVec, &tmp)
|
dot := mat.Dot(shiftVec, &tmp)
|
||||||
tmp3.Scale((test.nu+dot)/(test.nu+float64(len(ob))), &tmp3)
|
tmp3.Scale((test.nu+dot)/(test.nu+float64(len(ob))), &tmp3)
|
||||||
if !mat64.EqualApprox(&tmp3, &sUp.sigma, 1e-10) {
|
if !mat.EqualApprox(&tmp3, &sUp.sigma, 1e-10) {
|
||||||
t.Errorf("Sigma mismatch")
|
t.Errorf("Sigma mismatch")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,17 +227,17 @@ func TestStudentsTConditional(t *testing.T) {
|
|||||||
func TestStudentsTMarginalSingle(t *testing.T) {
|
func TestStudentsTMarginalSingle(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mu []float64
|
mu []float64
|
||||||
sigma *mat64.SymDense
|
sigma *mat.SymDense
|
||||||
nu float64
|
nu float64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4},
|
mu: []float64{2, 3, 4},
|
||||||
sigma: mat64.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
sigma: mat.NewSymDense(3, []float64{2, 0.5, 3, 0.5, 1, 0.6, 3, 0.6, 10}),
|
||||||
nu: 5,
|
nu: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mu: []float64{2, 3, 4, 5},
|
mu: []float64{2, 3, 4, 5},
|
||||||
sigma: mat64.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
sigma: mat.NewSymDense(4, []float64{2, 0.5, 3, 0.1, 0.5, 1, 0.6, 0.2, 3, 0.6, 10, 0.3, 0.1, 0.2, 0.3, 3}),
|
||||||
nu: 6,
|
nu: 6,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user