4
$\begingroup$

I want to evaluate the solution of a system of non-linear ODEs using ParametricNDSolve. The output of ParametricNDSolve is a ParametricFunction object. Let's call it $f_\theta(t)$, where $\theta$ is a list of all parameters used in ParametricNDSolve.

For a given choice of the parameters $\hat\theta$, the ParametricFunction becomes a InterpolatingFunction object. I want to evaluate this function at multiple points $\{t_1,t_2,...,t_n\}$, which is, obtaining the value $f_{\hat\theta}(t_i)$.

Does Mathematica fully solve the system of equations each time I call $f_{\hat\theta}(t_i)$ for a different $i$? Or does it cache the InterpolatingFunction after the first call (let's say, $f_{\hat\theta}(t_1)$) and uses it to obtain the value of $f_{\hat\theta}$ at $t_2,...,t_n$?

$\endgroup$
6
  • 2
    $\begingroup$ It's in the docs: Search for "ParametricCaching" (short answer: by default, it caches and reuses the last solution for a given set of parameters) $\endgroup$
    – Michael E2
    Commented Jul 29, 2021 at 20:17
  • $\begingroup$ Thanks @MichaelE2! If you post as a solution I'll be happy to accept it. If so, you should mention that the reference is in ParametricNDSolve/Options/Method/ParametricCaching. $\endgroup$
    – anonymous
    Commented Jul 29, 2021 at 20:27
  • $\begingroup$ I added a bit.... :) $\endgroup$
    – Michael E2
    Commented Jul 29, 2021 at 20:55
  • 2
    $\begingroup$ Related: What are the valid options for the “ParametricCaching” option in ParametricNDSolve? You seem to have gotten a better answer than I did, though. :-) $\endgroup$ Commented Jul 29, 2021 at 21:02
  • $\begingroup$ @MichaelSeifert Missed that question -- sorry. Summer's been busy. $\endgroup$
    – Michael E2
    Commented Jul 29, 2021 at 21:53

1 Answer 1

5
$\begingroup$

To extend this Q&A beyond one that is "easily found in the documentation," where some basic facts about "ParametricCaching" are given, I'll add some undocumented suboptions to Method -> {"ParametricCaching" -> {Automatic, ...opts...}}:

sol = ParametricNDSolveValue[{x''[t] + a x[t] == 0, x[0] == b, 
    x'[0] == 0}, x, {t, 0, 1000}, {a, b}, MaxSteps -> ∞];
sol[[-1, -1, -3]]
(*
{"Cache" -> True, "CacheTableLength" -> 19, "CacheTableWidth" -> 7, 
 "CacheKeyMaxBytes" -> 1000000, "CacheResultMaxBytes" -> 1000000, 
 "KeyComparison" -> None, "ResultComparison" -> LessEqual}
*)

For instance, we can use the timings to verify when a cached solution is reused. This confirms that the "TableCache*" suboptions seem to set the dimensions of the cache table:

sol1 = ParametricNDSolveValue[{x''[t] + a x[t] == 0, x[0] == b, 
    x'[0] == 0}, x, {t, 0, 1000}, {a, b}, MaxSteps -> ∞, 
   Method -> {"ParametricCaching" -> {Automatic, 
       "CacheTableLength" -> 1, "CacheTableWidth" -> 1}}]; 
sol1[1, 1][1] // AbsoluteTiming
sol1[1, 1][2] // AbsoluteTiming
sol1[1, 2][2] // AbsoluteTiming
sol1[1, 1][2] // AbsoluteTiming
(*
  {0.017357, 0.540302}
  {0.000014, -0.416147}
  {0.020204, -0.832294}
  {0.01881, -0.416147}   <-- N.B. Recomputed
*)

sol2 = ParametricNDSolveValue[{x''[t] + a x[t] == 0, x[0] == b, 
   x'[0] == 0}, x, {t, 0, 1000}, {a, b}, MaxSteps -> ∞, 
  Method -> {"ParametricCaching" -> {Automatic, 
      "CacheTableLength" -> 1, "CacheTableWidth" -> 2}}]; 
sol2[1, 1][1] // AbsoluteTiming
sol2[1, 1][2] // AbsoluteTiming
sol2[1, 2][2] // AbsoluteTiming
sol2[1, 1][2] // AbsoluteTiming
(*
  {0.019945, 0.540302}
  {0.000017, -0.416147}
  {0.01882, -0.832294}
  {0.000022, -0.416147}  <-- N.B. Reused
*)

The memory-related options should be self-explanatory and useful. We can test "CacheResultMaxBytes" but I'm not sure how to test "CacheKeyMaxBytes".

(* bytes of a result *)
sol1[1, 1] // ByteCount
(*  305704  *)

sol3 = ParametricNDSolveValue[{x''[t] + a x[t] == 0, x[0] == b, 
   x'[0] == 0}, x, {t, 0, 1000}, {a, b}, MaxSteps -> ∞, 
  Method -> {"ParametricCaching" -> {Automatic, 
      "CacheResultMaxBytes" -> 400000}}]; 
sol3[1, 1][1] // AbsoluteTiming
sol3[1, 1][2] // AbsoluteTiming
(*
  {0.015709, 0.540302}
  {0.000013, -0.416147}  <-- N.B. Reused
*)

sol4 = ParametricNDSolveValue[{x''[t] + a x[t] == 0, x[0] == b, 
   x'[0] == 0}, x, {t, 0, 1000}, {a, b}, MaxSteps -> ∞, 
  Method -> {"ParametricCaching" -> {Automatic, 
      "CacheResultMaxBytes" -> 1000}}];
sol4[1, 1][1] // AbsoluteTiming
sol4[1, 1][2] // AbsoluteTiming
(*
  {0.018927, 0.540302}
  {0.022862, -0.416147}  <-- N.B. Recomputed
*)

I don't about keys and their function in ParametricNDSolve caching, nor how "ResultComparison" is used.

(Note it's important to rerun ParametricNDSolveValue each time you want to test to reset the cache table.)

$\endgroup$
1
  • $\begingroup$ Thanks for the detailed answer! $\endgroup$
    – anonymous
    Commented Jul 29, 2021 at 21:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.