-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quantity currently incompatible with QuadGK #40
Comments
I wouldn’t mind taking a crack at a PR for this if you’re on board with changing this implementation, but I’d need to spend a little time making sure I understand the surrounding |
It looks like it returns a quantity with empty units, which is a correct multiplicative identity. But returning the underlying |
This comment was marked as outdated.
This comment was marked as outdated.
Is that all that’s needed to get QuadGK working? We could add an integration test for it. |
I’m happy to make the change. But, thinking out loud, I am also worried that design decisions made in Unitful (and propagated to and enforced by dependents) will influence the design of DynamicQuantities, because of network effects like this. In particular, consider this part of the docstring:
It sounds like this only applies when the type of What I’m thinking is that this usage of But I guess we have to, if it’s a common pattern across packages. |
@stevengj do you know other packages which assume this behavior of Maybe another option is to write a promotion rule for |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Okay I fixed it. #42 is now working with QuadGK.jl However it required the following changes. Before: abstract type AbstractQuantity{T,D} end
one(::Quantity{T,D}) -> Quantity{T,D}
one(::Type{Quantity{T,D}}) -> Quantity{T,D} is now abstract type AbstractQuantity{T,D} <: Number end
one(::Quantity{T,D}) -> T
one(::Type{Quantity{T,D}}) -> T is this actually what we want? @ChrisRackauckas or @odow I'd be eager to hear your opinion as well. |
I don't have a particularly strong opinion here. The docstring for I kind of stumbled onto this issue after being inspired by @ChrisRackauckas over on a Julia Discourse thread. I love the premise of integrating dimensionful quantities more directly into scientific computing calculations, have had some overall good experiences with Unitful, but I think DynamicQuantities approach is more promising in the long run. I would love to have better direct support between these kinds of packages without all of the |
That's definitely not correct if the units are encoded in the type, in which case Given that the type has to change, it seems a lot simpler to return the base scalar type rather than a dimensionless |
@stevengj I'm not sure if you've read the README so apologies if I'm overexplaining here: the underlying motivation for DynamicQuantities.jl is precisely this. DynamicQuantities stores units in the value rather than the type. This avoids type instabilities and overspecialized methods. Even in type stable situations, there is not much of a slowdown either – see example on README. Chris explains the benefits better than I can here. Thus, in DynamicQuantities, we can both have This is my main issue here. We no longer need to do this, because with DynamicQuantities, you can have the same exact type of quantity be a multiplicative identity. But in any case I am happy to implement it. I think that Unitful.jl compatibility, where possible, should be prioritized. |
Cross-referencing #42 (comment): changing |
Where possible, I'd keep the (Although JuMP's main problem is that |
Thanks for bringing up these points. It's very useful to know that With this in mind maybe we could:
"Get the first parametric type, if it exists"
function base_type(::Type{T}) where {T}
params = T isa UnionAll ? T.body.parameters : T.parameters
return length(params) == 0 ? T : params[1]
end to generically unwrap types like quantities and dual numbers, rather than using Aside: it would be nice if something like this function was in the standard library so packages could overload its behavior in case the base type is not listed first. Rather than needing to rely on ambiguous behavior from Default behavior: Quantity{Float64} -> Float64
Array{Float16,2} -> Float16
Float32 -> Float32
ComplexF64 -> Float64
Array{ComplexF64,1} -> ComplexF64
Dual{Int64} -> Int64 with failure cases like: julia> base_type(typeof(StaticArrays.SArray{Tuple{32,3}}(randn(32, 3))))
Tuple{32, 3} that would need to be overloaded... (or with a custom method for |
The main things that would be good to have tests for are various combinations of |
Really? If that's true, a lot of them are probably bugs, since that's only supposed to be guaranteed for (Most of the places where Base assumes That being said, if you store the units in the value rather than the type (to make things like |
I agree. In the short term I suppose it could be provided by a little package that defines a function |
I can make a package for this. Just to confirm, would you need Also, Also would you recommend making |
Not sure what you are asking about with |
Got it, thanks. The ext question was more: say I want to accelerate the transition to use this theoretical package. For special cases where the above function does not work for a particular wrapper (?), I was thinking whether it makes more sense to define those special cases in this package within |
Actually I can't think of any special cases after adding a mapping I created https://github.com/SymbolicML/BaseType.jl and gave you maintain access @stevengj. So the idea is that the |
Some points:
|
Don't worry, this wasn't what I was suggesting. If I would do something in this direction, each interface would go in
Good point, I'll remove them from the examples.
Not sure about this one:
Also there's no other That being said I don't feel strongly about this so if you would prefer BaseNumericType.jl, I will go ahead and change it.
If someone can move it there and give me write or maintain access, then that sounds good to me! |
FYI the countdown for the package to be registered ends tomorrow, so if you would prefer BaseNumericType.jl, let me know soon. |
Update: looks like this Issue is still valid but now errors differently. Integration of functions that output DynamicQuantities dimensionful types works on a primitive/float-valued domain but not on a dimensionful domain. # Julia v1.10.2, Windows x86-64
# Temp environment with only:
# DynamicQuantities v0.12.3
# QuadGK v2.9.4
julia> using DynamicQuantities, QuadGK
# Integrate a function with dimensionful output over a scalar-valued domain
julia> quadgk(t -> 5u"m/s"*t, 0, 10)
(250.0 m s⁻¹, 0.0 m s⁻¹)
# Integrate a function with dimensionful output over a dimensionful domain
julia> quadgk(t -> 5u"m/s"*t, 0u"s", 10u"s")
MethodError: no method matching kronrod(::Type{Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}}, ::Int64)
Closest candidates are:
kronrod(::Any, ::Integer, ::Real, ::Real; rtol, quad)
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\weightedgauss.jl:90
kronrod(::Type{T}, ::Integer) where T<:AbstractFloat
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\gausskronrod.jl:316
kronrod(::AbstractMatrix{<:Real}, ::Integer, ::Real, ::Pair{<:Tuple{Real, Real}, <:Tuple{Real, Real}})
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\gausskronrod.jl:390
...
Stacktrace:
[1] macro expansion
@ C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\gausskronrod.jl:564 [inlined]
[2] _cachedrule
@ C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\gausskronrod.jl:564 [inlined]
[3] cachedrule
@ C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\gausskronrod.jl:569 [inlined]
[4] do_quadgk(f::var"#1#2", s::Tuple{Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}, Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}}, n::Int64, atol::Nothing, rtol::Nothing, maxevals::Int64, nrm::typeof(LinearAlgebra.norm), segbuf::Nothing)
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\adapt.jl:7
[5] (::QuadGK.var"#50#51"{Nothing, Nothing, Int64, Int64, typeof(LinearAlgebra.norm), Nothing})(f::Function, s::Tuple{Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}, Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}}, ::Function)
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\adapt.jl:253
[6] handle_infinities(workfunc::QuadGK.var"#50#51"{Nothing, Nothing, Int64, Int64, typeof(LinearAlgebra.norm), Nothing}, f::var"#1#2", s::Tuple{Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}, Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}})
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\adapt.jl:145
[7] quadgk(::Function, ::Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}, ::Vararg{Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}}; atol::Nothing, rtol::Nothing, maxevals::Int64, order::Int64, norm::Function, segbuf::Nothing)
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\adapt.jl:252
[8] quadgk(::Function, ::Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}, ::Vararg{Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}})
@ QuadGK C:\Users\mikei\.julia\packages\QuadGK\OtnWt\src\adapt.jl:250
[9] top-level scope
@ REPL[5]:1 There's a |
In principle we can add a |
Oh but right, |
I've been testing out DynamicQuantities as a replacement for Unitful in some of my packages and I discovered that it currently doesn't work with QuadGK's integral solver like Unitful does. MWE (issue also opened here).
It looks like the issue probably spawns from here where
Base.one(::Quantity)
produces anew_quantity
.QuadGK would expect
Base.one
for the above example to return simply aFloat64
instead. This seems consistent with the docstring forBase.one
, excerpted:It also seems consistent with how Unitful handles this
Was the current definition of
Base.one
here intended to return the dimensioned type?The text was updated successfully, but these errors were encountered: