8686//! ```
8787
8888use anyhow:: { bail, Result } ;
89+ use crate :: fuga:: ConvToMat ;
90+ use crate :: util:: non_macro:: eye;
91+ use crate :: traits:: math:: { Norm , Normed , InnerProduct , Vector } ;
8992
9093/// Trait for defining an ODE problem.
9194///
@@ -890,12 +893,12 @@ impl ButcherTableau for TSIT45 {
890893/// Enum for implicit solvers.
891894///
892895/// This enum defines the available implicit solvers for the Gauss-Legendre 4th order integrator.
893- /// Currently, only the fixed-point iteration method is implemented .
896+ /// Currently, there are two options: fixed-point iteration and Broyden's method .
894897#[ derive( Debug , Clone , Copy ) ]
895898#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
896899pub enum ImplicitSolver {
897900 FixedPoint ,
898- // Broyden,
901+ Broyden ,
899902 //TrustRegion(f64, f64),
900903}
901904
@@ -939,6 +942,7 @@ impl GL4 {
939942}
940943
941944impl ODEIntegrator for GL4 {
945+ #[ allow( non_snake_case) ]
942946 #[ inline]
943947 fn step < P : ODEProblem > ( & self , problem : & P , t : f64 , y : & mut [ f64 ] , dt : f64 ) -> Result < f64 > {
944948 let n = y. len ( ) ;
@@ -983,7 +987,76 @@ impl ODEIntegrator for GL4 {
983987 break ;
984988 }
985989 }
986- }
990+ } ,
991+ ImplicitSolver :: Broyden => {
992+ let m = 2 * n;
993+ let mut U = vec ! [ 0.0 ; m] ;
994+
995+ // Initial Guess via Fixed-Point Iteration
996+ {
997+ let mut k1 = vec ! [ 0.0 ; n] ;
998+ let mut k2 = vec ! [ 0.0 ; n] ;
999+ let mut y1 = vec ! [ 0.0 ; n] ;
1000+ let mut y2 = vec ! [ 0.0 ; n] ;
1001+
1002+ y1. copy_from_slice ( y) ;
1003+ y2. copy_from_slice ( y) ;
1004+ problem. rhs ( t + c * dt, & y1, & mut k1) ?;
1005+ problem. rhs ( t + d * dt, & y2, & mut k2) ?;
1006+ for i in 0 .. n {
1007+ U [ i] = k1[ i] ;
1008+ U [ n + i] = k2[ i] ;
1009+ }
1010+ }
1011+
1012+ // F_vec = F(U)
1013+ let mut F_vec = vec ! [ 0.0 ; m] ;
1014+ compute_F ( problem, t, y, dt, c, d, sqrt3, & U , & mut F_vec ) ?;
1015+
1016+ // Initialize inverse Jacobian matrix
1017+ let mut J_inv = eye ( m) ;
1018+
1019+ // Repeat Broyden's method
1020+ for _ in 0 .. self . max_step_iter {
1021+ // delta = - J_inv * F_vec
1022+ let mut delta = ( & J_inv * & F_vec ) . mul_scalar ( -1.0 ) ;
1023+
1024+ // U <- U + delta
1025+ U . iter_mut ( ) . zip ( delta. iter_mut ( ) ) . for_each ( |( u, d) | * u += * d) ;
1026+
1027+ let mut F_new = vec ! [ 0.0 ; m] ;
1028+ compute_F ( problem, t, y, dt, c, d, sqrt3, & U , & mut F_new ) ?;
1029+
1030+ // If infinity norm of F_new is less than tol, break
1031+ if F_new . norm ( Norm :: LInf ) < self . tol {
1032+ break ;
1033+ }
1034+
1035+ // Residual: delta_F = F_new - F_vec
1036+ let delta_F = F_new . sub_vec ( & F_vec ) ;
1037+
1038+ // J_inv * delta_F
1039+ let J_inv_delta_F = & J_inv * & delta_F;
1040+ let denom = delta. dot ( & J_inv_delta_F ) ;
1041+ if denom. abs ( ) < 1e-12 {
1042+ break ;
1043+ }
1044+
1045+ // Broyden "good" update
1046+ // J_inv <- J_inv + ((delta - J_inv * delta_F) * delta^T * J_inv) / denom
1047+ let delta_minus_J_inv_delta_F = delta. sub_vec ( & J_inv_delta_F ) . to_col ( ) ;
1048+ let delta_T_J_inv = & delta. to_row ( ) * & J_inv ;
1049+ let update = ( delta_minus_J_inv_delta_F * delta_T_J_inv) / denom;
1050+ J_inv = J_inv + update;
1051+ F_vec = F_new ;
1052+ }
1053+
1054+ // Extract k1 and k2
1055+ for i in 0 .. n {
1056+ k1[ i] = U [ i] ;
1057+ k2[ i] = U [ n + i] ;
1058+ }
1059+ } ,
9871060 }
9881061
9891062 for i in 0 ..n {
@@ -993,3 +1066,42 @@ impl ODEIntegrator for GL4 {
9931066 Ok ( dt)
9941067 }
9951068}
1069+
1070+ // Helper function to compute the function F(U) for the implicit solver.
1071+ // y1 = y + dt*(c*k1 + d*k2 - sqrt3/2*(k2-k1))
1072+ // y2 = y + dt*(c*k1 + d*k2 + sqrt3/2*(k2-k1))
1073+ #[ allow( non_snake_case) ]
1074+ fn compute_F < P : ODEProblem > (
1075+ problem : & P ,
1076+ t : f64 ,
1077+ y : & [ f64 ] ,
1078+ dt : f64 ,
1079+ c : f64 ,
1080+ d : f64 ,
1081+ sqrt3 : f64 ,
1082+ U : & [ f64 ] ,
1083+ F : & mut [ f64 ] ,
1084+ ) -> Result < ( ) > {
1085+ let n = y. len ( ) ;
1086+ let mut y1 = vec ! [ 0.0 ; n] ;
1087+ let mut y2 = vec ! [ 0.0 ; n] ;
1088+
1089+ for i in 0 ..n {
1090+ let k1 = U [ i] ;
1091+ let k2 = U [ n + i] ;
1092+ y1[ i] = y[ i] + dt * ( c * k1 + d * k2 - sqrt3 * ( k2 - k1) / 2.0 ) ;
1093+ y2[ i] = y[ i] + dt * ( c * k1 + d * k2 + sqrt3 * ( k2 - k1) / 2.0 ) ;
1094+ }
1095+
1096+ let mut f1 = vec ! [ 0.0 ; n] ;
1097+ let mut f2 = vec ! [ 0.0 ; n] ;
1098+ problem. rhs ( t + c * dt, & y1, & mut f1) ?;
1099+ problem. rhs ( t + d * dt, & y2, & mut f2) ?;
1100+
1101+ // F = [ k1 - f1, k2 - f2 ]
1102+ for i in 0 ..n {
1103+ F [ i] = U [ i] - f1[ i] ;
1104+ F [ n + i] = U [ n + i] - f2[ i] ;
1105+ }
1106+ Ok ( ( ) )
1107+ }
0 commit comments