5858SimpleImplicitTauLeaping (; epsilon= 0.05 ) = SimpleImplicitTauLeaping (epsilon)
5959
6060function compute_hor (nu)
61- hor = zeros (Int , size (nu, 2 ))
61+ hor = zeros (Int64 , size (nu, 2 ))
6262 for j in 1 : size (nu, 2 )
6363 hor[j] = sum (abs .(nu[:, j])) > maximum (abs .(nu[:, j])) ? 2 : 1
6464 end
7777
7878function compute_tau_explicit (u, rate_cache, nu, hor, p, t, epsilon, rate)
7979 rate (rate_cache, u, p, t)
80- mu = zeros (length (u))
81- sigma2 = zeros (length (u))
80+ mu = zeros (Float64, length (u))
81+ sigma2 = zeros (Float64, length (u))
8282 tau = Inf
8383 for i in 1 : length (u)
8484 for j in 1 : size (nu, 2 )
@@ -100,21 +100,20 @@ function compute_tau_implicit(u, rate_cache, nu, p, t, rate)
100100 for i in 1 : length (u)
101101 sum_nu_a = 0.0
102102 for j in 1 : size (nu, 2 )
103- if nu[i, j] < 0 # Only sum negative stoichiometry
103+ if nu[i, j] < 0
104104 sum_nu_a += abs (nu[i, j]) * rate_cache[j]
105105 end
106106 end
107- if sum_nu_a > 0 && u[i] > 0 # Avoid division by zero
107+ if sum_nu_a > 0 && u[i] > 0
108108 tau = min (tau, u[i] / sum_nu_a)
109109 end
110110 end
111111 return tau
112112end
113113
114114function implicit_tau_step (u_prev, t_prev, tau, rate_cache, counts, nu, p, rate, numjumps)
115- # Nonlinear system: F(u_new) = u_new - u_prev - sum(nu_j * (k_j - tau * (a_j(u_prev) - a_j(u_new)))) = 0
116- function f (u_new)
117- rate_new = zeros (Float64, numjumps)
115+ function f (u_new, p)
116+ rate_new = zeros (eltype (u_new), numjumps)
118117 rate (rate_new, u_new, p, t_prev + tau)
119118 residual = u_new - u_prev
120119 for j in 1 : numjumps
@@ -123,41 +122,14 @@ function implicit_tau_step(u_prev, t_prev, tau, rate_cache, counts, nu, p, rate,
123122 return residual
124123 end
125124
126- # Numerical Jacobian
127- function compute_jacobian (u_new)
128- n = length (u_new)
129- J = zeros (Float64, n, n)
130- h = 1e-6
131- f_u = f (u_new)
132- for j in 1 : n
133- u_pert = copy (u_new)
134- u_pert[j] += h
135- f_pert = f (u_pert)
136- J[:, j] = (f_pert - f_u) / h
137- end
138- return J
139- end
125+ u_new = float .(u_prev + sum (nu[:, j] * counts[j] for j in 1 : numjumps))
126+ prob = NonlinearProblem {false} (f, u_new, p)
127+ sol = solve (prob, SimpleNewtonRaphson (), abstol= 1e-6 , maxiters= 100 )
140128
141- # Inline Newton-Raphson
142- u_new = float .(u_prev + sum (nu[:, j] * counts[j] for j in 1 : numjumps)) # Initial guess: explicit step
143- tol = 1e-6
144- maxiters = 100
145- for iter in 1 : maxiters
146- F = f (u_new)
147- if norm (F) < tol
148- return round .(Int, max .(u_new, 0.0 )) # Converged
149- end
150- J = compute_jacobian (u_new)
151- if abs (det (J)) < 1e-10 # Check for singular Jacobian
152- return nothing
153- end
154- delta = J \ F
155- u_new -= delta
156- if any (isnan .(u_new)) || any (isinf .(u_new))
157- return nothing
158- end
129+ if sol. retcode != ReturnCode. Success || any (isnan .(sol. u)) || any (isinf .(sol. u))
130+ return nothing
159131 end
160- return nothing # Failed to converge
132+ return round .(Int64, max .(sol . u, 0.0 ))
161133end
162134
163135function DiffEqBase. solve (jump_prob:: JumpProblem , alg:: SimpleImplicitTauLeaping ; seed= nothing , dtmin= 1e-10 , saveat= nothing )
@@ -200,7 +172,6 @@ function DiffEqBase.solve(jump_prob::JumpProblem, alg::SimpleImplicitTauLeaping;
200172 while t[end ] < t_end
201173 u_prev = u[end ]
202174 t_prev = t[end ]
203- # Recompute stoichiometry
204175 for j in 1 : numjumps
205176 fill! (counts_temp, 0 )
206177 counts_temp[j] = 1
@@ -210,11 +181,10 @@ function DiffEqBase.solve(jump_prob::JumpProblem, alg::SimpleImplicitTauLeaping;
210181 rate (rate_cache, u_prev, p, t_prev)
211182 tau_prime = compute_tau_explicit (u_prev, rate_cache, nu, hor, p, t_prev, epsilon, rate)
212183 tau_double_prime = compute_tau_implicit (u_prev, rate_cache, nu, p, t_prev, rate)
213- # Cao et al. (2007): Use tau_prime for explicit, tau_double_prime for implicit
214184 use_implicit = false
215- tau = tau_prime # Default to explicit
216- if tau_double_prime < tau_prime && any (u_prev .< 10 ) # Implicit if populations are low
217- tau = tau_double_prime
185+ tau = tau_prime
186+ if any (u_prev .< 10 )
187+ tau = min ( tau_double_prime, tau_prime) # Tighter cap for accuracy
218188 use_implicit = true
219189 end
220190 tau = max (tau, dtmin)
@@ -230,11 +200,11 @@ function DiffEqBase.solve(jump_prob::JumpProblem, alg::SimpleImplicitTauLeaping;
230200 if use_implicit
231201 u_new = implicit_tau_step (u_prev, t_prev, tau, rate_cache, counts, nu, p, rate, numjumps)
232202 if u_new === nothing || any (u_new .< 0 )
233- tau /= 2 # Halve tau if implicit fails or produces negative populations
203+ tau /= 2
234204 continue
235205 end
236206 elseif any (u_new .< 0 )
237- tau /= 2 # Halve tau if explicit produces negative populations
207+ tau /= 2
238208 continue
239209 end
240210 u_new = max .(u_new, 0 )
0 commit comments