-
Notifications
You must be signed in to change notification settings - Fork 154
Added furlongs test #758
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
base: master
Are you sure you want to change the base?
Added furlongs test #758
Changes from all commits
f8f5178
361000d
712742e
c7b35e7
3e3894b
af8176e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ using Random | |
| using ForwardDiff | ||
| using DiffTests | ||
|
|
||
| include(joinpath(dirname(@__FILE__), "Furlongs.jl")) | ||
| include(joinpath(dirname(@__FILE__), "utils.jl")) | ||
|
|
||
| Random.seed!(1) | ||
|
|
@@ -133,4 +134,12 @@ end | |
| end | ||
| end | ||
|
|
||
| @testset "non-standard numbers" begin | ||
| furlong = Furlongs.Furlong{2}(1.0) | ||
|
|
||
| f(x) = exp(x) + 4*sin(x)*oneunit(x) | ||
|
|
||
| @test ForwardDiff.derivative(f, furlong) == exp(furlong) + 4*cos(furlong) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would any of |
||
| end | ||
|
|
||
| end # module | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| module Furlongs # Provides a non-standard number type, Furlong, for testing purposes. Adapted from https://github.com/JuliaLang/julia/blob/v1.11.6/test/testhelpers/Furlongs.jl | ||
|
|
||
| export Furlong | ||
|
|
||
| const TNumber = Real # ForwardDiff only supports Real numbers | ||
|
|
||
| # Here we implement a minimal dimensionful type Furlong, which is used | ||
| # to test dimensional correctness of various functions in Base. | ||
|
|
||
| # represents a quantity in furlongs^p | ||
| struct Furlong{p,T<:TNumber} <: TNumber | ||
| val::T | ||
| Furlong{p,T}(v::TNumber) where {p,T} = new(v) | ||
| end | ||
| Furlong(x::T) where {T<:TNumber} = Furlong{1,T}(x) | ||
| Furlong(x::Furlong) = x | ||
| (::Type{T})(x::Furlong{0}) where {T<:TNumber} = T(x.val)::T | ||
| (::Type{T})(x::Furlong{0}) where {T<:Furlong{0}} = T(x.val)::T | ||
| (::Type{T})(x::Furlong{0}) where {T<:Furlong} = typeassert(x, T) | ||
| Furlong{p}(v::TNumber) where {p} = Furlong{p,typeof(v)}(v) | ||
| Furlong{p}(x::Furlong{q}) where {p,q} = (typeassert(x, Furlong{p}); Furlong{p,typeof(x.val)}(x.val)) | ||
| Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (typeassert(x, Furlong{p}); Furlong{p,T}(T(x.val))) | ||
|
|
||
| Base.promote_rule(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} = | ||
| Furlong{p,promote_type(T,S)} | ||
| Base.promote_rule(::Type{Furlong{0,T}}, ::Type{S}) where {T,S<:Union{Real,Complex}} = | ||
| Furlong{0,promote_type(T,S)} | ||
| # only Furlong{0} forms a ring and isa TNumber | ||
| Base.convert(::Type{T}, y::TNumber) where {T<:Furlong{0}} = T(y)::T | ||
| Base.convert(::Type{Furlong}, y::TNumber) = Furlong{0}(y) | ||
| Base.convert(::Type{Furlong{<:Any,T}}, y::TNumber) where {T<:TNumber} = Furlong{0,T}(y) | ||
| Base.convert(::Type{T}, y::TNumber) where {T<:Furlong} = typeassert(y, T) # throws, since cannot convert a Furlong{0} to a Furlong{p} | ||
| # other Furlong{p} form a group | ||
| Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)::T | ||
| Base.convert(::Type{Furlong}, y::Furlong) = y | ||
| Base.convert(::Type{Furlong{<:Any,T}}, y::Furlong{p}) where {p,T<:TNumber} = Furlong{p,T}(y) | ||
| Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)::T | ||
|
|
||
| Base.one(::Furlong{p,T}) where {p,T} = one(T) | ||
| Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T) | ||
| Base.oneunit(::Furlong{p,T}) where {p,T} = Furlong{p,T}(one(T)) | ||
| Base.oneunit(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(one(T)) | ||
| Base.zero(::Furlong{p,T}) where {p,T} = Furlong{p,T}(zero(T)) | ||
| Base.zero(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(zero(T)) | ||
| Base.iszero(x::Furlong) = iszero(x.val) | ||
| Base.float(x::Furlong{p}) where {p} = Furlong{p}(float(x.val)) | ||
| Base.eps(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(eps(T)) | ||
| Base.eps(::Furlong{p,T}) where {p,T<:AbstractFloat} = eps(Furlong{p,T}) | ||
| Base.floatmin(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmin(T)) | ||
| Base.floatmin(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmin(Furlong{p,T}) | ||
| Base.floatmax(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmax(T)) | ||
| Base.floatmax(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmax(Furlong{p,T}) | ||
| Base.conj(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(conj(x.val)) | ||
|
|
||
| # convert Furlong exponent p to a canonical form | ||
| canonical_p(p) = isinteger(p) ? Int(p) : Rational{Int}(p) | ||
|
|
||
| Base.abs(x::Furlong{p}) where {p} = Furlong{p}(abs(x.val)) | ||
| Base.abs2(x::Furlong{p}) where {p} = Furlong{canonical_p(2p)}(abs2(x.val)) | ||
| Base.inv(x::Furlong{p}) where {p} = Furlong{canonical_p(-p)}(inv(x.val)) | ||
|
|
||
| for f in (:isfinite, :isnan, :isreal, :isinf) | ||
| @eval Base.$f(x::Furlong) = $f(x.val) | ||
| end | ||
| for f in (:real,:imag,:complex,:+,:-) | ||
| @eval Base.$f(x::Furlong{p}) where {p} = Furlong{p}($f(x.val)) | ||
| end | ||
|
|
||
| import Base: +, -, ==, !=, <, <=, isless, isequal, *, /, //, div, rem, mod, ^ | ||
| for op in (:+, :-) | ||
| @eval function $op(x::Furlong{p}, y::Furlong{p}) where {p} | ||
| v = $op(x.val, y.val) | ||
| Furlong{p}(v) | ||
| end | ||
| end | ||
| for op in (:(==), :(!=), :<, :<=, :isless, :isequal) | ||
| @eval $op(x::Furlong{p}, y::Furlong{p}) where {p} = $op(x.val, y.val)::Bool | ||
| end | ||
| for (f,op) in ((:_plus,:+),(:_minus,:-),(:_times,:*),(:_div,://)) | ||
| @eval function $f(v::T, ::Furlong{p}, ::Union{Furlong{q},Val{q}}) where {T,p,q} | ||
| s = $op(p, q) | ||
| Furlong{canonical_p(s),T}(v) | ||
| end | ||
| end | ||
| for (op,eop) in ((:*, :_plus), (:/, :_minus), (://, :_minus), (:div, :_minus)) | ||
| @eval begin | ||
| $op(x::Furlong{p}, y::Furlong{q}) where {p,q} = | ||
| $eop($op(x.val, y.val),x,y) | ||
| $op(x::Furlong{p}, y::S) where {p,S<:TNumber} = $op(x,Furlong{0,S}(y)) | ||
| $op(x::S, y::Furlong{p}) where {p,S<:TNumber} = $op(Furlong{0,S}(x),y) | ||
| end | ||
| end | ||
| # to fix an ambiguity | ||
| //(x::Furlong, y::Complex) = x // Furlong{0,typeof(y)}(y) | ||
| for op in (:rem, :mod) | ||
| @eval begin | ||
| $op(x::Furlong{p}, y::Furlong) where {p} = Furlong{p}($op(x.val, y.val)) | ||
| $op(x::Furlong{p}, y::TNumber) where {p} = Furlong{p}($op(x.val, y)) | ||
| end | ||
| end | ||
| Base.sqrt(x::Furlong) = _div(sqrt(x.val), x, Val(2)) | ||
| Base.muladd(x::Furlong, y::Furlong, z::Furlong) = x*y + z | ||
| Base.muladd(x::Furlong, y::TNumber, z::TNumber) = x*y + z | ||
| Base.muladd(x::Furlong, y::Furlong, z::TNumber) = x*y + z | ||
| Base.muladd(x::TNumber, y::Furlong, z::TNumber) = x*y + z | ||
| Base.muladd(x::TNumber, y::TNumber, z::Furlong) = x*y + z | ||
| Base.muladd(x::TNumber, y::Furlong, z::Furlong) = x*y + z | ||
| Base.muladd(x::Furlong, y::TNumber, z::Furlong) = x*y + z | ||
|
|
||
| Base.exp(f::Furlongs.Furlong) = exp(f.val) | ||
| Base.cos(f::Furlongs.Furlong) = cos(f.val) | ||
| Base.sin(f::Furlongs.Furlong) = sin(f.val) | ||
|
Comment on lines
+110
to
+112
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These still don't seem reasonable to me - IMO they only exist for dimensionless numbers (ie Furlong{0}). This is also how they're defined in Unitful IIRC.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cf. #758 (comment) The test currently entails If my comment makes no sense, please elaborate on what is unreasonable - I'm quite sure I may not have understood what you mean. |
||
|
|
||
| end | ||
Uh oh!
There was an error while loading. Please reload this page.