Class: Ignis::Sparse::SparseMatrix
- Inherits:
-
Object
- Object
- Ignis::Sparse::SparseMatrix
- Defined in:
- lib/nvruby/sparse/sparse_matrix.rb
Overview
Sparse matrix representation with multiple format support
Instance Attribute Summary collapse
-
#col_indices ⇒ CUDA::Memory?
readonly
Column indices.
-
#device_index ⇒ Integer
readonly
Device index.
-
#dtype ⇒ Symbol
readonly
Data type.
-
#format ⇒ Symbol
readonly
Sparse format (:csr, :csc, :coo).
-
#nnz ⇒ Integer
readonly
Number of non-zero elements.
-
#row_indices ⇒ CUDA::Memory?
readonly
Row indices (for COO).
-
#row_ptr ⇒ CUDA::Memory?
readonly
CSR format: row_ptr, col_indices, values.
-
#shape ⇒ Array<Integer>
readonly
Matrix shape [rows, cols].
-
#values ⇒ CUDA::Memory?
readonly
Values array.
Class Method Summary collapse
-
.coo(values:, row_indices:, col_indices:, shape:, dtype: :float32, device: nil) ⇒ SparseMatrix
Create a sparse matrix in COO format.
-
.csr(values:, row_ptr:, col_indices:, shape:, dtype: :float32, device: nil) ⇒ SparseMatrix
Create a sparse matrix in CSR format.
-
.from_dense(dense, format: :csr, threshold: 0.0) ⇒ SparseMatrix
Create sparse matrix from dense NvArray.
-
.identity(size, dtype: :float32, device: nil) ⇒ SparseMatrix
Create identity sparse matrix.
Instance Method Summary collapse
-
#cols ⇒ Integer
Number of columns.
-
#density ⇒ Float
Density ratio.
-
#free! ⇒ void
Free all memory.
-
#on_device? ⇒ Boolean
Check if on device.
-
#rows ⇒ Integer
Number of rows.
-
#sparsity ⇒ Float
Sparsity ratio.
-
#spmv(x, y: nil, alpha: 1.0, beta: 0.0, transpose: false) ⇒ NvArray
Sparse matrix-vector multiplication: y = alpha * A * x + beta * y.
-
#to_dense ⇒ NvArray
Convert to dense NvArray.
-
#to_device(device: nil) ⇒ self
Transfer to GPU.
-
#to_host ⇒ self
Transfer data to host.
- #to_s ⇒ String
Instance Attribute Details
#col_indices ⇒ CUDA::Memory? (readonly)
Returns Column indices.
27 28 29 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 27 def col_indices @col_indices end |
#device_index ⇒ Integer (readonly)
Returns Device index.
20 21 22 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 20 def device_index @device_index end |
#dtype ⇒ Symbol (readonly)
Returns Data type.
17 18 19 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 17 def dtype @dtype end |
#format ⇒ Symbol (readonly)
Returns Sparse format (:csr, :csc, :coo).
8 9 10 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 8 def format @format end |
#nnz ⇒ Integer (readonly)
Returns Number of non-zero elements.
14 15 16 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 14 def nnz @nnz end |
#row_indices ⇒ CUDA::Memory? (readonly)
Returns Row indices (for COO).
30 31 32 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 30 def row_indices @row_indices end |
#row_ptr ⇒ CUDA::Memory? (readonly)
CSR format: row_ptr, col_indices, values
24 25 26 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 24 def row_ptr @row_ptr end |
#shape ⇒ Array<Integer> (readonly)
Returns Matrix shape [rows, cols].
11 12 13 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 11 def shape @shape end |
#values ⇒ CUDA::Memory? (readonly)
Returns Values array.
33 34 35 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 33 def values @values end |
Class Method Details
.coo(values:, row_indices:, col_indices:, shape:, dtype: :float32, device: nil) ⇒ SparseMatrix
Create a sparse matrix in COO format
57 58 59 60 61 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 57 def self.coo(values:, row_indices:, col_indices:, shape:, dtype: :float32, device: nil) matrix = new(format: :coo, shape: shape, nnz: values.size, dtype: dtype, device: device) matrix.send(:initialize_coo, values, row_indices, col_indices) matrix end |
.csr(values:, row_ptr:, col_indices:, shape:, dtype: :float32, device: nil) ⇒ SparseMatrix
Create a sparse matrix in CSR format
43 44 45 46 47 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 43 def self.csr(values:, row_ptr:, col_indices:, shape:, dtype: :float32, device: nil) matrix = new(format: :csr, shape: shape, nnz: values.size, dtype: dtype, device: device) matrix.send(:initialize_csr, values, row_ptr, col_indices) matrix end |
.from_dense(dense, format: :csr, threshold: 0.0) ⇒ SparseMatrix
Create sparse matrix from dense NvArray
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 82 def self.from_dense(dense, format: :csr, threshold: 0.0) raise ArgumentError, "Expected NvArray, got #{dense.class}" unless dense.is_a?(NvArray) raise DimensionError, "Expected 2D array, got #{dense.ndim}D" unless dense.ndim == 2 dense = dense.to_host unless dense.on_host? data = dense.flatten rows, cols = dense.shape row_indices = [] col_indices_arr = [] values_arr = [] data.each_with_index do |val, idx| next if val.abs <= threshold row_indices << idx / cols col_indices_arr << idx % cols values_arr << val end if format == :csr # Convert row indices to row pointer row_ptr = Array.new(rows + 1, 0) row_indices.each { |r| row_ptr[r + 1] += 1 } (1..rows).each { |i| row_ptr[i] += row_ptr[i - 1] } csr(values: values_arr, row_ptr: row_ptr, col_indices: col_indices_arr, shape: [rows, cols], dtype: dense.dtype, device: dense.device_index) else coo(values: values_arr, row_indices: row_indices, col_indices: col_indices_arr, shape: [rows, cols], dtype: dense.dtype, device: dense.device_index) end end |
.identity(size, dtype: :float32, device: nil) ⇒ SparseMatrix
Create identity sparse matrix
68 69 70 71 72 73 74 75 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 68 def self.identity(size, dtype: :float32, device: nil) values = Array.new(size, 1.0) row_ptr = (0..size).to_a col_indices = (0...size).to_a csr(values: values, row_ptr: row_ptr, col_indices: col_indices, shape: [size, size], dtype: dtype, device: device) end |
Instance Method Details
#cols ⇒ Integer
Returns Number of columns.
122 123 124 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 122 def cols @shape[1] end |
#density ⇒ Float
Density ratio
134 135 136 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 134 def density @nnz.to_f / (rows * cols) end |
#free! ⇒ void
This method returns an undefined value.
Free all memory
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 216 def free! @row_ptr&.free! @col_indices&.free! @row_indices&.free! @values&.free! @row_ptr = nil @col_indices = nil @row_indices = nil @values = nil @on_device = false end |
#on_device? ⇒ Boolean
Check if on device
169 170 171 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 169 def on_device? @on_device end |
#rows ⇒ Integer
Returns Number of rows.
117 118 119 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 117 def rows @shape[0] end |
#sparsity ⇒ Float
Sparsity ratio
128 129 130 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 128 def sparsity 1.0 - (@nnz.to_f / (rows * cols)) end |
#spmv(x, y: nil, alpha: 1.0, beta: 0.0, transpose: false) ⇒ NvArray
Sparse matrix-vector multiplication: y = alpha * A * x + beta * y
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 195 def spmv(x, y: nil, alpha: 1.0, beta: 0.0, transpose: false) raise ArgumentError, "Expected NvArray, got #{x.class}" unless x.is_a?(NvArray) out_rows = transpose ? cols : rows in_cols = transpose ? rows : cols raise DimensionError, "Vector size #{x.size} != matrix cols #{in_cols}" unless x.size == in_cols to_device unless on_device? x = x.to_device unless x.on_device? y ||= NvArray.zeros([out_rows], dtype: @dtype, device: @device_index) y = y.to_device unless y.on_device? execute_spmv(x, y, alpha, beta, transpose) y end |
#to_dense ⇒ NvArray
Convert to dense NvArray
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 175 def to_dense result = NvArray.zeros(@shape, dtype: @dtype, device: nil) case @format when :csr (result) when :coo (result) end result end |
#to_device(device: nil) ⇒ self
Transfer to GPU
141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 141 def to_device(device: nil) target_device = device || @device_index case @format when :csr transfer_csr_to_device(target_device) when :coo transfer_coo_to_device(target_device) end @device_index = target_device @on_device = true self end |
#to_host ⇒ self
Transfer data to host
158 159 160 161 162 163 164 165 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 158 def to_host return self unless on_device? # Currently we don't support device-side mutation of sparse structures # so the host copy is already up to date. We just free device memory. free! self end |
#to_s ⇒ String
230 231 232 |
# File 'lib/nvruby/sparse/sparse_matrix.rb', line 230 def to_s "SparseMatrix(shape=#{@shape}, nnz=#{@nnz}, format=#{@format}, density=#{(density * 100).round(2)}%)" end |