Skip to content

Commit 80fff03

Browse files
yebaiclaude
andcommitted
Rename evaluator API to ADProblems and fold autograd testing into the core interface.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 216232b commit 80fff03

18 files changed

Lines changed: 222 additions & 308 deletions

docs/src/pplapi.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ DerivativeOrder
2626
capabilities
2727
prepare
2828
value_and_gradient
29+
test_autograd
2930
dimension
3031
```

ext/AbstractPPLDifferentiationInterfaceExt.jl

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,12 @@ struct DIPrepared{E,B,C}
88
evaluator::E
99
backend::B
1010
prep::C
11-
dim::Int
1211
end
1312

1413
AbstractPPL.capabilities(::Type{<:DIPrepared}) = DerivativeOrder{1}()
15-
AbstractPPL.dimension(p::DIPrepared) = p.dim
14+
AbstractPPL.dimension(p::DIPrepared) = AbstractPPL.dimension(p.evaluator)
1615

17-
function (p::DIPrepared)(x::AbstractVector{<:AbstractFloat})
18-
length(x) == p.dim || throw(
19-
DimensionMismatch(
20-
"Expected a vector of length $(p.dim), but got length $(length(x))."
21-
),
22-
)
16+
function (p::DIPrepared)(x)
2317
return p.evaluator(x)
2418
end
2519

@@ -29,19 +23,16 @@ end
2923
function AbstractPPL.prepare(
3024
adtype::ADTypes.AbstractADType, problem, x::AbstractVector{<:AbstractFloat}
3125
)
32-
evaluator = AbstractPPL.prepare(problem, x)
26+
evaluator = AbstractPPL.ADProblems.VectorEvaluator(
27+
AbstractPPL.prepare(problem, x), length(x)
28+
)
3329
prep = DI.prepare_gradient(evaluator, adtype, x)
34-
return DIPrepared(evaluator, adtype, prep, length(x))
30+
return DIPrepared(evaluator, adtype, prep)
3531
end
3632

3733
@inline function AbstractPPL.value_and_gradient(
3834
p::DIPrepared, x::AbstractVector{<:AbstractFloat}
3935
)
40-
length(x) == p.dim || throw(
41-
DimensionMismatch(
42-
"Expected a vector of length $(p.dim), but got length $(length(x))."
43-
),
44-
)
4536
return DI.value_and_gradient(p.evaluator, p.prep, p.backend, x)
4637
end
4738

ext/AbstractPPLEnzymeExt.jl

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,25 @@ using Enzyme: Enzyme
66

77
struct EnzymePrepared{E}
88
evaluator::E
9-
dim::Int
109
end
1110

1211
AbstractPPL.capabilities(::Type{<:EnzymePrepared}) = DerivativeOrder{1}()
13-
AbstractPPL.dimension(p::EnzymePrepared) = p.dim
12+
AbstractPPL.dimension(p::EnzymePrepared) = AbstractPPL.dimension(p.evaluator)
1413

15-
function (p::EnzymePrepared)(x::AbstractVector{<:AbstractFloat})
16-
length(x) == p.dim || throw(
17-
DimensionMismatch(
18-
"Expected a vector of length $(p.dim), but got length $(length(x))."
19-
),
20-
)
14+
function (p::EnzymePrepared)(x)
2115
return p.evaluator(x)
2216
end
2317

2418
function AbstractPPL.prepare(::AutoEnzyme, problem, x::AbstractVector{<:AbstractFloat})
25-
evaluator = AbstractPPL.prepare(problem, x)
26-
return EnzymePrepared(evaluator, length(x))
19+
evaluator = AbstractPPL.ADProblems.VectorEvaluator(
20+
AbstractPPL.prepare(problem, x), length(x)
21+
)
22+
return EnzymePrepared(evaluator)
2723
end
2824

2925
@inline function AbstractPPL.value_and_gradient(
3026
p::EnzymePrepared, x::AbstractVector{<:AbstractFloat}
3127
)
32-
length(x) == p.dim || throw(
33-
DimensionMismatch(
34-
"Expected a vector of length $(p.dim), but got length $(length(x))."
35-
),
36-
)
3728
dx = zero(x)
3829
result = Enzyme.autodiff(
3930
Enzyme.set_runtime_activity(Enzyme.ReverseWithPrimal),

ext/AbstractPPLFiniteDifferencesExt.jl

Lines changed: 19 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,87 +5,63 @@ using AbstractPPL.Utils: flatten_to!!, unflatten_to!!
55
using ADTypes: AutoFiniteDifferences
66
using FiniteDifferences: FiniteDifferences
77

8-
struct FDPrepared{F,M,P}
9-
evaluator
8+
struct FDPrepared{E,F,M}
9+
evaluator::E
1010
f::F
1111
fdm::M
12-
inputspec::P
1312
end
1413

1514
AbstractPPL.capabilities(::Type{<:FDPrepared}) = DerivativeOrder{1}()
15+
AbstractPPL.dimension(p::FDPrepared) = AbstractPPL.dimension(p.evaluator)
1616

17-
function AbstractPPL.dimension(::FDPrepared{<:Any,<:Any,<:NamedTuple})
18-
throw(
19-
ArgumentError(
20-
"`dimension` is only available for evaluators prepared with a vector of floating-point numbers.",
21-
),
22-
)
23-
end
24-
function AbstractPPL.dimension(p::FDPrepared{<:Any,<:Any,<:AbstractVector})
25-
return length(p.inputspec)
26-
end
27-
28-
function (p::FDPrepared{<:Any,<:Any,<:NamedTuple})(values::NamedTuple)
29-
typeof(values) === typeof(p.inputspec) || throw(
17+
function (p::FDPrepared{<:AbstractPPL.ADProblems.NamedTupleEvaluator})(values::NamedTuple)
18+
typeof(values) === typeof(p.evaluator.inputspec) || throw(
3019
ArgumentError(
3120
"Expected the same NamedTuple structure that was used to prepare this evaluator.",
3221
),
3322
)
3423
return p.evaluator(values)
3524
end
3625

37-
function (p::FDPrepared{<:Any,<:Any,<:NamedTuple})(x::AbstractVector)
38-
return p.f(x)
39-
end
40-
41-
function (p::FDPrepared{<:Any,<:Any,<:AbstractVector})(x::AbstractVector{<:AbstractFloat})
42-
length(x) == length(p.inputspec) || throw(
43-
DimensionMismatch(
44-
"Expected a vector of length $(length(p.inputspec)), but got length $(length(x)).",
45-
),
46-
)
47-
return p.evaluator(x)
48-
end
49-
5026
function (p::FDPrepared)(x)
51-
throw(MethodError(p, (x,)))
27+
return p.evaluator(x)
5228
end
5329

5430
function AbstractPPL.prepare(adtype::AutoFiniteDifferences, problem, values::NamedTuple)
55-
evaluator = AbstractPPL.prepare(problem, values)
31+
evaluator = AbstractPPL.ADProblems.NamedTupleEvaluator(
32+
AbstractPPL.prepare(problem, values), values
33+
)
5634
f = x -> evaluator(unflatten_to!!(values, x))
57-
return FDPrepared(evaluator, f, adtype.fdm, values)
35+
return FDPrepared(evaluator, f, adtype.fdm)
5836
end
5937

6038
function AbstractPPL.prepare(
6139
adtype::AutoFiniteDifferences, problem, x::AbstractVector{<:AbstractFloat}
6240
)
63-
evaluator = AbstractPPL.prepare(problem, x)
64-
return FDPrepared(evaluator, evaluator, adtype.fdm, x)
41+
evaluator = AbstractPPL.ADProblems.VectorEvaluator(
42+
AbstractPPL.prepare(problem, x), length(x)
43+
)
44+
return FDPrepared(evaluator, evaluator, adtype.fdm)
6545
end
6646

6747
function AbstractPPL.value_and_gradient(
68-
p::FDPrepared{<:Any,<:Any,<:NamedTuple}, values::NamedTuple
48+
p::FDPrepared{<:AbstractPPL.ADProblems.NamedTupleEvaluator}, values::NamedTuple
6949
)
70-
typeof(values) === typeof(p.inputspec) || throw(
50+
typeof(values) === typeof(p.evaluator.inputspec) || throw(
7151
ArgumentError(
7252
"Expected the same NamedTuple structure that was used to prepare this evaluator.",
7353
),
7454
)
7555
x = flatten_to!!(nothing, values)
7656
val = p.evaluator(values)
7757
grad = FiniteDifferences.grad(p.fdm, p.f, x)[1]
78-
return (val, unflatten_to!!(p.inputspec, grad))
58+
return (val, unflatten_to!!(p.evaluator.inputspec, grad))
7959
end
8060

8161
function AbstractPPL.value_and_gradient(
82-
p::FDPrepared{<:Any,<:Any,<:AbstractVector}, x::AbstractVector{<:AbstractFloat}
62+
p::FDPrepared{<:AbstractPPL.ADProblems.VectorEvaluator},
63+
x::AbstractVector{<:AbstractFloat},
8364
)
84-
length(x) == length(p.inputspec) || throw(
85-
DimensionMismatch(
86-
"Expected a vector of length $(length(p.inputspec)), but got length $(length(x)).",
87-
),
88-
)
8965
val = p.evaluator(x)
9066
grad = FiniteDifferences.grad(p.fdm, p.f, x)[1]
9167
return (val, grad)

ext/AbstractPPLForwardDiffExt.jl

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,79 +5,62 @@ using AbstractPPL.Utils: flatten_to!!, unflatten_to!!
55
using ADTypes: AutoForwardDiff
66
using ForwardDiff: ForwardDiff
77

8-
struct ForwardDiffPrepared{F,C,R,P}
9-
evaluator
8+
struct ForwardDiffPrepared{E,F,C,R}
9+
evaluator::E
1010
f::F
1111
config::C
1212
result::R
13-
inputspec::P
1413
end
1514

1615
AbstractPPL.capabilities(::Type{<:ForwardDiffPrepared}) = DerivativeOrder{1}()
16+
AbstractPPL.dimension(p::ForwardDiffPrepared) = AbstractPPL.dimension(p.evaluator)
1717

18-
function AbstractPPL.dimension(::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:NamedTuple})
19-
throw(
20-
ArgumentError(
21-
"`dimension` is only available for evaluators prepared with a vector of floating-point numbers.",
22-
),
23-
)
24-
end
25-
function AbstractPPL.dimension(p::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:AbstractVector})
26-
return length(p.inputspec)
18+
function (p::ForwardDiffPrepared)(x::AbstractVector{<:Integer})
19+
throw(MethodError(p, (x,)))
2720
end
2821

29-
function (p::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:NamedTuple})(values::NamedTuple)
30-
typeof(values) === typeof(p.inputspec) || throw(
22+
function (p::ForwardDiffPrepared{<:AbstractPPL.ADProblems.NamedTupleEvaluator})(
23+
values::NamedTuple
24+
)
25+
typeof(values) === typeof(p.evaluator.inputspec) || throw(
3126
ArgumentError(
3227
"Expected the same NamedTuple structure that was used to prepare this evaluator.",
3328
),
3429
)
3530
return p.evaluator(values)
3631
end
3732

38-
function (p::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:AbstractVector})(
39-
x::AbstractVector{<:Integer}
40-
)
41-
throw(MethodError(p, (x,)))
42-
end
43-
44-
function (p::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:AbstractVector})(x::AbstractVector)
45-
length(x) == length(p.inputspec) || throw(
46-
DimensionMismatch(
47-
"Expected a vector of length $(length(p.inputspec)), but got length $(length(x)).",
48-
),
49-
)
50-
return p.evaluator(x)
51-
end
52-
5333
function (p::ForwardDiffPrepared)(x)
54-
throw(MethodError(p, (x,)))
34+
return p.evaluator(x)
5535
end
5636

5737
function AbstractPPL.prepare(::AutoForwardDiff, problem, values::NamedTuple)
58-
evaluator = AbstractPPL.prepare(problem, values)
38+
evaluator = AbstractPPL.ADProblems.NamedTupleEvaluator(
39+
AbstractPPL.prepare(problem, values), values
40+
)
5941
x = flatten_to!!(nothing, values)
6042
f = let evaluator = evaluator, values = values
6143
x -> evaluator(unflatten_to!!(values, x))
6244
end
6345
result = ForwardDiff.DiffResults.MutableDiffResult(zero(eltype(x)), (similar(x),))
6446
cfg = ForwardDiff.GradientConfig(f, x)
65-
return ForwardDiffPrepared(evaluator, f, cfg, result, values)
47+
return ForwardDiffPrepared(evaluator, f, cfg, result)
6648
end
6749

6850
function AbstractPPL.prepare(::AutoForwardDiff, problem, x::AbstractVector{<:AbstractFloat})
69-
evaluator = AbstractPPL.prepare(problem, x)
70-
f = evaluator
71-
cfg = ForwardDiff.GradientConfig(f, x)
51+
evaluator = AbstractPPL.ADProblems.VectorEvaluator(
52+
AbstractPPL.prepare(problem, x), length(x)
53+
)
54+
cfg = ForwardDiff.GradientConfig(evaluator, x)
7255
grad_buf = similar(x)
7356
result = ForwardDiff.DiffResults.MutableDiffResult(zero(eltype(x)), (grad_buf,))
74-
return ForwardDiffPrepared(evaluator, f, cfg, result, x)
57+
return ForwardDiffPrepared(evaluator, evaluator, cfg, result)
7558
end
7659

7760
@inline function AbstractPPL.value_and_gradient(
78-
p::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:NamedTuple}, values::NamedTuple
61+
p::ForwardDiffPrepared{<:AbstractPPL.ADProblems.NamedTupleEvaluator}, values::NamedTuple
7962
)
80-
typeof(values) === typeof(p.inputspec) || throw(
63+
typeof(values) === typeof(p.evaluator.inputspec) || throw(
8164
ArgumentError(
8265
"Expected the same NamedTuple structure that was used to prepare this evaluator.",
8366
),
@@ -86,18 +69,13 @@ end
8669
ForwardDiff.gradient!(p.result, p.f, x, p.config)
8770
val = ForwardDiff.DiffResults.value(p.result)
8871
grad = copy(ForwardDiff.DiffResults.gradient(p.result))
89-
return (val, unflatten_to!!(p.inputspec, grad))
72+
return (val, unflatten_to!!(p.evaluator.inputspec, grad))
9073
end
9174

9275
@inline function AbstractPPL.value_and_gradient(
93-
p::ForwardDiffPrepared{<:Any,<:Any,<:Any,<:AbstractVector},
76+
p::ForwardDiffPrepared{<:AbstractPPL.ADProblems.VectorEvaluator},
9477
x::AbstractVector{<:AbstractFloat},
9578
)
96-
length(x) == length(p.inputspec) || throw(
97-
DimensionMismatch(
98-
"Expected a vector of length $(length(p.inputspec)), but got length $(length(x)).",
99-
),
100-
)
10179
ForwardDiff.gradient!(p.result, p.f, x, p.config)
10280
val = ForwardDiff.DiffResults.value(p.result)
10381
grad = copy(ForwardDiff.DiffResults.gradient(p.result))

0 commit comments

Comments
 (0)