Skip to content

Commit e4555a6

Browse files
committed
feat: add customization methods for AMG solver and enhance hierarchy management
1 parent 039a774 commit e4555a6

2 files changed

Lines changed: 99 additions & 1 deletion

File tree

src/iteratives/amg/mod.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,59 @@ where
111111
self.nu_pre = nu_pre;
112112
self.nu_post = nu_post;
113113
}
114+
115+
/// Gets the current tolerance
116+
pub fn tolerance(&self) -> T {
117+
self.tol
118+
}
119+
120+
/// Sets a new tolerance
121+
pub fn set_tolerance(&mut self, tol: T) {
122+
self.tol = tol;
123+
}
124+
125+
/// Gets the theta parameter for strength-of-connection
126+
pub fn theta(&self) -> T {
127+
self.theta
128+
}
129+
130+
/// Sets a new theta parameter (requires rebuilding hierarchy)
131+
pub fn set_theta(&mut self, theta: T) {
132+
self.theta = theta;
133+
// Clear hierarchy to force rebuild with new theta
134+
self.hierarchy = None;
135+
}
136+
137+
/// Gets the minimum coarse level size
138+
pub fn coarse_size(&self) -> usize {
139+
self.n_min
140+
}
141+
142+
/// Gets the pre-smoothing iterations
143+
pub fn pre_smoothing(&self) -> usize {
144+
self.nu_pre
145+
}
146+
147+
/// Gets the post-smoothing iterations
148+
pub fn post_smoothing(&self) -> usize {
149+
self.nu_post
150+
}
151+
152+
/// Checks if the solver has converged
153+
pub fn has_converged(&self) -> bool {
154+
self.converged
155+
}
156+
157+
/// Gets the number of levels in the AMG hierarchy
158+
pub fn num_levels(&self) -> usize {
159+
self.hierarchy.as_ref().map_or(0, |h| h.levels.len())
160+
}
161+
162+
/// Get residual norm (absolute maximum)
163+
pub fn residual_norm(&self, a: &CsrMatrix<T>, b: &DVector<T>) -> T {
164+
let residual = a * &self.x - b;
165+
residual.amax()
166+
}
114167
}
115168

116169
impl<T> IterativeSolver<CsrMatrix<T>, DVector<T>, T> for Amg<T>
@@ -161,7 +214,7 @@ where
161214
// Check convergence after the V-cycle
162215
let new_residual = a * &self.x - b;
163216
let new_residual_norm = new_residual.amax();
164-
217+
println!("Iteration {}: Residual norm = {}", self.iter, new_residual_norm);
165218
if new_residual_norm <= self.tol {
166219
self.converged = true;
167220
true
@@ -357,4 +410,46 @@ mod tests {
357410
let converged = solve_amg_with_initial_guess(&a, &b, &mut x, 100, 1e-6, 0.25);
358411
assert!(converged, "Convenience function with initial guess should converge");
359412
}
413+
414+
#[test]
415+
fn amg_customization_methods() {
416+
let mut solver = Amg::new(1e-6, 0.25, 100);
417+
418+
// Test getters
419+
assert_eq!(solver.tolerance(), 1e-6);
420+
assert_eq!(solver.theta(), 0.25);
421+
assert_eq!(solver.coarse_size(), 100);
422+
assert_eq!(solver.pre_smoothing(), 1);
423+
assert_eq!(solver.post_smoothing(), 1);
424+
assert!(!solver.has_converged());
425+
assert_eq!(solver.num_levels(), 0);
426+
427+
// Test setters
428+
solver.set_tolerance(1e-8);
429+
assert_eq!(solver.tolerance(), 1e-8);
430+
431+
solver.set_theta(0.5);
432+
assert_eq!(solver.theta(), 0.5);
433+
434+
solver.set_smoothing(3, 2);
435+
assert_eq!(solver.pre_smoothing(), 3);
436+
assert_eq!(solver.post_smoothing(), 2);
437+
}
438+
439+
#[test]
440+
fn amg_hierarchy_info() {
441+
let a = poisson_1d(20);
442+
let b = DVector::from_vec(vec![1.0; 20]);
443+
444+
let mut solver = Amg::new(1e-6, 0.25, 100);
445+
solver.init(&a, &b, None);
446+
447+
// After initialization, hierarchy should be built
448+
assert!(solver.num_levels() > 0, "Hierarchy should have levels after init");
449+
450+
// Test theta change clears hierarchy
451+
solver.set_theta(0.1);
452+
solver.init(&a, &b, None);
453+
assert!(solver.num_levels() > 0, "Hierarchy should be rebuilt after theta change");
454+
}
360455
}

src/iteratives/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ pub mod amg;
99

1010
pub use biconjugate_gradient::solve as solve_biconjugate_gradient;
1111

12+
#[cfg(feature = "amg")]
13+
pub use amg::{Amg, solve_amg, solve_amg_with_initial_guess};
14+
1215
pub use nalgebra_sparse::{CscMatrix, CsrMatrix};
1316
pub(crate) use nalgebra_sparse::na::{DVector, SimdRealField};
1417
pub(crate) use rayon::prelude::*;

0 commit comments

Comments
 (0)