From 67e706d727d009f1ee59355ec456f27c9f1fc6b8 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Wed, 13 Aug 2025 15:33:48 -0500 Subject: [PATCH] FisSal2011: Write H5 --- src/Cuts/tableau/gmi_dual.jl | 110 ++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 7 deletions(-) diff --git a/src/Cuts/tableau/gmi_dual.jl b/src/Cuts/tableau/gmi_dual.jl index 1596c07..40f9c6e 100644 --- a/src/Cuts/tableau/gmi_dual.jl +++ b/src/Cuts/tableau/gmi_dual.jl @@ -335,6 +335,13 @@ function collect_gmi_FisSal2011( basis_cache = nothing λ, Δ = 0, 0 μ = 10 + + basis_vars_to_id = Dict() + basis_id_to_vars = Dict{Int, Vector{Int}}() + basis_id_to_sizes = Dict{Int, Vector{Int}}() + next_basis_id = 1 + cut_basis_id = Int[] + cut_row = Int[] end gapcl(v) = 100 * (v - obj_initial) / (obj_mip - obj_initial) @@ -513,6 +520,25 @@ function collect_gmi_FisSal2011( end end @timeit "Append unique cuts" begin + @timeit "Track basis" begin + vb = basis.var_basic + vn = basis.var_nonbasic + cb = basis.constr_basic + cn = basis.constr_nonbasic + basis_vars = [vb; vn; cb; cn] + basis_sizes = [length(vb), length(vn), length(cb), length(cn)] + + if basis_vars ∉ keys(basis_vars_to_id) + basis_id = next_basis_id + basis_vars_to_id[basis_vars] = basis_id + basis_id_to_vars[basis_id] = basis_vars + basis_id_to_sizes[basis_id] = basis_sizes + next_basis_id += 1 + else + basis_id = basis_vars_to_id[basis_vars] + end + end + if round == 1 pool = ConstraintSet( lhs = sparse(cuts_s.lhs[unique_indices, :]'), @@ -524,6 +550,10 @@ function collect_gmi_FisSal2011( multipliers_curr = zeros(ncuts_unique) multipliers_best = zeros(ncuts_unique) pool_cut_age = zeros(ncuts_unique) + for i in unique_indices + push!(cut_basis_id, basis_id) + push!(cut_row, selected_rows[i]) + end else if !isempty(unique_indices) @timeit "Append LHS" begin @@ -557,6 +587,10 @@ function collect_gmi_FisSal2011( append!(multipliers_curr, zeros(ncuts_unique)) append!(multipliers_best, zeros(ncuts_unique)) append!(pool_cut_age, zeros(ncuts_unique)) + for i in unique_indices + push!(cut_basis_id, basis_id) + push!(cut_row, selected_rows[i]) + end end end end @@ -588,6 +622,19 @@ function collect_gmi_FisSal2011( multipliers_curr = multipliers_curr[idx_keep] multipliers_best = multipliers_best[idx_keep] pool_cut_age = pool_cut_age[idx_keep] + cut_basis_id = cut_basis_id[idx_keep] + cut_row = cut_row[idx_keep] + end + @timeit "Update known bases" begin + used_basis_ids = Set(cut_basis_id) + for basis_id in collect(keys(basis_id_to_vars)) + if basis_id ∉ used_basis_ids + basis_vars = basis_id_to_vars[basis_id] + delete!(basis_vars_to_id, basis_vars) + delete!(basis_id_to_vars, basis_id) + delete!(basis_id_to_sizes, basis_id) + end + end end pool_size_mb = Base.summarysize(pool) / 1024^2 end @@ -747,13 +794,62 @@ function collect_gmi_FisSal2011( @timeit "Keep only active cuts" begin positive_idx = findall(multipliers_best .> 1e-6) - @info "Keeping $(length(positive_idx)) active cuts" - pool.lhs = pool.lhs[:, positive_idx] - pool.lb = pool.lb[positive_idx] - pool.ub = pool.ub[positive_idx] - pool.hash = pool.hash[positive_idx] - multipliers_best = multipliers_best[positive_idx] - multipliers_curr = multipliers_curr[positive_idx] + + @timeit "Clean up cut pool" begin + pool.lhs = pool.lhs[:, positive_idx] + pool.lb = pool.lb[positive_idx] + pool.ub = pool.ub[positive_idx] + pool.hash = pool.hash[positive_idx] + multipliers_best = multipliers_best[positive_idx] + multipliers_curr = multipliers_curr[positive_idx] + cut_basis_id = cut_basis_id[positive_idx] + cut_row = cut_row[positive_idx] + end + + @timeit "Clean up known bases" begin + used_basis_ids = Set(cut_basis_id) + for basis_id in collect(keys(basis_id_to_vars)) + if basis_id ∉ used_basis_ids + basis_vars = basis_id_to_vars[basis_id] + delete!(basis_vars_to_id, basis_vars) + delete!(basis_id_to_vars, basis_id) + delete!(basis_id_to_sizes, basis_id) + end + end + end + + @info "Keeping $(length(positive_idx)) cuts from $(length(used_basis_ids)) unique bases" + end + + @timeit "Write cuts to H5" begin + if !isempty(cut_basis_id) + @timeit "Convert IDs to offsets" begin + id_to_offset = Dict{Int, Int}() + gmi_basis_vars = [] + gmi_basis_sizes = [] + for (offset, basis_id) in enumerate(sort(collect(keys(basis_id_to_vars)))) + id_to_offset[basis_id] = offset + push!(gmi_basis_vars, basis_id_to_vars[basis_id]) + push!(gmi_basis_sizes, basis_id_to_sizes[basis_id]) + end + gmi_cut_basis = [id_to_offset[basis_id] for basis_id in cut_basis_id] + gmi_cut_row = cut_row + end + + @timeit "Convert to matrices" begin + gmi_basis_vars_matrix = hcat(gmi_basis_vars...)' + gmi_basis_sizes_matrix = hcat(gmi_basis_sizes...)' + end + + @timeit "Write H5" begin + h5 = H5File(h5_filename, "r+") + h5.put_array("gmi_basis_vars", gmi_basis_vars_matrix) + h5.put_array("gmi_basis_sizes", gmi_basis_sizes_matrix) + h5.put_array("gmi_cut_basis", gmi_cut_basis) + h5.put_array("gmi_cut_row", gmi_cut_row) + h5.file.close() + end + end end to = TimerOutputs.get_defaulttimer()