diff --git a/src/algorithms/TambyVanderpooten.jl b/src/algorithms/TambyVanderpooten.jl index 02f6def..b4b0a96 100644 --- a/src/algorithms/TambyVanderpooten.jl +++ b/src/algorithms/TambyVanderpooten.jl @@ -30,19 +30,20 @@ function _update_search_region( y::Vector{Float64}, yN::Vector{Float64}, ) - bounds_to_remove = Vector{Float64}[] p = length(y) + bounds_to_remove = Vector{Float64}[] + bounds_to_add = Dict{Vector{Float64},Vector{Vector{Vector{Float64}}}}() for u in keys(U_N) if all(y .< u) push!(bounds_to_remove, u) for l in 1:p u_l = _get_child(u, y, l) N = [ - k != l ? [yi for yi in U_N[u][k] if yi[l] < y[l]] : [y] + k == l ? [y] : [yi for yi in U_N[u][k] if yi[l] < y[l]] for k in 1:p ] - if all(!isempty(N[k]) for k in 1:p if u_l[k] ≠ yN[k]) - U_N[u_l] = N + if all(!isempty(N[k]) for k in 1:p if k != l && u_l[k] != yN[k]) + bounds_to_add[u_l] = N end end else @@ -53,27 +54,31 @@ function _update_search_region( end end end - for bound_to_remove in bounds_to_remove - delete!(U_N, bound_to_remove) + for u in bounds_to_remove + delete!(U_N, u) end + merge!(U_N, bounds_to_add) return end function _get_child(u::Vector{Float64}, y::Vector{Float64}, k::Int) @assert length(u) == length(y) - return vcat(u[1:k-1], y[k], u[k+1:length(y)]) + return vcat(u[1:(k-1)], y[k], u[(k+1):length(y)]) end function _select_search_zone( U_N::Dict{Vector{Float64},Vector{Vector{Vector{Float64}}}}, yI::Vector{Float64}, + yN::Vector{Float64}, ) - i, j = - argmax([ - prod(_project(u, k) - _project(yI, k)) for k in 1:length(yI), - u in keys(U_N) - ]).I - return i, collect(keys(U_N))[j] + upper_bounds = collect(keys(U_N)) + p = length(yI) + hvs = [ + u[k] == yN[k] ? 0.0 : prod(_project(u, k) .- _project(yI, k)) for + k in 1:p, u in upper_bounds + ] + k_star, j_star = argmax(hvs).I + return k_star, upper_bounds[j_star] end function optimize_multiobjective!( @@ -100,7 +105,6 @@ function optimize_multiobjective!( warm_start_supported = true end solutions = Dict{Vector{Float64},Dict{MOI.VariableIndex,Float64}}() - YN = Vector{Float64}[] variables = MOI.get(model.inner, MOI.ListOfVariableIndices()) n = MOI.output_dimension(model.f) yI, yN = zeros(n), zeros(n) @@ -114,7 +118,7 @@ function optimize_multiobjective!( return status, nothing end _, Y = _compute_point(model, variables, f_i) - yI[i] = Y + 1 + yI[i] = Y model.ideal_point[i] = Y MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MAX_SENSE) MOI.optimize!(model.inner) @@ -124,7 +128,7 @@ function optimize_multiobjective!( return status, nothing end _, Y = _compute_point(model, variables, f_i) - yN[i] = Y + yN[i] = Y + 1 end MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MIN_SENSE) U_N = Dict{Vector{Float64},Vector{Vector{Vector{Float64}}}}() @@ -136,7 +140,7 @@ function optimize_multiobjective!( status = MOI.TIME_LIMIT break end - k, u = _select_search_zone(U_N, yI) + k, u = _select_search_zone(U_N, yI, yN) MOI.set( model.inner, MOI.ObjectiveFunction{typeof(scalars[k])}(), diff --git a/test/algorithms/TambyVanderpooten.jl b/test/algorithms/TambyVanderpooten.jl index 97d8582..33356ac 100644 --- a/test/algorithms/TambyVanderpooten.jl +++ b/test/algorithms/TambyVanderpooten.jl @@ -621,7 +621,44 @@ function test_vector_of_variables_objective() MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) MOI.add_constraint(model, sum(1.0 * xi for xi in x), MOI.GreaterThan(1.0)) MOI.optimize!(model) - MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL + return +end + +function test_issue_105() + cost = [100.0, 120.0, 150.0, 110.0, 200.0, 170.0] + time = [8.0, 3.0, 4.0, 2.0, 5.0, 4.0] + capacity = [10.0, 8.0] + demand = [5.0, 8.0, 5.0] + m, n = 2, 3 + model = MOI.instantiate(; with_bridge_type = Float64) do + return MOA.Optimizer(HiGHS.Optimizer) + end + MOI.set(model, MOA.Algorithm(), MOA.TambyVanderpooten()) + MOI.set(model, MOI.Silent(), true) + x = MOI.add_variables(model, m * n) + MOI.add_constraint.(model, x, MOI.GreaterThan(0.0)) + MOI.add_constraint.(model, x, MOI.Integer()) + X = reshape(x, m, n) + for i in 1:m + f_i = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, X[i, :]), 0.0) + MOI.add_constraint(model, f_i, MOI.LessThan(capacity[i])) + end + for j in 1:n + f_j = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, X[:, j]), 0.0) + MOI.add_constraint(model, f_j, MOI.EqualTo(demand[j])) + end + f = MOI.Utilities.operate( + vcat, + Float64, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(cost, x), 0.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(time, x), 0.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(1.0, x), 0.0), + ) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) + MOI.optimize!(model) + @test MOI.get(model, MOI.ResultCount()) == 6 return end