6
6
7
7
const TAG = :ReverseAD
8
8
9
+ """
10
+ const MAX_CHUNK::Int = 10
11
+
12
+ An upper bound on the chunk sie for forward-over-reverse. Increasing this could
13
+ improve performance at the cost of extra memory allocation. It has been 10 for a
14
+ long time, and nobody seems to have complained.
15
+ """
16
+ const MAX_CHUNK = 10
17
+
9
18
"""
10
19
_eval_hessian(
11
20
d::NLPEvaluator,
@@ -23,46 +32,30 @@ Returns the number of non-zeros in the computed Hessian, which will be used to
23
32
update the offset for the next call.
24
33
"""
25
34
function _eval_hessian (
26
- d:: NLPEvaluator ,
27
- f:: _FunctionStorage ,
28
- H:: AbstractVector{Float64} ,
29
- λ:: Float64 ,
30
- offset:: Int ,
31
- ):: Int
32
- chunk = min (size (f. seed_matrix, 2 ), d. max_chunk)
33
- # As a performance optimization, skip dynamic dispatch if the chunk is 1.
34
- if chunk == 1
35
- return _eval_hessian_inner (d, f, H, λ, offset, Val (1 ))
36
- else
37
- return _eval_hessian_inner (d, f, H, λ, offset, Val (chunk))
38
- end
39
- end
40
-
41
- function _eval_hessian_inner (
42
35
d:: NLPEvaluator ,
43
36
ex:: _FunctionStorage ,
44
37
H:: AbstractVector{Float64} ,
45
38
scale:: Float64 ,
46
39
nzcount:: Int ,
47
- :: Val{CHUNK} ,
48
- ) where {CHUNK}
40
+ ):: Int
49
41
if ex. linearity == LINEAR
50
42
@assert length (ex. hess_I) == 0
51
43
return 0
52
44
end
45
+ chunk = min (size (ex. seed_matrix, 2 ), d. max_chunk)
53
46
Coloring. prepare_seed_matrix! (ex. seed_matrix, ex. rinfo)
54
47
# Compute hessian-vector products
55
48
num_products = size (ex. seed_matrix, 2 ) # number of hessian-vector products
56
- num_chunks = div (num_products, CHUNK )
49
+ num_chunks = div (num_products, chunk )
57
50
@assert size (ex. seed_matrix, 1 ) == length (ex. rinfo. local_indices)
58
- for offset in 1 : CHUNK : (CHUNK * num_chunks)
59
- _eval_hessian_chunk (d, ex, offset, CHUNK, Val (CHUNK) )
51
+ for offset in 1 : chunk : (chunk * num_chunks)
52
+ _eval_hessian_chunk (d, ex, offset, chunk, chunk )
60
53
end
61
54
# leftover chunk
62
- remaining = num_products - CHUNK * num_chunks
55
+ remaining = num_products - chunk * num_chunks
63
56
if remaining > 0
64
- offset = CHUNK * num_chunks + 1
65
- _eval_hessian_chunk (d, ex, offset, remaining, Val (CHUNK) )
57
+ offset = chunk * num_chunks + 1
58
+ _eval_hessian_chunk (d, ex, offset, remaining, chunk )
66
59
end
67
60
want, got = nzcount + length (ex. hess_I), length (H)
68
61
if want > got
@@ -90,32 +83,45 @@ function _eval_hessian_chunk(
90
83
ex:: _FunctionStorage ,
91
84
offset:: Int ,
92
85
chunk:: Int ,
93
- :: Val{CHUNK} ,
94
- ) where {CHUNK}
86
+ chunk_size :: Int ,
87
+ )
95
88
for r in eachindex (ex. rinfo. local_indices)
96
89
# set up directional derivatives
97
90
@inbounds idx = ex. rinfo. local_indices[r]
98
91
# load up ex.seed_matrix[r,k,k+1,...,k+remaining-1] into input_ϵ
99
92
for s in 1 : chunk
100
- # If `chunk < CHUNK `, leaves junk in the unused components
101
- d. input_ϵ[(idx- 1 )* CHUNK + s] = ex. seed_matrix[r, offset+ s- 1 ]
93
+ # If `chunk < chunk_size `, leaves junk in the unused components
94
+ d. input_ϵ[(idx- 1 )* chunk_size + s] = ex. seed_matrix[r, offset+ s- 1 ]
102
95
end
103
96
end
104
- _hessian_slice_inner (d, ex, Val (CHUNK) )
97
+ _hessian_slice_inner (d, ex, chunk_size )
105
98
fill! (d. input_ϵ, 0.0 )
106
99
# collect directional derivatives
107
100
for r in eachindex (ex. rinfo. local_indices)
108
101
@inbounds idx = ex. rinfo. local_indices[r]
109
102
# load output_ϵ into ex.seed_matrix[r,k,k+1,...,k+remaining-1]
110
103
for s in 1 : chunk
111
- ex. seed_matrix[r, offset+ s- 1 ] = d. output_ϵ[(idx- 1 )* CHUNK + s]
104
+ ex. seed_matrix[r, offset+ s- 1 ] = d. output_ϵ[(idx- 1 )* chunk_size + s]
112
105
end
113
106
end
114
107
return
115
108
end
116
109
117
- function _hessian_slice_inner (d, ex, :: Val{CHUNK} ) where {CHUNK}
118
- T = ForwardDiff. Partials{CHUNK,Float64} # This is our element type.
110
+ # A wrapper function to avoid dynamic dispatch.
111
+ function _generate_hessian_slice_inner ()
112
+ exprs = map (1 : MAX_CHUNK) do id
113
+ T = ForwardDiff. Partials{id,Float64}
114
+ return :(return _hessian_slice_inner (d, ex, $ T))
115
+ end
116
+ return MOI. Nonlinear. _create_binary_switch (1 : MAX_CHUNK, exprs)
117
+ end
118
+
119
+ @eval function _hessian_slice_inner (d, ex, id:: Int )
120
+ $ (_generate_hessian_slice_inner ())
121
+ return error (" Invalid chunk size: $id " )
122
+ end
123
+
124
+ function _hessian_slice_inner (d, ex, :: Type{T} ) where {T}
119
125
fill! (d. output_ϵ, 0.0 )
120
126
output_ϵ = _reinterpret_unsafe (T, d. output_ϵ)
121
127
subexpr_forward_values_ϵ =
0 commit comments