cdense.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright ©2019 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. package mat
  5. import "gonum.org/v1/gonum/blas/cblas128"
  6. // Dense is a dense matrix representation with complex data.
  7. type CDense struct {
  8. mat cblas128.General
  9. capRows, capCols int
  10. }
  11. // Dims returns the number of rows and columns in the matrix.
  12. func (m *CDense) Dims() (r, c int) {
  13. return m.mat.Rows, m.mat.Cols
  14. }
  15. // H performs an implicit conjugate transpose by returning the receiver inside a
  16. // Conjugate.
  17. func (m *CDense) H() CMatrix {
  18. return Conjugate{m}
  19. }
  20. // NewCDense creates a new complex Dense matrix with r rows and c columns.
  21. // If data == nil, a new slice is allocated for the backing slice.
  22. // If len(data) == r*c, data is used as the backing slice, and changes to the
  23. // elements of the returned CDense will be reflected in data.
  24. // If neither of these is true, NewCDense will panic.
  25. // NewCDense will panic if either r or c is zero.
  26. //
  27. // The data must be arranged in row-major order, i.e. the (i*c + j)-th
  28. // element in the data slice is the {i, j}-th element in the matrix.
  29. func NewCDense(r, c int, data []complex128) *CDense {
  30. if r <= 0 || c <= 0 {
  31. if r == 0 || c == 0 {
  32. panic(ErrZeroLength)
  33. }
  34. panic("mat: negative dimension")
  35. }
  36. if data != nil && r*c != len(data) {
  37. panic(ErrShape)
  38. }
  39. if data == nil {
  40. data = make([]complex128, r*c)
  41. }
  42. return &CDense{
  43. mat: cblas128.General{
  44. Rows: r,
  45. Cols: c,
  46. Stride: c,
  47. Data: data,
  48. },
  49. capRows: r,
  50. capCols: c,
  51. }
  52. }
  53. // reuseAs resizes an empty matrix to a r×c matrix,
  54. // or checks that a non-empty matrix is r×c.
  55. //
  56. // reuseAs must be kept in sync with reuseAsZeroed.
  57. func (m *CDense) reuseAs(r, c int) {
  58. if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols {
  59. // Panic as a string, not a mat.Error.
  60. panic("mat: caps not correctly set")
  61. }
  62. if r == 0 || c == 0 {
  63. panic(ErrZeroLength)
  64. }
  65. if m.IsZero() {
  66. m.mat = cblas128.General{
  67. Rows: r,
  68. Cols: c,
  69. Stride: c,
  70. Data: useC(m.mat.Data, r*c),
  71. }
  72. m.capRows = r
  73. m.capCols = c
  74. return
  75. }
  76. if r != m.mat.Rows || c != m.mat.Cols {
  77. panic(ErrShape)
  78. }
  79. }
  80. func (m *CDense) reuseAsZeroed(r, c int) {
  81. // This must be kept in-sync with reuseAs.
  82. if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols {
  83. // Panic as a string, not a mat.Error.
  84. panic("mat: caps not correctly set")
  85. }
  86. if r == 0 || c == 0 {
  87. panic(ErrZeroLength)
  88. }
  89. if m.IsZero() {
  90. m.mat = cblas128.General{
  91. Rows: r,
  92. Cols: c,
  93. Stride: c,
  94. Data: useZeroedC(m.mat.Data, r*c),
  95. }
  96. m.capRows = r
  97. m.capCols = c
  98. return
  99. }
  100. if r != m.mat.Rows || c != m.mat.Cols {
  101. panic(ErrShape)
  102. }
  103. m.Zero()
  104. }
  105. // Reset zeros the dimensions of the matrix so that it can be reused as the
  106. // receiver of a dimensionally restricted operation.
  107. //
  108. // See the Reseter interface for more information.
  109. func (m *CDense) Reset() {
  110. // Row, Cols and Stride must be zeroed in unison.
  111. m.mat.Rows, m.mat.Cols, m.mat.Stride = 0, 0, 0
  112. m.capRows, m.capCols = 0, 0
  113. m.mat.Data = m.mat.Data[:0]
  114. }
  115. // IsZero returns whether the receiver is zero-sized. Zero-sized matrices can be the
  116. // receiver for size-restricted operations. CDense matrices can be zeroed using Reset.
  117. func (m *CDense) IsZero() bool {
  118. // It must be the case that m.Dims() returns
  119. // zeros in this case. See comment in Reset().
  120. return m.mat.Stride == 0
  121. }
  122. // Zero sets all of the matrix elements to zero.
  123. func (m *CDense) Zero() {
  124. r := m.mat.Rows
  125. c := m.mat.Cols
  126. for i := 0; i < r; i++ {
  127. zeroC(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c])
  128. }
  129. }
  130. // Copy makes a copy of elements of a into the receiver. It is similar to the
  131. // built-in copy; it copies as much as the overlap between the two matrices and
  132. // returns the number of rows and columns it copied. If a aliases the receiver
  133. // and is a transposed Dense or VecDense, with a non-unitary increment, Copy will
  134. // panic.
  135. //
  136. // See the Copier interface for more information.
  137. func (m *CDense) Copy(a CMatrix) (r, c int) {
  138. r, c = a.Dims()
  139. if a == m {
  140. return r, c
  141. }
  142. r = min(r, m.mat.Rows)
  143. c = min(c, m.mat.Cols)
  144. if r == 0 || c == 0 {
  145. return 0, 0
  146. }
  147. // TODO(btracey): Check for overlap when complex version exists.
  148. // TODO(btracey): Add fast-paths.
  149. for i := 0; i < r; i++ {
  150. for j := 0; j < c; j++ {
  151. m.set(i, j, a.At(i, j))
  152. }
  153. }
  154. return r, c
  155. }