-
Notifications
You must be signed in to change notification settings - Fork 28
/
incomplete.jl
140 lines (130 loc) · 4.74 KB
/
incomplete.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# To pass incomplete specifications, we provide the "only_"
# family of functions. It allows the users to simply provide
# fg! for optimization or fj! for solving systems of equations
# and have NLSolversBase wrap them up properly so "F" can be
# calculated on its own and the save for partial derivatives.
# Note, that for TwiceDifferentiable we cannot provide con-
# structors if h == nothing, as that requires automatic dif-
# fferentiation of some sort.
# Mutating version
only_fg!(fg, h = nothing) = (nothing, nothing, fg, h, true)
only_fj!(fj, h = nothing) = (nothing, nothing, fj, h, true)
only_g!_and_fg!(g, fg, h = nothing) = (nothing, g, fg, h, true)
only_j!_and_fj!(j, fj, h = nothing) = (nothing, j, fj, h, true)
only_f_and_fg!(f, fg, h = nothing) = (f, nothing, fg, h, true)
only_f!_and_fj!(f, fj, h = nothing) = (f, nothing, fj, h, true)
# Non-mutating version
only_fg(fg, h = nothing) = (nothing, nothing, fg, h, false)
only_fj(fj, h = nothing) = (nothing, nothing, fj, h, false)
only_g_and_fg(g, fg, h = nothing) = (nothing, g, fg, h, false)
only_j_and_fj(j, fj, h = nothing) = (nothing, j, fj, h, false)
only_f_and_fg(f, fg, h = nothing) = (f, nothing, fg, h, false)
only_f_and_fj(f, fj, h = nothing) = (f, nothing, fj, h, false)
function make_f_from_t(t, x, F::TF) where TF
fdf = t[3]
if t[end]
# Mutating version
if TF <: Real
return f(x) = fdf(nothing, x)
else
return (F, x) -> fdf(F, nothing, x)
end
else
# Non-mutating version
# The contract with the user is that fdf returns (F, DF)
# and then we simply need to pick out the first element
# of whatever fdf returns.
if TF <: Real
return x -> fdf(x)[1]
else
return (F, x) -> copy!(F, fdf(x)[1])
end
end
end
function make_f_and_df_from_t(t, x, F::TF) where TF
fdf = t[3]
if t[end]
# Mutating version
if TF <: Real
f(x) = fdf(nothing, x)
function g!(G, x)
fdf(G, x)
# return `nothing` to cause a high chance of
# program failure if users accidentally use
# the output of g!
return nothing
end
return f, g!, fdf
else
f!(F, x) = fdf(F, nothing, x)
j!(J, x) = fdf(nothing, J, x)
return f!, j!, fdf
end
else
# Non-mutating version
# The contract with the user is that fdf returns (F, DF)
# and then we simply need to pick out the first element
# of whatever fdf returns. We need weird names to avoid
# overwritten method warning.
if TF <: Real
ff(x) = fdf(x)[1]
gg!(G, x) = copy!(G, fdf(x)[2])
function ffgg!(G, x)
f, g = fdf(x)
copy!(G, g)
f
end
return ff, gg!, ffgg!
else
ff!(F, x) = copy!(F, fdf(x)[1])
jj!(J, x) = copy!(J, fdf(x)[2])
function ffjj!(F, J, x)
f, j = fdf(x)
copy!(J, j)
copy!(F, f)
end
return ff!, jj!, ffjj!
end
end
end
function make_df_from_t(t, x, F::TF) where TF
fdf = t[3]
if t[end]
# Mutating version
if TF <: Real
return fdf
else
return (J, x) -> fdf(nothing, J, x)
end
else
# Non-mutating version
# The contract with the user is that fdf returns (F, DF)
# and then we simply need to pick out the first element
# of whatever fdf returns.
if TF <: Real
return (G, x) -> copy!(G, fdf(x)[2])
else
return (J, x) -> copy!(J, fdf(x)[2])
end
end
end
# Constructors
NonDifferentiable(t::Tuple, x::AbstractArray, F::Real = real(zero(eltype(x)))) =
NonDifferentiable(make_f_from_t(t, x, F), x, F)
NonDifferentiable(t::Tuple, x::AbstractArray, F::AbstractArray) =
NonDifferentiable(make_f_from_t(t, x, F), x, F)
function OnceDifferentiable(t::Tuple, x::AbstractArray, F::Real = real(zero(eltype(x))))
f, g!, fg! = make_f_and_df_from_t(t, x, F)
OnceDifferentiable(f, g!, fg!, x, F)
end
function OnceDifferentiable(t::Tuple, x::AbstractArray, F::AbstractArray)
f!, j!, fj! = make_f_and_df_from_t(t, x, F)
OnceDifferentiable(f!, j!, fj!, x, F)
end
function TwiceDifferentiable(t::Tuple, x::AbstractArray, F::Real = real(zero(eltype(x))))
f, g! = make_f_and_df_from_t(t, x, F)
TwiceDifferentiable(f, g!, t[3], t[4], x, F)
end
function TwiceDifferentiable(t::Tuple{TF, TG, TFG, TH, TB}, x::AbstractArray, F::Real = real(zero(eltype(x)))) where {TF, TG, TFG, TH <: Void, TB}
throw(MethodError())
end