5
$\begingroup$

I'm trying to get some performance increase out of my own implicit differential equation solver using Compile[]. The uncompiled function is of the following form:

fun = Module[
  {sol = ConstantArray[0, 10], init = 0.001},
  f[xN_] = xN + xNP1^2 == 4;
  Do[
    sol[[i]] = xNP1 /. FindRoot[f[init], {xNP1, init}];
    init = sol[[i]]
    , {i, 10}
  ];
  sol
]

which works correctly. Of course, for the real function I need many more than 10 iteration in the loop and was hoping to gain some performance increase with Compile[]. Here is the compile code:

cFun = Compile[{},
         Module[
           {sol = ConstantArray[0, 10], init = 0.001},
           f[xN_] = xN + xNP1^2 == 4;
           Do[
             sol[[i]] = xNP1 /. FindRoot[f[init], {xNP1, init}];
             init = sol[[i]]
             , {i, 10}
           ];
           sol
         ]
      ]

However, the compiled function fails with because f[init] is held unevaluated as passed into FindRoot, I believe. Is there a way around this or another solution I am not thinking of?

$\endgroup$
1
  • 1
    $\begingroup$ You're going to have some trouble with this one no matter what, since FindRoot returns a rule as an answer and Compile only really handles functions that return numbers. Also, the slow part is almost certainly FindRoot, so Compile is unlikely to help too much. $\endgroup$
    – Pillsy
    Commented Apr 5, 2012 at 19:52

2 Answers 2

8
$\begingroup$

I think you're going after it the wrong way. FindRoot is not compilable, and it's expected to be the most CPU-expensive part of your loop, so the possible benefits of compilation seem scarce.

To quote this most excellent answer by halirutan:

To summarize: Usually you don't need any list of supported functions, because the rule of thumb is, that compile will not work with already optimized, complicated Mathematica-methods. This includes NIntegrate, FindRoot or NMinimize. Nevertheless, Compile can easily be used to make those function-calls really fast. What you have to do is to compile your target function, because the most time with stuff like NIntegrate is spent, evaluating the integrand. The same is true for FindRoot, NMinimize and many more methods.

(emphasis mine).

$\endgroup$
1
$\begingroup$

You should take a good look at the advanced documentation for NDSolve. NDSolve allows you to choose from many methods and you can tweak them in many ways. I think it will be very hard to beat the performance that is possible with the built in NDSolve.

$\endgroup$
2
  • $\begingroup$ Here I'm using a MWE and not the real equations. The real equations are a set of Differential-Algebraic Equations that have to be solved implicitly. I actually sent a Premier Service help request to Wolfram and they said the way I was solving it was probably the best way. I was just trying to get some performance increase here. It doesn't look like that is possible. $\endgroup$ Commented Apr 6, 2012 at 1:49
  • $\begingroup$ In that case you still might be able to improve performance if your compiled code includes a root-finding method built from scratch. It looks like you are doing root finding in 1D. If you know you can start with two points where the function changes sign Brent's method is a great choice. I could provide a Mma implementation of Brent's method. If you can't use Brent's method, another method such as Newton's method or secant method might work well. They are both easy to implement. You may also need to roll your own version of other function that can't be compiled. $\endgroup$
    – Ted Ersek
    Commented Apr 6, 2012 at 17:38

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.