0
# MultilevelSolver Class
1
2
The core solver class that manages AMG hierarchies and provides solve methods with extensive control over the solution process. This class represents a complete multigrid hierarchy with operators, grids, and smoothers at each level.
3
4
## Capabilities
5
6
### Main Solver Class
7
8
The primary class for managing and executing AMG solvers.
9
10
```python { .api }
11
class MultilevelSolver:
12
"""
13
Multilevel AMG solver managing hierarchy of operators and grids.
14
15
Manages the complete AMG hierarchy including:
16
- Level operators (matrices)
17
- Prolongation and restriction operators
18
- Pre and post smoothers
19
- Coarse grid solver
20
21
Provides methods for solving linear systems using multigrid cycles
22
and accessing hierarchy information.
23
24
Attributes:
25
- levels: list of level dictionaries containing operators
26
- A: list of matrices at each level
27
- P: list of prolongation operators
28
- R: list of restriction operators
29
- presmoother: list of pre-smoothing operators
30
- postsmoother: list of post-smoothing operators
31
"""
32
33
def solve(self, b, x0=None, tol=1e-5, maxiter=None,
34
cycle='V', accel=None, callback=None, residuals=None, **kwargs):
35
"""
36
Solve Ax = b using multigrid cycles.
37
38
Main solution method supporting various multigrid cycles,
39
convergence criteria, and Krylov acceleration.
40
41
Parameters:
42
- b: array-like, right-hand side vector
43
- x0: array-like, initial guess (default: zero vector)
44
- tol: float, convergence tolerance (default 1e-5)
45
- maxiter: int, maximum iterations (default: automatic)
46
- cycle: str, multigrid cycle type:
47
* 'V': V-cycle (default, most efficient)
48
* 'W': W-cycle (more robust, higher cost)
49
* 'F': F-cycle (flexible cycle)
50
- accel: str, Krylov acceleration method:
51
* None: no acceleration (default)
52
* 'cg': conjugate gradient acceleration
53
* 'gmres': GMRES acceleration
54
* 'bicgstab': BiCGSTAB acceleration
55
* 'fgmres': flexible GMRES
56
- callback: callable, function called after each iteration
57
- residuals: list, stores residual norms if provided
58
- return_residuals: bool, return residual history
59
60
Returns:
61
array: solution vector x such that ||b - Ax|| < tol * ||b||
62
63
Raises:
64
ValueError: if b has wrong dimensions or parameters are invalid
65
RuntimeError: if solver fails to converge within maxiter
66
"""
67
68
def aspreconditioner(self, cycle='V'):
69
"""
70
Return linear operator for use as preconditioner.
71
72
Creates scipy LinearOperator that applies one multigrid
73
cycle, suitable for use with Krylov methods.
74
75
Parameters:
76
- cycle: str, multigrid cycle type ('V', 'W', 'F')
77
78
Returns:
79
scipy.sparse.linalg.LinearOperator: preconditioner operator
80
with matvec method applying multigrid cycle
81
82
Raises:
83
ValueError: if cycle type is invalid
84
"""
85
86
def __repr__(self):
87
"""
88
String representation showing hierarchy information.
89
90
Returns:
91
str: formatted hierarchy summary including:
92
- Number of levels
93
- Grid complexity (total unknowns / fine grid unknowns)
94
- Operator complexity (total nonzeros / fine grid nonzeros)
95
- Coarse solver information
96
- Per-level statistics (unknowns, nonzeros, percentages)
97
"""
98
99
def __len__(self):
100
"""
101
Number of levels in the hierarchy.
102
103
Returns:
104
int: number of levels (fine grid is level 0)
105
"""
106
```
107
108
**Usage Examples:**
109
110
```python
111
import pyamg
112
import numpy as np
113
from scipy.sparse.linalg import gmres
114
115
# Create solver and examine hierarchy
116
A = pyamg.gallery.poisson((100, 100))
117
ml = pyamg.ruge_stuben_solver(A)
118
print(ml) # Display hierarchy information
119
print(f"Number of levels: {len(ml)}")
120
121
# Basic solve with V-cycle
122
b = np.random.rand(A.shape[0])
123
x = ml.solve(b)
124
125
# Solve with W-cycle and custom tolerance
126
x = ml.solve(b, cycle='W', tol=1e-8)
127
128
# Solve with initial guess
129
x0 = np.ones(A.shape[0])
130
x = ml.solve(b, x0=x0, maxiter=50)
131
132
# Use as preconditioner with Krylov method
133
M = ml.aspreconditioner()
134
x, info = gmres(A, b, M=M, tol=1e-8)
135
136
# Monitor convergence
137
residuals = []
138
x = ml.solve(b, residuals=residuals)
139
print(f"Convergence in {len(residuals)} iterations")
140
141
# Custom callback function
142
def callback(x):
143
r = np.linalg.norm(b - A*x)
144
print(f"Residual: {r:.2e}")
145
146
x = ml.solve(b, callback=callback)
147
```
148
149
### Level Access and Hierarchy Information
150
151
Methods and attributes for inspecting the multigrid hierarchy.
152
153
```python { .api }
154
class MultilevelSolver:
155
156
@property
157
def A(self):
158
"""
159
List of matrices at each level.
160
161
Returns:
162
list: sparse matrices [A0, A1, ..., A_{L-1}]
163
where A0 is the fine grid matrix
164
"""
165
166
@property
167
def P(self):
168
"""
169
List of prolongation operators.
170
171
Returns:
172
list: prolongation matrices [P0, P1, ..., P_{L-2}]
173
where Pi maps from level i+1 to level i
174
"""
175
176
@property
177
def R(self):
178
"""
179
List of restriction operators.
180
181
Returns:
182
list: restriction matrices [R0, R1, ..., R_{L-2}]
183
where Ri maps from level i to level i+1
184
"""
185
186
@property
187
def levels(self):
188
"""
189
Complete level information.
190
191
Returns:
192
list: level dictionaries containing:
193
- 'A': operator matrix
194
- 'P': prolongation operator (if not coarsest)
195
- 'R': restriction operator (if not coarsest)
196
- 'presmoother': pre-smoothing operator
197
- 'postsmoother': post-smoothing operator
198
- Additional level-specific data
199
"""
200
201
def grid_complexity(self):
202
"""
203
Compute grid complexity of hierarchy.
204
205
Grid complexity measures memory overhead as ratio of
206
total unknowns across all levels to fine grid unknowns.
207
208
Returns:
209
float: grid complexity = sum(Ni) / N0
210
where Ni is number of unknowns at level i
211
"""
212
213
def operator_complexity(self):
214
"""
215
Compute operator complexity of hierarchy.
216
217
Operator complexity measures storage overhead as ratio of
218
total nonzeros across all levels to fine grid nonzeros.
219
220
Returns:
221
float: operator complexity = sum(nnz(Ai)) / nnz(A0)
222
"""
223
```
224
225
**Usage Examples:**
226
227
```python
228
# Examine hierarchy structure
229
A = pyamg.gallery.linear_elasticity((50, 50))
230
ml = pyamg.smoothed_aggregation_solver(A)
231
232
print(f"Grid complexity: {ml.grid_complexity():.2f}")
233
print(f"Operator complexity: {ml.operator_complexity():.2f}")
234
235
# Access level operators
236
print(f"Fine grid size: {ml.A[0].shape}")
237
print(f"Coarse grid size: {ml.A[-1].shape}")
238
239
# Examine prolongation operators
240
for i, P in enumerate(ml.P):
241
print(f"P{i} maps {P.shape[1]} -> {P.shape[0]} points")
242
243
# Access complete level information
244
for i, level in enumerate(ml.levels):
245
A_level = level['A']
246
print(f"Level {i}: {A_level.shape[0]} unknowns, "
247
f"{A_level.nnz} nonzeros")
248
```
249
250
### Cycle Control and Advanced Solving
251
252
Methods for controlling multigrid cycle behavior and advanced solution strategies.
253
254
```python { .api }
255
class MultilevelSolver:
256
257
def cycle(self, level, x, b, cycle='V'):
258
"""
259
Apply one multigrid cycle starting at given level.
260
261
Low-level method for applying multigrid cycles with
262
explicit level control. Used internally by solve().
263
264
Parameters:
265
- level: int, starting level (0 = fine grid)
266
- x: array, solution vector (modified in-place)
267
- b: array, right-hand side vector
268
- cycle: str, cycle type ('V', 'W', 'F')
269
270
Returns:
271
None (x is modified in-place)
272
"""
273
274
def _solve_level0(self, x, b, **kwargs):
275
"""
276
Apply smoothing at finest level.
277
278
Internal method applying pre/post smoothing at level 0.
279
280
Parameters:
281
- x: array, solution vector (modified in-place)
282
- b: array, right-hand side
283
- **kwargs: smoothing parameters
284
"""
285
```
286
287
### Solver Diagnostics and Utilities
288
289
Methods for analyzing solver performance and behavior.
290
291
```python { .api }
292
def multilevel_solver(A, **kwargs):
293
"""
294
Alias for MultilevelSolver constructor.
295
296
Provided for backward compatibility and alternative naming.
297
298
Parameters:
299
- A: sparse matrix, coefficient matrix
300
- **kwargs: solver construction parameters
301
302
Returns:
303
MultilevelSolver: AMG solver instance
304
"""
305
```
306
307
## Performance and Usage Guidelines
308
309
### Cycle Selection
310
311
- **V-cycle**: Most efficient, suitable for most problems
312
- **W-cycle**: More robust for difficult problems, higher computational cost
313
- **F-cycle**: Flexible cycle, adaptive coarse grid correction
314
315
### Memory Management
316
317
- Grid complexity > 2.0 may indicate memory issues
318
- Operator complexity > 3.0 suggests aggressive coarsening
319
- Use `max_levels` and `max_coarse` to control hierarchy size
320
321
### Convergence Monitoring
322
323
- Default tolerance is relative: `||r|| < tol * ||b||`
324
- Use callback functions to monitor intermediate progress
325
- Store residual history with `residuals` parameter
326
- Set reasonable `maxiter` to prevent infinite loops
327
328
### Preconditioner Usage
329
330
- Single V-cycle typically effective for preconditioning
331
- W-cycle may be needed for very difficult problems
332
- Use with CG for SPD problems, GMRES for general problems
333
- Combine with Krylov methods for optimal performance
334
335
### Common Issues
336
337
- **Slow convergence**: Try W-cycle or different solver method
338
- **Memory errors**: Reduce max_levels or increase max_coarse
339
- **Poor scaling**: Check operator and grid complexity ratios
340
- **Stagnation**: May need better coarse grid solver or different method