Class: Ignis::Solver::SparseSolver

Inherits:
Object
  • Object
show all
Defined in:
lib/nvruby/solver/sparse_solver.rb

Overview

High-level sparse linear solver using cuDSS Solves sparse systems of the form Ax = b using direct methods

cuDSS phases:

  1. Analysis: Reordering and symbolic factorization

  2. Factorization: Numerical factorization (LU, Cholesky, LDL)

  3. Solve: Forward/backward substitution

Examples:

Solve a sparse linear system

solver = Ignis::Solver::SparseSolver.new(sparse_matrix)
solver.analyze!
solver.factor!
x = solver.solve(b)
solver.destroy!

Quick solve (combines all phases)

x = Ignis::Solver::SparseSolver.solve(sparse_matrix, b)

Constant Summary collapse

MATRIX_TYPE_GENERAL =

Matrix types for cuDSS

0
MATRIX_TYPE_SYMMETRIC =
1
MATRIX_TYPE_HERMITIAN =
2
MATRIX_TYPE_SPD =

Symmetric Positive Definite

3
MATRIX_TYPE_HPD =

Hermitian Positive Definite

4
INDEX_BASE_ZERO =

Index base

0
INDEX_BASE_ONE =
1
CUDA_R_32F =

CUDA library data types (from library_types.h) cuDSS uses these for both value and index types

0
CUDA_R_64F =

float

1
CUDA_R_16F =

double

2
CUDA_C_32F =

half

4
CUDA_C_64F =

cuComplex

5
CUDA_R_32I =

cuDoubleComplex

10
CUDA_R_64I =

int32

24

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sparse_matrix, matrix_type: :general) ⇒ SparseSolver

Initialize sparse solver

Parameters:

  • sparse_matrix (Sparse::SparseMatrix)

    Sparse coefficient matrix A in CSR format

  • matrix_type (Symbol) (defaults to: :general)

    Type of matrix (:general, :symmetric, :spd, :hermitian, :hpd)



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/nvruby/solver/sparse_solver.rb', line 77

def initialize(sparse_matrix, matrix_type: :general)
  validate_matrix!(sparse_matrix)
  @matrix = sparse_matrix
  @matrix_type = matrix_type
  @analyzed = false
  @factored = false
  @handle = nil
  @config = nil
  @data = nil
  @matrix_wrapper = nil
  @placeholder_x = nil
  @placeholder_b = nil
  @stream = nil

  initialize_cudss!
end

Instance Attribute Details

#analyzedBoolean (readonly)

Returns Whether analysis has been performed.

Returns:

  • (Boolean)

    Whether analysis has been performed



53
54
55
# File 'lib/nvruby/solver/sparse_solver.rb', line 53

def analyzed
  @analyzed
end

#factoredBoolean (readonly)

Returns Whether factorization has been performed.

Returns:

  • (Boolean)

    Whether factorization has been performed



56
57
58
# File 'lib/nvruby/solver/sparse_solver.rb', line 56

def factored
  @factored
end

#matrixSparse::SparseMatrix (readonly)

Returns The sparse coefficient matrix.

Returns:



47
48
49
# File 'lib/nvruby/solver/sparse_solver.rb', line 47

def matrix
  @matrix
end

#matrix_typeSymbol (readonly)

Returns Matrix type (:general, :symmetric, :spd).

Returns:

  • (Symbol)

    Matrix type (:general, :symmetric, :spd)



50
51
52
# File 'lib/nvruby/solver/sparse_solver.rb', line 50

def matrix_type
  @matrix_type
end

Class Method Details

.solve(sparse_matrix, b, matrix_type: :general) ⇒ NvArray

Convenience method to solve a sparse system in one call

Parameters:

  • sparse_matrix (Sparse::SparseMatrix)

    Sparse coefficient matrix A

  • b (NvArray)

    Right-hand side vector/matrix b

  • matrix_type (Symbol) (defaults to: :general)

    Type of matrix (:general, :symmetric, :spd)

Returns:

  • (NvArray)

    Solution vector/matrix x



63
64
65
66
67
68
69
70
71
72
# File 'lib/nvruby/solver/sparse_solver.rb', line 63

def self.solve(sparse_matrix, b, matrix_type: :general)
  solver = new(sparse_matrix, matrix_type: matrix_type)
  begin
    solver.analyze!
    solver.factor!
    solver.solve(b)
  ensure
    solver.destroy!
  end
end

Instance Method Details

#analyze!self

Perform analysis phase (reordering + symbolic factorization)

Returns:

  • (self)

Raises:



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/nvruby/solver/sparse_solver.rb', line 96

def analyze!
  raise StateError, "cuDSS not initialized" unless @handle

  phase = CuDSSBindings::CUDSS_PHASE_ANALYSIS
  status = CuDSSBindings.cudssExecute(
    @handle, phase, @config, @data, @matrix_wrapper, @placeholder_x, @placeholder_b
  )
  CuDSSBindings.check_status!(status, "cuDSS analysis")

  @analyzed = true
  self
end

#destroy!void

This method returns an undefined value.

Release all cuDSS resources



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/nvruby/solver/sparse_solver.rb', line 174

def destroy!
  if @placeholder_x
    CuDSSBindings.cudssMatrixDestroy(@placeholder_x)
    @placeholder_x = nil
  end

  if @placeholder_b
    CuDSSBindings.cudssMatrixDestroy(@placeholder_b)
    @placeholder_b = nil
  end

  if @matrix_wrapper
    CuDSSBindings.cudssMatrixDestroy(@matrix_wrapper)
    @matrix_wrapper = nil
  end

  if @data && @handle
    CuDSSBindings.cudssDataDestroy(@handle, @data)
    @data = nil
  end

  if @config
    CuDSSBindings.cudssConfigDestroy(@config)
    @config = nil
  end

  if @handle
    CuDSSBindings.cudssDestroy(@handle)
    @handle = nil
  end

  @analyzed = false
  @factored = false
end

#factor!self

Perform numerical factorization

Returns:

  • (self)

Raises:



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/nvruby/solver/sparse_solver.rb', line 111

def factor!
  raise StateError, "Must call analyze! before factor!" unless @analyzed

  phase = CuDSSBindings::CUDSS_PHASE_FACTORIZATION
  status = CuDSSBindings.cudssExecute(
    @handle, phase, @config, @data, @matrix_wrapper, @placeholder_x, @placeholder_b
  )
  CuDSSBindings.check_status!(status, "cuDSS factorization")

  @factored = true
  self
end

#refactor!self

Refactor with updated numerical values (same sparsity pattern) Useful when solving multiple systems with same structure but different values

Returns:

  • (self)

Raises:



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/nvruby/solver/sparse_solver.rb', line 160

def refactor!
  raise StateError, "Must call factor! before refactor!" unless @factored

  phase = CuDSSBindings::CUDSS_PHASE_REFACTORIZATION
  status = CuDSSBindings.cudssExecute(
    @handle, phase, @config, @data, @matrix_wrapper, nil, nil
  )
  CuDSSBindings.check_status!(status, "cuDSS refactorization")

  self
end

#solve(b) ⇒ NvArray

Solve the system Ax = b

Parameters:

  • b (NvArray)

    Right-hand side vector/matrix

Returns:

  • (NvArray)

    Solution vector/matrix x

Raises:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/nvruby/solver/sparse_solver.rb', line 127

def solve(b)
  raise StateError, "Must call factor! before solve!" unless @factored

  validate_rhs!(b)

  # Ensure b is on device
  b_dev = b.on_device? ? b : b.to_device

  # Create output matrix
  x = NvArray.zeros(b.shape, dtype: b.dtype, device: @matrix.device_index)
  x = x.to_device

  # Create cuDSS matrix wrappers for b and x
  b_wrapper = create_dense_matrix_wrapper(b_dev)
  x_wrapper = create_dense_matrix_wrapper(x)

  # Execute solve phase
  phase = CuDSSBindings::CUDSS_PHASE_SOLVE
  status = CuDSSBindings.cudssExecute(
    @handle, phase, @config, @data, @matrix_wrapper, x_wrapper, b_wrapper
  )
  CuDSSBindings.check_status!(status, "cuDSS solve")

  # Cleanup temporary wrappers
  CuDSSBindings.cudssMatrixDestroy(b_wrapper)
  CuDSSBindings.cudssMatrixDestroy(x_wrapper)

  x
end