gonum.org/v1/gonum@v0.14.0/mat/dense.go (about)

     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.
     4  
     5  package mat
     6  
     7  import (
     8  	"gonum.org/v1/gonum/blas"
     9  	"gonum.org/v1/gonum/blas/blas64"
    10  	"gonum.org/v1/gonum/lapack"
    11  	"gonum.org/v1/gonum/lapack/lapack64"
    12  )
    13  
    14  var (
    15  	dense *Dense
    16  
    17  	_ Matrix      = dense
    18  	_ allMatrix   = dense
    19  	_ denseMatrix = dense
    20  	_ Mutable     = dense
    21  
    22  	_ ClonerFrom   = dense
    23  	_ RowViewer    = dense
    24  	_ ColViewer    = dense
    25  	_ RawRowViewer = dense
    26  	_ Grower       = dense
    27  
    28  	_ RawMatrixSetter = dense
    29  	_ RawMatrixer     = dense
    30  
    31  	_ Reseter = dense
    32  )
    33  
    34  // Dense is a dense matrix representation.
    35  type Dense struct {
    36  	mat blas64.General
    37  
    38  	capRows, capCols int
    39  }
    40  
    41  // NewDense creates a new Dense matrix with r rows and c columns. If data == nil,
    42  // a new slice is allocated for the backing slice. If len(data) == r*c, data is
    43  // used as the backing slice, and changes to the elements of the returned Dense
    44  // will be reflected in data. If neither of these is true, NewDense will panic.
    45  // NewDense will panic if either r or c is zero.
    46  //
    47  // The data must be arranged in row-major order, i.e. the (i*c + j)-th
    48  // element in the data slice is the {i, j}-th element in the matrix.
    49  func NewDense(r, c int, data []float64) *Dense {
    50  	if r <= 0 || c <= 0 {
    51  		if r == 0 || c == 0 {
    52  			panic(ErrZeroLength)
    53  		}
    54  		panic(ErrNegativeDimension)
    55  	}
    56  	if data != nil && r*c != len(data) {
    57  		panic(ErrShape)
    58  	}
    59  	if data == nil {
    60  		data = make([]float64, r*c)
    61  	}
    62  	return &Dense{
    63  		mat: blas64.General{
    64  			Rows:   r,
    65  			Cols:   c,
    66  			Stride: c,
    67  			Data:   data,
    68  		},
    69  		capRows: r,
    70  		capCols: c,
    71  	}
    72  }
    73  
    74  // ReuseAs changes the receiver if it IsEmpty() to be of size r×c.
    75  //
    76  // ReuseAs re-uses the backing data slice if it has sufficient capacity,
    77  // otherwise a new slice is allocated. The backing data is zero on return.
    78  //
    79  // ReuseAs panics if the receiver is not empty, and panics if
    80  // the input sizes are less than one. To empty the receiver for re-use,
    81  // Reset should be used.
    82  func (m *Dense) ReuseAs(r, c int) {
    83  	if r <= 0 || c <= 0 {
    84  		if r == 0 || c == 0 {
    85  			panic(ErrZeroLength)
    86  		}
    87  		panic(ErrNegativeDimension)
    88  	}
    89  	if !m.IsEmpty() {
    90  		panic(ErrReuseNonEmpty)
    91  	}
    92  	m.reuseAsZeroed(r, c)
    93  }
    94  
    95  // reuseAsNonZeroed resizes an empty matrix to a r×c matrix,
    96  // or checks that a non-empty matrix is r×c. It does not zero
    97  // the data in the receiver.
    98  func (m *Dense) reuseAsNonZeroed(r, c int) {
    99  	// reuseAs must be kept in sync with reuseAsZeroed.
   100  	if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols {
   101  		// Panic as a string, not a mat.Error.
   102  		panic(badCap)
   103  	}
   104  	if r == 0 || c == 0 {
   105  		panic(ErrZeroLength)
   106  	}
   107  	if m.IsEmpty() {
   108  		m.mat = blas64.General{
   109  			Rows:   r,
   110  			Cols:   c,
   111  			Stride: c,
   112  			Data:   use(m.mat.Data, r*c),
   113  		}
   114  		m.capRows = r
   115  		m.capCols = c
   116  		return
   117  	}
   118  	if r != m.mat.Rows || c != m.mat.Cols {
   119  		panic(ErrShape)
   120  	}
   121  }
   122  
   123  // reuseAsZeroed resizes an empty matrix to a r×c matrix,
   124  // or checks that a non-empty matrix is r×c. It zeroes
   125  // all the elements of the matrix.
   126  func (m *Dense) reuseAsZeroed(r, c int) {
   127  	// reuseAsZeroed must be kept in sync with reuseAsNonZeroed.
   128  	if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols {
   129  		// Panic as a string, not a mat.Error.
   130  		panic(badCap)
   131  	}
   132  	if r == 0 || c == 0 {
   133  		panic(ErrZeroLength)
   134  	}
   135  	if m.IsEmpty() {
   136  		m.mat = blas64.General{
   137  			Rows:   r,
   138  			Cols:   c,
   139  			Stride: c,
   140  			Data:   useZeroed(m.mat.Data, r*c),
   141  		}
   142  		m.capRows = r
   143  		m.capCols = c
   144  		return
   145  	}
   146  	if r != m.mat.Rows || c != m.mat.Cols {
   147  		panic(ErrShape)
   148  	}
   149  	m.Zero()
   150  }
   151  
   152  // Zero sets all of the matrix elements to zero.
   153  func (m *Dense) Zero() {
   154  	r := m.mat.Rows
   155  	c := m.mat.Cols
   156  	for i := 0; i < r; i++ {
   157  		zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c])
   158  	}
   159  }
   160  
   161  // isolatedWorkspace returns a new dense matrix w with the size of a and
   162  // returns a callback to defer which performs cleanup at the return of the call.
   163  // This should be used when a method receiver is the same pointer as an input argument.
   164  func (m *Dense) isolatedWorkspace(a Matrix) (w *Dense, restore func()) {
   165  	r, c := a.Dims()
   166  	if r == 0 || c == 0 {
   167  		panic(ErrZeroLength)
   168  	}
   169  	w = getDenseWorkspace(r, c, false)
   170  	return w, func() {
   171  		m.Copy(w)
   172  		putDenseWorkspace(w)
   173  	}
   174  }
   175  
   176  // Reset empties the matrix so that it can be reused as the
   177  // receiver of a dimensionally restricted operation.
   178  //
   179  // Reset should not be used when the matrix shares backing data.
   180  // See the Reseter interface for more information.
   181  func (m *Dense) Reset() {
   182  	// Row, Cols and Stride must be zeroed in unison.
   183  	m.mat.Rows, m.mat.Cols, m.mat.Stride = 0, 0, 0
   184  	m.capRows, m.capCols = 0, 0
   185  	m.mat.Data = m.mat.Data[:0]
   186  }
   187  
   188  // IsEmpty returns whether the receiver is empty. Empty matrices can be the
   189  // receiver for size-restricted operations. The receiver can be emptied using
   190  // Reset.
   191  func (m *Dense) IsEmpty() bool {
   192  	// It must be the case that m.Dims() returns
   193  	// zeros in this case. See comment in Reset().
   194  	return m.mat.Stride == 0
   195  }
   196  
   197  // asTriDense returns a TriDense with the given size and side. The backing data
   198  // of the TriDense is the same as the receiver.
   199  func (m *Dense) asTriDense(n int, diag blas.Diag, uplo blas.Uplo) *TriDense {
   200  	return &TriDense{
   201  		mat: blas64.Triangular{
   202  			N:      n,
   203  			Stride: m.mat.Stride,
   204  			Data:   m.mat.Data,
   205  			Uplo:   uplo,
   206  			Diag:   diag,
   207  		},
   208  		cap: n,
   209  	}
   210  }
   211  
   212  // DenseCopyOf returns a newly allocated copy of the elements of a.
   213  func DenseCopyOf(a Matrix) *Dense {
   214  	d := &Dense{}
   215  	d.CloneFrom(a)
   216  	return d
   217  }
   218  
   219  // SetRawMatrix sets the underlying blas64.General used by the receiver.
   220  // Changes to elements in the receiver following the call will be reflected
   221  // in b.
   222  func (m *Dense) SetRawMatrix(b blas64.General) {
   223  	m.capRows, m.capCols = b.Rows, b.Cols
   224  	m.mat = b
   225  }
   226  
   227  // RawMatrix returns the underlying blas64.General used by the receiver.
   228  // Changes to elements in the receiver following the call will be reflected
   229  // in returned blas64.General.
   230  func (m *Dense) RawMatrix() blas64.General { return m.mat }
   231  
   232  // Dims returns the number of rows and columns in the matrix.
   233  func (m *Dense) Dims() (r, c int) { return m.mat.Rows, m.mat.Cols }
   234  
   235  // Caps returns the number of rows and columns in the backing matrix.
   236  func (m *Dense) Caps() (r, c int) { return m.capRows, m.capCols }
   237  
   238  // T performs an implicit transpose by returning the receiver inside a Transpose.
   239  func (m *Dense) T() Matrix {
   240  	return Transpose{m}
   241  }
   242  
   243  // ColView returns a Vector reflecting the column j, backed by the matrix data.
   244  //
   245  // See ColViewer for more information.
   246  func (m *Dense) ColView(j int) Vector {
   247  	var v VecDense
   248  	v.ColViewOf(m, j)
   249  	return &v
   250  }
   251  
   252  // SetCol sets the values in the specified column of the matrix to the values
   253  // in src. len(src) must equal the number of rows in the receiver.
   254  func (m *Dense) SetCol(j int, src []float64) {
   255  	if j >= m.mat.Cols || j < 0 {
   256  		panic(ErrColAccess)
   257  	}
   258  	if len(src) != m.mat.Rows {
   259  		panic(ErrColLength)
   260  	}
   261  
   262  	blas64.Copy(
   263  		blas64.Vector{N: m.mat.Rows, Inc: 1, Data: src},
   264  		blas64.Vector{N: m.mat.Rows, Inc: m.mat.Stride, Data: m.mat.Data[j:]},
   265  	)
   266  }
   267  
   268  // SetRow sets the values in the specified rows of the matrix to the values
   269  // in src. len(src) must equal the number of columns in the receiver.
   270  func (m *Dense) SetRow(i int, src []float64) {
   271  	if i >= m.mat.Rows || i < 0 {
   272  		panic(ErrRowAccess)
   273  	}
   274  	if len(src) != m.mat.Cols {
   275  		panic(ErrRowLength)
   276  	}
   277  
   278  	copy(m.rawRowView(i), src)
   279  }
   280  
   281  // RowView returns row i of the matrix data represented as a column vector,
   282  // backed by the matrix data.
   283  //
   284  // See RowViewer for more information.
   285  func (m *Dense) RowView(i int) Vector {
   286  	var v VecDense
   287  	v.RowViewOf(m, i)
   288  	return &v
   289  }
   290  
   291  // RawRowView returns a slice backed by the same array as backing the
   292  // receiver.
   293  func (m *Dense) RawRowView(i int) []float64 {
   294  	if i >= m.mat.Rows || i < 0 {
   295  		panic(ErrRowAccess)
   296  	}
   297  	return m.rawRowView(i)
   298  }
   299  
   300  func (m *Dense) rawRowView(i int) []float64 {
   301  	return m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+m.mat.Cols]
   302  }
   303  
   304  // DiagView returns the diagonal as a matrix backed by the original data.
   305  func (m *Dense) DiagView() Diagonal {
   306  	n := min(m.mat.Rows, m.mat.Cols)
   307  	return &DiagDense{
   308  		mat: blas64.Vector{
   309  			N:    n,
   310  			Inc:  m.mat.Stride + 1,
   311  			Data: m.mat.Data[:(n-1)*m.mat.Stride+n],
   312  		},
   313  	}
   314  }
   315  
   316  // Slice returns a new Matrix that shares backing data with the receiver.
   317  // The returned matrix starts at {i,j} of the receiver and extends k-i rows
   318  // and l-j columns. The final row in the resulting matrix is k-1 and the
   319  // final column is l-1.
   320  // Slice panics with ErrIndexOutOfRange if the slice is outside the capacity
   321  // of the receiver.
   322  func (m *Dense) Slice(i, k, j, l int) Matrix {
   323  	return m.slice(i, k, j, l)
   324  }
   325  
   326  func (m *Dense) slice(i, k, j, l int) *Dense {
   327  	mr, mc := m.Caps()
   328  	if i < 0 || mr <= i || j < 0 || mc <= j || k < i || mr < k || l < j || mc < l {
   329  		if i == k || j == l {
   330  			panic(ErrZeroLength)
   331  		}
   332  		panic(ErrIndexOutOfRange)
   333  	}
   334  	t := *m
   335  	t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (k-1)*t.mat.Stride+l]
   336  	t.mat.Rows = k - i
   337  	t.mat.Cols = l - j
   338  	t.capRows -= i
   339  	t.capCols -= j
   340  	return &t
   341  }
   342  
   343  // Grow returns the receiver expanded by r rows and c columns. If the dimensions
   344  // of the expanded matrix are outside the capacities of the receiver a new
   345  // allocation is made, otherwise not. Note the receiver itself is not modified
   346  // during the call to Grow.
   347  func (m *Dense) Grow(r, c int) Matrix {
   348  	if r < 0 || c < 0 {
   349  		panic(ErrIndexOutOfRange)
   350  	}
   351  	if r == 0 && c == 0 {
   352  		return m
   353  	}
   354  
   355  	r += m.mat.Rows
   356  	c += m.mat.Cols
   357  
   358  	var t Dense
   359  	switch {
   360  	case m.mat.Rows == 0 || m.mat.Cols == 0:
   361  		t.mat = blas64.General{
   362  			Rows:   r,
   363  			Cols:   c,
   364  			Stride: c,
   365  			// We zero because we don't know how the matrix will be used.
   366  			// In other places, the mat is immediately filled with a result;
   367  			// this is not the case here.
   368  			Data: useZeroed(m.mat.Data, r*c),
   369  		}
   370  	case r > m.capRows || c > m.capCols:
   371  		cr := max(r, m.capRows)
   372  		cc := max(c, m.capCols)
   373  		t.mat = blas64.General{
   374  			Rows:   r,
   375  			Cols:   c,
   376  			Stride: cc,
   377  			Data:   make([]float64, cr*cc),
   378  		}
   379  		t.capRows = cr
   380  		t.capCols = cc
   381  		// Copy the complete matrix over to the new matrix.
   382  		// Including elements not currently visible. Use a temporary structure
   383  		// to avoid modifying the receiver.
   384  		var tmp Dense
   385  		tmp.mat = blas64.General{
   386  			Rows:   m.mat.Rows,
   387  			Cols:   m.mat.Cols,
   388  			Stride: m.mat.Stride,
   389  			Data:   m.mat.Data,
   390  		}
   391  		tmp.capRows = m.capRows
   392  		tmp.capCols = m.capCols
   393  		t.Copy(&tmp)
   394  		return &t
   395  	default:
   396  		t.mat = blas64.General{
   397  			Data:   m.mat.Data[:(r-1)*m.mat.Stride+c],
   398  			Rows:   r,
   399  			Cols:   c,
   400  			Stride: m.mat.Stride,
   401  		}
   402  	}
   403  	t.capRows = r
   404  	t.capCols = c
   405  	return &t
   406  }
   407  
   408  // CloneFrom makes a copy of a into the receiver, overwriting the previous value of
   409  // the receiver. The clone from operation does not make any restriction on shape and
   410  // will not cause shadowing.
   411  //
   412  // See the ClonerFrom interface for more information.
   413  func (m *Dense) CloneFrom(a Matrix) {
   414  	r, c := a.Dims()
   415  	mat := blas64.General{
   416  		Rows:   r,
   417  		Cols:   c,
   418  		Stride: c,
   419  	}
   420  	m.capRows, m.capCols = r, c
   421  
   422  	aU, trans := untransposeExtract(a)
   423  	switch aU := aU.(type) {
   424  	case *Dense:
   425  		amat := aU.mat
   426  		mat.Data = make([]float64, r*c)
   427  		if trans {
   428  			for i := 0; i < r; i++ {
   429  				blas64.Copy(blas64.Vector{N: c, Inc: amat.Stride, Data: amat.Data[i : i+(c-1)*amat.Stride+1]},
   430  					blas64.Vector{N: c, Inc: 1, Data: mat.Data[i*c : (i+1)*c]})
   431  			}
   432  		} else {
   433  			for i := 0; i < r; i++ {
   434  				copy(mat.Data[i*c:(i+1)*c], amat.Data[i*amat.Stride:i*amat.Stride+c])
   435  			}
   436  		}
   437  	case *VecDense:
   438  		amat := aU.mat
   439  		mat.Data = make([]float64, aU.mat.N)
   440  		blas64.Copy(blas64.Vector{N: aU.mat.N, Inc: amat.Inc, Data: amat.Data},
   441  			blas64.Vector{N: aU.mat.N, Inc: 1, Data: mat.Data})
   442  	default:
   443  		mat.Data = make([]float64, r*c)
   444  		w := *m
   445  		w.mat = mat
   446  		for i := 0; i < r; i++ {
   447  			for j := 0; j < c; j++ {
   448  				w.set(i, j, a.At(i, j))
   449  			}
   450  		}
   451  		*m = w
   452  		return
   453  	}
   454  	m.mat = mat
   455  }
   456  
   457  // Copy makes a copy of elements of a into the receiver. It is similar to the
   458  // built-in copy; it copies as much as the overlap between the two matrices and
   459  // returns the number of rows and columns it copied. If a aliases the receiver
   460  // and is a transposed Dense or VecDense, with a non-unitary increment, Copy will
   461  // panic.
   462  //
   463  // See the Copier interface for more information.
   464  func (m *Dense) Copy(a Matrix) (r, c int) {
   465  	r, c = a.Dims()
   466  	if a == m {
   467  		return r, c
   468  	}
   469  	r = min(r, m.mat.Rows)
   470  	c = min(c, m.mat.Cols)
   471  	if r == 0 || c == 0 {
   472  		return 0, 0
   473  	}
   474  
   475  	aU, trans := untransposeExtract(a)
   476  	switch aU := aU.(type) {
   477  	case *Dense:
   478  		amat := aU.mat
   479  		if trans {
   480  			if amat.Stride != 1 {
   481  				m.checkOverlap(amat)
   482  			}
   483  			for i := 0; i < r; i++ {
   484  				blas64.Copy(blas64.Vector{N: c, Inc: amat.Stride, Data: amat.Data[i : i+(c-1)*amat.Stride+1]},
   485  					blas64.Vector{N: c, Inc: 1, Data: m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]})
   486  			}
   487  		} else {
   488  			switch o := offset(m.mat.Data, amat.Data); {
   489  			case o < 0:
   490  				for i := r - 1; i >= 0; i-- {
   491  					copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c])
   492  				}
   493  			case o > 0:
   494  				for i := 0; i < r; i++ {
   495  					copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c])
   496  				}
   497  			default:
   498  				// Nothing to do.
   499  			}
   500  		}
   501  	case *VecDense:
   502  		var n, stride int
   503  		amat := aU.mat
   504  		if trans {
   505  			if amat.Inc != 1 {
   506  				m.checkOverlap(aU.asGeneral())
   507  			}
   508  			n = c
   509  			stride = 1
   510  		} else {
   511  			n = r
   512  			stride = m.mat.Stride
   513  		}
   514  		if amat.Inc == 1 && stride == 1 {
   515  			copy(m.mat.Data, amat.Data[:n])
   516  			break
   517  		}
   518  		switch o := offset(m.mat.Data, amat.Data); {
   519  		case o < 0:
   520  			blas64.Copy(blas64.Vector{N: n, Inc: -amat.Inc, Data: amat.Data},
   521  				blas64.Vector{N: n, Inc: -stride, Data: m.mat.Data})
   522  		case o > 0:
   523  			blas64.Copy(blas64.Vector{N: n, Inc: amat.Inc, Data: amat.Data},
   524  				blas64.Vector{N: n, Inc: stride, Data: m.mat.Data})
   525  		default:
   526  			// Nothing to do.
   527  		}
   528  	default:
   529  		m.checkOverlapMatrix(aU)
   530  		for i := 0; i < r; i++ {
   531  			for j := 0; j < c; j++ {
   532  				m.set(i, j, a.At(i, j))
   533  			}
   534  		}
   535  	}
   536  
   537  	return r, c
   538  }
   539  
   540  // Stack appends the rows of b onto the rows of a, placing the result into the
   541  // receiver with b placed in the greater indexed rows. Stack will panic if the
   542  // two input matrices do not have the same number of columns or the constructed
   543  // stacked matrix is not the same shape as the receiver.
   544  func (m *Dense) Stack(a, b Matrix) {
   545  	ar, ac := a.Dims()
   546  	br, bc := b.Dims()
   547  	if ac != bc || m == a || m == b {
   548  		panic(ErrShape)
   549  	}
   550  
   551  	m.reuseAsNonZeroed(ar+br, ac)
   552  
   553  	m.Copy(a)
   554  	w := m.slice(ar, ar+br, 0, bc)
   555  	w.Copy(b)
   556  }
   557  
   558  // Augment creates the augmented matrix of a and b, where b is placed in the
   559  // greater indexed columns. Augment will panic if the two input matrices do
   560  // not have the same number of rows or the constructed augmented matrix is
   561  // not the same shape as the receiver.
   562  func (m *Dense) Augment(a, b Matrix) {
   563  	ar, ac := a.Dims()
   564  	br, bc := b.Dims()
   565  	if ar != br || m == a || m == b {
   566  		panic(ErrShape)
   567  	}
   568  
   569  	m.reuseAsNonZeroed(ar, ac+bc)
   570  
   571  	m.Copy(a)
   572  	w := m.slice(0, br, ac, ac+bc)
   573  	w.Copy(b)
   574  }
   575  
   576  // Trace returns the trace of the matrix.
   577  //
   578  // Trace will panic with ErrSquare if the matrix is not square and with
   579  // ErrZeroLength if the matrix has zero size.
   580  func (m *Dense) Trace() float64 {
   581  	r, c := m.Dims()
   582  	if r != c {
   583  		panic(ErrSquare)
   584  	}
   585  	if m.IsEmpty() {
   586  		panic(ErrZeroLength)
   587  	}
   588  	// TODO(btracey): could use internal asm sum routine.
   589  	var v float64
   590  	for i := 0; i < m.mat.Rows; i++ {
   591  		v += m.mat.Data[i*m.mat.Stride+i]
   592  	}
   593  	return v
   594  }
   595  
   596  // Norm returns the specified norm of the receiver. Valid norms are:
   597  //
   598  //	1 - The maximum absolute column sum
   599  //	2 - The Frobenius norm, the square root of the sum of the squares of the elements
   600  //	Inf - The maximum absolute row sum
   601  //
   602  // Norm will panic with ErrNormOrder if an illegal norm is specified and with
   603  // ErrShape if the matrix has zero size.
   604  func (m *Dense) Norm(norm float64) float64 {
   605  	if m.IsEmpty() {
   606  		panic(ErrZeroLength)
   607  	}
   608  	lnorm := normLapack(norm, false)
   609  	if lnorm == lapack.MaxColumnSum {
   610  		work := getFloat64s(m.mat.Cols, false)
   611  		defer putFloat64s(work)
   612  		return lapack64.Lange(lnorm, m.mat, work)
   613  	}
   614  	return lapack64.Lange(lnorm, m.mat, nil)
   615  }