Skip to content

Commit 74454b2

Browse files
Merge pull request #53 from ChrisRackauckas-Claude/centralize-ci
Centralize CI on SciML reusable workflows
2 parents 15032a2 + 8a742af commit 74454b2

8 files changed

Lines changed: 140 additions & 105 deletions

File tree

.github/dependabot.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ updates:
55
directory: "/" # Location of package manifests
66
schedule:
77
interval: "weekly"
8-
ignore:
9-
- dependency-name: "crate-ci/typos"
10-
update-types: ["version-update:semver-patch", "version-update:semver-minor"]
118
- package-ecosystem: "julia"
129
directories:
1310
- "/"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: "Documentation"
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
- 'release-'
8+
push:
9+
branches:
10+
- main
11+
tags: '*'
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: ${{ github.ref_name != github.event.repository.default_branch || github.ref != 'refs/tags/v*' }}
16+
17+
jobs:
18+
docs:
19+
name: Documentation
20+
uses: "SciML/.github/.github/workflows/documentation.yml@v1"
21+
secrets: "inherit"

.github/workflows/Downgrade.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Downgrade
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
- 'release-'
8+
paths-ignore:
9+
- 'docs/**'
10+
push:
11+
branches:
12+
- main
13+
paths-ignore:
14+
- 'docs/**'
15+
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: ${{ github.ref_name != github.event.repository.default_branch || github.ref != 'refs/tags/v*' }}
19+
20+
jobs:
21+
downgrade:
22+
name: Downgrade
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
group:
27+
- Core
28+
uses: "SciML/.github/.github/workflows/downgrade.yml@v1"
29+
with:
30+
group: "${{ matrix.group }}"
31+
julia-version: "lts"
32+
skip: "Pkg,TOML"
33+
secrets: "inherit"

.github/workflows/FormatCheck.yml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ on:
1111

1212
jobs:
1313
runic:
14-
runs-on: ubuntu-latest
15-
steps:
16-
- uses: actions/checkout@v6
17-
- uses: julia-actions/setup-julia@v3
18-
with:
19-
version: '1'
20-
- uses: fredrikekre/runic-action@v1
21-
with:
22-
version: '1'
14+
name: Runic
15+
uses: "SciML/.github/.github/workflows/runic.yml@v1"
16+
secrets: "inherit"

.github/workflows/SpellCheck.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: Spell Check
2+
3+
on: [pull_request]
4+
5+
jobs:
6+
typos-check:
7+
name: Spell Check with Typos
8+
uses: "SciML/.github/.github/workflows/spellcheck.yml@v1"
9+
secrets: "inherit"

.github/workflows/Tests.yml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,3 @@ jobs:
4141
julia-version: "${{ matrix.version }}"
4242
julia-arch: "${{ matrix.arch }}"
4343
secrets: "inherit"
44-
45-
docs:
46-
name: Documentation
47-
runs-on: ubuntu-latest
48-
steps:
49-
- uses: actions/checkout@v6
50-
- uses: julia-actions/setup-julia@v3
51-
with:
52-
version: '1'
53-
- uses: julia-actions/julia-buildpkg@v1
54-
- uses: julia-actions/julia-docdeploy@v1
55-
env:
56-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57-
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
58-
- run: |
59-
julia --project=docs -e '
60-
using Documenter: DocMeta, doctest
61-
using FunctionWrappersWrappers
62-
DocMeta.setdocmeta!(FunctionWrappersWrappers, :DocTestSetup, :(using FunctionWrappersWrappers); recursive=true)
63-
doctest(FunctionWrappersWrappers)'

ext/FunctionWrappersWrappersEnzymeExt.jl

Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ EnzymeCore.EnzymeRules.inactive_type(::Type{NoCacheStorage}) = true
3939
# `ForwardMode` matching the outer config so the delegated call inherits
4040
# those flags.
4141
@inline function _fwd_mode(
42-
::Val{NeedsPrimal}, ::Val{RuntimeActivity}, ::Val{StrongZero}
43-
) where {NeedsPrimal, RuntimeActivity, StrongZero}
42+
::Val{NeedsPrimal}, ::Val{RuntimeActivity}, ::Val{StrongZero}
43+
) where {NeedsPrimal, RuntimeActivity, StrongZero}
4444
mode = NeedsPrimal ? ForwardWithPrimal : Forward
4545
RuntimeActivity && (mode = Enzyme.set_runtime_activity(mode))
4646
StrongZero && (mode = Enzyme.set_strong_zero(mode))
@@ -63,11 +63,11 @@ end
6363
# meaningful tangent — so the function shadow is ignored and the inner
6464
# `Enzyme.autodiff` call uses `Const(f_orig)`.
6565
function EnzymeRules.forward(
66-
::EnzymeRules.FwdConfig{false, true, W, RuntimeActivity, StrongZero},
67-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
68-
RT::Type{<:EnzymeCore.Annotation{T}},
69-
args::Vararg{EnzymeCore.Annotation, N}
70-
) where {T, W, N, RuntimeActivity, StrongZero}
66+
::EnzymeRules.FwdConfig{false, true, W, RuntimeActivity, StrongZero},
67+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
68+
RT::Type{<:EnzymeCore.Annotation{T}},
69+
args::Vararg{EnzymeCore.Annotation, N}
70+
) where {T, W, N, RuntimeActivity, StrongZero}
7171
f_orig = unwrap(func.val)
7272
mode = _fwd_mode(Val(false), Val(RuntimeActivity), Val(StrongZero))
7373
if W == 1
@@ -86,11 +86,11 @@ end
8686

8787
# Both primal and shadow (ForwardWithPrimal mode)
8888
function EnzymeRules.forward(
89-
::EnzymeRules.FwdConfig{true, true, W, RuntimeActivity, StrongZero},
90-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
91-
RT::Type{<:EnzymeCore.Annotation{T}},
92-
args::Vararg{EnzymeCore.Annotation, N}
93-
) where {T, W, N, RuntimeActivity, StrongZero}
89+
::EnzymeRules.FwdConfig{true, true, W, RuntimeActivity, StrongZero},
90+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
91+
RT::Type{<:EnzymeCore.Annotation{T}},
92+
args::Vararg{EnzymeCore.Annotation, N}
93+
) where {T, W, N, RuntimeActivity, StrongZero}
9494
f_orig = unwrap(func.val)
9595
pargs = ntuple(i -> args[i].val, Val(N))
9696
primal = f_orig(pargs...)::T
@@ -113,11 +113,11 @@ end
113113

114114
# Primal only (Const return type) — width-independent
115115
function EnzymeRules.forward(
116-
::EnzymeRules.FwdConfig{true, false, W, RuntimeActivity, StrongZero},
117-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
118-
RT::Type{<:EnzymeCore.Annotation},
119-
args::Vararg{EnzymeCore.Annotation, N}
120-
) where {W, N, RuntimeActivity, StrongZero}
116+
::EnzymeRules.FwdConfig{true, false, W, RuntimeActivity, StrongZero},
117+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
118+
RT::Type{<:EnzymeCore.Annotation},
119+
args::Vararg{EnzymeCore.Annotation, N}
120+
) where {W, N, RuntimeActivity, StrongZero}
121121
f_orig = unwrap(func.val)
122122
pargs = ntuple(i -> args[i].val, Val(N))
123123
return f_orig(pargs...)
@@ -137,13 +137,13 @@ end
137137
# IMPORTANT: forward the `RuntimeActivity` and `StrongZero` flags from the
138138
# outer config into the delegated `Enzyme.autodiff` call. Prior to this
139139
# fix the rule hard-coded `Forward`, silently dropping
140-
# `set_runtime_activity(Forward)` on the way down into `f_orig`.
140+
# `set_runtime_activity(Forward)` on the way down into `f_orig`.
141141
function EnzymeRules.forward(
142-
::EnzymeRules.FwdConfig{false, false, W, RuntimeActivity, StrongZero},
143-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
144-
RT::Type{<:EnzymeCore.Annotation},
145-
args::Vararg{EnzymeCore.Annotation, N}
146-
) where {W, N, RuntimeActivity, StrongZero}
142+
::EnzymeRules.FwdConfig{false, false, W, RuntimeActivity, StrongZero},
143+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
144+
RT::Type{<:EnzymeCore.Annotation},
145+
args::Vararg{EnzymeCore.Annotation, N}
146+
) where {W, N, RuntimeActivity, StrongZero}
147147
f_orig = unwrap(func.val)
148148
mode = _fwd_mode(Val(false), Val(RuntimeActivity), Val(StrongZero))
149149
Enzyme.autodiff(mode, Const(f_orig), Const, args...)
@@ -155,11 +155,11 @@ end
155155
# =============================================================================
156156

157157
function EnzymeRules.augmented_primal(
158-
config::EnzymeRules.RevConfig,
159-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
160-
RT::Type{<:EnzymeCore.Active{T}},
161-
args::Vararg{EnzymeCore.Annotation, N}
162-
) where {T, N}
158+
config::EnzymeRules.RevConfig,
159+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
160+
RT::Type{<:EnzymeCore.Active{T}},
161+
args::Vararg{EnzymeCore.Annotation, N}
162+
) where {T, N}
163163
f_orig = unwrap(func.val)
164164
pargs = ntuple(i -> args[i].val, Val(N))
165165
result = f_orig(pargs...)::T
@@ -175,11 +175,11 @@ end
175175
# return). Just run the primal for its side effects; no tape is needed because
176176
# the reverse pass has nothing to propagate back from the return.
177177
function EnzymeRules.augmented_primal(
178-
config::EnzymeRules.RevConfig,
179-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
180-
RT::Type{<:EnzymeCore.Const},
181-
args::Vararg{EnzymeCore.Annotation, N}
182-
) where {N}
178+
config::EnzymeRules.RevConfig,
179+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
180+
RT::Type{<:EnzymeCore.Const},
181+
args::Vararg{EnzymeCore.Annotation, N}
182+
) where {N}
183183
f_orig = unwrap(func.val)
184184
pargs = ntuple(i -> args[i].val, Val(N))
185185
f_orig(pargs...)
@@ -189,11 +189,11 @@ end
189189
# Duplicated / BatchDuplicated return: record the primal so that reverse has
190190
# it available when propagating dret through the arguments.
191191
function EnzymeRules.augmented_primal(
192-
config::EnzymeRules.RevConfig,
193-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
194-
RT::Type{<:EnzymeCore.Duplicated{T}},
195-
args::Vararg{EnzymeCore.Annotation, N}
196-
) where {T, N}
192+
config::EnzymeRules.RevConfig,
193+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
194+
RT::Type{<:EnzymeCore.Duplicated{T}},
195+
args::Vararg{EnzymeCore.Annotation, N}
196+
) where {T, N}
197197
f_orig = unwrap(func.val)
198198
pargs = ntuple(i -> args[i].val, Val(N))
199199
primal = f_orig(pargs...)::T
@@ -205,11 +205,11 @@ function EnzymeRules.augmented_primal(
205205
end
206206

207207
function EnzymeRules.augmented_primal(
208-
config::EnzymeRules.RevConfig,
209-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
210-
RT::Type{<:EnzymeCore.BatchDuplicated{T, W}},
211-
args::Vararg{EnzymeCore.Annotation, N}
212-
) where {T, W, N}
208+
config::EnzymeRules.RevConfig,
209+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
210+
RT::Type{<:EnzymeCore.BatchDuplicated{T, W}},
211+
args::Vararg{EnzymeCore.Annotation, N}
212+
) where {T, W, N}
213213
f_orig = unwrap(func.val)
214214
pargs = ntuple(i -> args[i].val, Val(N))
215215
primal = f_orig(pargs...)::T
@@ -235,41 +235,43 @@ end
235235
# function, then scale by dret. This avoids type-inference issues that arise
236236
# from calling autodiff(Reverse, Const{Any}(...), ...).
237237
@generated function _fww_reverse_grads(
238-
mode, f_orig, dret_val::T, args::Vararg{EnzymeCore.Active, N}
239-
) where {T, N}
238+
mode, f_orig, dret_val::T, args::Vararg{EnzymeCore.Active, N}
239+
) where {T, N}
240240
# Build forward-mode calls for each partial derivative
241241
exprs = []
242242
for i in 1:N
243243
seeds = [j == i ? :(one(eltype(typeof(args[$j])))) : :(zero(eltype(typeof(args[$j])))) for j in 1:N]
244244
dups = [:(Duplicated(args[$j].val, $(seeds[j]))) for j in 1:N]
245245
Ti = :(eltype(typeof(args[$i])))
246-
push!(exprs, quote
247-
fwd = Enzyme.autodiff(mode, Const(f_orig), Duplicated{$T}, $(dups...))
248-
$Ti(fwd[1] * dret_val)::$Ti
249-
end)
246+
push!(
247+
exprs, quote
248+
fwd = Enzyme.autodiff(mode, Const(f_orig), Duplicated{$T}, $(dups...))
249+
$Ti(fwd[1] * dret_val)::$Ti
250+
end
251+
)
250252
end
251253
return Expr(:tuple, exprs...)
252254
end
253255

254256
function EnzymeRules.reverse(
255-
config::EnzymeRules.RevConfig,
256-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
257-
dret::EnzymeCore.Active{T},
258-
tape,
259-
args::Vararg{EnzymeCore.Active, N}
260-
) where {T, N}
257+
config::EnzymeRules.RevConfig,
258+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
259+
dret::EnzymeCore.Active{T},
260+
tape,
261+
args::Vararg{EnzymeCore.Active, N}
262+
) where {T, N}
261263
f_orig = unwrap(func.val)
262264
return _fww_reverse_grads(_fwd_mode_from_rev(config), f_orig, dret.val, args...)
263265
end
264266

265267
# Handle mixed Active/Const args: return nothing for Const, gradient for Active
266268
function EnzymeRules.reverse(
267-
config::EnzymeRules.RevConfig,
268-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
269-
dret::EnzymeCore.Active,
270-
tape,
271-
args::Vararg{EnzymeCore.Annotation, N}
272-
) where {N}
269+
config::EnzymeRules.RevConfig,
270+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
271+
dret::EnzymeCore.Active,
272+
tape,
273+
args::Vararg{EnzymeCore.Annotation, N}
274+
) where {N}
273275
f_orig = unwrap(func.val)
274276
dret_val = dret.val
275277
mode = _fwd_mode_from_rev(config)
@@ -303,12 +305,12 @@ end
303305
# `BatchDuplicated` args return `nothing` because their gradients are
304306
# accumulated in-place by the `Enzyme.autodiff(Reverse, …)` call above.
305307
function EnzymeRules.reverse(
306-
config::EnzymeRules.RevConfig,
307-
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
308-
dret::Type{<:EnzymeCore.Const},
309-
tape,
310-
args::Vararg{EnzymeCore.Annotation, N}
311-
) where {N}
308+
config::EnzymeRules.RevConfig,
309+
func::EnzymeCore.Annotation{<:FunctionWrappersWrapper},
310+
dret::Type{<:EnzymeCore.Const},
311+
tape,
312+
args::Vararg{EnzymeCore.Annotation, N}
313+
) where {N}
312314
f_orig = unwrap(func.val)
313315
# Only worth invoking Enzyme.autodiff when at least one arg is
314316
# Duplicated/BatchDuplicated — otherwise there's nothing to accumulate.

test/enzyme_tests.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ end
284284
# du_shadow gives the accumulation into u_shadow:
285285
# u_shadow[1] += a*y + b*2x
286286
# u_shadow[2] += a*x + b*3y^2
287-
f!(du, u) = (du[1] = u[1]*u[2]; du[2] = u[1]^2 + u[2]^3; nothing)
287+
f!(du, u) = (du[1] = u[1] * u[2]; du[2] = u[1]^2 + u[2]^3; nothing)
288288
fww = FunctionWrappersWrapper(
289289
f!, (Tuple{Vector{Float64}, Vector{Float64}},), (Nothing,)
290290
)
@@ -300,9 +300,9 @@ end
300300
Reverse, Const(fww), Const,
301301
Duplicated(du, du_shadow), Duplicated(u, u_shadow)
302302
)
303-
@test du [x*y, x^2 + y^3]
304-
@test u_shadow[1] a*y + b*2*x # 5 + 2 = 7
305-
@test u_shadow[2] a*x + b*3*y^2 # 2 + 37.5 = 39.5
303+
@test du [x * y, x^2 + y^3]
304+
@test u_shadow[1] a * y + b * 2 * x # 5 + 2 = 7
305+
@test u_shadow[2] a * x + b * 3 * y^2 # 2 + 37.5 = 39.5
306306
end
307307

308308
@testset "Enzyme ReverseWithPrimal: IIP with Duplicated args" begin
@@ -432,7 +432,7 @@ end
432432
)
433433

434434
du = [0.0]; du_shadow = [1.0]
435-
u = [3.0]; u_shadow = [0.0]
435+
u = [3.0]; u_shadow = [0.0]
436436

437437
rconfig = EnzymeRules.RevConfig{false, false, 1, (false, false), false, false}()
438438
aug = EnzymeRules.augmented_primal(
@@ -515,4 +515,3 @@ end
515515
@test du_h[1] 2.0 * 3.5 # primal: u[1] * t = 7.0
516516
@test ddu_h[1] 2.0 # ∂(u[1]*t)/∂t = u[1]
517517
end
518-

0 commit comments

Comments
 (0)