cdense.go 5.2 KB

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