-
Notifications
You must be signed in to change notification settings - Fork 100
/
Copy pathAutodiff.jl
108 lines (90 loc) · 3.36 KB
/
Autodiff.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
function autodiff_array_gradient(a,i_to_x)
i_to_cfg = lazy_map(ConfigMap(ForwardDiff.gradient),i_to_x)
i_to_xdual = lazy_map(DualizeMap(ForwardDiff.gradient),i_to_x)
i_to_ydual = a(i_to_xdual)
i_to_result = lazy_map(AutoDiffMap(ForwardDiff.gradient),i_to_ydual,i_to_x,i_to_cfg)
i_to_result
end
function autodiff_array_jacobian(a,i_to_x)
i_to_cfg = lazy_map(ConfigMap(ForwardDiff.jacobian),i_to_x)
i_to_xdual = lazy_map(DualizeMap(ForwardDiff.jacobian),i_to_x)
i_to_ydual = a(i_to_xdual)
i_to_result = lazy_map(AutoDiffMap(ForwardDiff.jacobian),i_to_ydual,i_to_x,i_to_cfg)
i_to_result
end
function autodiff_array_hessian(a,i_to_x)
agrad = i_to_y -> autodiff_array_gradient(a,i_to_y)
autodiff_array_jacobian(agrad,i_to_x)
end
function autodiff_array_gradient(a,i_to_x,j_to_i)
i_to_xdual = lazy_map(DualizeMap(ForwardDiff.gradient),i_to_x)
j_to_ydual = a(i_to_xdual)
j_to_x = lazy_map(Reindex(i_to_x),j_to_i)
j_to_cfg = lazy_map(ConfigMap(ForwardDiff.gradient),j_to_x)
j_to_result = lazy_map(AutoDiffMap(ForwardDiff.gradient),j_to_ydual,j_to_x,j_to_cfg)
j_to_result
end
function autodiff_array_jacobian(a,i_to_x,j_to_i)
i_to_xdual = lazy_map(DualizeMap(ForwardDiff.jacobian),i_to_x)
j_to_ydual = a(i_to_xdual)
j_to_x = lazy_map(Reindex(i_to_x),j_to_i)
j_to_cfg = lazy_map(ConfigMap(ForwardDiff.jacobian),j_to_x)
j_to_result = lazy_map(AutoDiffMap(ForwardDiff.jacobian),j_to_ydual,j_to_x,j_to_cfg)
j_to_result
end
function autodiff_array_hessian(a,i_to_x,i_to_j)
agrad = i_to_y -> autodiff_array_gradient(a,i_to_y,i_to_j)
autodiff_array_jacobian(agrad,i_to_x,i_to_j)
end
struct ConfigMap{F} <: Map
f::F
end
# TODO Prescribing long chunk size can lead to slow compilation times!
function return_cache(k::ConfigMap{typeof(ForwardDiff.gradient)},x)
cfg = ForwardDiff.GradientConfig(nothing,x,ForwardDiff.Chunk{length(x)}())
cfg
end
function return_cache(k::ConfigMap{typeof(ForwardDiff.jacobian)},x)
cfg = ForwardDiff.JacobianConfig(nothing,x,ForwardDiff.Chunk{length(x)}())
cfg
end
function evaluate!(cfg,k::ConfigMap,x)
cfg
end
struct DualizeMap{F} <: Map
f::F
end
function return_cache(k::DualizeMap,x)
return_cache(ConfigMap(k.f),x)
end
function evaluate!(cfg,k::DualizeMap,x)
xdual = cfg.duals
ForwardDiff.seed!(xdual, x, cfg.seeds)
xdual
end
struct AutoDiffMap{F} <: Map
f::F
end
function return_cache(k::AutoDiffMap,ydual,x,cfg::ForwardDiff.GradientConfig{T}) where T
ydual isa Real || throw(ForwardDiff.GRAD_ERROR)
result = similar(x, ForwardDiff.valtype(ydual))
result
end
function evaluate!(result,k::AutoDiffMap,ydual,x,cfg::ForwardDiff.GradientConfig{T}) where T
@notimplementedif ForwardDiff.chunksize(cfg) != length(x)
@notimplementedif length(result) != length(x)
result = ForwardDiff.extract_gradient!(T, result, ydual)
return result
end
function return_cache(k::AutoDiffMap,ydual,x,cfg::ForwardDiff.JacobianConfig{T,V,N}) where {F,T,V,N}
ydual isa AbstractArray || throw(ForwardDiff.JACOBIAN_ERROR)
result = similar(ydual, ForwardDiff.valtype(eltype(ydual)), length(ydual), N)
result
end
function evaluate!(result,k::AutoDiffMap,ydual,x,cfg::ForwardDiff.JacobianConfig{T,V,N}) where {F,T,V,N}
@notimplementedif ForwardDiff.chunksize(cfg) != length(x)
@notimplementedif size(result,2) != length(x)
ForwardDiff.extract_jacobian!(T, result, ydual, N)
ForwardDiff.extract_value!(T, result, ydual)
return result
end