Skip to content

Commit 263b478

Browse files
committed
Added furlongs test
1 parent d813023 commit 263b478

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

test/DerivativeTest.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ using Random
88
using ForwardDiff
99
using DiffTests
1010

11+
include(joinpath(dirname(@__FILE__), "Furlongs.jl"))
1112
include(joinpath(dirname(@__FILE__), "utils.jl"))
1213

1314
Random.seed!(1)
@@ -113,4 +114,10 @@ end
113114
@test ForwardDiff.derivative(x -> (1+im)*x, 0) == (1+im)
114115
end
115116

117+
@testset "non-standard numbers" begin
118+
furlong = Furlongs.Furlong{2}(1.0)
119+
f(x) = exp(x) + 4*sin(x)*oneunit(x)
120+
@test ForwardDiff.derivative(f, furlong)= exp(furlong) + 4*cos(furlong)
121+
end
122+
116123
end # module

test/Furlongs.jl

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
module Furlongs
4+
5+
export Furlong
6+
7+
# Here we implement a minimal dimensionful type Furlong, which is used
8+
# to test dimensional correctness of various functions in Base.
9+
10+
# represents a quantity in furlongs^p
11+
struct Furlong{p,T<:Number} <: Number
12+
val::T
13+
Furlong{p,T}(v::Number) where {p,T} = new(v)
14+
end
15+
Furlong(x::T) where {T<:Number} = Furlong{1,T}(x)
16+
Furlong(x::Furlong) = x
17+
(::Type{T})(x::Furlong{0}) where {T<:Number} = T(x.val)::T
18+
(::Type{T})(x::Furlong{0}) where {T<:Furlong{0}} = T(x.val)::T
19+
(::Type{T})(x::Furlong{0}) where {T<:Furlong} = typeassert(x, T)
20+
Furlong{p}(v::Number) where {p} = Furlong{p,typeof(v)}(v)
21+
Furlong{p}(x::Furlong{q}) where {p,q} = (typeassert(x, Furlong{p}); Furlong{p,typeof(x.val)}(x.val))
22+
Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (typeassert(x, Furlong{p}); Furlong{p,T}(T(x.val)))
23+
24+
Base.promote_rule(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} =
25+
Furlong{p,promote_type(T,S)}
26+
Base.promote_rule(::Type{Furlong{0,T}}, ::Type{S}) where {T,S<:Union{Real,Complex}} =
27+
Furlong{0,promote_type(T,S)}
28+
# only Furlong{0} forms a ring and isa Number
29+
Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y)::T
30+
Base.convert(::Type{Furlong}, y::Number) = Furlong{0}(y)
31+
Base.convert(::Type{Furlong{<:Any,T}}, y::Number) where {T<:Number} = Furlong{0,T}(y)
32+
Base.convert(::Type{T}, y::Number) where {T<:Furlong} = typeassert(y, T) # throws, since cannot convert a Furlong{0} to a Furlong{p}
33+
# other Furlong{p} form a group
34+
Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)::T
35+
Base.convert(::Type{Furlong}, y::Furlong) = y
36+
Base.convert(::Type{Furlong{<:Any,T}}, y::Furlong{p}) where {p,T<:Number} = Furlong{p,T}(y)
37+
Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)::T
38+
39+
Base.one(::Furlong{p,T}) where {p,T} = one(T)
40+
Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T)
41+
Base.oneunit(::Furlong{p,T}) where {p,T} = Furlong{p,T}(one(T))
42+
Base.oneunit(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(one(T))
43+
Base.zero(::Furlong{p,T}) where {p,T} = Furlong{p,T}(zero(T))
44+
Base.zero(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(zero(T))
45+
Base.iszero(x::Furlong) = iszero(x.val)
46+
Base.float(x::Furlong{p}) where {p} = Furlong{p}(float(x.val))
47+
Base.eps(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(eps(T))
48+
Base.eps(::Furlong{p,T}) where {p,T<:AbstractFloat} = eps(Furlong{p,T})
49+
Base.floatmin(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmin(T))
50+
Base.floatmin(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmin(Furlong{p,T})
51+
Base.floatmax(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmax(T))
52+
Base.floatmax(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmax(Furlong{p,T})
53+
Base.conj(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(conj(x.val))
54+
55+
# convert Furlong exponent p to a canonical form
56+
canonical_p(p) = isinteger(p) ? Int(p) : Rational{Int}(p)
57+
58+
Base.abs(x::Furlong{p}) where {p} = Furlong{p}(abs(x.val))
59+
Base.abs2(x::Furlong{p}) where {p} = Furlong{canonical_p(2p)}(abs2(x.val))
60+
Base.inv(x::Furlong{p}) where {p} = Furlong{canonical_p(-p)}(inv(x.val))
61+
62+
for f in (:isfinite, :isnan, :isreal, :isinf)
63+
@eval Base.$f(x::Furlong) = $f(x.val)
64+
end
65+
for f in (:real,:imag,:complex,:+,:-)
66+
@eval Base.$f(x::Furlong{p}) where {p} = Furlong{p}($f(x.val))
67+
end
68+
69+
import Base: +, -, ==, !=, <, <=, isless, isequal, *, /, //, div, rem, mod, ^
70+
for op in (:+, :-)
71+
@eval function $op(x::Furlong{p}, y::Furlong{p}) where {p}
72+
v = $op(x.val, y.val)
73+
Furlong{p}(v)
74+
end
75+
end
76+
for op in (:(==), :(!=), :<, :<=, :isless, :isequal)
77+
@eval $op(x::Furlong{p}, y::Furlong{p}) where {p} = $op(x.val, y.val)::Bool
78+
end
79+
for (f,op) in ((:_plus,:+),(:_minus,:-),(:_times,:*),(:_div,://))
80+
@eval function $f(v::T, ::Furlong{p}, ::Union{Furlong{q},Val{q}}) where {T,p,q}
81+
s = $op(p, q)
82+
Furlong{canonical_p(s),T}(v)
83+
end
84+
end
85+
for (op,eop) in ((:*, :_plus), (:/, :_minus), (://, :_minus), (:div, :_minus))
86+
@eval begin
87+
$op(x::Furlong{p}, y::Furlong{q}) where {p,q} =
88+
$eop($op(x.val, y.val),x,y)
89+
$op(x::Furlong{p}, y::S) where {p,S<:Number} = $op(x,Furlong{0,S}(y))
90+
$op(x::S, y::Furlong{p}) where {p,S<:Number} = $op(Furlong{0,S}(x),y)
91+
end
92+
end
93+
# to fix an ambiguity
94+
//(x::Furlong, y::Complex) = x // Furlong{0,typeof(y)}(y)
95+
for op in (:rem, :mod)
96+
@eval begin
97+
$op(x::Furlong{p}, y::Furlong) where {p} = Furlong{p}($op(x.val, y.val))
98+
$op(x::Furlong{p}, y::Number) where {p} = Furlong{p}($op(x.val, y))
99+
end
100+
end
101+
Base.sqrt(x::Furlong) = _div(sqrt(x.val), x, Val(2))
102+
Base.muladd(x::Furlong, y::Furlong, z::Furlong) = x*y + z
103+
Base.muladd(x::Furlong, y::Number, z::Number) = x*y + z
104+
Base.muladd(x::Furlong, y::Furlong, z::Number) = x*y + z
105+
Base.muladd(x::Number, y::Furlong, z::Number) = x*y + z
106+
Base.muladd(x::Number, y::Number, z::Furlong) = x*y + z
107+
Base.muladd(x::Number, y::Furlong, z::Furlong) = x*y + z
108+
Base.muladd(x::Furlong, y::Number, z::Furlong) = x*y + z
109+
110+
end

0 commit comments

Comments
 (0)