@@ -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
116169impl < 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}
0 commit comments