Skip to content

Commit 117655a

Browse files
committed
Get majority of tests working with RealQuantity
1 parent 116c2a3 commit 117655a

File tree

4 files changed

+73
-66
lines changed

4 files changed

+73
-66
lines changed

ext/DynamicQuantitiesUnitfulExt.jl

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module DynamicQuantitiesUnitfulExt
22

3-
import DynamicQuantities
3+
using DynamicQuantities: DynamicQuantities, ABSTRACT_QUANTITY_TYPES
4+
45
import Unitful
56
import Unitful: @u_str
67

@@ -23,30 +24,33 @@ function unitful_equivalences()
2324
return NamedTuple((k => si_units[k] for k in keys(si_units)))
2425
end
2526

26-
Base.convert(::Type{Unitful.Quantity}, x::DynamicQuantities.Quantity) =
27-
let
28-
validate_upreferred()
29-
cumulator = DynamicQuantities.ustrip(x)
30-
dims = DynamicQuantities.dimension(x)
31-
if dims isa DynamicQuantities.SymbolicDimensions
32-
throw(ArgumentError("Conversion of a `DynamicQuantities.Quantity` to a `Unitful.Quantity` is not defined with dimensions of type `SymbolicDimensions`. Instead, you can first use the `uexpand` function to convert the dimensions to their base SI form of type `Dimensions`, then convert this quantity to a `Unitful.Quantity`."))
27+
for (_, _, Q) in ABSTRACT_QUANTITY_TYPES
28+
@eval begin
29+
function Base.convert(::Type{Unitful.Quantity}, x::$Q)
30+
validate_upreferred()
31+
cumulator = DynamicQuantities.ustrip(x)
32+
dims = DynamicQuantities.dimension(x)
33+
if dims isa DynamicQuantities.SymbolicDimensions
34+
throw(ArgumentError("Conversion of a `DynamicQuantities." * string($Q) * "` to a `Unitful.Quantity` is not defined with dimensions of type `SymbolicDimensions`. Instead, you can first use the `uexpand` function to convert the dimensions to their base SI form of type `Dimensions`, then convert this quantity to a `Unitful.Quantity`."))
35+
end
36+
equiv = unitful_equivalences()
37+
for dim in keys(dims)
38+
value = dims[dim]
39+
iszero(value) && continue
40+
cumulator *= equiv[dim]^value
41+
end
42+
cumulator
3343
end
34-
equiv = unitful_equivalences()
35-
for dim in keys(dims)
36-
value = dims[dim]
37-
iszero(value) && continue
38-
cumulator *= equiv[dim]^value
44+
function Base.convert(::Type{$Q}, x::Unitful.Quantity{T}) where {T}
45+
return convert($Q{T,DynamicQuantities.DEFAULT_DIM_TYPE}, x)
46+
end
47+
function Base.convert(::Type{$Q{T,D}}, x::Unitful.Quantity) where {T,R,D<:DynamicQuantities.AbstractDimensions{R}}
48+
value = Unitful.ustrip(Unitful.upreferred(x))
49+
dimension = convert(D, Unitful.dimension(x))
50+
return $Q(convert(T, value), dimension)
3951
end
40-
cumulator
41-
end
42-
43-
Base.convert(::Type{DynamicQuantities.Quantity}, x::Unitful.Quantity{T}) where {T} = convert(DynamicQuantities.Quantity{T,DynamicQuantities.DEFAULT_DIM_TYPE}, x)
44-
Base.convert(::Type{DynamicQuantities.Quantity{T,D}}, x::Unitful.Quantity) where {T,R,D<:DynamicQuantities.AbstractDimensions{R}} =
45-
let
46-
value = Unitful.ustrip(Unitful.upreferred(x))
47-
dimension = convert(D, Unitful.dimension(x))
48-
return DynamicQuantities.Quantity(convert(T, value), dimension)
4952
end
53+
end
5054

5155
Base.convert(::Type{DynamicQuantities.Dimensions}, d::Unitful.Dimensions) = convert(DynamicQuantities.DEFAULT_DIM_TYPE, d)
5256
Base.convert(::Type{DynamicQuantities.Dimensions{R}}, d::Unitful.Dimensions{D}) where {R,D} =

src/fixed_rational.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,23 @@ struct FixedRational{T<:Integer,den} <: Real
1414
num::T
1515
global unsafe_fixed_rational(num::Integer, ::Type{T}, ::Val{den}) where {T,den} = new{T,den}(num)
1616
end
17+
@inline _denom(::Type{F}) where {T,den,F<:FixedRational{T,den}} = den
1718

1819
"""
1920
denom(F::FixedRational)
2021
2122
Since `den` can be a different type than `T`, this function
2223
is used to get the denominator as a `T`.
2324
"""
24-
denom(::Type{F}) where {T,den,F<:FixedRational{T,den}} = convert(T, den)
25+
denom(::Type{<:F}) where {T,F<:FixedRational{T}} = convert(T, _denom(F))
2526
denom(x::FixedRational) = denom(typeof(x))
2627

2728
# But, for Val(den), we need to use the same type as at init.
2829
# Otherwise, we would have type instability.
29-
val_denom(::Type{F}) where {T,den,F<:FixedRational{T,den}} = Val(den)
30+
val_denom(::Type{<:F}) where {F<:FixedRational} = Val(_denom(F))
3031

31-
num_type(::Type{F}) where {T,F<:FixedRational{T}} = T
32+
num_type(::Type{<:FixedRational{T}}) where {T} = T
33+
num_type(x::FixedRational) = num_type(typeof(x))
3234

3335
const DEFAULT_NUMERATOR_TYPE = Int32
3436
const DEFAULT_DENOM = DEFAULT_NUMERATOR_TYPE(2^4 * 3^2 * 5^2 * 7)
@@ -75,9 +77,9 @@ Base.decompose(x::F) where {T,F<:FixedRational{T}} = (x.num, zero(T), denom(F))
7577

7678
# Promotion with self or rational-like
7779
function Base.promote_rule(::Type{F1}, ::Type{F2}) where {F1<:FixedRational,F2<:FixedRational}
78-
denom(F1) == denom(F2) ||
80+
_denom(F1) == _denom(F2) ||
7981
error("Refusing to promote `FixedRational` types with mixed denominators. Use `Rational` instead.")
80-
return FixedRational{promote_type(num_type(F1), num_type(F2)),denom(F1)}
82+
return FixedRational{promote_type(num_type(F1), num_type(F2)), _denom(F1)}
8183
end
8284
function Base.promote_rule(::Type{F}, ::Type{Rational{T2}}) where {F<:FixedRational,T2}
8385
return Rational{promote_type(num_type(F),T2)}

test/test_unitful.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import Ratios: SimpleRatio
66
import SaferIntegers: SafeInt16
77
using Test
88

9-
risapprox(x::Unitful.Quantity, y::Unitful.Quantity; kws...) =
10-
let (xfloat, yfloat) = (Unitful.ustrip Unitful.upreferred).((x, y))
11-
return isapprox(xfloat, yfloat; kws...)
12-
end
9+
function risapprox(x::Unitful.Quantity, y::Unitful.Quantity; kws...)
10+
(xfloat, yfloat) = (Unitful.ustrip Unitful.upreferred).((x, y))
11+
return isapprox(xfloat, yfloat; kws...)
12+
end
1313

1414
for T in [DEFAULT_VALUE_TYPE, Float16, Float32, Float64], R in [DEFAULT_DIM_BASE_TYPE, Rational{Int16}, Rational{Int32}, SimpleRatio{Int}, SimpleRatio{SafeInt16}]
1515
D = DynamicQuantities.Dimensions{R}

test/unittests.jl

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using DynamicQuantities
22
using DynamicQuantities: FixedRational
3-
using DynamicQuantities: DEFAULT_DIM_BASE_TYPE, DEFAULT_DIM_TYPE, DEFAULT_VALUE_TYPE
3+
using DynamicQuantities: DEFAULT_QUANTITY_TYPE, DEFAULT_DIM_BASE_TYPE, DEFAULT_DIM_TYPE, DEFAULT_VALUE_TYPE
44
using DynamicQuantities: array_type, value_type, dim_type, quantity_type
5-
using DynamicQuantities: GenericQuantity
5+
using DynamicQuantities: GenericQuantity, with_type_parameters, constructorof
66
using Ratios: SimpleRatio
77
using SaferIntegers: SafeInt16
88
using StaticArrays: SArray, MArray
@@ -20,7 +20,7 @@ end
2020

2121
@testset "Basic utilities" begin
2222

23-
for Q in [Quantity, GenericQuantity], T in [DEFAULT_VALUE_TYPE, Float16, Float32, Float64], R in [DEFAULT_DIM_BASE_TYPE, Rational{Int16}, Rational{Int32}, SimpleRatio{Int}, SimpleRatio{SafeInt16}]
23+
for Q in [Quantity, GenericQuantity, RealQuantity], T in [DEFAULT_VALUE_TYPE, Float16, Float32, Float64], R in [DEFAULT_DIM_BASE_TYPE, Rational{Int16}, Rational{Int32}, SimpleRatio{Int}, SimpleRatio{SafeInt16}]
2424
D = Dimensions{R}
2525
x = Q(T(0.2), D, length=1, mass=2.5)
2626

@@ -390,32 +390,32 @@ end
390390
@test utime(x) == -2
391391

392392
y = 0.9u"sqrt(mΩ)"
393-
@test typeof(y) == Quantity{Float64,DEFAULT_DIM_TYPE}
393+
@test typeof(y) == with_type_parameters(DEFAULT_QUANTITY_TYPE, Float64, DEFAULT_DIM_TYPE)
394394
@test ustrip(y) 0.02846049894151541
395395
@test ucurrent(y) == -1
396396
@test ulength(y) == 1
397397

398398
y = BigFloat(0.3) * u"mΩ"
399-
@test typeof(y) == Quantity{BigFloat,DEFAULT_DIM_TYPE}
399+
@test typeof(y) == with_type_parameters(DEFAULT_QUANTITY_TYPE, BigFloat, DEFAULT_DIM_TYPE)
400400
@test ustrip(y) 0.0003
401401
@test ulength(y) == 2
402402

403-
y32 = convert(Quantity{Float32,Dimensions{Rational{Int16}}}, y)
404-
@test typeof(y32) == Quantity{Float32,Dimensions{Rational{Int16}}}
403+
y32 = convert(with_type_parameters(DEFAULT_QUANTITY_TYPE, Float32, Dimensions{Rational{Int16}}), y)
404+
@test typeof(y32) == with_type_parameters(DEFAULT_QUANTITY_TYPE, Float32, Dimensions{Rational{Int16}})
405405
@test ustrip(y32) 0.0003
406406

407407
z = u"yr"
408408
@test utime(z) == 1
409409
@test ustrip(z) 60 * 60 * 24 * 365.25
410410

411411
# Test type stability of extreme range of units
412-
@test typeof(u"1") == Quantity{Float64,DEFAULT_DIM_TYPE}
413-
@test typeof(u"1f0") == Quantity{Float64,DEFAULT_DIM_TYPE}
414-
@test typeof(u"s"^2) == Quantity{Float64,DEFAULT_DIM_TYPE}
415-
@test typeof(u"") == Quantity{Float64,DEFAULT_DIM_TYPE}
416-
@test typeof(u"Gyr") == Quantity{Float64,DEFAULT_DIM_TYPE}
417-
@test typeof(u"fm") == Quantity{Float64,DEFAULT_DIM_TYPE}
418-
@test typeof(u"fm"^2) == Quantity{Float64,DEFAULT_DIM_TYPE}
412+
@test typeof(u"1") == DEFAULT_QUANTITY_TYPE
413+
@test typeof(u"1f0") == DEFAULT_QUANTITY_TYPE
414+
@test typeof(u"s"^2) == DEFAULT_QUANTITY_TYPE
415+
@test typeof(u"") == DEFAULT_QUANTITY_TYPE
416+
@test typeof(u"Gyr") == DEFAULT_QUANTITY_TYPE
417+
@test typeof(u"fm") == DEFAULT_QUANTITY_TYPE
418+
@test typeof(u"fm"^2) == DEFAULT_QUANTITY_TYPE
419419

420420
@test_throws LoadError eval(:(u":x"))
421421
end
@@ -486,10 +486,10 @@ end
486486
a = 0.5u"km/s"
487487
b = MyNumber(0.5)
488488
ar = [a, b]
489-
@test ar isa Vector{Number}
489+
@test ar isa Vector{Real}
490490
@test a === ar[1]
491491
@test b === ar[2]
492-
@test promote_type(MyNumber, typeof(a)) == Number
492+
@test promote_type(MyNumber, typeof(a)) == Real
493493

494494
# Explicit conversion so coverage can see it:
495495
D = DEFAULT_DIM_TYPE
@@ -609,7 +609,7 @@ end
609609

610610
q = 1.5us"km/s"
611611
@test q == 1.5 * us"km" / us"s"
612-
@test typeof(q) <: Quantity{Float64,<:SymbolicDimensions}
612+
@test typeof(q) <: with_type_parameters(DEFAULT_QUANTITY_TYPE, Float64, SymbolicDimensions{DEFAULT_DIM_BASE_TYPE})
613613
@test string(dimension(q)) == "s⁻¹ km"
614614
@test uexpand(q) == 1.5u"km/s"
615615
@test string(dimension(us"Constants.au^1.5")) == "au³ᐟ²"
@@ -683,13 +683,13 @@ end
683683
@test_throws DimensionError uconvert(us"nm * J", 5e-9u"m")
684684

685685
# Types:
686-
@test typeof(uconvert(us"nm", 5e-9u"m")) <: Quantity{Float64,<:SymbolicDimensions}
686+
@test typeof(uconvert(us"nm", 5e-9u"m")) <: RealQuantity{Float64,<:SymbolicDimensions}
687687
@test typeof(uconvert(us"nm", GenericQuantity(5e-9u"m"))) <: GenericQuantity{Float64,<:SymbolicDimensions}
688688
@test uconvert(GenericQuantity(us"nm"), GenericQuantity(5e-9u"m")) 5us"nm"
689689
@test uconvert(GenericQuantity(us"nm"), GenericQuantity(5e-9u"m")) GenericQuantity(5us"nm")
690690

691691
# We only want to convert the dimensions, and ignore the quantity type:
692-
@test typeof(uconvert(GenericQuantity(us"nm"), 5e-9u"m")) <: Quantity{Float64,<:SymbolicDimensions}
692+
@test typeof(uconvert(GenericQuantity(us"nm"), 5e-9u"m")) <: RealQuantity{Float64,<:SymbolicDimensions}
693693

694694
q = 1.5u"Constants.M_sun"
695695
qs = uconvert(us"Constants.M_sun", 5.0 * q)
@@ -704,7 +704,7 @@ end
704704
VERSION >= v"1.8" &&
705705
@test_throws "You passed a quantity" uconvert(1.2us"m", 1.0u"m")
706706

707-
for Q in (Quantity, GenericQuantity)
707+
for Q in (RealQuantity, Quantity, GenericQuantity)
708708
# Different types require converting both arguments:
709709
q = convert(Q{Float16}, 1.5u"g")
710710
qs = uconvert(convert(Q{Float16}, us"g"), 5 * q)
@@ -769,10 +769,10 @@ end
769769
x = 1.0u"m"
770770
y = x ^ (3//2)
771771
@test y == Quantity(1.0, length=3//2)
772-
@test typeof(y) == Quantity{Float64,DEFAULT_DIM_TYPE}
772+
@test typeof(y) == RealQuantity{Float64,DEFAULT_DIM_TYPE}
773773
end
774774

775-
for Q in (Quantity, GenericQuantity)
775+
for Q in (RealQuantity, Quantity, GenericQuantity)
776776
@testset "Arrays" begin
777777
@testset "Basics" begin
778778
x = QuantityArray(randn(32), Q(u"km/s"))
@@ -798,7 +798,7 @@ for Q in (Quantity, GenericQuantity)
798798

799799
# Test default constructors:
800800
@test QuantityArray(ones(3), u"m/s") == QuantityArray(ones(3), length=1, time=-1)
801-
@test typeof(QuantityArray(ones(3), u"m/s")) <: QuantityArray{Float64,1,<:Dimensions,<:Quantity,<:Array}
801+
@test typeof(QuantityArray(ones(3), u"m/s")) <: QuantityArray{Float64,1,<:Dimensions,<:constructorof(DEFAULT_QUANTITY_TYPE),<:Array}
802802

803803
# We can create quantity arrays with generic quantity
804804
@test typeof(QuantityArray([[1.0], [2.0, 3.0]], dimension(u"m/s"))) <: QuantityArray{<:Any,1,<:Dimensions,<:GenericQuantity,<:Array}
@@ -964,14 +964,14 @@ for Q in (Quantity, GenericQuantity)
964964
@test ustrip(x .* y) == ustrip(x) .* ustrip(y)
965965
end
966966

967-
Q == Quantity && @testset "Broadcast different arrays" begin
967+
Q in (Quantity, RealQuantity) && @testset "Broadcast different arrays" begin
968968
f(x, y, z, w) = x * y + z * w
969969
g(x, y, z, w) = f.(x, y, z, w)
970970

971971
x = randn(32)
972972
y = QuantityArray(randn(32), u"km/s")
973973
z = rand(1:10, 32)
974-
w = Quantity{Float32}(u"m/s")
974+
w = Q{Float32}(u"m/s")
975975
@test typeof(g(x, y, z, w)) <: QuantityArray{Float64}
976976

977977
y32 = QuantityArray(ustrip(y), dimension(y))
@@ -990,7 +990,7 @@ for Q in (Quantity, GenericQuantity)
990990
@test typeof(b .* y) <: QuantityArray{Float64}
991991
end
992992

993-
Q == Quantity && @testset "Broadcast scalars" begin
993+
Q in (RealQuantity, Quantity) && @testset "Broadcast scalars" begin
994994
for (x, qx) in ((0.5, 0.5u"s"), ([0.5, 0.2], GenericQuantity([0.5, 0.2], time=1)))
995995
@test size(qx) == size(x)
996996
@test length(qx) == length(x)
@@ -1128,8 +1128,8 @@ end
11281128
qy = QuantityArray(y; length=1)
11291129

11301130
@test typeof(convert(typeof(qx), qy)) == typeof(qx)
1131-
@test convert(typeof(qx), qy)[1] isa Quantity{Float64}
1132-
@test convert(typeof(qx), qy)[1] == convert(Quantity{Float64}, qy[1])
1131+
@test convert(typeof(qx), qy)[1] isa RealQuantity{Float64}
1132+
@test convert(typeof(qx), qy)[1] == convert(RealQuantity{Float64}, qy[1])
11331133
end
11341134
end
11351135

@@ -1152,21 +1152,21 @@ end
11521152
:log, :log2, :log10, :log1p, :exp, :exp2, :exp10, :expm1, :frexp, :exponent,
11531153
:atan, :atand
11541154
)
1155-
for Q in (Quantity, GenericQuantity), D in (Dimensions, SymbolicDimensions), f in functions
1155+
for Q in (RealQuantity, Quantity, GenericQuantity), D in (Dimensions, SymbolicDimensions), f in functions
11561156
# Only test on valid domain
11571157
valid_inputs = filter(
11581158
x -> is_input_valid(eval(f), x),
11591159
5rand(100) .- 2.5
11601160
)
11611161
for x in valid_inputs[1:3]
1162-
qx_dimensionless = Quantity(x, D)
1163-
qx_dimensions = Quantity(x, convert(D, dimension(u"m/s")))
1162+
qx_dimensionless = Q(x, D)
1163+
qx_dimensions = Q(x, convert(D, dimension(u"m/s")))
11641164
@eval @test $f($qx_dimensionless) == $f($x)
11651165
@eval @test_throws DimensionError $f($qx_dimensions)
11661166
if f in (:atan, :atand)
11671167
for y in valid_inputs[end-3:end]
1168-
qy_dimensionless = Quantity(y, D)
1169-
qy_dimensions = Quantity(y, convert(D, dimension(u"m/s")))
1168+
qy_dimensionless = Q(y, D)
1169+
qy_dimensions = Q(y, convert(D, dimension(u"m/s")))
11701170
@eval @test $f($y, $qx_dimensionless) == $f($y, $x)
11711171
@eval @test $f($qy_dimensionless, $x) == $f($y, $x)
11721172
@eval @test $f($qy_dimensionless, $qx_dimensionless) == $f($y, $x)
@@ -1189,8 +1189,9 @@ end
11891189
:floor, :trunc, :ceil, :significand,
11901190
:ldexp, :round,
11911191
)
1192-
for Q in (Quantity, GenericQuantity), D in (Dimensions, SymbolicDimensions), f in functions
1192+
for Q in (RealQuantity, Quantity, GenericQuantity), D in (Dimensions, SymbolicDimensions), f in functions
11931193
T = f in (:abs, :real, :imag, :conj) ? ComplexF64 : Float64
1194+
T <: Complex && Q == RealQuantity && continue
11941195
if f == :modf # Functions that return multiple outputs
11951196
for x in 5rand(T, 3) .- 2.5
11961197
dim = convert(D, dimension(u"m/s"))
@@ -1251,7 +1252,7 @@ end
12511252
end
12521253

12531254
@testset "Test div" begin
1254-
for Q in (Quantity, GenericQuantity)
1255+
for Q in (RealQuantity, Quantity, GenericQuantity)
12551256
x = Q{Int}(10, length=1)
12561257
y = Q{Int}(3, mass=-1)
12571258
@test div(x, y) == Q{Int}(3, length=1, mass=1)

0 commit comments

Comments
 (0)