Skip to content

Commit d3af887

Browse files
committed
Merge branch 'main' into gd/reac
2 parents c7e7598 + 0dd1abf commit d3af887

52 files changed

Lines changed: 527 additions & 381 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
22
version: 2
3+
enable-beta-ecosystems: true # Julia ecosystem
34
updates:
45
- package-ecosystem: "github-actions"
56
directory: "/" # Location of package manifests
67
schedule:
78
interval: "weekly"
9+
- package-ecosystem: "julia"
10+
directories: # Location of Julia projects
11+
- "/DifferentiationInterface"
12+
- "/DifferentiationInterface/docs"
13+
- "/DifferentiationInterface/test"
14+
- "/DifferentiationInterfaceTest"
15+
- "/DifferentiationInterfaceTest/docs"
16+
- "/DifferentiationInterfaceTest/test"
17+
schedule:
18+
interval: "daily"
19+
groups:
20+
# Group all Julia package updates into a single PR:
21+
all-julia-packages:
22+
patterns:
23+
- "*"
24+
ignore:
25+
- dependency-name: "Diffractor"
26+
versions: ["<= 0.2.10"]

.github/workflows/CompatHelper.yml

Lines changed: 0 additions & 52 deletions
This file was deleted.

.github/workflows/Documentation.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
dir: './DifferentiationInterfaceTest'
3636

3737
steps:
38-
- uses: actions/checkout@v5
38+
- uses: actions/checkout@v6
3939
- uses: julia-actions/setup-julia@v2
4040
with:
4141
version: '1' # TODO: 1

.github/workflows/PreCommit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
pre-commit:
1919
runs-on: ubuntu-latest
2020
steps:
21-
- uses: actions/checkout@v5
21+
- uses: actions/checkout@v6
2222
- uses: julia-actions/setup-julia@v2
2323
- uses: julia-actions/cache@v2
2424
- run: julia -e 'using Pkg; Pkg.add("Runic")'

.github/workflows/Test.yml

Lines changed: 99 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,105 @@ concurrency:
1616
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
1717

1818
jobs:
19-
test-DI:
20-
name: ${{ matrix.version }} - DI (${{ matrix.group }})
19+
# test-DI-Core:
20+
# name: ${{ matrix.version }} - DI Core (${{ matrix.group }})
21+
# runs-on: ubuntu-latest
22+
# if: ${{ !contains(github.event.pull_request.labels.*.name, 'skipci') }}
23+
# timeout-minutes: 120
24+
# permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
25+
# actions: write
26+
# contents: read
27+
# strategy:
28+
# fail-fast: false # TODO: toggle
29+
# matrix:
30+
# version:
31+
# - '1.10'
32+
# - '1.11'
33+
# - '1.12'
34+
# group:
35+
# - Internals
36+
# - SimpleFiniteDiff
37+
# - ZeroBackends
38+
# skip_lts:
39+
# - ${{ github.event.pull_request.draft }}
40+
# skip_pre:
41+
# - ${{ github.event.pull_request.draft }}
42+
# exclude:
43+
# - skip_lts: true
44+
# version: '1.10'
45+
# - skip_pre: true
46+
# version: '1.12'
47+
# env:
48+
# JULIA_DI_TEST_TYPE: 'Core'
49+
# JULIA_DI_TEST_GROUP: ${{ matrix.group }}
50+
# JULIA_DI_PR_DRAFT: ${{ github.event.pull_request.draft }}
51+
# steps:
52+
# - uses: actions/checkout@v6
53+
# - uses: julia-actions/setup-julia@v2
54+
# with:
55+
# version: ${{ matrix.version }}
56+
# arch: x64
57+
# - uses: julia-actions/cache@v2
58+
# - name: Install dependencies & run tests
59+
# run: julia --color=yes -e '
60+
# using Pkg;
61+
# Pkg.activate("./DifferentiationInterface/test");
62+
# if VERSION < v"1.11";
63+
# Pkg.rm("DifferentiationInterfaceTest");
64+
# Pkg.resolve();
65+
# else;
66+
# Pkg.develop(; path="./DifferentiationInterfaceTest");
67+
# end;
68+
# Pkg.activate("./DifferentiationInterface");
69+
# test_kwargs = (; allow_reresolve=false, coverage=true);
70+
# if ENV["JULIA_DI_PR_DRAFT"] == "true";
71+
# Pkg.test("DifferentiationInterface"; julia_args=["-O1"], test_kwargs...);
72+
# else;
73+
# Pkg.test("DifferentiationInterface"; test_kwargs...);
74+
# end;'
75+
# - uses: julia-actions/julia-processcoverage@v1
76+
# with:
77+
# directories: ./DifferentiationInterface/src,./DifferentiationInterface/ext,./DifferentiationInterface/test
78+
# - uses: codecov/codecov-action@v5
79+
# with:
80+
# files: lcov.info
81+
# flags: DI
82+
# token: ${{ secrets.CODECOV_TOKEN }}
83+
# fail_ci_if_error: false
84+
85+
test-DI-Backend:
86+
name: ${{ matrix.version }} - DI Back (${{ matrix.group }})
2187
runs-on: ubuntu-latest
2288
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skipci') }}
2389
timeout-minutes: 120
2490
permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
2591
actions: write
2692
contents: read
2793
strategy:
28-
fail-fast: true # TODO: toggle
94+
fail-fast: false # TODO: toggle
2995
matrix:
3096
version:
3197
# - '1.10'
3298
- '1.11'
33-
- '1.12'
99+
# - '1.12'
34100
group:
35-
# - Core/Internals
36-
# - Back/DifferentiateWith
37-
# - Core/SimpleFiniteDiff
38-
# - Back/SparsityDetector
39-
# - Core/ZeroBackends
40-
# - Back/ChainRules
41-
# # - Back/Diffractor
42-
# - Back/Enzyme
43-
# - Back/FastDifferentiation
44-
# - Back/FiniteDiff
45-
# - Back/FiniteDifferences
46-
# - Back/ForwardDiff
47-
# - Back/GTPSA
48-
# - Back/Mooncake
49-
# - Back/PolyesterForwardDiff
50-
- Back/Reactant
51-
# - Back/ReverseDiff
52-
# - Back/Symbolics
53-
# - Back/Tracker
54-
# - Back/Zygote
101+
# - ChainRules
102+
# - DifferentiateWith
103+
# - Diffractor
104+
# - Enzyme
105+
# - FastDifferentiation
106+
# - FiniteDiff
107+
# - FiniteDifferences
108+
# - ForwardDiff
109+
# - GTPSA
110+
# - Mooncake
111+
# - PolyesterForwardDiff
112+
- Reactant
113+
# - ReverseDiff
114+
# - SparsityDetector
115+
# - Symbolics
116+
# - Tracker
117+
# - Zygote
55118
skip_lts:
56119
- ${{ github.event.pull_request.draft }}
57120
skip_pre:
@@ -62,41 +125,29 @@ jobs:
62125
- skip_pre: true
63126
version: '1.12'
64127
- version: '1.11'
65-
group: Back/ChainRules
66-
- version: '1.12'
67-
group: Back/Enzyme
128+
group: ChainRules
68129
- version: '1.12'
69-
group: Back/Reactant
130+
group: Enzyme
70131
- version: '1.12'
71-
group: Back/DifferentiateWith
132+
group: DifferentiateWith
72133
env:
134+
JULIA_DI_TEST_TYPE: 'Back'
73135
JULIA_DI_TEST_GROUP: ${{ matrix.group }}
74136
JULIA_DI_PR_DRAFT: ${{ github.event.pull_request.draft }}
75137
steps:
76-
- uses: actions/checkout@v5
138+
- uses: actions/checkout@v6
77139
- uses: julia-actions/setup-julia@v2
78140
with:
79141
version: ${{ matrix.version }}
80142
arch: x64
81143
- uses: julia-actions/cache@v2
82144
- name: Install dependencies & run tests
83-
run: julia --color=yes -e '
145+
run: julia --code-coverage=user --color=yes -e '
84146
using Pkg;
85-
Pkg.Registry.update();
86-
Pkg.activate("./DifferentiationInterface/test");
87-
if VERSION < v"1.11";
88-
Pkg.rm("DifferentiationInterfaceTest");
89-
Pkg.resolve();
90-
else;
91-
Pkg.develop(; path="./DifferentiationInterfaceTest");
92-
end;
93-
Pkg.activate("./DifferentiationInterface");
94-
test_kwargs = (; allow_reresolve=false, coverage=true);
95-
if ENV["JULIA_DI_PR_DRAFT"] == "true";
96-
Pkg.test("DifferentiationInterface"; julia_args=["-O1"], test_kwargs...);
97-
else;
98-
Pkg.test("DifferentiationInterface"; test_kwargs...);
99-
end;'
147+
group = ENV["JULIA_DI_TEST_GROUP"];
148+
Pkg.activate("./DifferentiationInterface/test/Back/$group");
149+
Pkg.develop([PackageSpec(path="./DifferentiationInterface"), PackageSpec(path="./DifferentiationInterfaceTest")]);
150+
include("./DifferentiationInterface/test/Back/run_backend.jl");'
100151
- uses: julia-actions/julia-processcoverage@v1
101152
with:
102153
directories: ./DifferentiationInterface/src,./DifferentiationInterface/ext,./DifferentiationInterface/test
@@ -116,7 +167,7 @@ jobs:
116167
# actions: write
117168
# contents: read
118169
# strategy:
119-
# fail-fast: true
170+
# fail-fast: false # TODO: toggle
120171
# matrix:
121172
# version:
122173
# - '1.10'
@@ -140,7 +191,7 @@ jobs:
140191
# JULIA_DIT_TEST_GROUP: ${{ matrix.group }}
141192
# JULIA_DI_PR_DRAFT: ${{ github.event.pull_request.draft }}
142193
# steps:
143-
# - uses: actions/checkout@v5
194+
# - uses: actions/checkout@v6
144195
# - uses: julia-actions/setup-julia@v2
145196
# with:
146197
# version: ${{ matrix.version }}

DifferentiationInterface/docs/src/dev/math.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,34 @@ It is inspired by
1010

1111
Consider a mathematical function $f(x, c, s) = y$ where
1212

13-
- $x \in \mathcal{X}$ is the active argument (the one being differentiated)
14-
- $c \in \mathcal{C}$ is a constant argument (corresponds to [`Constant`](@ref) contexts)
15-
- $s \in \mathcal{S}$ is a scratch argument (corresponds to [`Cache`](@ref) contexts)
16-
- $y \in \mathcal{Y}$ is the output
13+
- $x \in \mathcal{X}$ is the active argument (the one being differentiated)
14+
- $c \in \mathcal{C}$ is a constant argument (corresponds to [`Constant`](@ref) contexts)
15+
- $s \in \mathcal{S}$ is a scratch argument (corresponds to [`Cache`](@ref) contexts)
16+
- $y \in \mathcal{Y}$ is the output
1717

1818
In Julia code, some of the input arguments might be mutated, while the output may be written to as well.
1919
Therefore, the proper model is a function $\phi(x_0, c_0, s_0, y_0) = (x_1, c_1, s_1, y_1)$ where $a_0$ is the state of argument $a$ before $f$ is run, while $a_1$ is its state after $a$ is run.
2020

2121
DI makes the following hypotheses on the implementation of $f$ (aka the behavior of $\phi$):
2222

23-
1. The active argument $x$ is not mutated, so $x_1 = x_0$
24-
2. The constant argument $c$ is not mutated, so $c_1 = c_0$
25-
3. The initial value of the scratch argument $s_0$ does not matter
26-
4. The initial value of the output $y_0$ does not matter
23+
1. The active argument $x$ is not mutated, so $x_1 = x_0$.
24+
2. The constant argument $c$ is not mutated, so $c_1 = c_0$.
25+
3. The initial value of the scratch argument $s_0$ does not matter. It does not affect any of the states $x_1$, $c_1$, $s_1$, $y_1$.
26+
4. The initial value of the output $y_0$ does not matter. It does not affect any of the states $x_1$, $c_1$, $s_1$, $y_1$.
2727

2828
## Forward mode
2929

3030
We want to compute a Jacobian-Vector Product (JVP) $\dot{y} = \left(\frac{\partial f}{\partial x}\right) \dot{x}$ where $\dot{x} \in \mathcal{X}$ is an input tangent.
3131

3232
To do that, we run our AD backend on $\phi$ with input tangents $(\dot{x}_0, \dot{c}_0, \dot{s}_0, \dot{y}_0)$ and obtain $(\dot{x}_1, \dot{c}_1, \dot{s}_1, \dot{y}_1)$.
33-
The interesting value is
33+
The value of interest is
3434
$$\dot{y}_1 = \frac{\partial y_1}{\partial x_0} \dot{x}_0 + \frac{\partial y_1}{\partial c_0} \dot{c}_0 + \frac{\partial y_1}{\partial s_0} \dot{s}_0 + \frac{\partial y_1}{\partial y_0} \dot{y}_0$$
3535

3636
Thanks to our hypotheses 3 and 4 on the function's implementation, $\frac{\partial y_1}{\partial s_0} = 0$ and $\frac{\partial y_1}{\partial y_0} = 0$, so we are left with:
3737
$$\dot{y}_1 = \frac{\partial y_1}{\partial x_0} \dot{x_0} + \frac{\partial y_1}{\partial c_0} \dot{c_0}$$
3838

39-
Thus, as long as $\dot{c}_0 = 0$, the output tangent $\dot{y}_1$ contains the correct JVP.
40-
Let us now look at $\dot{s}_1$ with the help of hypothesis 2:
39+
Thus, as long as we set $\dot{c}_0 = 0$, the output tangent $\dot{y}_1$ contains the correct JVP.
40+
Let us now look at $\dot{c}_1$ with the help of hypothesis 2:
4141
$$\dot{c}_1 = \frac{\partial c_1}{\partial x_0} \dot{x}_0 + \frac{\partial c_1}{\partial c_0} \dot{c}_0 + \frac{\partial c_1}{\partial s_0} \dot{s}_0 + \frac{\partial c_1}{\partial y_0} \dot{y}_0 = \dot{c}_0$$
4242

4343
The tangent of $c$ will always be preserved by differentiation.
@@ -47,14 +47,14 @@ The tangent of $c$ will always be preserved by differentiation.
4747
We want to compute a Vector-Jacobian Product (VJP) $\bar{x} = \left(\frac{\partial f}{\partial x}\right)^* \bar{y}$ where $\bar{y} \in \mathcal{Y}$ is an output sensivity.
4848

4949
To do that, we run our AD backend on $\phi$ with output sensitivities $(\bar{x}_1, \bar{c}_1, \bar{s}_1, \bar{y}_1)$ and obtain $(\bar{x}_0, \bar{c}_0, \bar{s}_0, \bar{y}_0)$.
50-
The interesting value is
50+
The value of interest is
5151
$$\bar{x}_0 = \left(\frac{\partial x_1}{\partial x_0}\right)^* \bar{x}_1 + \left(\frac{\partial c_1}{\partial x_0}\right)^* \bar{c}_1 + \left(\frac{\partial s_1}{\partial x_0}\right)^* \bar{s}_1 + \left(\frac{\partial y_1}{\partial x_0}\right)^* \bar{y}_1$$
5252

53-
Thanks to our hypotheses 1 and 2 on the function's implementation, $\frac{\partial x_1}{\partial x_0} = I$ and $\frac{\partial c_1}{\partial x_0} = 0$, so we are left with:
53+
Thanks to our hypotheses 1 and 2 on the function's implementation, $\frac{\partial x_1}{\partial x_0} = I$ and $\frac{\partial c_1}{\partial x_0} = \frac{\partial c_0}{\partial x_0} =0$, so we are left with:
5454
$$\bar{x}_0 = \bar{x}_1 + \left(\frac{\partial s_1}{\partial x_0}\right)^* \bar{s}_1 + \left(\frac{\partial y_1}{\partial x_0}\right)^* \bar{y}_1$$
5555

56-
Thus, as long as $\bar{x}_1 = 0$ and $\bar{s}_1 = 0$, the input sensitivity $\bar{x}_0$ contains the correct VJP.
57-
Let us now look at $\bar{s}_0$ with the help of hypothesis 3:
56+
Thus, as long as we set $\bar{x}_1 = 0$ and $\bar{s}_1 = 0$, the input sensitivity $\bar{x}_0$ contains the correct VJP.
57+
Let us now look at $\bar{s}_0$ with the help of hypothesis 3, which tells us that $\frac{\partial x_1}{\partial s_0} = 0$, $\frac{\partial c_1}{\partial s_0} = 0$, $\frac{\partial s_1}{\partial s_0} = 0$, and $\frac{\partial y_1}{\partial s_0} = 0$:
5858

5959
$$\bar{s}_0 = \left(\frac{\partial x_1}{\partial s_0}\right)^* \bar{x}_1 + \left(\frac{\partial c_1}{\partial s_0}\right)^* \bar{c}_1 + \left(\frac{\partial s_1}{\partial s_0}\right)^* \bar{s}_1 + \left(\frac{\partial y_1}{\partial s_0}\right)^* \bar{y}_1 = 0$$
6060

0 commit comments

Comments
 (0)