Skip to content

Change behavior of one to match Unitful #42

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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ julia = "1.6"
[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
Ratios = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
SaferIntegers = "88634af6-177f-5301-88b8-7819386cfa38"
Expand All @@ -43,4 +44,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[targets]
test = ["Test", "Aqua", "LinearAlgebra", "Ratios", "SaferIntegers", "SafeTestsets", "ScientificTypes", "ScientificTypesBase", "StaticArrays", "Unitful"]
test = ["Test", "Aqua", "LinearAlgebra", "QuadGK", "Ratios", "SaferIntegers", "SafeTestsets", "ScientificTypes", "ScientificTypesBase", "StaticArrays", "Unitful"]
24 changes: 12 additions & 12 deletions src/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ Base.:*(l::AbstractDimensions, r::AbstractDimensions) = map_dimensions(+, l, r)
Base.:*(l::AbstractQuantity, r::AbstractQuantity) = new_quantity(typeof(l), ustrip(l) * ustrip(r), dimension(l) * dimension(r))
Base.:*(l::AbstractQuantity, r::AbstractDimensions) = new_quantity(typeof(l), ustrip(l), dimension(l) * r)
Base.:*(l::AbstractDimensions, r::AbstractQuantity) = new_quantity(typeof(r), ustrip(r), l * dimension(r))
Base.:*(l::AbstractQuantity, r) = new_quantity(typeof(l), ustrip(l) * r, dimension(l))
Base.:*(l, r::AbstractQuantity) = new_quantity(typeof(r), l * ustrip(r), dimension(r))
Base.:*(l::AbstractDimensions, r) = error("Please use an `AbstractQuantity` for multiplication. You used multiplication on types: $(typeof(l)) and $(typeof(r)).")
Base.:*(l, r::AbstractDimensions) = error("Please use an `AbstractQuantity` for multiplication. You used multiplication on types: $(typeof(l)) and $(typeof(r)).")
Base.:*(l::AbstractQuantity, r::Number) = new_quantity(typeof(l), ustrip(l) * r, dimension(l))
Base.:*(l::Number, r::AbstractQuantity) = new_quantity(typeof(r), l * ustrip(r), dimension(r))
Base.:*(l::AbstractDimensions, r::Number) = error("Please use an `AbstractQuantity` for multiplication. You used multiplication on types: $(typeof(l)) and $(typeof(r)).")
Base.:*(l::Number, r::AbstractDimensions) = error("Please use an `AbstractQuantity` for multiplication. You used multiplication on types: $(typeof(l)) and $(typeof(r)).")

Base.:/(l::AbstractDimensions, r::AbstractDimensions) = map_dimensions(-, l, r)
Base.:/(l::AbstractQuantity, r::AbstractQuantity) = new_quantity(typeof(l), ustrip(l) / ustrip(r), dimension(l) / dimension(r))
Base.:/(l::AbstractQuantity, r::AbstractDimensions) = new_quantity(typeof(l), ustrip(l), dimension(l) / r)
Base.:/(l::AbstractDimensions, r::AbstractQuantity) = new_quantity(typeof(r), inv(ustrip(r)), l / dimension(r))
Base.:/(l::AbstractQuantity, r) = new_quantity(typeof(l), ustrip(l) / r, dimension(l))
Base.:/(l, r::AbstractQuantity) = l * inv(r)
Base.:/(l::AbstractDimensions, r) = error("Please use an `AbstractQuantity` for division. You used division on types: $(typeof(l)) and $(typeof(r)).")
Base.:/(l, r::AbstractDimensions) = error("Please use an `AbstractQuantity` for division. You used division on types: $(typeof(l)) and $(typeof(r)).")
Base.:/(l::AbstractQuantity, r::Number) = new_quantity(typeof(l), ustrip(l) / r, dimension(l))
Base.:/(l::Number, r::AbstractQuantity) = l * inv(r)
Base.:/(l::AbstractDimensions, r::Number) = error("Please use an `AbstractQuantity` for division. You used division on types: $(typeof(l)) and $(typeof(r)).")
Base.:/(l::Number, r::AbstractDimensions) = error("Please use an `AbstractQuantity` for division. You used division on types: $(typeof(l)) and $(typeof(r)).")

Base.:+(l::AbstractQuantity, r::AbstractQuantity) =
let
Expand All @@ -24,18 +24,18 @@ Base.:+(l::AbstractQuantity, r::AbstractQuantity) =
Base.:-(l::AbstractQuantity) = new_quantity(typeof(l), -ustrip(l), dimension(l))
Base.:-(l::AbstractQuantity, r::AbstractQuantity) = l + (-r)

Base.:+(l::AbstractQuantity, r) =
Base.:+(l::AbstractQuantity, r::Number) =
let
iszero(dimension(l)) || throw(DimensionError(l, r))
new_quantity(typeof(l), ustrip(l) + r, dimension(l))
end
Base.:+(l, r::AbstractQuantity) =
Base.:+(l::Number, r::AbstractQuantity) =
let
iszero(dimension(r)) || throw(DimensionError(l, r))
new_quantity(typeof(r), l + ustrip(r), dimension(r))
end
Base.:-(l::AbstractQuantity, r) = l + (-r)
Base.:-(l, r::AbstractQuantity) = l + (-r)
Base.:-(l::AbstractQuantity, r::Number) = l + (-r)
Base.:-(l::Number, r::AbstractQuantity) = l + (-r)

# We don't promote on the dimension types:
function Base.:^(l::AbstractDimensions{R}, r::Integer) where {R}
Expand Down
4 changes: 2 additions & 2 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ to a base unit (e.g., `length` by default maps to `m`). You may also need to ove
abstract type AbstractDimensions{R} end

"""
AbstractQuantity{T,D}
AbstractQuantity{T,D} <: Number

An abstract type for quantities. `T` is the type of the value of the quantity,
and `D` is the type of the dimensions of the quantity. By default, `D` is set to
Expand All @@ -33,7 +33,7 @@ object is stored in the `:dimensions` field. These fields can be accessed with
`ustrip` and `dimension`, respectively. Many operators in `Base` are defined on
`AbstractQuantity` objects, including `+, -, *, /, ^, sqrt, cbrt, abs`.
"""
abstract type AbstractQuantity{T,D} end
abstract type AbstractQuantity{T,D} <: Number end

"""
Dimensions{R<:Real} <: AbstractDimensions{R}
Expand Down
35 changes: 11 additions & 24 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ end
end

Base.float(q::AbstractQuantity) = new_quantity(typeof(q), float(ustrip(q)), dimension(q))
Base.convert(::Type{T}, q::AbstractQuantity) where {T<:Real} =
Base.convert(::Type{T}, q::AbstractQuantity) where {T<:Number} =
let
@assert iszero(dimension(q)) "$(typeof(q)): $(q) has dimensions! Use `ustrip` instead."
return convert(T, ustrip(q))
Expand Down Expand Up @@ -58,43 +58,32 @@ Base.keys(q::AbstractQuantity) = keys(ustrip(q))
function Base.isapprox(l::AbstractQuantity, r::AbstractQuantity; kws...)
return isapprox(ustrip(l), ustrip(r); kws...) && dimension(l) == dimension(r)
end
function Base.isapprox(l, r::AbstractQuantity; kws...)
function Base.isapprox(l::Number, r::AbstractQuantity; kws...)
iszero(dimension(r)) || throw(DimensionError(l, r))
return isapprox(l, ustrip(r); kws...)
end
function Base.isapprox(l::AbstractQuantity, r; kws...)
function Base.isapprox(l::AbstractQuantity, r::Number; kws...)
iszero(dimension(l)) || throw(DimensionError(l, r))
return isapprox(ustrip(l), r; kws...)
end
Base.iszero(d::AbstractDimensions) = all_dimensions(iszero, d)
Base.:(==)(l::AbstractDimensions, r::AbstractDimensions) = all_dimensions(==, l, r)
Base.:(==)(l::AbstractQuantity, r::AbstractQuantity) = ustrip(l) == ustrip(r) && dimension(l) == dimension(r)
Base.:(==)(l, r::AbstractQuantity) = ustrip(l) == ustrip(r) && iszero(dimension(r))
Base.:(==)(l::AbstractQuantity, r) = ustrip(l) == ustrip(r) && iszero(dimension(l))
Base.:(==)(l::Number, r::AbstractQuantity) = ustrip(l) == ustrip(r) && iszero(dimension(r))
Base.:(==)(l::AbstractQuantity, r::Number) = ustrip(l) == ustrip(r) && iszero(dimension(l))
function Base.isless(l::AbstractQuantity, r::AbstractQuantity)
dimension(l) == dimension(r) || throw(DimensionError(l, r))
return isless(ustrip(l), ustrip(r))
end
function Base.isless(l::AbstractQuantity, r)
function Base.isless(l::AbstractQuantity, r::Number)
iszero(dimension(l)) || throw(DimensionError(l, r))
return isless(ustrip(l), r)
end
function Base.isless(l, r::AbstractQuantity)
function Base.isless(l::Number, r::AbstractQuantity)
iszero(dimension(r)) || throw(DimensionError(l, r))
return isless(l, ustrip(r))
end

# Get rid of method ambiguities:
Base.isless(::AbstractQuantity, ::Missing) = missing
Base.isless(::Missing, ::AbstractQuantity) = missing
Base.:(==)(::AbstractQuantity, ::Missing) = missing
Base.:(==)(::Missing, ::AbstractQuantity) = missing
Base.isapprox(::AbstractQuantity, ::Missing; kws...) = missing
Base.isapprox(::Missing, ::AbstractQuantity; kws...) = missing

Base.:(==)(::AbstractQuantity, ::WeakRef) = error("Cannot compare a quantity to a weakref")
Base.:(==)(::WeakRef, ::AbstractQuantity) = error("Cannot compare a weakref to a quantity")


# Simple flags:
for f in (:iszero, :isfinite, :isinf, :isnan, :isreal)
Expand All @@ -107,19 +96,17 @@ for f in (:real, :imag, :conj, :adjoint, :unsigned, :nextfloat, :prevfloat)
end

# Base.one, typemin, typemax
for f in (:one, :typemin, :typemax)
for f in (:typemin, :typemax)
@eval begin
Base.$f(::Type{Q}) where {T,D,Q<:AbstractQuantity{T,D}} = new_quantity(Q, $f(T), D)
Base.$f(::Type{Q}) where {T,Q<:AbstractQuantity{T}} = $f(constructor_of(Q){T, DEFAULT_DIM_TYPE})
Base.$f(::Type{Q}) where {Q<:AbstractQuantity} = $f(Q{DEFAULT_VALUE_TYPE, DEFAULT_DIM_TYPE})
end
if f == :one # Return empty dimensions, as should be multiplicative identity.
@eval Base.$f(q::Q) where {Q<:AbstractQuantity} = new_quantity(Q, $f(ustrip(q)), one(dimension(q)))
else
@eval Base.$f(q::Q) where {Q<:AbstractQuantity} = new_quantity(Q, $f(ustrip(q)), dimension(q))
Base.$f(q::Q) where {Q<:AbstractQuantity} = new_quantity(Q, $f(ustrip(q)), dimension(q))
end
end
Base.one(::Type{Q}) where {T,Q<:AbstractQuantity{T}} = one(T)
Base.one(::Type{D}) where {D<:AbstractDimensions} = D()
Base.one(q::Q) where {Q<:AbstractQuantity} = one(ustrip(q))
Base.one(::D) where {D<:AbstractDimensions} = one(D)

# Additive identities (zero)
Expand Down
23 changes: 2 additions & 21 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
using SafeTestsets
import Ratios: SimpleRatio

@static if !hasmethod(round, Tuple{Int, SimpleRatio{Int}})
@eval Base.round(T, x::SimpleRatio) = round(T, x.num // x.den)
end

if parse(Bool, get(ENV, "DQ_TEST_UPREFERRED", "false"))
@safetestset "Test upreferred disallowed" begin
include("test_ban_upreferred.jl")
end
else
@safetestset "Unitful.jl integration tests" begin
include("test_unitful.jl")
end
@safetestset "ScientificTypes.jl integration tests" begin
include("test_scitypes.jl")
end
@safetestset "Unit tests" begin
include("unittests.jl")
end
@safetestset "Aqua tests" begin
include("test_aqua.jl")
end
@safetestset "QuadGK integration tests" begin
include("test_quadgk.jl")
end
7 changes: 7 additions & 0 deletions test/test_quadgk.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using DynamicQuantities
using Test
using QuadGK

integral = quadgk(t -> 5u"m/s^2" * t, 0u"s", 10u"s")

@test integral == (5u"m/s^2" * (10u"s")^2 / 2, 0.0u"m")