Skip to content

Commit 3590f94

Browse files
authored
Drop support for Julia 1.0 (#577)
* drop 1.0, now that LTS == 1.6 * revert to one Project * rm Compat * tests * k=2 * turns out this does still need Compat
1 parent 335d025 commit 3590f94

File tree

20 files changed

+244
-287
lines changed

20 files changed

+244
-287
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
fail-fast: false
1616
matrix:
1717
version:
18-
- "1.0" # LTS
18+
- "1.6" # LTS
1919
- "1" # Latest Release
2020
os:
2121
- ubuntu-latest

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ChainRules"
22
uuid = "082447d4-558c-5d27-93f4-14fc19e9eca2"
3-
version = "1.21"
3+
version = "1.22"
44

55
[deps]
66
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
@@ -15,10 +15,10 @@ ChainRulesCore = "1.11.5"
1515
ChainRulesTestUtils = "1"
1616
Compat = "3.35"
1717
FiniteDifferences = "0.12.20"
18-
JuliaInterpreter = "0.8"
18+
JuliaInterpreter = "0.8" # latest is "0.9.1"
1919
RealDot = "0.1"
2020
StaticArrays = "1.2"
21-
julia = "1"
21+
julia = "1.6"
2222

2323
[extras]
2424
ChainRulesTestUtils = "cdddcdb0-9152-4a09-a978-84456f9df70a"

src/ChainRules.jl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@ using Statistics
1313
# to the normal rule of only overload via `ChainRulesCore.rrule`.
1414
import ChainRulesCore: rrule, frule
1515

16-
if VERSION < v"1.3.0-DEV.142"
17-
# In prior versions, the BLAS submodule also exported `dot`, which caused a conflict
18-
# with its parent module. To get around this, we can simply create a hard binding for
19-
# the one we want to use without qualification.
20-
import LinearAlgebra: dot
21-
end
22-
2316
# numbers that we know commute under multiplication
2417
const CommutativeMulNumber = Union{Real,Complex}
2518

src/rulesets/Base/base.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,7 @@ end
148148
@scalar_rule sinc(x) cosc(x)
149149

150150
# the position of the minus sign below warrants the correct type for π
151-
if VERSION v"1.6"
152-
@scalar_rule sincospi(x) @setup((sinpix, cospix) = Ω) (π * cospix) (π * (-sinpix))
153-
end
151+
@scalar_rule sincospi(x) @setup((sinpix, cospix) = Ω) (π * cospix) (π * (-sinpix))
154152

155153
@scalar_rule(
156154
clamp(x, low, high),

src/rulesets/Base/evalpoly.jl

Lines changed: 128 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,149 @@
11

2-
if VERSION v"1.4"
3-
function frule((_, ẋ, ṗ), ::typeof(evalpoly), x, p::Union{Tuple,AbstractVector})
4-
Δx, Δp = ẋ, unthunk(ṗ)
5-
N = length(p)
6-
@inbounds y = p[N]
7-
Δy = Δp[N]
8-
@inbounds for i in (N - 1):-1:1
9-
Δy = muladd(Δx, y, muladd(x, Δy, Δp[i]))
10-
y = muladd(x, y, p[i])
11-
end
12-
return y, Δy
2+
function frule((_, ẋ, ṗ), ::typeof(evalpoly), x, p::Union{Tuple,AbstractVector})
3+
Δx, Δp = ẋ, unthunk(ṗ)
4+
N = length(p)
5+
@inbounds y = p[N]
6+
Δy = Δp[N]
7+
@inbounds for i in (N - 1):-1:1
8+
Δy = muladd(Δx, y, muladd(x, Δy, Δp[i]))
9+
y = muladd(x, y, p[i])
1310
end
11+
return y, Δy
12+
end
1413

15-
function rrule(::typeof(evalpoly), x, p::Union{Tuple,AbstractVector})
16-
y, ys = _evalpoly_intermediates(x, p)
17-
project_x = ProjectTo(x)
18-
project_p = p isa Tuple ? identity : ProjectTo(p)
19-
function evalpoly_pullback(Δy)
20-
∂x, ∂p = _evalpoly_back(x, p, ys, Δy)
21-
return NoTangent(), project_x(∂x), project_p(∂p)
22-
end
23-
return y, evalpoly_pullback
14+
function rrule(::typeof(evalpoly), x, p::Union{Tuple,AbstractVector})
15+
y, ys = _evalpoly_intermediates(x, p)
16+
project_x = ProjectTo(x)
17+
project_p = p isa Tuple ? identity : ProjectTo(p)
18+
function evalpoly_pullback(Δy)
19+
∂x, ∂p = _evalpoly_back(x, p, ys, Δy)
20+
return NoTangent(), project_x(∂x), project_p(∂p)
2421
end
22+
return y, evalpoly_pullback
23+
end
2524

26-
function rrule(::typeof(evalpoly), x, p::Vector{<:Matrix}) # does not type infer with ProjectTo
27-
y, ys = _evalpoly_intermediates(x, p)
28-
function evalpoly_pullback(Δy)
29-
∂x, ∂p = _evalpoly_back(x, p, ys, Δy)
30-
return NoTangent(), ∂x, ∂p
31-
end
32-
return y, evalpoly_pullback
25+
function rrule(::typeof(evalpoly), x, p::Vector{<:Matrix}) # does not type infer with ProjectTo
26+
y, ys = _evalpoly_intermediates(x, p)
27+
function evalpoly_pullback(Δy)
28+
∂x, ∂p = _evalpoly_back(x, p, ys, Δy)
29+
return NoTangent(), ∂x, ∂p
3330
end
31+
return y, evalpoly_pullback
32+
end
3433

35-
# evalpoly but storing intermediates
36-
function _evalpoly_intermediates(x, p::Tuple)
37-
return if @generated
38-
N = length(p.parameters)
39-
exs = []
40-
vars = []
41-
ex = :(p[$N])
42-
for i in 1:(N - 1)
43-
yi = Symbol("y", i)
44-
push!(vars, yi)
45-
push!(exs, :($yi = $ex))
46-
ex = :(muladd(x, $yi, p[$(N - i)]))
47-
end
48-
push!(exs, :(y = $ex))
49-
Expr(:block, exs..., :(y, ($(vars...),)))
50-
else
51-
_evalpoly_intermediates_fallback(x, p)
34+
# evalpoly but storing intermediates
35+
function _evalpoly_intermediates(x, p::Tuple)
36+
return if @generated
37+
N = length(p.parameters)
38+
exs = []
39+
vars = []
40+
ex = :(p[$N])
41+
for i in 1:(N - 1)
42+
yi = Symbol("y", i)
43+
push!(vars, yi)
44+
push!(exs, :($yi = $ex))
45+
ex = :(muladd(x, $yi, p[$(N - i)]))
5246
end
47+
push!(exs, :(y = $ex))
48+
Expr(:block, exs..., :(y, ($(vars...),)))
49+
else
50+
_evalpoly_intermediates_fallback(x, p)
5351
end
54-
function _evalpoly_intermediates_fallback(x, p::Tuple)
55-
N = length(p)
56-
y = p[N]
57-
ys = (y, ntuple(N - 2) do i
58-
return y = muladd(x, y, p[N - i])
59-
end...)
60-
y = muladd(x, y, p[1])
61-
return y, ys
62-
end
63-
function _evalpoly_intermediates(x, p)
64-
N = length(p)
65-
@inbounds yn = one(x) * p[N]
66-
ys = similar(p, typeof(yn), N - 1)
67-
@inbounds ys[1] = yn
68-
@inbounds for i in 2:(N - 1)
69-
ys[i] = muladd(x, ys[i - 1], p[N - i + 1])
70-
end
71-
@inbounds y = muladd(x, ys[N - 1], p[1])
72-
return y, ys
52+
end
53+
function _evalpoly_intermediates_fallback(x, p::Tuple)
54+
N = length(p)
55+
y = p[N]
56+
ys = (y, ntuple(N - 2) do i
57+
return y = muladd(x, y, p[N - i])
58+
end...)
59+
y = muladd(x, y, p[1])
60+
return y, ys
61+
end
62+
function _evalpoly_intermediates(x, p)
63+
N = length(p)
64+
@inbounds yn = one(x) * p[N]
65+
ys = similar(p, typeof(yn), N - 1)
66+
@inbounds ys[1] = yn
67+
@inbounds for i in 2:(N - 1)
68+
ys[i] = muladd(x, ys[i - 1], p[N - i + 1])
7369
end
70+
@inbounds y = muladd(x, ys[N - 1], p[1])
71+
return y, ys
72+
end
7473

75-
# TODO: Handle following cases
76-
# 1) x is a UniformScaling, pᵢ is a matrix
77-
# 2) x is a matrix, pᵢ is a UniformScaling
78-
@inline _evalpoly_backx(x, yi, ∂yi) = ∂yi * yi'
79-
@inline _evalpoly_backx(x, yi, ∂x, ∂yi) = muladd(∂yi, yi', ∂x)
80-
@inline _evalpoly_backx(x::Number, yi, ∂yi) = conj(dot(∂yi, yi))
81-
@inline _evalpoly_backx(x::Number, yi, ∂x, ∂yi) = _evalpoly_backx(x, yi, ∂yi) + ∂x
74+
# TODO: Handle following cases
75+
# 1) x is a UniformScaling, pᵢ is a matrix
76+
# 2) x is a matrix, pᵢ is a UniformScaling
77+
@inline _evalpoly_backx(x, yi, ∂yi) = ∂yi * yi'
78+
@inline _evalpoly_backx(x, yi, ∂x, ∂yi) = muladd(∂yi, yi', ∂x)
79+
@inline _evalpoly_backx(x::Number, yi, ∂yi) = conj(dot(∂yi, yi))
80+
@inline _evalpoly_backx(x::Number, yi, ∂x, ∂yi) = _evalpoly_backx(x, yi, ∂yi) + ∂x
8281

83-
@inline _evalpoly_backp(pi, ∂yi) = ∂yi
82+
@inline _evalpoly_backp(pi, ∂yi) = ∂yi
8483

85-
function _evalpoly_back(x, p::Tuple, ys, Δy)
86-
return if @generated
87-
exs = []
88-
vars = []
89-
N = length(p.parameters)
90-
for i in 2:(N - 1)
91-
∂pi = Symbol("∂p", i)
92-
push!(vars, ∂pi)
93-
push!(exs, :(∂x = _evalpoly_backx(x, ys[$(N - i)], ∂x, ∂yi)))
94-
push!(exs, :($∂pi = _evalpoly_backp(p[$i], ∂yi)))
95-
push!(exs, :(∂yi = x′ * ∂yi))
96-
end
97-
push!(vars, :(_evalpoly_backp(p[$N], ∂yi))) # ∂pN
98-
Expr(
99-
:block,
100-
:(x′ = x'),
101-
:(∂yi = Δy),
102-
:(∂p1 = _evalpoly_backp(p[1], ∂yi)),
103-
:(∂x = _evalpoly_backx(x, ys[$(N - 1)], ∂yi)),
104-
:(∂yi = x′ * ∂yi),
105-
exs...,
106-
:(∂p = (∂p1, $(vars...))),
107-
:(∂x, Tangent{typeof(p),typeof(∂p)}(∂p)),
108-
)
109-
else
110-
_evalpoly_back_fallback(x, p, ys, Δy)
84+
function _evalpoly_back(x, p::Tuple, ys, Δy)
85+
return if @generated
86+
exs = []
87+
vars = []
88+
N = length(p.parameters)
89+
for i in 2:(N - 1)
90+
∂pi = Symbol("∂p", i)
91+
push!(vars, ∂pi)
92+
push!(exs, :(∂x = _evalpoly_backx(x, ys[$(N - i)], ∂x, ∂yi)))
93+
push!(exs, :($∂pi = _evalpoly_backp(p[$i], ∂yi)))
94+
push!(exs, :(∂yi = x′ * ∂yi))
11195
end
96+
push!(vars, :(_evalpoly_backp(p[$N], ∂yi))) # ∂pN
97+
Expr(
98+
:block,
99+
:(x′ = x'),
100+
:(∂yi = Δy),
101+
:(∂p1 = _evalpoly_backp(p[1], ∂yi)),
102+
:(∂x = _evalpoly_backx(x, ys[$(N - 1)], ∂yi)),
103+
:(∂yi = x′ * ∂yi),
104+
exs...,
105+
:(∂p = (∂p1, $(vars...))),
106+
:(∂x, Tangent{typeof(p),typeof(∂p)}(∂p)),
107+
)
108+
else
109+
_evalpoly_back_fallback(x, p, ys, Δy)
112110
end
113-
function _evalpoly_back_fallback(x, p::Tuple, ys, Δy)
114-
x′ = x'
115-
∂yi = unthunk(Δy)
116-
N = length(p)
117-
∂p1 = _evalpoly_backp(p[1], ∂yi)
111+
end
112+
function _evalpoly_back_fallback(x, p::Tuple, ys, Δy)
113+
x′ = x'
114+
∂yi = unthunk(Δy)
115+
N = length(p)
116+
∂p1 = _evalpoly_backp(p[1], ∂yi)
117+
∂x = _evalpoly_backx(x, ys[N - 1], ∂yi)
118+
∂yi = x′ * ∂yi
119+
∂p = (
120+
∂p1,
121+
ntuple(N - 2) do i
122+
∂x = _evalpoly_backx(x, ys[N-i-1], ∂x, ∂yi)
123+
∂pi = _evalpoly_backp(p[i+1], ∂yi)
124+
∂yi = x′ * ∂yi
125+
return ∂pi
126+
end...,
127+
_evalpoly_backp(p[N], ∂yi), # ∂pN
128+
)
129+
return ∂x, Tangent{typeof(p),typeof(∂p)}(∂p)
130+
end
131+
function _evalpoly_back(x, p, ys, Δy)
132+
x′ = x'
133+
∂yi = one(x′) * Δy
134+
N = length(p)
135+
@inbounds ∂p1 = _evalpoly_backp(p[1], ∂yi)
136+
∂p = similar(p, typeof(∂p1))
137+
@inbounds begin
118138
∂x = _evalpoly_backx(x, ys[N - 1], ∂yi)
119139
∂yi = x′ * ∂yi
120-
∂p = (
121-
∂p1,
122-
ntuple(N - 2) do i
123-
∂x = _evalpoly_backx(x, ys[N-i-1], ∂x, ∂yi)
124-
∂pi = _evalpoly_backp(p[i+1], ∂yi)
125-
∂yi = x′ * ∂yi
126-
return ∂pi
127-
end...,
128-
_evalpoly_backp(p[N], ∂yi), # ∂pN
129-
)
130-
return ∂x, Tangent{typeof(p),typeof(∂p)}(∂p)
131-
end
132-
function _evalpoly_back(x, p, ys, Δy)
133-
x′ = x'
134-
∂yi = one(x′) * Δy
135-
N = length(p)
136-
@inbounds ∂p1 = _evalpoly_backp(p[1], ∂yi)
137-
∂p = similar(p, typeof(∂p1))
138-
@inbounds begin
139-
∂x = _evalpoly_backx(x, ys[N - 1], ∂yi)
140+
∂p[1] = ∂p1
141+
for i in 2:(N - 1)
142+
∂x = _evalpoly_backx(x, ys[N - i], ∂x, ∂yi)
143+
∂p[i] = _evalpoly_backp(p[i], ∂yi)
140144
∂yi = x′ * ∂yi
141-
∂p[1] = ∂p1
142-
for i in 2:(N - 1)
143-
∂x = _evalpoly_backx(x, ys[N - i], ∂x, ∂yi)
144-
∂p[i] = _evalpoly_backp(p[i], ∂yi)
145-
∂yi = x′ * ∂yi
146-
end
147-
∂p[N] = _evalpoly_backp(p[N], ∂yi)
148145
end
149-
return ∂x, ∂p
146+
∂p[N] = _evalpoly_backp(p[N], ∂yi)
150147
end
148+
return ∂x, ∂p
151149
end

src/rulesets/Base/mapreduce.jl

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,10 @@ function frule(
115115
y = sum(abs2, x; dims=dims)
116116
∂y = if dims isa Colon
117117
2 * realdot(x, ẋ)
118-
elseif VERSION v"1.2" # multi-iterator mapreduce introduced in v1.2
118+
else
119119
mapreduce(+, x, ẋ; dims=dims) do xi, dxi
120120
2 * realdot(xi, dxi)
121121
end
122-
else
123-
2 * sum(realdot.(x, ẋ); dims=dims)
124122
end
125123
return y, ∂y
126124
end
@@ -419,16 +417,10 @@ end
419417
# To support 2nd derivatives, some may need their own gradient rules. And _drop1 should perhaps
420418
# be replaced by _peel1 like Iterators.peel
421419

422-
if VERSION >= v"1.6"
423-
_reverse1(x) = Iterators.reverse(x)
424-
_drop1(x) = Iterators.drop(x, 1)
425-
_zip2(x, y) = zip(x, y) # for `accumulate`, below
426-
else
427-
# Old versions don't support accumulate(::itr), nor multi-dim reverse
428-
_reverse1(x) = reverse(vec(x))
429-
_drop1(x) = vec(x)[2:end]
430-
_zip2(x, y) = collect(zip(x, y))
431-
end
420+
_reverse1(x) = Iterators.reverse(x)
421+
_drop1(x) = Iterators.drop(x, 1)
422+
_zip2(x, y) = zip(x, y) # for `accumulate`, below
423+
432424
_reverse1(x::Tuple) = reverse(x)
433425
_drop1(x::Tuple) = Base.tail(x)
434426
_zip2(x::Tuple{Vararg{Any,N}}, y::Tuple{Vararg{Any,N}}) where N = ntuple(i -> (x[i],y[i]), N)
@@ -480,16 +472,9 @@ function rrule(
480472
function decumulate(dy)
481473
dy_plain = _no_tuple_tangent(unthunk(dy))
482474
rev_list = if init === _InitialValue()
483-
if VERSION >= v"1.6"
484-
# Here we rely on `zip` to stop early. Begin explicit with _reverse1(_drop1(...))
485-
# gets "no method matching iterate(::Base.Iterators.Reverse{Base.Iterators.Drop{Array{"
486-
_zip2(_reverse1(hobbits), _reverse1(dy_plain))
487-
else
488-
# However, on 1.0 and some others, zip does not stop early. But since accumulate
489-
# also doesn't work on iterators, `_drop1` doesn't make one, so this should work:
490-
_zip2(_reverse1(hobbits), _reverse1(_drop1(dy_plain)))
491-
# What an awful tangle.
492-
end
475+
# Here we rely on `zip` to stop early. Begin explicit with _reverse1(_drop1(...))
476+
# gets "no method matching iterate(::Base.Iterators.Reverse{Base.Iterators.Drop{Array{"
477+
_zip2(_reverse1(hobbits), _reverse1(dy_plain))
493478
else
494479
_zip2(_reverse1(hobbits), _reverse1(dy_plain))
495480
end

0 commit comments

Comments
 (0)