Skip to content
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

Merged
merged 40 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
72c5e67
test on julia 1.4
Anhtu07 Dec 21, 2020
f807aa3
Merge branch 'newfeature'
Anhtu07 Dec 21, 2020
46c0ec4
Merge remote-tracking branch 'mtanneau/master' into newfeature
Anhtu07 Dec 22, 2020
61e1e4f
Merge branch 'newfeature'
Anhtu07 Dec 22, 2020
c683ca1
Merge remote-tracking branch 'mtanneau/master'
Anhtu07 Dec 23, 2020
c83a339
Merge branch 'master' into newfeature
Anhtu07 Dec 23, 2020
7a8afd3
First commit for coefficient strengthening
Anhtu07 Dec 29, 2020
a41ddfd
Add test3
Anhtu07 Dec 30, 2020
89bb756
Add coef strengthening to presolve.jl
Anhtu07 Dec 31, 2020
ceaf8cb
Merge branch 'newfeature'
Anhtu07 Dec 31, 2020
6387ed5
remove julia 1.4
Anhtu07 Dec 31, 2020
4193cef
Merge remote-tracking branch 'mtanneau/master'
Anhtu07 Dec 31, 2020
394e729
Merge branch 'master' into newfeature
Anhtu07 Dec 31, 2020
531ac5e
remove infinity
Anhtu07 Jan 1, 2021
f429307
Merge branch 'master' into newfeature
Anhtu07 Jan 6, 2021
e5e945c
row by row iteration
Anhtu07 Jan 7, 2021
12f54be
update coef_strengthening
Anhtu07 Jan 12, 2021
4038192
O(nz) update
Anhtu07 Jan 12, 2021
d2b4cce
Update
Anhtu07 Jan 21, 2021
2354d4d
Merge branch 'newfeature'
Anhtu07 Jan 21, 2021
30fa452
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 22, 2021
9d44a01
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 22, 2021
67f9de0
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 22, 2021
e76f989
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 22, 2021
fb5e4dd
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 22, 2021
9f8a6b4
Merge branch 'master' into newfeature
Anhtu07 Jan 22, 2021
e964e7b
consistent update
Anhtu07 Jan 22, 2021
1707cd8
Merge branch 'newfeature'
Anhtu07 Jan 22, 2021
a2faa0a
using isfinite
Anhtu07 Jan 22, 2021
1a29210
minor fix
Anhtu07 Jan 22, 2021
3eb946e
Add test
Anhtu07 Jan 23, 2021
6eb7c75
fix
Anhtu07 Jan 23, 2021
3a1d952
Merge branch 'master' into newfeature
Anhtu07 Jan 30, 2021
0b4b83e
skip deactivated rows/cols
Anhtu07 Jan 30, 2021
1ea9b79
fix bumped comments
Anhtu07 Jan 30, 2021
3e7fdc3
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 30, 2021
72cb1ad
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 30, 2021
021f501
Update test/mip/coefficient_strengthening.jl
Anhtu07 Jan 31, 2021
8ae6572
Update src/mip/coefficient_strengthening.jl
Anhtu07 Jan 31, 2021
92d07a6
Update
Anhtu07 Jan 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions src/mip/coefficient_strengthening.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
"""
Copy link
Collaborator

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.

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}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving maximal_activity and minimal_activity to util.jl.

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}
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 _coefficient_strengthenening!.

# 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
37 changes: 36 additions & 1 deletion src/presolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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")


"""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
on every constraints.
in every constraint.


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
Loading