Coverage for /usr/lib/python3/dist-packages/scipy/integrate/_ivp/rk.py: 32%

191 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1import numpy as np 

2from .base import OdeSolver, DenseOutput 

3from .common import (validate_max_step, validate_tol, select_initial_step, 

4 norm, warn_extraneous, validate_first_step) 

5from . import dop853_coefficients 

6 

7# Multiply steps computed from asymptotic behaviour of errors by this. 

8SAFETY = 0.9 

9 

10MIN_FACTOR = 0.2 # Minimum allowed decrease in a step size. 

11MAX_FACTOR = 10 # Maximum allowed increase in a step size. 

12 

13 

14def rk_step(fun, t, y, f, h, A, B, C, K): 

15 """Perform a single Runge-Kutta step. 

16 

17 This function computes a prediction of an explicit Runge-Kutta method and 

18 also estimates the error of a less accurate method. 

19 

20 Notation for Butcher tableau is as in [1]_. 

21 

22 Parameters 

23 ---------- 

24 fun : callable 

25 Right-hand side of the system. 

26 t : float 

27 Current time. 

28 y : ndarray, shape (n,) 

29 Current state. 

30 f : ndarray, shape (n,) 

31 Current value of the derivative, i.e., ``fun(x, y)``. 

32 h : float 

33 Step to use. 

34 A : ndarray, shape (n_stages, n_stages) 

35 Coefficients for combining previous RK stages to compute the next 

36 stage. For explicit methods the coefficients at and above the main 

37 diagonal are zeros. 

38 B : ndarray, shape (n_stages,) 

39 Coefficients for combining RK stages for computing the final 

40 prediction. 

41 C : ndarray, shape (n_stages,) 

42 Coefficients for incrementing time for consecutive RK stages. 

43 The value for the first stage is always zero. 

44 K : ndarray, shape (n_stages + 1, n) 

45 Storage array for putting RK stages here. Stages are stored in rows. 

46 The last row is a linear combination of the previous rows with 

47 coefficients 

48 

49 Returns 

50 ------- 

51 y_new : ndarray, shape (n,) 

52 Solution at t + h computed with a higher accuracy. 

53 f_new : ndarray, shape (n,) 

54 Derivative ``fun(t + h, y_new)``. 

55 

56 References 

57 ---------- 

58 .. [1] E. Hairer, S. P. Norsett G. Wanner, "Solving Ordinary Differential 

59 Equations I: Nonstiff Problems", Sec. II.4. 

60 """ 

61 K[0] = f 

62 for s, (a, c) in enumerate(zip(A[1:], C[1:]), start=1): 

63 dy = np.dot(K[:s].T, a[:s]) * h 

64 K[s] = fun(t + c * h, y + dy) 

65 

66 y_new = y + h * np.dot(K[:-1].T, B) 

67 f_new = fun(t + h, y_new) 

68 

69 K[-1] = f_new 

70 

71 return y_new, f_new 

72 

73 

74class RungeKutta(OdeSolver): 

75 """Base class for explicit Runge-Kutta methods.""" 

76 C: np.ndarray = NotImplemented 

77 A: np.ndarray = NotImplemented 

78 B: np.ndarray = NotImplemented 

79 E: np.ndarray = NotImplemented 

80 P: np.ndarray = NotImplemented 

81 order: int = NotImplemented 

82 error_estimator_order: int = NotImplemented 

83 n_stages: int = NotImplemented 

84 

85 def __init__(self, fun, t0, y0, t_bound, max_step=np.inf, 

86 rtol=1e-3, atol=1e-6, vectorized=False, 

87 first_step=None, **extraneous): 

88 warn_extraneous(extraneous) 

89 super().__init__(fun, t0, y0, t_bound, vectorized, 

90 support_complex=True) 

91 self.y_old = None 

92 self.max_step = validate_max_step(max_step) 

93 self.rtol, self.atol = validate_tol(rtol, atol, self.n) 

94 self.f = self.fun(self.t, self.y) 

95 if first_step is None: 

96 self.h_abs = select_initial_step( 

97 self.fun, self.t, self.y, self.f, self.direction, 

98 self.error_estimator_order, self.rtol, self.atol) 

99 else: 

100 self.h_abs = validate_first_step(first_step, t0, t_bound) 

101 self.K = np.empty((self.n_stages + 1, self.n), dtype=self.y.dtype) 

102 self.error_exponent = -1 / (self.error_estimator_order + 1) 

103 self.h_previous = None 

104 

105 def _estimate_error(self, K, h): 

106 return np.dot(K.T, self.E) * h 

107 

108 def _estimate_error_norm(self, K, h, scale): 

109 return norm(self._estimate_error(K, h) / scale) 

110 

111 def _step_impl(self): 

112 t = self.t 

113 y = self.y 

114 

115 max_step = self.max_step 

116 rtol = self.rtol 

117 atol = self.atol 

118 

119 min_step = 10 * np.abs(np.nextafter(t, self.direction * np.inf) - t) 

120 

121 if self.h_abs > max_step: 

122 h_abs = max_step 

123 elif self.h_abs < min_step: 

124 h_abs = min_step 

125 else: 

126 h_abs = self.h_abs 

127 

128 step_accepted = False 

129 step_rejected = False 

130 

131 while not step_accepted: 

132 if h_abs < min_step: 

133 return False, self.TOO_SMALL_STEP 

134 

135 h = h_abs * self.direction 

136 t_new = t + h 

137 

138 if self.direction * (t_new - self.t_bound) > 0: 

139 t_new = self.t_bound 

140 

141 h = t_new - t 

142 h_abs = np.abs(h) 

143 

144 y_new, f_new = rk_step(self.fun, t, y, self.f, h, self.A, 

145 self.B, self.C, self.K) 

146 scale = atol + np.maximum(np.abs(y), np.abs(y_new)) * rtol 

147 error_norm = self._estimate_error_norm(self.K, h, scale) 

148 

149 if error_norm < 1: 

150 if error_norm == 0: 

151 factor = MAX_FACTOR 

152 else: 

153 factor = min(MAX_FACTOR, 

154 SAFETY * error_norm ** self.error_exponent) 

155 

156 if step_rejected: 

157 factor = min(1, factor) 

158 

159 h_abs *= factor 

160 

161 step_accepted = True 

162 else: 

163 h_abs *= max(MIN_FACTOR, 

164 SAFETY * error_norm ** self.error_exponent) 

165 step_rejected = True 

166 

167 self.h_previous = h 

168 self.y_old = y 

169 

170 self.t = t_new 

171 self.y = y_new 

172 

173 self.h_abs = h_abs 

174 self.f = f_new 

175 

176 return True, None 

177 

178 def _dense_output_impl(self): 

179 Q = self.K.T.dot(self.P) 

180 return RkDenseOutput(self.t_old, self.t, self.y_old, Q) 

181 

182 

183class RK23(RungeKutta): 

184 """Explicit Runge-Kutta method of order 3(2). 

185 

186 This uses the Bogacki-Shampine pair of formulas [1]_. The error is controlled 

187 assuming accuracy of the second-order method, but steps are taken using the 

188 third-order accurate formula (local extrapolation is done). A cubic Hermite 

189 polynomial is used for the dense output. 

190 

191 Can be applied in the complex domain. 

192 

193 Parameters 

194 ---------- 

195 fun : callable 

196 Right-hand side of the system: the time derivative of the state ``y`` 

197 at time ``t``. The calling signature is ``fun(t, y)``, where ``t`` is a 

198 scalar and ``y`` is an ndarray with ``len(y) = len(y0)``. ``fun`` must 

199 return an array of the same shape as ``y``. See `vectorized` for more 

200 information. 

201 t0 : float 

202 Initial time. 

203 y0 : array_like, shape (n,) 

204 Initial state. 

205 t_bound : float 

206 Boundary time - the integration won't continue beyond it. It also 

207 determines the direction of the integration. 

208 first_step : float or None, optional 

209 Initial step size. Default is ``None`` which means that the algorithm 

210 should choose. 

211 max_step : float, optional 

212 Maximum allowed step size. Default is np.inf, i.e., the step size is not 

213 bounded and determined solely by the solver. 

214 rtol, atol : float and array_like, optional 

215 Relative and absolute tolerances. The solver keeps the local error 

216 estimates less than ``atol + rtol * abs(y)``. Here `rtol` controls a 

217 relative accuracy (number of correct digits), while `atol` controls 

218 absolute accuracy (number of correct decimal places). To achieve the 

219 desired `rtol`, set `atol` to be smaller than the smallest value that 

220 can be expected from ``rtol * abs(y)`` so that `rtol` dominates the 

221 allowable error. If `atol` is larger than ``rtol * abs(y)`` the 

222 number of correct digits is not guaranteed. Conversely, to achieve the 

223 desired `atol` set `rtol` such that ``rtol * abs(y)`` is always smaller 

224 than `atol`. If components of y have different scales, it might be 

225 beneficial to set different `atol` values for different components by 

226 passing array_like with shape (n,) for `atol`. Default values are 

227 1e-3 for `rtol` and 1e-6 for `atol`. 

228 vectorized : bool, optional 

229 Whether `fun` may be called in a vectorized fashion. False (default) 

230 is recommended for this solver. 

231 

232 If ``vectorized`` is False, `fun` will always be called with ``y`` of 

233 shape ``(n,)``, where ``n = len(y0)``. 

234 

235 If ``vectorized`` is True, `fun` may be called with ``y`` of shape 

236 ``(n, k)``, where ``k`` is an integer. In this case, `fun` must behave 

237 such that ``fun(t, y)[:, i] == fun(t, y[:, i])`` (i.e. each column of 

238 the returned array is the time derivative of the state corresponding 

239 with a column of ``y``). 

240 

241 Setting ``vectorized=True`` allows for faster finite difference 

242 approximation of the Jacobian by methods 'Radau' and 'BDF', but 

243 will result in slower execution for this solver. 

244 

245 Attributes 

246 ---------- 

247 n : int 

248 Number of equations. 

249 status : string 

250 Current status of the solver: 'running', 'finished' or 'failed'. 

251 t_bound : float 

252 Boundary time. 

253 direction : float 

254 Integration direction: +1 or -1. 

255 t : float 

256 Current time. 

257 y : ndarray 

258 Current state. 

259 t_old : float 

260 Previous time. None if no steps were made yet. 

261 step_size : float 

262 Size of the last successful step. None if no steps were made yet. 

263 nfev : int 

264 Number evaluations of the system's right-hand side. 

265 njev : int 

266 Number of evaluations of the Jacobian. Is always 0 for this solver as it does not use the Jacobian. 

267 nlu : int 

268 Number of LU decompositions. Is always 0 for this solver. 

269 

270 References 

271 ---------- 

272 .. [1] P. Bogacki, L.F. Shampine, "A 3(2) Pair of Runge-Kutta Formulas", 

273 Appl. Math. Lett. Vol. 2, No. 4. pp. 321-325, 1989. 

274 """ 

275 order = 3 

276 error_estimator_order = 2 

277 n_stages = 3 

278 C = np.array([0, 1/2, 3/4]) 

279 A = np.array([ 

280 [0, 0, 0], 

281 [1/2, 0, 0], 

282 [0, 3/4, 0] 

283 ]) 

284 B = np.array([2/9, 1/3, 4/9]) 

285 E = np.array([5/72, -1/12, -1/9, 1/8]) 

286 P = np.array([[1, -4 / 3, 5 / 9], 

287 [0, 1, -2/3], 

288 [0, 4/3, -8/9], 

289 [0, -1, 1]]) 

290 

291 

292class RK45(RungeKutta): 

293 """Explicit Runge-Kutta method of order 5(4). 

294 

295 This uses the Dormand-Prince pair of formulas [1]_. The error is controlled 

296 assuming accuracy of the fourth-order method accuracy, but steps are taken 

297 using the fifth-order accurate formula (local extrapolation is done). 

298 A quartic interpolation polynomial is used for the dense output [2]_. 

299 

300 Can be applied in the complex domain. 

301 

302 Parameters 

303 ---------- 

304 fun : callable 

305 Right-hand side of the system. The calling signature is ``fun(t, y)``. 

306 Here ``t`` is a scalar, and there are two options for the ndarray ``y``: 

307 It can either have shape (n,); then ``fun`` must return array_like with 

308 shape (n,). Alternatively it can have shape (n, k); then ``fun`` 

309 must return an array_like with shape (n, k), i.e., each column 

310 corresponds to a single column in ``y``. The choice between the two 

311 options is determined by `vectorized` argument (see below). 

312 t0 : float 

313 Initial time. 

314 y0 : array_like, shape (n,) 

315 Initial state. 

316 t_bound : float 

317 Boundary time - the integration won't continue beyond it. It also 

318 determines the direction of the integration. 

319 first_step : float or None, optional 

320 Initial step size. Default is ``None`` which means that the algorithm 

321 should choose. 

322 max_step : float, optional 

323 Maximum allowed step size. Default is np.inf, i.e., the step size is not 

324 bounded and determined solely by the solver. 

325 rtol, atol : float and array_like, optional 

326 Relative and absolute tolerances. The solver keeps the local error 

327 estimates less than ``atol + rtol * abs(y)``. Here `rtol` controls a 

328 relative accuracy (number of correct digits), while `atol` controls 

329 absolute accuracy (number of correct decimal places). To achieve the 

330 desired `rtol`, set `atol` to be smaller than the smallest value that 

331 can be expected from ``rtol * abs(y)`` so that `rtol` dominates the 

332 allowable error. If `atol` is larger than ``rtol * abs(y)`` the 

333 number of correct digits is not guaranteed. Conversely, to achieve the 

334 desired `atol` set `rtol` such that ``rtol * abs(y)`` is always smaller 

335 than `atol`. If components of y have different scales, it might be 

336 beneficial to set different `atol` values for different components by 

337 passing array_like with shape (n,) for `atol`. Default values are 

338 1e-3 for `rtol` and 1e-6 for `atol`. 

339 vectorized : bool, optional 

340 Whether `fun` is implemented in a vectorized fashion. Default is False. 

341 

342 Attributes 

343 ---------- 

344 n : int 

345 Number of equations. 

346 status : string 

347 Current status of the solver: 'running', 'finished' or 'failed'. 

348 t_bound : float 

349 Boundary time. 

350 direction : float 

351 Integration direction: +1 or -1. 

352 t : float 

353 Current time. 

354 y : ndarray 

355 Current state. 

356 t_old : float 

357 Previous time. None if no steps were made yet. 

358 step_size : float 

359 Size of the last successful step. None if no steps were made yet. 

360 nfev : int 

361 Number evaluations of the system's right-hand side. 

362 njev : int 

363 Number of evaluations of the Jacobian. Is always 0 for this solver as it does not use the Jacobian. 

364 nlu : int 

365 Number of LU decompositions. Is always 0 for this solver. 

366 

367 References 

368 ---------- 

369 .. [1] J. R. Dormand, P. J. Prince, "A family of embedded Runge-Kutta 

370 formulae", Journal of Computational and Applied Mathematics, Vol. 6, 

371 No. 1, pp. 19-26, 1980. 

372 .. [2] L. W. Shampine, "Some Practical Runge-Kutta Formulas", Mathematics 

373 of Computation,, Vol. 46, No. 173, pp. 135-150, 1986. 

374 """ 

375 order = 5 

376 error_estimator_order = 4 

377 n_stages = 6 

378 C = np.array([0, 1/5, 3/10, 4/5, 8/9, 1]) 

379 A = np.array([ 

380 [0, 0, 0, 0, 0], 

381 [1/5, 0, 0, 0, 0], 

382 [3/40, 9/40, 0, 0, 0], 

383 [44/45, -56/15, 32/9, 0, 0], 

384 [19372/6561, -25360/2187, 64448/6561, -212/729, 0], 

385 [9017/3168, -355/33, 46732/5247, 49/176, -5103/18656] 

386 ]) 

387 B = np.array([35/384, 0, 500/1113, 125/192, -2187/6784, 11/84]) 

388 E = np.array([-71/57600, 0, 71/16695, -71/1920, 17253/339200, -22/525, 

389 1/40]) 

390 # Corresponds to the optimum value of c_6 from [2]_. 

391 P = np.array([ 

392 [1, -8048581381/2820520608, 8663915743/2820520608, 

393 -12715105075/11282082432], 

394 [0, 0, 0, 0], 

395 [0, 131558114200/32700410799, -68118460800/10900136933, 

396 87487479700/32700410799], 

397 [0, -1754552775/470086768, 14199869525/1410260304, 

398 -10690763975/1880347072], 

399 [0, 127303824393/49829197408, -318862633887/49829197408, 

400 701980252875 / 199316789632], 

401 [0, -282668133/205662961, 2019193451/616988883, -1453857185/822651844], 

402 [0, 40617522/29380423, -110615467/29380423, 69997945/29380423]]) 

403 

404 

405class DOP853(RungeKutta): 

406 """Explicit Runge-Kutta method of order 8. 

407 

408 This is a Python implementation of "DOP853" algorithm originally written 

409 in Fortran [1]_, [2]_. Note that this is not a literate translation, but 

410 the algorithmic core and coefficients are the same. 

411 

412 Can be applied in the complex domain. 

413 

414 Parameters 

415 ---------- 

416 fun : callable 

417 Right-hand side of the system. The calling signature is ``fun(t, y)``. 

418 Here, ``t`` is a scalar, and there are two options for the ndarray ``y``: 

419 It can either have shape (n,); then ``fun`` must return array_like with 

420 shape (n,). Alternatively it can have shape (n, k); then ``fun`` 

421 must return an array_like with shape (n, k), i.e. each column 

422 corresponds to a single column in ``y``. The choice between the two 

423 options is determined by `vectorized` argument (see below). 

424 t0 : float 

425 Initial time. 

426 y0 : array_like, shape (n,) 

427 Initial state. 

428 t_bound : float 

429 Boundary time - the integration won't continue beyond it. It also 

430 determines the direction of the integration. 

431 first_step : float or None, optional 

432 Initial step size. Default is ``None`` which means that the algorithm 

433 should choose. 

434 max_step : float, optional 

435 Maximum allowed step size. Default is np.inf, i.e. the step size is not 

436 bounded and determined solely by the solver. 

437 rtol, atol : float and array_like, optional 

438 Relative and absolute tolerances. The solver keeps the local error 

439 estimates less than ``atol + rtol * abs(y)``. Here `rtol` controls a 

440 relative accuracy (number of correct digits), while `atol` controls 

441 absolute accuracy (number of correct decimal places). To achieve the 

442 desired `rtol`, set `atol` to be smaller than the smallest value that 

443 can be expected from ``rtol * abs(y)`` so that `rtol` dominates the 

444 allowable error. If `atol` is larger than ``rtol * abs(y)`` the 

445 number of correct digits is not guaranteed. Conversely, to achieve the 

446 desired `atol` set `rtol` such that ``rtol * abs(y)`` is always smaller 

447 than `atol`. If components of y have different scales, it might be 

448 beneficial to set different `atol` values for different components by 

449 passing array_like with shape (n,) for `atol`. Default values are 

450 1e-3 for `rtol` and 1e-6 for `atol`. 

451 vectorized : bool, optional 

452 Whether `fun` is implemented in a vectorized fashion. Default is False. 

453 

454 Attributes 

455 ---------- 

456 n : int 

457 Number of equations. 

458 status : string 

459 Current status of the solver: 'running', 'finished' or 'failed'. 

460 t_bound : float 

461 Boundary time. 

462 direction : float 

463 Integration direction: +1 or -1. 

464 t : float 

465 Current time. 

466 y : ndarray 

467 Current state. 

468 t_old : float 

469 Previous time. None if no steps were made yet. 

470 step_size : float 

471 Size of the last successful step. None if no steps were made yet. 

472 nfev : int 

473 Number evaluations of the system's right-hand side. 

474 njev : int 

475 Number of evaluations of the Jacobian. Is always 0 for this solver 

476 as it does not use the Jacobian. 

477 nlu : int 

478 Number of LU decompositions. Is always 0 for this solver. 

479 

480 References 

481 ---------- 

482 .. [1] E. Hairer, S. P. Norsett G. Wanner, "Solving Ordinary Differential 

483 Equations I: Nonstiff Problems", Sec. II. 

484 .. [2] `Page with original Fortran code of DOP853 

485 <http://www.unige.ch/~hairer/software.html>`_. 

486 """ 

487 n_stages = dop853_coefficients.N_STAGES 

488 order = 8 

489 error_estimator_order = 7 

490 A = dop853_coefficients.A[:n_stages, :n_stages] 

491 B = dop853_coefficients.B 

492 C = dop853_coefficients.C[:n_stages] 

493 E3 = dop853_coefficients.E3 

494 E5 = dop853_coefficients.E5 

495 D = dop853_coefficients.D 

496 

497 A_EXTRA = dop853_coefficients.A[n_stages + 1:] 

498 C_EXTRA = dop853_coefficients.C[n_stages + 1:] 

499 

500 def __init__(self, fun, t0, y0, t_bound, max_step=np.inf, 

501 rtol=1e-3, atol=1e-6, vectorized=False, 

502 first_step=None, **extraneous): 

503 super().__init__(fun, t0, y0, t_bound, max_step, rtol, atol, 

504 vectorized, first_step, **extraneous) 

505 self.K_extended = np.empty((dop853_coefficients.N_STAGES_EXTENDED, 

506 self.n), dtype=self.y.dtype) 

507 self.K = self.K_extended[:self.n_stages + 1] 

508 

509 def _estimate_error(self, K, h): # Left for testing purposes. 

510 err5 = np.dot(K.T, self.E5) 

511 err3 = np.dot(K.T, self.E3) 

512 denom = np.hypot(np.abs(err5), 0.1 * np.abs(err3)) 

513 correction_factor = np.ones_like(err5) 

514 mask = denom > 0 

515 correction_factor[mask] = np.abs(err5[mask]) / denom[mask] 

516 return h * err5 * correction_factor 

517 

518 def _estimate_error_norm(self, K, h, scale): 

519 err5 = np.dot(K.T, self.E5) / scale 

520 err3 = np.dot(K.T, self.E3) / scale 

521 err5_norm_2 = np.linalg.norm(err5)**2 

522 err3_norm_2 = np.linalg.norm(err3)**2 

523 if err5_norm_2 == 0 and err3_norm_2 == 0: 

524 return 0.0 

525 denom = err5_norm_2 + 0.01 * err3_norm_2 

526 return np.abs(h) * err5_norm_2 / np.sqrt(denom * len(scale)) 

527 

528 def _dense_output_impl(self): 

529 K = self.K_extended 

530 h = self.h_previous 

531 for s, (a, c) in enumerate(zip(self.A_EXTRA, self.C_EXTRA), 

532 start=self.n_stages + 1): 

533 dy = np.dot(K[:s].T, a[:s]) * h 

534 K[s] = self.fun(self.t_old + c * h, self.y_old + dy) 

535 

536 F = np.empty((dop853_coefficients.INTERPOLATOR_POWER, self.n), 

537 dtype=self.y_old.dtype) 

538 

539 f_old = K[0] 

540 delta_y = self.y - self.y_old 

541 

542 F[0] = delta_y 

543 F[1] = h * f_old - delta_y 

544 F[2] = 2 * delta_y - h * (self.f + f_old) 

545 F[3:] = h * np.dot(self.D, K) 

546 

547 return Dop853DenseOutput(self.t_old, self.t, self.y_old, F) 

548 

549 

550class RkDenseOutput(DenseOutput): 

551 def __init__(self, t_old, t, y_old, Q): 

552 super().__init__(t_old, t) 

553 self.h = t - t_old 

554 self.Q = Q 

555 self.order = Q.shape[1] - 1 

556 self.y_old = y_old 

557 

558 def _call_impl(self, t): 

559 x = (t - self.t_old) / self.h 

560 if t.ndim == 0: 

561 p = np.tile(x, self.order + 1) 

562 p = np.cumprod(p) 

563 else: 

564 p = np.tile(x, (self.order + 1, 1)) 

565 p = np.cumprod(p, axis=0) 

566 y = self.h * np.dot(self.Q, p) 

567 if y.ndim == 2: 

568 y += self.y_old[:, None] 

569 else: 

570 y += self.y_old 

571 

572 return y 

573 

574 

575class Dop853DenseOutput(DenseOutput): 

576 def __init__(self, t_old, t, y_old, F): 

577 super().__init__(t_old, t) 

578 self.h = t - t_old 

579 self.F = F 

580 self.y_old = y_old 

581 

582 def _call_impl(self, t): 

583 x = (t - self.t_old) / self.h 

584 

585 if t.ndim == 0: 

586 y = np.zeros_like(self.y_old) 

587 else: 

588 x = x[:, None] 

589 y = np.zeros((len(x), len(self.y_old)), dtype=self.y_old.dtype) 

590 

591 for i, f in enumerate(reversed(self.F)): 

592 y += f 

593 if i % 2 == 0: 

594 y *= x 

595 else: 

596 y *= 1 - x 

597 y += self.y_old 

598 

599 return y.T