-
Notifications
You must be signed in to change notification settings - Fork 19
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
Create AutoFloat
type for units
#66
base: main
Are you sure you want to change the base?
Conversation
[Diff since v0.5.0](v0.5.0...v0.6.0) **Closed issues:** - Physical constants (#26) **Merged pull requests:** - Create (1) physical constants, and (2) symbolic dimensions object (#32) (@MilesCranmer)
[Diff since v0.7.3](v0.7.3...v0.7.4) **Merged pull requests:** - Add `uconvert` and chemistry example (#48) (@gaurav-arya) - Add `uconvert` method for `QuantityArray` (#61) (@MilesCranmer) - Deprecate `expand_units` -> `uexpand` (#62) (@MilesCranmer)
Benchmark Results
Benchmark PlotsA plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR. |
AutoFloat
type for units
9063393
to
6f3fc1f
Compare
6f3fc1f
to
3bc4463
Compare
This seems too complicated to me. Isn't it possible to just convert apply |
I am not sure how to do it any other way. Do you have an implementation in mind? |
To me it seems the main problem is that the current implementation of the julia> typeof(Unitful.u"m")
Unitful.FreeUnits{(m,), 𝐋, nothing}
julia> typeof(Unitful.u"1f0m")
Unitful.Quantity{Float32, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}
julia> typeof(1f0Unitful.u"m")
Unitful.Quantity{Float32, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}
julia> typeof(Unitful.u"1f0")
Float32 I think this would be more intuitive than the current behaviour of DynamicQuantities: julia> typeof(DynamicQuantities.u"m")
DynamicQuantities.Quantity{Float64, DynamicQuantities.Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}
julia> typeof(DynamicQuantities.u"1f0m")
DynamicQuantities.Quantity{Float64, DynamicQuantities.Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}
julia> typeof(1f0DynamicQuantities.u"m")
DynamicQuantities.Quantity{Float64, DynamicQuantities.Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}
julia> typeof(DynamicQuantities.u"1f0")
DynamicQuantities.Quantity{Float64, DynamicQuantities.Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}} Edit: I retract this comment partly. I guess these inconsistencies with Unitful are unavoidable since DynamicQuantities does not store the unit in the type domain. However, I don't think DynamicQuantities should try to convert everything to the default type. |
These conversions are to make the return value of
The operator |
Also keep in mind (I see your edit mentioned this) that all units and constants have numerical values in SI base units, so they are stored as |
It's a macro, so the string is replaced with whatever expression you want to replace it with. And then the resulting function/code/etc. is compiled by the Julia compiler. I don't see how the conversions help type stability. As a quick demonstration I replaced the julia> using DynamicQuantities, Test
julia> julia> f(x) = x * u"3m/s"
f (generic function with 1 method)
julia> @inferred f(3)
9.0 m s⁻¹
julia> @inferred f(1.0)
3.0 m s⁻¹
julia> @code_warntype f(2)
MethodInstance for f(::Int64)
from f(x) @ Main REPL[18]:1
Arguments
#self#::Core.Const(f)
x::Int64
Body::Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}
1 ─ %1 = (x * 3.0 m s⁻¹)::Core.PartialStruct(Quantity{Float64, Dimensions{DynamicQuantities.FixedRational{Int32, 25200}}}, Any[Float64, Core.Const(m s⁻¹)])
└── return %1
julia> @code_lowered f(1.0)
CodeInfo(
1 ─ %1 = x * 3.0 m s⁻¹
└── return %1
)
To be precise, it would only require to choose a default quantity type for |
I guess using However I do like having We need |
I still think that it would be preferable to change the macro and parsing in more fundamental ways. But in any case, I don't think adding a new numeric type is a good idea (I've seen too many things go wrong in different packages). The much simpler approach would be to make the "units" quantities with julia> 1.0 * true
1.0
julia> 2 * true
2
julia> Float16(3) * true
Float16(3.0)
julia> 4f0 * true
4.0f0 |
Unlike Bool I think we want to convert integers to floats, otherwise the user could write |
I'm not sure if that's a good idea. To me it seems rather surprising to not respect the types chosen by a user (which also lead to #65 and is inconsistent with Unitful). If you really want to prevent this case, you could specialize |
The user could still convert to a |
Btw with |
To clarify the key problem: the question is, when the user writes something like It's a tricky problem and I don't have a perfect solution, but hopefully the thoughts below are helpful.
Edit: lastly, regarding @devmotion's concern about adding a new numerical type, I very much share it: it is indeed a somewhat tricky problem. Essentially, it boils down to there not being an However, two points regarding Edit 2: in fact, as a middle ground, what if we intentionally only defined |
Thanks for sharing all of your thoughts on this! The one comment I will make is that I think we should try to avoid an API that requires things like using DynamicQuantities.Units: m, kg
using DynamicQuantities.Constants: c
q = 0.3f0 * kg/m^3 * c^2 which is just normal Julia code (which, btw, would create a Keep in mind this |
Just to clarify something – the promotion rules here turn out to be the same as used in irrational numbers. e.g., julia> promote(π, 1) |> typeof
Tuple{Float64, Float64}
julia> promote(π, 1f0) |> typeof
Tuple{Float32, Float32} |
Attempt 2 at #30. cc @gaurav-arya - let me know what you think. This should fixes #65.
The following behavior occurs:
Float16(1.0)u"km/s"
Float16
type1f0u"km/s"
Float32
type1.0u"km/s"
Float64
typebig(1.0)u"km/s"
BigFloat
typeI also do:
1u"km/s"
Float64
typeThe reason I convert integers to float is because of type instability. I don't want some units to convert to float for the sake of precision issues (like femtometers) while others can stay in integral form. So for integers the user will have to be explicit.
TODO remaining:
AutoFloat
for SymbolicDimensions versions of units