I am new to Julia and trying out the ModelingToolking package. I have a basic understanding of the type system and the dynamic dispatch, but couldn’t figure out why this didn’t work.
This works perfectly - almost magic to me:
>>> using ModelingToolkit
>>> using Distributions
>>> @variables t
>>> d = Normal()
>>> pdf(d, t)
(exp((-abs2((t - 0.0) / 1.0)) / 2) * invsqrt2π) / 1.0
Then this didn’t work.
>>> cdf(d, t)
MethodError: no method matching AbstractFloat(::Num)
Closest candidates are:
AbstractFloat(::Real, !Matched::RoundingMode) where T<:AbstractFloat at rounding.jl:200
AbstractFloat(::T) where T<:Number at boot.jl:716
AbstractFloat(!Matched::Bool) at float.jl:258
If I check the Distributions package documentation, both functions have the same function signature:
Also, from the ModelingToolkit tutorial,
Note that by default,
Term objects wrapped in
Num in order to make them behave like subtypes of
So, I’m wondering why it worked for pdf but not for cdf.
Symbolic values get passed through normal Julia code fine, but in this case
erfc is implemented in C and Julia attempts to convert the symbolic value
t to a floating point number to pass to the C routine. This can’t work, so you get the traceback. The solution is to tell
erfc is a fundamental operation and that it shouldn’nt bother trying to look inside it.
julia> using SpecialFunctions
julia> @register SpecialFunctions.erfc(x)
julia> cdf(d, t)
erfc((-((t - 0.0) / 1.0)) * invsqrt2) / 2
In the case of
exp had already been registered with
ModelingToolkit, so it already knew not to look inside.
I kinda remember that Matlab can symbolically differentiate its normcdf function. Does that mean Matlab’s normcdf is not derived from erfc?
I encountered this same issue two years but still haven’t figured out how to do it in Julia…
Thanks, @contradict. It’s great to know that this works!
Φ = cdf(d, t)
# 0.3989422804014327 * exp(-0.5000000000000001 * (t ^ 2))
Oh, yikes, I’m surprised that worked! For a function like
erfc that is implemented in a C library, you also need to register a derivative if you want to differentiate it. It looks like a derivative was registered for
erfc, but the function itself was not registered, and I’m not sure where it should have been.
I don’t know how Matlab handles this, but
ModelingToolkit defines the derivatives of some base set of functions and then works to express derivatives of your expression in terms of that base set.