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 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"); } */ 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

= -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 }