WIP: Experimental support for Unitful-like statically-typed units
I understand this goes against the main point of this package, but it turned out to be extremely easy to stick in a StaticDimensions interface.
The trick is to store a regular dynamic Dimensions object (immutable struct) as one of the type parameters:
struct StaticDimensions{R,D<:AbstractDimensions{R},dim} <: AbstractStaticDimensions{R,D,dim}
# (No fields)
StaticDimensions(d::AbstractDimensions) = new{eltype(d),typeof(d),d}()
end
Promotion rules work as you'd expect with Unitful:
julia> using DynamicQuantities; using DynamicQuantities: StaticDimensions
julia> x = Quantity{Float64,StaticDimensions}.([1.0u"m", 1.0u"km", 10us"Constants.Mpc"])
3-element Vector{Quantity{Float64, StaticDimensions(m::Dimensions{FixedRational{Int32, 25200}})}}:
1.0 m
1000.0 m
3.085677581491367e23 m
Where you can see it correctly promotes the dimensions (even symbolic dimensions).
We can see that units can be inferred:
julia> x = Quantity{Float64,StaticDimensions}(10u"km")
10000.0 m
julia> y = Quantity{Float64,StaticDimensions}(1u"h")
3600.0 s
julia> @inferred x / y
2.7777777777777777 m s⁻¹
julia> typeof(x / y)
Quantity{Float64, StaticDimensions(m s⁻¹::Dimensions{FixedRational{Int32, 25200}})}
If anyone is interested, would love help in making this infer as well as Unitful. It then would make it really easy to switch between static and dynamic quantities – Dimensions for initial work, and then StaticDimensions whenever you are faced with optimizing a fast SIMD loop.
Any of @yingboma @chrisrackauckas @devmotion @aplavin, would you be up to help with improving this? I think the basics are ready, we would just need to ensure that inference is as good as Unitful.
Benchmark Results
| main | 6afba7c2824aa4... | main/6afba7c2824aa4... | |
|---|---|---|---|
| Quantity/creation/Quantity(x) | 2.79 ± 0.009 ns | 2.79 ± 0 ns | 1 |
| Quantity/creation/Quantity(x, length=y) | 3.41 ± 0.01 ns | 3.41 ± 0.01 ns | 1 |
| Quantity/with_numbers/*real | 3.11 ± 0.01 ns | 3.1 ± 0.01 ns | 1 |
| Quantity/with_numbers/^int | 8.05 ± 2.2 ns | 8.05 ± 2.2 ns | 1 |
| Quantity/with_numbers/^int * real | 8.37 ± 1.9 ns | 8.37 ± 1.9 ns | 1 |
| Quantity/with_quantity/+y | 4.04 ± 0.001 ns | 4.04 ± 0.001 ns | 1 |
| Quantity/with_quantity//y | 3.11 ± 0 ns | 3.11 ± 0.001 ns | 1 |
| Quantity/with_self/dimension | 3.11 ± 0.01 ns | 3.1 ± 0.01 ns | 1 |
| Quantity/with_self/inv | 3.11 ± 0.001 ns | 3.11 ± 0 ns | 1 |
| Quantity/with_self/ustrip | 2.79 ± 0.009 ns | 2.79 ± 0.01 ns | 1 |
| QuantityArray/broadcasting/multi_array_of_quantities | 0.143 ± 0.00082 ms | 0.146 ± 0.001 ms | 0.978 |
| QuantityArray/broadcasting/multi_normal_array | 0.0541 ± 0.003 ms | 0.056 ± 0.0019 ms | 0.967 |
| QuantityArray/broadcasting/multi_quantity_array | 0.155 ± 0.0015 ms | 0.155 ± 0.00052 ms | 1 |
| QuantityArray/broadcasting/x^2_array_of_quantities | 23.9 ± 2.3 μs | 23.3 ± 2.3 μs | 1.03 |
| QuantityArray/broadcasting/x^2_normal_array | 4.83 ± 0.88 μs | 5.12 ± 0.91 μs | 0.943 |
| QuantityArray/broadcasting/x^2_quantity_array | 6.97 ± 0.26 μs | 6.98 ± 0.29 μs | 0.999 |
| QuantityArray/broadcasting/x^4_array_of_quantities | 0.0815 ± 0.00058 ms | 0.0816 ± 0.00055 ms | 1 |
| QuantityArray/broadcasting/x^4_normal_array | 0.0499 ± 0.00017 ms | 0.0498 ± 0.00018 ms | 1 |
| QuantityArray/broadcasting/x^4_quantity_array | 0.053 ± 0.00022 ms | 0.053 ± 0.0029 ms | 1 |
| time_to_load | 0.144 ± 0.00087 s | 0.151 ± 0.00055 s | 0.957 |
Benchmark Plots
A plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR. Go to "Actions"->"Benchmark a pull request"->[the most recent run]->"Artifacts" (at the bottom).