3
$\begingroup$

I want to speed up evaluation time of a long expression (a function of a single parameter t). To do so, I thought about using Compile but I then run into warnings about numerical errors (although the function itself is absolutely fine). Here is an example for an expression in question:

expr=Uncompress["1:eJztnL9KA0EQh0+TiGVAQS3t7W0TrASLGIRgIygkuBA9zEXsLOzSaeVb+AJWgmhhYaE+hGBhZyPE2ySYZG8vGwNr7s93xcElt3OTuZ3vNw6DqwduuZZ1HMeTpy3hNWuz8irnn3bEUdXrXs77p/J+U7jH+3Ux418I+XH3O7mwVD/1zAvb/jGwUN5acs+qjb4D0k7D6R1mg/JCZAKeNB4q9+7VzWGhlhmyIC6Dz/bkZUlo3ZI/1JMmNlxPMaVxRn4i5A09k55c3uwazpoWf8rQZII+DPgVfAed+zNDv/x87Xru4vmloMSusdtev937Wira+4lKqJ3t0FBnbYVaZ3isrdUJv7oy2ltq4OXrnIms38p+fX9defw4eQrs19bb3fJmazF9+3UUUsW3Zpvq8n+hqM//yj/GM5+bSjx1EFVi5PQOIAAElE07JQiMVPmQ79q/FYPxye0/Fhdh9yOmEfObPEJMbcYTMQUCsYPAJGLa/3PauM4otLqXPfSKzHaU3Ivu1jP2NfKOniL0NehraOMNhZO5XynFKMWAQMogYLmvoVRtxuKCvgZ5FMs8QkwRUyCQcghMsa8x8cSH5hlMfDDxQWcEjqeW4xRzFHNAIOUQYOKDPCKPEFPEFAgAgfh2Rpj4UBcz8WFJ2ijFouU3FKYUsxlPSjEgEDsIMPFBHpFHiCliCgSAQHz7GhNPfPA/PkIXM/FhSRwp5qLlNxynmLMZT4o5IBA7CDDxQR6RR4gpYgoEgEBiOiMhOWO2w8QHfQ36GlA4QfuVUoxSDAikDAJMfJBH5BFiipgCASCQmL7G+I2M0IYIEx9MfFgSR4q5aPkNxynmbMaTYg4IxA4CTHyQR+QRYoqYAgEgkJjOSEjOmO0w8UFfg74GFE7QfqUUoxQDAimDABMf5BF5hJgipkAACES1r/EDoJXfZA=="];
compiledExpr = With[{e = expr}, Compile[{{t, _Real}}, Re[e], RuntimeOptions -> "Quality"]]; 
compiledExpr[2.]

CompiledFunction::cfn: Numerical error encountered at instruction 29; proceeding with uncompiled evaluation.

(* {-19.6371, -13.3496, 13.3496, 19.6371} *)

If one then looks at

Needs["CompiledFunctionTools`"];
CompilePrint[compiledExpr]

it is possible to observe the instruction in question. However, I don't know how to extract the relevant information about all those common expressions inside the CompiledFunction that would allow me to debug what is going on without writing and tracing all instructions one after another by hand. Perhaps it is also just sufficient to provide other options to Compile that already solve the problem.

There are somehow related questions (61596), (13689) but they seem to both tackle an issue with infinite expressions during evaluation, which for me should not be the case (the erroneous instruction in my case is a Sqrt). Most relevant appears to be (92440) but in order to make an attempt to use the conclusion there, I need to figure out how to better understand what happens inside my CompiledFuntion.

I wonder

  • how to debug such situations generally to figure out what exactly is going wrong and
  • how to fix this specific error
  • (optional) if there is any other means than Compile which enables faster evaluation of expr for given t

and would really appreciate assistance.

$\endgroup$
  • 2
    $\begingroup$ Using CompilationOptions -> {"ExpressionOptimization" -> False} seems to remove the warnings. $\endgroup$ – b.gates.you.know.what Mar 20 '18 at 11:31
  • $\begingroup$ @b.gatessucks Thanks. Indeed that at least solves the problem for this particular example and many parameter values for other similar expressions. However, not all of them. So I'd be really interested in a way to somehow strategically debug such errors without keeping track of everything by hand, i.e. evaluate all instructions of the CompiledFunction one after another $\endgroup$ – Lukas Mar 20 '18 at 12:31
6
$\begingroup$

This is not going to attempt to answer the general debugging question (in fact, I don't think there is a way to do that), so feel free to consider it as just a long comment.

The specific situation is, however, clear enough. According to the warning message, the numerical error happened at instruction 29, which per CompilePrint is

29 R31 = Sqrt[ R30]

What kind of compiled evaluation error could happen with this simple arithmetic operation?

Sqrt cannot really overflow and I am using version 11.3, which does no underflow checking (in earlier versions, one could switch underflow checking off explicitly for the sake of experiment, and that would still give the error), so it is not either one of those.

The remaining alternative is a type exception. If R30 is negative, the result will be a complex number, which cannot be stored in the real register R31.

As further evidence, note that the following does not fall back to uncompiled evaluation

compiledExpr = With[{e = expr}, 
                 Compile[{{t, _Complex}}, Re[e], RuntimeOptions -> "Quality"]];
compiledExpr[2.]

(* {-19.6371, -13.3496, 13.3496, 19.6371} *)

and the input expr certainly has instances where the square root of something negative could be taken

FirstCase[expr, Power[subexpr_, 1/2] :> subexpr, None, Infinity] /. t -> 2.

(* -2.25007*10^20 *)

This topic is discussed in several places in the documentation, for example see Compiling Wolfram Language Expressions

The compiled code generated by Compile must make assumptions not only about the types of arguments you will supply, but also about the types of all objects that arise during the execution of the code. Sometimes these types depend on the actual values of the arguments you specify. Thus, for example, Sqrt[x] yields a real number result for real x if x is not negative, but yields a complex number if x is negative.

Compile always makes a definite assumption about the type returned by a particular function. If this assumption turns out to be invalid in a particular case when the code generated by Compile is executed, then the Wolfram Language simply abandons the compiled code in this case, and evaluates an ordinary Wolfram Language expression to get the result.

or the Type Propagation section of the Wolfram System Compiler tutorial.

$\endgroup$
  • $\begingroup$ May I ask why 11.3 no longer has underflow checking? $\endgroup$ – QuantumDot Mar 21 '18 at 19:01
  • 3
    $\begingroup$ Performance, efficiency, consistency and better arithmetic support for the new compiler. There are a couple of slides about machine underflow in this talk. $\endgroup$ – ilian Mar 21 '18 at 21:46
  • $\begingroup$ @ilian Thank you very much for the detailed answer/comment. You're right that it is not general, but it does definitely guide me to more general discussions in the documentation - which is already very helpful! $\endgroup$ – Lukas Mar 26 '18 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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