Repository: skelterjohn/go.matrix
Branch: go1
Commit: daa59528eefd
Files: 25
Total size: 95.2 KB
Directory structure:
gitextract_v_1rg_cr/
├── AUTHORS
├── LICENSE
├── README
├── arithmetic.go
├── dense.go
├── dense_arithmetic.go
├── dense_basic.go
├── dense_data.go
├── dense_decomp.go
├── dense_eigen.go
├── dense_svd.go
├── dense_test.go
├── densebench_test.go
├── error.go
├── matrix.go
├── matrix_test.go
├── pivot.go
├── pivot_arithmetic.go
├── pivot_basic.go
├── pivot_test.go
├── sparse.go
├── sparse_arithmetic.go
├── sparse_basic.go
├── sparse_test.go
└── util.go
================================================
FILE CONTENTS
================================================
================================================
FILE: AUTHORS
================================================
John Asmuth <jasmuth@gmail.com>
Ryanne Dolan
================================================
FILE: LICENSE
================================================
Copyright (c) 2013 the AUTHORS. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* The names in AUTHORs may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README
================================================
================================================
FILE: arithmetic.go
================================================
// Copyright 2009 The GoMatrix 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
import "math"
/*
Finds the sum of two matrices.
*/
func Sum(A MatrixRO, Bs ...MatrixRO) (C *DenseMatrix) {
C = MakeDenseCopy(A)
var err error
for _, B := range Bs {
err = C.Add(MakeDenseCopy(B))
if err != nil {
break
}
}
if err != nil {
C = nil
}
return
}
/*
Finds the difference between two matrices.
*/
func Difference(A, B MatrixRO) (C *DenseMatrix) {
C = MakeDenseCopy(A)
err := C.Subtract(MakeDenseCopy(B))
if err != nil {
C = nil
}
return
}
/*
Finds the Product of two matrices.
*/
func Product(A MatrixRO, Bs ...MatrixRO) (C *DenseMatrix) {
C = MakeDenseCopy(A)
for _, B := range Bs {
Cm, err := C.Times(B)
if err != nil {
return
}
C = Cm.(*DenseMatrix)
}
return
}
func Transpose(A MatrixRO) (B Matrix) {
switch Am := A.(type) {
case *DenseMatrix:
B = Am.Transpose()
return
case *SparseMatrix:
B = Am.Transpose()
return
}
B = A.DenseMatrix().Transpose()
return
}
func Inverse(A MatrixRO) (B Matrix) {
var err error
switch Am := A.(type) {
case *DenseMatrix:
B, err = Am.Inverse()
if err != nil {
panic(err)
}
return
}
B, err = A.DenseMatrix().Inverse()
if err != nil {
panic(err)
}
return
}
/*
The Kronecker product. (http://en.wikipedia.org/wiki/Kronecker_product)
*/
func Kronecker(A, B MatrixRO) (C *DenseMatrix) {
ars, acs := A.Rows(), A.Cols()
brs, bcs := B.Rows(), B.Cols()
C = Zeros(ars*brs, acs*bcs)
for i := 0; i < ars; i++ {
for j := 0; j < acs; j++ {
Cij := C.GetMatrix(i*brs, j*bcs, brs, bcs)
Cij.SetMatrix(0, 0, Scaled(B, A.Get(i, j)))
}
}
return
}
func Vectorize(Am MatrixRO) (V *DenseMatrix) {
elems := Am.DenseMatrix().Transpose().Array()
V = MakeDenseMatrix(elems, Am.Rows()*Am.Cols(), 1)
return
}
func Unvectorize(V MatrixRO, rows, cols int) (A *DenseMatrix) {
A = MakeDenseMatrix(V.DenseMatrix().Array(), cols, rows).Transpose()
return
}
/*
Uses a number of goroutines to do the dot products necessary
for the matrix multiplication in parallel.
*/
func ParallelProduct(A, B MatrixRO) (C *DenseMatrix) {
if A.Cols() != B.Rows() {
return nil
}
C = Zeros(A.Rows(), B.Cols())
in := make(chan int)
quit := make(chan bool)
dotRowCol := func() {
for {
select {
case i := <-in:
sums := make([]float64, B.Cols())
for k := 0; k < A.Cols(); k++ {
for j := 0; j < B.Cols(); j++ {
sums[j] += A.Get(i, k) * B.Get(k, j)
}
}
for j := 0; j < B.Cols(); j++ {
C.Set(i, j, sums[j])
}
case <-quit:
return
}
}
}
threads := 2
for i := 0; i < threads; i++ {
go dotRowCol()
}
for i := 0; i < A.Rows(); i++ {
in <- i
}
for i := 0; i < threads; i++ {
quit <- true
}
return
}
/*
Scales a matrix by a scalar.
*/
func Scaled(A MatrixRO, f float64) (B *DenseMatrix) {
B = MakeDenseCopy(A)
B.Scale(f)
return
}
/*
Tests the element-wise equality of the two matrices.
*/
func Equals(A, B MatrixRO) bool {
if A.Rows() != B.Rows() || A.Cols() != B.Cols() {
return false
}
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if A.Get(i, j) != B.Get(i, j) {
return false
}
}
}
return true
}
/*
Tests to see if the difference between two matrices,
element-wise, exceeds ε.
*/
func ApproxEquals(A, B MatrixRO, ε float64) bool {
if A.Rows() != B.Rows() || A.Cols() != B.Cols() {
return false
}
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if math.Abs(A.Get(i, j)-B.Get(i, j)) > ε {
return false
}
}
}
return true
}
================================================
FILE: dense.go
================================================
// Copyright 2009 The GoMatrix 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
import (
"math/rand"
)
/*
A matrix backed by a flat array of all elements.
*/
type DenseMatrix struct {
matrix
// flattened matrix data. elements[i*step+j] is row i, col j
elements []float64
// actual offset between rows
step int
}
/*
Returns an array of slices referencing the matrix data. Changes to
the slices effect changes to the matrix.
*/
func (A *DenseMatrix) Arrays() [][]float64 {
a := make([][]float64, A.rows)
for i := 0; i < A.rows; i++ {
a[i] = A.elements[i*A.step : i*A.step+A.cols]
}
return a
}
/*
Returns the contents of this matrix stored into a flat array (row-major).
*/
func (A *DenseMatrix) Array() []float64 {
if A.step == A.rows {
return A.elements[0 : A.rows*A.cols]
}
a := make([]float64, A.rows*A.cols)
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
a[i*A.cols+j] = A.elements[i*A.step+j]
}
}
return a
}
func (A *DenseMatrix) rowSlice(row int) []float64 {
return A.elements[row*A.step : row*A.step+A.cols]
}
/*
Get the element in the ith row and jth column.
*/
func (A *DenseMatrix) Get(i int, j int) (v float64) {
/*
i = i % A.rows
if i < 0 {
i = A.rows - i
}
j = j % A.cols
if j < 0 {
j = A.cols - j
}
*/
// reslicing like this does efficient range checks, perhaps
v = A.elements[i*A.step : i*A.step+A.cols][j]
//v = A.elements[i*A.step+j]
return
}
/*
Set the element in the ith row and jth column to v.
*/
func (A *DenseMatrix) Set(i int, j int, v float64) {
/*
i = i % A.rows
if i < 0 {
i = A.rows - i
}
j = j % A.cols
if j < 0 {
j = A.cols - j
}
*/
// reslicing like this does efficient range checks, perhaps
A.elements[i*A.step : i*A.step+A.cols][j] = v
//A.elements[i*A.step+j] = v
}
/*
Get a submatrix starting at i,j with rows rows and cols columns. Changes to
the returned matrix show up in the original.
*/
func (A *DenseMatrix) GetMatrix(i, j, rows, cols int) *DenseMatrix {
B := new(DenseMatrix)
B.elements = A.elements[i*A.step+j : i*A.step+j+(rows-1)*A.step+cols]
B.rows = rows
B.cols = cols
B.step = A.step
return B
}
/*
Copy B into A, with B's 0, 0 aligning with A's i, j
*/
func (A *DenseMatrix) SetMatrix(i, j int, B *DenseMatrix) {
for r := 0; r < B.rows; r++ {
for c := 0; c < B.cols; c++ {
A.Set(i+r, j+c, B.Get(r, c))
}
}
}
func (A *DenseMatrix) GetColVector(j int) *DenseMatrix {
return A.GetMatrix(0, j, A.rows, 1)
}
func (A *DenseMatrix) GetRowVector(i int) *DenseMatrix {
return A.GetMatrix(i, 0, 1, A.cols)
}
/*
Get a copy of this matrix with 0s above the diagonal.
*/
func (A *DenseMatrix) L() *DenseMatrix {
B := A.Copy()
for i := 0; i < A.rows; i++ {
for j := i + 1; j < A.cols; j++ {
B.Set(i, j, 0)
}
}
return B
}
/*
Get a copy of this matrix with 0s below the diagonal.
*/
func (A *DenseMatrix) U() *DenseMatrix {
B := A.Copy()
for i := 0; i < A.rows; i++ {
for j := 0; j < i && j < A.cols; j++ {
B.Set(i, j, 0)
}
}
return B
}
func (A *DenseMatrix) Copy() *DenseMatrix {
B := new(DenseMatrix)
B.rows = A.rows
B.cols = A.cols
B.step = A.cols
B.elements = make([]float64, B.rows*B.cols)
for row := 0; row < B.rows; row++ {
copy(B.rowSlice(row), A.rowSlice(row))
}
return B
}
/*
Get a new matrix [A B].
*/
func (A *DenseMatrix) Augment(B *DenseMatrix) (C *DenseMatrix, err error) {
if A.rows != B.rows {
err = ErrorDimensionMismatch
return
}
C = Zeros(A.rows, A.cols+B.cols)
err = A.AugmentFill(B, C)
return
}
func (A *DenseMatrix) AugmentFill(B, C *DenseMatrix) (err error) {
if A.rows != B.rows || C.rows != A.rows || C.cols != A.cols+B.cols {
err = ErrorDimensionMismatch
return
}
C.SetMatrix(0, 0, A)
C.SetMatrix(0, A.cols, B)
/*
for i := 0; i < C.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
C.Set(i, j, A.Get(i, j))
}
for j := 0; j < B.Cols(); j++ {
C.Set(i, j+A.Cols(), B.Get(i, j))
}
}*/
return
}
/*
Get a new matrix [A; B], with A above B.
*/
func (A *DenseMatrix) Stack(B *DenseMatrix) (C *DenseMatrix, err error) {
if A.cols != B.cols {
err = ErrorDimensionMismatch
return
}
C = Zeros(A.rows+B.rows, A.cols)
err = A.StackFill(B, C)
return
}
func (A *DenseMatrix) StackFill(B, C *DenseMatrix) (err error) {
if A.cols != B.cols || C.cols != A.cols || C.rows != A.rows+B.rows {
err = ErrorDimensionMismatch
return
}
C.SetMatrix(0, 0, A)
C.SetMatrix(A.rows, 0, B)
/*
for j := 0; j < A.cols; j++ {
for i := 0; i < A.Rows(); i++ {
C.Set(i, j, A.Get(i, j))
}
for i := 0; i < B.cols; i++ {
C.Set(i+A.rows, j, B.Get(i, j))
}
}
*/
return
}
/*
Create a sparse matrix copy.
*/
func (A *DenseMatrix) SparseMatrix() *SparseMatrix {
B := ZerosSparse(A.rows, A.cols)
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
v := A.Get(i, j)
if v != 0 {
B.Set(i, j, v)
}
}
}
return B
}
func (A *DenseMatrix) DenseMatrix() *DenseMatrix {
return A.Copy()
}
func Zeros(rows, cols int) *DenseMatrix {
A := new(DenseMatrix)
A.elements = make([]float64, rows*cols)
A.rows = rows
A.cols = cols
A.step = cols
return A
}
func Ones(rows, cols int) *DenseMatrix {
A := new(DenseMatrix)
A.elements = make([]float64, rows*cols)
A.rows = rows
A.cols = cols
A.step = cols
for i := 0; i < len(A.elements); i++ {
A.elements[i] = 1
}
return A
}
func Numbers(rows, cols int, num float64) *DenseMatrix {
A := Zeros(rows, cols)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
A.Set(i, j, num)
}
}
return A
}
/*
Create an identity matrix with span rows and span columns.
*/
func Eye(span int) *DenseMatrix {
A := Zeros(span, span)
for i := 0; i < span; i++ {
A.Set(i, i, 1)
}
return A
}
func Normals(rows, cols int) *DenseMatrix {
A := Zeros(rows, cols)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
A.Set(i, j, rand.NormFloat64())
}
}
return A
}
func Diagonal(d []float64) *DenseMatrix {
n := len(d)
A := Zeros(n, n)
for i := 0; i < n; i++ {
A.Set(i, i, d[i])
}
return A
}
func MakeDenseCopy(A MatrixRO) *DenseMatrix {
B := Zeros(A.Rows(), A.Cols())
for i := 0; i < B.rows; i++ {
for j := 0; j < B.cols; j++ {
B.Set(i, j, A.Get(i, j))
}
}
return B
}
func MakeDenseMatrix(elements []float64, rows, cols int) *DenseMatrix {
A := new(DenseMatrix)
A.rows = rows
A.cols = cols
A.step = cols
A.elements = elements
return A
}
func MakeDenseMatrixStacked(data [][]float64) *DenseMatrix {
rows := len(data)
cols := len(data[0])
elements := make([]float64, rows*cols)
for i := 0; i < rows; i++ {
for j := 0; j < cols; j++ {
elements[i*cols+j] = data[i][j]
}
}
return MakeDenseMatrix(elements, rows, cols)
}
func (A *DenseMatrix) String() string { return String(A) }
================================================
FILE: dense_arithmetic.go
================================================
// Copyright 2009 The GoMatrix 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
import "runtime"
func (A *DenseMatrix) Plus(B MatrixRO) (Matrix, error) {
C := A.Copy()
err := C.Add(B)
return C, err
}
func (A *DenseMatrix) PlusDense(B *DenseMatrix) (*DenseMatrix, error) {
C := A.Copy()
err := C.AddDense(B)
return C, err
}
func (A *DenseMatrix) Minus(B MatrixRO) (Matrix, error) {
C := A.Copy()
err := C.Subtract(B)
return C, err
}
func (A *DenseMatrix) MinusDense(B *DenseMatrix) (*DenseMatrix, error) {
C := A.Copy()
err := C.SubtractDense(B)
return C, err
}
func (A *DenseMatrix) Add(B MatrixRO) error {
if A.cols != B.Cols() || A.rows != B.Rows() {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
index := i * A.step
for j := 0; j < A.cols; j++ {
A.elements[index] += B.Get(i, j)
index++
}
}
return nil
}
func (A *DenseMatrix) AddDense(B *DenseMatrix) error {
if A.cols != B.cols || A.rows != B.rows {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
A.elements[i*A.step+j] += B.elements[i*B.step+j]
}
}
return nil
}
func (A *DenseMatrix) Subtract(B MatrixRO) error {
if Bd, ok := B.(*DenseMatrix); ok {
return A.SubtractDense(Bd)
}
if A.cols != B.Cols() || A.rows != B.Rows() {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
index := i * A.step
for j := 0; j < A.cols; j++ {
A.elements[index] -= B.Get(i, j)
index++
}
}
return nil
}
func (A *DenseMatrix) SubtractDense(B *DenseMatrix) error {
if A.cols != B.cols || A.rows != B.rows {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
indexA := i * A.step
indexB := i * B.step
for j := 0; j < A.cols; j++ {
A.elements[indexA] -= B.elements[indexB]
indexA++
indexB++
}
}
return nil
}
func (A *DenseMatrix) Times(B MatrixRO) (Matrix, error) {
if Bd, ok := B.(*DenseMatrix); ok {
return A.TimesDense(Bd)
}
if A.cols != B.Rows() {
return nil, ErrorDimensionMismatch
}
C := Zeros(A.rows, B.Cols())
for i := 0; i < A.rows; i++ {
for j := 0; j < B.Cols(); j++ {
sum := float64(0)
for k := 0; k < A.cols; k++ {
sum += A.elements[i*A.step+k] * B.Get(k, j)
}
C.elements[i*C.step+j] = sum
}
}
return C, nil
}
type parJob struct {
start, finish int
}
func parTimes1(A, B, C *DenseMatrix) {
C = Zeros(A.rows, B.cols)
mp := runtime.GOMAXPROCS(0)
jobChan := make(chan box, 1+mp)
go func() {
rowCount := A.rows / mp
for startRow := 0; startRow < A.rows; startRow += rowCount {
start := startRow
finish := startRow + rowCount
if finish >= A.rows {
finish = A.rows
}
jobChan <- parJob{start: start, finish: finish}
}
close(jobChan)
}()
wait := parFor(jobChan, func(iBox box) {
job := iBox.(parJob)
for i := job.start; i < job.finish; i++ {
sums := C.elements[i*C.step : (i+1)*C.step]
for k := 0; k < A.cols; k++ {
for j := 0; j < B.cols; j++ {
sums[j] += A.elements[i*A.step+k] * B.elements[k*B.step+j]
}
}
}
})
wait()
return
}
//this is an adaptation of code from a go-nuts post made by Dmitriy Vyukov
func parTimes2(A, B, C *DenseMatrix) {
const threshold = 8
currentGoroutineCount := 1
maxGoroutines := runtime.GOMAXPROCS(0) + 2
var aux func(sync chan bool, A, B, C *DenseMatrix, rs, re, cs, ce, ks, ke int)
aux = func(sync chan bool, A, B, C *DenseMatrix, rs, re, cs, ce, ks, ke int) {
dr := re - rs
dc := ce - cs
dk := ke - ks
switch {
case currentGoroutineCount < maxGoroutines && dr >= dc && dr >= dk && dr >= threshold:
sync0 := make(chan bool, 1)
rm := (rs + re) / 2
currentGoroutineCount++
go aux(sync0, A, B, C, rs, rm, cs, ce, ks, ke)
aux(nil, A, B, C, rm, re, cs, ce, ks, ke)
<-sync0
currentGoroutineCount--
case currentGoroutineCount < maxGoroutines && dc >= dk && dc >= dr && dc >= threshold:
sync0 := make(chan bool, 1)
cm := (cs + ce) / 2
currentGoroutineCount++
go aux(sync0, A, B, C, rs, re, cs, cm, ks, ke)
aux(nil, A, B, C, rs, re, cm, ce, ks, ke)
<-sync0
currentGoroutineCount--
case currentGoroutineCount < maxGoroutines && dk >= dc && dk >= dr && dk >= threshold:
km := (ks + ke) / 2
aux(nil, A, B, C, rs, re, cs, ce, ks, km)
aux(nil, A, B, C, rs, re, cs, ce, km, ke)
default:
for row := rs; row < re; row++ {
sums := C.elements[row*C.step : (row+1)*C.step]
for k := ks; k < ke; k++ {
for col := cs; col < ce; col++ {
sums[col] += A.elements[row*A.step+k] * B.elements[k*B.step+col]
}
}
}
}
if sync != nil {
sync <- true
}
}
aux(nil, A, B, C, 0, A.rows, 0, B.cols, 0, A.cols)
return
}
var (
WhichParMethod = 2
WhichSyncMethod = 1
)
func (A *DenseMatrix) TimesDense(B *DenseMatrix) (C *DenseMatrix, err error) {
C = Zeros(A.rows, B.cols)
err = A.TimesDenseFill(B, C)
return
}
func (A *DenseMatrix) TimesDenseFill(B, C *DenseMatrix) (err error) {
if C.rows != A.rows || C.cols != B.cols || A.cols != B.rows {
err = ErrorDimensionMismatch
return
}
if WhichParMethod > 0 && runtime.GOMAXPROCS(0) > 1 {
switch WhichParMethod {
case 1:
parTimes1(A, B, C)
case 2:
parTimes2(A, B, C)
}
} else {
switch {
case A.cols > 100 && WhichSyncMethod == 2:
transposeTimes(A, B, C)
default:
for i := 0; i < A.rows; i++ {
sums := C.elements[i*C.step : (i+1)*C.step]
for k, a := range A.elements[i*A.step : i*A.step + A.cols] {
for j, b := range B.elements[k*B.step : k * B.step + B.cols] {
sums[j] += a * b
}
}
}
}
}
return
}
func transposeTimes(A, B, C *DenseMatrix) {
Bt := B.Transpose()
Bcols := Bt.Arrays()
for i := 0; i < A.rows; i++ {
Arow := A.elements[i*A.step : i*A.step+A.cols]
for j := 0; j < B.cols; j++ {
Bcol := Bcols[j]
for k := range Arow {
C.elements[i*C.step+j] += Arow[k] * Bcol[k]
}
}
}
return
}
func (A *DenseMatrix) ElementMult(B MatrixRO) (Matrix, error) {
C := A.Copy()
err := C.ScaleMatrix(B)
return C, err
}
func (A *DenseMatrix) ElementMultDense(B *DenseMatrix) (*DenseMatrix, error) {
C := A.Copy()
err := C.ScaleMatrixDense(B)
return C, err
}
func (A *DenseMatrix) Scale(f float64) {
for i := 0; i < A.rows; i++ {
index := i * A.step
for j := 0; j < A.cols; j++ {
A.elements[index] *= f
index++
}
}
}
func (A *DenseMatrix) ScaleMatrix(B MatrixRO) error {
if Bd, ok := B.(*DenseMatrix); ok {
return A.ScaleMatrixDense(Bd)
}
if A.rows != B.Rows() || A.cols != B.Cols() {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
indexA := i * A.step
for j := 0; j < A.cols; j++ {
A.elements[indexA] *= B.Get(i, j)
indexA++
}
}
return nil
}
func (A *DenseMatrix) ScaleMatrixDense(B *DenseMatrix) error {
if A.rows != B.rows || A.cols != B.cols {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
indexA := i * A.step
indexB := i * B.step
for j := 0; j < A.cols; j++ {
A.elements[indexA] *= B.elements[indexB]
indexA++
indexB++
}
}
return nil
}
================================================
FILE: dense_basic.go
================================================
// Copyright 2009 The GoMatrix 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
import (
"math"
"errors"
)
func (A *DenseMatrix) Symmetric() bool {
if A.rows != A.cols {
return false
}
for i := 0; i < A.rows; i++ {
for j := 0; j < i; j++ {
if A.Get(i, j) != A.Get(j, i) {
return false
}
}
}
return true
}
func (m *DenseMatrix) SwapRows(r1 int, r2 int) {
index1 := r1 * m.step
index2 := r2 * m.step
for j := 0; j < m.cols; j++ {
m.elements[index1], m.elements[index2] = m.elements[index2], m.elements[index1]
index1++
index2++
}
}
func (m *DenseMatrix) ScaleRow(r int, f float64) {
index := r * m.step
for j := 0; j < m.cols; j++ {
m.elements[index] *= f
index++
}
}
func (m *DenseMatrix) ScaleAddRow(rd int, rs int, f float64) {
indexd := rd * m.step
indexs := rs * m.step
for j := 0; j < m.cols; j++ {
m.elements[indexd] += f * m.elements[indexs]
indexd++
indexs++
}
}
func (A *DenseMatrix) Inverse() (*DenseMatrix, error) {
if A.Rows() != A.Cols() {
return nil, ErrorDimensionMismatch
}
aug, _ := A.Augment(Eye(A.Rows()))
for i := 0; i < aug.Rows(); i++ {
j := i
for k := i; k < aug.Rows(); k++ {
if math.Abs(aug.Get(k, i)) > math.Abs(aug.Get(j, i)) {
j = k
}
}
if j != i {
aug.SwapRows(i, j)
}
if aug.Get(i, i) == 0 {
return nil, ExceptionSingular
}
aug.ScaleRow(i, 1.0/aug.Get(i, i))
for k := 0; k < aug.Rows(); k++ {
if k == i {
continue
}
aug.ScaleAddRow(k, i, -aug.Get(k, i))
}
}
inv := aug.GetMatrix(0, A.Cols(), A.Rows(), A.Cols())
return inv, nil
}
func (A *DenseMatrix) Det() float64 {
B := A.Copy()
P := B.LUInPlace()
return product(B.DiagonalCopy()) * P.Det()
}
func (A *DenseMatrix) Trace() float64 { return sum(A.DiagonalCopy()) }
func (A *DenseMatrix) OneNorm() (ε float64) {
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
ε = max(ε, A.Get(i, j))
}
}
return
}
func (A *DenseMatrix) TwoNorm() float64 {
var sum float64 = 0
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
v := A.elements[i*A.step+j]
sum += v * v
}
}
return math.Sqrt(sum)
}
func (A *DenseMatrix) InfinityNorm() (ε float64) {
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
ε += A.Get(i, j)
}
}
return
}
func (A *DenseMatrix) Transpose() *DenseMatrix {
B := Zeros(A.Cols(), A.Rows())
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
B.Set(j, i, A.Get(i, j))
}
}
return B
}
func (A *DenseMatrix) TransposeInPlace() (err error) {
if A.rows != A.cols {
err = errors.New("Can only transpose a square matrix in place")
return
}
for i := 0; i < A.rows; i++ {
for j := 0; j < i; j++ {
tmp := A.Get(i, j)
A.Set(i, j, A.Get(j, i))
A.Set(j, i, tmp)
}
}
return
}
func solveLower(A *DenseMatrix, b Matrix) *DenseMatrix {
x := make([]float64, A.Cols())
for i := 0; i < A.Rows(); i++ {
x[i] = b.Get(i, 0)
for j := 0; j < i; j++ {
x[i] -= x[j] * A.Get(i, j)
}
//the diagonal defined to be ones
//x[i] /= A.Get(i, i);
}
return MakeDenseMatrix(x, A.Cols(), 1)
}
func solveUpper(A *DenseMatrix, b Matrix) *DenseMatrix {
x := make([]float64, A.Cols())
for i := A.Rows() - 1; i >= 0; i-- {
x[i] = b.Get(i, 0)
for j := i + 1; j < A.Cols(); j++ {
x[i] -= x[j] * A.Get(i, j)
}
x[i] /= A.Get(i, i)
}
return MakeDenseMatrix(x, A.Cols(), 1)
}
func (A *DenseMatrix) Solve(b MatrixRO) (*DenseMatrix, error) {
Acopy := A.Copy()
P := Acopy.LUInPlace()
Pinv := P.Inverse()
pb, err := Pinv.Times(b)
if !(err == nil) {
return nil, err
}
y := solveLower(Acopy, pb)
x := solveUpper(Acopy, y)
return x, nil
}
func (A *DenseMatrix) SolveDense(b *DenseMatrix) (*DenseMatrix, error) {
return A.Solve(b)
}
================================================
FILE: dense_data.go
================================================
// Copyright 2009 The GoMatrix 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
//returns a copy of the row (not a slice)
func (A *DenseMatrix) RowCopy(i int) []float64 {
row := make([]float64, A.cols)
for j := 0; j < A.cols; j++ {
row[j] = A.Get(i, j)
}
return row
}
//returns a copy of the column (not a slice)
func (A *DenseMatrix) ColCopy(j int) []float64 {
col := make([]float64, A.rows)
for i := 0; i < A.rows; i++ {
col[i] = A.Get(i, j)
}
return col
}
//returns a copy of the diagonal (not a slice)
func (A *DenseMatrix) DiagonalCopy() []float64 {
span := A.rows
if A.cols < span {
span = A.cols
}
diag := make([]float64, span)
for i := 0; i < span; i++ {
diag[i] = A.Get(i, i)
}
return diag
}
func (A *DenseMatrix) BufferRow(i int, buf []float64) {
for j := 0; j < A.cols; j++ {
buf[j] = A.Get(i, j)
}
}
func (A *DenseMatrix) BufferCol(j int, buf []float64) {
for i := 0; i < A.rows; i++ {
buf[i] = A.Get(i, j)
}
}
func (A *DenseMatrix) BufferDiagonal(buf []float64) {
for i := 0; i < A.rows && i < A.cols; i++ {
buf[i] = A.Get(i, i)
}
}
func (A *DenseMatrix) FillRow(i int, buf []float64) {
for j := 0; j < A.cols; j++ {
A.Set(i, j, buf[j])
}
}
func (A *DenseMatrix) FillCol(j int, buf []float64) {
for i := 0; i < A.rows; i++ {
A.Set(i, j, buf[i])
}
}
func (A *DenseMatrix) FillDiagonal(buf []float64) {
for i := 0; i < A.rows && i < A.cols; i++ {
A.Set(i, i, buf[i])
}
}
================================================
FILE: dense_decomp.go
================================================
// Copyright 2009 The GoMatrix 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
import "math"
/*
Returns the cholesky decomposition C of A, st CC'=A.
*/
func (A *DenseMatrix) Cholesky() (L *DenseMatrix, err error) {
n := A.Rows()
L = Zeros(n, n)
isspd := A.Cols() == n
for j := 0; j < n; j++ {
Lrowj := L.RowCopy(j)
d := float64(0)
for k := 0; k < j; k++ {
Lrowk := L.RowCopy(k)
s := float64(0)
for i := 0; i < k; i++ {
s += Lrowk[i] * Lrowj[i]
}
s = (A.Get(j, k) - s) / Lrowk[k]
Lrowj[k] = s
L.Set(j, k, s)
d += s * s
isspd = isspd && (A.Get(k, j) == A.Get(j, k))
}
d = A.Get(j, j) - d
isspd = isspd && (d > 0.0)
L.Set(j, j, math.Sqrt(max(d, float64(0))))
for k := j + 1; k < n; k++ {
L.Set(j, k, 0)
}
}
if !isspd {
err = ExceptionNotSPD
}
return
}
/*
return L,U,P, st PLU=A.
*/
func (A *DenseMatrix) LU() (L, U *DenseMatrix, P *PivotMatrix) {
m := A.Rows()
n := A.Cols()
C := A.Copy()
P = C.LUInPlace()
L = C.L()
for i := 0; i < m && i < n; i++ {
L.Set(i, i, 1)
}
U = C.U()
return
}
/*
Overwrites A with [L\U] and returns P, st PLU=A. L is considered to
have 1s in the diagonal.
*/
func (A *DenseMatrix) LUInPlace() (P *PivotMatrix) {
m := A.Rows()
n := A.Cols()
LUcolj := make([]float64, m)
LUrowi := make([]float64, n)
piv := make([]int, m)
for i := 0; i < m; i++ {
piv[i] = i
}
pivsign := float64(1.0)
for j := 0; j < n; j++ {
A.BufferCol(j, LUcolj)
for i := 0; i < m; i++ {
A.BufferRow(i, LUrowi)
kmax := i
if j < i {
kmax = j
}
s := float64(0)
for k := 0; k < kmax; k++ {
s += LUrowi[k] * LUcolj[k]
}
LUcolj[i] -= s
LUrowi[j] = LUcolj[i]
A.Set(i, j, LUrowi[j])
}
p := j
for i := j + 1; i < m; i++ {
if math.Abs(LUcolj[i]) > math.Abs(LUcolj[p]) {
p = i
}
}
if p != j {
A.SwapRows(p, j)
k := piv[p]
piv[p] = piv[j]
piv[j] = k
pivsign = -pivsign
}
if j < m && A.Get(j, j) != 0 {
for i := j + 1; i < m; i++ {
A.Set(i, j, A.Get(i, j)/A.Get(j, j))
}
}
}
P = MakePivotMatrix(piv, pivsign)
return
}
func (A *DenseMatrix) QR() (Q, R *DenseMatrix) {
m := A.Rows()
n := A.Cols()
QR := A.Copy()
Q = Zeros(m, n)
R = Zeros(m, n)
i, j, k := 0, 0, 0
norm := float64(0.0)
s := float64(0.0)
for k = 0; k < n; k++ {
norm = 0
for i = k; i < m; i++ {
norm = math.Hypot(norm, QR.Get(i, k))
}
if norm != 0.0 {
if QR.Get(k, k) < 0 {
norm = -norm
}
for i = k; i < m; i++ {
QR.Set(i, k, QR.Get(i, k)/norm)
}
QR.Set(k, k, QR.Get(k, k)+1.0)
for j = k + 1; j < n; j++ {
s = 0.0
for i = k; i < m; i++ {
s += QR.Get(i, k) * QR.Get(i, j)
}
s = -s / QR.Get(k, k)
for i = k; i < m; i++ {
QR.Set(i, j, QR.Get(i, j)+s*QR.Get(i, k))
if i < j {
R.Set(i, j, QR.Get(i, j))
}
}
}
}
R.Set(k, k, -norm)
}
//Q Matrix:
i, j, k = 0, 0, 0
for k = n - 1; k >= 0; k-- {
Q.Set(k, k, 1.0)
for j = k; j < n; j++ {
if QR.Get(k, k) != 0 {
s = 0.0
for i = k; i < m; i++ {
s += QR.Get(i, k) * Q.Get(i, j)
}
s = -s / QR.Get(k, k)
for i = k; i < m; i++ {
Q.Set(i, j, Q.Get(i, j)+s*QR.Get(i, k))
}
}
}
}
return
}
================================================
FILE: dense_eigen.go
================================================
// Copyright 2009 The GoMatrix 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
import "math"
/*
Returns V,D st V*D*inv(V) = A and D is diagonal (or block diagonal).
*/
func (A *DenseMatrix) Eigen() (V, D *DenseMatrix, err error) {
//code translated/ripped off from Jama
if A.cols != A.rows {
err = ErrorDimensionMismatch
return
}
n := A.cols
Va := A.Copy().Arrays()
d := make([]float64, n)
e := make([]float64, n)
if A.Symmetric() {
tred2(Va[0:n], d[0:n], e[0:n]) //pass slices so they're references
tql2(Va[0:n], d[0:n], e[0:n])
} else {
H := A.GetMatrix(0, 0, n, n).Copy().Arrays()
ort := make([]float64, n)
// Reduce to Hessenberg form.
orthes(Va[0:n], d[0:n], e[0:n], H[0:n], ort[0:n])
// Reduce Hessenberg to real Schur form.
hqr2(Va[0:n], d[0:n], e[0:n], H[0:n], ort[0:n])
}
V, D = MakeDenseMatrixStacked(Va), makeD(d, e)
return
}
func makeD(d []float64, e []float64) *DenseMatrix {
n := len(d)
X := Zeros(n, n)
D := X.Arrays()
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
D[i][j] = 0.0
}
D[i][i] = d[i]
if e[i] > 0 {
D[i][i+1] = e[i]
} else if e[i] < 0 {
D[i][i-1] = e[i]
}
}
return X
}
func tred2(V [][]float64, d []float64, e []float64) {
n := len(V)
// This is derived from the Algol procedures tred2 by
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
for j := 0; j < n; j++ {
d[j] = V[n-1][j]
}
// Householder reduction to tridiagonal form.
for i := n - 1; i > 0; i-- {
// Scale to avoid under/overflow.
scale := float64(0)
h := float64(0)
for k := 0; k < i; k++ {
scale = scale + math.Abs(d[k])
}
if scale == 0.0 {
e[i] = d[i-1]
for j := 0; j < i; j++ {
d[j] = V[i-1][j]
V[i][j] = 0.0
V[j][i] = 0.0
}
} else {
// Generate Householder vector.
for k := 0; k < i; k++ {
d[k] /= scale
h += d[k] * d[k]
}
f := d[i-1]
g := math.Sqrt(h)
if f > 0 {
g = -g
}
e[i] = scale * g
h = h - f*g
d[i-1] = f - g
for j := 0; j < i; j++ {
e[j] = 0.0
}
// Apply similarity transformation to remaining columns.
for j := 0; j < i; j++ {
f = d[j]
V[j][i] = f
g = e[j] + V[j][j]*f
for k := j + 1; k <= i-1; k++ {
g += V[k][j] * d[k]
e[k] += V[k][j] * f
}
e[j] = g
}
f = 0.0
for j := 0; j < i; j++ {
e[j] /= h
f += e[j] * d[j]
}
hh := f / (h + h)
for j := 0; j < i; j++ {
e[j] -= hh * d[j]
}
for j := 0; j < i; j++ {
f = d[j]
g = e[j]
for k := j; k <= i-1; k++ {
V[k][j] -= (f*e[k] + g*d[k])
}
d[j] = V[i-1][j]
V[i][j] = 0.0
}
}
d[i] = h
}
// Accumulate transformations.
for i := 0; i < n-1; i++ {
V[n-1][i] = V[i][i]
V[i][i] = 1.0
h := d[i+1]
if h != 0.0 {
for k := 0; k <= i; k++ {
d[k] = V[k][i+1] / h
}
for j := 0; j <= i; j++ {
g := float64(0)
for k := 0; k <= i; k++ {
g += V[k][i+1] * V[k][j]
}
for k := 0; k <= i; k++ {
V[k][j] -= g * d[k]
}
}
}
for k := 0; k <= i; k++ {
V[k][i+1] = 0.0
}
}
for j := 0; j < n; j++ {
d[j] = V[n-1][j]
V[n-1][j] = 0.0
}
V[n-1][n-1] = 1.0
e[0] = 0.0
}
func tql2(V [][]float64, d []float64, e []float64) {
// This is derived from the Algol procedures tql2, by
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
n := len(V)
for i := 1; i < n; i++ {
e[i-1] = e[i]
}
e[n-1] = 0.0
f := float64(0)
tst1 := float64(0)
eps := math.Pow(2.0, -52.0)
for l := 0; l < n; l++ {
// Find small subdiagonal element
tst1 = max(tst1, math.Abs(d[l])+math.Abs(e[l]))
m := l
for m < n {
if math.Abs(e[m]) <= eps*tst1 {
break
}
m++
}
// If m == l, d[l] is an eigenvalue,
// otherwise, iterate.
if m > l {
iter := 0
for true {
iter = iter + 1 // (Could check iteration count here.)
// Compute implicit shift
g := d[l]
p := (d[l+1] - g) / (2.0 * e[l])
r := math.Sqrt(p*p + 1.0)
if p < 0 {
r = -r
}
d[l] = e[l] / (p + r)
d[l+1] = e[l] * (p + r)
dl1 := d[l+1]
h := g - d[l]
for i := l + 2; i < n; i++ {
d[i] -= h
}
f = f + h
// Implicit QL transformation.
p = d[m]
c := float64(1)
c2 := c
c3 := c
el1 := e[l+1]
s := float64(0)
s2 := float64(0)
for i := m - 1; i >= l; i-- {
c3 = c2
c2 = c
s2 = s
g = c * e[i]
h = c * p
r = math.Sqrt(p*p + e[i]*e[i])
e[i+1] = s * r
s = e[i] / r
c = p / r
p = c*d[i] - s*g
d[i+1] = h + s*(c*g+s*d[i])
// Accumulate transformation.
for k := 0; k < n; k++ {
h = V[k][i+1]
V[k][i+1] = s*V[k][i] + c*h
V[k][i] = c*V[k][i] - s*h
}
}
p = -s * s2 * c3 * el1 * e[l] / dl1
e[l] = s * p
d[l] = c * p
// Check for convergence.
if !(math.Abs(e[l]) > eps*tst1) {
break
}
}
}
d[l] = d[l] + f
e[l] = 0.0
}
// Sort eigenvalues and corresponding vectors.
for i := 0; i < n-1; i++ {
k := i
p := d[i]
for j := i + 1; j < n; j++ {
if d[j] < p {
k = j
p = d[j]
}
}
if k != i {
d[k] = d[i]
d[i] = p
for j := 0; j < n; j++ {
p = V[j][i]
V[j][i] = V[j][k]
V[j][k] = p
}
}
}
}
func orthes(V [][]float64, d []float64, e []float64, H [][]float64, ort []float64) {
// This is derived from the Algol procedures orthes and ortran,
// by Martin and Wilkinson, Handbook for Auto. Comp.,
// Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutines in EISPACK.
n := len(V)
low := 0
high := n - 1
for m := low + 1; m <= high-1; m++ {
// Scale column.
scale := float64(0)
for i := m; i <= high; i++ {
scale = scale + math.Abs(H[i][m-1])
}
if scale != 0.0 {
// Compute Householder transformation.
h := float64(0)
for i := high; i >= m; i-- {
ort[i] = H[i][m-1] / scale
h += ort[i] * ort[i]
}
g := math.Sqrt(h)
if ort[m] > 0 {
g = -g
}
h = h - ort[m]*g
ort[m] = ort[m] - g
// Apply Householder similarity transformation
// H = (I-u*u'/h)*H*(I-u*u')/h)
for j := m; j < n; j++ {
f := float64(0)
for i := high; i >= m; i-- {
f += ort[i] * H[i][j]
}
f = f / h
for i := m; i <= high; i++ {
H[i][j] -= f * ort[i]
}
}
for i := 0; i <= high; i++ {
f := float64(0)
for j := high; j >= m; j-- {
f += ort[j] * H[i][j]
}
f = f / h
for j := m; j <= high; j++ {
H[i][j] -= f * ort[j]
}
}
ort[m] = scale * ort[m]
H[m][m-1] = scale * g
}
}
// Accumulate transformations (Algol's ortran).
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if i == j {
V[i][j] = 1
} else {
V[i][j] = 0
}
}
}
for m := high - 1; m >= low+1; m-- {
if H[m][m-1] != 0.0 {
for i := m + 1; i <= high; i++ {
ort[i] = H[i][m-1]
}
for j := m; j <= high; j++ {
g := float64(0)
for i := m; i <= high; i++ {
g += ort[i] * V[i][j]
}
// Double division avoids possible underflow
g = (g / ort[m]) / H[m][m-1]
for i := m; i <= high; i++ {
V[i][j] += g * ort[i]
}
}
}
}
}
func hqr2(V [][]float64, d []float64, e []float64, H [][]float64, ort []float64) {
// This is derived from the Algol procedure hqr2,
// by Martin and Wilkinson, Handbook for Auto. Comp.,
// Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
// Initialize
n := len(V)
nn := n
n = nn - 1
low := 0
high := nn - 1
eps := math.Pow(2.0, -52.0)
exshift := float64(0)
p := float64(0)
q := float64(0)
r := float64(0)
s := float64(0)
z := float64(0)
var t, w, x, y float64
// Store roots isolated by balanc and compute matrix norm
norm := float64(0)
for i := 0; i < nn; i++ {
if i < low || i > high {
d[i] = H[i][i]
e[i] = 0.0
}
for j := int(max(float64(i)-1, 0)); j < nn; j++ {
norm = norm + math.Abs(H[i][j])
}
}
// Outer loop over eigenvalue index
iter := 0
for n >= low {
// Look for single small sub-diagonal element
l := n
for l > low {
s = math.Abs(H[l-1][l-1]) + math.Abs(H[l][l])
if s == 0.0 {
s = norm
}
if math.Abs(H[l][l-1]) < eps*s {
break
}
l--
}
// Check for convergence
// One root found
if l == n {
H[n][n] = H[n][n] + exshift
d[n] = H[n][n]
e[n] = 0.0
n--
iter = 0
// Two roots found
} else if l == n-1 {
w = H[n][n-1] * H[n-1][n]
p = (H[n-1][n-1] - H[n][n]) / 2.0
q = p*p + w
z = math.Sqrt(math.Abs(q))
H[n][n] = H[n][n] + exshift
H[n-1][n-1] = H[n-1][n-1] + exshift
x = H[n][n]
// Real pair
if q >= 0 {
if p >= 0 {
z = p + z
} else {
z = p - z
}
d[n-1] = x + z
d[n] = d[n-1]
if z != 0.0 {
d[n] = x - w/z
}
e[n-1] = 0.0
e[n] = 0.0
x = H[n][n-1]
s = math.Abs(x) + math.Abs(z)
p = x / s
q = z / s
r = math.Sqrt(p*p + q*q)
p = p / r
q = q / r
// Row modification
for j := n - 1; j < nn; j++ {
z = H[n-1][j]
H[n-1][j] = q*z + p*H[n][j]
H[n][j] = q*H[n][j] - p*z
}
// Column modification
for i := 0; i <= n; i++ {
z = H[i][n-1]
H[i][n-1] = q*z + p*H[i][n]
H[i][n] = q*H[i][n] - p*z
}
// Accumulate transformations
for i := low; i <= high; i++ {
z = V[i][n-1]
V[i][n-1] = q*z + p*V[i][n]
V[i][n] = q*V[i][n] - p*z
}
// Complex pair
} else {
d[n-1] = x + p
d[n] = x + p
e[n-1] = z
e[n] = -z
}
n = n - 2
iter = 0
// No convergence yet
} else {
// Form shift
x = H[n][n]
y = 0.0
w = 0.0
if l < n {
y = H[n-1][n-1]
w = H[n][n-1] * H[n-1][n]
}
// Wilkinson's original ad hoc shift
if iter == 10 {
exshift += x
for i := low; i <= n; i++ {
H[i][i] -= x
}
s = math.Abs(H[n][n-1]) + math.Abs(H[n-1][n-2])
y = 0.75 * s
x = y
w = -0.4375 * s * s
}
// MATLAB's new ad hoc shift
if iter == 30 {
s = (y - x) / 2.0
s = s*s + w
if s > 0 {
s = math.Sqrt(s)
if y < x {
s = -s
}
s = x - w/((y-x)/2.0+s)
for i := low; i <= n; i++ {
H[i][i] -= s
}
exshift += s
w = 0.964
y = w
x = y
}
}
iter = iter + 1 // (Could check iteration count here.)
// Look for two consecutive small sub-diagonal elements
m := n - 2
for m >= l {
z = H[m][m]
r = x - z
s = y - z
p = (r*s-w)/H[m+1][m] + H[m][m+1]
q = H[m+1][m+1] - z - r - s
r = H[m+2][m+1]
s = math.Abs(p) + math.Abs(q) + math.Abs(r)
p = p / s
q = q / s
r = r / s
if m == l {
break
}
if math.Abs(H[m][m-1])*(math.Abs(q)+math.Abs(r)) <
eps*(math.Abs(p)*(math.Abs(H[m-1][m-1])+math.Abs(z)+
math.Abs(H[m+1][m+1]))) {
break
}
m--
}
for i := m + 2; i <= n; i++ {
H[i][i-2] = 0.0
if i > m+2 {
H[i][i-3] = 0.0
}
}
// Double QR step involving rows l:n and columns m:n
for k := m; k <= n-1; k++ {
notlast := (k != n-1)
if k != m {
p = H[k][k-1]
q = H[k+1][k-1]
if notlast {
r = H[k+2][k-1]
} else {
r = 0
}
x = math.Abs(p) + math.Abs(q) + math.Abs(r)
if x != 0.0 {
p = p / x
q = q / x
r = r / x
}
}
if x == 0.0 {
break
}
s = math.Sqrt(p*p + q*q + r*r)
if p < 0 {
s = -s
}
if s != 0 {
if k != m {
H[k][k-1] = -s * x
} else if l != m {
H[k][k-1] = -H[k][k-1]
}
p = p + s
x = p / s
y = q / s
z = r / s
q = q / p
r = r / p
// Row modification
for j := k; j < nn; j++ {
p = H[k][j] + q*H[k+1][j]
if notlast {
p = p + r*H[k+2][j]
H[k+2][j] = H[k+2][j] - p*z
}
H[k][j] = H[k][j] - p*x
H[k+1][j] = H[k+1][j] - p*y
}
// Column modification
for i := 0; i <= int(min(float64(n), float64(k)+3)); i++ {
p = x*H[i][k] + y*H[i][k+1]
if notlast {
p = p + z*H[i][k+2]
H[i][k+2] = H[i][k+2] - p*r
}
H[i][k] = H[i][k] - p
H[i][k+1] = H[i][k+1] - p*q
}
// Accumulate transformations
for i := low; i <= high; i++ {
p = x*V[i][k] + y*V[i][k+1]
if notlast {
p = p + z*V[i][k+2]
V[i][k+2] = V[i][k+2] - p*r
}
V[i][k] = V[i][k] - p
V[i][k+1] = V[i][k+1] - p*q
}
} // (s != 0)
} // k loop
} // check convergence
} // while (n >= low)
// Backsubstitute to find vectors of upper triangular form
if norm == 0.0 {
return
}
for n = nn - 1; n >= 0; n-- {
p = d[n]
q = e[n]
// Real vector
if q == 0 {
l := n
H[n][n] = 1.0
for i := n - 1; i >= 0; i-- {
w = H[i][i] - p
r = 0.0
for j := l; j <= n; j++ {
r = r + H[i][j]*H[j][n]
}
if e[i] < 0.0 {
z = w
s = r
} else {
l = i
if e[i] == 0.0 {
if w != 0.0 {
H[i][n] = -r / w
} else {
H[i][n] = -r / (eps * norm)
}
// Solve real equations
} else {
x = H[i][i+1]
y = H[i+1][i]
q = (d[i]-p)*(d[i]-p) + e[i]*e[i]
t = (x*s - z*r) / q
H[i][n] = t
if math.Abs(x) > math.Abs(z) {
H[i+1][n] = (-r - w*t) / x
} else {
H[i+1][n] = (-s - y*t) / z
}
}
// Overflow control
t = math.Abs(H[i][n])
if (eps*t)*t > 1 {
for j := i; j <= n; j++ {
H[j][n] = H[j][n] / t
}
}
}
}
// Complex vector
} else if q < 0 {
l := n - 1
// Last vector component imaginary so matrix is triangular
if math.Abs(H[n][n-1]) > math.Abs(H[n-1][n]) {
H[n-1][n-1] = q / H[n][n-1]
H[n-1][n] = -(H[n][n] - p) / H[n][n-1]
} else {
cdivr, cdivi := cdiv(0.0, -H[n-1][n], H[n-1][n-1]-p, q)
H[n-1][n-1] = cdivr
H[n-1][n] = cdivi
}
H[n][n-1] = 0.0
H[n][n] = 1.0
for i := n - 2; i >= 0; i-- {
var ra, sa, vr, vi float64
ra = 0.0
sa = 0.0
for j := l; j <= n; j++ {
ra = ra + H[i][j]*H[j][n-1]
sa = sa + H[i][j]*H[j][n]
}
w = H[i][i] - p
if e[i] < 0.0 {
z = w
r = ra
s = sa
} else {
l = i
if e[i] == 0 {
cdivr, cdivi := cdiv(-ra, -sa, w, q)
H[i][n-1] = cdivr
H[i][n] = cdivi
} else {
// Solve complex equations
x = H[i][i+1]
y = H[i+1][i]
vr = (d[i]-p)*(d[i]-p) + e[i]*e[i] - q*q
vi = (d[i] - p) * 2.0 * q
if vr == 0.0 && vi == 0.0 {
vr = eps * norm * (math.Abs(w) + math.Abs(q) +
math.Abs(x) + math.Abs(y) + math.Abs(z))
}
cdivr, cdivi := cdiv(x*r-z*ra+q*sa, x*s-z*sa-q*ra, vr, vi)
H[i][n-1] = cdivr
H[i][n] = cdivi
if math.Abs(x) > (math.Abs(z) + math.Abs(q)) {
H[i+1][n-1] = (-ra - w*H[i][n-1] + q*H[i][n]) / x
H[i+1][n] = (-sa - w*H[i][n] - q*H[i][n-1]) / x
} else {
cdiv(-r-y*H[i][n-1], -s-y*H[i][n], z, q)
H[i+1][n-1] = cdivr
H[i+1][n] = cdivi
}
}
// Overflow control
t = max(math.Abs(H[i][n-1]), math.Abs(H[i][n]))
if (eps*t)*t > 1 {
for j := i; j <= n; j++ {
H[j][n-1] = H[j][n-1] / t
H[j][n] = H[j][n] / t
}
}
}
}
}
}
// Vectors of isolated roots
for i := 0; i < nn; i++ {
if i < low || i > high {
for j := i; j < nn; j++ {
V[i][j] = H[i][j]
}
}
}
// Back transformation to get eigenvectors of original matrix
for j := nn - 1; j >= low; j-- {
for i := low; i <= high; i++ {
z = 0.0
for k := low; k <= int(min(float64(j), float64(high))); k++ {
z = z + V[i][k]*H[k][j]
}
V[i][j] = z
}
}
}
func cdiv(xr float64, xi float64, yr float64, yi float64) (cdivr float64, cdivi float64) {
var r, d float64
if math.Abs(yr) > math.Abs(yi) {
r = yi / yr
d = yr + r*yi
cdivr = (xr + r*xi) / d
cdivi = (xi - r*xr) / d
} else {
r = yr / yi
d = yi + r*yr
cdivr = (r*xr + xi) / d
cdivi = (r*xi - xr) / d
}
return
}
================================================
FILE: dense_svd.go
================================================
// Copyright 2009 The GoMatrix 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
import "math"
/*
Returns U, Σ, V st Σ is diagonal (or block diagonal) and UΣV'=Arg
*/
func (Arg *DenseMatrix) SVD() (theU, Σ, theV *DenseMatrix, err error) {
//copied from Jama
// Derived from LINPACK code.
// Initialize.
A := Arg.Copy().Arrays()
m := Arg.rows
n := Arg.cols
/* Apparently the failing cases are only a proper subset of (m<n),
so let's not throw error. Correct fix to come later?
if (m<n) {
throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
*/
if m < n {
err = ErrorDimensionMismatch
return
}
nu := minInt(m, n)
s := make([]float64, minInt(m+1, n))
U := make([][]float64, m)
for i := 0; i < m; i++ {
U[i] = make([]float64, nu)
}
V := make([][]float64, n)
for i := 0; i < n; i++ {
V[i] = make([]float64, n)
}
e := make([]float64, n)
work := make([]float64, m)
wantu := true
wantv := true
// Reduce A to bidiagonal form, storing the diagonal elements
// in s and the super-diagonal elements in e.
nct := minInt(m-1, n)
nrt := maxInt(0, minInt(n-2, m))
for k := 0; k < maxInt(nct, nrt); k++ {
if k < nct {
// Compute the transformation for the k-th column and
// place the k-th diagonal in s[k].
// Compute 2-norm of k-th column without under/overflow.
s[k] = 0
for i := k; i < m; i++ {
s[k] = math.Hypot(s[k], A[i][k])
}
if s[k] != 0.0 {
if A[k][k] < 0.0 {
s[k] = -s[k]
}
for i := k; i < m; i++ {
A[i][k] /= s[k]
}
A[k][k] += 1.0
}
s[k] = -s[k]
}
for j := k + 1; j < n; j++ {
if (k < nct) && (s[k] != 0.0) {
// Apply the transformation.
t := float64(0)
for i := k; i < m; i++ {
t += A[i][k] * A[i][j]
}
t = -t / A[k][k]
for i := k; i < m; i++ {
A[i][j] += t * A[i][k]
}
}
// Place the k-th row of A into e for the
// subsequent calculation of the row transformation.
e[j] = A[k][j]
}
if wantu && (k < nct) {
// Place the transformation in U for subsequent back
// multiplication.
for i := k; i < m; i++ {
U[i][k] = A[i][k]
}
}
if k < nrt {
// Compute the k-th row transformation and place the
// k-th super-diagonal in e[k].
// Compute 2-norm without under/overflow.
e[k] = 0
for i := k + 1; i < n; i++ {
e[k] = math.Hypot(e[k], e[i])
}
if e[k] != 0.0 {
if e[k+1] < 0.0 {
e[k] = -e[k]
}
for i := k + 1; i < n; i++ {
e[i] /= e[k]
}
e[k+1] += 1.0
}
e[k] = -e[k]
if (k+1 < m) && (e[k] != 0.0) {
// Apply the transformation.
for i := k + 1; i < m; i++ {
work[i] = 0.0
}
for j := k + 1; j < n; j++ {
for i := k + 1; i < m; i++ {
work[i] += e[j] * A[i][j]
}
}
for j := k + 1; j < n; j++ {
t := -e[j] / e[k+1]
for i := k + 1; i < m; i++ {
A[i][j] += t * work[i]
}
}
}
if wantv {
// Place the transformation in V for subsequent
// back multiplication.
for i := k + 1; i < n; i++ {
V[i][k] = e[i]
}
}
}
}
// Set up the final bidiagonal matrix or order p.
p := minInt(n, m+1)
if nct < n {
s[nct] = A[nct][nct]
}
if m < p {
s[p-1] = 0.0
}
if nrt+1 < p {
e[nrt] = A[nrt][p-1]
}
e[p-1] = 0.0
// If required, generate U.
if wantu {
for j := nct; j < nu; j++ {
for i := 0; i < m; i++ {
U[i][j] = 0.0
}
U[j][j] = 1.0
}
for k := nct - 1; k >= 0; k-- {
if s[k] != 0.0 {
for j := k + 1; j < nu; j++ {
t := float64(0)
for i := k; i < m; i++ {
t += U[i][k] * U[i][j]
}
t = -t / U[k][k]
for i := k; i < m; i++ {
U[i][j] += t * U[i][k]
}
}
for i := k; i < m; i++ {
U[i][k] = -U[i][k]
}
U[k][k] = 1.0 + U[k][k]
for i := 0; i < k-1; i++ {
U[i][k] = 0.0
}
} else {
for i := 0; i < m; i++ {
U[i][k] = 0.0
}
U[k][k] = 1.0
}
}
}
// If required, generate V.
if wantv {
for k := n - 1; k >= 0; k-- {
if (k < nrt) && (e[k] != 0.0) {
for j := k + 1; j < nu; j++ {
t := float64(0)
for i := k + 1; i < n; i++ {
t += V[i][k] * V[i][j]
}
t = -t / V[k+1][k]
for i := k + 1; i < n; i++ {
V[i][j] += t * V[i][k]
}
}
}
for i := 0; i < n; i++ {
V[i][k] = 0.0
}
V[k][k] = 1.0
}
}
// Main iteration loop for the singular values.
pp := p - 1
iter := 0
eps := math.Pow(2.0, -52.0)
tiny := math.Pow(2.0, -966.0)
for p > 0 {
var k, kase int
// Here is where a test for too many iterations would go.
// This section of the program inspects for
// negligible elements in the s and e arrays. On
// completion the variables kase and k are set as follows.
// kase = 1 if s(p) and e[k-1] are negligible and k<p
// kase = 2 if s(k) is negligible and k<p
// kase = 3 if e[k-1] is negligible, k<p, and
// s(k), ..., s(p) are not negligible (qr step).
// kase = 4 if e(p-1) is negligible (convergence).
for k = p - 2; k >= -1; k-- {
if k == -1 {
break
}
if math.Abs(e[k]) <=
tiny+eps*(math.Abs(s[k])+math.Abs(s[k+1])) {
e[k] = 0.0
break
}
}
if k == p-2 {
kase = 4
} else {
var ks int
for ks = p - 1; ks >= k; ks-- {
if ks == k {
break
}
t := float64(0)
if ks != p {
t = math.Abs(e[ks])
}
if ks != k+1 {
t += math.Abs(e[ks-1])
}
//double t = (ks != p ? Math.abs(e[ks]) : 0.) +
// (ks != k+1 ? Math.abs(e[ks-1]) : 0.);
if math.Abs(s[ks]) <= tiny+eps*t {
s[ks] = 0.0
break
}
}
if ks == k {
kase = 3
} else if ks == p-1 {
kase = 1
} else {
kase = 2
k = ks
}
}
k++
// Perform the task indicated by kase.
//fmt.Printf("kase = %d\n", kase);
switch kase {
// Deflate negligible s(p).
case 1:
{
f := e[p-2]
e[p-2] = 0.0
for j := p - 2; j >= k; j-- {
t := math.Hypot(s[j], f)
cs := s[j] / t
sn := f / t
s[j] = t
if j != k {
f = -sn * e[j-1]
e[j-1] = cs * e[j-1]
}
if wantv {
for i := 0; i < n; i++ {
t = cs*V[i][j] + sn*V[i][p-1]
V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1]
V[i][j] = t
}
}
}
}
break
// Split at negligible s(k).
case 2:
{
f := e[k-1]
e[k-1] = 0.0
for j := k; j < p; j++ {
t := math.Hypot(s[j], f)
cs := s[j] / t
sn := f / t
s[j] = t
f = -sn * e[j]
e[j] = cs * e[j]
if wantu {
for i := 0; i < m; i++ {
t = cs*U[i][j] + sn*U[i][k-1]
U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1]
U[i][j] = t
}
}
}
}
break
// Perform one qr step.
case 3:
{
// Calculate the shift.
scale := max(max(max(max(
math.Abs(s[p-1]), math.Abs(s[p-2])),
math.Abs(e[p-2])),
math.Abs(s[k])),
math.Abs(e[k]))
sp := s[p-1] / scale
spm1 := s[p-2] / scale
epm1 := e[p-2] / scale
sk := s[k] / scale
ek := e[k] / scale
b := ((spm1+sp)*(spm1-sp) + epm1*epm1) / 2.0
c := (sp * epm1) * (sp * epm1)
shift := float64(0)
if (b != 0.0) || (c != 0.0) {
shift = math.Sqrt(b*b + c)
if b < 0.0 {
shift = -shift
}
shift = c / (b + shift)
}
f := (sk+sp)*(sk-sp) + shift
g := sk * ek
// Chase zeros.
for j := k; j < p-1; j++ {
t := math.Hypot(f, g)
cs := f / t
sn := g / t
if j != k {
e[j-1] = t
}
f = cs*s[j] + sn*e[j]
e[j] = cs*e[j] - sn*s[j]
g = sn * s[j+1]
s[j+1] = cs * s[j+1]
if wantv {
for i := 0; i < n; i++ {
t = cs*V[i][j] + sn*V[i][j+1]
V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1]
V[i][j] = t
}
}
t = math.Hypot(f, g)
cs = f / t
sn = g / t
s[j] = t
f = cs*e[j] + sn*s[j+1]
s[j+1] = -sn*e[j] + cs*s[j+1]
g = sn * e[j+1]
e[j+1] = cs * e[j+1]
if wantu && (j < m-1) {
for i := 0; i < m; i++ {
t = cs*U[i][j] + sn*U[i][j+1]
U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1]
U[i][j] = t
}
}
}
e[p-2] = f
iter = iter + 1
}
break
// Convergence.
case 4:
{
// Make the singular values positive.
if s[k] <= 0.0 {
if s[k] < 0.0 {
s[k] = -s[k]
} else {
s[k] = 0
}
if wantv {
for i := 0; i <= pp; i++ {
V[i][k] = -V[i][k]
}
}
}
// Order the singular values.
for k < pp {
if s[k] >= s[k+1] {
break
}
t := s[k]
s[k] = s[k+1]
s[k+1] = t
if wantv && (k < n-1) {
for i := 0; i < n; i++ {
t = V[i][k+1]
V[i][k+1] = V[i][k]
V[i][k] = t
}
}
if wantu && (k < m-1) {
for i := 0; i < m; i++ {
t = U[i][k+1]
U[i][k+1] = U[i][k]
U[i][k] = t
}
}
k++
}
iter = 0
p--
}
break
}
}
//fmt.Printf("testing\n%v\n%v\n%v\n%v\n%v\n", A, V, U, e, s);
theU = MakeDenseMatrixStacked(U).GetMatrix(0, 0, m, minInt(m+1, n))
Σ = Diagonal(s)
theV = MakeDenseMatrixStacked(V)
return
}
================================================
FILE: dense_test.go
================================================
// Copyright 2009 The GoMatrix 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
import (
"fmt"
"math/rand"
"testing"
"time"
)
const ε = 0.000001
const verbose = false
const speedTest = true
/* TEST: arithmetic.go */
func TestEquals(t *testing.T) {
if !Equals(Ones(5, 3), Ones(5, 3)) {
t.Fail()
}
if Equals(Ones(3, 5), Ones(5, 3)) {
t.Fail()
}
if Equals(Zeros(3, 3), Ones(3, 3)) {
t.Fail()
}
}
func TestApproximates(t *testing.T) {
A := Numbers(3, 3, 6)
B := Numbers(3, 3, .1)
C := Numbers(3, 3, .6)
D, err := A.ElementMult(B)
if !(err == nil) && !ApproxEquals(D, C, ε) {
t.Fail()
}
}
func TestAdd(t *testing.T) {
A := Normals(3, 3)
B := Normals(3, 3)
C := Sum(A, B)
if C.Nil() {
t.Fail()
}
for i := 0; i < C.Rows(); i++ {
for j := 0; j < C.Cols(); j++ {
if A.Get(i, j)+B.Get(i, j) != C.Get(i, j) {
t.Fail()
}
}
}
}
func TestSubtract(t *testing.T) {
A := Normals(3, 3)
B := Normals(3, 3)
C := Difference(A, B)
if C.Nil() {
t.Fail()
}
for i := 0; i < C.Rows(); i++ {
for j := 0; j < C.Cols(); j++ {
if A.Get(i, j)-B.Get(i, j) != C.Get(i, j) {
t.Fail()
}
}
}
}
func TestProduct(t *testing.T) {
A := MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
B := MakeDenseMatrix([]float64{1, 7, -4, 4,
3, -2, -6, 1,
-12, 8, 1, 20,
0, 0, -10, 3,
},
4, 4)
C, err := A.Times(B)
if !(err == nil) {
t.Fail()
}
var Ctrue Matrix
Ctrue = MakeDenseMatrix([]float64{48, 14, -56, -46,
66, -21, -10, -108,
-240, 68, 101, 356,
114, -122, -56, -203,
},
4, 4)
if !Equals(C, Ctrue) {
t.Fail()
}
P := MakePivotMatrix([]int{1, 3, 0, 2}, -1)
C, err = P.Times(A)
Ctrue, err = P.DenseMatrix().Times(A)
if !Equals(C, Ctrue) {
t.Fail()
}
}
func TestParallelProduct(t *testing.T) {
w := 100000
h := 40
if !verbose {
w = 100
h = 4
}
rand.Seed(time.Now().UnixNano())
A := Normals(h, w)
B := Normals(w, h)
var C *DenseMatrix
var start, end int64
start = time.Now().UnixNano()
Ctrue, err := A.Times(B)
if !(err == nil) {
t.Fail()
}
end = time.Now().UnixNano()
if verbose {
fmt.Printf("%fs for synchronous\n", float64(end-start)/1000000000)
}
start = time.Now().UnixNano()
C = ParallelProduct(A, B)
if !(err == nil) {
t.Fail()
}
end = time.Now().UnixNano()
if verbose {
fmt.Printf("%fs for parallel\n", float64(end-start)/1000000000)
}
if !Equals(C, Ctrue) {
t.Fail()
}
}
var MaxProcs int = 1
func TestTimesDenseProcs(t *testing.T) {
A := Normals(10, 10)
B := Normals(10, 10)
old := MaxProcs
MaxProcs = 1
C, _ := A.TimesDense(B)
MaxProcs = 2
Cp, _ := A.TimesDense(B)
if !Equals(C, Cp) {
t.Fail()
}
MaxProcs = old
}
func TestElementMult(t *testing.T) {
A := MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
T := MakeDenseMatrix([]float64{0.1, 0.1, 0.1, 0.1,
10, 10, 10, 10,
100, 100, 100, 100,
1000, 1000, 1000, 1000,
},
4, 4)
C, err := A.ElementMult(T)
if !(err == nil) {
t.Fail()
}
Ctrue := MakeDenseMatrix([]float64{0.6, -0.2, -0.4, 0.4,
30, -30, -60, 10,
-1200, 800, 2100, -800,
-6000, 0, -10000, 7000,
},
4, 4)
if !ApproxEquals(C, Ctrue, ε) {
t.Fail()
}
}
func TestScale(t *testing.T) {
A := Normals(3, 3)
f := float64(5.3)
B := A.Copy()
B.Scale(f)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if A.Get(i, j)*f != B.Get(i, j) {
t.Fail()
}
}
}
}
func TestScaleMatrix(t *testing.T) {
A := Normals(4, 4)
B := Normals(4, 4)
C := A.Copy()
C.ScaleMatrix(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if A.Get(i, j)*B.Get(i, j) != C.Get(i, j) {
t.Fail()
}
}
}
}
/* TEST: basic.go */
func TestSymmetric(t *testing.T) {
A := MakeDenseMatrix([]float64{
6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
if A.Symmetric() {
t.Fail()
}
B := MakeDenseMatrix([]float64{
6, 3, -12, -6,
3, -3, 8, 0,
-12, 8, 21, -10,
-6, 0, -10, 7,
},
4, 4)
if !B.Symmetric() {
t.Fail()
}
}
func TestInverse(t *testing.T) {
A := MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
Ainv, err := A.Inverse()
if !(err == nil) {
t.Fail()
}
AAinv, err := A.Times(Ainv)
if !(err == nil) {
t.Fail()
}
if !ApproxEquals(Eye(A.Rows()), AAinv, ε) {
if verbose {
fmt.Printf("A\n%v\n\nAinv\n%v\n\nA*Ainv\n%v\n", A, Ainv, AAinv)
}
t.Fail()
}
}
func TestDet(t *testing.T) {
A := MakeDenseMatrix([]float64{4, -2, 5,
-1, -7, 10,
0, 1, -3,
},
3, 3)
if A.Det() != 45 {
if verbose {
fmt.Printf("A\n%v\n\nA.Det()\n%v\n\n", A, A.Det())
}
t.Fail()
}
}
func TestTrace(t *testing.T) {
A := MakeDenseMatrix([]float64{4, -2, 5,
-1, -7, 10,
0, 1, -3,
},
3, 3)
if A.Trace() != 4-7-3 {
if verbose {
fmt.Printf("A\n%v\n\nA.Trace()\n%v\n\n", A, A.Trace())
}
t.Fail()
}
}
func TestTranspose(t *testing.T) {
A := Normals(4, 4)
B := A.Transpose()
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
if A.Get(i, j) != B.Get(j, i) {
t.Fail()
}
}
}
}
func TestSolve(t *testing.T) {
A := MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
b := MakeDenseMatrix([]float64{1, 1, 1, 1}, 4, 1)
x, err := A.Solve(b)
if !(err == nil) {
t.Fail()
}
xtrue := MakeDenseMatrix([]float64{-0.906250, -3.393750, 1.275000, 1.187500}, 4, 1)
if !Equals(x, xtrue) {
t.Fail()
}
}
/* TEST: decomp.go */
func TestCholesky(t *testing.T) {
A := MakeDenseMatrix([]float64{1, 0.2, 0,
0.2, 1, 0.5,
0, 0.5, 1,
},
3, 3)
B, err := A.Cholesky()
if !(err == nil) {
t.Fail()
}
if !ApproxEquals(A, Product(B, B.Transpose()), ε) {
t.Fail()
}
}
func TestLU(t *testing.T) {
A := MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
L, U, P := A.LU()
LU, err := L.Times(U)
PLU, err := P.Times(LU)
if !(err == nil) {
if verbose {
fmt.Printf("TestLU: %v\n", err)
}
t.Fail()
}
if !Equals(A, PLU) {
if verbose {
fmt.Printf("TestLU:\n%v\n!=\n%v\n", A, PLU)
}
t.Fail()
}
A = MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
Ltrue, Utrue, Ptrue := A.LU()
P = A.LUInPlace()
L = A.L()
U = A.U()
for i := 0; i < L.Rows(); i++ {
L.Set(i, i, 1)
}
PL := Product(P, L)
PLU2 := Product(PL, U)
PLtrue := Product(Ptrue, Ltrue)
PLUtrue := Product(PLtrue, Utrue)
if !Equals(PLU2, PLUtrue) {
t.Fail()
}
}
func TestQR(t *testing.T) {
A := MakeDenseMatrix([]float64{6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
Q, R := A.QR()
Qtrue := MakeDenseMatrix([]float64{-0.4, 0.278610, 0.543792, -0.683130,
-0.2, -0.358213, -0.699161, -0.585540,
0.8, 0.437816, -0.126237, -0.390360,
0.4, -0.776129, 0.446686, -0.195180,
},
4, 4)
Rtrue := MakeDenseMatrix([]float64{-15, 7.8, 15.6, -5.4,
0, 4.019950, 17.990272, -8.179206,
0, 0, -5.098049, 5.612709,
0, 0, 0, -1.561440,
},
4, 4)
QR := Product(Q, R)
if !ApproxEquals(Q, Qtrue, ε) ||
!ApproxEquals(R, Rtrue, ε) ||
!ApproxEquals(A, QR, ε) {
t.Fail()
}
}
/* TEST: eigen.go */
func TestEigen(t *testing.T) {
A := MakeDenseMatrix([]float64{
2, 1,
1, 2,
},
2, 2)
V, D, _ := A.Eigen()
Vinv, _ := V.Inverse()
Aguess := Product(Product(V, D), Vinv)
if !ApproxEquals(A, Aguess, ε) {
t.Fail()
}
B := MakeDenseMatrix([]float64{
6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
V, D, _ = B.Eigen()
Vinv, _ = V.Inverse()
if !ApproxEquals(B, Product(Product(V, D), Vinv), ε) {
if verbose {
fmt.Printf("B =\n%v\nV=\n%v\nD=\n%v\n", B, V, D)
}
t.Fail()
}
Bm, _ := B.Times(B.Transpose())
B = Bm.DenseMatrix()
V, D, _ = B.Eigen()
Vinv, _ = V.Inverse()
if !ApproxEquals(B, Product(Product(V, D), Vinv), ε) {
if verbose {
fmt.Printf("B =\n%v\nV=\n%v\nD=\n%v\n", B, V, D)
}
t.Fail()
}
}
func TestSVD(t *testing.T) {
A := MakeDenseMatrix([]float64{
6, -2, -4, 4,
3, -3, -6, 1,
-12, 8, 21, -8,
-6, 0, -10, 7,
},
4, 4)
U, Σ, V, _ := A.SVD()
Arecomp := Product(Product(U, Σ), V.Transpose())
if !ApproxEquals(A, Arecomp, ε) {
t.Fail()
}
A = Normals(5, 3)
U, Σ, V, _ = A.SVD()
Arecomp = Product(Product(U, Σ), V.Transpose())
if !ApproxEquals(A, Arecomp, ε) {
t.Fail()
}
}
/* TEST: matrix.go */
func TestGetMatrix(t *testing.T) {
A := Zeros(4, 4)
B := A.GetMatrix(1, 1, 2, 2)
B.Set(0, 1, 1)
if A.Get(1, 2) != 1 {
t.Fail()
}
}
func TestL(t *testing.T) {
A := Normals(4, 4)
L := A.L()
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if j > i && L.Get(i, j) != 0 {
t.Fail()
} else if j <= i && L.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
A = Normals(4, 2)
L = A.L()
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if j > i && L.Get(i, j) != 0 {
t.Fail()
} else if j <= i && L.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
A = Normals(2, 4)
L = A.L()
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if j > i && L.Get(i, j) != 0 {
t.Fail()
} else if j <= i && L.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
}
func TestU(t *testing.T) {
A := Normals(4, 4)
U := A.U()
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if j < i && U.Get(i, j) != 0 {
t.Fail()
} else if j >= i && U.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
A = Normals(2, 4)
U = A.U()
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if j < i && U.Get(i, j) != 0 {
t.Fail()
} else if j >= i && U.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
A = Normals(4, 2)
U = A.U()
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if j < i && U.Get(i, j) != 0 {
t.Fail()
} else if j >= i && U.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
}
func TestAugment(t *testing.T) {
var A, B, C *DenseMatrix
A = Normals(4, 4)
B = Normals(4, 4)
C, _ = A.Augment(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i, j+A.Cols()) != B.Get(i, j) {
t.Fail()
}
}
}
A = Normals(2, 2)
B = Normals(4, 4)
C, err := A.Augment(B)
if err == nil {
t.Fail()
}
A = Normals(4, 4)
B = Normals(4, 2)
C, _ = A.Augment(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i, j+A.Cols()) != B.Get(i, j) {
t.Fail()
}
}
}
}
func TestStack(t *testing.T) {
var A, B, C *DenseMatrix
A = Normals(4, 4)
B = Normals(4, 4)
C, _ = A.Stack(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i+A.Rows(), j) != B.Get(i, j) {
t.Fail()
}
}
}
A = Normals(4, 4)
B = Normals(4, 2)
C, err := A.Stack(B)
if err == nil {
t.Fail()
}
A = Normals(2, 4)
B = Normals(4, 4)
C, err = A.Stack(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i+A.Rows(), j) != B.Get(i, j) {
t.Fail()
}
}
}
}
func TestZeros(t *testing.T) {
A := Zeros(4, 5)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if A.Get(i, j) != 0 {
t.Fail()
}
}
}
}
func TestNumbers(t *testing.T) {
n := float64(1.0)
A := Numbers(3, 3, n)
// fmt.Printf("%v\n\n\n",A.String());
Atrue := MakeDenseMatrix([]float64{n, n, n,
n, n, n,
n, n, n,
},
3, 3)
if !Equals(A, Atrue) {
t.Fail()
}
}
func TestOnes(t *testing.T) {
A := Ones(4, 5)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if A.Get(i, j) != 1 {
t.Fail()
}
}
}
}
func TestEye(t *testing.T) {
A := Eye(4)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if (i != j && A.Get(i, j) != 0) || (i == j && A.Get(i, j) != 1) {
t.Fail()
}
}
}
}
func TestNormals(t *testing.T) {
//test that it's filled with random data?
A := Normals(3, 4)
if A.Rows() != 3 || A.Cols() != 4 {
t.Fail()
}
}
func TestKronecker(t *testing.T) {
A := MakeDenseMatrix([]float64{0, 1, 2, 3}, 2, 2)
B := MakeDenseMatrix([]float64{5, 6, 7, 8, 9, 10}, 2, 3)
C := Kronecker(A, B)
Cp := MakeDenseMatrix([]float64{0, 0, 0, 5, 6, 7,
0, 0, 0, 8, 9, 10,
10, 12, 14, 15, 18, 21,
16, 18, 20, 24, 27, 30}, 4, 6)
if !Equals(C, Cp) {
t.Fail()
}
}
func TestVectorize(t *testing.T) {
A := MakeDenseMatrix([]float64{0, 1, 2, 3, 4, 5}, 2, 3)
V := Vectorize(A)
Vp := MakeDenseMatrix([]float64{0, 3, 1, 4, 2, 5}, 6, 1)
if !Equals(V, Vp) {
t.Fail()
}
}
func TestSubmatrix(t *testing.T) {
Eye(3).GetMatrix(1, 1, 2, 2).GetColVector(0)
}
/* TEST: util.go */
/*
func TestMultipleProduct(t *testing.T) {
A := Ones(3, 1)
B := Ones(1, 3)
C := MultipleProduct(A, B, A)
D := Product(A, B)
E := Product(D, A)
if !Equals(E, C) {
t.Fail()
}
}
*/
================================================
FILE: densebench_test.go
================================================
package matrix
import (
"fmt"
"testing"
"time"
)
func BenchmarkTransposeTimes(b *testing.B) {
fmt.Println("benchmark")
for s := 25; s <= 100; s += 25 {
w, h := s/2, s*2
A := Normals(h, w)
B := Normals(w, h)
var times [2]float64
const Count = 500
MaxProcs = 1
WhichSyncMethod = 1
start := time.Now()
for i := 0; i < Count; i++ {
A.Times(B)
}
end := time.Now()
duration := end.Sub(start)
times[0] = float64(duration) / 1e9
WhichSyncMethod = 2
start = time.Now()
for i := 0; i < Count; i++ {
A.Times(B)
}
end = time.Now()
duration = end.Sub(start)
times[1] = float64(duration) / 1e9
fmt.Printf("%d: %.2f\n", h, times[1]/times[0])
}
}
================================================
FILE: error.go
================================================
// Copyright 2009 The GoMatrix 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
import "fmt"
const (
//The matrix returned was nil.
errorNilMatrix = iota + 1
//The dimensions of the inputs do not make sense for this operation.
errorDimensionMismatch
//The indices provided are out of bounds.
errorIllegalIndex
//The matrix provided has a singularity.
exceptionSingular
//The matrix provided is not positive semi-definite.
exceptionNotSPD
)
type error_ int
func (e error_) Error() string {
switch e {
case errorNilMatrix:
return "Matrix is nil"
case errorDimensionMismatch:
return "Input dimensions do not match"
case errorIllegalIndex:
return "Index out of bounds"
case exceptionSingular:
return "Matrix is singular"
case exceptionNotSPD:
return "Matrix is not positive semidefinite"
}
return fmt.Sprintf("Unknown error code %d", e)
}
func (e error_) String() string {
return e.Error()
}
var (
//The matrix returned was nil.
ErrorNilMatrix error_ = error_(errorNilMatrix)
//The dimensions of the inputs do not make sense for this operation.
ErrorDimensionMismatch error_ = error_(errorDimensionMismatch)
//The indices provided are out of bounds.
ErrorIllegalIndex error_ = error_(errorIllegalIndex)
//The matrix provided has a singularity.
ExceptionSingular error_ = error_(exceptionSingular)
//The matrix provided is not positive semi-definite.
ExceptionNotSPD error_ = error_(exceptionNotSPD)
)
================================================
FILE: matrix.go
================================================
// Copyright 2009 The GoMatrix Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//target:gomatrix.googlecode.com/hg/matrix
//Linear algebra.
package matrix
import (
"errors"
"fmt"
"strconv"
"strings"
)
//The MatrixRO interface defines matrix operations that do not change the
//underlying data, such as information requests or the creation of transforms
/*
Read-only matrix types (at the moment, PivotMatrix).
*/
type MatrixRO interface {
//Returns true if the underlying object is nil.
Nil() bool
//The number of rows in this matrix.
Rows() int
//The number of columns in this matrix.
Cols() int
//The number of elements in this matrix.
NumElements() int
//The size pair, (Rows(), Cols())
GetSize() (int, int)
//The element in the ith row and jth column.
Get(i, j int) float64
Plus(MatrixRO) (Matrix, error)
Minus(MatrixRO) (Matrix, error)
Times(MatrixRO) (Matrix, error)
//The determinant of this matrix.
Det() float64
//The trace of this matrix.
Trace() float64
//A pretty-print string.
String() string
DenseMatrix() *DenseMatrix
SparseMatrix() *SparseMatrix
}
/*
A mutable matrix.
*/
type Matrix interface {
MatrixRO
//Set the element at the ith row and jth column to v.
Set(i int, j int, v float64)
Add(MatrixRO) error
Subtract(MatrixRO) error
Scale(float64)
}
type matrix struct {
rows int
cols int
}
func (A *matrix) Nil() bool { return A == nil }
func (A *matrix) Rows() int { return A.rows }
func (A *matrix) Cols() int { return A.cols }
func (A *matrix) NumElements() int { return A.rows * A.cols }
func (A *matrix) GetSize() (rows, cols int) {
rows = A.rows
cols = A.cols
return
}
/*
Take a matlab-style matrix representation
eg [a b c; d e f]
*/
func ParseMatlab(txt string) (A *DenseMatrix, err error) {
var arrays [][]float64
spaceSep := strings.Fields(txt)
tok := func() (t string, eos bool) {
defer func() {
for len(spaceSep) != 0 && len(spaceSep[0]) == 0 {
spaceSep = spaceSep[1:]
}
}()
isNotNumber := func(c byte) bool {
return c != '[' || c != ']' || c == ';'
}
if len(spaceSep) == 0 {
eos = true
return
}
top := spaceSep[0]
var lof int
for ; lof < len(top) && !isNotNumber(top[lof]); lof++ {
}
if lof != 0 {
t = top[:lof]
spaceSep[0] = top[lof:]
return
} else {
t = top[:1]
spaceSep[0] = top[1:]
return
}
panic("unreachable")
}
stack := func(row []float64) (err error) {
if len(arrays) == 0 {
arrays = [][]float64{row}
return
}
if len(arrays[0]) != len(row) {
err = errors.New("misaligned row")
}
arrays = append(arrays, row)
return
}
var row []float64
loop:
for {
t, eos := tok()
if eos {
break loop
}
switch t {
case "[":
case ";":
err = stack(row)
if err != nil {
return
}
row = []float64{}
case "]":
err = stack(row)
if err != nil {
return
}
break loop
default:
var v float64
v, err = strconv.ParseFloat(t, 64)
if err != nil {
return
}
row = append(row, v)
}
}
A = MakeDenseMatrixStacked(arrays)
return
}
func String(A MatrixRO) string {
condense := func(vs string) string {
if strings.Index(vs, ".") != -1 {
for vs[len(vs)-1] == '0' {
vs = vs[0 : len(vs)-1]
}
}
if vs[len(vs)-1] == '.' {
vs = vs[0 : len(vs)-1]
}
return vs
}
if A == nil {
return "{nil}"
}
s := "{"
maxLen := 0
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
v := A.Get(i, j)
vs := condense(fmt.Sprintf("%f", v))
maxLen = maxInt(maxLen, len(vs))
}
}
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
v := A.Get(i, j)
vs := condense(fmt.Sprintf("%f", v))
for len(vs) < maxLen {
vs = " " + vs
}
s += vs
if i != A.Rows()-1 || j != A.Cols()-1 {
s += ","
}
if j != A.Cols()-1 {
s += " "
}
}
if i != A.Rows()-1 {
s += "\n "
}
}
s += "}"
return s
}
================================================
FILE: matrix_test.go
================================================
package matrix
import (
"testing"
)
func TestParse(t *testing.T) {
s := `[1 2 3;4 5 6]`
A, err := ParseMatlab(s)
if err != nil {
t.Fatal(err)
}
Ar := MakeDenseMatrix([]float64{1,2,3,4,5,6}, 2, 3)
if !Equals(A, Ar) {
t.Error()
}
}
================================================
FILE: pivot.go
================================================
// Copyright 2009 The GoMatrix 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
/*
A space-optimized structure for pivot matrices, ie a matrix with
exactly one 1 in each row and each column.
*/
type PivotMatrix struct {
matrix
pivots []int
pivotSign float64
}
func (P *PivotMatrix) Get(i, j int) float64 {
i = i % P.rows
if i < 0 {
i = P.rows - i
}
j = j % P.cols
if j < 0 {
j = P.cols - j
}
if P.pivots[j] == i {
return 1
}
return 0
}
/*
Convert this PivotMatrix into a DenseMatrix.
*/
func (P *PivotMatrix) DenseMatrix() *DenseMatrix {
A := Zeros(P.rows, P.cols)
for j := 0; j < P.rows; j++ {
A.Set(P.pivots[j], j, 1)
}
return A
}
/*
Convert this PivotMatrix into a SparseMatrix.
*/
func (P *PivotMatrix) SparseMatrix() *SparseMatrix {
A := ZerosSparse(P.rows, P.cols)
for j := 0; j < P.rows; j++ {
A.Set(P.pivots[j], j, 1)
}
return A
}
/*
Make a copy of this PivotMatrix.
*/
func (P *PivotMatrix) Copy() *PivotMatrix { return MakePivotMatrix(P.pivots, P.pivotSign) }
func MakePivotMatrix(pivots []int, pivotSign float64) *PivotMatrix {
n := len(pivots)
P := new(PivotMatrix)
P.rows = n
P.cols = n
P.pivots = pivots
P.pivotSign = pivotSign
return P
}
func (A *PivotMatrix) String() string { return String(A) }
================================================
FILE: pivot_arithmetic.go
================================================
// Copyright 2009 The GoMatrix 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
func (P *PivotMatrix) Minus(A MatrixRO) (Matrix, error) {
if P.rows != A.Rows() || P.cols != A.Cols() {
return nil, ErrorDimensionMismatch
}
B := P.DenseMatrix()
B.Subtract(A)
return B, nil
}
func (P *PivotMatrix) Plus(A MatrixRO) (Matrix, error) {
if P.rows != A.Rows() || P.cols != A.Cols() {
return nil, ErrorDimensionMismatch
}
B := P.DenseMatrix()
B.Add(A)
return B, nil
}
/*
Multiply this pivot matrix by another.
*/
func (P *PivotMatrix) Times(A MatrixRO) (Matrix, error) {
if P.Cols() != A.Rows() {
return nil, ErrorDimensionMismatch
}
B := Zeros(P.rows, A.Cols())
for i := 0; i < P.rows; i++ {
k := 0
for ; i != P.pivots[k]; k++ {
}
for j := 0; j < A.Cols(); j++ {
B.Set(i, j, A.Get(k, j))
}
}
return B, nil
}
/*
Multiplication optimized for when two pivots are the operands.
*/
func (P *PivotMatrix) TimesPivot(A *PivotMatrix) (*PivotMatrix, error) {
if P.rows != A.rows {
return nil, ErrorDimensionMismatch
}
newPivots := make([]int, P.rows)
newSign := P.pivotSign * A.pivotSign
for i := 0; i < A.rows; i++ {
newPivots[i] = P.pivots[A.pivots[i]]
}
return MakePivotMatrix(newPivots, newSign), nil
}
/*
Equivalent to PxA, but streamlined to take advantage of the datastructures.
*/
func (P *PivotMatrix) RowPivotDense(A *DenseMatrix) (*DenseMatrix, error) {
if P.rows != A.rows {
return nil, ErrorDimensionMismatch
}
B := Zeros(A.rows, A.cols)
for si := 0; si < A.rows; si++ {
di := P.pivots[si]
Astart := si * A.step
Bstart := di * B.step
for j := 0; j < A.cols; j++ {
B.elements[Bstart+j] = A.elements[Astart+j]
}
}
return B, nil
}
/*
Equivalent to AxP, but streamlined to take advantage of the datastructures.
*/
func (P *PivotMatrix) ColPivotDense(A *DenseMatrix) (*DenseMatrix, error) {
if P.rows != A.cols {
return nil, ErrorDimensionMismatch
}
B := Zeros(A.rows, A.cols)
for i := 0; i < B.rows; i++ {
Astart := i * A.step
Bstart := i * B.step
for sj := 0; sj < B.cols; sj++ {
dj := P.pivots[sj]
B.elements[Bstart+dj] = A.elements[Astart+sj]
}
}
return B, nil
}
/*
Equivalent to PxA, but streamlined to take advantage of the datastructures.
*/
func (P *PivotMatrix) RowPivotSparse(A *SparseMatrix) (*SparseMatrix, error) {
if P.rows != A.rows {
return nil, ErrorDimensionMismatch
}
B := ZerosSparse(A.rows, A.cols)
for index, value := range A.elements {
si, j := A.GetRowColIndex(index)
di := P.pivots[si]
B.Set(di, j, value)
}
return B, nil
}
/*
Equivalent to AxP, but streamlined to take advantage of the datastructures.
*/
func (P *PivotMatrix) ColPivotSparse(A *SparseMatrix) (*SparseMatrix, error) {
if P.rows != A.cols {
return nil, ErrorDimensionMismatch
}
B := ZerosSparse(A.rows, A.cols)
for index, value := range A.elements {
i, sj := A.GetRowColIndex(index)
dj := P.pivots[sj]
B.Set(i, dj, value)
}
return B, nil
}
================================================
FILE: pivot_basic.go
================================================
// Copyright 2009 The GoMatrix 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
import "math"
/*
Swap two rows in this PivotMatrix.
*/
func (P *PivotMatrix) SwapRows(r1, r2 int) error {
// tmp := P.pivots[r1];
// P.pivots[r1] = P.pivots[r2];
// P.pivots[r2] = tmp;
P.pivots[r1], P.pivots[r2] = P.pivots[r2], P.pivots[r1]
P.pivotSign *= -1
return nil
}
func (P *PivotMatrix) Symmetric() bool {
for i := 0; i < P.rows; i++ {
if P.pivots[P.pivots[i]] != i {
return false
}
}
return true
}
func (A *PivotMatrix) Inverse() *PivotMatrix { return A.Transpose() }
func (P *PivotMatrix) Transpose() *PivotMatrix {
newPivots := make([]int, P.rows)
for i := 0; i < P.rows; i++ {
newPivots[P.pivots[i]] = i
}
return MakePivotMatrix(newPivots, P.pivotSign)
}
func (P *PivotMatrix) Det() float64 { return P.pivotSign }
func (P *PivotMatrix) Trace() (r float64) {
for i := 0; i < len(P.pivots); i++ {
if P.pivots[i] == i {
r += 1
}
}
return
}
/*
Returns x such that Px=b.
*/
func (P *PivotMatrix) Solve(b MatrixRO) (Matrix, error) {
return P.Transpose().Times(b) //error comes from times
}
func (A *PivotMatrix) OneNorm() float64 { return float64(A.rows) }
func (A *PivotMatrix) TwoNorm() float64 { return math.Sqrt(float64(A.rows)) }
func (A *PivotMatrix) InfinityNorm() float64 { return 1 }
================================================
FILE: pivot_test.go
================================================
// Copyright 2009 The GoMatrix 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
import "testing"
import "fmt"
func TestTimes_Pivot(t *testing.T) {
P1 := MakePivotMatrix([]int{2, 1, 0}, -1)
P2 := MakePivotMatrix([]int{2, 0, 1}, 1)
P, _ := P1.TimesPivot(P2)
if !Equals(P, Product(P1, P2)) {
if verbose {
fmt.Printf("%v\n%v\n%v\n", P1, P2, P)
}
t.Fail()
}
}
func TestRowPivot(t *testing.T) {
P := MakePivotMatrix([]int{2, 1, 0}, -1)
A := Normals(3, 4)
B, _ := P.RowPivotDense(A)
Btrue := Product(P, A)
if !Equals(B, Btrue) {
t.Fail()
}
A = Normals(4, 3)
_, err := P.RowPivotDense(A)
if err == nil {
t.Fail()
}
C := Normals(3, 4).SparseMatrix()
D, _ := P.RowPivotSparse(C)
Btrue = Product(P, C)
if !Equals(D, Btrue) {
t.Fail()
}
}
func TestColPivot(t *testing.T) {
P := MakePivotMatrix([]int{2, 1, 0}, -1)
A := Normals(4, 3)
B, _ := P.ColPivotDense(A)
Btrue := Product(A, P)
if !Equals(B, Btrue) {
t.Fail()
}
A = Normals(3, 4)
_, err := P.ColPivotDense(A)
if err == nil {
t.Fail()
}
C := Normals(4, 3).SparseMatrix()
D, _ := P.ColPivotSparse(C)
Btrue = Product(C, P)
if !Equals(D, Btrue) {
t.Fail()
}
}
================================================
FILE: sparse.go
================================================
// Copyright 2009 The GoMatrix 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
import "math/rand"
/*
A sparse matrix based on go's map datastructure.
*/
type SparseMatrix struct {
matrix
elements map[int]float64
// offset to start of matrix s.t. idx = i*cols + j + offset
// offset = starting row * step + starting col
offset int
// analogous to dense step
step int
}
func (A *SparseMatrix) Get(i, j int) float64 {
i = i % A.rows
if i < 0 {
i = A.rows - i
}
j = j % A.cols
if j < 0 {
j = A.cols - j
}
x, _ := A.elements[i*A.step+j+A.offset]
return x
}
/*
Looks up an element given its element index.
*/
func (A *SparseMatrix) GetIndex(index int) float64 {
x, ok := A.elements[index]
if !ok {
return 0
}
return x
}
/*
Turn an element index into a row number.
*/
func (A *SparseMatrix) GetRowIndex(index int) (i int) {
i = (index - A.offset) / A.cols
return
}
/*
Turn an element index into a column number.
*/
func (A *SparseMatrix) GetColIndex(index int) (j int) {
j = (index - A.offset) % A.cols
return
}
/*
Turn an element index into a row and column number.
*/
func (A *SparseMatrix) GetRowColIndex(index int) (i int, j int) {
i = (index - A.offset) / A.step
j = (index - A.offset) % A.step
return
}
func (A *SparseMatrix) Set(i int, j int, v float64) {
i = i % A.rows
if i < 0 {
i = A.rows - i
}
j = j % A.cols
if j < 0 {
j = A.cols - j
}
// v == 0 results in removal of key from underlying map
if v == 0 {
delete(A.elements, i*A.step+j+A.offset)
} else {
A.elements[i*A.step+j+A.offset] = v
}
}
/*
Sets an element given its index.
*/
func (A *SparseMatrix) SetIndex(index int, v float64) {
// v == 0 results in removal of key from underlying map
if v == 0 {
delete(A.elements, index)
} else {
A.elements[index] = v
}
}
/*
A channel that will carry the indices of non-zero elements.
*/
func (A *SparseMatrix) Indices() (out chan int) {
//maybe thread the populating?
out = make(chan int)
go func(o chan int) {
for index := range A.elements {
i, j := A.GetRowColIndex(index)
if 0 <= i && i < A.rows && 0 <= j && j < A.cols {
o <- index
}
}
close(o)
}(out)
return
}
/*
Get a matrix representing a subportion of A. Changes to the new matrix will be
reflected in A.
*/
func (A *SparseMatrix) GetMatrix(i, j, rows, cols int) (subMatrix *SparseMatrix) {
if i < 0 || j < 0 || i+rows > A.rows || j+cols > A.cols {
i = maxInt(0, i)
j = maxInt(0, j)
rows = minInt(A.rows-i, rows)
rows = minInt(A.cols-j, cols)
}
subMatrix = new(SparseMatrix)
subMatrix.rows = rows
subMatrix.cols = cols
subMatrix.offset = (i+A.offset/A.step)*A.step + (j + A.offset%A.step)
subMatrix.step = A.step
subMatrix.elements = A.elements
return
}
/*
Gets a reference to a column vector.
*/
func (A *SparseMatrix) GetColVector(j int) *SparseMatrix {
return A.GetMatrix(0, j, A.rows, j+1)
}
/*
Gets a reference to a row vector.
*/
func (A *SparseMatrix) GetRowVector(i int) *SparseMatrix {
return A.GetMatrix(i, 0, 1, A.cols)
}
/*
Creates a new matrix [A B].
*/
func (A *SparseMatrix) Augment(B *SparseMatrix) (*SparseMatrix, error) {
if A.rows != B.rows {
return nil, ErrorDimensionMismatch
}
C := ZerosSparse(A.rows, A.cols+B.cols)
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
C.Set(i, j, value)
}
for index, value := range B.elements {
i, j := B.GetRowColIndex(index)
C.Set(i, j+A.cols, value)
}
return C, nil
}
/*
Creates a new matrix [A;B], where A is above B.
*/
func (A *SparseMatrix) Stack(B *SparseMatrix) (*SparseMatrix, error) {
if A.cols != B.cols {
return nil, ErrorDimensionMismatch
}
C := ZerosSparse(A.rows+B.rows, A.cols)
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
C.Set(i, j, value)
}
for index, value := range B.elements {
i, j := B.GetRowColIndex(index)
C.Set(i+A.rows, j, value)
}
return C, nil
}
/*
Returns a copy with all zeros above the diagonal.
*/
func (A *SparseMatrix) L() *SparseMatrix {
B := ZerosSparse(A.rows, A.cols)
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
if i >= j {
B.Set(i, j, value)
}
}
return B
}
/*
Returns a copy with all zeros below the diagonal.
*/
func (A *SparseMatrix) U() *SparseMatrix {
B := ZerosSparse(A.rows, A.cols)
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
if i <= j {
B.Set(i, j, value)
}
}
return B
}
func (A *SparseMatrix) Copy() *SparseMatrix {
B := ZerosSparse(A.rows, A.cols)
for index, value := range A.elements {
B.elements[index] = value
}
return B
}
func ZerosSparse(rows int, cols int) *SparseMatrix {
A := new(SparseMatrix)
A.rows = rows
A.cols = cols
A.offset = 0
A.step = cols
A.elements = map[int]float64{}
return A
}
/*
Creates a matrix and puts a standard normal in n random elements, with replacement.
*/
func NormalsSparse(rows int, cols int, n int) *SparseMatrix {
A := ZerosSparse(rows, cols)
for k := 0; k < n; k++ {
i := rand.Intn(rows)
j := rand.Intn(cols)
A.Set(i, j, rand.NormFloat64())
}
return A
}
/*
Create a sparse matrix using the provided map as its backing.
*/
func MakeSparseMatrix(elements map[int]float64, rows int, cols int) *SparseMatrix {
A := ZerosSparse(rows, cols)
A.elements = elements
return A
}
/*
Convert this sparse matrix into a dense matrix.
*/
func (A *SparseMatrix) DenseMatrix() *DenseMatrix {
B := Zeros(A.rows, A.cols)
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
B.Set(i, j, value)
}
return B
}
func (A *SparseMatrix) SparseMatrix() *SparseMatrix {
return A.Copy()
}
func (A *SparseMatrix) String() string { return String(A) }
================================================
FILE: sparse_arithmetic.go
================================================
// Copyright 2009 The GoMatrix 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
/*
The sum of this matrix and another.
*/
func (A *SparseMatrix) Plus(B MatrixRO) (Matrix, error) {
C := A.Copy()
err := C.Add(B)
return C, err
}
/*
The sum of this matrix and another sparse matrix, optimized for sparsity.
*/
func (A *SparseMatrix) PlusSparse(B *SparseMatrix) (*SparseMatrix, error) {
C := A.Copy()
err := C.AddSparse(B)
return C, err
}
/*
The difference between this matrix and another.
*/
func (A *SparseMatrix) Minus(B MatrixRO) (Matrix, error) {
C := A.Copy()
err := C.Subtract(B)
return C, err
}
/*
The difference between this matrix and another sparse matrix, optimized for sparsity.
*/
func (A *SparseMatrix) MinusSparse(B *SparseMatrix) (*SparseMatrix, error) {
C := A.Copy()
err := C.SubtractSparse(B)
return C, err
}
/*
Add another matrix to this one in place.
*/
func (A *SparseMatrix) Add(B MatrixRO) error {
if Bs, ok := B.(*SparseMatrix); ok {
return A.AddSparse(Bs)
}
if A.rows != B.Rows() || A.cols != B.Cols() {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
A.Set(i, j, A.Get(i, j)+B.Get(i, j))
}
}
return nil
}
/*
Add another matrix to this one in place, optimized for sparsity.
*/
func (A *SparseMatrix) AddSparse(B *SparseMatrix) error {
if A.rows != B.Rows() || A.cols != B.Cols() {
return ErrorDimensionMismatch
}
for index, value := range B.elements {
i, j := A.GetRowColIndex(index)
A.Set(i, j, A.Get(i, j)+value)
}
return nil
}
/*
Subtract another matrix from this one in place.
*/
func (A *SparseMatrix) Subtract(B MatrixRO) error {
if Bs, ok := B.(*SparseMatrix); ok {
return A.SubtractSparse(Bs)
}
if A.rows != B.Rows() || A.cols != B.Cols() {
return ErrorDimensionMismatch
}
for i := 0; i < A.rows; i++ {
for j := 0; j < A.cols; j++ {
A.Set(i, j, A.Get(i, j)-B.Get(i, j))
}
}
return nil
}
/*
Subtract another matrix from this one in place, optimized for sparsity.
*/
func (A *SparseMatrix) SubtractSparse(B *SparseMatrix) error {
if A.rows != B.Rows() || A.cols != B.Cols() {
return ErrorDimensionMismatch
}
for index, value := range B.elements {
i, j := A.GetRowColIndex(index)
A.Set(i, j, A.Get(i, j)-value)
}
return nil
}
/*
Get the product of this matrix and another.
*/
func (A *SparseMatrix) Times(B MatrixRO) (Matrix, error) {
/* uncomment this if an efficient version is written
if Bs, ok := B.(*SparseMatrix); ok {
return A.TimesSparse(Bs);
}
*/
if A.cols != B.Rows() {
return nil, ErrorDimensionMismatch
}
C := ZerosSparse(A.rows, B.Cols())
for index, value := range A.elements {
i, k := A.GetRowColIndex(index)
//not sure if there is a more efficient way to do this without using
//a different data structure
for j := 0; j < B.Cols(); j++ {
v := B.Get(k, j)
if v != 0 {
C.Set(i, j, C.Get(i, j)+value*v)
}
}
}
return C, nil
}
/*
Get the product of this matrix and another, optimized for sparsity.
*/
func (A *SparseMatrix) TimesSparse(B *SparseMatrix) (*SparseMatrix, error) {
if A.cols != B.Rows() {
return nil, ErrorDimensionMismatch
}
C := ZerosSparse(A.rows, B.Cols())
for index, value := range A.elements {
i, k := A.GetRowColIndex(index)
//not sure if there is a more efficient way to do this without using
//a different data structure
for j := 0; j < B.Cols(); j++ {
v := B.Get(k, j)
if v != 0 {
C.Set(i, j, C.Get(i, j)+value*v)
}
}
}
return C, nil
}
/*
Scale this matrix by f.
*/
func (A *SparseMatrix) Scale(f float64) {
for index, value := range A.elements {
A.elements[index] = value * f
}
}
/*
Get the element-wise product of this matrix and another.
*/
func (A *SparseMatrix) ElementMult(B MatrixRO) (*SparseMatrix, error) {
C := A.Copy()
err := C.ScaleMatrix(B)
return C, err
}
/*
Get the element-wise product of this matrix and another, optimized for sparsity.
*/
func (A *SparseMatrix) ElementMultSparse(B *SparseMatrix) (*SparseMatrix, error) {
C := A.Copy()
err := C.ScaleMatrixSparse(B)
return C, err
}
/*
Scale this matrix by another, element-wise.
*/
func (A *SparseMatrix) ScaleMatrix(B MatrixRO) error {
if A.rows != B.Rows() || A.cols != B.Cols() {
return ErrorDimensionMismatch
}
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
A.Set(i, j, value*B.Get(i, j))
}
return nil
}
/*
Scale this matrix by another sparse matrix, element-wise. Optimized for sparsity.
*/
func (A *SparseMatrix) ScaleMatrixSparse(B *SparseMatrix) error {
if len(B.elements) > len(A.elements) {
if A.rows != B.rows || A.cols != B.cols {
return ErrorDimensionMismatch
}
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
A.Set(i, j, value*B.Get(i, j))
}
}
return A.ScaleMatrix(B)
}
================================================
FILE: sparse_basic.go
================================================
// Copyright 2009 The GoMatrix 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
import "math"
/*
Swap two rows in this matrix.
*/
func (A *SparseMatrix) SwapRows(r1, r2 int) {
js := map[int]bool{}
for index := range A.elements {
i, j := A.GetRowColIndex(index)
if i == r1 || i == r2 {
js[j] = true
}
}
for j := range js {
tmp := A.Get(r1, j)
A.Set(r1, j, A.Get(r2, j))
A.Set(r2, j, tmp)
}
}
/*
Scale a row by a scalar.
*/
func (A *SparseMatrix) ScaleRow(r int, f float64) {
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
if i == r {
A.Set(i, j, value*f)
}
}
}
/*
Add a multiple of row rs to row rd.
*/
func (A *SparseMatrix) ScaleAddRow(rd, rs int, f float64) {
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
if i == rs {
A.Set(rd, j, A.Get(rd, j)+value*f)
}
}
}
func (A *SparseMatrix) Symmetric() bool {
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
if i != j && value != A.Get(j, i) {
return false
}
}
return true
}
func (A *SparseMatrix) Transpose() *SparseMatrix {
B := ZerosSparse(A.cols, A.rows)
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
B.Set(j, i, value)
}
return B
}
func (A *SparseMatrix) Det() float64 {
//TODO: obviously this is a horrible way to do it
return A.DenseMatrix().Det()
}
func (A *SparseMatrix) Trace() (res float64) {
for index, value := range A.elements {
i, j := A.GetRowColIndex(index)
if i == j {
res += value
}
}
return
}
func (A *SparseMatrix) OneNorm() (res float64) {
for _, value := range A.elements {
res += math.Abs(value)
}
return
}
func (A *SparseMatrix) TwoNorm() float64 {
var sum float64 = 0
for _, value := range A.elements {
sum += value * value
}
return math.Sqrt(sum)
}
func (A *SparseMatrix) InfinityNorm() (res float64) {
for _, value := range A.elements {
res = max(res, math.Abs(value))
}
return
}
================================================
FILE: sparse_test.go
================================================
// Copyright 2009 The GoMatrix 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
import (
"fmt"
"math/rand"
"testing"
)
func TestAdd_Sparse(t *testing.T) {
A := NormalsSparse(3, 3, 9)
B := NormalsSparse(3, 3, 9)
C1, _ := A.Plus(B)
C2, _ := A.PlusSparse(B)
if !ApproxEquals(C1, Sum(A, B), ε) {
t.Fail()
}
if !ApproxEquals(C2, Sum(A, B), ε) {
t.Fail()
}
}
func TestSubtract_Sparse(t *testing.T) {
A := NormalsSparse(3, 3, 9)
B := NormalsSparse(3, 3, 9)
C1, _ := A.Minus(B)
C2, _ := A.MinusSparse(B)
if !ApproxEquals(C1, Difference(A, B), ε) {
t.Fail()
}
if !ApproxEquals(C2, Difference(A, B), ε) {
t.Fail()
}
}
func TestTimes_Sparse(t *testing.T) {
A := Normals(3, 3).SparseMatrix()
B := Normals(3, 3).SparseMatrix()
C1, _ := A.Times(B)
C2, _ := A.TimesSparse(B)
if !ApproxEquals(C1, Product(A, B), ε) {
t.Fail()
}
if !ApproxEquals(C2, Product(A, B), ε) {
t.Fail()
}
}
func TestElementMult_Sparse(t *testing.T) {
A := Normals(3, 3).SparseMatrix()
B := Normals(3, 3).SparseMatrix()
C1, _ := A.ElementMult(B)
C2, _ := A.ElementMultSparse(B)
D, _ := A.DenseMatrix().ElementMult(B)
if !Equals(D, C1) {
t.Fail()
}
if !Equals(D, C2) {
t.Fail()
}
}
func TestGetMatrix_Sparse(t *testing.T) {
A := ZerosSparse(6, 6)
for i := 0; i < 36; i++ {
x := rand.Intn(6)
y := rand.Intn(6)
A.Set(y, x, 1)
}
B := A.GetMatrix(1, 1, 4, 4)
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
if B.Get(i, j) != A.Get(i+1, j+1) {
t.Fail()
}
}
}
}
func TestAugment_Sparse(t *testing.T) {
var A, B, C *SparseMatrix
A = NormalsSparse(4, 4, 16)
B = NormalsSparse(4, 4, 16)
C, _ = A.Augment(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i, j+A.Cols()) != B.Get(i, j) {
t.Fail()
}
}
}
A = NormalsSparse(2, 2, 4)
B = NormalsSparse(4, 4, 16)
C, err := A.Augment(B)
if err == nil {
t.Fail()
}
A = NormalsSparse(4, 4, 16)
B = NormalsSparse(4, 2, 8)
C, _ = A.Augment(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i, j+A.Cols()) != B.Get(i, j) {
t.Fail()
}
}
}
}
func TestStack_Sparse(t *testing.T) {
var A, B, C *SparseMatrix
A = NormalsSparse(4, 4, 16)
B = NormalsSparse(4, 4, 16)
C, _ = A.Stack(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i+A.Rows(), j) != B.Get(i, j) {
t.Fail()
}
}
}
A = NormalsSparse(2, 2, 4)
B = NormalsSparse(4, 4, 16)
C, err := A.Stack(B)
if err == nil {
if verbose {
fmt.Printf("%v\n", err)
}
t.Fail()
}
A = NormalsSparse(4, 4, 16)
B = NormalsSparse(2, 4, 8)
C, _ = A.Stack(B)
for i := 0; i < A.Rows(); i++ {
for j := 0; j < A.Cols(); j++ {
if C.Get(i, j) != A.Get(i, j) {
t.Fail()
}
}
}
for i := 0; i < B.Rows(); i++ {
for j := 0; j < B.Cols(); j++ {
if C.Get(i+A.Rows(), j) != B.Get(i, j) {
t.Fail()
}
}
}
}
================================================
FILE: util.go
================================================
// Copyright 2009 The GoMatrix 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
import "runtime"
func max(x, y float64) float64 {
if x > y {
return x
}
return y
}
func maxInt(x, y int) int {
if x > y {
return x
}
return y
}
func min(x, y float64) float64 {
if x < y {
return x
}
return y
}
func minInt(x, y int) int {
if x < y {
return x
}
return y
}
func sum(a []float64) (s float64) {
for _, v := range a {
s += v
}
return
}
func product(a []float64) float64 {
p := float64(1)
for _, v := range a {
p *= v
}
return p
}
type box interface{}
func countBoxes(start, cap int) chan box {
ints := make(chan box)
go func() {
for i := start; i < cap; i++ {
ints <- i
}
close(ints)
}()
return ints
}
func parFor(inputs <-chan box, foo func(i box)) (wait func()) {
n := runtime.GOMAXPROCS(0)
block := make(chan bool, n)
for j := 0; j < n; j++ {
go func() {
for {
i, ok := <-inputs
if !ok {
break
}
foo(i)
}
block <- true
}()
}
wait = func() {
for i := 0; i < n; i++ {
<-block
}
}
return
}
gitextract_v_1rg_cr/ ├── AUTHORS ├── LICENSE ├── README ├── arithmetic.go ├── dense.go ├── dense_arithmetic.go ├── dense_basic.go ├── dense_data.go ├── dense_decomp.go ├── dense_eigen.go ├── dense_svd.go ├── dense_test.go ├── densebench_test.go ├── error.go ├── matrix.go ├── matrix_test.go ├── pivot.go ├── pivot_arithmetic.go ├── pivot_basic.go ├── pivot_test.go ├── sparse.go ├── sparse_arithmetic.go ├── sparse_basic.go ├── sparse_test.go └── util.go
SYMBOL INDEX (247 symbols across 22 files)
FILE: arithmetic.go
function Sum (line 12) | func Sum(A MatrixRO, Bs ...MatrixRO) (C *DenseMatrix) {
function Difference (line 30) | func Difference(A, B MatrixRO) (C *DenseMatrix) {
function Product (line 42) | func Product(A MatrixRO, Bs ...MatrixRO) (C *DenseMatrix) {
function Transpose (line 56) | func Transpose(A MatrixRO) (B Matrix) {
function Inverse (line 69) | func Inverse(A MatrixRO) (B Matrix) {
function Kronecker (line 89) | func Kronecker(A, B MatrixRO) (C *DenseMatrix) {
function Vectorize (line 102) | func Vectorize(Am MatrixRO) (V *DenseMatrix) {
function Unvectorize (line 108) | func Unvectorize(V MatrixRO, rows, cols int) (A *DenseMatrix) {
function ParallelProduct (line 117) | func ParallelProduct(A, B MatrixRO) (C *DenseMatrix) {
function Scaled (line 166) | func Scaled(A MatrixRO, f float64) (B *DenseMatrix) {
function Equals (line 175) | func Equals(A, B MatrixRO) bool {
function ApproxEquals (line 193) | func ApproxEquals(A, B MatrixRO, ε float64) bool {
FILE: dense.go
type DenseMatrix (line 14) | type DenseMatrix struct
method Arrays (line 26) | func (A *DenseMatrix) Arrays() [][]float64 {
method Array (line 37) | func (A *DenseMatrix) Array() []float64 {
method rowSlice (line 50) | func (A *DenseMatrix) rowSlice(row int) []float64 {
method Get (line 57) | func (A *DenseMatrix) Get(i int, j int) (v float64) {
method Set (line 78) | func (A *DenseMatrix) Set(i int, j int, v float64) {
method GetMatrix (line 98) | func (A *DenseMatrix) GetMatrix(i, j, rows, cols int) *DenseMatrix {
method SetMatrix (line 110) | func (A *DenseMatrix) SetMatrix(i, j int, B *DenseMatrix) {
method GetColVector (line 118) | func (A *DenseMatrix) GetColVector(j int) *DenseMatrix {
method GetRowVector (line 122) | func (A *DenseMatrix) GetRowVector(i int) *DenseMatrix {
method L (line 129) | func (A *DenseMatrix) L() *DenseMatrix {
method U (line 142) | func (A *DenseMatrix) U() *DenseMatrix {
method Copy (line 152) | func (A *DenseMatrix) Copy() *DenseMatrix {
method Augment (line 167) | func (A *DenseMatrix) Augment(B *DenseMatrix) (C *DenseMatrix, err err...
method AugmentFill (line 176) | func (A *DenseMatrix) AugmentFill(B, C *DenseMatrix) (err error) {
method Stack (line 198) | func (A *DenseMatrix) Stack(B *DenseMatrix) (C *DenseMatrix, err error) {
method StackFill (line 207) | func (A *DenseMatrix) StackFill(B, C *DenseMatrix) (err error) {
method SparseMatrix (line 230) | func (A *DenseMatrix) SparseMatrix() *SparseMatrix {
method DenseMatrix (line 243) | func (A *DenseMatrix) DenseMatrix() *DenseMatrix {
method String (line 345) | func (A *DenseMatrix) String() string { return String(A) }
function Zeros (line 247) | func Zeros(rows, cols int) *DenseMatrix {
function Ones (line 256) | func Ones(rows, cols int) *DenseMatrix {
function Numbers (line 270) | func Numbers(rows, cols int, num float64) *DenseMatrix {
function Eye (line 285) | func Eye(span int) *DenseMatrix {
function Normals (line 293) | func Normals(rows, cols int) *DenseMatrix {
function Diagonal (line 305) | func Diagonal(d []float64) *DenseMatrix {
function MakeDenseCopy (line 314) | func MakeDenseCopy(A MatrixRO) *DenseMatrix {
function MakeDenseMatrix (line 324) | func MakeDenseMatrix(elements []float64, rows, cols int) *DenseMatrix {
function MakeDenseMatrixStacked (line 333) | func MakeDenseMatrixStacked(data [][]float64) *DenseMatrix {
FILE: dense_arithmetic.go
method Plus (line 9) | func (A *DenseMatrix) Plus(B MatrixRO) (Matrix, error) {
method PlusDense (line 14) | func (A *DenseMatrix) PlusDense(B *DenseMatrix) (*DenseMatrix, error) {
method Minus (line 20) | func (A *DenseMatrix) Minus(B MatrixRO) (Matrix, error) {
method MinusDense (line 26) | func (A *DenseMatrix) MinusDense(B *DenseMatrix) (*DenseMatrix, error) {
method Add (line 32) | func (A *DenseMatrix) Add(B MatrixRO) error {
method AddDense (line 48) | func (A *DenseMatrix) AddDense(B *DenseMatrix) error {
method Subtract (line 62) | func (A *DenseMatrix) Subtract(B MatrixRO) error {
method SubtractDense (line 82) | func (A *DenseMatrix) SubtractDense(B *DenseMatrix) error {
method Times (line 102) | func (A *DenseMatrix) Times(B MatrixRO) (Matrix, error) {
type parJob (line 126) | type parJob struct
function parTimes1 (line 130) | func parTimes1(A, B, C *DenseMatrix) {
function parTimes2 (line 167) | func parTimes2(A, B, C *DenseMatrix) {
method TimesDense (line 224) | func (A *DenseMatrix) TimesDense(B *DenseMatrix) (C *DenseMatrix, err er...
method TimesDenseFill (line 229) | func (A *DenseMatrix) TimesDenseFill(B, C *DenseMatrix) (err error) {
function transposeTimes (line 260) | func transposeTimes(A, B, C *DenseMatrix) {
method ElementMult (line 278) | func (A *DenseMatrix) ElementMult(B MatrixRO) (Matrix, error) {
method ElementMultDense (line 284) | func (A *DenseMatrix) ElementMultDense(B *DenseMatrix) (*DenseMatrix, er...
method Scale (line 290) | func (A *DenseMatrix) Scale(f float64) {
method ScaleMatrix (line 300) | func (A *DenseMatrix) ScaleMatrix(B MatrixRO) error {
method ScaleMatrixDense (line 318) | func (A *DenseMatrix) ScaleMatrixDense(B *DenseMatrix) error {
FILE: dense_basic.go
method Symmetric (line 12) | func (A *DenseMatrix) Symmetric() bool {
method SwapRows (line 26) | func (m *DenseMatrix) SwapRows(r1 int, r2 int) {
method ScaleRow (line 36) | func (m *DenseMatrix) ScaleRow(r int, f float64) {
method ScaleAddRow (line 44) | func (m *DenseMatrix) ScaleAddRow(rd int, rs int, f float64) {
method Inverse (line 54) | func (A *DenseMatrix) Inverse() (*DenseMatrix, error) {
method Det (line 84) | func (A *DenseMatrix) Det() float64 {
method Trace (line 90) | func (A *DenseMatrix) Trace() float64 { return sum(A.DiagonalCopy()) }
method OneNorm (line 92) | func (A *DenseMatrix) OneNorm() (ε float64) {
method TwoNorm (line 101) | func (A *DenseMatrix) TwoNorm() float64 {
method InfinityNorm (line 112) | func (A *DenseMatrix) InfinityNorm() (ε float64) {
method Transpose (line 121) | func (A *DenseMatrix) Transpose() *DenseMatrix {
method TransposeInPlace (line 131) | func (A *DenseMatrix) TransposeInPlace() (err error) {
function solveLower (line 146) | func solveLower(A *DenseMatrix, b Matrix) *DenseMatrix {
function solveUpper (line 159) | func solveUpper(A *DenseMatrix, b Matrix) *DenseMatrix {
method Solve (line 171) | func (A *DenseMatrix) Solve(b MatrixRO) (*DenseMatrix, error) {
method SolveDense (line 186) | func (A *DenseMatrix) SolveDense(b *DenseMatrix) (*DenseMatrix, error) {
FILE: dense_data.go
method RowCopy (line 8) | func (A *DenseMatrix) RowCopy(i int) []float64 {
method ColCopy (line 17) | func (A *DenseMatrix) ColCopy(j int) []float64 {
method DiagonalCopy (line 26) | func (A *DenseMatrix) DiagonalCopy() []float64 {
method BufferRow (line 38) | func (A *DenseMatrix) BufferRow(i int, buf []float64) {
method BufferCol (line 44) | func (A *DenseMatrix) BufferCol(j int, buf []float64) {
method BufferDiagonal (line 50) | func (A *DenseMatrix) BufferDiagonal(buf []float64) {
method FillRow (line 56) | func (A *DenseMatrix) FillRow(i int, buf []float64) {
method FillCol (line 62) | func (A *DenseMatrix) FillCol(j int, buf []float64) {
method FillDiagonal (line 68) | func (A *DenseMatrix) FillDiagonal(buf []float64) {
FILE: dense_decomp.go
method Cholesky (line 12) | func (A *DenseMatrix) Cholesky() (L *DenseMatrix, err error) {
method LU (line 50) | func (A *DenseMatrix) LU() (L, U *DenseMatrix, P *PivotMatrix) {
method LUInPlace (line 70) | func (A *DenseMatrix) LUInPlace() (P *PivotMatrix) {
method QR (line 124) | func (A *DenseMatrix) QR() (Q, R *DenseMatrix) {
FILE: dense_eigen.go
method Eigen (line 12) | func (A *DenseMatrix) Eigen() (V, D *DenseMatrix, err error) {
function makeD (line 41) | func makeD(d []float64, e []float64) *DenseMatrix {
function tred2 (line 59) | func tred2(V [][]float64, d []float64, e []float64) {
function tql2 (line 176) | func tql2(V [][]float64, d []float64, e []float64) {
function orthes (line 298) | func orthes(V [][]float64, d []float64, e []float64, H [][]float64, ort ...
function hqr2 (line 395) | func hqr2(V [][]float64, d []float64, e []float64, H [][]float64, ort []...
function cdiv (line 850) | func cdiv(xr float64, xi float64, yr float64, yi float64) (cdivr float64...
FILE: dense_svd.go
method SVD (line 12) | func (Arg *DenseMatrix) SVD() (theU, Σ, theV *DenseMatrix, err error) {
FILE: dense_test.go
constant ε (line 14) | ε = 0.000001
constant verbose (line 15) | verbose = false
constant speedTest (line 16) | speedTest = true
function TestEquals (line 20) | func TestEquals(t *testing.T) {
function TestApproximates (line 32) | func TestApproximates(t *testing.T) {
function TestAdd (line 42) | func TestAdd(t *testing.T) {
function TestSubtract (line 58) | func TestSubtract(t *testing.T) {
function TestProduct (line 74) | func TestProduct(t *testing.T) {
function TestParallelProduct (line 115) | func TestParallelProduct(t *testing.T) {
function TestTimesDenseProcs (line 159) | func TestTimesDenseProcs(t *testing.T) {
function TestElementMult (line 174) | func TestElementMult(t *testing.T) {
function TestScale (line 206) | func TestScale(t *testing.T) {
function TestScaleMatrix (line 221) | func TestScaleMatrix(t *testing.T) {
function TestSymmetric (line 238) | func TestSymmetric(t *testing.T) {
function TestInverse (line 261) | func TestInverse(t *testing.T) {
function TestDet (line 288) | func TestDet(t *testing.T) {
function TestTrace (line 303) | func TestTrace(t *testing.T) {
function TestTranspose (line 318) | func TestTranspose(t *testing.T) {
function TestSolve (line 330) | func TestSolve(t *testing.T) {
function TestCholesky (line 353) | func TestCholesky(t *testing.T) {
function TestLU (line 368) | func TestLU(t *testing.T) {
function TestQR (line 422) | func TestQR(t *testing.T) {
function TestEigen (line 456) | func TestEigen(t *testing.T) {
function TestSVD (line 503) | func TestSVD(t *testing.T) {
function TestGetMatrix (line 526) | func TestGetMatrix(t *testing.T) {
function TestL (line 535) | func TestL(t *testing.T) {
function TestU (line 571) | func TestU(t *testing.T) {
function TestAugment (line 607) | func TestAugment(t *testing.T) {
function TestStack (line 653) | func TestStack(t *testing.T) {
function TestZeros (line 702) | func TestZeros(t *testing.T) {
function TestNumbers (line 713) | func TestNumbers(t *testing.T) {
function TestOnes (line 728) | func TestOnes(t *testing.T) {
function TestEye (line 740) | func TestEye(t *testing.T) {
function TestNormals (line 752) | func TestNormals(t *testing.T) {
function TestKronecker (line 760) | func TestKronecker(t *testing.T) {
function TestVectorize (line 773) | func TestVectorize(t *testing.T) {
function TestSubmatrix (line 782) | func TestSubmatrix(t *testing.T) {
FILE: densebench_test.go
function BenchmarkTransposeTimes (line 9) | func BenchmarkTransposeTimes(b *testing.B) {
FILE: error.go
constant errorNilMatrix (line 11) | errorNilMatrix = iota + 1
constant errorDimensionMismatch (line 13) | errorDimensionMismatch
constant errorIllegalIndex (line 15) | errorIllegalIndex
constant exceptionSingular (line 17) | exceptionSingular
constant exceptionNotSPD (line 19) | exceptionNotSPD
type error_ (line 22) | type error_
method Error (line 24) | func (e error_) Error() string {
method String (line 39) | func (e error_) String() string {
FILE: matrix.go
type MatrixRO (line 22) | type MatrixRO interface
type Matrix (line 58) | type Matrix interface
type matrix (line 69) | type matrix struct
method Nil (line 74) | func (A *matrix) Nil() bool { return A == nil }
method Rows (line 76) | func (A *matrix) Rows() int { return A.rows }
method Cols (line 78) | func (A *matrix) Cols() int { return A.cols }
method NumElements (line 80) | func (A *matrix) NumElements() int { return A.rows * A.cols }
method GetSize (line 82) | func (A *matrix) GetSize() (rows, cols int) {
function ParseMatlab (line 93) | func ParseMatlab(txt string) (A *DenseMatrix, err error) {
function String (line 180) | func String(A MatrixRO) string {
FILE: matrix_test.go
function TestParse (line 7) | func TestParse(t *testing.T) {
FILE: pivot.go
type PivotMatrix (line 11) | type PivotMatrix struct
method Get (line 17) | func (P *PivotMatrix) Get(i, j int) float64 {
method DenseMatrix (line 35) | func (P *PivotMatrix) DenseMatrix() *DenseMatrix {
method SparseMatrix (line 46) | func (P *PivotMatrix) SparseMatrix() *SparseMatrix {
method Copy (line 57) | func (P *PivotMatrix) Copy() *PivotMatrix { return MakePivotMatrix(P.p...
method String (line 69) | func (A *PivotMatrix) String() string { return String(A) }
function MakePivotMatrix (line 59) | func MakePivotMatrix(pivots []int, pivotSign float64) *PivotMatrix {
FILE: pivot_arithmetic.go
method Minus (line 7) | func (P *PivotMatrix) Minus(A MatrixRO) (Matrix, error) {
method Plus (line 16) | func (P *PivotMatrix) Plus(A MatrixRO) (Matrix, error) {
method Times (line 28) | func (P *PivotMatrix) Times(A MatrixRO) (Matrix, error) {
method TimesPivot (line 47) | func (P *PivotMatrix) TimesPivot(A *PivotMatrix) (*PivotMatrix, error) {
method RowPivotDense (line 65) | func (P *PivotMatrix) RowPivotDense(A *DenseMatrix) (*DenseMatrix, error) {
method ColPivotDense (line 84) | func (P *PivotMatrix) ColPivotDense(A *DenseMatrix) (*DenseMatrix, error) {
method RowPivotSparse (line 103) | func (P *PivotMatrix) RowPivotSparse(A *SparseMatrix) (*SparseMatrix, er...
method ColPivotSparse (line 120) | func (P *PivotMatrix) ColPivotSparse(A *SparseMatrix) (*SparseMatrix, er...
FILE: pivot_basic.go
method SwapRows (line 12) | func (P *PivotMatrix) SwapRows(r1, r2 int) error {
method Symmetric (line 22) | func (P *PivotMatrix) Symmetric() bool {
method Inverse (line 31) | func (A *PivotMatrix) Inverse() *PivotMatrix { return A.Transpose() }
method Transpose (line 33) | func (P *PivotMatrix) Transpose() *PivotMatrix {
method Det (line 41) | func (P *PivotMatrix) Det() float64 { return P.pivotSign }
method Trace (line 43) | func (P *PivotMatrix) Trace() (r float64) {
method Solve (line 55) | func (P *PivotMatrix) Solve(b MatrixRO) (Matrix, error) {
method OneNorm (line 59) | func (A *PivotMatrix) OneNorm() float64 { return float64(A.rows) }
method TwoNorm (line 60) | func (A *PivotMatrix) TwoNorm() float64 { return math.Sqrt(float64(...
method InfinityNorm (line 61) | func (A *PivotMatrix) InfinityNorm() float64 { return 1 }
FILE: pivot_test.go
function TestTimes_Pivot (line 10) | func TestTimes_Pivot(t *testing.T) {
function TestRowPivot (line 22) | func TestRowPivot(t *testing.T) {
function TestColPivot (line 43) | func TestColPivot(t *testing.T) {
FILE: sparse.go
type SparseMatrix (line 12) | type SparseMatrix struct
method Get (line 22) | func (A *SparseMatrix) Get(i, j int) float64 {
method GetIndex (line 38) | func (A *SparseMatrix) GetIndex(index int) float64 {
method GetRowIndex (line 49) | func (A *SparseMatrix) GetRowIndex(index int) (i int) {
method GetColIndex (line 57) | func (A *SparseMatrix) GetColIndex(index int) (j int) {
method GetRowColIndex (line 65) | func (A *SparseMatrix) GetRowColIndex(index int) (i int, j int) {
method Set (line 71) | func (A *SparseMatrix) Set(i int, j int, v float64) {
method SetIndex (line 91) | func (A *SparseMatrix) SetIndex(index int, v float64) {
method Indices (line 103) | func (A *SparseMatrix) Indices() (out chan int) {
method GetMatrix (line 122) | func (A *SparseMatrix) GetMatrix(i, j, rows, cols int) (subMatrix *Spa...
method GetColVector (line 143) | func (A *SparseMatrix) GetColVector(j int) *SparseMatrix {
method GetRowVector (line 150) | func (A *SparseMatrix) GetRowVector(i int) *SparseMatrix {
method Augment (line 157) | func (A *SparseMatrix) Augment(B *SparseMatrix) (*SparseMatrix, error) {
method Stack (line 179) | func (A *SparseMatrix) Stack(B *SparseMatrix) (*SparseMatrix, error) {
method L (line 201) | func (A *SparseMatrix) L() *SparseMatrix {
method U (line 215) | func (A *SparseMatrix) U() *SparseMatrix {
method Copy (line 226) | func (A *SparseMatrix) Copy() *SparseMatrix {
method DenseMatrix (line 269) | func (A *SparseMatrix) DenseMatrix() *DenseMatrix {
method SparseMatrix (line 278) | func (A *SparseMatrix) SparseMatrix() *SparseMatrix {
method String (line 282) | func (A *SparseMatrix) String() string { return String(A) }
function ZerosSparse (line 234) | func ZerosSparse(rows int, cols int) *SparseMatrix {
function NormalsSparse (line 247) | func NormalsSparse(rows int, cols int, n int) *SparseMatrix {
function MakeSparseMatrix (line 260) | func MakeSparseMatrix(elements map[int]float64, rows int, cols int) *Spa...
FILE: sparse_arithmetic.go
method Plus (line 10) | func (A *SparseMatrix) Plus(B MatrixRO) (Matrix, error) {
method PlusSparse (line 19) | func (A *SparseMatrix) PlusSparse(B *SparseMatrix) (*SparseMatrix, error) {
method Minus (line 28) | func (A *SparseMatrix) Minus(B MatrixRO) (Matrix, error) {
method MinusSparse (line 37) | func (A *SparseMatrix) MinusSparse(B *SparseMatrix) (*SparseMatrix, erro...
method Add (line 46) | func (A *SparseMatrix) Add(B MatrixRO) error {
method AddSparse (line 67) | func (A *SparseMatrix) AddSparse(B *SparseMatrix) error {
method Subtract (line 83) | func (A *SparseMatrix) Subtract(B MatrixRO) error {
method SubtractSparse (line 104) | func (A *SparseMatrix) SubtractSparse(B *SparseMatrix) error {
method Times (line 120) | func (A *SparseMatrix) Times(B MatrixRO) (Matrix, error) {
method TimesSparse (line 151) | func (A *SparseMatrix) TimesSparse(B *SparseMatrix) (*SparseMatrix, erro...
method Scale (line 176) | func (A *SparseMatrix) Scale(f float64) {
method ElementMult (line 185) | func (A *SparseMatrix) ElementMult(B MatrixRO) (*SparseMatrix, error) {
method ElementMultSparse (line 194) | func (A *SparseMatrix) ElementMultSparse(B *SparseMatrix) (*SparseMatrix...
method ScaleMatrix (line 203) | func (A *SparseMatrix) ScaleMatrix(B MatrixRO) error {
method ScaleMatrixSparse (line 219) | func (A *SparseMatrix) ScaleMatrixSparse(B *SparseMatrix) error {
FILE: sparse_basic.go
method SwapRows (line 12) | func (A *SparseMatrix) SwapRows(r1, r2 int) {
method ScaleRow (line 30) | func (A *SparseMatrix) ScaleRow(r int, f float64) {
method ScaleAddRow (line 42) | func (A *SparseMatrix) ScaleAddRow(rd, rs int, f float64) {
method Symmetric (line 51) | func (A *SparseMatrix) Symmetric() bool {
method Transpose (line 61) | func (A *SparseMatrix) Transpose() *SparseMatrix {
method Det (line 70) | func (A *SparseMatrix) Det() float64 {
method Trace (line 75) | func (A *SparseMatrix) Trace() (res float64) {
method OneNorm (line 85) | func (A *SparseMatrix) OneNorm() (res float64) {
method TwoNorm (line 92) | func (A *SparseMatrix) TwoNorm() float64 {
method InfinityNorm (line 100) | func (A *SparseMatrix) InfinityNorm() (res float64) {
FILE: sparse_test.go
function TestAdd_Sparse (line 13) | func TestAdd_Sparse(t *testing.T) {
function TestSubtract_Sparse (line 26) | func TestSubtract_Sparse(t *testing.T) {
function TestTimes_Sparse (line 39) | func TestTimes_Sparse(t *testing.T) {
function TestElementMult_Sparse (line 52) | func TestElementMult_Sparse(t *testing.T) {
function TestGetMatrix_Sparse (line 66) | func TestGetMatrix_Sparse(t *testing.T) {
function TestAugment_Sparse (line 85) | func TestAugment_Sparse(t *testing.T) {
function TestStack_Sparse (line 131) | func TestStack_Sparse(t *testing.T) {
FILE: util.go
function max (line 9) | func max(x, y float64) float64 {
function maxInt (line 16) | func maxInt(x, y int) int {
function min (line 23) | func min(x, y float64) float64 {
function minInt (line 30) | func minInt(x, y int) int {
function sum (line 37) | func sum(a []float64) (s float64) {
function product (line 44) | func product(a []float64) float64 {
type box (line 52) | type box interface
function countBoxes (line 54) | func countBoxes(start, cap int) chan box {
function parFor (line 65) | func parFor(inputs <-chan box, foo func(i box)) (wait func()) {
Condensed preview — 25 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (112K chars).
[
{
"path": "AUTHORS",
"chars": 45,
"preview": "John Asmuth <jasmuth@gmail.com>\nRyanne Dolan\n"
},
{
"path": "LICENSE",
"chars": 1229,
"preview": "\u0001\nCopyright (c) 2013 the AUTHORS. All rights reserved.\n\nRedistribution and use in source and binary forms, with or witho"
},
{
"path": "README",
"chars": 0,
"preview": ""
},
{
"path": "arithmetic.go",
"chars": 3660,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense.go",
"chars": 6867,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_arithmetic.go",
"chars": 7134,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_basic.go",
"chars": 3840,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_data.go",
"chars": 1539,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_decomp.go",
"chars": 3324,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_eigen.go",
"chars": 16283,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_svd.go",
"chars": 9248,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "dense_test.go",
"chars": 13461,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "densebench_test.go",
"chars": 692,
"preview": "package matrix\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc BenchmarkTransposeTimes(b *testing.B) {\n\tfmt.Println(\"benchma"
},
{
"path": "error.go",
"chars": 1542,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "matrix.go",
"chars": 3997,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "matrix_test.go",
"chars": 248,
"preview": "package matrix\n\nimport (\n\t\"testing\"\n)\n\nfunc TestParse(t *testing.T) {\n\ts := `[1 2 3;4 5 6]`\n\tA, err := ParseMatlab(s)\n\t\n"
},
{
"path": "pivot.go",
"chars": 1360,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "pivot_arithmetic.go",
"chars": 3052,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "pivot_basic.go",
"chars": 1432,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "pivot_test.go",
"chars": 1260,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "sparse.go",
"chars": 5772,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "sparse_arithmetic.go",
"chars": 4918,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "sparse_basic.go",
"chars": 2053,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "sparse_test.go",
"chars": 3374,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
},
{
"path": "util.go",
"chars": 1184,
"preview": "// Copyright 2009 The GoMatrix Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// li"
}
]
About this extraction
This page contains the full source code of the skelterjohn/go.matrix GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 25 files (95.2 KB), approximately 37.1k tokens, and a symbol index with 247 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.