Skip to content
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

Support dispatches on Number via union type #49

Merged
merged 66 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
a491992
Define `AbstractQuantity <: Number`
MilesCranmer Sep 19, 2023
69f3fd5
Remove defiitions for `Missing`
MilesCranmer Sep 19, 2023
a8f25f7
Create AbstractUnionQuantity for multiple abstract quantities
MilesCranmer Sep 24, 2023
1410e05
Create GenericQuantity
MilesCranmer Sep 24, 2023
cd1dd2e
Update array to allow generic quantities
MilesCranmer Sep 25, 2023
37cb7e6
Fix some method ambiguities
MilesCranmer Sep 25, 2023
b282ad1
Start separate file for ambiguities
MilesCranmer Sep 25, 2023
66113e2
Fix ambiguity in AbstractDimensions + Quantity
MilesCranmer Sep 25, 2023
670ab84
Fix ambiguity in powers
MilesCranmer Sep 25, 2023
3e920f9
Fix ambiguity in constructors
MilesCranmer Sep 25, 2023
7491a93
Fix ambiguity in getindex
MilesCranmer Sep 25, 2023
613b2f0
Move other methods to ambiguities
MilesCranmer Sep 25, 2023
b735283
Rename to `disambiguities`
MilesCranmer Sep 25, 2023
37289c8
Fix ambiguities in promotion rules
MilesCranmer Sep 25, 2023
d1414ea
Merge branch 'main' into union-type
gaurav-arya Oct 15, 2023
810ed86
Export generic quantity
gaurav-arya Oct 15, 2023
561ba11
Merge branch 'main' into union-type
MilesCranmer Oct 17, 2023
679057c
Add docstrings for generic quantities
MilesCranmer Oct 22, 2023
61b35bf
More types on missing
MilesCranmer Oct 22, 2023
042d3eb
Prevent invalid dimension conversions
MilesCranmer Oct 22, 2023
d24d3ac
Remove old missing test
MilesCranmer Oct 22, 2023
4e8b750
Fix string test for local version
MilesCranmer Oct 22, 2023
f38d630
Fix method hierarchy in constructors
MilesCranmer Oct 22, 2023
913228b
Add GenericQuantity tests
MilesCranmer Oct 22, 2023
d68b041
Revert "Remove old missing test"
MilesCranmer Oct 22, 2023
22d12d0
Fix rounding behavior
MilesCranmer Oct 22, 2023
ad2ed1c
Remove overkill promotion function
MilesCranmer Oct 22, 2023
cc519ea
Formatting
MilesCranmer Oct 22, 2023
72addf4
Add missing promotion utility between symbolic and regular
MilesCranmer Oct 22, 2023
6b1607c
Merge branch 'prevent-invalid-conversions' into union-type
MilesCranmer Oct 22, 2023
bca03f2
Make SymbolicDimensions conversion work for union type
MilesCranmer Oct 22, 2023
b6b3245
Test promotion with both symbolic/non and quantity/generic
MilesCranmer Oct 22, 2023
0567e47
Remove unused constructors
MilesCranmer Oct 22, 2023
1d85f85
Formatting
MilesCranmer Oct 22, 2023
9ac4df0
More generic quantity tests
MilesCranmer Oct 22, 2023
b20998b
Add promotion rule for generic numbers
MilesCranmer Oct 22, 2023
c49c648
Add explicit promote_type tests
MilesCranmer Oct 22, 2023
097cd31
Test conversion to `Vector{Any}`
MilesCranmer Oct 22, 2023
3a73997
Merge branch 'main' into union-type
MilesCranmer Oct 22, 2023
f437e6e
Add docs for union quantity
MilesCranmer Oct 23, 2023
bc5a9f4
Add docs on `GenericQuantity`
MilesCranmer Oct 23, 2023
21c9823
Clean up docs
MilesCranmer Oct 23, 2023
8267824
Refactor + and - definitions
MilesCranmer Oct 23, 2023
0c68bb9
More docs
MilesCranmer Oct 23, 2023
ddd4894
Add more examples
MilesCranmer Oct 23, 2023
452d18c
Add projectile motion example
MilesCranmer Oct 23, 2023
c495b83
Split out projectile motion example
MilesCranmer Oct 23, 2023
a65d8ba
Add custom dimensions example
MilesCranmer Oct 24, 2023
78b87ef
Fix documentation number
MilesCranmer Oct 24, 2023
aa60738
Expand unittest coverage
MilesCranmer Oct 24, 2023
9ebd6bc
Example of custom quantity
MilesCranmer Oct 24, 2023
5248189
Add example of `uconvert` on `GenericQuantity`
MilesCranmer Oct 24, 2023
f8b6e98
Improve cookie example
MilesCranmer Oct 24, 2023
3bb9452
Refactor internal utilities
MilesCranmer Oct 28, 2023
ce9d527
Add compatibility for generic quantities in measurements
MilesCranmer Oct 28, 2023
d02b466
Add GenericQuantity to array tests
MilesCranmer Oct 28, 2023
1f0b39d
More GenericQuantity tests
MilesCranmer Oct 28, 2023
3faa4ee
Ensure convert(Number, q) is tested
MilesCranmer Oct 28, 2023
e9e7b8c
Apply suggestions from code review
MilesCranmer Oct 28, 2023
697037a
Reformat tests
MilesCranmer Oct 28, 2023
108aada
Refactor QuantityArray for GenericQuantity
MilesCranmer Oct 29, 2023
46abb61
Fix documentation build
MilesCranmer Oct 29, 2023
68ff3c1
Clean up quantity array docs
MilesCranmer Oct 29, 2023
cc28197
Update name to UnionAbstractQuantity
MilesCranmer Oct 31, 2023
a401e86
Update fieldname check from code review
MilesCranmer Nov 1, 2023
2a1c7ad
Update internal_utils.jl
MilesCranmer Nov 1, 2023
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
4 changes: 2 additions & 2 deletions ext/DynamicQuantitiesLinearAlgebraExt.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module DynamicQuantitiesLinearAlgebraExt

import LinearAlgebra: norm
import DynamicQuantities: AbstractQuantity, ustrip, dimension, new_quantity
import DynamicQuantities: AbstractUnionQuantity, ustrip, dimension, new_quantity

norm(q::AbstractQuantity, p::Real=2) = new_quantity(typeof(q), norm(ustrip(q), p), dimension(q))
norm(q::AbstractUnionQuantity, p::Real=2) = new_quantity(typeof(q), norm(ustrip(q), p), dimension(q))

end
6 changes: 3 additions & 3 deletions ext/DynamicQuantitiesScientificTypesExt.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module DynamicQuantitiesScientificTypesExt

import DynamicQuantities: AbstractQuantity, ustrip
import DynamicQuantities: AbstractUnionQuantity, ustrip
import ScientificTypes as ST
import ScientificTypesBase as STB

STB.scitype(x::AbstractQuantity, C::ST.DefaultConvention) = STB.scitype(ustrip(x), C)
STB.Scitype(::Type{<:AbstractQuantity{T}}, C::ST.DefaultConvention) where {T} = STB.Scitype(T, C)
STB.scitype(x::AbstractUnionQuantity, C::ST.DefaultConvention) = STB.scitype(ustrip(x), C)
STB.Scitype(::Type{<:AbstractUnionQuantity{T}}, C::ST.DefaultConvention) where {T} = STB.Scitype(T, C)

end
1 change: 1 addition & 0 deletions src/DynamicQuantities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ include("units.jl")
include("constants.jl")
include("uparse.jl")
include("symbolic_dimensions.jl")
include("disambiguities.jl")

import PackageExtensionCompat: @require_extensions
import .Units
Expand Down
36 changes: 18 additions & 18 deletions src/arrays.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Compat: allequal

"""
QuantityArray{T,N,D<:AbstractDimensions,Q<:AbstractQuantity,V<:AbstractArray}
QuantityArray{T,N,D<:AbstractDimensions,Q<:AbstractUnionQuantity,V<:AbstractArray}

An array of quantities with value `value` of type `V` and dimensions `dimensions` of type `D`
(which are shared across all elements of the array). This is a subtype of `AbstractArray{Q,N}`,
Expand All @@ -15,22 +15,22 @@ and so can be used in most places where a normal array would be used, including
# Constructors

- `QuantityArray(value::AbstractArray, dimensions::AbstractDimensions)`: Create a `QuantityArray` with value `value` and dimensions `dimensions`.
- `QuantityArray(value::AbstractArray, quantity::Quantity)`: Create a `QuantityArray` with value `value` and dimensions inferred
- `QuantityArray(value::AbstractArray, quantity::AbstractUnionQuantity)`: Create a `QuantityArray` with value `value` and dimensions inferred
with `dimension(quantity)`. This is so that you can easily create an array with the units module, like so:
```julia
julia> A = QuantityArray(randn(32), 1u"m")
```
- `QuantityArray(v::AbstractArray{<:AbstractQuantity})`: Create a `QuantityArray` from an array of quantities. This means the following
- `QuantityArray(v::AbstractArray{<:AbstractUnionQuantity})`: Create a `QuantityArray` from an array of quantities. This means the following
syntax works:
```julia
julia> A = QuantityArray(randn(32) .* 1u"km/s")
```
"""
struct QuantityArray{T,N,D<:AbstractDimensions,Q<:AbstractQuantity{T,D},V<:AbstractArray{T,N}} <: AbstractArray{Q,N}
struct QuantityArray{T,N,D<:AbstractDimensions,Q<:AbstractUnionQuantity{T,D},V<:AbstractArray{T,N}} <: AbstractArray{Q,N}
value::V
dimensions::D

function QuantityArray(v::_V, d::_D, ::Type{_Q}) where {_T,_N,_D<:AbstractDimensions,_Q<:AbstractQuantity,_V<:AbstractArray{_T,_N}}
function QuantityArray(v::_V, d::_D, ::Type{_Q}) where {_T,_N,_D<:AbstractDimensions,_Q<:AbstractUnionQuantity,_V<:AbstractArray{_T,_N}}
Q_out = constructor_of(_Q){_T,_D}
return new{_T,_N,_D,Q_out,_V}(v, d)
end
Expand All @@ -39,8 +39,8 @@ end
# Construct with a Quantity (easier, as you can use the units):
QuantityArray(v::AbstractArray; kws...) = QuantityArray(v, DEFAULT_DIM_TYPE(; kws...))
QuantityArray(v::AbstractArray, d::AbstractDimensions) = QuantityArray(v, d, Quantity)
QuantityArray(v::AbstractArray, q::AbstractQuantity) = QuantityArray(v .* ustrip(q), dimension(q), typeof(q))
QuantityArray(v::QA) where {Q<:AbstractQuantity,QA<:AbstractArray{Q}} =
QuantityArray(v::AbstractArray, q::AbstractUnionQuantity) = QuantityArray(v .* ustrip(q), dimension(q), typeof(q))
QuantityArray(v::QA) where {Q<:AbstractUnionQuantity,QA<:AbstractArray{Q}} =
let
allequal(dimension.(v)) || throw(DimensionError(first(v), v))
QuantityArray(ustrip.(v), dimension(first(v)), Q)
Expand All @@ -58,7 +58,7 @@ function Base.promote_rule(::Type{QA1}, ::Type{QA2}) where {QA1<:QuantityArray,Q
"Cannot promote quantity arrays with different dimensions."
)
@assert(
Q <: AbstractQuantity{T,D} && V <: AbstractArray{T},
Q <: AbstractUnionQuantity{T,D} && V <: AbstractArray{T},
"Incompatible promotion rules between\n $(QA1)\nand\n $(QA2)\nPlease convert to a common quantity type first."
)

Expand Down Expand Up @@ -92,9 +92,9 @@ quantity_type(A::QuantityArray) = quantity_type(typeof(A))
dim_type(::Type{<:QuantityArray{T,N,D}}) where {T,N,D} = D
dim_type(A::QuantityArray) = dim_type(typeof(A))

value_type(::Type{<:AbstractQuantity{T}}) where {T} = T
value_type(::Type{<:AbstractUnionQuantity{T}}) where {T} = T
value_type(::Type{<:QuantityArray{T}}) where {T} = T
value_type(A::Union{<:QuantityArray,<:AbstractQuantity}) = value_type(typeof(A))
value_type(A::Union{<:QuantityArray,<:AbstractUnionQuantity}) = value_type(typeof(A))

# One field:
for f in (:size, :length, :axes)
Expand All @@ -109,11 +109,11 @@ function Base.getindex(A::QuantityArray, i...)
return new_quantity(quantity_type(A), output_value, dimension(A))
end
end
function Base.setindex!(A::QuantityArray{T,N,D,Q}, v::Q, i...) where {T,N,D,Q<:AbstractQuantity}
function Base.setindex!(A::QuantityArray{T,N,D,Q}, v::Q, i...) where {T,N,D,Q<:AbstractUnionQuantity}
dimension(A) == dimension(v) || throw(DimensionError(A, v))
return unsafe_setindex!(A, v, i...)
end
function Base.setindex!(A::QuantityArray{T,N,D,Q}, v::AbstractQuantity, i...) where {T,N,D,Q<:AbstractQuantity}
function Base.setindex!(A::QuantityArray{T,N,D,Q}, v::AbstractUnionQuantity, i...) where {T,N,D,Q<:AbstractUnionQuantity}
return setindex!(A, convert(Q, v), i...)
end

Expand All @@ -134,7 +134,7 @@ end

Base.BroadcastStyle(::Type{QA}) where {QA<:QuantityArray} = Broadcast.ArrayStyle{QA}()

function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{QA}}, ::Type{ElType}) where {QA<:QuantityArray,ElType<:AbstractQuantity}
function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{QA}}, ::Type{ElType}) where {QA<:QuantityArray,ElType<:AbstractUnionQuantity}
T = value_type(ElType)
output_array = similar(bc, T)
first_output::ElType = materialize_first(bc)
Expand All @@ -156,10 +156,10 @@ end
materialize_first(bc::Base.Broadcast.Broadcasted) = bc.f(materialize_first.(bc.args)...)

# Base cases
materialize_first(q::AbstractQuantity{<:AbstractArray}) = new_quantity(typeof(q), first(ustrip(q)), dimension(q))
materialize_first(q::AbstractQuantity) = q
materialize_first(q::AbstractGenericQuantity{<:AbstractArray}) = new_quantity(typeof(q), first(ustrip(q)), dimension(q))
MilesCranmer marked this conversation as resolved.
Show resolved Hide resolved
materialize_first(q::AbstractUnionQuantity) = q
materialize_first(q::QuantityArray) = first(q)
materialize_first(q::AbstractArray{Q}) where {Q<:AbstractQuantity} = first(q)
materialize_first(q::AbstractArray{Q}) where {Q<:AbstractUnionQuantity} = first(q)

# Derived calls
materialize_first(r::Base.RefValue) = materialize_first(r.x)
Expand Down Expand Up @@ -202,8 +202,8 @@ for f in (:cat, :hcat, :vcat)
end
end
end
Base.fill(x::AbstractQuantity, dims::Dims...) = QuantityArray(fill(ustrip(x), dims...), dimension(x), typeof(x))
Base.fill(x::AbstractQuantity, t::Tuple{}) = QuantityArray(fill(ustrip(x), t), dimension(x), typeof(x))
Base.fill(x::AbstractUnionQuantity, dims::Dims...) = QuantityArray(fill(ustrip(x), dims...), dimension(x), typeof(x))
Base.fill(x::AbstractUnionQuantity, t::Tuple{}) = QuantityArray(fill(ustrip(x), t), dimension(x), typeof(x))

ulength(q::QuantityArray) = ulength(dimension(q))
umass(q::QuantityArray) = umass(dimension(q))
Expand Down
14 changes: 14 additions & 0 deletions src/disambiguities.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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")

Base.:*(l::AbstractDimensions, r::Number) = error("Please use an `AbstractUnionQuantity` for multiplication. You used multiplication on types: $(typeof(l)) and $(typeof(r)).")
Base.:*(l::Number, r::AbstractDimensions) = error("Please use an `AbstractUnionQuantity` for multiplication. You used multiplication on types: $(typeof(l)) and $(typeof(r)).")
Base.:/(l::AbstractDimensions, r::Number) = error("Please use an `AbstractUnionQuantity` for division. You used division on types: $(typeof(l)) and $(typeof(r)).")
Base.:/(l::Number, r::AbstractDimensions) = error("Please use an `AbstractUnionQuantity` for division. You used division on types: $(typeof(l)) and $(typeof(r)).")
112 changes: 69 additions & 43 deletions src/math.jl
Original file line number Diff line number Diff line change
@@ -1,41 +1,60 @@
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)).")
for (type, base_type) in ABSTRACT_QUANTITY_TYPES
@eval begin
Base.:*(l::$type, r::$type) = new_quantity(typeof(l), ustrip(l) * ustrip(r), dimension(l) * dimension(r))
Base.:/(l::$type, r::$type) = new_quantity(typeof(l), ustrip(l) / ustrip(r), dimension(l) / dimension(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::AbstractQuantity) =
let
dimension(l) == dimension(r) || throw(DimensionError(l, r))
new_quantity(typeof(l), ustrip(l) + ustrip(r), dimension(l))
end
Base.:-(l::AbstractQuantity) = new_quantity(typeof(l), -ustrip(l), dimension(l))
Base.:-(l::AbstractQuantity, r::AbstractQuantity) = l + (-r)
Base.:*(l::$type, r::$base_type) = new_quantity(typeof(l), ustrip(l) * r, dimension(l))
Base.:/(l::$type, r::$base_type) = new_quantity(typeof(l), ustrip(l) / r, dimension(l))

Base.:*(l::$base_type, r::$type) = new_quantity(typeof(r), l * ustrip(r), dimension(r))
Base.:/(l::$base_type, r::$type) = new_quantity(typeof(r), l / ustrip(r), inv(dimension(r)))

Base.:*(l::$type, r::AbstractDimensions) = new_quantity(typeof(l), ustrip(l), dimension(l) * r)
Base.:/(l::$type, r::AbstractDimensions) = new_quantity(typeof(l), ustrip(l), dimension(l) / r)
gaurav-arya marked this conversation as resolved.
Show resolved Hide resolved

Base.:+(l::AbstractQuantity, r) =
let
iszero(dimension(l)) || throw(DimensionError(l, r))
new_quantity(typeof(l), ustrip(l) + r, dimension(l))
Base.:*(l::AbstractDimensions, r::$type) = new_quantity(typeof(r), ustrip(r), l * dimension(r))
Base.:/(l::AbstractDimensions, r::$type) = new_quantity(typeof(r), inv(ustrip(r)), l / dimension(r))
end
Base.:+(l, r::AbstractQuantity) =
let
iszero(dimension(r)) || throw(DimensionError(l, r))
new_quantity(typeof(r), l + ustrip(r), dimension(r))
end

Base.:*(l::AbstractDimensions, r::AbstractDimensions) = map_dimensions(+, l, r)
Base.:/(l::AbstractDimensions, r::AbstractDimensions) = map_dimensions(-, l, r)

for (type, base_type) in ABSTRACT_QUANTITY_TYPES
@eval begin
Base.:+(l::$type, r::$type) =
let
dimension(l) == dimension(r) || throw(DimensionError(l, r))
new_quantity(typeof(l), ustrip(l) + ustrip(r), dimension(l))
end
Base.:+(l::$type, r::$base_type) =
let
iszero(dimension(l)) || throw(DimensionError(l, r))
new_quantity(typeof(l), ustrip(l) + r, dimension(l))
end
Base.:+(l::$base_type, r::$type) =
let
iszero(dimension(r)) || throw(DimensionError(l, r))
new_quantity(typeof(r), l + ustrip(r), dimension(r))
end

Base.:-(l::$type, r::$type) = l + (-r)
Base.:-(l::$type, r::$base_type) = l + (-r)
MilesCranmer marked this conversation as resolved.
Show resolved Hide resolved
Base.:-(l::$base_type, r::$type) = l + (-r)
end
Base.:-(l::AbstractQuantity, r) = l + (-r)
Base.:-(l, r::AbstractQuantity) = l + (-r)
end

Base.:-(l::AbstractUnionQuantity) = new_quantity(typeof(l), -ustrip(l), dimension(l))

# Combining different abstract types
for op in (:*, :/, :+, :-),
(t1, _) in ABSTRACT_QUANTITY_TYPES,
(t2, _) in ABSTRACT_QUANTITY_TYPES

t1 == t2 && continue

@eval Base.$op(l::$t1, r::$t2) = $op(promote(l, r)...)
end

# We don't promote on the dimension types:
function Base.:^(l::AbstractDimensions{R}, r::Integer) where {R}
Expand All @@ -57,26 +76,33 @@ for (p, ex) in [
@eval @inline Base.literal_pow(::typeof(^), l::AbstractDimensions, ::Val{$p}) = $ex
end

function Base.:^(l::AbstractQuantity{T,D}, r::Integer) where {T,R,D<:AbstractDimensions{R}}
function _pow_int(l::AbstractUnionQuantity{T,D}, r) where {T,R,D<:AbstractDimensions{R}}
return new_quantity(typeof(l), ustrip(l)^r, dimension(l)^r)
end
function Base.:^(l::AbstractQuantity{T,D}, r::Number) where {T,R,D<:AbstractDimensions{R}}
function _pow(l::AbstractUnionQuantity{T,D}, r) where {T,R,D<:AbstractDimensions{R}}
dim_pow = tryrationalize(R, r)
val_pow = convert(T, dim_pow)
# Need to ensure we take the numerical power by the rationalized quantity:
return new_quantity(typeof(l), ustrip(l)^val_pow, dimension(l)^dim_pow)
end
for (type, _) in ABSTRACT_QUANTITY_TYPES
@eval begin
Base.:^(l::$type, r::Integer) = _pow_int(l, r)
Base.:^(l::$type, r::Number) = _pow(l, r)
Base.:^(l::$type, r::Rational) = _pow(l, r)
end
end
@inline Base.literal_pow(::typeof(^), l::AbstractDimensions, ::Val{p}) where {p} = map_dimensions(Base.Fix1(*, p), l)
@inline Base.literal_pow(::typeof(^), l::AbstractQuantity, ::Val{p}) where {p} = new_quantity(typeof(l), Base.literal_pow(^, ustrip(l), Val(p)), Base.literal_pow(^, dimension(l), Val(p)))
@inline Base.literal_pow(::typeof(^), l::AbstractUnionQuantity, ::Val{p}) where {p} = new_quantity(typeof(l), Base.literal_pow(^, ustrip(l), Val(p)), Base.literal_pow(^, dimension(l), Val(p)))

Base.inv(d::AbstractDimensions) = map_dimensions(-, d)
Base.inv(q::AbstractQuantity) = new_quantity(typeof(q), inv(ustrip(q)), inv(dimension(q)))
Base.inv(q::AbstractUnionQuantity) = new_quantity(typeof(q), inv(ustrip(q)), inv(dimension(q)))

Base.sqrt(d::AbstractDimensions{R}) where {R} = d^inv(convert(R, 2))
Base.sqrt(q::AbstractQuantity) = new_quantity(typeof(q), sqrt(ustrip(q)), sqrt(dimension(q)))
Base.sqrt(q::AbstractUnionQuantity) = new_quantity(typeof(q), sqrt(ustrip(q)), sqrt(dimension(q)))
Base.cbrt(d::AbstractDimensions{R}) where {R} = d^inv(convert(R, 3))
Base.cbrt(q::AbstractQuantity) = new_quantity(typeof(q), cbrt(ustrip(q)), cbrt(dimension(q)))
Base.cbrt(q::AbstractUnionQuantity) = new_quantity(typeof(q), cbrt(ustrip(q)), cbrt(dimension(q)))

Base.abs(q::AbstractQuantity) = new_quantity(typeof(q), abs(ustrip(q)), dimension(q))
Base.abs2(q::AbstractQuantity) = new_quantity(typeof(q), abs2(ustrip(q)), dimension(q)^2)
Base.angle(q::AbstractQuantity{T}) where {T<:Complex} = angle(ustrip(q))
Base.abs(q::AbstractUnionQuantity) = new_quantity(typeof(q), abs(ustrip(q)), dimension(q))
Base.abs2(q::AbstractUnionQuantity) = new_quantity(typeof(q), abs2(ustrip(q)), dimension(q)^2)
Base.angle(q::AbstractUnionQuantity{T}) where {T<:Complex} = angle(ustrip(q))
Loading
Loading