111111
112112function implicit_tau_step (u_prev, t_prev, tau, rate_cache, counts, nu, p, rate, numjumps)
113113 # Define the nonlinear system: F(u_new) = u_new - u_prev - sum(nu_j * (counts_j - tau * (a_j(u_prev) - a_j(u_new)))) = 0
114- function f (u_new, params )
115- rate_new = zeros (eltype (u_new) , numjumps)
114+ function f (u_new)
115+ rate_new = zeros (Float64 , numjumps)
116116 rate (rate_new, u_new, p, t_prev + tau)
117117 residual = u_new - u_prev
118118 for j in 1 : numjumps
@@ -121,19 +121,41 @@ function implicit_tau_step(u_prev, t_prev, tau, rate_cache, counts, nu, p, rate,
121121 return residual
122122 end
123123
124- # Initial guess
125- u_new = copy (u_prev)
126-
127- # Solve the nonlinear system
128- prob = NonlinearProblem (f, u_new, nothing )
129- sol = solve (prob, SimpleNewtonRaphson ())
130-
131- # Check for convergence and numerical stability
132- if sol. retcode != ReturnCode. Success || any (isnan .(sol. u)) || any (isinf .(sol. u))
133- return nothing # Signal failure to trigger tau halving
124+ # Compute Jacobian using finite differences
125+ function compute_jacobian (u_new)
126+ n = length (u_new)
127+ J = zeros (Float64, n, n)
128+ h = 1e-6
129+ f_u = f (u_new)
130+ for j in 1 : n
131+ u_pert = copy (u_new)
132+ u_pert[j] += h
133+ f_pert = f (u_pert)
134+ J[:, j] = (f_pert - f_u) / h
135+ end
136+ return J
134137 end
135138
136- return round .(Int, max .(sol. u, 0.0 ))
139+ # Inline Newton-Raphson
140+ u_new = float .(u_prev + sum (nu[:, j] * counts[j] for j in 1 : numjumps)) # Initial guess: explicit step
141+ tol = 1e-6
142+ maxiters = 100
143+ for iter in 1 : maxiters
144+ F = f (u_new)
145+ if norm (F) < tol
146+ return round .(Int, max .(u_new, 0.0 )) # Converged
147+ end
148+ J = compute_jacobian (u_new)
149+ if abs (det (J)) < 1e-10 # Check for singular Jacobian
150+ return nothing # Signal failure
151+ end
152+ delta = J \ F
153+ u_new -= delta
154+ if any (isnan .(u_new)) || any (isinf .(u_new))
155+ return nothing # Signal failure
156+ end
157+ end
158+ return nothing # Failed to converge
137159end
138160
139161function DiffEqBase. solve (jump_prob:: JumpProblem , alg:: SimpleImplicitTauLeaping ; seed= nothing , dtmin= 1e-10 , saveat= nothing )
@@ -205,7 +227,6 @@ function DiffEqBase.solve(jump_prob::JumpProblem, alg::SimpleImplicitTauLeaping;
205227 continue
206228 end
207229 else
208- # Implicit update using NonlinearSolve
209230 u_new = implicit_tau_step (u_prev, t_prev, tau, rate_cache, counts, nu, p, rate, numjumps)
210231 if u_new === nothing || any (u_new .< 0 )
211232 # Halve tau to avoid negative populations, as per Cao et al. (2006, J. Chem. Phys., DOI: 10.1063/1.2159468)
0 commit comments