From 55b0a2bbcad4805a0cfbb2ed0f6393e5fa3274fc Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 7 Aug 2025 21:42:24 -0500 Subject: [PATCH] AddSlackVariables: Improve performance --- src/Cuts/tableau/transform.jl | 112 +++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 49 deletions(-) diff --git a/src/Cuts/tableau/transform.jl b/src/Cuts/tableau/transform.jl index 020687e..9453a9e 100644 --- a/src/Cuts/tableau/transform.jl +++ b/src/Cuts/tableau/transform.jl @@ -96,56 +96,70 @@ Base.@kwdef mutable struct AddSlackVariables <: Transform end function forward!(t::AddSlackVariables, data::ProblemData) - nrows, ncols = size(data.constr_lhs) - isequality = abs.(data.constr_ub .- data.constr_lb) .< 1e-6 - eq = [i for i = 1:nrows if isequality[i]] - ge = [i for i = 1:nrows if isfinite(data.constr_lb[i]) && !isequality[i]] - le = [i for i = 1:nrows if isfinite(data.constr_ub[i]) && !isequality[i]] - EQ, GE, LE = length(eq), length(ge), length(le) - function is_integral(row_idx, rhs) - rhs_is_integer = abs(rhs - round(rhs)) <= 1e-6 - cols, coeffs = findnz(data.constr_lhs[row_idx, :])[1:2] - vars_are_integer = all(j -> data.var_types[j] ∈ ['I', 'B'], cols) - coeffs_are_integer = all(v -> abs(v - round(v)) <= 1e-6, coeffs) - return rhs_is_integer && vars_are_integer && coeffs_are_integer + @timeit "Identify constraint type" begin + nrows, ncols = size(data.constr_lhs) + isequality = abs.(data.constr_ub .- data.constr_lb) .< 1e-6 + eq = [i for i = 1:nrows if isequality[i]] + ge = [i for i = 1:nrows if isfinite(data.constr_lb[i]) && !isequality[i]] + le = [i for i = 1:nrows if isfinite(data.constr_ub[i]) && !isequality[i]] + EQ, GE, LE = length(eq), length(ge), length(le) + end + @timeit "Identify slack type" begin + constr_lhs_t = sparse(data.constr_lhs') + function is_integral(row_idx, rhs) + rhs_is_integer = abs(rhs - round(rhs)) <= 1e-6 + cols, coeffs = findnz(constr_lhs_t[:, row_idx])[1:2] + vars_are_integer = all(j -> data.var_types[j] ∈ ['I', 'B'], cols) + coeffs_are_integer = all(v -> abs(v - round(v)) <= 1e-6, coeffs) + return rhs_is_integer && vars_are_integer && coeffs_are_integer + end + slack_types = [ + [is_integral(ge[i], data.constr_lb[ge[i]]) ? 'I' : 'C' for i = 1:GE]; + [is_integral(le[i], data.constr_ub[le[i]]) ? 'I' : 'C' for i = 1:LE] + ] + end + @timeit "Build M1" begin + t.M1 = [ + I spzeros(ncols, GE + LE) + data.constr_lhs[ge, :] spzeros(GE, GE + LE) + -data.constr_lhs[le, :] spzeros(LE, GE + LE) + ] + end + @timeit "Build M2" begin + t.M2 = [ + zeros(ncols) + data.constr_lb[ge] + -data.constr_ub[le] + ] + end + @timeit "Build t.lhs, t.rhs" begin + t.ncols_orig = ncols + t.GE, t.LE = GE, LE + t.lhs_ge = data.constr_lhs[ge, :] + t.lhs_le = data.constr_lhs[le, :] + t.rhs_ge = data.constr_lb[ge] + t.rhs_le = data.constr_ub[le] + end + @timeit "Build data.constr_lhs" begin + data.constr_lhs = [ + data.constr_lhs[eq, :] spzeros(EQ, GE) spzeros(EQ, LE) + data.constr_lhs[ge, :] -I spzeros(GE, LE) + data.constr_lhs[le, :] spzeros(LE, GE) I + ] + end + @timeit "Build other data fields" begin + data.obj = [data.obj; zeros(GE + LE)] + data.var_lb = [data.var_lb; zeros(GE + LE)] + data.var_ub = [data.var_ub; [Inf for _ = 1:(GE+LE)]] + data.var_names = [data.var_names; ["__s$i" for i = 1:(GE+LE)]] + data.var_types = [data.var_types; slack_types] + data.constr_lb = [ + data.constr_lb[eq] + data.constr_lb[ge] + data.constr_ub[le] + ] + data.constr_ub = copy(data.constr_lb) end - slack_types = [ - [is_integral(ge[i], data.constr_lb[ge[i]]) ? 'I' : 'C' for i = 1:GE]; - [is_integral(le[i], data.constr_ub[le[i]]) ? 'I' : 'C' for i = 1:LE] - ] - t.M1 = [ - I spzeros(ncols, GE + LE) - data.constr_lhs[ge, :] spzeros(GE, GE + LE) - -data.constr_lhs[le, :] spzeros(LE, GE + LE) - ] - t.M2 = [ - zeros(ncols) - data.constr_lb[ge] - -data.constr_ub[le] - ] - t.ncols_orig = ncols - t.GE, t.LE = GE, LE - t.lhs_ge = data.constr_lhs[ge, :] - t.lhs_le = data.constr_lhs[le, :] - t.rhs_ge = data.constr_lb[ge] - t.rhs_le = data.constr_ub[le] - - data.constr_lhs = [ - data.constr_lhs[eq, :] spzeros(EQ, GE) spzeros(EQ, LE) - data.constr_lhs[ge, :] -I spzeros(GE, LE) - data.constr_lhs[le, :] spzeros(LE, GE) I - ] - data.obj = [data.obj; zeros(GE + LE)] - data.var_lb = [data.var_lb; zeros(GE + LE)] - data.var_ub = [data.var_ub; [Inf for _ = 1:(GE+LE)]] - data.var_names = [data.var_names; ["__s$i" for i = 1:(GE+LE)]] - data.var_types = [data.var_types; slack_types] - data.constr_lb = [ - data.constr_lb[eq] - data.constr_lb[ge] - data.constr_ub[le] - ] - data.constr_ub = copy(data.constr_lb) end function backwards!(t::AddSlackVariables, c::ConstraintSet)