1 // Copyright ©2013 The Gonum Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
10 "gonum.org/v1/gonum/blas"
11 "gonum.org/v1/gonum/blas/blas64"
12 "gonum.org/v1/gonum/floats"
13 "gonum.org/v1/gonum/lapack"
14 "gonum.org/v1/gonum/lapack/lapack64"
17 // Matrix is the basic matrix interface type.
18 type Matrix interface {
19 // Dims returns the dimensions of a Matrix.
22 // At returns the value of a matrix element at row i, column j.
23 // It will panic if i or j are out of bounds for the matrix.
26 // T returns the transpose of the Matrix. Whether T returns a copy of the
27 // underlying data is implementation dependent.
28 // This method may be implemented using the Transpose type, which
29 // provides an implicit matrix transpose.
34 _ Matrix = Transpose{}
35 _ Untransposer = Transpose{}
38 // Transpose is a type for performing an implicit matrix transpose. It implements
39 // the Matrix interface, returning values from the transpose of the matrix within.
40 type Transpose struct {
44 // At returns the value of the element at row i and column j of the transposed
45 // matrix, that is, row j and column i of the Matrix field.
46 func (t Transpose) At(i, j int) float64 {
47 return t.Matrix.At(j, i)
50 // Dims returns the dimensions of the transposed matrix. The number of rows returned
51 // is the number of columns in the Matrix field, and the number of columns is
52 // the number of rows in the Matrix field.
53 func (t Transpose) Dims() (r, c int) {
54 c, r = t.Matrix.Dims()
58 // T performs an implicit transpose by returning the Matrix field.
59 func (t Transpose) T() Matrix {
63 // Untranspose returns the Matrix field.
64 func (t Transpose) Untranspose() Matrix {
68 // Untransposer is a type that can undo an implicit transpose.
69 type Untransposer interface {
70 // Note: This interface is needed to unify all of the Transpose types. In
71 // the mat methods, we need to test if the Matrix has been implicitly
72 // transposed. If this is checked by testing for the specific Transpose type
73 // then the behavior will be different if the user uses T() or TTri() for a
76 // Untranspose returns the underlying Matrix stored for the implicit transpose.
80 // UntransposeBander is a type that can undo an implicit band transpose.
81 type UntransposeBander interface {
82 // Untranspose returns the underlying Banded stored for the implicit transpose.
83 UntransposeBand() Banded
86 // UntransposeTrier is a type that can undo an implicit triangular transpose.
87 type UntransposeTrier interface {
88 // Untranspose returns the underlying Triangular stored for the implicit transpose.
89 UntransposeTri() Triangular
92 // Mutable is a matrix interface type that allows elements to be altered.
93 type Mutable interface {
94 // Set alters the matrix element at row i, column j to v.
95 // It will panic if i or j are out of bounds for the matrix.
96 Set(i, j int, v float64)
101 // A RowViewer can return a Vector reflecting a row that is backed by the matrix
102 // data. The Vector returned will have length equal to the number of columns.
103 type RowViewer interface {
104 RowView(i int) Vector
107 // A RawRowViewer can return a slice of float64 reflecting a row that is backed by the matrix
109 type RawRowViewer interface {
110 RawRowView(i int) []float64
113 // A ColViewer can return a Vector reflecting a column that is backed by the matrix
114 // data. The Vector returned will have length equal to the number of rows.
115 type ColViewer interface {
116 ColView(j int) Vector
119 // A RawColViewer can return a slice of float64 reflecting a column that is backed by the matrix
121 type RawColViewer interface {
122 RawColView(j int) []float64
125 // A Cloner can make a copy of a into the receiver, overwriting the previous value of the
126 // receiver. The clone operation does not make any restriction on shape and will not cause
128 type Cloner interface {
132 // A Reseter can reset the matrix so that it can be reused as the receiver of a dimensionally
133 // restricted operation. This is commonly used when the matrix is being used as a workspace
134 // or temporary matrix.
136 // If the matrix is a view, using the reset matrix may result in data corruption in elements
138 type Reseter interface {
142 // A Copier can make a copy of elements of a into the receiver. The submatrix copied
143 // starts at row and column 0 and has dimensions equal to the minimum dimensions of
144 // the two matrices. The number of row and columns copied is returned.
145 // Copy will copy from a source that aliases the receiver unless the source is transposed;
146 // an aliasing transpose copy will panic with the exception for a special case when
147 // the source data has a unitary increment or stride.
148 type Copier interface {
149 Copy(a Matrix) (r, c int)
152 // A Grower can grow the size of the represented matrix by the given number of rows and columns.
153 // Growing beyond the size given by the Caps method will result in the allocation of a new
154 // matrix and copying of the elements. If Grow is called with negative increments it will
155 // panic with ErrIndexOutOfRange.
156 type Grower interface {
158 Grow(r, c int) Matrix
161 // A BandWidther represents a banded matrix and can return the left and right half-bandwidths, k1 and
163 type BandWidther interface {
164 BandWidth() (k1, k2 int)
167 // A RawMatrixSetter can set the underlying blas64.General used by the receiver. There is no restriction
168 // on the shape of the receiver. Changes to the receiver's elements will be reflected in the blas64.General.Data.
169 type RawMatrixSetter interface {
170 SetRawMatrix(a blas64.General)
173 // A RawMatrixer can return a blas64.General representation of the receiver. Changes to the blas64.General.Data
174 // slice will be reflected in the original matrix, changes to the Rows, Cols and Stride fields will not.
175 type RawMatrixer interface {
176 RawMatrix() blas64.General
179 // A RawVectorer can return a blas64.Vector representation of the receiver. Changes to the blas64.Vector.Data
180 // slice will be reflected in the original matrix, changes to the Inc field will not.
181 type RawVectorer interface {
182 RawVector() blas64.Vector
185 // A NonZeroDoer can call a function for each non-zero element of the receiver.
186 // The parameters of the function are the element indices and its value.
187 type NonZeroDoer interface {
188 DoNonZero(func(i, j int, v float64))
191 // A RowNonZeroDoer can call a function for each non-zero element of a row of the receiver.
192 // The parameters of the function are the element indices and its value.
193 type RowNonZeroDoer interface {
194 DoRowNonZero(i int, fn func(i, j int, v float64))
197 // A ColNonZeroDoer can call a function for each non-zero element of a column of the receiver.
198 // The parameters of the function are the element indices and its value.
199 type ColNonZeroDoer interface {
200 DoColNonZero(j int, fn func(i, j int, v float64))
203 // TODO(btracey): Consider adding CopyCol/CopyRow if the behavior seems useful.
204 // TODO(btracey): Add in fast paths to Row/Col for the other concrete types
205 // (TriDense, etc.) as well as relevant interfaces (RowColer, RawRowViewer, etc.)
207 // Col copies the elements in the jth column of the matrix into the slice dst.
208 // The length of the provided slice must equal the number of rows, unless the
209 // slice is nil in which case a new slice is first allocated.
210 func Col(dst []float64, j int, a Matrix) []float64 {
216 dst = make([]float64, r)
222 aU, aTrans := untranspose(a)
223 if rm, ok := aU.(RawMatrixer); ok {
226 copy(dst, m.Data[j*m.Stride:j*m.Stride+m.Cols])
230 blas64.Vector{Inc: m.Stride, Data: m.Data[j:]},
231 blas64.Vector{Inc: 1, Data: dst},
235 for i := 0; i < r; i++ {
241 // Row copies the elements in the ith row of the matrix into the slice dst.
242 // The length of the provided slice must equal the number of columns, unless the
243 // slice is nil in which case a new slice is first allocated.
244 func Row(dst []float64, i int, a Matrix) []float64 {
250 dst = make([]float64, c)
256 aU, aTrans := untranspose(a)
257 if rm, ok := aU.(RawMatrixer); ok {
261 blas64.Vector{Inc: m.Stride, Data: m.Data[i:]},
262 blas64.Vector{Inc: 1, Data: dst},
266 copy(dst, m.Data[i*m.Stride:i*m.Stride+m.Cols])
269 for j := 0; j < c; j++ {
275 // Cond returns the condition number of the given matrix under the given norm.
276 // The condition number must be based on the 1-norm, 2-norm or ∞-norm.
277 // Cond will panic with matrix.ErrShape if the matrix has zero size.
279 // BUG(btracey): The computation of the 1-norm and ∞-norm for non-square matrices
280 // is innacurate, although is typically the right order of magnitude. See
281 // https://github.com/xianyi/OpenBLAS/issues/636. While the value returned will
282 // change with the resolution of this bug, the result from Cond will match the
283 // condition number used internally.
284 func Cond(a Matrix, norm float64) float64 {
286 if m == 0 || n == 0 {
289 var lnorm lapack.MatrixNorm
292 panic("mat: bad norm value")
294 lnorm = lapack.MaxColumnSum
297 ok := svd.Factorize(a, SVDNone)
303 lnorm = lapack.MaxRowSum
307 // Use the LU decomposition to compute the condition number.
309 lu.factorize(a, lnorm)
313 // Use the QR factorization to compute the condition number.
315 qr.factorize(a, lnorm)
318 // Use the LQ factorization to compute the condition number.
320 lq.factorize(a, lnorm)
324 // Det returns the determinant of the matrix a. In many expressions using LogDet
325 // will be more numerically stable.
326 func Det(a Matrix) float64 {
327 det, sign := LogDet(a)
328 return math.Exp(det) * sign
331 // Dot returns the sum of the element-wise product of a and b.
332 // Dot panics if the matrix sizes are unequal.
333 func Dot(a, b Vector) float64 {
339 if arv, ok := a.(RawVectorer); ok {
340 if brv, ok := b.(RawVectorer); ok {
341 return blas64.Dot(la, arv.RawVector(), brv.RawVector())
345 for i := 0; i < la; i++ {
346 sum += a.At(i, 0) * b.At(i, 0)
351 // Equal returns whether the matrices a and b have the same size
352 // and are element-wise equal.
353 func Equal(a, b Matrix) bool {
356 if ar != br || ac != bc {
359 aU, aTrans := untranspose(a)
360 bU, bTrans := untranspose(b)
361 if rma, ok := aU.(RawMatrixer); ok {
362 if rmb, ok := bU.(RawMatrixer); ok {
363 ra := rma.RawMatrix()
364 rb := rmb.RawMatrix()
365 if aTrans == bTrans {
366 for i := 0; i < ra.Rows; i++ {
367 for j := 0; j < ra.Cols; j++ {
368 if ra.Data[i*ra.Stride+j] != rb.Data[i*rb.Stride+j] {
375 for i := 0; i < ra.Rows; i++ {
376 for j := 0; j < ra.Cols; j++ {
377 if ra.Data[i*ra.Stride+j] != rb.Data[j*rb.Stride+i] {
385 if rma, ok := aU.(RawSymmetricer); ok {
386 if rmb, ok := bU.(RawSymmetricer); ok {
387 ra := rma.RawSymmetric()
388 rb := rmb.RawSymmetric()
389 // Symmetric matrices are always upper and equal to their transpose.
390 for i := 0; i < ra.N; i++ {
391 for j := i; j < ra.N; j++ {
392 if ra.Data[i*ra.Stride+j] != rb.Data[i*rb.Stride+j] {
400 if ra, ok := aU.(*VecDense); ok {
401 if rb, ok := bU.(*VecDense); ok {
402 // If the raw vectors are the same length they must either both be
403 // transposed or both not transposed (or have length 1).
404 for i := 0; i < ra.n; i++ {
405 if ra.mat.Data[i*ra.mat.Inc] != rb.mat.Data[i*rb.mat.Inc] {
412 for i := 0; i < ar; i++ {
413 for j := 0; j < ac; j++ {
414 if a.At(i, j) != b.At(i, j) {
422 // EqualApprox returns whether the matrices a and b have the same size and contain all equal
423 // elements with tolerance for element-wise equality specified by epsilon. Matrices
424 // with non-equal shapes are not equal.
425 func EqualApprox(a, b Matrix, epsilon float64) bool {
428 if ar != br || ac != bc {
431 aU, aTrans := untranspose(a)
432 bU, bTrans := untranspose(b)
433 if rma, ok := aU.(RawMatrixer); ok {
434 if rmb, ok := bU.(RawMatrixer); ok {
435 ra := rma.RawMatrix()
436 rb := rmb.RawMatrix()
437 if aTrans == bTrans {
438 for i := 0; i < ra.Rows; i++ {
439 for j := 0; j < ra.Cols; j++ {
440 if !floats.EqualWithinAbsOrRel(ra.Data[i*ra.Stride+j], rb.Data[i*rb.Stride+j], epsilon, epsilon) {
447 for i := 0; i < ra.Rows; i++ {
448 for j := 0; j < ra.Cols; j++ {
449 if !floats.EqualWithinAbsOrRel(ra.Data[i*ra.Stride+j], rb.Data[j*rb.Stride+i], epsilon, epsilon) {
457 if rma, ok := aU.(RawSymmetricer); ok {
458 if rmb, ok := bU.(RawSymmetricer); ok {
459 ra := rma.RawSymmetric()
460 rb := rmb.RawSymmetric()
461 // Symmetric matrices are always upper and equal to their transpose.
462 for i := 0; i < ra.N; i++ {
463 for j := i; j < ra.N; j++ {
464 if !floats.EqualWithinAbsOrRel(ra.Data[i*ra.Stride+j], rb.Data[i*rb.Stride+j], epsilon, epsilon) {
472 if ra, ok := aU.(*VecDense); ok {
473 if rb, ok := bU.(*VecDense); ok {
474 // If the raw vectors are the same length they must either both be
475 // transposed or both not transposed (or have length 1).
476 for i := 0; i < ra.n; i++ {
477 if !floats.EqualWithinAbsOrRel(ra.mat.Data[i*ra.mat.Inc], rb.mat.Data[i*rb.mat.Inc], epsilon, epsilon) {
484 for i := 0; i < ar; i++ {
485 for j := 0; j < ac; j++ {
486 if !floats.EqualWithinAbsOrRel(a.At(i, j), b.At(i, j), epsilon, epsilon) {
494 // LogDet returns the log of the determinant and the sign of the determinant
495 // for the matrix that has been factorized. Numerical stability in product and
496 // division expressions is generally improved by working in log space.
497 func LogDet(a Matrix) (det float64, sign float64) {
498 // TODO(btracey): Add specialized routines for TriDense, etc.
504 // Max returns the largest element value of the matrix A.
505 // Max will panic with matrix.ErrShape if the matrix has zero size.
506 func Max(a Matrix) float64 {
508 if r == 0 || c == 0 {
512 aU, _ := untranspose(a)
513 switch m := aU.(type) {
517 for i := 0; i < rm.Rows; i++ {
518 for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] {
526 rm := m.RawTriangular()
527 // The max of a triangular is at least 0 unless the size is 1.
532 if rm.Uplo == blas.Upper {
533 for i := 0; i < rm.N; i++ {
534 for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] {
542 for i := 0; i < rm.N; i++ {
543 for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+i+1] {
551 rm := m.RawSymmetric()
552 if rm.Uplo != blas.Upper {
553 panic(badSymTriangle)
556 for i := 0; i < rm.N; i++ {
557 for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] {
567 for i := 0; i < r; i++ {
568 for j := 0; j < c; j++ {
579 // Min returns the smallest element value of the matrix A.
580 // Min will panic with matrix.ErrShape if the matrix has zero size.
581 func Min(a Matrix) float64 {
583 if r == 0 || c == 0 {
587 aU, _ := untranspose(a)
588 switch m := aU.(type) {
592 for i := 0; i < rm.Rows; i++ {
593 for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] {
601 rm := m.RawTriangular()
602 // The min of a triangular is at most 0 unless the size is 1.
607 if rm.Uplo == blas.Upper {
608 for i := 0; i < rm.N; i++ {
609 for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] {
617 for i := 0; i < rm.N; i++ {
618 for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+i+1] {
626 rm := m.RawSymmetric()
627 if rm.Uplo != blas.Upper {
628 panic(badSymTriangle)
631 for i := 0; i < rm.N; i++ {
632 for _, v := range rm.Data[i*rm.Stride+i : i*rm.Stride+rm.N] {
642 for i := 0; i < r; i++ {
643 for j := 0; j < c; j++ {
654 // Norm returns the specified (induced) norm of the matrix a. See
655 // https://en.wikipedia.org/wiki/Matrix_norm for the definition of an induced norm.
658 // 1 - The maximum absolute column sum
659 // 2 - Frobenius norm, the square root of the sum of the squares of the elements.
660 // Inf - The maximum absolute row sum.
661 // Norm will panic with ErrNormOrder if an illegal norm order is specified and
662 // with matrix.ErrShape if the matrix has zero size.
663 func Norm(a Matrix, norm float64) float64 {
665 if r == 0 || c == 0 {
668 aU, aTrans := untranspose(a)
670 switch rma := aU.(type) {
672 rm := rma.RawMatrix()
673 n := normLapack(norm, aTrans)
674 if n == lapack.MaxColumnSum {
675 work = getFloats(rm.Cols, false)
676 defer putFloats(work)
678 return lapack64.Lange(n, rm, work)
680 rm := rma.RawTriangular()
681 n := normLapack(norm, aTrans)
682 if n == lapack.MaxRowSum || n == lapack.MaxColumnSum {
683 work = getFloats(rm.N, false)
684 defer putFloats(work)
686 return lapack64.Lantr(n, rm, work)
688 rm := rma.RawSymmetric()
689 n := normLapack(norm, aTrans)
690 if n == lapack.MaxRowSum || n == lapack.MaxColumnSum {
691 work = getFloats(rm.N, false)
692 defer putFloats(work)
694 return lapack64.Lansy(n, rm, work)
696 rv := rma.RawVector()
702 imax := blas64.Iamax(rma.n, rv)
703 return math.Abs(rma.At(imax, 0))
705 return blas64.Asum(rma.n, rv)
707 return blas64.Nrm2(rma.n, rv)
710 return blas64.Asum(rma.n, rv)
712 imax := blas64.Iamax(rma.n, rv)
713 return math.Abs(rma.At(imax, 0))
721 for j := 0; j < c; j++ {
723 for i := 0; i < r; i++ {
724 sum += math.Abs(a.At(i, j))
733 for i := 0; i < r; i++ {
734 for j := 0; j < c; j++ {
739 return math.Sqrt(sum)
742 for i := 0; i < r; i++ {
744 for j := 0; j < c; j++ {
745 sum += math.Abs(a.At(i, j))
755 // normLapack converts the float64 norm input in Norm to a lapack.MatrixNorm.
756 func normLapack(norm float64, aTrans bool) lapack.MatrixNorm {
759 n := lapack.MaxColumnSum
765 return lapack.NormFrob
767 n := lapack.MaxRowSum
769 n = lapack.MaxColumnSum
777 // Sum returns the sum of the elements of the matrix.
778 func Sum(a Matrix) float64 {
779 // TODO(btracey): Add a fast path for the other supported matrix types.
783 aU, _ := untranspose(a)
784 if rma, ok := aU.(RawMatrixer); ok {
785 rm := rma.RawMatrix()
786 for i := 0; i < rm.Rows; i++ {
787 for _, v := range rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols] {
793 for i := 0; i < r; i++ {
794 for j := 0; j < c; j++ {
801 // Trace returns the trace of the matrix. Trace will panic if the
802 // matrix is not square.
803 func Trace(a Matrix) float64 {
809 aU, _ := untranspose(a)
810 switch m := aU.(type) {
814 for i := 0; i < r; i++ {
815 t += rm.Data[i*rm.Stride+i]
819 rm := m.RawTriangular()
821 for i := 0; i < r; i++ {
822 t += rm.Data[i*rm.Stride+i]
826 rm := m.RawSymmetric()
828 for i := 0; i < r; i++ {
829 t += rm.Data[i*rm.Stride+i]
834 for i := 0; i < r; i++ {
841 func min(a, b int) int {
848 func max(a, b int) int {
855 // use returns a float64 slice with l elements, using f if it
856 // has the necessary capacity, otherwise creating a new slice.
857 func use(f []float64, l int) []float64 {
861 return make([]float64, l)
864 // useZeroed returns a float64 slice with l elements, using f if it
865 // has the necessary capacity, otherwise creating a new slice. The
866 // elements of the returned slice are guaranteed to be zero.
867 func useZeroed(f []float64, l int) []float64 {
873 return make([]float64, l)
876 // zero zeros the given slice's elements.
877 func zero(f []float64) {
883 // useInt returns an int slice with l elements, using i if it
884 // has the necessary capacity, otherwise creating a new slice.
885 func useInt(i []int, l int) []int {
889 return make([]int, l)