Skip to content

Commit f7e7932

Browse files
committed
Improve type stability of src/range.jl
1 parent 6c2ca24 commit f7e7932

File tree

1 file changed

+100
-108
lines changed

1 file changed

+100
-108
lines changed

src/range.jl

Lines changed: 100 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -3,103 +3,6 @@
33
# Use of this source code is governed by an MIT-style license that can be found
44
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
55

6-
function _range_infeasibility!(
7-
optimizer::Optimizer,
8-
::Type{T},
9-
variables,
10-
lb_con::Dict{MOI.VariableIndex,MOI.ConstraintIndex},
11-
ub_con::Dict{MOI.VariableIndex,MOI.ConstraintIndex},
12-
) where {T}
13-
range_consistent = true
14-
15-
affine_cons = vcat(
16-
MOI.get(
17-
optimizer.original_model,
18-
MOI.ListOfConstraintIndices{
19-
MOI.ScalarAffineFunction{T},
20-
MOI.EqualTo{T},
21-
}(),
22-
),
23-
MOI.get(
24-
optimizer.original_model,
25-
MOI.ListOfConstraintIndices{
26-
MOI.ScalarAffineFunction{T},
27-
MOI.LessThan{T},
28-
}(),
29-
),
30-
MOI.get(
31-
optimizer.original_model,
32-
MOI.ListOfConstraintIndices{
33-
MOI.ScalarAffineFunction{T},
34-
MOI.GreaterThan{T},
35-
}(),
36-
),
37-
)
38-
39-
for con in affine_cons
40-
if !_in_time(optimizer)
41-
return range_consistent
42-
end
43-
func = MOI.get(optimizer.original_model, MOI.ConstraintFunction(), con)
44-
failed = false
45-
list_of_variables = MOI.VariableIndex[]
46-
interval = _eval_variables(func) do var_idx
47-
push!(list_of_variables, var_idx)
48-
# this only fails if we allow continuing after bounds issues
49-
if !haskey(variables, var_idx)
50-
failed = true
51-
return Interval(-Inf, Inf)
52-
end
53-
return variables[var_idx]
54-
end
55-
if failed
56-
continue
57-
end
58-
set = MOI.get(optimizer.original_model, MOI.ConstraintSet(), con)
59-
if _invalid_range(set, interval)
60-
cons = Set{MOI.ConstraintIndex}()
61-
push!(cons, con)
62-
for var in list_of_variables
63-
if haskey(lb_con, var)
64-
push!(cons, lb_con[var])
65-
end
66-
if haskey(ub_con, var)
67-
push!(cons, ub_con[var])
68-
end
69-
end
70-
push!(
71-
optimizer.results,
72-
InfeasibilityData(
73-
collect(cons),
74-
true, # strictly speaking, we might need the propor "sides"
75-
RangeData(interval.lo, interval.hi, set),
76-
),
77-
)
78-
range_consistent = false
79-
end
80-
end
81-
return range_consistent
82-
end
83-
84-
function _invalid_range(set::MOI.EqualTo, interval)
85-
rhs = set.value
86-
return interval.lo > rhs || interval.hi < rhs
87-
end
88-
89-
function _invalid_range(set::MOI.LessThan, interval)
90-
rhs = set.upper
91-
return interval.lo > rhs
92-
end
93-
94-
function _invalid_range(set::MOI.GreaterThan, interval)
95-
rhs = set.lower
96-
return interval.hi < rhs
97-
end
98-
99-
#=
100-
Helpers
101-
=#
102-
1036
# This type and the associated function were inspired by IntervalArithmetic.jl
1047
# Copyright (c) 2014-2021: David P. Sanders & Luis Benet
1058

@@ -132,23 +35,112 @@ function Base.:*(x::T, a::Interval{T}) where {T<:Real}
13235
return Interval(a.hi * x, a.lo * x)
13336
end
13437

135-
# This type and the associated function were inspired by JuMP.jl and
136-
# MathOptInterface.jl
38+
# Back to functions written for MathOptIIS.jl
39+
40+
function _range_infeasibility!(
41+
optimizer::Optimizer,
42+
::Type{T},
43+
variables::Dict{MOI.VariableIndex,Interval{T}},
44+
lb_con::Dict{MOI.VariableIndex,MOI.ConstraintIndex},
45+
ub_con::Dict{MOI.VariableIndex,MOI.ConstraintIndex},
46+
) where {T}
47+
range_consistent = _range_infeasibility!(
48+
optimizer,
49+
optimizer.original_model,
50+
T,
51+
variables,
52+
lb_con,
53+
ub_con,
54+
MOI.EqualTo{T},
55+
)
56+
range_consistent &= _range_infeasibility!(
57+
optimizer,
58+
optimizer.original_model,
59+
T,
60+
variables,
61+
lb_con,
62+
ub_con,
63+
MOI.LessThan{T},
64+
)
65+
return _range_infeasibility!(
66+
optimizer,
67+
optimizer.original_model,
68+
T,
69+
variables,
70+
lb_con,
71+
ub_con,
72+
MOI.GreaterThan{T},
73+
)
74+
end
13775

138-
function _eval_variables(value_fn::Function, t::MOI.ScalarAffineTerm)
139-
return t.coefficient * value_fn(t.variable)
76+
function _range_infeasibility!(
77+
optimizer::Optimizer,
78+
original_model::MOI.ModelLike,
79+
::Type{T},
80+
variables::Dict{MOI.VariableIndex,Interval{T}},
81+
lb_con::Dict{MOI.VariableIndex,MOI.ConstraintIndex},
82+
ub_con::Dict{MOI.VariableIndex,MOI.ConstraintIndex},
83+
::Type{S},
84+
) where {T,S}
85+
range_consistent = true
86+
for con in MOI.get(
87+
original_model,
88+
MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{T},S}(),
89+
)
90+
if !_in_time(optimizer)
91+
return range_consistent
92+
end
93+
func = MOI.get(original_model, MOI.ConstraintFunction(), con)
94+
interval = _eval_variables(variables, func)
95+
if interval === nothing
96+
continue
97+
end
98+
set = MOI.get(original_model, MOI.ConstraintSet(), con)::S
99+
if !_invalid_range(set, interval)
100+
continue
101+
end
102+
cons = Set{MOI.ConstraintIndex}()
103+
push!(cons, con)
104+
for t in func.terms
105+
if (c = get(lb_con, t.variable, nothing)) !== nothing
106+
push!(cons, c)
107+
end
108+
if (c = get(ub_con, t.variable, nothing)) !== nothing
109+
push!(cons, c)
110+
end
111+
end
112+
push!(
113+
optimizer.results,
114+
InfeasibilityData(
115+
collect(cons),
116+
true, # strictly speaking, we might need the proper "sides"
117+
RangeData(interval.lo, interval.hi, set),
118+
),
119+
)
120+
range_consistent = false
121+
end
122+
return range_consistent
140123
end
141124

142125
function _eval_variables(
143-
value_fn::Function,
144-
f::MOI.ScalarAffineFunction{T},
145-
) where {T}
146-
# TODO: this conversion exists in JuMP, but not in MOI
147-
S = Base.promote_op(value_fn, MOI.VariableIndex)
148-
U = MOI.MA.promote_operation(*, T, S)
126+
map::AbstractDict{MOI.VariableIndex,U},
127+
f::MOI.ScalarAffineFunction,
128+
) where {U}
149129
out = convert(U, f.constant)
150130
for t in f.terms
151-
out += _eval_variables(value_fn, t)
131+
v = get(map, t.variable, nothing)
132+
if v === nothing
133+
return
134+
end
135+
out += t.coefficient * v
152136
end
153137
return out
154138
end
139+
140+
function _invalid_range(set::MOI.EqualTo, interval)
141+
return !(interval.lo <= set.value <= interval.hi)
142+
end
143+
144+
_invalid_range(set::MOI.LessThan, interval) = set.upper < interval.lo
145+
146+
_invalid_range(set::MOI.GreaterThan, interval) = interval.hi < set.lower

0 commit comments

Comments
 (0)