Skip to content

Commit f63d8ae

Browse files
authored
Refactor PrimalDualMap (#183)
* Cleanup renames * Restructure PDMap * Complete restructure of PrimalDualMap * add docs, fix names and add errors * format
1 parent be30333 commit f63d8ae

18 files changed

+548
-461
lines changed

docs/src/reference.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@
44
Dualization.supported_constraints
55
Dualization.supported_objective
66
Dualization.DualNames
7+
Dualization.VariableData
8+
Dualization.ConstraintData
9+
Dualization.PrimalDualMap
710
```

src/MOI_wrapper.jl

Lines changed: 75 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ function _change_constant(
126126
model,
127127
ci::MOI.ConstraintIndex{<:MOI.ScalarAffineFunction,S},
128128
constant,
129-
idx,
129+
::Int,
130130
) where {S}
131131
MOI.set(model, MOI.ConstraintSet(), ci, S(constant))
132132
return
@@ -136,7 +136,7 @@ function _change_constant(
136136
model,
137137
ci::MOI.ConstraintIndex{<:MOI.VectorAffineFunction},
138138
constant,
139-
idx,
139+
idx::Int,
140140
)
141141
func = MOI.get(model, MOI.ConstraintFunction(), ci)
142142
constants = copy(func.constant)
@@ -159,23 +159,19 @@ function MOI.modify(
159159
constant = -constant
160160
end
161161
vi = obj_change.variable
162-
if haskey(primal_dual_map.primal_convar_to_primal_convarcon_and_index, vi)
163-
ci_primal, index =
164-
primal_dual_map.primal_convar_to_primal_convarcon_and_index[vi]
165-
ci_dual = primal_dual_map.primal_convarcon_to_dual_con[ci_primal]
166-
if ci_dual === NO_CONSTRAINT
167-
return
168-
end
162+
data = get(primal_dual_map.primal_variable_data, vi, nothing)
163+
if data === nothing
164+
# error
165+
elseif data.dual_constraint === nothing
166+
return
167+
elseif data.primal_constrained_variable_constraint !== nothing
169168
constant = -constant
170-
else
171-
ci_dual = primal_dual_map.primal_var_to_dual_con[vi]
172-
index = 1
173169
end
174170
_change_constant(
175171
optimizer.dual_problem.dual_model,
176-
ci_dual,
172+
data.dual_constraint,
177173
constant,
178-
index,
174+
data.primal_constrained_variable_index,
179175
)
180176
return
181177
end
@@ -246,32 +242,31 @@ function MOI.get(
246242
optimizer::DualOptimizer{T},
247243
::MOI.VariablePrimal,
248244
vi::MOI.VariableIndex,
249-
) where {T}
245+
)::T where {T}
250246
primal_dual_map = optimizer.dual_problem.primal_dual_map
251-
if haskey(primal_dual_map.primal_convar_to_primal_convarcon_and_index, vi)
252-
ci_primal, idx =
253-
primal_dual_map.primal_convar_to_primal_convarcon_and_index[vi]
254-
ci_dual = primal_dual_map.primal_convarcon_to_dual_con[ci_primal]
255-
if ci_dual === NO_CONSTRAINT
256-
return zero(T)
257-
elseif ci_dual isa MOI.ConstraintIndex{<:MOI.AbstractVectorFunction}
258-
return MOI.get(
259-
optimizer.dual_problem.dual_model,
260-
MOI.ConstraintDual(),
261-
ci_dual,
262-
)[idx]
263-
else
264-
return MOI.get(
265-
optimizer.dual_problem.dual_model,
266-
MOI.ConstraintDual(),
267-
ci_dual,
268-
)
269-
end
270-
else
247+
data = get(primal_dual_map.primal_variable_data, vi, nothing)
248+
if data === nothing
249+
# error
250+
elseif data.dual_constraint === nothing
251+
return zero(T)
252+
elseif data.primal_constrained_variable_constraint === nothing
271253
return -MOI.get(
272254
optimizer.dual_problem.dual_model,
273255
MOI.ConstraintDual(),
274-
primal_dual_map.primal_var_to_dual_con[vi],
256+
data.dual_constraint,
257+
)
258+
elseif data.dual_constraint isa
259+
MOI.ConstraintIndex{<:MOI.AbstractVectorFunction}
260+
return MOI.get(
261+
optimizer.dual_problem.dual_model,
262+
MOI.ConstraintDual(),
263+
data.dual_constraint,
264+
)[data.primal_constrained_variable_index]
265+
else
266+
return MOI.get(
267+
optimizer.dual_problem.dual_model,
268+
MOI.ConstraintDual(),
269+
data.dual_constraint,
275270
)
276271
end
277272
end
@@ -282,16 +277,17 @@ function MOI.get(
282277
ci::MOI.ConstraintIndex{F,S},
283278
) where {F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet}
284279
primal_dual_map = optimizer.dual_problem.primal_dual_map
285-
if haskey(primal_dual_map.primal_convarcon_to_dual_con, ci)
286-
ci_dual = primal_dual_map.primal_convarcon_to_dual_con[ci]
287-
if ci_dual === NO_CONSTRAINT
280+
if haskey(primal_dual_map.primal_constrained_variables, ci)
281+
vi = primal_dual_map.primal_constrained_variables[ci][]
282+
ci_dual = primal_dual_map.primal_variable_data[vi].dual_constraint
283+
if ci_dual === nothing
288284
return MOI.Utilities.eval_variables(
289-
primal_dual_map.primal_convarcon_to_dual_function[ci],
290-
) do vi
285+
primal_dual_map.primal_variable_data[vi].dual_function,
286+
) do inner_vi
291287
return MOI.get(
292288
optimizer.dual_problem.dual_model,
293289
MOI.VariablePrimal(),
294-
vi,
290+
inner_vi,
295291
)
296292
end
297293
end
@@ -309,7 +305,7 @@ function MOI.get(
309305
return MOI.get(
310306
optimizer.dual_problem.dual_model,
311307
MOI.VariablePrimal(),
312-
primal_dual_map.primal_con_to_dual_var_vec[ci][],
308+
primal_dual_map.primal_constraint_data[ci].dual_variables[],
313309
)
314310
end
315311
end
@@ -320,29 +316,32 @@ function MOI.get(
320316
ci::MOI.ConstraintIndex{F,S},
321317
) where {F<:MOI.AbstractVectorFunction,S<:MOI.AbstractVectorSet}
322318
primal_dual_map = optimizer.dual_problem.primal_dual_map
323-
if haskey(primal_dual_map.primal_convarcon_to_dual_con, ci)
324-
ci_dual = primal_dual_map.primal_convarcon_to_dual_con[ci]
325-
if ci_dual === NO_CONSTRAINT
326-
return MOI.Utilities.eval_variables(
327-
primal_dual_map.primal_convarcon_to_dual_function[ci],
328-
) do vi
329-
return MOI.get(
330-
optimizer.dual_problem.dual_model,
331-
MOI.VariablePrimal(),
332-
vi,
333-
)
334-
end
319+
if !haskey(primal_dual_map.primal_constraint_data, ci)
320+
vis = primal_dual_map.primal_constrained_variables[ci]
321+
ci_dual = primal_dual_map.primal_variable_data[vis[1]].dual_constraint
322+
if ci_dual === nothing
323+
return [
324+
MOI.Utilities.eval_variables(
325+
primal_dual_map.primal_variable_data[vi].dual_function,
326+
) do inner_vi
327+
return MOI.get(
328+
optimizer.dual_problem.dual_model,
329+
MOI.VariablePrimal(),
330+
inner_vi,
331+
)
332+
end for vi in vis
333+
]
335334
end
336335
return MOI.get(
337336
optimizer.dual_problem.dual_model,
338337
MOI.ConstraintPrimal(),
339-
primal_dual_map.primal_convarcon_to_dual_con[ci],
338+
ci_dual,
340339
)
341340
else
342341
return MOI.get.(
343342
optimizer.dual_problem.dual_model,
344343
MOI.VariablePrimal(),
345-
primal_dual_map.primal_con_to_dual_var_vec[ci],
344+
primal_dual_map.primal_constraint_data[ci].dual_variables,
346345
)
347346
end
348347
end
@@ -353,9 +352,11 @@ function MOI.get(
353352
ci::MOI.ConstraintIndex{F,S},
354353
) where {T,F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet}
355354
primal_dual_map = optimizer.dual_problem.primal_dual_map
356-
if haskey(primal_dual_map.primal_convarcon_to_dual_con, ci)
357-
ci_dual = primal_dual_map.primal_convarcon_to_dual_con[ci]
358-
if ci_dual === NO_CONSTRAINT
355+
data = get(primal_dual_map.primal_constraint_data, ci, nothing)
356+
if data === nothing
357+
first_vi = primal_dual_map.primal_constrained_variables[ci][1]
358+
ci_dual = primal_dual_map.primal_variable_data[first_vi].dual_constraint
359+
if ci_dual === nothing
359360
return zero(T)
360361
else
361362
return MOI.get(
@@ -365,17 +366,16 @@ function MOI.get(
365366
)
366367
end
367368
else
368-
primal_ci_constant =
369-
primal_dual_map.primal_con_to_primal_constants_vec[ci][1]
369+
primal_ci_constant = data.primal_set_constants[1]
370370
# If it has no key then there is no dual constraint
371-
if !haskey(primal_dual_map.primal_con_to_dual_convarcon, ci)
371+
ci_dual = data.dual_constrained_variable_constraint
372+
if ci_dual === nothing
372373
return -primal_ci_constant
373374
end
374-
ci_dual_problem = primal_dual_map.primal_con_to_dual_convarcon[ci]
375375
return MOI.get(
376376
optimizer.dual_problem.dual_model,
377377
MOI.ConstraintDual(),
378-
ci_dual_problem,
378+
ci_dual,
379379
) - primal_ci_constant
380380
end
381381
end
@@ -386,13 +386,12 @@ function MOI.get(
386386
ci::MOI.ConstraintIndex{F,S},
387387
) where {T,F<:MOI.AbstractVectorFunction,S<:MOI.AbstractVectorSet}
388388
primal_dual_map = optimizer.dual_problem.primal_dual_map
389-
if haskey(primal_dual_map.primal_convarcon_to_dual_con, ci)
390-
ci_dual = primal_dual_map.primal_convarcon_to_dual_con[ci]
391-
if ci_dual === NO_CONSTRAINT
392-
n = MOI.output_dimension(
393-
primal_dual_map.primal_convarcon_to_dual_function[ci],
394-
)
395-
return zeros(T, n)
389+
data = get(primal_dual_map.primal_constraint_data, ci, nothing)
390+
if data === nothing
391+
vis = primal_dual_map.primal_constrained_variables[ci]
392+
ci_dual = primal_dual_map.primal_variable_data[vis[1]].dual_constraint
393+
if ci_dual === nothing
394+
return zeros(T, length(vis))
396395
else
397396
return MOI.get(
398397
optimizer.dual_problem.dual_model,
@@ -401,18 +400,17 @@ function MOI.get(
401400
)
402401
end
403402
else
403+
ci_dual = data.dual_constrained_variable_constraint
404404
# If it has no key then there is no dual constraint
405-
if !haskey(primal_dual_map.primal_con_to_dual_convarcon, ci)
405+
if ci_dual === nothing
406406
# The number of dual variable associated with the primal constraint is the ci dimension
407-
ci_dimension =
408-
length(primal_dual_map.primal_con_to_dual_var_vec[ci])
407+
ci_dimension = length(data.dual_variables)
409408
return zeros(T, ci_dimension)
410409
end
411-
ci_dual_problem = primal_dual_map.primal_con_to_dual_convarcon[ci]
412410
return MOI.get(
413411
optimizer.dual_problem.dual_model,
414412
MOI.ConstraintDual(),
415-
ci_dual_problem,
413+
ci_dual,
416414
)
417415
end
418416
end

src/constrained_variables.jl

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,27 @@ function _select_constrained_variables(
1414
primal_model,
1515
)
1616
params = Set(variable_parameters)
17+
selected_variables = Set{MOI.VariableIndex}()
1718
for S in single_or_vector_variables_types
1819
_select_constrained_variables(
1920
dual_problem.primal_dual_map,
2021
primal_model,
2122
S,
2223
params,
24+
selected_variables,
2325
)
2426
end
2527
return
2628
end
2729

28-
const NO_CONSTRAINT = MOI.ConstraintIndex{Nothing,Nothing}(0)
29-
3030
# Function barrier for the type instability of `F` and `S`.
3131
function _select_constrained_variables(
32-
m::PrimalDualMap,
32+
m::PrimalDualMap{T},
3333
primal_model,
3434
::Type{S},
3535
params,
36-
) where {S<:MOI.AbstractVectorSet}
36+
selected_variables,
37+
) where {T,S<:MOI.AbstractVectorSet}
3738
cis = MOI.get(
3839
primal_model,
3940
MOI.ListOfConstraintIndices{MOI.VectorOfVariables,S}(),
@@ -44,46 +45,40 @@ function _select_constrained_variables(
4445
if all(
4546
# no element of the VectorOfVariables is a constrained variable
4647
# and not a parameter
47-
vi ->
48-
!haskey(m.primal_convar_to_primal_convarcon_and_index, vi) &&
49-
!(vi in params),
48+
vi -> !(vi in selected_variables) && !(vi in params),
5049
f.variables,
5150
)
52-
for (i, vi) in enumerate(f.variables)
53-
m.primal_convar_to_primal_convarcon_and_index[vi] = (ci, i)
51+
m.primal_constrained_variables[ci] = f.variables
52+
for vi in f.variables
53+
push!(selected_variables, vi)
5454
end
55-
# Placeholder to indicate this constraint is part of constrained variables,
56-
# it will be replaced later with a dual constraints
57-
m.primal_convarcon_to_dual_con[ci] = NO_CONSTRAINT
5855
end
5956
end
6057
return
6158
end
6259

6360
function _select_constrained_variables(
64-
m::PrimalDualMap,
61+
m::PrimalDualMap{T},
6562
primal_model,
6663
::Type{S},
6764
params,
68-
) where {S<:MOI.AbstractScalarSet}
65+
selected_variables,
66+
) where {T,S<:MOI.AbstractScalarSet}
6967
cis = MOI.get(
7068
primal_model,
7169
MOI.ListOfConstraintIndices{MOI.VariableIndex,S}(),
7270
)
7371
for ci in cis
74-
f = MOI.get(primal_model, MOI.ConstraintFunction(), ci)
72+
vi = MOI.get(primal_model, MOI.ConstraintFunction(), ci)
7573
# no element of the VectorOfVariables is a constrained variable
7674
# and not a parameter
77-
if !haskey(m.primal_convar_to_primal_convarcon_and_index, f) &&
78-
!(f in params)
75+
if !(vi in selected_variables) && !(vi in params)
7976
set = MOI.get(primal_model, MOI.ConstraintSet(), ci)
8077
if !iszero(MOI.constant(set))
8178
continue
8279
end
83-
m.primal_convar_to_primal_convarcon_and_index[f] = (ci, 1)
84-
# Placeholder to indicate this constraint is part of constrained variables,
85-
# it will be replaced later with a dual constraints
86-
m.primal_convarcon_to_dual_con[ci] = NO_CONSTRAINT
80+
m.primal_constrained_variables[ci] = [vi]
81+
push!(selected_variables, vi)
8782
end
8883
end
8984
return

0 commit comments

Comments
 (0)