-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Coefficient Strengthening #14
Changes from 37 commits
72c5e67
f807aa3
46c0ec4
61e1e4f
c683ca1
c83a339
7a8afd3
a41ddfd
89bb756
ceaf8cb
6387ed5
4193cef
394e729
531ac5e
f429307
e5e945c
12f54be
4038192
d2b4cce
2354d4d
30fa452
9d44a01
67f9de0
e76f989
fb5e4dd
9f8a6b4
e964e7b
1707cd8
a2faa0a
1a29210
3eb946e
6eb7c75
3a1d952
0b4b83e
1ea9b79
3e7fdc3
72cb1ad
021f501
8ae6572
92d07a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
""" | ||
Perform coefficient strengthening on each row and on each integer variable. | ||
|
||
In particular, we consider the i-th constraints of the form | ||
aᵢ x ⩽ bᵢ and where xⱼ is a integer/binary variable. | ||
If aᵢⱼ ⩾ d = bᵢ - Mᵢⱼ - aᵢⱼ (uⱼ - 1) > 0 | ||
where Mᵢⱼ is maximal activity of the i-th row without considering xⱼ | ||
and uⱼ is upper bound of xⱼ, then we transform | ||
aᵢⱼ <- aᵢⱼ - d | ||
bᵢ <- bᵢ - duⱼ . | ||
|
||
A similar update rule is applied for the constraints of the form cᵢ ⩽ aᵢ x. | ||
|
||
In case the constraint is ranged, i.e, cᵢ ⩽ aᵢ x ⩽ bᵢ, no coefficient strengthening is performed. | ||
|
||
The new coefficients are stored by updating ps.pb0 . | ||
If some coefficient is reduced to 0, it is kept as 0 in both ps.pb0.arows and ps.pb0.acols, | ||
and the number of nonzeros in each row/column is updated. | ||
|
||
If a row/column is reduced to 0 after this step, it will be set to be inactive. | ||
""" | ||
|
||
function maximal_activity(ps::PresolveData{T}, i::Int)::T where {T} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider moving |
||
sup = zero(T) | ||
|
||
row = ps.pb0.arows[i] | ||
for (j, aij) in zip(row.nzind, row.nzval) | ||
ps.colflag[j] || continue | ||
if aij > zero(T) | ||
sup += aij * ps.ucol[j] | ||
elseif aij < zero(T) | ||
sup += aij * ps.lcol[j] | ||
end | ||
isfinite(sup) || return sup | ||
end | ||
return sup | ||
end | ||
|
||
function minimal_activity(ps::PresolveData{T}, i::Int)::T where {T} | ||
inf = zero(T) | ||
|
||
row = ps.pb0.arows[i] | ||
for (j, aij) in zip(row.nzind, row.nzval) | ||
mtanneau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ps.colflag[j] || continue | ||
if aij > zero(T) | ||
inf += aij * ps.lcol[j] | ||
elseif aij < zero(T) | ||
inf += aij * ps.ucol[j] | ||
end | ||
isfinite(inf) || return inf | ||
end | ||
return inf | ||
end | ||
|
||
function upperbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, max_act::T) where {T} | ||
# perform coef strengthening for one constraint of the form a'x <= u | ||
new_bound = ps.urow[i] | ||
new_coef = coef | ||
if coef > 0 | ||
d = new_bound - max_act - coef * (ps.ucol[j]-1) | ||
if coef >= d > 0 | ||
new_coef = new_coef - d | ||
new_bound -= d*ps.ucol[j] | ||
end | ||
elseif coef < 0 | ||
d = new_bound - max_act - coef * (ps.lcol[j]+1) | ||
if -coef >= d > 0 | ||
new_coef = new_coef + d | ||
new_bound += d*ps.lcol[j] | ||
end | ||
joehuchette marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
return new_coef, new_bound | ||
end | ||
|
||
function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, min_act::T) where {T} | ||
# perform coef strengthening for one constraint of the form l < = a'x | ||
new_bound = ps.lrow[i] | ||
new_coef = coef | ||
if coef > 0 | ||
d = -new_bound + min_act + coef*(ps.lcol[j]+1) | ||
if coef >= d > 0 | ||
new_coef = coef - d | ||
new_bound -= d*ps.lcol[j] | ||
end | ||
elseif coef < 0 | ||
d = -new_bound + min_act + coef*(ps.ucol[j]-1) | ||
if -coef >= d > 0 | ||
new_coef = coef + d | ||
new_bound += d*ps.ucol[j] | ||
end | ||
end | ||
return new_coef, new_bound | ||
end | ||
|
||
function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about this naming. It sounds like you're only applying coefficient strengthening on zero coefficients (maybe?). I would just call this |
||
# perform coefficient stregthening but if there is a coefficient that is reduced to 0 | ||
# it is explicitly stored in the ps.pb0.arows and ps.pb0.acols | ||
|
||
# keep track of index for each var fo update ps.acols | ||
Anhtu07 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# use this to find which index of ps.pb0.acols[i].nzval to update | ||
i_index = zeros(Int, ps.pb0.nvar) | ||
|
||
for i in 1:ps.pb0.ncon | ||
mtanneau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ps.rowflag[i] || continue | ||
|
||
lrow = ps.lrow[i] | ||
urow = ps.urow[i] | ||
if isfinite(lrow) && isfinite(urow) #skip ranged constraints | ||
continue | ||
end | ||
|
||
row = ps.pb0.arows[i] | ||
if all(ps.var_types[row.nzind] .== CONTINUOUS) # at least 1 integer | ||
continue | ||
end | ||
|
||
sup = maximal_activity(ps, i) | ||
inf = minimal_activity(ps, i) | ||
|
||
j_index = 0 # keep track of index of variable j in row.nzind & row.nzval | ||
for j in row.nzind | ||
j_index += 1 | ||
i_index[j] += 1 | ||
if ps.var_types[j] == CONTINUOUS || !ps.colflag[j] | ||
continue | ||
else | ||
Anhtu07 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
coef = row.nzval[j_index] | ||
|
||
if isfinite(urow) | ||
if coef > 0 | ||
max_act = sup - coef * ps.ucol[j] # maximal activity of every variables except j | ||
else | ||
max_act = sup - coef * ps.lcol[j] | ||
end | ||
new_coef, new_bound = upperbound_strengthening(ps, i, j, coef, max_act) | ||
# update problem | ||
row.nzval[j_index] = new_coef | ||
ps.pb0.acols[j].nzval[i_index[j]] = new_coef | ||
ps.urow[i] = new_bound | ||
#update nonzero | ||
if !iszero(coef) && iszero(new_coef) | ||
ps.nzrow[i] -= 1 | ||
ps.nzcol[j] -= 1 | ||
end | ||
#update sup | ||
if coef > 0 | ||
sup -= (coef - new_coef) * ps.ucol[j] | ||
else | ||
sup -= (coef - new_coef) * ps.lcol[j] | ||
end | ||
elseif isfinite(lrow) | ||
if coef > 0 | ||
min_act = inf - coef * ps.lcol[j] # minimal activity of every variables except j | ||
else | ||
min_act = inf - coef * ps.ucol[j] | ||
end | ||
new_coef, new_bound = lowerbound_strengthening(ps, i, j, coef, min_act) | ||
#update problem | ||
row.nzval[j_index] = new_coef | ||
ps.pb0.acols[j].nzval[i_index[j]] = new_coef | ||
ps.lrow[i] = new_bound | ||
#update nonzero | ||
if !iszero(coef) && iszero(new_coef) | ||
ps.nzrow[i] -= 1 | ||
ps.nzcol[j] -= 1 | ||
end | ||
#update inf | ||
if coef > 0 | ||
inf -= (coef - new_coef) * ps.lcol[j] | ||
else | ||
inf -= (coef - new_coef) * ps.ucol[j] | ||
end | ||
end | ||
end | ||
end | ||
end | ||
return nothing | ||
end |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -319,6 +319,7 @@ include("lp/free_column_singleton.jl") | |||||
include("lp/dominated_column.jl") | ||||||
|
||||||
include("mip/round_integer_bounds.jl") | ||||||
include("mip/coefficient_strengthening.jl") | ||||||
|
||||||
|
||||||
""" | ||||||
|
@@ -414,6 +415,9 @@ function presolve!(ps::PresolveData{T}) where {T} | |||||
# Round the bounds of integer variables are integers. | ||||||
round_integer_bounds!(ps) | ||||||
|
||||||
# Coefficient strengthening | ||||||
coefficient_strengthening!(ps) | ||||||
|
||||||
# Check bound consistency on all rows/columns | ||||||
st = bounds_consistency_checks!(ps) | ||||||
ps.status == PRIMAL_INFEASIBLE && return ps.status | ||||||
|
@@ -625,6 +629,7 @@ function round_integer_bounds!(ps::PresolveData{T}) where {T} | |||||
for j in 1:ps.pb0.nvar | ||||||
round_integer_bounds!(ps, j) | ||||||
end | ||||||
|
||||||
return nothing | ||||||
end | ||||||
|
||||||
|
@@ -681,7 +686,7 @@ function remove_dominated_columns!(ps::PresolveData{T}) where {T} | |||||
iszero(aij) && continue # empty column | ||||||
|
||||||
# Strengthen dual bounds | ||||||
#= | ||||||
#= | ||||||
|
||||||
=# | ||||||
mtanneau marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
cj = ps.obj[j] | ||||||
|
@@ -723,3 +728,33 @@ function remove_dominated_columns!(ps::PresolveData{T}) where {T} | |||||
end | ||||||
return nothing | ||||||
end | ||||||
|
||||||
""" | ||||||
coefficient_strengthening!(ps::PresolveData) | ||||||
|
||||||
Perform coefficient strengthening for integer/binary variables | ||||||
on every constraints. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Called once at the beginning of the presolve procedure. | ||||||
""" | ||||||
|
||||||
mtanneau marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
function coefficient_strengthening!(ps::PresolveData{T}) where {T} | ||||||
mtanneau marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
ps.pb0.is_continuous && return nothing | ||||||
|
||||||
zero_coefficient_strengthening!(ps) | ||||||
|
||||||
# inactive rows | ||||||
for (i, row) in enumerate(ps.pb0.arows) | ||||||
if all(row.nzval .== 0) | ||||||
ps.rowflag[i] = false | ||||||
end | ||||||
end | ||||||
# inactive cols | ||||||
for (j, col) in enumerate(ps.pb0.acols) | ||||||
if all(col.nzval .== 0) | ||||||
ps.colflag[j] = false | ||||||
end | ||||||
end | ||||||
mtanneau marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
return nothing | ||||||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The location of this docstring is a bit odd--usually it would go immediately before (no extra newline) before a function it's describing. Here, it's above
maximal_activity
, but that's just really a helper function.