From 72c5e6765e41bfaeccb47c16f17d779f30fe33f2 Mon Sep 17 00:00:00 2001 From: tuna Date: Sun, 20 Dec 2020 19:34:01 -0600 Subject: [PATCH 01/27] test on julia 1.4 --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86acd97..e5de56f 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,7 @@ jobs: fail-fast: false matrix: version: + - '1.4' - '1.5' - 'nightly' os: From 7a8afd30737eaa9761b898ccbf43376c63bf6a67 Mon Sep 17 00:00:00 2001 From: tuna Date: Mon, 28 Dec 2020 19:16:20 -0600 Subject: [PATCH 02/27] First commit for coefficient strengthening -Implement and create tests for coef strengthening -Ignore ranged constraints (i.e., d <= a'x <= b) --- src/mip/coefficient_strengthening.jl | 84 +++++++++++++++++++++++++++ src/presolve.jl | 1 + test/mip/coefficient_strengthening.jl | 73 +++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 src/mip/coefficient_strengthening.jl create mode 100644 test/mip/coefficient_strengthening.jl diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl new file mode 100644 index 0000000..5150428 --- /dev/null +++ b/src/mip/coefficient_strengthening.jl @@ -0,0 +1,84 @@ +function maximal_activity(row::RowOrCol{T}, j::Int, ucol::Vector{T}, lcol::Vector{T})::T where {T} + # compute the sup of row i (execpt the integer variable j) + + # only compute the maximal activity of any variables except j + nonzero_index = [row.nzind[i] for i in 1:length(row.nzind) if row.nzind[i] != j] + nonzero_value = row.nzval[nonzero_index] + + pos_coef = deepcopy(nonzero_value) + neg_coef = deepcopy(nonzero_value) + + for i in 1:length(nonzero_value) + if nonzero_value[i] < 0 + pos_coef[i] = 0 + else + neg_coef[i] = 0 + end + end + sup = ucol[nonzero_index]'pos_coef + lcol[nonzero_index]'neg_coef + return T(sup) +end + +function single_row_strengthening(row::RowOrCol{T}, b::T, j::Int, ucol::Vector{T}, lcol::Vector{T}) where {T} + # perform coef strengthening for one constraints of the from a'x < b + # and return new a' and b' + flag = false # wether there is an update + i = findfirst(isequal(j), row.nzind) # index for integer variable j + a = deepcopy(row.nzval) + if a[i] > 0 + d = b - maximal_activity(row, j, ucol, lcol) - a[i]*(ucol[j]-1) + if a[i] >= d && d > 0 + a[i] = a[i] - d + b = b - d*ucol[j] + flag = true + end + elseif a[i] < 0 + d = b - maximal_activity(row, j, ucol, lcol) - a[i]*(lcol[j]+1) + if -a[i] >= d && d > 0 + a[i] = a[i] + d + b = b + d*lcol[j] + flag = true + end + end + return a, b, a[i], flag +end + +function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30)) where {T} + # perform coefficient strengthening on integer variable j + ps.colflag[j] || (ps.var_types[j] != CONTINUOUS) || return nothing + + for i in 1:length(ps.pb0.arows) + row = ps.pb0.arows[i] + lrow = ps.lrow[i] + urow = ps.urow[i] + + if lrow > -inf && urow < inf + continue #skipping ranged constraints + elseif urow < inf + a, b, new_coef, updated = single_row_strengthening(row, urow, j, ps.ucol, ps.lcol) + if updated + row.nzval = a + ps.urow[i] = b + + # update collumns of A in problem data + k = findfirst(isequal(i), ps.pb0.acols[j].nzind) + ps.pb0.acols[j].nzval[k] = new_coef + end + + elseif lrow > -inf + r = deepcopy(row) + r.nzval = -r.nzval + a, b, new_coef, updated = single_row_strengthening(r, -lrow, j, ps.ucol, ps.lcol) + if updated + row.nzval = -a + ps.lrow[i] = -b + + # update collumns of A in problem data + k = findfirst(isequal(i), ps.pb0.acols[j].nzind) + ps.pb0.acols[j].nzval[k] = -new_coef + end + end + end + + return nothing +end diff --git a/src/presolve.jl b/src/presolve.jl index bb77f0e..fc6b7e1 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -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") """ diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl new file mode 100644 index 0000000..1386c7c --- /dev/null +++ b/test/mip/coefficient_strengthening.jl @@ -0,0 +1,73 @@ +function positive_coef_strengthen_test(T::Type) + # Build the following model + #= + min x + y + z + w + s.t. 2 x - 5 y + 4 z + 3 w ⩽ 8 + y + z + 0.5w ⩽ 6 + 0 ⩽ x ⩽ 1 + 1 ⩽ y ⩽ 2.5 + 0 ⩽ z ⩽ 1 + 2 ⩽ w ⩽ 3 + w is integer =# + C = T[1, 1, 1, 1] + lc = T[0, 1, 0, 2] + uc = T[1, 5//2, 1, 3] + lr = T[-1e30, -1e30] + ur = T[8, 6] + A = T[2 -5 4 3 + 0 1 1 1] + + varTypes = [MOP.CONTINUOUS, MOP.CONTINUOUS, + MOP.CONTINUOUS, MOP.GENERAL_INTEGER] + + pb = MOP.ProblemData{T}() + + MOP.load_problem!(pb, "Test", + true, C, zero(T), + sparse(A), lr, ur, lc, uc, + varTypes + ) + ps = MOP.PresolveData(pb) + + #MOP.coefficient_strenthening!(ps) + + #@test + return ps +end + +function negative_coef_strengthen_test(T::Type) + Build the following model + #= + min x + y + z + w + s.t. x + y + z - 2 w ⩽ 10 + 2x + 3y + 4z + 5w ⩽ 20 + 0 ⩽ x ⩽ 2 + 0 ⩽ y ⩽ 1 + 0 ⩽ z ⩽ 2 + -3 ⩽ w + w is integer =# + C = T[1, 1, 1, 1] + lc = T[0, 0, 0, -3] + uc = T[2, 1, 2, 10^30] + lr = T[-1e30, -1e30] + ur = T[10, 20] + A = T[1 1 1 -2 + 2 3 4 5] + + varTypes = [MOP.CONTINUOUS, MOP.CONTINUOUS, + MOP.CONTINUOUS, MOP.GENERAL_INTEGER] + + pb = MOP.ProblemData{T}() + + MOP.load_problem!(pb, "Test", + true, C, zero(T), + sparse(A), lr, ur, lc, uc, + varTypes + ) + ps = MOP.PresolveData(pb) + + #MOP.coefficient_strenthening!(ps) + + #@test + return nothing +end From a41ddfdc5772806803ab9abd432553a2adb7f98c Mon Sep 17 00:00:00 2001 From: tuna Date: Tue, 29 Dec 2020 19:03:41 -0600 Subject: [PATCH 03/27] Add test3 -Adding more test on coefficient strengthening -CS now removes 0 coefficient, and empty column is now respresented as [] --- src/mip/coefficient_strengthening.jl | 58 ++++++++----- test/mip/coefficient_strengthening.jl | 113 ++++++++++++++++++++++++-- 2 files changed, 143 insertions(+), 28 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 5150428..f15e233 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -2,7 +2,7 @@ function maximal_activity(row::RowOrCol{T}, j::Int, ucol::Vector{T}, lcol::Vecto # compute the sup of row i (execpt the integer variable j) # only compute the maximal activity of any variables except j - nonzero_index = [row.nzind[i] for i in 1:length(row.nzind) if row.nzind[i] != j] + nonzero_index = [i for i in 1:length(row.nzind) if row.nzind[i] != j] nonzero_value = row.nzval[nonzero_index] pos_coef = deepcopy(nonzero_value) @@ -19,28 +19,27 @@ function maximal_activity(row::RowOrCol{T}, j::Int, ucol::Vector{T}, lcol::Vecto return T(sup) end -function single_row_strengthening(row::RowOrCol{T}, b::T, j::Int, ucol::Vector{T}, lcol::Vector{T}) where {T} +function single_row_strengthening(row::RowOrCol{T}, b::T, k::Int, j::Int, ucol::Vector{T}, lcol::Vector{T}) where {T} # perform coef strengthening for one constraints of the from a'x < b # and return new a' and b' flag = false # wether there is an update - i = findfirst(isequal(j), row.nzind) # index for integer variable j a = deepcopy(row.nzval) - if a[i] > 0 - d = b - maximal_activity(row, j, ucol, lcol) - a[i]*(ucol[j]-1) - if a[i] >= d && d > 0 - a[i] = a[i] - d + if a[k] > 0 + d = b - maximal_activity(row, j, ucol, lcol) - a[k]*(ucol[j]-1) + if a[k] >= d && d > 0 + a[k] = a[k] - d b = b - d*ucol[j] flag = true end - elseif a[i] < 0 - d = b - maximal_activity(row, j, ucol, lcol) - a[i]*(lcol[j]+1) - if -a[i] >= d && d > 0 - a[i] = a[i] + d + elseif a[k] < 0 + d = b - maximal_activity(row, j, ucol, lcol) - a[k]*(lcol[j]+1) + if -a[k] >= d && d > 0 + a[k] = a[k] + d b = b + d*lcol[j] flag = true end end - return a, b, a[i], flag + return a, b, a[k], flag end function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30)) where {T} @@ -52,33 +51,52 @@ function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30 lrow = ps.lrow[i] urow = ps.urow[i] + m = findfirst(isequal(j), row.nzind) + if m == nothing + continue + end if lrow > -inf && urow < inf continue #skipping ranged constraints elseif urow < inf - a, b, new_coef, updated = single_row_strengthening(row, urow, j, ps.ucol, ps.lcol) + a, b, new_coef, updated = single_row_strengthening(row, urow, m, j, ps.ucol, ps.lcol) if updated row.nzval = a ps.urow[i] = b # update collumns of A in problem data - k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - ps.pb0.acols[j].nzval[k] = new_coef + # and update the sparse matrix in the case where the new coefficient is close to 0 + if abs(new_coef) <= eps(T) + deleteat!(row.nzind, m) + deleteat!(row.nzval, m) + k = findfirst(isequal(i), ps.pb0.acols[j].nzind) + deleteat!(ps.pb0.acols[j].nzind, k) + deleteat!(ps.pb0.acols[j].nzval, k) + else + k = findfirst(isequal(i), ps.pb0.acols[j].nzind) + ps.pb0.acols[j].nzval[k] = new_coef + end end - elseif lrow > -inf r = deepcopy(row) r.nzval = -r.nzval - a, b, new_coef, updated = single_row_strengthening(r, -lrow, j, ps.ucol, ps.lcol) + a, b, new_coef, updated = single_row_strengthening(r, -lrow, m, j, ps.ucol, ps.lcol) if updated row.nzval = -a ps.lrow[i] = -b # update collumns of A in problem data - k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - ps.pb0.acols[j].nzval[k] = -new_coef + if abs(new_coef) <= eps(T) + deleteat!(row.nzind, m) + deleteat!(row.nzval, m) + k = findfirst(isequal(i), ps.pb0.acols[j].nzind) + deleteat!(ps.pb0.acols[j].nzind, k) + deleteat!(ps.pb0.acols[j].nzval, k) + else + k = findfirst(isequal(i), ps.pb0.acols[j].nzind) + ps.pb0.acols[j].nzval[k] = new_coef + end end end end - return nothing end diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index 1386c7c..8d638ff 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -1,4 +1,4 @@ -function positive_coef_strengthen_test(T::Type) +function coef_strengthen_test1(T::Type) # Build the following model #= min x + y + z + w @@ -29,14 +29,33 @@ function positive_coef_strengthen_test(T::Type) ) ps = MOP.PresolveData(pb) - #MOP.coefficient_strenthening!(ps) + for i in 1:length(ps.var_types) + if ps.var_types[i] == MOP.GENERAL_INTEGER || ps.var_types[i] == MOP.BINARY + MOP.coefficient_strengthening!(ps, i) + end + end - #@test - return ps + @test ps.urow == T[5, 9//2] + @test ps.lrow == T[-1e30, -1e30] + + @test ps.pb0.arows[1].nzind == [1, 2, 3, 4] + @test ps.pb0.arows[1].nzval == T[2, -5, 4, 2] + @test ps.pb0.arows[2].nzind == [2, 3, 4] + @test isapprox(ps.pb0.arows[2].nzval, T[1, 1, 1//2], atol = eps(T)) + + @test ps.pb0.acols[1].nzind == [1] + @test ps.pb0.acols[1].nzval == T[2] + @test ps.pb0.acols[2].nzind == [1, 2] + @test ps.pb0.acols[2].nzval == T[-5, 1] + @test ps.pb0.acols[3].nzind == [1, 2] + @test ps.pb0.acols[3].nzval == T[4, 1] + @test ps.pb0.acols[4].nzind == [1, 2] + @test ps.pb0.acols[4].nzval == T[2, 1//2] + @test ps.status == MOP.NOT_INFERRED + return nothing end -function negative_coef_strengthen_test(T::Type) - Build the following model +function coef_strengthen_test2(T::Type) #= min x + y + z + w s.t. x + y + z - 2 w ⩽ 10 @@ -66,8 +85,86 @@ function negative_coef_strengthen_test(T::Type) ) ps = MOP.PresolveData(pb) - #MOP.coefficient_strenthening!(ps) + for i in 1:length(ps.var_types) + if ps.var_types[i] == MOP.GENERAL_INTEGER || ps.var_types[i] == MOP.BINARY + MOP.coefficient_strengthening!(ps, i) + end + end + + @test ps.urow == T[7, 20] + @test ps.lrow == T[-1e30, -1e30] + + @test ps.pb0.arows[1].nzind == [1, 2, 3, 4] + @test ps.pb0.arows[1].nzval == T[1, 1, 1, -1] + @test ps.pb0.arows[2].nzind == [1, 2, 3, 4] + @test ps.pb0.arows[2].nzval == T[2, 3, 4, 5] - #@test + @test ps.pb0.acols[1].nzind == [1, 2] + @test ps.pb0.acols[1].nzval == T[1, 2] + @test ps.pb0.acols[2].nzind == [1, 2] + @test ps.pb0.acols[2].nzval == T[1, 3] + @test ps.pb0.acols[3].nzind == [1, 2] + @test ps.pb0.acols[3].nzval == T[1, 4] + @test ps.pb0.acols[4].nzind == [1, 2] + @test ps.pb0.acols[4].nzval == T[-1, 5] + @test ps.status == MOP.NOT_INFERRED return nothing end + + +function coef_strengthen_test3(T::Type) + C = T[1, 1, 1, 1, 1] + lc = T[-4, -3//2, 9, 0, -1] + uc = T[2, 1, 15, 1, 1] + lr = T[2, -1e30] + ur = T[1e30, 13/3] + A = T[1 -2 1 1 -1 + 1 1 0 1 1] + + varTypes = [MOP.CONTINUOUS, MOP.CONTINUOUS, + MOP.GENERAL_INTEGER, MOP.BINARY, MOP.CONTINUOUS] + + pb = MOP.ProblemData{T}() + + MOP.load_problem!(pb, "Test", + true, C, zero(T), + sparse(A), lr, ur, lc, uc, + varTypes + ) + ps = MOP.PresolveData(pb) + + for i in 1:length(ps.var_types) + if ps.var_types[i] == MOP.GENERAL_INTEGER || ps.var_types[i] == MOP.BINARY + MOP.coefficient_strengthening!(ps, i) + end + end + + @test ps.urow == T[1e30, 4] + @test ps.lrow == T[-7, -1e30] + + @test ps.pb0.arows[1].nzind == [1, 2, 5] + @test ps.pb0.arows[1].nzval == T[1, -2, -1] + @test ps.pb0.arows[2].nzind == [1, 2, 4, 5] + @test isapprox(ps.pb0.arows[2].nzval, T[1, 1, 2//3, 1], atol = 1e-12) + + + @test ps.pb0.acols[1].nzind == [1, 2] + @test ps.pb0.acols[1].nzval == T[1, 1] + @test ps.pb0.acols[2].nzind == [1, 2] + @test ps.pb0.acols[2].nzval == T[-2, 1] + @test ps.pb0.acols[3].nzind == [] + @test ps.pb0.acols[3].nzval == T[] + @test ps.pb0.acols[4].nzind == [2] + @test isapprox(ps.pb0.acols[4].nzval, T[2//3], atol = 1e-12) + + @test ps.status == MOP.NOT_INFERRED + return nothing +end + +@testset "Coefficient Strengthening" begin + for T in COEFF_TYPES + @testset "$T" begin coef_strengthen_test1(T) end + @testset "$T" begin coef_strengthen_test2(T) end + @testset "$T" begin coef_strengthen_test3(T) end + end +end From 89bb756bf9978f4d0a3abed4ef809c024b78428a Mon Sep 17 00:00:00 2001 From: tuna Date: Wed, 30 Dec 2020 19:23:40 -0600 Subject: [PATCH 04/27] Add coef strengthening to presolve.jl -Add coef strengthening to presolve.jl -Add testset --- src/mip/coefficient_strengthening.jl | 31 ++++++++++++--------------- src/presolve.jl | 22 +++++++++++++++++++ test/mip/coefficient_strengthening.jl | 30 +++++++++++++------------- test/runtests.jl | 3 +++ 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index f15e233..cf62e20 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -19,32 +19,32 @@ function maximal_activity(row::RowOrCol{T}, j::Int, ucol::Vector{T}, lcol::Vecto return T(sup) end -function single_row_strengthening(row::RowOrCol{T}, b::T, k::Int, j::Int, ucol::Vector{T}, lcol::Vector{T}) where {T} +function single_row_strengthening(row::RowOrCol{T}, b::T, m::Int, j::Int, ucol::Vector{T}, lcol::Vector{T}) where {T} # perform coef strengthening for one constraints of the from a'x < b # and return new a' and b' flag = false # wether there is an update a = deepcopy(row.nzval) - if a[k] > 0 - d = b - maximal_activity(row, j, ucol, lcol) - a[k]*(ucol[j]-1) - if a[k] >= d && d > 0 - a[k] = a[k] - d + if a[m] > 0 + d = b - maximal_activity(row, j, ucol, lcol) - a[m]*(ucol[j]-1) + if a[m] >= d && d > 0 + a[m] = a[m] - d b = b - d*ucol[j] flag = true end - elseif a[k] < 0 - d = b - maximal_activity(row, j, ucol, lcol) - a[k]*(lcol[j]+1) - if -a[k] >= d && d > 0 - a[k] = a[k] + d + elseif a[m] < 0 + d = b - maximal_activity(row, j, ucol, lcol) - a[m]*(lcol[j]+1) + if -a[m] >= d && d > 0 + a[m] = a[m] + d b = b + d*lcol[j] flag = true end end - return a, b, a[k], flag + return a, b, a[m], flag end function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30)) where {T} # perform coefficient strengthening on integer variable j - ps.colflag[j] || (ps.var_types[j] != CONTINUOUS) || return nothing + (ps.var_types[j] != CONTINUOUS) || return nothing for i in 1:length(ps.pb0.arows) row = ps.pb0.arows[i] @@ -52,11 +52,8 @@ function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30 urow = ps.urow[i] m = findfirst(isequal(j), row.nzind) - if m == nothing - continue - end - if lrow > -inf && urow < inf - continue #skipping ranged constraints + if m == nothing || (lrow > -inf && urow < inf) + continue #skipping ranged constraints and elseif urow < inf a, b, new_coef, updated = single_row_strengthening(row, urow, m, j, ps.ucol, ps.lcol) if updated @@ -93,7 +90,7 @@ function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30 deleteat!(ps.pb0.acols[j].nzval, k) else k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - ps.pb0.acols[j].nzval[k] = new_coef + ps.pb0.acols[j].nzval[k] = -new_coef end end end diff --git a/src/presolve.jl b/src/presolve.jl index fc6b7e1..50eff0e 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -415,6 +415,9 @@ function presolve!(ps::PresolveData{T}) where {T} # Round the bounds of integer variables are integers. round_integer_bounds!(ps) + # Coeficient strengthening + coefficient_strengthening!(ps) + # Check bound consistency on all rows/columns st = bounds_consistency_checks!(ps) ps.status == PRIMAL_INFEASIBLE && return ps.status @@ -756,3 +759,22 @@ 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. + +Called once at the very beginning of the presolve procedure. +""" + +function coefficient_strengthening!(ps::PresolveData{T}) where {T} + # The problem is LP. + ps.pb0.is_continuous && return nothing + + for j in 1:ps.pb0.nvar + coefficient_strengthening!(ps, j) + end + return nothing +end diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index 8d638ff..09b0b2c 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -29,11 +29,8 @@ function coef_strengthen_test1(T::Type) ) ps = MOP.PresolveData(pb) - for i in 1:length(ps.var_types) - if ps.var_types[i] == MOP.GENERAL_INTEGER || ps.var_types[i] == MOP.BINARY - MOP.coefficient_strengthening!(ps, i) - end - end + MOP.coefficient_strengthening!(ps) + @test ps.urow == T[5, 9//2] @test ps.lrow == T[-1e30, -1e30] @@ -85,11 +82,7 @@ function coef_strengthen_test2(T::Type) ) ps = MOP.PresolveData(pb) - for i in 1:length(ps.var_types) - if ps.var_types[i] == MOP.GENERAL_INTEGER || ps.var_types[i] == MOP.BINARY - MOP.coefficient_strengthening!(ps, i) - end - end + MOP.coefficient_strengthening!(ps) @test ps.urow == T[7, 20] @test ps.lrow == T[-1e30, -1e30] @@ -113,6 +106,16 @@ end function coef_strengthen_test3(T::Type) + #= + min x₁ + x₂ + x₃ + x₄ + x₅ + s.t. 2 ⩽x₁ + -2x₂ + x₃ + x₄ + -x₅ + x₁ + x₂ + x₄ + x₅ ⩽ 4.333 + -4 ⩽ x₁ ⩽ 2 + -1.5 ⩽ x₂ ⩽ 1 + 9 ⩽ x₃ ⩽ 15 + 0 ⩽ x₄ ⩽ 1 + -1 ⩽ x₅ ⩽ 1 + x₃ is integer, x₄ is binary =# C = T[1, 1, 1, 1, 1] lc = T[-4, -3//2, 9, 0, -1] uc = T[2, 1, 15, 1, 1] @@ -133,11 +136,8 @@ function coef_strengthen_test3(T::Type) ) ps = MOP.PresolveData(pb) - for i in 1:length(ps.var_types) - if ps.var_types[i] == MOP.GENERAL_INTEGER || ps.var_types[i] == MOP.BINARY - MOP.coefficient_strengthening!(ps, i) - end - end + MOP.coefficient_strengthening!(ps) + @test ps.urow == T[1e30, 4] @test ps.lrow == T[-7, -1e30] diff --git a/test/runtests.jl b/test/runtests.jl index f77ed02..452a42a 100755 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -27,4 +27,7 @@ end @testset "round integer bounds" begin include("mip/round_integer_bounds.jl") end + @testset "coeficient strengtheing" begin + include("mip/coefficient_strengthening.jl") + end end From 6387ed5dd1b2d7f48bd2a5f802c98c438f7b6338 Mon Sep 17 00:00:00 2001 From: tuna Date: Wed, 30 Dec 2020 19:32:04 -0600 Subject: [PATCH 05/27] remove julia 1.4 --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26970a1..6c56771 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,6 @@ jobs: fail-fast: false matrix: version: - - '1.4' - '1.5' - 'nightly' os: From 531ac5e7fcc7d3e7cfcefd5a001e0e67f23f8da8 Mon Sep 17 00:00:00 2001 From: tuna Date: Fri, 1 Jan 2021 17:51:02 -0600 Subject: [PATCH 06/27] remove infinity - using Inf instead of 1e30 --- src/mip/coefficient_strengthening.jl | 8 ++++---- test/mip/coefficient_strengthening.jl | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index cf62e20..5ffee49 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -42,7 +42,7 @@ function single_row_strengthening(row::RowOrCol{T}, b::T, m::Int, j::Int, ucol:: return a, b, a[m], flag end -function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30)) where {T} +function coefficient_strengthening!(ps::PresolveData{T}, j::Int) where {T} # perform coefficient strengthening on integer variable j (ps.var_types[j] != CONTINUOUS) || return nothing @@ -52,9 +52,9 @@ function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30 urow = ps.urow[i] m = findfirst(isequal(j), row.nzind) - if m == nothing || (lrow > -inf && urow < inf) + if m == nothing || (lrow > -Inf && urow < Inf) continue #skipping ranged constraints and - elseif urow < inf + elseif urow < Inf a, b, new_coef, updated = single_row_strengthening(row, urow, m, j, ps.ucol, ps.lcol) if updated row.nzval = a @@ -73,7 +73,7 @@ function coefficient_strengthening!(ps::PresolveData{T}, j::Int, inf::T = T(1e30 ps.pb0.acols[j].nzval[k] = new_coef end end - elseif lrow > -inf + elseif lrow > -Inf r = deepcopy(row) r.nzval = -r.nzval a, b, new_coef, updated = single_row_strengthening(r, -lrow, m, j, ps.ucol, ps.lcol) diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index 09b0b2c..cd41569 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -12,7 +12,7 @@ function coef_strengthen_test1(T::Type) C = T[1, 1, 1, 1] lc = T[0, 1, 0, 2] uc = T[1, 5//2, 1, 3] - lr = T[-1e30, -1e30] + lr = T[-Inf, -Inf] ur = T[8, 6] A = T[2 -5 4 3 0 1 1 1] @@ -33,7 +33,7 @@ function coef_strengthen_test1(T::Type) @test ps.urow == T[5, 9//2] - @test ps.lrow == T[-1e30, -1e30] + @test ps.lrow == T[-Inf, -Inf] @test ps.pb0.arows[1].nzind == [1, 2, 3, 4] @test ps.pb0.arows[1].nzval == T[2, -5, 4, 2] @@ -64,8 +64,8 @@ function coef_strengthen_test2(T::Type) w is integer =# C = T[1, 1, 1, 1] lc = T[0, 0, 0, -3] - uc = T[2, 1, 2, 10^30] - lr = T[-1e30, -1e30] + uc = T[2, 1, 2, Inf] + lr = T[-Inf, -Inf] ur = T[10, 20] A = T[1 1 1 -2 2 3 4 5] @@ -85,7 +85,7 @@ function coef_strengthen_test2(T::Type) MOP.coefficient_strengthening!(ps) @test ps.urow == T[7, 20] - @test ps.lrow == T[-1e30, -1e30] + @test ps.lrow == T[-Inf, -Inf] @test ps.pb0.arows[1].nzind == [1, 2, 3, 4] @test ps.pb0.arows[1].nzval == T[1, 1, 1, -1] @@ -119,8 +119,8 @@ function coef_strengthen_test3(T::Type) C = T[1, 1, 1, 1, 1] lc = T[-4, -3//2, 9, 0, -1] uc = T[2, 1, 15, 1, 1] - lr = T[2, -1e30] - ur = T[1e30, 13/3] + lr = T[2, -Inf] + ur = T[Inf, 13/3] A = T[1 -2 1 1 -1 1 1 0 1 1] @@ -139,8 +139,8 @@ function coef_strengthen_test3(T::Type) MOP.coefficient_strengthening!(ps) - @test ps.urow == T[1e30, 4] - @test ps.lrow == T[-7, -1e30] + @test ps.urow == T[Inf, 4] + @test ps.lrow == T[-7, -Inf] @test ps.pb0.arows[1].nzind == [1, 2, 5] @test ps.pb0.arows[1].nzval == T[1, -2, -1] From e5e945c1d038bc7ac8d4050f9597496beb6e5a06 Mon Sep 17 00:00:00 2001 From: tuna Date: Thu, 7 Jan 2021 15:24:42 -0600 Subject: [PATCH 07/27] row by row iteration - remove deepcopy - perform coefficient strengthening row by row instead of col by col --- src/mip/coefficient_strengthening.jl | 156 ++++++++++++++------------- src/presolve.jl | 7 +- 2 files changed, 84 insertions(+), 79 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 5ffee49..e979e1c 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -1,99 +1,105 @@ -function maximal_activity(row::RowOrCol{T}, j::Int, ucol::Vector{T}, lcol::Vector{T})::T where {T} +function maximal_activity(row::Row{T}, j::Int, ucol::Vector{T}, lcol::Vector{T})::T where {T} # compute the sup of row i (execpt the integer variable j) # only compute the maximal activity of any variables except j - nonzero_index = [i for i in 1:length(row.nzind) if row.nzind[i] != j] - nonzero_value = row.nzval[nonzero_index] + sup = zero(T) - pos_coef = deepcopy(nonzero_value) - neg_coef = deepcopy(nonzero_value) + for (k, a_k) in zip(row.nzind, row.nzval) + if k == j + continue + elseif a_k > zero(T) + sup += a_k*ucol[j] + else + sup += a_k*lcol[j] + end + end + return T(sup) +end - for i in 1:length(nonzero_value) - if nonzero_value[i] < 0 - pos_coef[i] = 0 +function minimal_activity(row::Row{T}, j::Int, ucol::Vector{T}, lcol::Vector{T})::T where {T} + # compute the inf of row i (execpt the integer variable j) + + # only compute the minimal activity of any variables except j + sup = zero(T) + + for (k, a_k) in zip(row.nzind, row.nzval) + if k == j + continue + elseif a_k > zero(T) + sup += a_k*lcol[j] else - neg_coef[i] = 0 + sup += a_k*ucol[j] end end - sup = ucol[nonzero_index]'pos_coef + lcol[nonzero_index]'neg_coef return T(sup) end -function single_row_strengthening(row::RowOrCol{T}, b::T, m::Int, j::Int, ucol::Vector{T}, lcol::Vector{T}) where {T} - # perform coef strengthening for one constraints of the from a'x < b - # and return new a' and b' - flag = false # wether there is an update - a = deepcopy(row.nzval) - if a[m] > 0 - d = b - maximal_activity(row, j, ucol, lcol) - a[m]*(ucol[j]-1) - if a[m] >= d && d > 0 - a[m] = a[m] - d - b = b - d*ucol[j] - flag = true +function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::In) where {T} + # perform coef strengthening for one constraints of the from a'x <= u + row = ps.pb0.arows[i] + a = row.nzval + u = ps.urow[i] + if a[j_index] > 0 + d = u - maximal_activity(row, j, ps.ucol, ps.lcol) - a[j_index]*(ps.ucol[j]-1) + if a[j_index] >= d && d > 0 + a[j_index] = a[j_index] - d + ps.urow[i] = u - d*ucol[j] end - elseif a[m] < 0 - d = b - maximal_activity(row, j, ucol, lcol) - a[m]*(lcol[j]+1) - if -a[m] >= d && d > 0 - a[m] = a[m] + d - b = b + d*lcol[j] - flag = true + elseif a[j_index] < 0 + d = u - maximal_activity(row, j, ps.ucol, ps.lcol) - a[j_index]*(ps.lcol[j]+1) + if -a[j_index] >= d && d > 0 + a[j_index] = a[j_index] + d + ps.urow[i] = u + d*lcol[j] end end - return a, b, a[m], flag + return nothing end -function coefficient_strengthening!(ps::PresolveData{T}, j::Int) where {T} - # perform coefficient strengthening on integer variable j - (ps.var_types[j] != CONTINUOUS) || return nothing - - for i in 1:length(ps.pb0.arows) - row = ps.pb0.arows[i] - lrow = ps.lrow[i] - urow = ps.urow[i] +function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::In) where {T} + # perform coef strengthening for one constraints of the from l < = a'x + row = ps.pb0.arows[i] + a = row.nzval + l = ps.urow[i] + if a[j_index] > 0 + d = -l + minimal_activity(row, j, ps.ucol, ps.lcol) + a[j_index]*(ps.lcol[j]+1) + if a[j_index] >= d && d > 0 + a[j_index] = a[j_index] - d + ps.lrow[i] = l - d*ps.lcol[j] + end + elseif a[j_index] < 0 + d = -l - minimal_activity(row, j, ps.ucol, ps.lcol) + a[j_index]*(ps.ucol[j]-1) + if -a[j_index] >= d && d > 0 + a[j_index] = a[j_index] + d + ps.urow[i] = u + d*ps.ucol[j] + end + end + return nothing +end - m = findfirst(isequal(j), row.nzind) - if m == nothing || (lrow > -Inf && urow < Inf) - continue #skipping ranged constraints and - elseif urow < Inf - a, b, new_coef, updated = single_row_strengthening(row, urow, m, j, ps.ucol, ps.lcol) - if updated - row.nzval = a - ps.urow[i] = b +function coefficient_strengthening!(ps::PresolveData{T}, i::Int) where {T} + # perform coefficient strengthening on row i + row = ps.pb0.arows[i] + lrow = ps.lrow[i] + urow = ps.urow[i] - # update collumns of A in problem data - # and update the sparse matrix in the case where the new coefficient is close to 0 - if abs(new_coef) <= eps(T) - deleteat!(row.nzind, m) - deleteat!(row.nzval, m) - k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - deleteat!(ps.pb0.acols[j].nzind, k) - deleteat!(ps.pb0.acols[j].nzval, k) - else - k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - ps.pb0.acols[j].nzval[k] = new_coef - end - end - elseif lrow > -Inf - r = deepcopy(row) - r.nzval = -r.nzval - a, b, new_coef, updated = single_row_strengthening(r, -lrow, m, j, ps.ucol, ps.lcol) - if updated - row.nzval = -a - ps.lrow[i] = -b + if lrow > -Inf && urow < Inf #skip ranged constraints + return nothing + end - # update collumns of A in problem data - if abs(new_coef) <= eps(T) - deleteat!(row.nzind, m) - deleteat!(row.nzval, m) - k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - deleteat!(ps.pb0.acols[j].nzind, k) - deleteat!(ps.pb0.acols[j].nzval, k) - else - k = findfirst(isequal(i), ps.pb0.acols[j].nzind) - ps.pb0.acols[j].nzval[k] = -new_coef - end + for j in ps.pb0.nvar + if ps.var_types[j] == CONTINUOUS || !ps.colflag[j] + continue + else + j_index = findfirst(isequal(j), row.nzind) # index of var j in sparse row + if j_index == nothing # zero coefficent variable + continue + elseif urow < Inf + upperbound_strengthening!(ps, i, j_index, j) + elseif lrow > -Inf + lowerbound_strengthening!(ps, i, j_index, j) end end end + return nothing end diff --git a/src/presolve.jl b/src/presolve.jl index f19436e..4c5d137 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -685,7 +685,7 @@ function remove_dominated_columns!(ps::PresolveData{T}) where {T} iszero(aij) && continue # empty column # Strengthen dual bounds - #= + #= =# cj = ps.obj[j] @@ -738,11 +738,10 @@ Called once at the very beginning of the presolve procedure. """ function coefficient_strengthening!(ps::PresolveData{T}) where {T} - # The problem is LP. ps.pb0.is_continuous && return nothing - for j in 1:ps.pb0.nvar - coefficient_strengthening!(ps, j) + for i in 1:ps.pb0.ncon + coefficient_strengthening!(ps, i) end return nothing end From 12f54be5b36ac3dd80d4a075f331434974d41557 Mon Sep 17 00:00:00 2001 From: tuna Date: Mon, 11 Jan 2021 18:53:12 -0600 Subject: [PATCH 08/27] update coef_strengthening - no longer using findfirst, which may cost nzlog(nz) worst-case time complexity --- src/mip/coefficient_strengthening.jl | 63 +++++++++++++++------------- src/presolve.jl | 14 ++++++- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index e979e1c..a0c0668 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -8,9 +8,9 @@ function maximal_activity(row::Row{T}, j::Int, ucol::Vector{T}, lcol::Vector{T}) if k == j continue elseif a_k > zero(T) - sup += a_k*ucol[j] + sup += a_k*ucol[k] else - sup += a_k*lcol[j] + sup += a_k*lcol[k] end end return T(sup) @@ -26,15 +26,15 @@ function minimal_activity(row::Row{T}, j::Int, ucol::Vector{T}, lcol::Vector{T}) if k == j continue elseif a_k > zero(T) - sup += a_k*lcol[j] + sup += a_k*lcol[k] else - sup += a_k*ucol[j] + sup += a_k*ucol[k] end end return T(sup) end -function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::In) where {T} +function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int)::T where {T} # perform coef strengthening for one constraints of the from a'x <= u row = ps.pb0.arows[i] a = row.nzval @@ -43,23 +43,23 @@ function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: d = u - maximal_activity(row, j, ps.ucol, ps.lcol) - a[j_index]*(ps.ucol[j]-1) if a[j_index] >= d && d > 0 a[j_index] = a[j_index] - d - ps.urow[i] = u - d*ucol[j] + ps.urow[i] = u - d*ps.ucol[j] end elseif a[j_index] < 0 d = u - maximal_activity(row, j, ps.ucol, ps.lcol) - a[j_index]*(ps.lcol[j]+1) if -a[j_index] >= d && d > 0 a[j_index] = a[j_index] + d - ps.urow[i] = u + d*lcol[j] + ps.urow[i] = u + d*ps.lcol[j] end end - return nothing + return T(a[j_index]) end -function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::In) where {T} +function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int)::T where {T} # perform coef strengthening for one constraints of the from l < = a'x row = ps.pb0.arows[i] a = row.nzval - l = ps.urow[i] + l = ps.lrow[i] if a[j_index] > 0 d = -l + minimal_activity(row, j, ps.ucol, ps.lcol) + a[j_index]*(ps.lcol[j]+1) if a[j_index] >= d && d > 0 @@ -73,31 +73,38 @@ function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: ps.urow[i] = u + d*ps.ucol[j] end end - return nothing + return T(a[j_index]) end -function coefficient_strengthening!(ps::PresolveData{T}, i::Int) where {T} - # perform coefficient strengthening on row i - row = ps.pb0.arows[i] - lrow = ps.lrow[i] - urow = ps.urow[i] +function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} + i_index = ones(Int, ps.pb0.nvar) # keep track of index for each var fo update ps.acols - if lrow > -Inf && urow < Inf #skip ranged constraints - return nothing - end + for i in 1:ps.pb0.ncon - for j in ps.pb0.nvar - if ps.var_types[j] == CONTINUOUS || !ps.colflag[j] + row = ps.pb0.arows[i] + lrow = ps.lrow[i] + urow = ps.urow[i] + if lrow > -Inf && urow < Inf #skip ranged constraints continue - else - j_index = findfirst(isequal(j), row.nzind) # index of var j in sparse row - if j_index == nothing # zero coefficent variable + end + + j_index = 0 # keep track of position of variable j in row.nzind & row.nzval + for j in row.nzind + j_index += 1 + if ps.var_types[j] == CONTINUOUS || !ps.colflag[j] continue - elseif urow < Inf - upperbound_strengthening!(ps, i, j_index, j) - elseif lrow > -Inf - lowerbound_strengthening!(ps, i, j_index, j) + else + if urow < Inf + new_coef = upperbound_strengthening!(ps, i, j_index, j) + ps.pb0.acols[j].nzval[i_index[j]] = new_coef + i_index[j] += 1 + elseif lrow > -Inf + new_coef = lowerbound_strengthening!(ps, i, j_index, j) + ps.pb0.acols[j].nzval[i_index[j]] = new_coef + i_index[j] += 1 + end end + end end diff --git a/src/presolve.jl b/src/presolve.jl index 4c5d137..b0b9866 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -740,8 +740,18 @@ Called once at the very beginning of the presolve procedure. function coefficient_strengthening!(ps::PresolveData{T}) where {T} ps.pb0.is_continuous && return nothing - for i in 1:ps.pb0.ncon - coefficient_strengthening!(ps, i) + zero_coefficient_strengthening!(ps) + + #removing 0 entries + for row in ps.pb0.arows + row.nzind = [row.nzind[i] for i in 1:length(row.nzval) if row.nzval[i] != 0] + row.nzval = [row.nzval[i] for i in 1:length(row.nzval) if row.nzval[i] != 0] + end + + for col in ps.pb0.acols + col.nzind = [col.nzind[i] for i in 1:length(col.nzval) if col.nzval[i] != 0] + col.nzval = [col.nzval[i] for i in 1:length(col.nzval) if col.nzval[i] != 0] end + return nothing end From 4038192631410833741be14a95e05599208592a5 Mon Sep 17 00:00:00 2001 From: tuna Date: Tue, 12 Jan 2021 16:47:34 -0600 Subject: [PATCH 09/27] O(nz) update - Update way in which the maximal activity of a row except variable j is compute --- src/mip/coefficient_strengthening.jl | 91 +++++++++++++++++----------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index a0c0668..99a973e 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -1,52 +1,42 @@ -function maximal_activity(row::Row{T}, j::Int, ucol::Vector{T}, lcol::Vector{T})::T where {T} - # compute the sup of row i (execpt the integer variable j) - - # only compute the maximal activity of any variables except j +function maximal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T where {T} sup = zero(T) - for (k, a_k) in zip(row.nzind, row.nzval) - if k == j - continue - elseif a_k > zero(T) - sup += a_k*ucol[k] + for (j, aij) in zip(row.nzind, row.nzval) + if aij > zero(T) + sup += aij*ucol[j] else - sup += a_k*lcol[k] + sup += aij*lcol[j] end end return T(sup) end -function minimal_activity(row::Row{T}, j::Int, ucol::Vector{T}, lcol::Vector{T})::T where {T} - # compute the inf of row i (execpt the integer variable j) - - # only compute the minimal activity of any variables except j - sup = zero(T) +function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T where {T} + inf = zero(T) - for (k, a_k) in zip(row.nzind, row.nzval) - if k == j - continue - elseif a_k > zero(T) - sup += a_k*lcol[k] + for (j, aij) in zip(row.nzind, row.nzval) + if aij > zero(T) + inf += aij*lcol[j] else - sup += a_k*ucol[k] + inf += aij*ucol[j] end end - return T(sup) + return T(inf) end -function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int)::T where {T} +function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, max_act) where {T} # perform coef strengthening for one constraints of the from a'x <= u row = ps.pb0.arows[i] a = row.nzval u = ps.urow[i] if a[j_index] > 0 - d = u - maximal_activity(row, j, ps.ucol, ps.lcol) - a[j_index]*(ps.ucol[j]-1) + d = u - max_act - a[j_index]*(ps.ucol[j]-1) if a[j_index] >= d && d > 0 a[j_index] = a[j_index] - d ps.urow[i] = u - d*ps.ucol[j] end elseif a[j_index] < 0 - d = u - maximal_activity(row, j, ps.ucol, ps.lcol) - a[j_index]*(ps.lcol[j]+1) + d = u - max_act - a[j_index]*(ps.lcol[j]+1) if -a[j_index] >= d && d > 0 a[j_index] = a[j_index] + d ps.urow[i] = u + d*ps.lcol[j] @@ -55,19 +45,19 @@ function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: return T(a[j_index]) end -function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int)::T where {T} +function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, min_act) where {T} # perform coef strengthening for one constraints of the from l < = a'x row = ps.pb0.arows[i] a = row.nzval l = ps.lrow[i] if a[j_index] > 0 - d = -l + minimal_activity(row, j, ps.ucol, ps.lcol) + a[j_index]*(ps.lcol[j]+1) + d = -l + min_act + a[j_index]*(ps.lcol[j]+1) if a[j_index] >= d && d > 0 a[j_index] = a[j_index] - d ps.lrow[i] = l - d*ps.lcol[j] end elseif a[j_index] < 0 - d = -l - minimal_activity(row, j, ps.ucol, ps.lcol) + a[j_index]*(ps.ucol[j]-1) + d = -l - min_act + a[j_index]*(ps.ucol[j]-1) if -a[j_index] >= d && d > 0 a[j_index] = a[j_index] + d ps.urow[i] = u + d*ps.ucol[j] @@ -77,36 +67,65 @@ function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: end function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} - i_index = ones(Int, ps.pb0.nvar) # keep track of index for each var fo update ps.acols + # perform coefficient stregthening but if there is a coefficient is reduced to 0 + # it is still kept in the sparse matrix (will be removed later) + # keep track of index for each var fo update ps.acols + # 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 - row = ps.pb0.arows[i] lrow = ps.lrow[i] urow = ps.urow[i] if lrow > -Inf && urow < Inf #skip ranged constraints continue end - j_index = 0 # keep track of position of variable j in row.nzind & row.nzval + row = ps.pb0.arows[i] + sup = maximal_activity(row, ps.ucol, ps.lcol) + inf = minimal_activity(row, ps.ucol, ps.lcol) + + 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 + coef = row.nzval[j_index] if urow < Inf - new_coef = upperbound_strengthening!(ps, i, j_index, j) + 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 = upperbound_strengthening!(ps, i, j_index, j, max_act) ps.pb0.acols[j].nzval[i_index[j]] = new_coef - i_index[j] += 1 + #update sup + if coef > 0 + sup = sup - (coef - new_coef) * ps.ucol[j] + else + sup = sup - (coef - new_coef) * ps.lcol[j] + end elseif lrow > -Inf - new_coef = lowerbound_strengthening!(ps, i, j_index, j) + 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 = lowerbound_strengthening!(ps, i, j_index, j, min_act) ps.pb0.acols[j].nzval[i_index[j]] = new_coef - i_index[j] += 1 + #update inf + if coef > 0 + inf = inf - (coef - new_coef) * ps.lcol[j] + else + inf = inf - (coef - new_coef) * ps.ucol[j] + end end end end end - return nothing end From d2b4cce8efaf323de67f0c791da3977381c3c286 Mon Sep 17 00:00:00 2001 From: tuna Date: Thu, 21 Jan 2021 16:26:41 -0600 Subject: [PATCH 10/27] Update - skip row with no integer variable - set rowflag/colflag - update #nonzeros in each row/col - add docs --- src/mip/coefficient_strengthening.jl | 50 +++++++++++++++++++++++---- src/presolve.jl | 19 +++++----- test/mip/coefficient_strengthening.jl | 42 +++++++++++++--------- 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 99a973e..3294546 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -1,3 +1,26 @@ +""" +Perform coefficient strengthening on each row and on each integer variables + +In particular, for the i-th constraints of the form +aᵢ x ⩽ bᵢ and let xⱼ be 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 +aᵢⱼ ≔ aᵢⱼ - d +bᵢ ≔ bᵢ - duⱼ +Also perform coefficient strengthening on constraints of the form aᵢ x ⩾ cᵢ +with similar update rule + +Skip ranged constraints, i.e, cᵢ ⩽ aᵢ x ⩽ bᵢ + +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 only the nonzeros are updated + +If a row is reduced to 0 after this step, it is set to be inactive +If a column is reduced to 0 after this step, it is set to be inactive + +""" function maximal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T where {T} sup = zero(T) @@ -31,13 +54,13 @@ function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: u = ps.urow[i] if a[j_index] > 0 d = u - max_act - a[j_index]*(ps.ucol[j]-1) - if a[j_index] >= d && d > 0 + if a[j_index] >= d > 0 a[j_index] = a[j_index] - d ps.urow[i] = u - d*ps.ucol[j] end elseif a[j_index] < 0 d = u - max_act - a[j_index]*(ps.lcol[j]+1) - if -a[j_index] >= d && d > 0 + if -a[j_index] >= d > 0 a[j_index] = a[j_index] + d ps.urow[i] = u + d*ps.lcol[j] end @@ -52,13 +75,13 @@ function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: l = ps.lrow[i] if a[j_index] > 0 d = -l + min_act + a[j_index]*(ps.lcol[j]+1) - if a[j_index] >= d && d > 0 + if a[j_index] >= d > 0 a[j_index] = a[j_index] - d ps.lrow[i] = l - d*ps.lcol[j] end elseif a[j_index] < 0 d = -l - min_act + a[j_index]*(ps.ucol[j]-1) - if -a[j_index] >= d && d > 0 + if -a[j_index] >= d > 0 a[j_index] = a[j_index] + d ps.urow[i] = u + d*ps.ucol[j] end @@ -68,12 +91,12 @@ end function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} # perform coefficient stregthening but if there is a coefficient is reduced to 0 - # it is still kept in the sparse matrix (will be removed later) + # it is still kept in the ps.pb0.arows and ps.pb0.acols # keep track of index for each var fo update ps.acols # 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 lrow = ps.lrow[i] @@ -83,6 +106,10 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} end row = ps.pb0.arows[i] + if all(ps.var_types[row.nzind] .== CONTINUOUS) # at least 1 integer + continue + end + sup = maximal_activity(row, ps.ucol, ps.lcol) inf = minimal_activity(row, ps.ucol, ps.lcol) @@ -94,6 +121,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} continue else coef = row.nzval[j_index] + if urow < Inf if coef > 0 max_act = sup - coef * ps.ucol[j] # maximal activity of every variables except j @@ -102,6 +130,11 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} end new_coef = upperbound_strengthening!(ps, i, j_index, j, max_act) ps.pb0.acols[j].nzval[i_index[j]] = new_coef + #update nonzero + if new_coef == 0 + ps.nzrow[i] -= 1 + ps.nzcol[j] -= 1 + end #update sup if coef > 0 sup = sup - (coef - new_coef) * ps.ucol[j] @@ -116,6 +149,11 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} end new_coef = lowerbound_strengthening!(ps, i, j_index, j, min_act) ps.pb0.acols[j].nzval[i_index[j]] = new_coef + #update nonzero + if new_coef == 0 + ps.nzrow[i] -= 1 + ps.nzcol[j] -= 1 + end #update inf if coef > 0 inf = inf - (coef - new_coef) * ps.lcol[j] diff --git a/src/presolve.jl b/src/presolve.jl index b0b9866..8f33e2b 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -629,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 @@ -742,15 +743,17 @@ function coefficient_strengthening!(ps::PresolveData{T}) where {T} zero_coefficient_strengthening!(ps) - #removing 0 entries - for row in ps.pb0.arows - row.nzind = [row.nzind[i] for i in 1:length(row.nzval) if row.nzval[i] != 0] - row.nzval = [row.nzval[i] for i in 1:length(row.nzval) if row.nzval[i] != 0] + # inactive rows + for (i, row) in enumerate(ps.pb0.arows) + if all(row.nzval .== 0) + ps.rowflag[i] = false + end end - - for col in ps.pb0.acols - col.nzind = [col.nzind[i] for i in 1:length(col.nzval) if col.nzval[i] != 0] - col.nzval = [col.nzval[i] for i in 1:length(col.nzval) if col.nzval[i] != 0] + # inactive cols + for (j, col) in enumerate(ps.pb0.acols) + if all(col.nzval .== 0) + ps.colflag[j] = false + end end return nothing diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index cd41569..aced75e 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -110,6 +110,8 @@ function coef_strengthen_test3(T::Type) min x₁ + x₂ + x₃ + x₄ + x₅ s.t. 2 ⩽x₁ + -2x₂ + x₃ + x₄ + -x₅ x₁ + x₂ + x₄ + x₅ ⩽ 4.333 + 2x₃ ⩽ 30 + 1.5 x₁ + 2x₂ - x₅ ⩽ 2.5 -4 ⩽ x₁ ⩽ 2 -1.5 ⩽ x₂ ⩽ 1 9 ⩽ x₃ ⩽ 15 @@ -117,12 +119,17 @@ function coef_strengthen_test3(T::Type) -1 ⩽ x₅ ⩽ 1 x₃ is integer, x₄ is binary =# C = T[1, 1, 1, 1, 1] + lc = T[-4, -3//2, 9, 0, -1] uc = T[2, 1, 15, 1, 1] - lr = T[2, -Inf] - ur = T[Inf, 13/3] + + lr = T[2, -Inf, -Inf, -Inf] + ur = T[Inf, 13/3, 30, 5//2] + A = T[1 -2 1 1 -1 - 1 1 0 1 1] + 1 1 0 1 1 + 0 0 2 0 0 + 3//2 2 0 0 -1] varTypes = [MOP.CONTINUOUS, MOP.CONTINUOUS, MOP.GENERAL_INTEGER, MOP.BINARY, MOP.CONTINUOUS] @@ -139,23 +146,26 @@ function coef_strengthen_test3(T::Type) MOP.coefficient_strengthening!(ps) - @test ps.urow == T[Inf, 4] - @test ps.lrow == T[-7, -Inf] + @test ps.urow == T[Inf, 4, 0, 5//2] + @test ps.lrow == T[-7, -Inf, -Inf, -Inf] - @test ps.pb0.arows[1].nzind == [1, 2, 5] - @test ps.pb0.arows[1].nzval == T[1, -2, -1] - @test ps.pb0.arows[2].nzind == [1, 2, 4, 5] + @test ps.pb0.arows[1].nzval == T[1, -2, 0, 0, -1] @test isapprox(ps.pb0.arows[2].nzval, T[1, 1, 2//3, 1], atol = 1e-12) + @test ps.pb0.arows[3].nzval == T[0] + @test ps.pb0.arows[4].nzval == T[3//2, 2,-1] - @test ps.pb0.acols[1].nzind == [1, 2] - @test ps.pb0.acols[1].nzval == T[1, 1] - @test ps.pb0.acols[2].nzind == [1, 2] - @test ps.pb0.acols[2].nzval == T[-2, 1] - @test ps.pb0.acols[3].nzind == [] - @test ps.pb0.acols[3].nzval == T[] - @test ps.pb0.acols[4].nzind == [2] - @test isapprox(ps.pb0.acols[4].nzval, T[2//3], atol = 1e-12) + @test ps.pb0.acols[1].nzval == T[1, 1, 3//2] + @test ps.pb0.acols[2].nzval == T[-2, 1, 2] + @test ps.pb0.acols[3].nzval == T[0, 0] + @test isapprox(ps.pb0.acols[4].nzval, T[0, 2//3], atol = 1e-12) + @test ps.pb0.acols[5].nzval == T[-1, 1, -1] + + @test ps.colflag[3] == false + @test ps.rowflag[3] == false + + @test ps.nzrow == [3, 4, 0, 3] + @test ps.nzcol == [3, 3, 0, 1, 3] @test ps.status == MOP.NOT_INFERRED return nothing From 30fa4520f131d0ce5215bb5adef018d99211bf7e Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Fri, 22 Jan 2021 15:41:57 -0600 Subject: [PATCH 11/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 3294546..dd1d5a5 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -101,7 +101,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} lrow = ps.lrow[i] urow = ps.urow[i] - if lrow > -Inf && urow < Inf #skip ranged constraints + if isfinite(lrow) && isfinite(urow) # skip ranged constraints continue end From 9d44a01b70a8e6f00a4f30f21ba8bdbafbe9d886 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Fri, 22 Jan 2021 15:42:06 -0600 Subject: [PATCH 12/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index dd1d5a5..cc45ba4 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -48,7 +48,7 @@ function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher end function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, max_act) where {T} - # perform coef strengthening for one constraints of the from a'x <= u + # perform coef strengthening for one constraint of the form a'x <= u row = ps.pb0.arows[i] a = row.nzval u = ps.urow[i] From 67f9de0b44a7a78f973bca21525905bc6abf08f1 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Fri, 22 Jan 2021 15:42:44 -0600 Subject: [PATCH 13/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index cc45ba4..480ecb3 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -119,7 +119,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} i_index[j] += 1 if ps.var_types[j] == CONTINUOUS || !ps.colflag[j] continue - else + end coef = row.nzval[j_index] if urow < Inf From e76f98965577c35e4a7dd26955ef09867d805d48 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Fri, 22 Jan 2021 15:50:45 -0600 Subject: [PATCH 14/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 480ecb3..03debe0 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -86,7 +86,7 @@ function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: ps.urow[i] = u + d*ps.ucol[j] end end - return T(a[j_index]) + return a[j_index] end function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} From fb5e4ddfed6bffe69aef5ee8e7f59e1d67e48f21 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Fri, 22 Jan 2021 15:51:50 -0600 Subject: [PATCH 15/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 03debe0..823040e 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -40,7 +40,7 @@ function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher for (j, aij) in zip(row.nzind, row.nzval) if aij > zero(T) inf += aij*lcol[j] - else + elseif aij < zero(T) inf += aij*ucol[j] end end From e964e7bb4fd1c4cb290fe46394866d5857c9320e Mon Sep 17 00:00:00 2001 From: tuna Date: Fri, 22 Jan 2021 16:31:33 -0600 Subject: [PATCH 16/27] consistent update - update all problem's parameters in the same block --- src/mip/coefficient_strengthening.jl | 53 ++++++++++++++++------------ 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 823040e..65b12c5 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -40,7 +40,7 @@ function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher for (j, aij) in zip(row.nzind, row.nzval) if aij > zero(T) inf += aij*lcol[j] - elseif aij < zero(T) + else inf += aij*ucol[j] end end @@ -48,45 +48,47 @@ function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher end function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, max_act) where {T} - # perform coef strengthening for one constraint of the form a'x <= u + # perform coef strengthening for one constraints of the from a'x <= u row = ps.pb0.arows[i] a = row.nzval - u = ps.urow[i] + new_bound = ps.urow[i] + new_coef = a[j_index] if a[j_index] > 0 - d = u - max_act - a[j_index]*(ps.ucol[j]-1) + d = new_bound - max_act - a[j_index]*(ps.ucol[j]-1) if a[j_index] >= d > 0 - a[j_index] = a[j_index] - d - ps.urow[i] = u - d*ps.ucol[j] + new_coef = new_coef - d + new_bound = new_bound - d*ps.ucol[j] end elseif a[j_index] < 0 - d = u - max_act - a[j_index]*(ps.lcol[j]+1) + d = new_bound - max_act - a[j_index]*(ps.lcol[j]+1) if -a[j_index] >= d > 0 - a[j_index] = a[j_index] + d - ps.urow[i] = u + d*ps.lcol[j] + new_coef = new_coef + d + new_bound = new_bound + d*ps.lcol[j] end end - return T(a[j_index]) + return new_coef, new_bound end function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, min_act) where {T} # perform coef strengthening for one constraints of the from l < = a'x row = ps.pb0.arows[i] a = row.nzval - l = ps.lrow[i] + new_bound = ps.lrow[i] + new_coef = a[j_index] if a[j_index] > 0 - d = -l + min_act + a[j_index]*(ps.lcol[j]+1) + d = -new_bound + min_act + a[j_index]*(ps.lcol[j]+1) if a[j_index] >= d > 0 - a[j_index] = a[j_index] - d - ps.lrow[i] = l - d*ps.lcol[j] + new_coef = a[j_index] - d + new_bound = new_bound - d*ps.lcol[j] end elseif a[j_index] < 0 - d = -l - min_act + a[j_index]*(ps.ucol[j]-1) + d = -new_bound - min_act + a[j_index]*(ps.ucol[j]-1) if -a[j_index] >= d > 0 - a[j_index] = a[j_index] + d - ps.urow[i] = u + d*ps.ucol[j] + new_coef = a[j_index] + d + new_bound = new_bound + d*ps.ucol[j] end end - return a[j_index] + return new_coef, new_bound end function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} @@ -101,7 +103,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} lrow = ps.lrow[i] urow = ps.urow[i] - if isfinite(lrow) && isfinite(urow) # skip ranged constraints + if lrow > -Inf && urow < Inf #skip ranged constraints continue end @@ -119,7 +121,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} i_index[j] += 1 if ps.var_types[j] == CONTINUOUS || !ps.colflag[j] continue - end + else coef = row.nzval[j_index] if urow < Inf @@ -128,8 +130,11 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else max_act = sup - coef * ps.lcol[j] end - new_coef = upperbound_strengthening!(ps, i, j_index, j, max_act) + new_coef, new_bound = upperbound_strengthening!(ps, i, j_index, j, 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 new_coef == 0 ps.nzrow[i] -= 1 @@ -147,8 +152,11 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else min_act = inf - coef * ps.ucol[j] end - new_coef = lowerbound_strengthening!(ps, i, j_index, j, min_act) + new_coef, new_bound = lowerbound_strengthening!(ps, i, j_index, j, 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 new_coef == 0 ps.nzrow[i] -= 1 @@ -162,7 +170,6 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} end end end - end end return nothing From a2faa0aab1715975267e48f0db465de63b351584 Mon Sep 17 00:00:00 2001 From: tuna Date: Fri, 22 Jan 2021 16:40:02 -0600 Subject: [PATCH 17/27] using isfinite --- src/mip/coefficient_strengthening.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 65b12c5..fec4a84 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -103,7 +103,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} lrow = ps.lrow[i] urow = ps.urow[i] - if lrow > -Inf && urow < Inf #skip ranged constraints + if isfinite(lrow) && isfinite(urow) #skip ranged constraints continue end @@ -124,7 +124,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else coef = row.nzval[j_index] - if urow < Inf + if isfinite(urow) if coef > 0 max_act = sup - coef * ps.ucol[j] # maximal activity of every variables except j else @@ -146,7 +146,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else sup = sup - (coef - new_coef) * ps.lcol[j] end - elseif lrow > -Inf + elseif isfinite(lrow) if coef > 0 min_act = inf - coef * ps.lcol[j] # minimal activity of every variables except j else From 1a292109e47d50243352f9f9fb7fb415115a8c8e Mon Sep 17 00:00:00 2001 From: tuna Date: Fri, 22 Jan 2021 16:54:23 -0600 Subject: [PATCH 18/27] minor fix --- src/mip/coefficient_strengthening.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index fec4a84..215339f 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -27,7 +27,7 @@ function maximal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher for (j, aij) in zip(row.nzind, row.nzval) if aij > zero(T) sup += aij*ucol[j] - else + elseif aij < zero(T) sup += aij*lcol[j] end end @@ -40,7 +40,7 @@ function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher for (j, aij) in zip(row.nzind, row.nzval) if aij > zero(T) inf += aij*lcol[j] - else + elseif aij < zero(T) inf += aij*ucol[j] end end From 3eb946ec32c8b3d69325fe6bf1666b42401fde41 Mon Sep 17 00:00:00 2001 From: tuna Date: Sat, 23 Jan 2021 14:41:50 -0600 Subject: [PATCH 19/27] Add test - add one more test - edit docs (period and complete sentence) - using += and -= --- src/mip/coefficient_strengthening.jl | 49 +++++++++++----------- test/mip/coefficient_strengthening.jl | 59 +++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 215339f..f7d50a9 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -1,26 +1,25 @@ """ -Perform coefficient strengthening on each row and on each integer variables +Perform coefficient strengthening on each row and on each integer variable. In particular, for the i-th constraints of the form aᵢ x ⩽ bᵢ and let xⱼ be 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 -aᵢⱼ ≔ aᵢⱼ - d -bᵢ ≔ bᵢ - duⱼ -Also perform coefficient strengthening on constraints of the form aᵢ x ⩾ cᵢ -with similar update rule +and uⱼ is upper bound of xⱼ, then we transform +aᵢⱼ <- aᵢⱼ - d +bᵢ <- bᵢ - duⱼ . -Skip ranged constraints, i.e, cᵢ ⩽ aᵢ x ⩽ bᵢ +A similar update rule is applied for the constraints of the form cᵢ ⩽ aᵢ x. -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 only the nonzeros are updated +In case the constraint is ranged, i.e, cᵢ ⩽ aᵢ x ⩽ bᵢ, no coefficient strengthening is performed. -If a row is reduced to 0 after this step, it is set to be inactive -If a column is reduced to 0 after this step, it is set to be inactive +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(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T where {T} sup = zero(T) @@ -47,7 +46,7 @@ function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T wher return T(inf) end -function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, max_act) where {T} +function upperbound_strengthening(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, max_act) where {T} # perform coef strengthening for one constraints of the from a'x <= u row = ps.pb0.arows[i] a = row.nzval @@ -57,19 +56,19 @@ function upperbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: d = new_bound - max_act - a[j_index]*(ps.ucol[j]-1) if a[j_index] >= d > 0 new_coef = new_coef - d - new_bound = new_bound - d*ps.ucol[j] + new_bound -= d*ps.ucol[j] end elseif a[j_index] < 0 d = new_bound - max_act - a[j_index]*(ps.lcol[j]+1) if -a[j_index] >= d > 0 new_coef = new_coef + d - new_bound = new_bound + d*ps.lcol[j] + new_bound += d*ps.lcol[j] end end return new_coef, new_bound end -function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, min_act) where {T} +function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, min_act) where {T} # perform coef strengthening for one constraints of the from l < = a'x row = ps.pb0.arows[i] a = row.nzval @@ -79,13 +78,13 @@ function lowerbound_strengthening!(ps::PresolveData{T}, i::Int, j_index::Int, j: d = -new_bound + min_act + a[j_index]*(ps.lcol[j]+1) if a[j_index] >= d > 0 new_coef = a[j_index] - d - new_bound = new_bound - d*ps.lcol[j] + new_bound -= d*ps.lcol[j] end elseif a[j_index] < 0 - d = -new_bound - min_act + a[j_index]*(ps.ucol[j]-1) + d = -new_bound + min_act + a[j_index]*(ps.ucol[j]-1) if -a[j_index] >= d > 0 new_coef = a[j_index] + d - new_bound = new_bound + d*ps.ucol[j] + new_bound += d*ps.ucol[j] end end return new_coef, new_bound @@ -130,7 +129,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else max_act = sup - coef * ps.lcol[j] end - new_coef, new_bound = upperbound_strengthening!(ps, i, j_index, j, max_act) + new_coef, new_bound = upperbound_strengthening(ps, i, j_index, j, max_act) # update problem row.nzval[j_index] = new_coef ps.pb0.acols[j].nzval[i_index[j]] = new_coef @@ -142,9 +141,9 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} end #update sup if coef > 0 - sup = sup - (coef - new_coef) * ps.ucol[j] + sup -= (coef - new_coef) * ps.ucol[j] else - sup = sup - (coef - new_coef) * ps.lcol[j] + sup -= (coef - new_coef) * ps.lcol[j] end elseif isfinite(lrow) if coef > 0 @@ -152,7 +151,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else min_act = inf - coef * ps.ucol[j] end - new_coef, new_bound = lowerbound_strengthening!(ps, i, j_index, j, min_act) + new_coef, new_bound = lowerbound_strengthening(ps, i, j_index, j, min_act) #update problem row.nzval[j_index] = new_coef ps.pb0.acols[j].nzval[i_index[j]] = new_coef @@ -164,9 +163,9 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} end #update inf if coef > 0 - inf = inf - (coef - new_coef) * ps.lcol[j] + inf -= (coef - new_coef) * ps.lcol[j] else - inf = inf - (coef - new_coef) * ps.ucol[j] + inf -= (coef - new_coef) * ps.ucol[j] end end end diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index aced75e..150b54f 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -171,10 +171,69 @@ function coef_strengthen_test3(T::Type) return nothing end +function coef_strengthen_test4(T::Type) + #= + min x + y + z + s.t. -6 ⩽ x - y + -10 ⩽ x + 2y + 3z ⩽ 10 + -1 ⩽ x + y ⩽ 6 + y is integer =# + + C = T[1, 1, 1] + + lc = T[-1, -Inf, -Inf] + uc = T[Inf, 6, Inf] + + lr = T[-61//10, -10] + ur = T[Inf, 10] + + A = T[1 -1 0 + 1 2 3] + + varTypes = [MOP.CONTINUOUS, MOP.GENERAL_INTEGER, MOP.CONTINUOUS] + + pb = MOP.ProblemData{T}() + + MOP.load_problem!(pb, "Test", + true, C, zero(T), + sparse(A), lr, ur, lc, uc, + varTypes + ) + ps = MOP.PresolveData(pb) + + MOP.coefficient_strengthening!(ps) + + @test ps.urow == T[Inf, 10] + @test isapprox(ps.lrow, T[-55/10, -10], atol = 1e-12) + + @test ps.pb0.arows[1].nzind == [1, 2] + @test isapprox(ps.pb0.arows[1].nzval, T[1, -9//10], atol = 1e-12) + @test ps.pb0.arows[2].nzind == [1, 2, 3] + @test ps.pb0.arows[2].nzval == T[1, 2, 3] + + + @test ps.pb0.acols[1].nzind == [1, 2] + @test ps.pb0.acols[1].nzval == T[1, 1] + @test ps.pb0.acols[2].nzind == [1, 2] + @test isapprox(ps.pb0.acols[2].nzval, T[-9//10,2], atol = 1e-12) + @test ps.pb0.acols[3].nzind == [2] + @test ps.pb0.acols[3].nzval == T[3] + + @test ps.rowflag[1] == true + @test ps.rowflag[2] == true + + @test ps.colflag[1] == true + @test ps.colflag[2] == true + @test ps.colflag[3] == true + + return nothing +end @testset "Coefficient Strengthening" begin for T in COEFF_TYPES @testset "$T" begin coef_strengthen_test1(T) end @testset "$T" begin coef_strengthen_test2(T) end @testset "$T" begin coef_strengthen_test3(T) end + @testset "$T" begin coef_strengthen_test4(T) end end end From 6eb7c75e9b3bd21fe3e05ee94fa5194b3c78f8ba Mon Sep 17 00:00:00 2001 From: tuna Date: Sat, 23 Jan 2021 15:30:33 -0600 Subject: [PATCH 20/27] fix --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 452a42a..8280430 100755 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -27,7 +27,7 @@ end @testset "round integer bounds" begin include("mip/round_integer_bounds.jl") end - @testset "coeficient strengtheing" begin + @testset "coefficient strengthening" begin include("mip/coefficient_strengthening.jl") end end From 0b4b83e41ecfce2038ab964744d54134086868e0 Mon Sep 17 00:00:00 2001 From: tuna Date: Sat, 30 Jan 2021 17:11:53 -0600 Subject: [PATCH 21/27] skip deactivated rows/cols --- src/mip/coefficient_strengthening.jl | 65 ++++++++++++++-------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index f7d50a9..e9901ce 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -20,47 +20,49 @@ 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(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T where {T} +function maximal_activity(ps::PresolveData{T}, i::Int)::T where {T} 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*ucol[j] + sup += aij * ps.ucol[j] elseif aij < zero(T) - sup += aij*lcol[j] + sup += aij * ps.lcol[j] end end return T(sup) end -function minimal_activity(row::Row{T}, ucol::Vector{T}, lcol::Vector{T})::T where {T} +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) + ps.colflag[j] || continue if aij > zero(T) - inf += aij*lcol[j] + inf += aij * ps.lcol[j] elseif aij < zero(T) - inf += aij*ucol[j] + inf += aij * ps.ucol[j] end end return T(inf) end -function upperbound_strengthening(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, max_act) where {T} +function upperbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, max_act::T) where {T} # perform coef strengthening for one constraints of the from a'x <= u - row = ps.pb0.arows[i] - a = row.nzval new_bound = ps.urow[i] - new_coef = a[j_index] - if a[j_index] > 0 - d = new_bound - max_act - a[j_index]*(ps.ucol[j]-1) - if a[j_index] >= d > 0 + 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 a[j_index] < 0 - d = new_bound - max_act - a[j_index]*(ps.lcol[j]+1) - if -a[j_index] >= d > 0 + 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 @@ -68,22 +70,20 @@ function upperbound_strengthening(ps::PresolveData{T}, i::Int, j_index::Int, j:: return new_coef, new_bound end -function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j_index::Int, j::Int, min_act) where {T} +function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, min_act::T) where {T} # perform coef strengthening for one constraints of the from l < = a'x - row = ps.pb0.arows[i] - a = row.nzval new_bound = ps.lrow[i] - new_coef = a[j_index] - if a[j_index] > 0 - d = -new_bound + min_act + a[j_index]*(ps.lcol[j]+1) - if a[j_index] >= d > 0 - new_coef = a[j_index] - d + 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 a[j_index] < 0 - d = -new_bound + min_act + a[j_index]*(ps.ucol[j]-1) - if -a[j_index] >= d > 0 - new_coef = a[j_index] + d + 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 @@ -99,6 +99,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} i_index = zeros(Int, ps.pb0.nvar) for i in 1:ps.pb0.ncon + ps.rowflag[i] || continue lrow = ps.lrow[i] urow = ps.urow[i] @@ -111,8 +112,8 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} continue end - sup = maximal_activity(row, ps.ucol, ps.lcol) - inf = minimal_activity(row, ps.ucol, ps.lcol) + 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 @@ -129,7 +130,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else max_act = sup - coef * ps.lcol[j] end - new_coef, new_bound = upperbound_strengthening(ps, i, j_index, j, max_act) + 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 @@ -151,7 +152,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} else min_act = inf - coef * ps.ucol[j] end - new_coef, new_bound = lowerbound_strengthening(ps, i, j_index, j, min_act) + 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 From 1ea9b793796a85f8f0bd615f452a0d8400e4cf25 Mon Sep 17 00:00:00 2001 From: tuna Date: Sat, 30 Jan 2021 17:33:26 -0600 Subject: [PATCH 22/27] fix bumped comments --- src/mip/coefficient_strengthening.jl | 18 ++++++++++-------- src/presolve.jl | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index e9901ce..b026595 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -1,8 +1,8 @@ """ Perform coefficient strengthening on each row and on each integer variable. -In particular, for the i-th constraints of the form -aᵢ x ⩽ bᵢ and let xⱼ be a integer/binary 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 @@ -31,8 +31,9 @@ function maximal_activity(ps::PresolveData{T}, i::Int)::T where {T} elseif aij < zero(T) sup += aij * ps.lcol[j] end + isfinite(sup) || return sup end - return T(sup) + return sup end function minimal_activity(ps::PresolveData{T}, i::Int)::T where {T} @@ -46,12 +47,13 @@ function minimal_activity(ps::PresolveData{T}, i::Int)::T where {T} elseif aij < zero(T) inf += aij * ps.ucol[j] end + isfinite(inf) || return inf end - return T(inf) + return inf end function upperbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, max_act::T) where {T} - # perform coef strengthening for one constraints of the from a'x <= u + # perform coef strengthening for one constraint of the form a'x <= u new_bound = ps.urow[i] new_coef = coef if coef > 0 @@ -71,7 +73,7 @@ function upperbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, max end function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, min_act::T) where {T} - # perform coef strengthening for one constraints of the from l < = a'x + # perform coef strengthening for one constraint of the form l < = a'x new_bound = ps.lrow[i] new_coef = coef if coef > 0 @@ -91,8 +93,8 @@ function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, min end function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} - # perform coefficient stregthening but if there is a coefficient is reduced to 0 - # it is still kept in the ps.pb0.arows and ps.pb0.acols + # 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 # use this to find which index of ps.pb0.acols[i].nzval to update diff --git a/src/presolve.jl b/src/presolve.jl index 8f33e2b..efcecca 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -415,7 +415,7 @@ function presolve!(ps::PresolveData{T}) where {T} # Round the bounds of integer variables are integers. round_integer_bounds!(ps) - # Coeficient strengthening + # Coefficient strengthening coefficient_strengthening!(ps) # Check bound consistency on all rows/columns @@ -735,7 +735,7 @@ end Perform coefficient strengthening for integer/binary variables on every constraints. -Called once at the very beginning of the presolve procedure. +Called once at the beginning of the presolve procedure. """ function coefficient_strengthening!(ps::PresolveData{T}) where {T} From 3e7fdc3c2393cb9726c904fc7935e0234f752788 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Sat, 30 Jan 2021 17:55:42 -0600 Subject: [PATCH 23/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index b026595..ffbca1e 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -138,7 +138,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} ps.pb0.acols[j].nzval[i_index[j]] = new_coef ps.urow[i] = new_bound #update nonzero - if new_coef == 0 + if !iszero(coef) && iszero(new_coef) ps.nzrow[i] -= 1 ps.nzcol[j] -= 1 end From 72cb1adf1aa75d8dbe45a0e399c8dc17b6830f62 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Sat, 30 Jan 2021 17:56:06 -0600 Subject: [PATCH 24/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index ffbca1e..0c69c23 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -160,7 +160,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} ps.pb0.acols[j].nzval[i_index[j]] = new_coef ps.lrow[i] = new_bound #update nonzero - if new_coef == 0 + if !iszero(coef) && iszero(new_coef) ps.nzrow[i] -= 1 ps.nzcol[j] -= 1 end From 021f5014547bffab5e0010c87d69eac4520c1703 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Sun, 31 Jan 2021 09:22:47 -0600 Subject: [PATCH 25/27] Update test/mip/coefficient_strengthening.jl Co-authored-by: mtanneau <9593025+mtanneau@users.noreply.github.com> --- test/mip/coefficient_strengthening.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index 150b54f..1604866 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -231,9 +231,11 @@ function coef_strengthen_test4(T::Type) end @testset "Coefficient Strengthening" begin for T in COEFF_TYPES - @testset "$T" begin coef_strengthen_test1(T) end - @testset "$T" begin coef_strengthen_test2(T) end - @testset "$T" begin coef_strengthen_test3(T) end - @testset "$T" begin coef_strengthen_test4(T) end + @testset "$T" begin + coef_strengthen_test1(T) + coef_strengthen_test2(T) + coef_strengthen_test3(T) + coef_strengthen_test4(T) + end end end From 8ae6572ace66ec95076be204b7012b0aabae0a67 Mon Sep 17 00:00:00 2001 From: Anhtu07 Date: Sun, 31 Jan 2021 09:29:22 -0600 Subject: [PATCH 26/27] Update src/mip/coefficient_strengthening.jl Co-authored-by: Joey Huchette --- src/mip/coefficient_strengthening.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 0c69c23..77f373e 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -96,7 +96,7 @@ function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} # 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 + # keep track of index for each var to update ps.acols # use this to find which index of ps.pb0.acols[i].nzval to update i_index = zeros(Int, ps.pb0.nvar) From 92d07a600cfd81f821f5ccd6052fce302e5f769f Mon Sep 17 00:00:00 2001 From: tuna Date: Sun, 31 Jan 2021 15:06:00 -0600 Subject: [PATCH 27/27] Update - move maximal_activity/ minimal_activity to util - remove coefficient_strengthening! from presolve.jl - deleting spaces --- src/MathOptPresolve.jl | 2 +- src/mip/coefficient_strengthening.jl | 45 +++++++-------------------- src/presolve.jl | 30 ------------------ src/util.jl | 32 +++++++++++++++++++ test/mip/coefficient_strengthening.jl | 10 ------ 5 files changed, 45 insertions(+), 74 deletions(-) diff --git a/src/MathOptPresolve.jl b/src/MathOptPresolve.jl index b38b555..9aeaa9f 100755 --- a/src/MathOptPresolve.jl +++ b/src/MathOptPresolve.jl @@ -2,11 +2,11 @@ module MathOptPresolve using SparseArrays -include("util.jl") include("status.jl") include("options.jl") include("problem_data.jl") include("solution.jl") include("presolve.jl") +include("util.jl") end diff --git a/src/mip/coefficient_strengthening.jl b/src/mip/coefficient_strengthening.jl index 77f373e..ccd76d7 100644 --- a/src/mip/coefficient_strengthening.jl +++ b/src/mip/coefficient_strengthening.jl @@ -20,38 +20,6 @@ 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} - 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) - 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] @@ -92,10 +60,21 @@ function lowerbound_strengthening(ps::PresolveData{T}, i::Int, j::Int, coef, min return new_coef, new_bound end -function zero_coefficient_strengthening!(ps::PresolveData{T}) where {T} +""" + coefficient_strengthening!(ps::PresolveData) + +Perform coefficient strengthening for integer/binary variables +in every constraint. + +Called once at the beginning of the presolve procedure. +""" + +function coefficient_strengthening!(ps::PresolveData{T}) where {T} # 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 + ps.pb0.is_continuous && return nothing + # keep track of index for each var to update ps.acols # use this to find which index of ps.pb0.acols[i].nzval to update i_index = zeros(Int, ps.pb0.nvar) diff --git a/src/presolve.jl b/src/presolve.jl index efcecca..f06a3b4 100644 --- a/src/presolve.jl +++ b/src/presolve.jl @@ -728,33 +728,3 @@ 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. - -Called once at the beginning of the presolve procedure. -""" - -function coefficient_strengthening!(ps::PresolveData{T}) where {T} - 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 - - return nothing -end diff --git a/src/util.jl b/src/util.jl index cebe628..fb10fab 100644 --- a/src/util.jl +++ b/src/util.jl @@ -1,3 +1,35 @@ # Positive and negative part of a number pos_part(x::T) where {T} = x >= zero(T) ? x : zero(T) neg_part(x::T) where {T} = x >= zero(T) ? zero(T) : -x + +function maximal_activity(ps::PresolveData{T}, i::Int)::T where {T} + 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) + 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 diff --git a/test/mip/coefficient_strengthening.jl b/test/mip/coefficient_strengthening.jl index 1604866..e4e2e4e 100644 --- a/test/mip/coefficient_strengthening.jl +++ b/test/mip/coefficient_strengthening.jl @@ -31,7 +31,6 @@ function coef_strengthen_test1(T::Type) MOP.coefficient_strengthening!(ps) - @test ps.urow == T[5, 9//2] @test ps.lrow == T[-Inf, -Inf] @@ -104,7 +103,6 @@ function coef_strengthen_test2(T::Type) return nothing end - function coef_strengthen_test3(T::Type) #= min x₁ + x₂ + x₃ + x₄ + x₅ @@ -119,13 +117,10 @@ function coef_strengthen_test3(T::Type) -1 ⩽ x₅ ⩽ 1 x₃ is integer, x₄ is binary =# C = T[1, 1, 1, 1, 1] - lc = T[-4, -3//2, 9, 0, -1] uc = T[2, 1, 15, 1, 1] - lr = T[2, -Inf, -Inf, -Inf] ur = T[Inf, 13/3, 30, 5//2] - A = T[1 -2 1 1 -1 1 1 0 1 1 0 0 2 0 0 @@ -145,7 +140,6 @@ function coef_strengthen_test3(T::Type) MOP.coefficient_strengthening!(ps) - @test ps.urow == T[Inf, 4, 0, 5//2] @test ps.lrow == T[-7, -Inf, -Inf, -Inf] @@ -161,9 +155,6 @@ function coef_strengthen_test3(T::Type) @test isapprox(ps.pb0.acols[4].nzval, T[0, 2//3], atol = 1e-12) @test ps.pb0.acols[5].nzval == T[-1, 1, -1] - @test ps.colflag[3] == false - @test ps.rowflag[3] == false - @test ps.nzrow == [3, 4, 0, 3] @test ps.nzcol == [3, 3, 0, 1, 3] @@ -212,7 +203,6 @@ function coef_strengthen_test4(T::Type) @test ps.pb0.arows[2].nzind == [1, 2, 3] @test ps.pb0.arows[2].nzval == T[1, 2, 3] - @test ps.pb0.acols[1].nzind == [1, 2] @test ps.pb0.acols[1].nzval == T[1, 1] @test ps.pb0.acols[2].nzind == [1, 2]