Skip to content

Commit f6d6ea8

Browse files
committed
[WIP] dynamic ranges
1 parent f0c1013 commit f6d6ea8

File tree

3 files changed

+537
-18
lines changed

3 files changed

+537
-18
lines changed

src/Numerical/analyze.jl

Lines changed: 146 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,21 @@ function MathOptAnalyzer.analyze(
1717
threshold_dense_entries::Int = 1000,
1818
threshold_small::Float64 = 1e-5,
1919
threshold_large::Float64 = 1e+5,
20+
threshold_dynamic_range_single::Float64 = 1e+6,
21+
threshold_dynamic_range_matrix::Float64 = 1e+8,
2022
)
2123
data = Data()
2224
data.threshold_dense_fill_in = threshold_dense_fill_in
2325
data.threshold_dense_entries = threshold_dense_entries
2426
data.threshold_small = threshold_small
2527
data.threshold_large = threshold_large
28+
data.threshold_dynamic_range_single = threshold_dynamic_range_single
29+
data.threshold_dynamic_range_matrix = threshold_dynamic_range_matrix
2630

2731
# initialize simples data
2832
data.sense = MOI.get(model, MOI.ObjectiveSense())
2933
data.number_of_variables = MOI.get(model, MOI.NumberOfVariables())
30-
sizehint!(data.variables_in_constraints, data.number_of_variables)
34+
sizehint!(data._variables_in_constraints, data.number_of_variables)
3135

3236
# objective pass
3337
objective_type = MOI.get(model, MOI.ObjectiveFunctionType())
@@ -56,13 +60,15 @@ function MathOptAnalyzer.analyze(
5660
# variable index constraints are not counted in the constraints pass
5761
list_of_variables = MOI.get(model, MOI.ListOfVariableIndices())
5862
for var in list_of_variables
59-
if !(var in data.variables_in_constraints)
63+
if !(var in data._variables_in_constraints)
6064
push!(
6165
data.variables_not_in_constraints,
6266
VariableNotInConstraints(var),
6367
)
6468
end
6569
end
70+
# TODO
71+
# compute ranges and dynamic ranges for variables and matrix
6672
sort!(data.dense_rows, by = x -> x.nnz, rev = true)
6773
sort!(data.matrix_small, by = x -> abs(x.coefficient))
6874
sort!(data.matrix_large, by = x -> abs(x.coefficient), rev = true)
@@ -96,13 +102,14 @@ end
96102

97103
function _get_objective_data(data, func::MOI.ScalarAffineFunction)
98104
nnz = 0
105+
_reset_function_range(data)
99106
for term in func.terms
100107
variable = term.variable
101108
coefficient = term.coefficient
102109
if iszero(coefficient)
103110
continue
104111
end
105-
nnz += _update_range(data.objective_range, coefficient)
112+
nnz += _update_function_range(data, coefficient, variable)
106113
if abs(coefficient) < data.threshold_small
107114
push!(
108115
data.objective_small,
@@ -115,9 +122,87 @@ function _get_objective_data(data, func::MOI.ScalarAffineFunction)
115122
)
116123
end
117124
end
125+
range = _function_range(data)
126+
if range > data.threshold_dynamic_range_single
127+
push!(
128+
data.large_dynamic_range_objective,
129+
LargeDynamicRangeObjective(
130+
data._small_coefficient[1][2],
131+
data._large_coefficient[1][2],
132+
range,
133+
),
134+
)
135+
end
136+
_reset_function_range(data)
137+
return
138+
end
139+
140+
function _reset_function_range(data::Data)
141+
empty!(data._large_coefficient)
142+
empty!(data._small_coefficient)
143+
sizehint!(data._large_coefficient, 1)
144+
sizehint!(data._small_coefficient, 1)
118145
return
119146
end
120147

148+
function _function_range(data::Data)
149+
if isempty(data._large_coefficient) || isempty(data._small_coefficient)
150+
return 0.0
151+
end
152+
large = data._large_coefficient[1][1]
153+
small = data._small_coefficient[1][1]
154+
return large / small
155+
end
156+
157+
function _update_function_range(data::Data, value, variable)
158+
if iszero(value)
159+
return 0
160+
end
161+
value = abs(value)
162+
if isempty(data._large_coefficient)
163+
push!(data._large_coefficient, (value, variable))
164+
elseif value > data._large_coefficient[1][1]
165+
data._large_coefficient[1] = (value, variable)
166+
end
167+
if isempty(data._small_coefficient)
168+
push!(data._small_coefficient, (value, variable))
169+
elseif value < data._small_coefficient[1][1]
170+
data._small_coefficient[1] = (value, variable)
171+
end
172+
return 1
173+
end
174+
175+
function _update_constraint_range(data::Data, value, variable, ref)
176+
if iszero(value)
177+
return 0
178+
end
179+
_update_function_range(data, value, variable)
180+
value = abs(value)
181+
#
182+
if isempty(data._large_matrix_coefficient)
183+
push!(data._large_matrix_coefficient, (value, ref, variable))
184+
elseif value > data._large_matrix_coefficient[1][1]
185+
data._large_matrix_coefficient[1] = (value, ref, variable)
186+
end
187+
if isempty(data._small_matrix_coefficient)
188+
push!(data._small_matrix_coefficient, (value, ref, variable))
189+
elseif value < data._small_matrix_coefficient[1][1]
190+
data._small_matrix_coefficient[1] = (value, ref, variable)
191+
end
192+
#
193+
if !haskey(data._large_variable_coefficient, variable)
194+
data._large_variable_coefficient[variable] = (value, ref)
195+
elseif value > data._large_matrix_coefficient[variable][1]
196+
data._large_variable_coefficient[variable] = (value, ref)
197+
end
198+
if !haskey(data._small_variable_coefficient, variable)
199+
data._small_variable_coefficient[variable] = (value, ref)
200+
elseif value < data._small_variable_coefficient[variable][1]
201+
data._small_variable_coefficient[variable] = (value, ref)
202+
end
203+
return 1
204+
end
205+
121206
function _get_objective_data(
122207
data,
123208
func::MOI.ScalarQuadraticFunction{T},
@@ -231,13 +316,15 @@ function _get_constraint_matrix_data(
231316
end
232317
end
233318
nnz = 0
319+
_reset_function_range(data)
234320
for term in func.terms
235321
variable = term.variable
236322
coefficient = term.coefficient
237323
if iszero(coefficient)
238324
continue
239325
end
240-
nnz += _update_range(data.matrix_range, coefficient)
326+
# nnz += _update_range(data.matrix_range, coefficient)
327+
nnz += _update_constraint_range(data, coefficient, variable, ref)
241328
if abs(coefficient) < data.threshold_small
242329
push!(
243330
data.matrix_small,
@@ -249,7 +336,7 @@ function _get_constraint_matrix_data(
249336
LargeMatrixCoefficient(ref, variable, coefficient),
250337
)
251338
end
252-
push!(data.variables_in_constraints, variable)
339+
push!(data._variables_in_constraints, variable)
253340
end
254341
if nnz == 0
255342
if !ignore_extras
@@ -261,6 +348,19 @@ function _get_constraint_matrix_data(
261348
nnz > data.threshold_dense_entries
262349
push!(data.dense_rows, DenseConstraint(ref, nnz))
263350
end
351+
range = _function_range(data)
352+
if range > data.threshold_dynamic_range_single
353+
push!(
354+
data.large_dynamic_range_constraints,
355+
LargeDynamicRangeConstraint(
356+
ref,
357+
data._small_coefficient[1][2],
358+
data._large_coefficient[1][2],
359+
range,
360+
),
361+
)
362+
end
363+
_reset_function_range(data)
264364
data.matrix_nnz += nnz
265365
return
266366
end
@@ -290,8 +390,8 @@ function _get_constraint_matrix_data(
290390
LargeMatrixQuadraticCoefficient(ref, v1, v2, coefficient),
291391
)
292392
end
293-
push!(data.variables_in_constraints, v1)
294-
push!(data.variables_in_constraints, v2)
393+
push!(data._variables_in_constraints, v1)
394+
push!(data._variables_in_constraints, v2)
295395
end
296396
data.has_quadratic_constraints = true
297397
_get_constraint_matrix_data(
@@ -307,15 +407,19 @@ function _get_constraint_matrix_data(
307407
data,
308408
ref::MOI.ConstraintIndex,
309409
func::MOI.VectorAffineFunction{T},
410+
ignore_extras::Bool = false,
310411
) where {T}
412+
nnz = 0
413+
_reset_function_range(data)
311414
for term in func.terms
312415
variable = term.scalar_term.variable
313416
coefficient = term.scalar_term.coefficient
314417
# index = term.output_index
315418
if iszero(coefficient)
316419
continue
317420
end
318-
_update_range(data.matrix_range, coefficient)
421+
# _update_range(data.matrix_range, coefficient)
422+
nnz += _update_constraint_range(data, coefficient, variable, ref)
319423
if abs(coefficient) < data.threshold_small
320424
push!(
321425
data.matrix_small,
@@ -327,8 +431,34 @@ function _get_constraint_matrix_data(
327431
LargeMatrixCoefficient(ref, variable, coefficient),
328432
)
329433
end
330-
push!(data.variables_in_constraints, variable)
434+
push!(data._variables_in_constraints, variable)
435+
end
436+
if nnz == 0
437+
if !ignore_extras
438+
push!(data.empty_rows, EmptyConstraint(ref))
439+
end
440+
return
441+
end
442+
# this computation for vector constraint can be more complicated
443+
# as this might need to be per index
444+
# if nnz / data.number_of_variables > data.threshold_dense_fill_in &&
445+
# nnz > data.threshold_dense_entries
446+
# push!(data.dense_rows, DenseConstraint(ref, nnz))
447+
# end
448+
range = _function_range(data)
449+
if range > data.threshold_dynamic_range_single
450+
push!(
451+
data.large_dynamic_range_constraints,
452+
LargeDynamicRangeConstraint(
453+
ref,
454+
data._small_coefficient[1][2],
455+
data._large_coefficient[1][2],
456+
range,
457+
),
458+
)
331459
end
460+
_reset_function_range(data)
461+
data.matrix_nnz += nnz
332462
return
333463
end
334464

@@ -337,14 +467,15 @@ function _get_constraint_matrix_data(
337467
ref::MOI.ConstraintIndex,
338468
func::MOI.VectorQuadraticFunction{T},
339469
) where {T}
470+
nnz = 0
340471
for term in func.quadratic_terms
341472
v1 = term.scalar_term.variable_1
342473
v2 = term.scalar_term.variable_2
343474
coefficient = term.scalar_term.coefficient
344475
if iszero(coefficient)
345476
continue
346477
end
347-
_update_range(data.matrix_quadratic_range, coefficient)
478+
nnz += _update_range(data.matrix_quadratic_range, coefficient)
348479
if abs(coefficient) < data.threshold_small
349480
push!(
350481
data.matrix_quadratic_small,
@@ -356,14 +487,14 @@ function _get_constraint_matrix_data(
356487
LargeMatrixQuadraticCoefficient(ref, v1, v2, coefficient),
357488
)
358489
end
359-
push!(data.variables_in_constraints, v1)
360-
push!(data.variables_in_constraints, v2)
490+
push!(data._variables_in_constraints, v1)
491+
push!(data._variables_in_constraints, v2)
361492
end
362493
_get_constraint_matrix_data(
363494
data,
364495
ref,
365496
MOI.VectorAffineFunction{T}(func.affine_terms, func.constants),
366-
# ignore_extras = nnz > 0,
497+
ignore_extras = nnz > 0,
367498
)
368499
return
369500
end
@@ -373,7 +504,7 @@ function _get_constraint_matrix_data(
373504
ref::MOI.ConstraintIndex,
374505
func::MOI.VariableIndex,
375506
)
376-
# push!(data.variables_in_constraints, func)
507+
# push!(data._variables_in_constraints, func)
377508
return
378509
end
379510

@@ -386,7 +517,7 @@ function _get_constraint_matrix_data(
386517
return
387518
end
388519
for var in func.variables
389-
push!(data.variables_in_constraints, var)
520+
push!(data._variables_in_constraints, var)
390521
end
391522
return
392523
end

0 commit comments

Comments
 (0)