From a76e6ee09016b41dbf2428f6718d6b865e0a7b42 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 5 Jun 2024 12:53:46 +0200 Subject: [PATCH 01/56] Pseudo-branching --- src/pseudo_branching.jl | 188 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/pseudo_branching.jl diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl new file mode 100644 index 000000000..2093da844 --- /dev/null +++ b/src/pseudo_branching.jl @@ -0,0 +1,188 @@ +struct PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBranchStrategy + iterations_until_stable::Int + stable::Bool + bounded_lmo::BLMO +end + +""" Function that keeps track of which branching candidates are stable """ +function is_stable(idx::Int, branch_tracker::Dict{Int, Float64}) + if branch_tracker[idx] >= branching.iterations_until_stable + return true + else + return false + end +end + + +function pseudo_weight_update!( + tree::Bonobo.BnBTree, + node::Bonobo.AbstractNode, + idx::Int +) + @assert !isempty(node.active_set) + active_set = copy(node.active_set) + empty!(active_set) + + + current_dual_gap = node.dual_gap# if this is a fw_node this should be the fw_dual_gap + + fx = floor(values[idx]) + # create LMO + bounds_left = copy(node.local_bounds) + if haskey(boundsLeft.upper_bounds, idx) + delete!(boundsLeft.upper_bounds, idx) + end + push!(boundsLeft.upper_bounds, (idx => fx)) + build_LMO( + branching.bounded_lmo, + tree.root.problem.integer_variable_bounds, + boundsLeft, + Bonobo.get_branching_indices(tree.root), + ) + status = check_feasibility(branching.bounded_lmo) + if status == OPTIMAL + empty!(active_set) + for (λ, v) in node.active_set + if v[idx] <= values[idx] + push!(active_set, ((λ, v))) + end + end + @assert !isempty(active_set) + FrankWolfe.active_set_renormalize!(active_set) + x, primal, dual_gap, active_set + _, _, primal_relaxed, dual_gap_relaxed, _ = + FrankWolfe.blended_pairwise_conditional_gradient( + tree.root.problem.f, + tree.root.problem.g, + branching.bounded_lmo, + active_set, + verbose=false, + epsilon=branching.solving_epsilon, + max_iteration=5, + ) + left_update = current_dual_gap - dual_gap_relaxed + else + @debug "Left non-optimal status $(status)" + end + + #right node: x_i >= floor(̂x_i) + cx = ceil(values[idx]) + boundsRight = copy(node.local_bounds) + if haskey(boundsRight.lower_bounds, idx) + delete!(boundsRight.lower_bounds, idx) + end + push!(boundsRight.lower_bounds, (idx => cx)) + build_LMO( + branching.bounded_lmo, + tree.root.problem.integer_variable_bounds, + boundsRight, + Bonobo.get_branching_indices(tree.root), + ) + status = check_feasibility(branching.bounded_lmo) + if status == OPTIMAL + empty!(active_set) + for (λ, v) in node.active_set + if v[idx] >= values[idx] + push!(active_set, (λ, v)) + end + end + if isempty(active_set) + @show values[idx] + @show length(active_set) + @info [active_set.atoms[idx] for idx in eachindex(active_set)] + error("Empty active set, unreachable") + end + FrankWolfe.active_set_renormalize!(active_set) + _, _, primal_relaxed, dual_gap_relaxed, _ = + FrankWolfe.blended_pairwise_conditional_gradient( + tree.root.problem.f, + tree.root.problem.g, + branching.bounded_lmo, + active_set, + verbose=false, + epsilon=branching.solving_epsilon, + max_iteration=5, + ) + right_update = current_dual_gap - dual_gap_relaxed + else + @debug "Right non-optimal status $(status)" + end + # reset LMO + build_LMO( + branching.bounded_lmo, + tree.root.problem.integer_variable_bounds, + node.local_bounds, + Bonobo.get_branching_indices(tree.root), + ) + pseudos[idx][1] = update_avg(left_update, pseudos[idx][1], branch_tracker[idx]) + pseudos[idx][2] = update_avg(right_update, pseudos[idx][2], branch_tracker[idx]) + branch_tracker[idx] += 1 + + +end + +function best_pseudo_choice( + tree::Bonobo.BnBTree, +) + branching_candidates = Bonobo.get_branching_indices(tree.root) + return argmax(map(idx-> maximum(pseudos[idx]), branching_candidates)) +end + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + branching::PSEUDO_COST, + node::Bonobo.AbstractNode +) + +Get branching variable using Pseudocost branching after costs have stabilized. +Prior to stabilization an adaptation of the Bonobo MOST_INFEASIBLE is used. + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::PSEUDO_COST{BLMO}, + node::Bonobo.AbstractNode, +) where BLMO <: BoundedLinearMinimizationOracle + best_idx = -1 + all_stable = true + for idx in Bonobo.get_branching_indices(tree.root) + if !is_stable(idx) + all_stable = false + end + end + if !all_stable# THEN Use Most Infeasible + values = Bonobo.get_relaxed_values(tree, node) + max_distance_to_feasible = 0.0 + for i in Bonobo.get_branching_indices(tree.root) + value = values[i] + if !is_approx_feasible(tree, value) + distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) + if distance_to_feasible > max_distance_to_feasible + best_idx = i + max_distance_to_feasible = distance_to_feasible + end + end + end + pseudo_weight_update!(tree, node, best_idx) + return best_idx + else + best_idx = best_pseudo_choice(tree, node) + return best_idx + end +end + +function update_avg(new_val::Float64, avg::Float64, N::Int64) + # N is the number of values used to compute the current avg + # avg is the current average + # new_val is the value that the current average has to be updated with + if N > 1 + return 1/(N+1) * (N * avg + new_val) + else + return new_val + end +end +#pseudos = Dict{Int,Array{Float64}}(i=>zeros(2) for idx in get_integer_variables(blmo)) + +#branch_tracker = Dict{Int, Int}(idx-> 0 for idx in get_integer_variables(blmo)) \ No newline at end of file From 17ad8fe6f5d8d84d0d83b5034f028568f0ab7ed5 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 5 Jun 2024 17:33:37 +0200 Subject: [PATCH 02/56] Added utility function to print the values of the parameters for Pseudocost --- src/utilities.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utilities.jl b/src/utilities.jl index 814b6430a..2bdbc42ec 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -235,3 +235,4 @@ _value_to_print(::Bonobo.BestFirstSearch) = "Move best bound" _value_to_print(::PartialStrongBranching) = "Partial strong branching" _value_to_print(::HybridStrongBranching) = "Hybrid strong branching" _value_to_print(::Bonobo.MOST_INFEASIBLE) = "Most infeasible" +_value_to_print(::PSEUDO_COST) = "Pseudo Cost" \ No newline at end of file From f70429c506d722d1afa37e2c1337fb0c8244219b Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 5 Jun 2024 17:34:57 +0200 Subject: [PATCH 03/56] Created some examples where I can test Pseudocost branching based on the similarl named examples already existing --- examples/HiGHS_example_PSEUDO_COST.jl | 36 +++++++++++++++ examples/portfolio_pseudocost.jl | 66 +++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 examples/HiGHS_example_PSEUDO_COST.jl create mode 100644 examples/portfolio_pseudocost.jl diff --git a/examples/HiGHS_example_PSEUDO_COST.jl b/examples/HiGHS_example_PSEUDO_COST.jl new file mode 100644 index 000000000..5385f4ccd --- /dev/null +++ b/examples/HiGHS_example_PSEUDO_COST.jl @@ -0,0 +1,36 @@ +using Boscia +using FrankWolfe +using Random +using HiGHS +using LinearAlgebra +import MathOptInterface + +const MOI = MathOptInterface + +n = 6 + +const diffw = 0.5 * ones(n) +o = HiGHS.Optimizer() + +MOI.set(o, MOI.Silent(), true) + +x = MOI.add_variables(o, n) + +for xi in x + MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) + MOI.add_constraint(o, xi, MOI.LessThan(1.0)) + MOI.add_constraint(o, xi, MOI.ZeroOne()) +end +lmo = Boscia.MathOptBLMO(o) + +function f(x) + return 0.5 * sum((x .- diffw) .^ 2) +end + +function grad!(storage, x) + @. storage = x - diffw +end +#pseudos = Dict{Int,Array{Float64}}(idx=>zeros(2) for idx in Boscia.get_integer_variables(lmo)) +#branch_tracker = Dict{Int, Float64}(idx=> 0 for idx in Boscia.get_integer_variables(lmo)) +iterations_stable = 1::Int +x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo), verbose=true) \ No newline at end of file diff --git a/examples/portfolio_pseudocost.jl b/examples/portfolio_pseudocost.jl new file mode 100644 index 000000000..2aa68759f --- /dev/null +++ b/examples/portfolio_pseudocost.jl @@ -0,0 +1,66 @@ +using Boscia +using FrankWolfe +using Test +using Random +using SCIP +using LinearAlgebra +import MathOptInterface +const MOI = MathOptInterface + +# seed = 0x946d4b7835e92ffa takes 90 minutes to solve! -> not anymore +seed = 0x946d4b7835e92ffa +Random.seed!(seed) + +n = 30 +const ri = rand(n) +const ai = rand(n) +const Ωi = rand(Float64) +const bi = sum(ai) +Ai = randn(n, n) +Ai = Ai' * Ai +const Mi = (Ai + Ai') / 2 +@assert isposdef(Mi) + + +@testset "Buchheim et. al. example" begin + o = SCIP.Optimizer() + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, n) + I = collect(1:n) #rand(1:n0, Int64(floor(n0/2))) + for i in 1:n + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + if i in I + MOI.add_constraint(o, x[i], MOI.Integer()) + end + end + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ai, x), 0.0), + MOI.LessThan(bi), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(n), x), 0.0), + MOI.GreaterThan(1.0), + ) + lmo = Boscia.MathOptBLMO(o) + + function f(x) + return 1 / 2 * Ωi * dot(x, Mi, x) - dot(ri, x) + end + function grad!(storage, x) + mul!(storage, Mi, x, Ωi, 0) + storage .-= ri + return storage + end + + depth = 5 + heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.2, :follow_gradient) + heuristics = [heu] + # heuristics = [] + iterations_stable = 3::Int# how many times until we consider a pseudocost as stable + x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo), verbose=true, time_limit=600, custom_heuristics=heuristics) + @test dot(ai, x) <= bi + 1e-2 + @test f(x) <= f(result[:raw_solution]) + 1e-6 +end From 45e9d34042cc55bfed9fca6cf65f61f31b0f9b0b Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 5 Jun 2024 17:37:58 +0200 Subject: [PATCH 04/56] included the file for pseudo branching --- src/Boscia.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Boscia.jl b/src/Boscia.jl index 5e92fc6ca..d4361ad91 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -23,6 +23,7 @@ include("callbacks.jl") include("problem.jl") include("heuristics.jl") include("strong_branching.jl") +include("pseudo_branching.jl") include("utilities.jl") include("interface.jl") include("managed_blmo.jl") From 5aaed15efa1b51a4d1a0f5326352ee9d6fde4bb6 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 5 Jun 2024 17:40:11 +0200 Subject: [PATCH 05/56] Made changes in order for PSEUDO_COST branching to run without failing. Current version runs on the two examples however it only uses MOST_INFEASIBLE, i.e. costs have not stabilized. --- src/pseudo_branching.jl | 61 +++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 2093da844..965faf09a 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -4,31 +4,34 @@ struct PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBran bounded_lmo::BLMO end -""" Function that keeps track of which branching candidates are stable """ -function is_stable(idx::Int, branch_tracker::Dict{Int, Float64}) - if branch_tracker[idx] >= branching.iterations_until_stable - return true - else - return false - end -end +# """ Function that keeps track of which branching candidates are stable """ +# function is_stable(idx::Int, branching::PSEUDO_COST{BLMO}) +# local branch_tracker = Dict{Int, Float64}(idx=> 0 for idx in Boscia.get_integer_variables(branching.bounded_lmo)) +# if branch_tracker[idx] >= branching.iterations_until_stable +# return true +# else +# return false +# end +# end function pseudo_weight_update!( tree::Bonobo.BnBTree, node::Bonobo.AbstractNode, - idx::Int -) + idx::Int, + values, + pseudos::Dict{Int,Array{Float64}}, + branch_tracker::Dict{Int, Int}, + branching::PSEUDO_COST{BLMO} +) where BLMO <: BoundedLinearMinimizationOracle @assert !isempty(node.active_set) active_set = copy(node.active_set) empty!(active_set) - - current_dual_gap = node.dual_gap# if this is a fw_node this should be the fw_dual_gap fx = floor(values[idx]) # create LMO - bounds_left = copy(node.local_bounds) + boundsLeft = copy(node.local_bounds) if haskey(boundsLeft.upper_bounds, idx) delete!(boundsLeft.upper_bounds, idx) end @@ -63,6 +66,7 @@ function pseudo_weight_update!( left_update = current_dual_gap - dual_gap_relaxed else @debug "Left non-optimal status $(status)" + left_update = Inf end #right node: x_i >= floor(̂x_i) @@ -106,6 +110,7 @@ function pseudo_weight_update!( right_update = current_dual_gap - dual_gap_relaxed else @debug "Right non-optimal status $(status)" + right_update = Inf end # reset LMO build_LMO( @@ -117,11 +122,9 @@ function pseudo_weight_update!( pseudos[idx][1] = update_avg(left_update, pseudos[idx][1], branch_tracker[idx]) pseudos[idx][2] = update_avg(right_update, pseudos[idx][2], branch_tracker[idx]) branch_tracker[idx] += 1 - - end -function best_pseudo_choice( +function best_pseudo_choice(# currently not in use. To be implemented later in order to improve readability tree::Bonobo.BnBTree, ) branching_candidates = Bonobo.get_branching_indices(tree.root) @@ -145,11 +148,19 @@ function Bonobo.get_branching_variable( branching::PSEUDO_COST{BLMO}, node::Bonobo.AbstractNode, ) where BLMO <: BoundedLinearMinimizationOracle + #the following should create the dictionaries only on first function call and then use existing ones + local pseudos = Dict{Int,Array{Float64}}(idx=>zeros(2) for idx in Boscia.get_integer_variables(branching.bounded_lmo)) + local branch_tracker = Dict{Int, Int}(idx=> 0 for idx in Boscia.get_integer_variables(branching.bounded_lmo)) + local call_tracker = 0 + best_idx = -1 all_stable = true for idx in Bonobo.get_branching_indices(tree.root) - if !is_stable(idx) + if branch_tracker[idx] >= branching.iterations_until_stable + all_stable = true + else all_stable = false + break end end if !all_stable# THEN Use Most Infeasible @@ -157,7 +168,7 @@ function Bonobo.get_branching_variable( max_distance_to_feasible = 0.0 for i in Bonobo.get_branching_indices(tree.root) value = values[i] - if !is_approx_feasible(tree, value) + if !Bonobo.is_approx_feasible(tree, value) distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) if distance_to_feasible > max_distance_to_feasible best_idx = i @@ -165,15 +176,23 @@ function Bonobo.get_branching_variable( end end end - pseudo_weight_update!(tree, node, best_idx) + if best_idx != -1 + pseudo_weight_update!(tree, node, best_idx, values, pseudos, branch_tracker, branching) + end return best_idx else - best_idx = best_pseudo_choice(tree, node) + println("Pseudos are stable") + # Pseudocosts have stabilized + call_tracker +=1 + println("pseudocosts have stabilized ", call_tracker) + + branching_candidates = Bonobo.get_branching_indices(tree.root) + best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later return best_idx end end -function update_avg(new_val::Float64, avg::Float64, N::Int64) +function update_avg(new_val::Float64, avg::Float64, N::Int) # N is the number of values used to compute the current avg # avg is the current average # new_val is the value that the current average has to be updated with From 38e9ed95e55d53a3602af5b4a4195757328c0912 Mon Sep 17 00:00:00 2001 From: Leon Date: Sun, 9 Jun 2024 22:16:30 +0200 Subject: [PATCH 06/56] What I have written down so far. Structure of Master Thesis not set yet. I.e. this is more like a non sorted collections of potential sections --- ...rk_master_thesis_branching_Leon_Stanzel.pdf | Bin 0 -> 187321 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 in_work_master_thesis_branching_Leon_Stanzel.pdf diff --git a/in_work_master_thesis_branching_Leon_Stanzel.pdf b/in_work_master_thesis_branching_Leon_Stanzel.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e7f590760cd5f4e5d041c2ec6eff47507b5f5990 GIT binary patch literal 187321 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

w~)B`u_W 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

Z!`}$dMW(12! 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%0DEv4{E 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 Js;>TSTmY!ntug=r literal 0 HcmV?d00001 From 1efdf5bbf4fa22d070c7a08a3f2cbd5ab014dbec Mon Sep 17 00:00:00 2001 From: Leon Date: Sun, 16 Jun 2024 15:32:05 +0200 Subject: [PATCH 07/56] version_16.06 --- ...k_master_thesis_branching_Leon_Stanzel.pdf | Bin 187321 -> 200223 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/in_work_master_thesis_branching_Leon_Stanzel.pdf b/in_work_master_thesis_branching_Leon_Stanzel.pdf index e7f590760cd5f4e5d041c2ec6eff47507b5f5990..1c34bb340886bd14a41309978c4eeaff49084e3a 100644 GIT binary patch delta 124610 zcmZ6Sb8siYyY6E<+1S|Fwr$(S#@07>vaxO3wr$(Card0xxmD-h{$qN2dghs`&+~S5 zcU8Y_EwDM6aL8l|B4V_RbgVFBJums+Fiebb$T%!a3=B+6%!Kq3gxZ8m%*;%LOq}e5 zx`g!dgiNf2^rD1}tV|5d?1c1kg#Ruogp8b=987Tr9>7c~yz3zNpp49H35@F)DbDL4 zoB&B%6I1v9(qa53#qnP%lD1}c|Gpt)AXFlxSF*En{@3xJhO(un>Azoa64EO;n!5f+ zmy_`SEA)~ggxWkTtZW>NhRlWxEDVOGY-UXCEDXkMtc)zih78P%3~cOtJSJw$#>R#K zc2+|Z21YhEPE$ie7EV(pP9|0sRzp@(c1Av3LOwniCuc`f!#^sLQF_FgJ@I;Dlfa4}B1WBba!dUh}|ZlNNZgg#GD-CU&{; zlL)RdKy?==oI;4jrdO_ojxvY`4qpUk$nZcHWD1-zHxrEQ4`E1Q_})+fapeR(px~5> zmuI5GbZ3u>7fvzJk zM~LG;yyWdoZ3T^;E$wXov10t6XD-e*mbU-iVr1b+XoDmHWn^Jb*oGuX*o7tnC=)U= z|8wx4k4#L2^fIQl=FS%XoMHHXK^PePqp+K3Xkcn!kZ6Ep36r6-;evk`i|MuCepU1NY(J@wn+?hlk@Dt$ym!Te@6z)g?B_t$p#q zxX!7m0RU*=OrqUtt^WOVT=eIoP;cZRxmuVV-U5^#bb;2FkQRRM-hf>PB7*U>jH7%= zHq1=J%lMiHSl^$Q9hGN?viRakW^J@^1ZAjB^fcf*z&*4Hk}Mrg^_fBjNz23D5O#n? zya=LH91bfL&dHC3d3F&9sL)W1560BiCCL|7g%FnL63II2!+# zISfoGd`=)Z@k|sAkT9%p39np~4OC3iPzjBBv94rj~*8wI%#(yK~ zpQ08p8i0|Bjg#~L@guqgTp@D}omM8+z+Zr{l?4n6CD*~t&FxRF|1kF1?lt!27EwS4 zHyFHJ>@Ha7?lcLrllk%XPmO0yd-;d<#`OA0rO&yw6^tpX7&3Dyv<8Y5q_K%1$UVp) z8k&iQ9}r<|G&GcnXhE@BXs->R_ouEv(K-Mxi%@}k8z36S86a3op1}e2j8+QN1UlN? z0$f`Qtij=-+3M~u07Q*6`j8_~N^pNfNk(qS-{i-mkP=f8KiCil5zn@EkS*k9%*U1 zIy$KW&2lmd;;@44Za^4NlPI|`t{~i8fm1*|+7J{0HhqAm;UF=1g_a*Ks$Da^~{8X856bq~lIE@GVQxFd< z7EKY@FPrPLf}dPjJdAfTd<@#?p+o$5$27ZHvwvC!&dM6LIgm5&>zEwD0W5>>ssrai zKh*jUq)XkyDd(r=10te zh6ac^j1tZOq}gvZ?@Re>436ywl|QS8Wbjumq<1_4EYR!6!%IS6LjPp0E1T_4(2v95 zq?VEvmtzDRpb7BVqO5{;4s&Z@Vhqku?+64;Bj9Qaw6YMm0$5Rm5d7Z1tI@&YcB0sI ztK0F;VLRu~%=$qAzS2h(f_%L(ikKxo3jl8Xq0l851!nPiH+lmse-Kdq0GNJskABJ@ ze@sc=wug@q`LA+-e+c+T(TxtC)dv%tcLuVD1%TgK-~g^aIOX8qPOiUt&0=4ge=d^z z{j-M!2dDQX=c8yYWdxr2uaL+k!>Ctfut1obK9$)3>#V+rnec-Mm2fTrpWQ~;^?toS zcf7J`WlsyN`;UcF{JMlCC2@gY4zWFqua>3X8KFU0l#7=yk9CgrAObNlgzSwa0{|gh zAjISnMgS{l$9JAB5OV?^+H)d^`}rEI0fLLjhtI6eC6L+LPBA|+xu52@-5@*|1NBd! z2GAtc4SUjNq8W3*=%)vf{{NC(vL^zW7%kkLbQp-jL=sEyhHICbEwYk2Fr_$lOR zGWd`mM@JamK9w4@~SgNKt zw@-R9eqJ;#Nbeku{tAfGaoh;lBsDv}+h0@Z93g`~nw)@W)u|#?WZE_w(c>_khpI$S zA!3fyV?9sFwyS7A+1ItOmnLm93DiOZY;aLYF&*AXxU;;hs2E2720hQfH3ze6Sg|Pp zT_$-Ni2t=farC-TJ-4qjUZ?gB35j0kCBaSdX_EED{jBh_tf zXxhuNhDWB*KImoAlb?2hOjngMTf;W<5=&wBx3j$_HhHRe{bh%Kg3$*3enc?`;P}uk zID^(CIF@Ab1$J1U%hI((sIbG=Ta%jd7LS)qT82kJ2!nLz-V)q)|+vBR6WNFfJ}>)-OHH^ z(NK)f@9Vo11LgYo8k&wODEn8vq$=CuIDEI>f@mVd8q0%Uh|g9?hhN93Lj57}x6;z| zVwvFUh?w84RG`4z4s&s|#MI`|Ysk(CNrTFe^jcD2p9-n&QUJ5dtU663)GRY7gZPUk ztT_I39-(MGg2;Fabef$YA`@R^~m>A#BTOvYX=D2&<&R#cjm&J!RsQVcmQ4XKT+W~07f9@s6KV!tw8 zXIg=YXnEVk#Qrx|PxOxTBg)#!BE4i zP(IXY*<^~ejA2Dinsh><+m^El4gXo)hheU7W9qgJ!~~UP06ZH8e`)lzO&MIRlE*TZ z7lJr+t|Hm194jjJf2rS88bsLQ5(?q8|6?+dlGd{yK5g z^*MjG(yXxtK8;34Cl8Gd8j8bE<{rg@Y-V;KUKJO~44orUSR!dicKkfXoZJxBKMC>9 zD7$T2_$&sV0Py3W-sa<`2at4%Hg9=c1Appcc0IhB=3&%Rs(?1+B^B}})U8|nJ9Cbu zS}igvtmaAx7DGk1&amZC8yKxSq|6AT={FrcDl=H!ZLk<6!1H*MelPpSnPK<{9p*O` z?%J$q=cxu}rK4HMT3{_~KmLP2-kk< z`sHOaK*82hVuzCUrE6aK$3~8P61*f?!jL}a3eV?{d@FM(#=?kDHt}bKjg*{%G(6jH z4Ri7-Y6$;^#3gAuAa{#GO@H=v-0)6@Nu9~HJzg{jo;vhs*ekDEPBiE6kG!slp5Ild zs&k>I=bz=jMkd^ZSXsgc37JjNQ(MevJTl})9pQ+9&Vu$nQw+SYvU^LY|(iY9z+8`oWP;*P#AgGAb zafs_iP=KmyQ%w1dRh!{%FMR`S{rJSY%?Tb(NM{x#9Jo3v&I>;Zd<0R3qdj;X?JFH& z$`URDt+aqm)8Eu5Gs$!7{dK@J<2pjR1wbv0SodZ zjzvV$4h(R7yxqhIol>Uq(I=ZppO~dTOGAa}rS9xE&L}LfeN)v6`E_$!S1A{c4k**j zQA{C@kEOAeZ^n^Lj~P@vA}&r=2|gg+5zp!s*^bn-PaJq(;_EB&i;&Kq2gSf2(LKd6 z+8$hU^S~B!zaJN>Yx)X&jW9CRwt~S}h%K;;^5_$hx$Lf+n4QAN=vh5AuiCb7F^{-$ zv=djzlJU$oQCyS`p+`grW#>V<0!&VfJYc=$rj?P7jVmm%lDS;K%}yilu9b7y9OxWR zoFfl4-F8a94{COW*bO=+@Sk0Q2-s~?lPP+Ik`AKKqWJ~*a*;4CbzGVWU-Z!Z zR64*dX9~yI7a~8L+XHZ#0&f$lZozoB|3q=o$xjA|ka*`M$Aceu&&!w}0w!S2@IGik zWMUtkn558rUIISoXpX}r>jj{xWl8_aB-bh@?*ToHi^#rxKqIiza>~2ygfBcD8qd6O zVLJLJm9ELf77L_(xHZ2aJYi|xB-3`4H?N0UvK@GxWI}pzj{rquz@%#tEYPR=?w>OB zH!CZ5k$MeWq2@79#)Uwur^9O;w7K$9a}}Dy{4IC zuA5Vu=s&tqwT7@&JQkx) zaZ{?&SK6$+?+K-!58%qb>B=B2727u$92w_HXb@=j!X192V-%T*%89Zi(^8XrWnQR|sGyL)qNom=dT zKt>Z=z2nFkeYGuc%~dVEzG-~-ZOI-(0AkcaMNwo0tg`_#tRb$oh(|s{yv}`cmEN;_jlCWgGT~KFv!p?z#Un+YfL|-R!wBqrhzW;)-0SaeoO_yXP+Tnl2t}mtU>(L~wq?n(S%uyIOq%^gBw%*PJ&gfzaD}nHa zfjP;1HE={!XY<@0SaCRj*e1D^u4;LH`1kNEf)^OoC7~zCz}(grVJS*jWIA z2aZ%mr?SbBM!tB6F?qJ}p03p(K#kSxtsoTAl8o%b4IpzBmWd(W4o~9DbX@@3u|BvQ zJ1lvTEh6MGRjnWLYi>wbvqM zb2a&9V=!e6xG?;f{>b%gWO=H+_+hx z4zP!~n-~Vj&8wtCnjyPYA`(vD6K$L@?*^3g$5#*6z{8?C2&=Lqo=3*~@*r^J+Jv>H z0E=&P?`4=MM6_7Tq6nTl48AC+K^JDL{2*oJm+iZcpMtqjb^|{MbL>bTN zRLYy`IEeP+!71iw28o}+x?-3Up`2#K$KM*L-@AjaLtYo!$FhHqPPh-CXCLQqGkZ_t z_=29kgls9TE*U=Nl54zto?v?1$x-bt0oNU+GE3esVVo3v!=|jjr~@m zisU=?4_&uoyk#CdE<&VJY@1a`wMg94kyUrvDDB(Z87|_-kxWcsb`Foe?NvSVKO{GAHOPu#L-@G8@&hMVns}C8#(jzG+Xuze1fZZAI z4dK*oRIM%7y`>DSO^hTjLSmWsKr zlS5Mm9%B5)bKy&U&$ogUk(Sj8)z`-XGY6kKU2$6k)U6~P)a@FKHx@9~M;;kZ+fskm zBCJcIih=|H0uB~=f|>p#0=(4&0N8>vh2fuP!Yr5Y+DmvbLnx#30oxjUD^aF(=ghMY zuNE2dSAG83wCm%_oat3vjojD#!)||gGqw4hsryeGLIFi- zMt$KWY6z%9c{q1{l_kCm#pc)b2}&3kD@2mXIs`>1-K|<&rNo{gg!zfG0B!Wk$ED8r zbl1COUlnh`^!OwQ%HTOZT;1!@4&q6Zuc&CD-LAp1aXBF-n5%3Ke*Gp@(HVoUse8Ay zDQh)yo%zo8BkefsNQ1IhWYMN?`vtz`vW{ZS5p|h9=?k3&BLcV~5hpd0W@>xzWL)Fn z=ma@?W*gk@*?Mf6rV^?EKsfVJGpgTG;fK%=>NAaGO3y5Ofs!19gT65iwO0jiJnSef zFN~y)-57F7$$|=VX2=ouxpG~;(%F<4Q^)jbLsQ>X)tSYiuPc;5c~L0)v;$b8UPLY+ zd}a6g;wE@_c7wZ%ux&V&qO-P+jt#k4*^mS8SUEbnaUufN*aZg`KsN&Wsdpl}+)3NQ zOkPrke|wC|K4)d3mfro#Q zJ6r2hi90fVx8}!^V+S+z%Uw}Z!V^0xmhF=3XZC}Z9Bp|_=g#nF3ZIa}a}GSaq*Lve zkx))b9`K~Nm?$KA=s9F;_+mafpN+-OwfSAmc~EqG(z%uZ%~AbB<=S96*zEY+4IpLa zqCOuPHo(Sm`Fy1Ag&LR;(-bXFgjl3@ADlg7E=FRm2h5F6HUSC{Onksm&LU;t1O#rj zG<2-uUg^73H+{qX` z7#5vu99v`o;Ze40dmF!#O^D%GB`Im^@L>(2JdS-Usn+Ag9P9LAIO2%?<{*aJ`Hvz9#0?6O&0)C9(b zfxSO~`lU?G;xC$<|ltNQg6Jv z05Fw=i>Hu$3J4YCloiJ}i5&1ilN`|BnAvhjDg`)W2G@tVee(!L|j5}#^4-w39I@Krf zQ0@j}A}zLN8}4>D^{k(eJo9DA^i%l8207`m?D(LReuu0P2K(Cu*M0f+GKBQn#(VxW zZaj}xMX7j#tS1k!yawqV_d>Y)ZiQa1?3beGR2XWHSpw|liEnav(1ebo=e>nwzh45t zWH|mh_}totz>Pw@S72|y#H!&RSropzmOz%R)^Deoj|kXm??arlAU{^=sD+CMt6?Mh z-Oo1M-g8TE_o2_d*j#d zCMWc>a)GHSzfK9vY(_SM#DsHfDqroe+y=h95*iob4VEt2sV+8>8}x z9s_NSrIvy`KV9*$HE%NNX)&k6>$VqeWK#ml(L$fg8ud4Vjf2u0EtVFznt}l6G7>{F zx5CfL8EBpZQaqYJ9_HxK3VXQk!}Gp6KB4U=CJ$HzRtQxFL|>=y=OSa@K-A);rW4PK z2_m2VIdg(rN7E!#h7i(Tc}Jl+t6-pv#yToOfV z|4lDW)`S3KV}YG$i{Fy&jMmkV0_Rq-gXmYJ81#_dC9d5IC_USaa}Wf8U7W#G-@Sl- zC5qjTu?vyvn$?`zxeJ^5iC04CR5yOeUOu0ij&IUFlFEcl;}&Yl3IF~)At;AGR1NSK ze^hsIgbZ(hd+HA`_&w}#Ix=>810FWvTA_*?);<&-J>uHy~!th%3ZqVmWBFuKDWS*LJa^+137BVgN z=~O)iiGZp|e~2J);)B;F(YT5aUJ7hpKjvtT^de@0M~*@$f13cXo=b}DmL5%kvQ=-) z$nk#bZH$o^z3PZ2DoUS}cQ~Osg|_SjPwrZCE+TM|ktZDYF~hsq3b*KQ{M{{Z!&(n- z+tCF(7pLNpN5X$F-z7KC*JXKiJx1}n!hLn&3rRkoW15q77QFHD)fwAZ+-UZ~Zl$xf z`vtTj)Q#wpM%4u%l(DnB2Y2wDSY|5KAh-%7@`wCVJFnb;8O(WgDkv#fE0sao)4nF4 z&kWq@b>fCckf(O~PQ^UF2NuZW5Ktq|C(wGZDR0($B=EKdZ<{U;<15fcu!)vDG9Oxi zG)LR3(Xdz7;(qxR(7G{UzGmY@(LP!eJB3JvX`aHT!@&*^Z|JwwVPzld$|^2obXkP) zMixnURhX_W)^Y(3XwRCvsN+?_fY;!Nh{#bQBp*M*^ea?FT7SbLhd-|VH{IW24BaMo zXRyF{{b4<>b^=@J#&OdwDAK0;3pSlhbYOM)KJr7Dpng}zSl0zmWm$b#HV!&cn#!F1 zzzH9H{gnr(o6SV+n_aIBH+Yt{#6O!^GK0$8Yai=CY~hxe5eNr%>&~A^m@Rv$$p{0B z)Heo*m^mqFPsD7x4-!pOLUsv?d|Y1rNPmh4_mnuI1B2t=cquPgW44XShLiH$EP9lf~UKc_^ea4A=dzlqe=YdM!$vT913r_K)0Kj7H03xO6-H?91)FyxH(m?5ISYDHMc+Fw7m@O9J0pl*dZ*_JO&vEh`^^H zGB$;K=l315BE>*}!JO+{Po`+}9rkMq`I`$E+Fd_8T>sbv>gvj>{3e@7BguY}qzeTu zzuJ1G5$ptOhgKix90`a`z0Qzbw1ZZ|pQG-6@WeweE3Dyc4SX&-hR?3<1c5i9Z&-J0 zf`iqH-c5B0FODe|cCm*o^65X>gETDcP#sJ7lcMY)nyvtQU)(%0da#K18L!E=cpn2` zhle1;>d`WH43t3K-u#@UXMDD0WlBarK+cAPA3PqwEyXSMY||4o@4fl~$=6Zx$-A>j zu)hq_81ILW3^wm7Y6nG=8Qq~_#3k^eQ^sNF=nvJ|?JWwm`CQQiH7a z0j<~6Nc;BLg$hWnkO;W=sQL;g$ddcR$@}r&QT2m3_YELjJQ%Jrx%}>T!uHL{<2Sfegt!@Dzv`-{q zA-|(?Fss&rvT=LE5TKwUi*}g9;mQitnctMulKigqkcA|o9W4gVoc;W2s8rQqEL+`2 zUSjR_Jt$$n!s?#8jmmpd2#UC#&NCNYTH;`COV@l#9Gy|@m^SMJvVk#?22$GNbKn-(TSRnUCgo6H=-#@J6v zS=J>wC=4>&{Ps>tFZ_&F8nkN7D<_4{6wmW9V7|rzuVKils>R;qYmbuq78Ji%C+yDs@0jPO?!_UwSec zqm!o>3`@zipBV_g@W2cKOPO86uk9Z5kn{8?BBGg2hWY9Z`U@&EB;qOt-j@HAe%N-- zjyTD|1;~>+42vYkVCc|;HeUD+O6RUpD-GtA|! zX+B#&c_2(^U2*q4Zw$VU;J@p%k$qqJCW-=`s%yxLtcyoq#?Js__w-U(v`C2iX}*&; zU_<8arz%t3=FuGp3y2wI{ZQ0`I&qsTm3s<09J!ut1G~r;3x08BE@R=MpU(}kT)a^y zdr=q9_e5ECb#i*M!TjM3gj)2Z229)9ywSn)?Daq7eS}>te0#8-p#xi%o?kM2GgDMX z?yhvkDnBzlDD!~i&M4{;u=XqC_CFC~>0qPCo;3#Xfi9b=YWiGvF>;pCULv-* zJ=JN^LP`q4?9f!MGhR&w1iX-e97WyNif>5 zBXlf-OrTG69_HYGbV+0}s2M(VB+$|%?&!g3C9?}XAH)D{QBPH>{tH`k)~`}LpY##J z-1Ojo*Qi2$K2@v7cmBq;#3+g#tJgIh`DpW57uwPK#j&M8t-cY|EQN-dB57 zt<&Pwze@*V)`$1 zKH=1@8FMcO!pPn#GoN6U9R#UvnbEElTz{#K`z--8>J-tYi@Pmb7PK)_Tzq&JVk2~f zj&Z77wdSq}FcyKT3B?XQC&Y;Ok#S3ODvj zyGp&~Sz*3oPLaZUm8LdYkM`9R#cuSIi_6 z%N79Up5Z<_`YYyYB*lX|g)6S^v4I-=F)yVrE%w2bW28rVVJBQs1-{I(adZbcsWUuN z+P8HV__wETxYesmt2jL{)shq#e;jzDYF2%R^#hfU3U*#JWG1g(#fyMb_}5?IDhuJH3r5y#lEPceKM9W>^sG-UwsF!8OV-w(K?NFDdV*&2Izo6P_38;A(E_1c3w5KefV{Oh_MRqP{M&n1#FVD+6kiwHEq9TQ@u4mm zP3AveQXv$f$Lu3S+@3P%s6)IEZ1>mNdN_2&YM@TVW)$(l#i{JQgfPcW8E;ynQF4;3Y% zK&QTmL-ByT)sB(&?8&Xh(Hdi>gh*f7! zF#6k*DRvo@sS$=>bs?HqH}^mjU>MizUoz3(A-jKiLYeSawP=+01ZPgVYKvs*R{xM@ z8tkleoQI^%@ER=t#&yHjl_{)t4!7Hm1HomidCY0aT_ zu*Fx^4c`#hhgoMBGq4iCp@HE03d@!L=yMhWlzg1CY>jB2ijO`am!zajpTegtqXsem zRM_;?K;2Irj-@cgv4hi1vaUhi6#ltHqMc1m>6tR`k}iU`M8`74&Q7-pJND(MHr52r zxj6dAe|$US@xA18%1U^s>n+TLX93U!Ing}J+xLHg{X9Z z+pUBr`sHEQw7=vdl#X^rzK$zCW|S!Fc8qS$al%*zHKNL%vwCx1)xDmJkQ6^YQ9}_N z3A5#-K%Jwf&cN6cTQBbC5S$6YXo-#JQV|mWGoW$+o)0Ct^P&Zg#0l8PXT`4m^z7j}VU267F1gd$2qjL^ zbO>+zkTT73QbFrtlqgx}pm$OT>KgD`$74PDtX#u#GC2ph6s#ES`Spf4PTEO~j$n*% z!PvPyW{vWkACKRByl=NVR39f?7k3CQ)J$efD+aIdIl>LKk7kwfAWhLUxn`j>960|e zbV3rd@^W~fdZzvvHC_uMEA-oIp$(3psXi-0udTmF1R(WRG~W+y;XQaul7!H^{(b*t z#SA0@*M(rc{H}rrFPRe#$WLMPbo=yK! z;7k`)=Jrm(k#9Qbz0h3Gea!dHkmnP+Q!}lxGV8dE?c7XI7|#+aIQ`2$y$0;eqN`+% zT_4l%HI($c^|l;g&VSTIwerLy-jQK7U0`Pq<1GX7Cp!&VZ?+MjD@MubE&*d@|J|Iy z@cjy4bv0PQ1HG8TGkS5>P9VcyxZ@bc+Q*gr`n+XG`KoNsOp*{9`Akb8`;8A$caz=d z?5+wVUa-|php^wk`FkKUGLu1iWV(UI%Z=nw-R?96VFP5cs00J>s@#aA`qprX$$JieR}mHHMq)ar8t}_8 zGUF+zYc$c$M6V>uAr6Ts#p)dyd&I>&R&^-<7t^{@Ov(7amFYf8&+5JHzMC{22rCJT z6n=RbuoWDUT@2b6)X;`Yk%_Tu)R)j_Zv)5TrZ{=0=JH7(zi9f+hpn;2wK|pG86`WQ z#$pW7j|AP zb4{HN(M0Yl^1;5z4Xp+b-j0hai(Dhw#%o)Cx%=x^NgyUX-H0(&rs-B)V5S$r+pt1w zRuBABHP2|=Up4J}JR^Uh^7Auw6E;6Wl&~Bi^WPt z4~vZU>J@^gEi7?XF(AJq^$F~md>!^i9f6fmv&B3BFJf0Jg`bsKDZODu)`%wI#b16s ziXqEN&-*1UUsR>~27?`7u&-Lf2(bwxLD{Q+Wru3xz3mYRJ|DLDp1#dMh~`%8V9XqO zEaNvOQPiqkOXwepQ)=@wDI8K;G;DE*yiV!{D;GDtcSK!`NQops$_NvtBTHMb(QyAb zH~Z;lH~kxn49;H${2g8Q`jCeyXd};*J$#GZHm$1;sfFk;GNumq`Xd3;ZbG}sOC*Si z6S8+F6E=A0s+kK!mA=r%{v{EAA6;`8bEUs5jo^DzHVhp~xf=}5A62&n)?Xu9uKk$q zb0MhkzHwAKIDZ}hCt@K2a?>e(x8XW@zJi%1$C$l$Q)|cJB8(Ko)zR~w5u^$_uub#k zOHzgs8KR_QDGm-^kzidYQ@JCXd+{fFU)-Jrcv*vzEUq#cvxvVtkh_yPtZctHt6L78 z?&fvZB`hUbLq(h0b&B!}p;<|ecPkzQoaDDEkokiBiuCya0+3ERtw<>aNv+PyzO;#~ z>8eM0AX@HgKBOZnbcnw8XIaP7SlM)*5w!h}=_Hx2e5aG0TVuf+V zc0<|hXRVJ(k)NF%=ym~ZqC~`f-nZrCxk~4MkGZJqr^nhoED7gS=h5s3z7^O)w5id; z=4||Nq#x^IYi8$ha&%Xk zc0nV}g{3{wl?$y6R^2DO0<3sk?hsb!!@R2U$8nj@eG;M{gZ&59oBd==!>t2>wjAwr zT)dV^$v-j4f7g9j)%uiBi=JqP*nQH;RdxEDq;0S@3!7%-1kNa`qzg#D4=y$|9##^1 zWAG3FGhc#}qy2How&q(!^KV0#>7yyPR+Vp8M2f-Xgr9d)Eud~o!uKLv?@DFocAHpG z{F2)Dc`3Zgz1)v0B776U2hrGkYTJ!Yu{BzvF$?ia1Q zEtpE@v)#L2DcVO$o00IDp$U_;*I_YEn<^M`b0%`z5VwIC1Ay8AOD3D?qf9M5IxGf6 zxRPq*IC#P-^&bM0&@sIP#&6UF@^vaC7UutzFT%#blwi323&76)FKOj}Cox64fUDrF z*Rx%(qjOqN3~g;~;YB0^0Sgg9Bk4qTpi?U0O63Xo@6Ya|(b5I)U!#TgOCN1J&3yed zZEI^%uQ5MNU8Z&Q*oFGbY5x@-hOh!x3KH7I<;mR42jYZ>{{;-h&Q3ti&Q6a28pwxv z4S;$-7&c@8YikY2Lz?>m8g29Qvk#KThZ5gq$wl%j&mi#&MeHS^7$+eepMu{#I!1rP zKsqOeiG^$r`~!rY38YE^b{H{02pR0r=67|u7xw4735-Fz0mxlMBxn^-1Zt8gKxbf0 z2$l;Rv=Nwz#H|I22kfa}%>Z@%^cQ7vAMk9?A(I$6F)$E_dU`kx?NXOuVhHK(xAzRB z8%sSpgl7W!%E=&rdJ6W=i$#tADzJlp`MyyD*%a&rq$>avG=OXaAJ9t7v`NTDhyi5e z)Q%@Ci}z15pe5oeA$3nsBmn^lkD(0~Ycr1)-%aoMj*ohJk4WSqsh`007d8 zIM1|~=iml{s(XV5<7yW|eiLvbTt&7B2Kqe5g;GeI0|r6{{l=PES_g*<>~L%kzyrjL zJ~hDYC;lR2b5tNFM*_Q!cxd4FsD&NHcDU5j>9Kp}1Um=5dox}QAYyCg53O|wbifkm zowg{Ks1xNpo}a=a=y5#5?Eym%Zriy&KeN1QO2Y3hQ^HAQb0U10r}B z>*8_AwL3T%umA=|E(XH>IdU>kZzv>@0#57+y%}gL2ay5?F}PnUU=7g#)}`;wV~XEv zxBl(y!x#pn75AGBIchiHGn5i+*YU&jy8zmn9RouorKdIU^j815CItxW9!&FKQckdH zNC>xFSc|U0go2l2Ido_aae+SP-VqK%%b>60*Kjs1`I)KtR9Tm5=GDGpqy1|s<%Rd# z`^KYNP80UJ7X7yq06}YrmRqYLsO-b(Fx(^uwtPf62wuWNtgN0TpNwuxVtsK=B&W8> z=Cb_>6Ury8oZCE}7n7h%5lspH&z#MN%F}P@tVF3ndpl8#ZHuLn9y)ue>BNS8G=ffS zWAwD*v^x#i&MO%5v4VJuvX&mZ?AFM3-uK{gui5vx1O|>eK!6585)Z#w(VjP7-ygZ~ z58Gi-0_vjB`3|-%(@2`Kl%;g?XKV6~W9Q0g-I|NBj@svl#iaO8=KKBkgu+miif;0B z*`!e6Zr=MttZxc%ERg~nypBB#lI>Z6yOq2CKR;aP4buSkIljGQH$65VN5c1Id&7Mk zF%t<19iP}_z&u{V0+0jGaYZ`2cW@H8`S+lr<+S0c;=x{S*VUAp2Az{BYDJ8=7)pg0 z!WN1o_@}tQ@B<`wof>c_8GWQDU5`kTi>q&}q(h#`TPLZr(*ZXGGc!uU!;+Tg$ki7f z!;NB9pk{OzL(xY(=jv&xLWEnl6)P7ph)&*^n+)0!zzO#n8?&>@`@^2t56)#kf`**fX8knPEWU?li~UJK4+E?m&Q_!!75^jggvFKU7muPM zHpY&VA`%N{W0a4MG&NQfALG!Pnro#4$+N1G^2IQf+`qr|=7!Cr~E-G1owQ>X)l zwh8lrkr}iov_ucZCAU(PjQaD^pnU1W!S26&J?`_I$Sh+YlE-GBqfXB=Q9WN}Qpza( zQQ^!DJmc~CSs|?=xsxzSWmdQJHVH~$i(BD#Dit3itLMmI4gCxF9E|iybRvJDRMXga zZd5U|quD^i;J%qNoHE0&NY_vgKPyn3b&U%xL>kt0=IhZ=-cH~Hx73%HuKsNc#zgH} zK!2b7--};tW9rSeX?5_G-I|o0#2q@i1dLI?SFkPjib$ggT_ilQ^GEINJx9u}r475T z{-`_xi45Kc0&h@b59}LJ;n_w}Gm05d9LYx2q%tgSZQd#9ebh6HRAwvtytZ!;;i=HLx=!$uw0`Qi&;*C?Kl;H?I&M*j@!_?GEirbarfOt3R z?l`223qy_1qK#L#E&rV$PYDr4?`Xv!s2!Olqt|u_)zB9$Yo6!KsoX-vuuz9M*7R*% z-IQyF>Pt`-?C#S~yTHW0+aQI6=`0d8KH;eTSteV447`_A4A|6hJ8>Bi?2F2X1GF)h zSP|CiG6v?IF`?k;f;sMZh1e+hIBfuv5+X=TBF&xa&SBCaf>jinYTa=wY}ZR=k{-^H z(@CKncNg4i4oOR~x=o^WD{^kurtNZHl+Jq2ulW92`N+Qscn{$eo4RYaNp^(I84Nih(nAYpJDv z8tqkYMo|@-ni_q6;&=d9Z~TH{?hJ4TChPE{bQ5Yzy(lLJE=F4(g@R780A9^LsXHe4 zUvJv)d<8yv6AvBH*e?eghQ&q2;45W_ba;JJMGG&uZX@c+;k0N(-CuAwV?LCUzRqSC zBK0tggE74#+2Zc4O6lXL{9VhW^eEZ}mtJ~RyMl!~`QooA_ySHbO4d{WvW0VA`0&1LU$Yb6 z*z38W)}S&q$W%=6sB7fJd~$DP?`vWDar*r?T$ zaKWk$63rz1L_5YZEm^;I!yPZA(lig7Fp$e8yVi@AcL`sX$$HaxGRn3-b90*%rEA8^ zZK%xxbT7m}6WmAYV6pr%)KfWggK({hn@rr$3QN(9uBNbv#@8MRLCj<#xMr( zRx4T9W!Y8aisolFh5w3g0oVo3s-^-gDzeCr%8Dt$rrqtlYknuE_3(8@c9Vg@HF3wOoBu=AIX~yw1#bR{-PleW+qTWd zW@8(7Y&5oQwP|eIMx(~&6Yl%not>RMGxr~GemZks_*_H0ascDP?ZR_-mH2;dx0t-# z!Lw=8NOs4U`)T!MSxRy&d#Nak5t*w6!s^On&AK)ldhYrx-cVBQFL6hxMZhBZ)CNVy z_}J6QHg{n%w_yK8t6Vi}&UZl^jC1^YNV(k^(_fCJHO-7 zyL2I<=kBcS8T)O50+ZkGh%UI8$1K8zUm3KT&QVVEmVsSV!QQ~Zj1V9C2YdoObtQj` zY*oX{s`6`7rXc3HZD%+gjLCw4GtEfDj0?;^fjzc6!mUdeU~3C8(mPcQOS+%g`i8 z8ZJML6`(4SyTidL*#7c<+FUMtKV)fb$t$zb_CA_xFw3udWkx;pve#*(pI^81CBwTq z3tQbG8EX0qtAo{BcrI5m|28R_Jx#%Bi!V!(fN!j0puAM166*hLx zM)dY9HZD_oZvl`DgGL$U`J%^3bpv+|w$7IE<%{`ERd<%DG)#;z`|C?zGarY>h^y&i zS@{b|8UFfyMKO-#U0;N6Ui?=*O&UGiZ_<)#0i!nJ)|v$+3^jEdkyXXpC|ylx%A>I@ z1^@&H2^>t48tWmNfpN?X=I*iLI0-N6UWWedjCyj%aJF(IL90U;!%jlu6dH`=92P8e z;-74%GL(B`YA`l(6O0SaKcy=I9k9?Zv;h{W9vAs+@|i1=&|9gv%-DGx^!Xq5@TL3x zyXxsw?FX{lOegpj9r86q(4Oc+N87~z{j4^|ygDk28c>|<&4`D(GDROA)UKaazpXE3 z1s-A!dBKtjbs1Q_P$~GY%z!&xgwo)aEbG&{Zi8zzhz25%EPm~z_w;)j&MjmI8VdSU zr>qgu-JpDb_DTA~0f|A~J8LYIXQv+CULG%OxqZp`to7{>@yg~oP1TX*3c1I?bR1wK zk5l&YuTmG~^zYn0Zd#PGM6UczwqZ#9qSMc2YwVQa z0ac~_$5s2}dUne;zUJOS>C$JQA_jSi*_g>O@ryEvb4M^I*?QNo7lh|Wbl&o(q z!+R1x+78>Ko1-qdzp;~3+y`&bXrL=uX&5J03th2rS~OqEr&`@f@RBLDaPdZR$? zhZE~^HIp*P@ZbC-4HjA`fNhV$J_ity5;6n^6qjFbSFOC-6tBN??C&c(WU9}s99aC$ z|7U*TxIWDx=lgewv!uX*eKCU^<(#!6eyY03cy7lFDRIf-`GWg9vZ+_)H+EJ>3zGYE zwR%lUl0E`qXHxx~|X_Zr#>Bz#DUs|<)R*j|J5|ciF9hK;CPUnl=Wsnc^puLmwN^!U;iz z%m`svYas5q^9UnDWwIH@RZoVJE;aA8%TZ9HR3ANZ6Zyy*vU9Ha+3u?x`9iGL zr7@3R_OSOL`Mu%`F;YY{8*Wxe-_Mvk;!|`h)zGe~^U3Y~Jv^V973?Qzj8`sl_FOg- zj&yh7K}B4}7ib;;F3{^^&W!*IA^l*{XnH@NT={Hg2x$Lu5h&K3yzirDiO&Fu)! zec7e{-Uox1h0}3Af}uvvO#| zFyna-AKbHT=xWpYKU6V>%uuB0y}tK9%)jktJ6Z@kV6QJObmpHhWAA4>oYbhD3bqpO zbPEO`J9$ICU|+aHtAEao-HCU*4(vhu+=Y<5h~~zg6*$&R%nlPN z_n+Y7yoqfB3i3ZiHP#Ec?8d80+|f%-1X%G>afX36bm>heFA zd8u%2wz|>-8-@a2VuhZ!ZT_?^L(KxF5pd_wW!I@A@nk4@*LjJVBFs%>951|MkB*M2 z@L!ZNZVv9;8c|zI)&Z7 z=VhgrB5G65&5>#_LQkWhw!YTK=505;Mmx1zG@7HG%M;$q5s}ywHLQ>Qqmm~g9hXiy|597xGpAJV2&&< z83y5-hKQWut>FhMu+$B{()C7 zmA#B974^G9n+Je3|h zGAU9QFBqv_3K$R(uX9ffx+D>A{>{zyJ)lfJ#>}H>lF5_9$Ug*Cw(&4u&4um4?? z)aqmXh`bNqd#w9w8DG^vNglB06CZV3COXfVHXq!a%%Dah3b{S;I8y|bz#K)8quon6 z9y+d4Eq{0%V(9J>ZPqB&;xJQ7e%Z2@meJm7eaZgdZ_YnqMfqjnL63Di`_Xy$Cdy#C zwt!;Io;v%9e}wn<$i0iU0V|O|TD$pPQ~hc0Xdb3Hy-|bl9$`5%gcV@9DQv@ZY{X!p z1N(8Ui0pE-C}l{wI7MwxRX+E3_5cG)KNFZKejo3%d^xYRPsiRrP-C7<6Gka3wm!BL z(aw9j4Y!WWrB{scV1um<{HMTCRYuUet?aICH`G}Z8xqBMM6)ygq=ma}ArWSps1Zn=L_;fxdVnzx5R%5O+=&nWLaW1vX}RbDc1dNhe@l|U}^Io6<~%fS4_TZQe!Np=_eqm7d*$5Vn}%dWX9HYcV~!vX^$jDUAzLgg zfE`G-emm(Idn9qTy~Ob#D(TfVGUH+Nj$L|1SY*eZ|Ca`YuSy_J!GPZpz`;pZS`z%s zG5FaWNB@>FTpMOd)^^?*tpW=-qjFTOP+^}5+9lF4KU7fBE?o_@Gjm#%ocPL_;)ue0 z12M#jr|;Et%MUQF%laYU=`PZ2&mHFOV9Ah$S26R_3?y{OT zK@vupKdbMK(174gPeY`5KPweXZ2%%<7pwdYX^W|QuL`Iw{!R|S(=)wR&Eb(7;U*ZK zA)uP~?bG)Cu8)iK!&l-M+;(>z^>A%QGlYunzK<#NNRdMXag9pu%ODz4k zY;&4|(Q$^xNn7ohvZSf|#*WJP`7^W}`KJB8woUOe%-KkmGm+)fg$2rJ){3$?)O6U_ zt~{#COo1BHWkPx(Zx%DdS-j=OzbUHA|6Z4lhz5cU!TNX;`;rt;lxl}tM(g=_;2z{3 z(SBQ&x`EG_**s}Cj&TCM$A=zmLc(ZM-0T*&`vG(Z5WXibBEPERQuf%(%=5+#8X7tV zvsVr4;*wyVj@@cQI?BPJXwrd-epS*!=gi=aQup<-7SvH#*^OaTYRY59q_dkcT3C1o z7GN?LX}PKCHk=L?!EtqnCqaT}gADNi)n(u|-toDg?Wa_z0tx{J5xbMmq~;?Pp0VMx zIvj)Np=mwssWxSSv`iJgY}d2PnRud4fN~0Eml<11%nXTH!eKP$4|<9TCHA6ip5dRI(K&<5%B1{~Y?n%ig23+z z)~`R0rs(R#s@Lr$Mw3tW`@^bo)8+DEIG-3Y-F4z~7!>277@Sy82)4camGMc-9T+2H za1VYv3uZ{cl^AU57mOtAJss0?jj1flhB~$AIxhUOd4d(XAXZ+t)ddu^{@^+(*V!xfJpZL+hTE zTa&b1dBjC*y=A+Q(lehkeZVSiNou%7 z6$?LxaE@9-2G(v5PwxUnV1C3+VtI_*n_tNJq?S+DxRRnP&lz^*S9-L_$e5|%p;7~5 z0`LOqm+0QU03{j#O4qNcxg%uQNf&3=nZnvI}1ui4~KC%Y?;gnPfEkY_olLm|%z(duxoHSol-Y z71Zf`@kgUu=jZR{ePu`r`vCOiKKEv24i#cZo#V599hK5M-`q@LMprD`T!$qW;vb$P z*;e1}LrKh=8y^YtpmBNR{=&Czb9z}VG?OdteG#~RvngT`OQU60FaVO94){X%Q@M;X z^Z1tHi8GJ}Ff%>AJ`aCu?*HR}sc|8i%Jc16rN#QeE#R|ji3sO*%#;4pPMY_D_mIUz zDQ#Te0MdtZ4>vY+hG@8gutM`E|ExkrCXb2Qs%24Q-r5Y*pFOT~<{AG};srLzKiAi<++eU*jWG8-u#oy@#=vKYT5O+X{eU_UYIUk$ql>s zByv@wjyW#qZjeiRf{VdWLY;rIW0d(=CN#H1Je!?2Gv`;%J5T;0+ITB68>OIo_qsh* zH~!Sp^bc2cvC))ZgPlh@YP=yWZK;uMr3}PFbseN#k#a(yG%QrHCR=ZIN~@lN`S2~i zsZ0OjDXpsozD+=%&WZJAS}VoVad2L6$jcSWN3mYDb~*2!908x-JB#Wab;gR;^gnM~ z2#tl~|6ve$czAjK4+W8zmy7NHH@1JlXrx@=a4E>iM9%XDmLSKK$jEy>fuN8%2WRKE zD7R!hJtN#IIAml!Wk({quXv9Hk3Lskx;bqH@ANw^yPo_FP*F;Y5LH&8ZJ^Tv*Lwr) zCTsjas=U0k4j_7ZICgq^em;~qI%rFnkBwMBsrXBaXP}7v^9MSa4JvG3o}DS#s(KF5 zA}ra(4;bTpP(#3z&xHrrQsCG@BVXG$>wC1(3@m$hrb$6(Uy(%jV1mm6bh0 zkoc}%3)IC56&RPEo_(UsC$dUlhsp}O209R7acy{5h#DrN4@6wVgA8x`&_eKmaK!^A z(-Ojl*48rd%`bY9e{*A+8$pcfGz6erGT(K$Z;rwAm57X5Pu{Zv5-1CYVvKkVX zzkE4D3KH~BcJPghEJ5WH4uX)neEqPKm*t#jhO=C zk02UWh2~&i5}?-dYg60 z$Pk0x;bYeY6|(>!#^!UmTFwN+>hEv{=vH+;m5SeqL5mc7nfhbOm{XHd(B802+q5oS zQEaD3+;H%c&dmDXq<>d<(Q@h?qzrkZy_5--;JX)uF#b`1tQ=?D7JPbbBAM8HCWBN@EcE_GkZ2ROzWSS6rUpi z#x*^=4G!_rL}tPW&hJ)2G4n@Q3F4uVLNmI>LBtO)${N`yNk}i-f-BJ{fTu( zTQ8GVj9N~r*wH(1^jOzfmVmMBma(Ip zmieQX0Fr-_TN0gSEb~sqF0Bhf`?Yv~P&(_H(koKyA6N=fF$4?bSlC zOg>avsPTNdm(1Kp>kZqVCtrcCI`NKXjXR^oCeqpMlE;ymyVT!c-^1g--4PuFvadWp zrkEQTM%aYyVWZcC`$MzJ3#sp{dEyqoFsTWqX_~QXf3pD8ZMLFX>9gGG&$Plq=~OeU5u7Yb1^}1NeMSsQ zV3N!ryaRi%%37|JxVys9UTFb8u0t|~u~n>QiGcXL^&3{l;z#|e0ViK1J`0^+wZuvO@^u#I5=<&LR zu7{91jko}b96FIB3;5IoM~g9iodyLwS|+Semq3SZ@f=4Md3ij0z3iaumi=6^H9!uG z>6V#@YH9bs^G-ldhmyq2hX140-0&Izv9AL)gA&bCo(3Q_0 zJbJU^=RY4!rrX#)X?Top&B)R#U=hTXyowz2W~QvKk0&?GsS{i`{ggZsjYSzkyZar# zT6vUmQ0EE5jF0O}@uEb877CiJX<`%Kj5puTSk5Cvww(EVyW08dIS0Dihs4xlT3qN^ zGYiAEuw}_21Jr>nVEocidb&m2o*-<G@f62*URDhN>)A(4FTP;vwxi+!|Ti4^4nw>tiC7uLNk7DFzm#H9~7Bqk*Fp!bWCTCwaa+0|*b?t7$GVW(D{u~D0U zxbbO3YDH7})>(3Shof8#F&8+R`yE|deQ^;U4cK^rlF7_A6&GfLKjYr`3)kzqwm69V z#P=*8oc6n0qPU~s5}qt>;vfL&c%wWusM(v-ZkEN(NQZ;8ZCmcI{PNcIWx-08Sb$O~ za#+18lum(F5;Imdst@MGV=T3sE)(q;ju`cAOz{O{4JH41$FAH!F6F+jKX$Qa9DL(5 zFJSAv!Sl_V5j9N#S%8S9g@jC~d9a`^OQ{i?3y5kKQBjL1F7(Z=~S;TZjW&t*69cpqomFjkHeOyM^w zx0VHmic$2qSoe%ir7`&}4zmmh5(s~}1r8H)|1h?8Ng^MfKL5fu4CT`mm?LuvH;&5W zEshm*n)IB-_=A$v;694ondenFN{&oZI(UOL2ERVHf3Q&w65GU|_rY-u2YE2nrs>1JsEKT(}`=%PN? ze+|YkO7WIC(zfhWn1b1LgSQ7c&jpgBi?4_t--b$QyC4H1G5iQV;;0Hwyhcm#*lekx zDF1hY?Za@z2|$P?0W4%vD>9j20Ma~43x=4wVq8r_PY%W#3i?cT#C790shht3K@qS_`W84a#az zk{St4hu>1Dc70T%nhu~D&tgIEN3UYLll8Y&#AVsV3DB|%v=1^?Rwd3&-Tt`#H@n^Q zi4ERXatOk=+0{QZY}>*Ih(44j^Ts*Xf7+1Je#an+Qgu8D@wmRmfAoN6Y#?~k6|~(< z3NIk2^+f+9>l=%H3BJ4lWKZuJ2=c01Sro<&Jxq3VE*EEfQh#O|6MbpGIqjUd9(|Ew ziJ?!d+-7~L`-|O~`w?z(UOA)a&P_C3Ms1+j4p+2`KLVw;GJW#x{U4v+*ga&J)l>XN zNmE$EU8)&xWCQ_~u!eQIf9M-_buahR1JZM;m+&SYcGxcjn9dvnpfIB;zM&l_$z6+x z&9en6syhiiC6q)sT*V&&pVSf6`d>8yc@w!3_xYiB%cHXJ5Rc(kZ46d$1If|8d+D-l zP?`77CizIQdU_dIGe~=EfM#ta%0pZ(8P1aN;aoz1_Q&0uQ^>>>yU+<2O_j~D&n%~_ ziT|2E#Bo0El$(440Et92$Nk=WCPC%iFgdmro>#DVtM+0v)ji^V^O@C3W%yKiDVeDR z=QpEkH!NBFi|hjNdt~Gl0zqN4^SHt>FFN>V1a5l9O!)5%U9oELL3}K3Hc`l7`o4|^ z>=2R$0a*<8wDc;8i`jgL^9EzkfBk;C@F4G_CU5LF+0a94z*I&0%oJJ2f41OEUgqN968?aE)_Dtyk8Mm3RGgU(dG(PwBZjvGcS&OK2`1v_)^V4qinPLhW|Bna5}@Ad1*D z^71)GYeGy=9yx(Perm-D=`GiEy?=#hW;L3Y?YiX0eB3dayt822p1DmZpX>OqFLvyMXiqeRw<63D<&4PLPcC=W z+6G?nr8*PQCLmF|HOtA@`_HPLF2&bWX*+VoULD;l zslqg*Mz`)C^1Zm;8#Uh>LYS;#s?imdbBliFpq5gdR@tKCD-~=>mso=o^Xs&V!!mYY zj3e1E%^BkZH0{N+wbRB35C=xT-J5Kgal%xxO;9Rf?#;tWo%ws_oup$w-mzJt!MV0Y z08smSe!tBekZT>18fM<7wqJCoS83SL`=)c?w>Ms9^o9S=MCY|`@w_XZ9*7~{S zvlU^?5pFW-57*A5E)SdY@|9j`HBi9+}P}+gp8i*PSN+$XXq(m-B~Aw)b;dzp*HMU4Q#_igO0$ zG{3-iK0f$<0x8X1^m^8(WiyrcCv5Cz9Id6&>0EE|N2AZW=iu_(kNv8pbR>mQy^&p` zoj4ENw31FN#gUa6o#x)oE&W7o_G&=L+HHlPy`>6DnZJ>TdE*hL{gaPmgPq9n=7+4} z-a$q2&*Q4g-GY1xQ#PTPuZcwj^xpYkF!8bW57vg|gNdI!mC`n$rjZ!MZ2M=KvitKL zbzokF9EZvR9b{uS$Ev5k%)J$KI&-}5>Aeb;oo>mtZ_Bur{%zmxZ3n`l?_`0(ic)U0 z;!Oh6jx-i^d94gPaCc&eCAJ5bZJ=n~x9zdsY?<31VzCGPu;&2;0&5MW3ET%Bn$zBy zK?!fq`Tbd)q9sOlGz)E3s(+q+h+zhF3sVtvO_Mt95DDZ6Jv@XcHC zHfk0kP)z0RY;D>6{AnDwx8{KS8Q7~ATf^>NhRWK#XI`YmFeg==L#@YP%iDf(HwTxk z$}3crdd62b9pVGSfN#ytU$P1Fu>O;^s^Uik=~8c`MU*S3EZu#C9QMi;O}UK9EKV*L zij2bu57+0LBf~qF)t3Eo5W3aX82Z(PY91K^O)jU|k-XgF^Vc49m#Klp_(jFSrtlaP z#A}%Tq2ME9A-5(~lL=`sxl(Y*3k6v9&8**2-VCOr+Nny#h$IP87q$|-rCqo>Uvn+s zX8Yn9#+Q@hfnw;feh@ECSQ8D)!0HO)dv#Pvw4e0_@^r%m9M*3Ofo-PVoSj*SK&~O> zcyjoaR8V2jnjH6A^&r3z%b`!%nxC1$-O|~Q7_nqlScVHRJo(mUfEf{2I3p{%!eD~k z!U3gcs2Qe{fb=6aUL(}y>%SGpB5$nftc)^L-%UAfY0 zKVdYdLUB=FCtz{CbdeX^_T_FOdSg2lkEqk5M_MeTM8kXKNbZDW3DQKwDk_V1(DBPNqrJM30U3jR|nsOjN%dT7+TTc2)TJ`Bw>ci z1z1!{fvNhvqmhkPFYKqp{X*@z{I&iLkGrI)_iH6Os6bbAYk5V22zv&2Recqa`6R{O zxj(hA=|^co8yL=DP5OiJL0(wtsnOM{ilKPT&a^yzp}&Bj$8NhNS2dlsOTfd6TsgyT zsbx+F-o_W?tLH9-wgtfgo7H!6t1@u*kecr8z!yWbB{J%`j^jN3{!AUCMhX*5^Q_NO zn--$fAP{78NoSVCyq*5+n3t2IqthEjwO`XYAx?E!x^Qav)5Q5Yr?b^;b%I*%Oi%o& z?K$t$HZg!pA9aFW_UMIp<24Ty`OJQJ)ThOdETvM2!+gfcD?IEX6DMUH$k-|4|DfzM zcVKc#qS<}^&c0_zY=dD34!_u+Kx4!1?rzjCcH@6F13Y!LE`ltWSxcfIVt zdeo~%He?e{MY+9DBqz1*3m0wo?s7}b|2VXp@doPuU9_3z&~85XR`-bE@jr0BX!d)s zL{yBN-GI5^!GmYsWUnwE=CZ%4uB)47ylc(GSMUxpWw;!!EHG74prKfQy$ADuKk!)Q z6N%7T5%4eZ*GL<)ENV(tJ>Ic$tVA5yZz>ucsdcJc@NiY}y4jcLJY-ns@aOCD;O$PG z(gMEdpRYw?a{A&|UGid`E-v*D(#Kv*rWEiG4%RP*A*NH!%~b3 z{9)0QWh-Q==?XtRCRTALzVaSi2Hy{o-Ce*Cv6B4VUv6tMy>#~?qPid!@TI|6F!LF= zdv8msV4n6Qv#PD^S6oMhE0@w!da)VkAOo)E8o7F4QBbkw(SeY4D85saC&TAwj#UEGc` zckpEVbZ5kLINV~L3uEoVlTI_OxEQ4&j`7gt2x`!>Xpp~I9V0|d=VYauzq=Pt(&3&cl0S3SU?-n2=Fa$4TK9*eA|2^uZK~Uen{Al&H`K zzy4q=U~}kqaJ*`4h;=tb%$t3mTjtLo7`wa?STR7Z#I9f3?s4JIW6htl8*=+Jgu*Q@ zhZktDvrz&Pk`vPkUA+FXJIEgr&rSp6VC2KLXaURQq$D%T!{1E#R^!<43v2R^9}W5K zSuAo{Mj3Sr3eV448%UD-M6Gj4C0C36nwp;57+HxCyA}9v<|?0XPsEr1W>F#2A37gR za){8Ac52t$yIE66u74zb&yytR>~0x&lcH&wB-sIEY_DWT_~BYN18GBJnR0*iDgPLn{pIF9He+%LduZj>?N!QTqX zG~J6CF=kJdfVPv)Rn&acABmr-g6L%-2dtnRG7@mA19&tH>M;>Vy zZ1u(QQDag?ka@2GcI~yOUk)zLl-7DI7p{m1vb+O5#A(jPt3#vg;lyinbet+Kcf8j) zlOgQTqaN7;kog$tnkNA$wp2snE;0+5Qu2PRbs?KC9am`~nAYifrchDB3r<-KGb$Ph z+OWeob&H&kf^bd8$4}OJ<&sbI(r3jx3j2!AL*+hG;jq0J;qSC=NHvi28WgGzlbx#dl)EplQ#|*`7 zb1Ib+?yS^F1xF#t6J~FF@}DBOJG&+PICg?dh_}Pci!j5e=Jd6z7u#|zZr6#$=fBwr zmkHcgk-fp>yuGBn(IsUz{q))SJux!#Fn{518X3J_QTviee7Pe7T3fWsGBF%4jQF@& zV8rcCB!v6UhS31QW;5i0pxQOUqzA`hQ?sd`PljG^z?2 z+Zx|T8k2NF{{k--Is48&D1eMTQ2idSRgwa?p1LzA-5=RjU;XC&f17w+(yxC#1QcAOK@z!7Mc-tNX}_n}%n9^2 zF@7oa>ha~;LE?bRW z;k;hWBA1d#A&Nsw#);L2AU7WyrS3a6j<59U-yg7Dc&xd-Wrd=d2-d;dh}~-NmnQ8t z^gD5+X#nuh=N-Pews|`J7j}))644fCJC3~WgFv(ayYW95ZQ9yY(S8V1vL~G&opA{n)4<~t4Mk2;3ATkcrXqV1FBW&tO~p1B8UyfNRSAqtiQ_wF z&$ENK-=q#BCeOf0JqqzGw|ERA#6$ezE zgZ2T5|qD#+jz z343FDr={1+lyRJ->fLZ=keYNaPctLV-x!aT#LgWEkwF&G@{qOq9pRRsrH!XZVyIJ* zZm7A_CI!oD{WX}S5YbASkt*BY`AY0SF24=%gvkx{9Cl9LEKyqiYhai|ls@&POas%i zn!w*&hktH#Z)N@bH!K|C3Nps`PN1eWGLC#$hVVBlieZ!k4eLqHbu{B2U$j#~GChp& zi6_Chf@q^?Q(J62)-~I3!oJ6(St86XO{sv7Iv2&UjrpK20G2vZ=lJHQ_)6G^^m-w% zH)0BNXWbEx8{awHMfvuRgzwjS-*Fb>WxgpFQ}?EFEI(nfd&~0$%yd4$fN@IjcbMGs zFa?e81G`=PSf5~BXFs#!v5(-uv{NyB%KPtW{_u_Q?qoWi9?GVJ??>d9^wOo^{4iXr zQHR2uF+D7CUEZv!0yZ;CDkDVYF^UP`zVO50Y<7knX1xcUM8Y1?Q@KzF{EM%Sklh)koq}wFa z+txjlP?sU4bZWr_`vdngGu_VIzfLC*t(f@PCz4HLNFJ|``}um!&n>6dN=Xh#5lP2O zQDo{E{x^o6O9?2@wN{E9cT~iu?r~uIt%FBhdzei)PQt%Csb;}u)M|_WH_P=H^xo*D2?A3yWE(oB=>Xv z%-E=R2o2X{v?4?IBAlQ?W2Gzjvjj7wO-D++yg!2-7{sAMn`rZLt^shVYRHm)U~wu$ zde=>`d}d5`8m2kt;vxE7rom`H-mIpA$j{uh{XW+yk1zAPts3(ZE*0iURPI`-kA1;o zTr-au{M^b&nzuWGjzoq)+ZA4Y5XZgXvc|DaiO(eFl&FPVKy+M!BkwIzT7Y#n{agYK z0)u2imoZKUGD?8xQwT71!e?$)EfvIK|Ku7`oU14eyBoJGn}C&;KPR+fR%kBMV_li6 zin@-$o@Bt*0q|Xpa)BdJ9a0!^oBC-8SuBcMRSs+Za~mlB-4B5L=J9M`iulT?E%G_&60HbD&Iqoo8xYl{*o)>!*JspHR&3SWU90nwts{z*GT!NC z=D)3WhJE#)lO_?RoM3H+iSd*5el!RlhGdmKBt!e-d6af>(G{5>qdiy_$_RO*0A8v~G zBHJa|PdcnGtR$EiwlLr(m5MQLz~@~Vhss@L@EM+YpVv2O zr#iUx$OrcN?Z1nBGMYX#u*DPT0v_I@JEc{N6(&yW;;fZldZC(9 zhc@E$!L2+a~p1 zj};PXA>V&n{U};QqP2PJfccjZ@-8DwaD|!emdp~rJM#TGsdZRn4?l#B`K>w#C6v?M1OYvCW`zSXvcuy#U?;OJc#{e3X4o^qmJrKiZ42`vY#q@dbQnn8`O zC7OI@VVRw6HG?j=whvN^K9}78p~s|mF+$K`aI>)fznmQ_D+@Qr|D79V{cpqg|3k?9 zH#bbUj>CjJR60bf7!5qE332Iv1|vZaPfztxLjL@|vilFx$@#|Rzt5PBY*LCnK#`}Q9MHc<1sD!gFJ564iRO^|3vI#umn&;+M=CYe7wD#LAhJJ`UM^s40a%9mPwKV zC>J^n*?Fbs`Yu`e_T)%G>%$eCc>43>icY@Ilqq8sr!Rp^>r-elbS!03aba zuoroZw^_JAXr^}&=zGb7mduo&y^t{VJ%#( zzzcQE0#F0v@d@0*4Dm4nWN!gU0jTFwAQ`Y!)inPv2m8EpNm z(!kxDau(&g391to`V{I4C`yk*8XP+!y%Ro~pe?s3sH^LH(Hi+&9s@>Oy`bJ!!L6Wk zfj527rLYXuvm5;L6^pLO^^V0`L_OQ!G7Q<9)^FvN`}%0XPb$#e&O{&N^OZIM(|TD2Hhf&+^oIr9r~k>>xq&~;o=H_d9KU_;1Y-&0BOQ|I@fpn-)c!S8v7;!zXNoNoP->o@5i+yz&ZAZ$>2i~KSfGQE??7JP>L-J)NE}#YvwFd-( z4}?TNw zo@RC({r(WAIPc&O*(VM-rHu3m;V%NpfltB^`B^tGqM!4hD+M)z z1NsuNf*#?ZSt6K{N#_3$c@UynFKrUZ8!FR zJy|D_Lq_xvtTg!a*c)MfGIf z7yy;C`_5NnrPQ3{g%U4O!UBEA)Xn)-w=UE5zkalNZgmsadL=Q3T$vBGTGA%}{Et5RB0gosuARB6ff%z;ABP*^0*>znmHI6S`~})H z+sCo&Bl~qB{W4(@-NL_Y_BVf(m&=$F9k>|WoK<>7%M8SC=n01By=m78{@CHJnXV`u z`>gnCYo-gsita>D#*@am;T?{lp7`z7NJsIVe-|5ES&o6JXhFS4^*}7jf8q7KTu~S4 zr(h}KH$NMKc|NykUNa+LXW_2IGi2>9A<uv;y^1n?-a!O>RncE7^xL6ZsejD>(8`HR|?+)0F?y^7C@f>jT2(7zC48Js&T-iE&6c{Qe%B~o05=+^sqvFHd}VlzyH{h!~Z{?H-Nf8v$TqX}mhslj8yTYngrexZU>&4IGe{aIFJ z6hQ?BM_}yo6GTlAsKKNQF&OU}?>L&7Rhl7BzKG>48+@TKXXiz$z@PHY>xXVMy?^y% zh>Nz^=-y}=7S@DiV7*v26*pIzKYIG3Sj&O)>6eC^`K;9e`?J;D@U_Z=VD!4We@~w> zB?m|?B`*Y1kBG4>hI3I&-?v`~d25OBanDd*h{MLNl@Jzjo{I{kH#G)8RXw;5czxA-8T6yuKn5)@srVIAO19plu`0*1 zD#_sh%Qv={ii4_tz-U<$8O5A7Oe#vBCFU0~s!WkxJepin25D6S%3AdFPQMRsD;n98 zU#^>WkQ_~eMh0T9`^eBqRfp#oc^K?ctg3yZu2hCe)7d;+0@W*cx=DOje?5}YbEBpO zUS+hrDt_M6`MiAMQTXd<>6&DBfock|H4Dkm*wu#FncYWNC8K27R{U7^Z z@@^}Au8oG7Y-48O=%VJY*)gdiLmqGHeIYj*HJiz*EpnHmz-?{=&bR$C;!-u2wlYpK60%*6$;5722`53ZPVYUK&oK2I1E|_hKw#KbrbfoulY`T`GJ?BHquGw9Pzx z->Q6PuW|cj)^A%AAMoM>H9O;6!t86FH zD!-u)EM~gqc_S2v0%{U1dMv^Rgm580oq3leyl>rlFPXP349}ifNk0Us`n#xOSrE)l zr5WO_Jy0aJJ@?sGf8T!;2rkd9F>kv9!g8q5r8K#Z@;I{*6n;>r)bsjK(WP%$rGoKJL9^~$Oci72NNc1}GhSMnWY9A*IcRm#DW7q#?%H@~?hDhxD1zbQ_)ZvO zM?P1GD&T>XD1#G>0bZE&z_7|8>y*V5>g)EERw|nL$cu>S!*On!>)o`u0^^qUsDx)@ zyGoC7f0*(W=+5(4d8M#g17Kx^-!(vFB=!_?!=G2MdT7&Wr~mt ziEP@}biRQkX(g_n=ii=ZQ${AH|C;Y9<$%fvzo93BG#blR%5vX!!{9bjbXTQ92;+_# zQPZ)ipAd7WL<>3&r<0vR6mFSOvF6`uT*MS3imq=I**sKq{ysrWs>Hopd(|2v)?1wS ze}1cnAe;b>&zWsXJKsN)CcJin~k&9Ma_vQp%SP(rtp^bKe zm$&swOL$KB*d)$fI0});a;uW+`7w0S@J2)H?<7}v1z!g15&wwWH`f6Cvau*ow+t(c)Me1C)o4}~d{>Rms*^r@Yzi&Pyz4jq z*+Xz*>;?*Gt(m95E{eUHH;&S}y~G?-xcD1Pz*AOXq}GK;9#% zsO1r3p);pSVSe7r9U9NTtgO?Z^ix%+TU$Cacg(a}?Svc#5}#PARTsQQUji2D=OH%r z_}xY0dv2bptt~h2=JO?Aa(|!?ehe^1!idvOjiSwni2-XdOhHR%5H%q5f1 zO3E+MXBG>cMpl+O*6*b?I)`D9N&WFD)h^dd2-dolYlNM<)(0DU_6f6J)uYpyjA~-8 zUy<<}ahwRS{hI&+c963 zc@t@~y?{xWR&5H6BrCf2G=_*!>(C3o79eDdzIFDgVgc8Y#&`}KICTCpER9v`){!x% z)R6%?eLeE7waA?_&KCL1uU=A(ytey&iSRTAjUc|I5~q$lsPs3de?wu!de1^0O~9&U z%J(BVMnj6=e)#sRwowy3s?u7?9?mdKxv;VoBdC9dW5Jl>htxcTs2rM#YjJrDSq|w$ zf8MTnw*`~dKw(#V4oQtolSHvtB{sK+Sh6Ebste2^?tLd3XG!&G{G?P>CTjIe0MuRo zZJD|{u@O@uW#8$mf3|C4Bw2ZW&=gBYWPSEcUC}vboG6+uDHFDN(@&9Y7_v%@gVZ6R zcX@4?JTsT#py+5b(UP{?v-q;U6h}R#rn4Me(HyY^H*(1QwnqreNllhJ*{B=9KSGv< z>6SRx?KW8yBDozq?#nH!%i2LvpvB!4NCg^rrpq&e#aphDf2zJX82;Xg`NvcpJvvo0 zXh3_1)7e#nUsVv%@E#Q7&(gItzY2^|O08TsX_~6$^N7bVsEj^syi+>$kyMpo-?~V?y78Fmcc!?^!m#pd@?c$5?kfP@#Z)t%{fl8! z?MO9yxH0=qe`ugC^uY(n4^Y=KRxFzt7o`$Lj-z;uTsHC27=bu8LW(~)X=QDKnGEwf zD^UU~yDO|=Ku*aaDj#>tod`-4>b;zbxy#Whu{b_kU7a`Pm{zsu)Gf-GT1_Xmx0vzi z9F)LfJF%_cn`zn5*C3g{rEHBLrK`l4D)xxdn)DqRf8+^45F!Z4RtTjq+cKzu^Y&Z- zE2U|Cd|J0eeoV0v=2+7dc%Px9hFXoOKg_<_;Is|kT}#b88Y=GFqE#$Q#jD(7vQ>AV zK%1sEGSt5hxcgPt&}iIU7iW$YJUz$YFw#e()P5SPsq~0GFcME~aZ?{Fx*zp<^gJkW zQ>D=}fA7WTkk`v}nDh&1aGWJ3S$oM4{&cZ$U6OmsmXo1R-+o9XSCV97WB@C^1hW&S zO9xrUL>@S~7$SaAXFh+23PorrpR*_y$@Qiq1pLz zm-ll@t8?(!FC`yUzWT$d_^2yz-yADs-u_6_e-X(tyWxB0mh1H`cBPPq&oVvqJay&b zy$7akfVEo}EB`m2K$`oN*E89-)`w)`d>Dc? zfAlsR>v_dVs*H}-C0m^dRg$iW*{68JuPDJ=b4pUn2_d#)VfT)WIvhutKkq%6g8Q5~ z@R>$*w>sroh8LWC?x;xwlZo@OjepL{)>ig7AJm!GS1Wq(TPS9tUDqve7yrhAalW0# zdRUJe-aNxx=X+DbT?vV{_$?<9;EKw+e`^c36Sk+Pye;iPd@XgVeq%XrKG~$G`b(6* z9JSD^@2CZNTN&zhDqYHJD;>IKj0g6p2<}|j?mBOqI6a=kH-_RKP|E%MCGswA(S{05 zrwC~UkSq9(!m3H6;dtG8s%1bUfBJ1N zyMg3-%`nr=XWp^oZhc_|KFG?J{jtsjuNLDt z*0%c!6Oqx=z3#EXo-FRK=XFj&3!o12K1558YpG{s{>T-_)I_t((feOAdd(LF$iH*u z_)Pq^1fJ#L7xzDpF|8hr!L^)he;=05Dd_Yf`-XB1q$0=8^W6oXs{zAb;s-bke%c$5 z`dtvS6VManjk9}dSdW61z5|JJkN?00dG*5YMYWTpNty3O?E69dSc%3xp%ZFXcC`t{ z{(|2~r>d3`0Lw3>44sy#`QKN*4!FZ5n>~kGddd8n!VQ^+$hzsf3l5WU21J# z4bO3*#fV!d(Z^`@ow%?&v>O3#$0vAvQOKQ07waN0y7gIUgjb9|yM5LAtl#d}BcG%Z z&+EzUsOOQg~@&pr|&>f5y5;>`qjn_)xfR z&e>Sz_N5DX;1{C(+a8>Xn;R3V3g2+KGME%L?-d9?BlF|F`n;5c1B;lUz2&xgYqZ4U zT>ijg;09>@#6V7E#y_pO*$5|KqC^%N)BmzpuV1=2CZ^IlNv4vWAYtnf~j7#d+JiD;Y>gL#^d-?J#82CE^Rq~5PTHKDdjuxy@w z{8slm*eUx4iQlCi*K{v$TtO6= z<(|eP7MiZnw-v4$u?m(J`*p)v)Q~nl+a?9M2K#qQ9P_n$&sfZLQ6|`_A|PG?_iR|v zCK`?MMB}oEm(^ET##nJWD4;su&goxgyseXFnDz6plZOZ64SvgaFBJkUGQGdWg(2zZ z_{TCCCDrvse}yYb;pore3MgZlQKyIRE&r0Z6B#hD`2B1^Vy0O5l`>ZV@l>4|t=~Km z`YEseqHphy0gr8kEL)`Eg~EuRT5F|)EboyK_ zMNQSqMA7zWZhcrqS*`9a&)J)#k}y?~6b0XH(N_9ve~(8!+lAlm08Gw(-Tfm%0}8s; zX1?eW#1x4H+rnp@TT42nc~9TXp6O!obc>TF&YITRG|VU8sbrZg*Ai1zQk)Z8A1{&w z-`(K&qYlB^9k?fYGo|;S4>3el9TQa#q{AwnoouSq{)iaoUn0id8>}WIWMO`|%hV44 zV!FI4f2RMjM$58{F28W(b=bFB#5i~kZP#pfR;}H>-a+fi zwz*ZAVGla$67%O*^nkZss1?`yEJQJHleZ$w2{mY-m0iZZMPfyfj4z>SqS7|XvgDSW z(IEkt><$1#0bjErr*oX)`y!ttG1r2c9DjTX-UkLrc2?yp{4+w!=`tml1z$bZ!T?L+MKNF<(?{5)v|1ZC zjCab9N}im*+Hu@D^_OWYx=76vq#9N`_8X-i?qq{2j_zHHN3^F~(vWAAhmr%QmL()E z2o@oC`cu`o^@?b3iy@8ihi}EvOen6jDn_76NoWiGl=D`e@#Us2-eSsvDPQrme>jlu zbWk;{$5GCaRHz(asR4FA7%e^l`a*0)V$Dp3esI99N$e~AhM+3FtX7DPT zk_?6afp}FIV-b%BBw$F`em6An(fmFn)G8r_G#g{d%VhG}BG*r}D2ka&f8~w-S+f6$ zf>an{{lyQtfR*1oNWb*?bvRhp;cRUjeXN};JrxHgQIQ`eF<+)(+Ib92T*CY#GBX!K z)Hd9l;OdnU&^KvsfE9}l)9U71|T^%8D zQBO0Dj>WoSA9P6TxM{15f8}MfW^=H8)i=FRzQpE^IcP6t!ihb&dPC~os@J{mLEv)l znn6^qLpv56e+pEQ4%$8oB->AT>k)|^|A`*X^mP^qAh~i7I6tk4%UncywH>YL(7NswrbtnlnlCW^UBKv09fcGWEP~%4yP*%SB z@YifPzNIZ=f&Vb&STU*}DYEKpu+pW1%|wMBqwx^oCX=!tb6CC=A-0Ac;m|Tf)OIexarm{WssF#5}WAZq+c zzSMmTNO|Nv0`P-pV62-yhe~3e~>_DQR-AbXsMx&n5 z(Ai4uVkq^L#GdjB2DstDX<&>3J7q8yRRp4)e{|tSucygo`|867gB;xKa?3{7N{)aE z_AES1olWjeJ7gz~e5lkm5%Sc&b}mqdMK)n`Ky6sA;4Rx`g*k1xVRv+|og$Q?So%~4 z>EiKQ&urkHf28Rf{$p0z$0IqH{Wt3(HvE}A1oK_tav2`{ZrFvY3r4=}1xxAL-&2+? zOlpepE)OQKtx>^}d*qc&Fvm}^w21MZjIb`FX4ACeF~n-*8DoXdn9RQwNvMri)maAj zmDC8XdRFy~PJ}Njeay#dN!lsB)$fWX0n1goB}Toze@vgi89xxLRgtK+_e(V6&&wgSv`$k|lUcxTi)6c#Q za;ekhf3@}Cu=ny_!E>p!hJZ!CeGB$)!Iw*+03UXO~-~LWJty!$Ci^ z8}4TYrarM56HIl+84|0P(05n0lh9q$EIc2N+P${ypSC;RSGy|hjK2BIfw^n1r8wV? z^!@66lV`)r(qSw*j{x(FORiuT*xg(1ipgSgf9OE>6(7CstmLDzfdc8o=_LnULXasX zEm41fYp5WlxDt$w{wJHVfXnZ2GD6#fOSu2Rae5k|*NB82y5mX+KgFRgw~x0rTrSN> zznn73?EG4^hdp4Qlv0w=U9aS7^TS(&ZY(1-Dv3;Tu1Gsvie=YwnA_`YGeO4239I(X<=BF2q&r8L7S4<@?$J8dsL4p%Lsi zL`v3nu$z$ygepxX<+NHZ`i{Ua;?vHEf9qO#LQG2OL|DoSlbtL|1q&nP-4y-6-&wxo z^NRtKF5a=oStB^iJpKD^KQ2bQgx*s^ivY=Vtr?o`Jpc)Z4|j}LCU>9|Ke>+p_A{Qr z=ZEby!tWL>+Vl~Y3*(iZbq=A9p>cmQHa=PiXRp_8?h(GPOFKR$Oow)6VfjXxe;rid z^}kM7V^Ae~g+McpOEn!NP+<2?3hJSt{(A==5N1$U=Yvz&Ku5^>31-IZOTOu2*`~p& z_FjN;>88MZ)!8y3a{nT2OUR>yyJ#J6_ff>f*LCo!=O{|b@=Pi_6Jjr$swQ6_5RGV8 zHTPK)LnnT~CPp~^2EluR(g{O1f1=$^mZRU;sdXlrp8~~BPdwnQvU?sLU&t%{(yakh z4xQp9y@UO`G7X|dlCuu*Qcm_dhsz$iRulCK`NsXh+VjDLGu$>C@&oW zNQ#APH{_I_0zOhg)2*+a%gd65b~rF+Ng>uhs7n&FLckQAf-|!mRh(&{7-g&|_F@zKYzb z&9HcAsoCxt&Cu7JPA$+Af7SI|EcNRRI_Kky(@_)H>~3B=w`^!*hr!&z0F|0aD3;1m zCTgOzca|!RP-O3GiQ)VZS7C=7Y>%Ip)pRDFH3<#DE^QO=&Zt zbVnB7v=60e+FOnQ0FBU(KN4m z=q>(ATw+{f4N={}foA<)U6SZq&WJhNL8*>vqyF-&MWyXix}yXAFtk($vrRl{6aEQ9 zd8B#Ma3T9@iWp-}BYK2D#$0{ltQ>Z+Ik75|rEc-z$hU2oZT_U?>ZSM^&S-PXTf^95 zrV|@bm~MMt8rf<=f8gZzDSV~5_pPQFAHC@cucvpkhJ-R^ygK8QBt&LkSx38!9`AZ4 z0H{~lIjBnb{0LS}{MzY~>$L&P{jZ2jbn$u*O*(YuZKV$k8--9CLz2#y@*I*JAyf9H zc;&c{J(C<2WckanF=}#lAD7$%^GLNqefWk)y?$;0Br}Ug_vokh4M=3Xr^Zagjol!9~P}s3<8uH;&Lk<{^CC3 zI$DRiNDDoue`2Wk7={ej(2Vk3$n{L~LC>m?w5;cR9J8pb8#^~*cRF^E{B5Rc@Wo82 zsz>y72ik1I5|hVZbZ~f5e`309idVK)`r=zOuC%k?eU;dGNUzsOO`r&}X3*x<2yJGL+YM zdJHPm_k6o8uCq1?O@LHw^K!Pm3GZe*hCaF)6hqsxsxNWZOKT20GmNaZ%R`3->zdS%y|%dsl$Q0QsqW{F}AhKJW0p z_)KP;1Y)i&jDcxDB7yrm!AflY^cWFD1kUo{Oq+@D{X?xctI7T z;v7cbg!VWDb4)vGWJgIl44V@TCftxsvJ*D=R}DFxvvqCV^TBxWbDYo7`p8iW)yZ0)0QAavMcOqRW%r+RKgAnMgZxHhhMadk|8zwo0 zdRPFQn%adsJXx#2D;8f1H;TpoeRFy~wj{Or#28lE)sRt>;JKCmtLzu-p{YzwzBs62 zke;vomNNP&OSkroOef%a^u{oJa>fA1f2k_GS>jahffc+)){nAyui}C+7gD7J>4Up& zUDq&5u}A9&j$qdd4??OF28GLwtg#Rcy)Fd)rbTtzW#0IVZf*jDt$~&s&#FbKBw1lQ?!Cf3jXD z9?djOB4YK}wv$!(R}&zv$h-ngUL+}59i|p8$tk6G#v^6>Tt~^Tv$j(yswR7sxC9W? zY_zL#Nf5CF8Rk8m?@veD0x1vW4lHtq5Gv7m@R0H zQ2LX7zg>tDrbM2+RC!L2(}Dof_JY3x24TUzzk`4*0p+SAFv8+_u0H0uRX%} zS{m~Onp$KMqfXOc%t6~K!of>Wng49VSo)e>wvS)t&Fg(gihOG9q0y6LHH2y}DWR9mX69rmIyVS@SfA^!Xo6jA5~*lX@YZw#nug_x;#X({NH3WHwP@Wi78}eyGnw#Lw=Js zM){E|XVY$=VMP=f4w&B2K5IJ*)6Zqk$2l)}Ym&|HtBPHKlvO7}=k$|!gO5wp)kj@? zN%#>y@+Nvfe+2%PPArYLsbl?nWhQ2Ln-^tWBJVs*I7;wg;?_SjM~E$rCXjhAWmi81 zTSQS++@(C{vsLUcFBO4&>w4zJc<^^&)SVk5z0#nb-+A@R9t*pj>}a?p@kQTj?nhq) z3zwmIh5yWn^T2A3p>SJnfBv;-?y8*vR1oBwhPfg2I zL|y}7uw(VhQ&#=3`q_XzGidxurXj$2-pyq;KJyo3=vYjvxL!3UVgJ``6dzw@MBnr{ zLxzBLcPku4#BCRN-U-3%@%lW=M$AqID~~iwZdhI-upJ z+P`2kWf1yBty>Hi(5o3^CFggb(KOK3CRJolv;OfEM0uyS*Awk*%>Zb0#j& z$ZYa6euq9ErS;@mqnV6TmUjRZ7FEvoiAOdwe-Tt!?0k$z3(|%kPxTk;cYwBeIofXS z12OnCYxCI`%imwvoQVVj;4+F=NFoDQGO2pk2z9MPeQ38Hj&rq-NkPCLXAE!T*KkX) z3Uz+8F0)>7!En$6^NiQx!P#%98gSFE6x>G;X{`<6-NdmNv zdq;RiNR}kKKa^OXNFolr^2(I6);@m!ZCr-I#G-8ix{Z&AnOYk=%1z!er_dTA<+GMi z|KN86HnAUm<0AIfBLGB~6A<;F%P3gbf2WEI6x3l%hjFqy&p>50ZaJ!j^c%tD?8|fr zBZE-7_*)OJyrz9p!@wiz-WoG5RULnz#?wY+AMaRj6kt^YPb=1!K~(+KL35!k7u`Pa!{x4$WxJ_2|Qwf7$6^ zN>`3Js@hGL$Jv`AteG$3k>5e3kOcO4VFHvDW!Y$>1C|8B*wJcdTBI~@rHP?-J!52R z9|w`+2n5qc|NksJD!s=|O1f!*CMdkJCI1>HOGNJHn71#`eSaIi{DEbWHjdl*f5SM+%P zkE;0kyvH*N-bj%lFcZ9S45bMrk}}r)(>T*Nt@p_bI~WA?5(;j^&DZl;2LA`rm$k@~ zG5!;mMp^+X5;-|HATLa1ZfA68G9WQ9F)}%qfm#6+e=#vLHaQ?ZJ_>Vma%Ev{3V582 zxCK<3+Y&ZRfnvqAc#69gcXusN+yewc0wlOgvEme`P$&*Xio3f*(IQ2P7Aan&{nB&J zz2}_!|7(5U%34YGGc(Vg+54G!v%>gH`vs?rEz}yQ2!+5odAWE*0dg8IjCgqfJUskd zJUo0@e~gTJAUGKK9~_I(0O$q-K_R05@Q`x@TEP*RycHbbr~!olRNcVu2LKy5%kf4KL*C|JZD;BXgFZf;LcPcAEG7#Gyd zUXqmq;0b~|0Ca&cpqmHK7Vx`dfToo*@UPOiuowY)4j|Z{h8IvfxTlpH5P$%{AR8bA zh6r(o*aF=Eh}{7%RMY`lEU>Fn;Z{=YH0$W)l9R5h%3ZN*X1F%9=_*Z=} z8#j;(9L5C$fq&P?{hJ1H%nA@&IjFNU5CVr`{mxGwY%r!Qa;f>H@GslmYYy*#QwBSiUeT4U<_`4t{iosID=c1KfGx-d4zLE=gCJOc zvm;=j-Jfg3{kws@046*L`SAjHe!u?v%?zP1TPOtV{kQucSIljo@KRsSnEkJkfB$Qg zm4$i%d^!0<0GuL%JOEx^UO|A6kO08{-#pq@puh6?N306O4hj(YGhM_v{U>FQzcj$| zSA(zu{>`NcMJN{tVEJ3-TKOO!* zb}MHP*!wRJgmT^Ch%V58B6sX5)mIA~1wB|1bd& zJ@oH=6(BZH+uzN`Cm;y0a&xot#zNdRVkH3ZEzaAokX7RyIyR#N4!l|HCHmPurhY z{~zOX9)!)!4eDuY4gOcubKbuV{|@2j`^)k#e}4YI(0@Dg@*rxkwsQLiAoK@-p#2Ai zp!}U4@P88L{|o+KPDIi+e?So8672scfcL+Ke}^D$h#Nuvdo=wQ6G5Dy9T*CA`xl3Z z$Y1Ec3HT7q_P?JZKsTVPyVc*hKS%h3Ac#>0LUhM}N%($)2wxat{{5EEe`yeTfDw}U zHwOZA20`3mf4d<7cQ72}0{)wmmltux5X4Zn`WpgpyCBX6YKs{3f4>v6{o8`5%?)S= z271BVtzp1_l!u6Mhx{`ogff34zo*AvDg8^sHtue22=+gQ4MO1mS^x3$00O;$HdssZ zP#du@$B$ucH`Owfo}6FD(bhLQq7sbyBL(103-5d#)X_7QW?W@0Z9hC6P19a14WFL( zqhve2nea00&JJEne^t(fBPsN6$)0lN4gWarwg=MKLMiMgh0>z72u>1psPQaKP)(SV zU(VmZ66)dKt=uVi=z#4SiyQ)+0Yz8%&r&Jju`)Rwhsdvuo-u5|M~qDI;|SeM(%tn` z^d}#XUxVVVW!qxNe|T@1#AS@Et`21n^r!Kk<*W5p34RDCeq7^XK;9d(An3u@uSv#Y$ z*v``X!Hx5@DJjZ1rhXq>3M$+lxv{13;_o`20&_7Ft|#ZKRI8+z^8v z5Xx`9GxhYwe=;^Rk(bXbMFK25_~pHeZ*L^3x1Bj<*Gswn_6qfs$a+LcbdWBr5M166FVG^lIzSSoZ!%z|-geQ1;np)| z*KqLzo7d!8?D=-Ei}_x?=84N)nX9ZkfDn&)@s$Yw)(4FsCJ|p$>_~$^d7MjOLL959 z`VhW(2p5urT?5uOSW0b~H2=_q;dN6qLG7)Qf6M7rFV!khOAQsb>Y$I!HA-QKqVS!E zHvh^OZbL1>A#WLIXU%cI;jYK3a9E1d|MWL z%}+iwmqL|Oe6e`Ryk^LWhYy%L+uX_hTA?^MSGO-UX{mKH72cc`9c47f&mv#kF}>MJ ze+Sbl{vtIER3|{zb>OX}QOvRaUi4wopFIMMBX?s4C@TEi!-5e;GvyBxK%|6k8f0ym+w{>}`<8Q_PRj~w&lG1T5?1frEiC!=R zPf~s^ycvccNaPaL_H5#mq-Xl>eOkCvQoNm4zvZ)nBdWYR`zjXvAO0C^}0)-i5?FA_F_a|Tcy^{S8bwn97gd9`*_@_sx9w` z`@<^W7p%lRBeTp7ddca%gxmq4=6MbDZk?(a(V%iE|tS40Uu4`o$Vj7qy2{ z8_6zg^I<|BxC>+wpS5{m{##0Tf63AXnn?oYr~D~VdS7dW?OMVC6y7>T5uwdmtYLLH z6+A+-J2Q;9uQ0=uunTUJbba0vouAw7`$kNe6UaNPT!?Sy`(|Wp%BGAS%=_PV4J_rr z`0SYF&b`+*t1SjAXDg-6Y-og&YakRtuFRq2JCD>N@1HwqNst}=ESH|we+ML$tbjRI zwV?{H*T{C9kUwRx;R<26qL?f{L;H4p+c>efH){%Q4KZI}Xk?1{dVXd`APi24-)@98 zGlhk9b0=(WnzLp;)BD;NWQB8%yiswyG*!Dn8r=SZE>A3eFXi6d9O*?AmW;qzhM=qj z!RLGr$ma~bEsPHt@imiee{`>=uSCEDb?AabSe~DBC~H0U$LmY-kpchHQVWFj(H67!2*SD$O*z*pr&$ zz(zhgvxet^lhYmW1rvX1MSApD6r<_xkJXAKya1S^XdgY(ak<9qe@>vhZgvyAZtE5+ ztTj&E>m1njSfmkg!uBSJBdu3X@^%rUkRM*y0wg<q>c;5juz@_?=kE&HjDmh|HL}n9;ZORxL0V)T+#crlajN!0egrKiJP(? z!1z7RKVqqqGG=jwe+=7s^i`GdJw;!>I3xjF%OoU(zWP3ga&92l*|{|lQmOUrSKOe z!v%P@QmZwFB&b9zp+=#v`mUWcU)CFS9Vsq~@5%btrtUk{e}3*oU)MciS)Q9T=UZgN z=RuaafB5Dc)`}D}fwvF#a}I^h4t*`P8qpf1}vy-T{H7@kMq;9Y~%|%Mnj$ zZj^ahg)mCuL3FWGy(b|IJk*OngX_wB4WvMwgoIH(=exoK{eGQ=lD5Abz4bC>KPZqmcG9QWfJZ}A}7b&+E$lV7IXi4l(4}V+?rDi)y6Nwpc zo19a5f1L+)tkOSHyCU*(%xmGoNMhIT3CM*L-y3+lijT8f?hZg(SJSR4KBRmt5AYrF)#X zY0cVBK!hMq3J7LU>_kG@swlr1ie7f?N)EPVin5KbsZ-k_kH?bqiX<^vB{_<*Q~Q#% z@=PA$tM+4okfu^j{(s`Vg$HfUh>e_1jeCjf@B_K_xfM$&DTkX!dGb@?y4f2o(a2nMRGvU=2MY2|TSFiy|=!e zkE<;31o*ED6_4#_J8Pf6mCe}Of6n?QQ&LX2(eC6AER$p@$OLoy2=yk2c@GF-xtngrx z%RjGq;>p;X#uBoX$qvQwj5jvbHJOPa5>G#L+dU(DM9VhXUdDySz3YkAe;1`I+`=Ng zwDdaD2gjzVUAkA3NyRxWXZ5|L;jP|Kur%U1@_m_-!IhxfGLeBXO zB~|l$q?Y85f+RF=UOj5JhTu@g`nr-?8?i{zEeW&jz3vzucPjDbf4_llM&BT<0D{h= zl(%|t;^jRzn{Uhtg0R~u6G#qi-}x#ek&G1fzV-}WBHzd$;9?*#*w}TTfM;L%I59Xm zF_=9+tRg`@wXti;yRE`+l|y}*Dt$J3e#igzD$Ru!tW)(aS!X9B3e|d}goNAW{89b+ zJ1V_o*AB&LVN{Ese{(VfNu7{GBArj@zw({c;(VEW#Kh-1bI^jF&$diJLSvJpb%)vS zzcaIuKDZhN={KpBx*X*2cKa}R_zfP-BywtzZrfXH3 z2oGm3Z<{gd016RF@szWqTw#E0DJe76>%{Dx&_%ilS&URT6Jo%Ym6yk2mUAS#J2F!k z%A$3Z?>3B-sjYdF>o;4K2Ys77LkD%ujixinaXGNwe=#VQd`eZ8Uph0Oka9Ug_nuB` zCe~hKRFr59=@}f5jX=9vy2?{hThw-_4bZGJX+l*Qu{ekflEXOFBlTIEvBTWO6rW9f z6LTN@$nrVjsjR>|ugcu^u(8Tu>9324h8Kdq9B5h+M6jvJ=VX^}bq;k`72f|M(A^T|V!KwVdKkXw)jT+&;jDx7UA z*jf&yBfuP|9o|nV<5rUgW^TCYFG{&Te`I=bf4!JHOr;)-d>ERioy;TzhvOk%xhwgI zso6hYKA(=I5o>g3rQ5F+yIpyalG@|ZK6-k8DHl*H)u|fV%AKT0C#cU=%_F&shJ3-k zqNXz&#zRgwGFv_^aTxp^w!d~1>IGFb+gK=jHs*ORsI|)F|2iiKemEK^KyaFGusK>< zf6HD$P}o@Uq3fPnD7sc37Lr*xUpnBu`*ox*8C@?oMo!>f$<2OKAFU5xV2mL?A}xl= zuR6ZIGa4fxWmTzcdr>$i?EojQ3Qfb~>pF`g8N4`jYaM{|eKH^N{V2<9!mM8hdFVv~6SCZq%Sj8k>!6+qV6Njcwbu zt;V)(+vj`szSz(C6YFBlImbA4WAJ4Pxp->2^(EFEyhOV%8RGUaDMx)-GR+ooM#a%1 zb9wyb9r2H2pEF9c&ER-05$kIA`f*-68y5f`&y*!hOH=oTBLT@05?cDrUFW zn~MV~?Qf^z+z>tk)asDey(JwhIAjg{CxKvDSLzD`|9o+Z+JC_Y4M6h&#^4v2l8A$v zayj&uDI@4*aQ9NsBuF(`PG*C|Zi*uv$*6uwN{ejpYtiMug1;&gc|T&xBE%bR#XScf zBlv%t`(mkvta17NrQ5mN7ZW!$n^98qmdpCfj9**oeOSE0MzCe&S#2^6<|qXThji53REW|sP>EUAdD*|{7X$5IsEA+eAvPEdC#2`| zvJ)YnOM#9N;C#2I8Mh0duF4;F_T}02mIEe!yojFCCbC8jEVZTVM-Z^ga-$alb zXKpx^!cA?@t4_C=5y3^`QHlKZ&@W_v>AmWPi?0>ErLckBl-R!E{eIa+MLg`$ydxOz zkMR6F2|suJ9Sxu#)j2|k$cURR77#kd?MK2$SZZMBfeFfzpYtc2;)2g6B}m6{{OY9m z_^q$PP*WgyNZ=sC8c=l^IyAB`hBPFX9tByF-7V;Nq@LmG-uF6}%0Pr|BKSz{Wc2tL zDm?lWUUIbD(xke>G)wgtpU&Uq@{(a%H=>LRGW*2L(hB%cP%3af(klU0I=(P=%j%SH z^iiGi5?(kB%^G@>4htc;(-ZJ{5w^mI7v63^XX5Q43RZqnZ?;%;35&!^|5myDgA}~p z@K(jl==nPKFG3C>iOY>;-ti3k^*BtXQ1>)DRgWvYRF9gi%7oXnA2t_$T~$1p0QuPp zr9pV;d<1xEHR{aMsh(rztWOhT=7t3&6`Q9nI#uEru1+Zk_7KbI=j}Wa-n4N+lh};v zq6_6eTb=uv($!+ReYph3t_7jy;bVaHz_X6V@(*ERoLp#kh; z?Z@h{qOUto^z6iOj- zp9C&^dG^Har0)on+rFb{G}WfFwZJuDmCg8w?Gb zO<>>*vQ7@Aoa(t&k-6|GYG{iF7t;r$nPvmC$%j?)&p;4RG>cAr1s zdfiejfr&K3+3W}9%?yEtXDm;uYB;5@lJO^y9x|U9<4wwYUM7B^GY(#8)Y(0YiyqM0 z3by3cmZjt~o4;$b+O48@|(kihu96xfpwy@{Hgk8H2V$eRa8!Ug>o zI@WIJ4CmIo@Tu-R3>BS*8CfBl@Q&q_A~XQyp0f8^&z58Mw|msuxXk)0dz*QkmWw-@ zzO9qSVavAhp!i3Br_Jo&vfb*9=px|14=)}qW#iF*&2s9)Ju}$OZs`eQ3EQ+uQc8;l zBcUy_hoa^t{x6);jT)I!YB^iwvhETk-INR$VNXd(Odr%ZpBtiLZku=U{6?>%MK>oU zPa~7{)&TmHc|&!?JC)Ci;azb%QRhmrVCUkL4l9<7k#M!9?KvqM*dCfJDOKR$<&VfF z_rRQMS5Aia+9Ann7^B{I^NXNyr?-V{gP*xfwj-9B!1Y+_=e;i0LRs?X>iUG-6R3dg zQ9CvQD~&fNLyHDQQ``O`h0ri{LL!~A_v1!+rvFOlU&uPSOQxHy13S5eM9^Q36zy2j zTw8?REX6LJI#t%3Vr1xrRbv3w+wwy=$NfNl47&(7S+qzjLbO=ie!_LIvm|m!$_JIo z&wuLP+Dm}W&`I{7r#9c%>6k#rShL)tGJ6Z#Ixc^SkuVtP?C;k$D7z<2!>kzfD!~vO zYUg1|39R{h>AQvZnmay8{0PGk2QPjb} z@A(9JrY2YLDMkG_sx{wg4nR7+96FA1Z+*$GuC<>d>eXENRU|s`3)3x=I<*2{ z%OfZZ_Z=>EpJ@4rX1~*kUP^J4HOL&A#=kpm>Zc6VmOli~2mH+&w5{kmLYs-2MmIdW z7-ZpNVJsyGAk%1yEdr>wv9ehc$p~lRAVCd##PjBjBB^k$yn|TqgMLQ79C>u~fJI~2 z^@w4ey=rroC+eVia&_IKR*xT$qyPCh`8?DJrSvH`ElF8XkCccCcSY^-fR)wl;n39d zd*_Olj#mtKqB=_|>VA*D9jg>X_lNb)Sp}~NwoT{0sVuqU;{tM^L>+&Y8PV?w$QEGm z2iBxf%F)McdC#6#ssX-x{0V3}Cql(5%7(8)P`XE7)wz!-M|af5zY1V!yhcn`K6o*o zJVGLNEyDh0X*va4pKEOGPWV4M>)m-k4+M4!E}R^np?ap#(ZZ{Ib#m;Ydr&+q^AX`e zACzFsSjK=){{Z+g7n0P*AkEjI?-o*CSp+$p^$E@4*Yj!suZ z_4m7}w_RJ5Tf#VpAvha&wus5BK-??gkMw*rGI38nq&ocM4{uOD9x1%uMoZ*gOg2ka zghoeT<$jyZeju|VTgE7Iqn@zj8-GAfII*3+{q`MRs{`7MR{TFNkDG{UM@jG=ZSLT; z|M=1tg_<(w*zx}-1)Cd@ThST7^hJ;}T~l?;Z^`Zml#Bn@)}iA*Ym>#SI?Uw*mtYyq zHa@RjMyEGJ8o2Ss5YXNqiD8u8bA-%c9EQV$?2?F+&u#u6u(rBp;6?a9J<5Rw0!i}` zY?S0~FdU#60hzKKpvl-b$qRjc`YJj}NL*?*bpB4|zZJa#ajCjcot>YYEnA;rP}u^# z(xTpmWrcLJ<>jT_7+(9DYx*jpk3kW&NoX`DE@&F7odc#6*NnF~Ht#2YTj-Q3?$$ID zL)nmYuCuisK9@46$JaFz-(h9`=a<~oO!?3*v@4K1j4Xs>%s8H=xHd|2r8?T~@KYN4 z;J#M#b4}Puf_er&{wDPkkH#UR?wI*ZXc1OJ+8eTy$wH@Fbs{LLY~rk32R+rz+v5Y? zL+&()sTwB+S{d~?MAesZiG?N11Z9x;O8-UkOA0Gtytx=G{9HKx*h_}2B1HMq){Z7| z#tvBKcQGkTxy1n@g7b$p z-wU_X*wtDv7I~rsv~h&pAUff42L_qJJR7k8WWK@6-x@hk9h`9-a*WQ;r-|7f@gBMY zI$ZJuCwEzYKik;W%cPY!^gN%zIhtpW?kBRfcaZ6Uj@>LuWnANJJALssYJ9U`s{8JK zJ#;{*I1Ca^M4e`KCskl^2>G^XjGkjSSwnzpW3JJeXBj2+HgaLZ|Nx--aq)!Ns2v_K>Q)dXhq3QD1T6 zw8NhBGFMdGN_vvfjJof;5YL?O-FM~Xty;l4+I!1?1EB<}pSF*h8r!ARU(70!BL~x5 zBR+JOCuW-B9MJ02Xxh7{v%;rtHN+Nu-k75j5SX{w*T=R>ju?{@{2L)W$v~t5o8i60 zc&-iy!s7siTF2HbJr4dkPef(gs#ijXJC0$D;~Sl{8>s>PyISGSxkXODnviMV*lSnY z8+$;Q73f_Cnmi}u%3^0J14 z*i|FR`&`GX;^IOM`gD^)7r@K_w_4RWWMPX6VQ>jL-Vu#>rKuTf;^%uF0$h~>Gn7(H zi<02haKQY3d`O*HiftR9kmccpk>e5ylctK~rGK}|tWv>HWX5S64VGM%Tavc-xbQII z?MOkXBT7VV`PR{?Hll1c?hbDtUBF2_K&vOxh_R1kYC*iE;_O0{9hl62iwagVn384* z7p(7YIZJ6E(8W!Zylox_g(I^A3~Q*?*#f~g#dFhdpeC~+>;#l@Q|DfIW-Txn6%CXfwJv8ZpgyDqeJ1Dm+#R#TM!p@sZW^$0fHjVV-FFelXE z9}eLV3jKL%wDa|<1t515%q=cE?P-WKVPy&hel(*pTAsIPFX;1vsWm^>8+2QdGtP})eqfzv(j-NJ)A41ZSq+JAlj5D)bYahTE~eGpARzx>8=azIY?{#TT&I_flH z)ARPp0@P@t9nf`e*sW_#9>*Q=7t_Gpo6RU-e6vZy()5rkng{#n?sLrNd~M8gT71T1f2xt1MMwRF_@fe$kns zN=)ZRvkD~GYN zKG!zce7JbXDzv3j@@L%E4yFuRx|CHA7cWlG@lZ$RA4SKL!$pv9(YqL)D_kgT%&r$u z$%F-(KFbdMJ5e4Pc=f|`NT4@=X3vX`jxMSV$}!5m$cC=p+OVad!|aMR&y0`hD;NLa zk#y|q`1vtdRBB0gTB`<}?zmhCR_rjp(m;4t1B*>%wKit&)V@b-1w!QV49G_eM(ib=*yZ-|S z8Q3-s$NiRY!v#zC+%n?snk5`J&%}#T+~Zcf(1zC@zey>`tAoLJU08lMq%F4YsxDEO zL%b(BSjMUC@6SKmvnElJhR6G%_HIk*4PZNTK_e8|UYhmsiw(Sc%Xs>Ji6jUzv#w(& zDwXmC6?VIUX3OUe6P)<`srBo0K4kBHceb=x;Fvjq{kePLfsU2u3W{*{{EF&K@@V3E zc2e(PS`MlhXF8Lpn$=R`^p*Ac#7MR&dWt6I)Wl4$QzvgG=^rsy2-;M0#6w{^2?R%7 zBg9T}aRI(?IIk8r4xYcJWDV~&XRkb1OfUOwpHO9-mk6T9VvFqhf`;5h9aF4>+EGO^ zJuzPRF7&%@;9@Z`;4U!pm++58@CtD`Ib&CUvYt4VWN8AD>m+|WOs|vo50hyN}$BOCf!gP9dWP%)R%XR*Tfoe z1mY6CL!&pOMtNMClq>~`uU+~Mn=SB7cI`S&dGm?mb1|}&eFCj4=R55W4MTQs5+Wje z-19LK68N9dzQZ0-{Jq0OwF5gCEHc$H)?+EJU$3TT#V@spXrmQW)_l|1|NYPdo<}&Os(cDj`4D0Ijcu1~-Q`a-vPOjVwK%9U&hpFpp+8~P z)qEgJ`L7+!(D$oN7=GvD zHnUT{{d7?PO$rzke^Z)w9_Un=niT6udsVzI*gQ-wXMHL>kCCt%O5<6)$H%W0R|)OL zV+_}H^L!cAT$=}A*J>ljCp)e{mKee8iJ-@g$1?x!Cp_;+wH`^;b$TgLaOR%TOze}J z;f0MmN-=z|R@VLH5!UXQ>Q{(i?^~7s3vKaH{^vc9h$a!vN+FL*Y(}i-aU&7tdqm3O zj$NT_%u4ey0Ai#lnObymV$Zl_?5<_V9h3sIYJGl!Lrn{q>ZjdA)>}Ul_g!o6YTdK= z4^3X(YJYjEw=0I|+aLRGT6BbZ;Pqz04^^Zu4{17K1Gnr4x6YN!m&pS z`|LWhB=9jc3#wmy8op2cEL~fbrih@Zg|?Kl5XOgq%b8$au=w76MItFx#ILP!KhHBz z$5HO?cV&9ZkkWOJ-yU;pVZHhmwAI};Xxqi_8yR~=QO`XW;|xsQT&f0mD>YQYakGcO z8*Iwd*~KO8P;EVX6-^2s4xT0)wgJV)RB*mva?*Vn(cJVJKWCp5%TI|JS<`SI_ zFkKj+#SB_qIzW}rJERDiJqCi|-mN6{PAs(jU?s-=<#~#wZOT(n#3O&Pos*pNiu2E^ zj;>-l_l0ImPo~86Jo)?K_zxy2Fs7>3PX5jN7wyLjhlrp+Ftjr<$EAg^IC} z)2$X&goE4(S%m-t7v02}5{f+4E2YZMSB8>k~n;Y;Q@ujijrZ@uyfR#BmrRCrPm(Q9@F17k3LpQo=0sp zUC%Dptxp4^)m0<(R#A-s)Fi0pzJEYt$pv(UrqvNZz+mD11O&-5Gl4hzMzRa~)S!8g zzmCCVsPW&s#4!PXW^klI1BPELh*3dU*~R>F83g2&73HPTAi!Y!1<<}7h4aZl;ZWRK zSp|eZa{mhVYD;h&#!cx`wN?@0IZgKHf^NtY`Q-)$t#obgf@o0Uz##<_gW#bw5>CK6 zkzwq?%m@kYGBhspQvt0%R`O=2;stU;LP9_WM^!+=>XVMzpl|#NElovrYrx*r* zm_70%J%a#`P{dTkFYKFovpu0Zq1$~ZR2ZiR2!GuBP@6&UTLChJ+@iwYeow;N-~uR1 zJp?4t)#B1TgM?siLFxtszGg_ERHJ7g#HnE4zos$61Go!xAhma+dn6&g^81`MPz~r} zoE-y5W~#}1?v(rr^yQ`3yZiu(b3Xx3V(%}mm0r{(ww~}>S0^Yw(O#Vm{c<>Q0CK)+ z6gM1@D96Cp*N>9j97?o5fBaYp!lBgrtaoAJfd(V})X5xX(-*2%%3h41*=%Bvhx6y> z3{FwqCGntw<(^Go8oSh*+)BT)_qk-R$Hvi7T+R;}=pn}Gr3b}=fPph0GTajc=>g`< zg?4}<&^NcrU;R+9u`da9#WLSxE1&eB_TNneJbr+q1u0{BFlg&Hog*^}4#W@-#P_t~ zH{sp4(hGg^x6HwJR&0Dm!M+{yv)%i*(O-@}!mcmJ-q0n)C=C!qa#KW|FW-FaRejQ+Zb1U zqqmJEjREtZ$2Q^nhmc_#SuOH6kfERY_@`@90%)6eJe}ENnOkgn{)9)H;?bUe5@?#D)fm^8M2z*WV99{1^Q6*320gz*)eY z$7!tqH&u28_IuEv1P$z^%Tw!ZX1)zjKGtvKen}Gwq>^1MUwuVM=sVUr2$TM|J&BEd zf&ZigrPzXvws-nO{3yVbXUBjOde^E;<@-GUcz*{E^ytqeS3(y*`ILW8pE}lX`^>9H&G=l;f;7eoemf>FVLteruIY{Si&1!|xj%O!d#3yRgH4xH z8Wl65cCGqHc*Fng?EBG&HEbDW+(?Kf6{DHAA-7=AW?>O-=E=Tlzh{=J-f{DG-jqMC zy6l1;X5)vRdw>t=g@?{1%U0upPdN;vW*Nb5T3L&t0`Mm3yTvtc?k8xJP(%R5GQqh0 zRg)oJ&MG(ia>D#((r<6&o6-WsM$*i1|23^B-WvK-GH@BgXw5(xtQ3Nm3~vp~ew)9B zCHB=G+9l}@e@soIUu2LX=i*mt%!_A|DygQTMKNrtWVM9@Y`YR zJLWnHDV>vgI(!P51~?^Pc+X_Y9J8t$3>s_NiFW;+P!n@T!qR$Jy>g$F&fYz((t5aS zAw-T^qG(7&ZdtAiq&VOKO{4~bCf5J1z9hNTVJyp}uw-kOniGgTxr8R){wYhYEY7;e zlCC_%453~JbG&_ir;TkOt#HW*?3(^(m{jqA^{2s94Xbx`f0yhh#W2_-0YDzh@X?Ke z{*dKdnA*EmovBh`ODo$n{jr?lAHKp`=(&&u=7Q$z4%*^*?B@_fWETUZk|v1}F>IA> zPk^UKn}mB?{Azl(y>-RdUX|ZJ7a-%u5=rifT0XzX z8MV9x!#=e#(*xjKZ%d`ep8j@hY*AUDtmQE7kwj;%oS5k9h%`8>(BpkC_MP*Qxs`<# zZ}_sB9a2OL#lH91wqN{PlW7u zmsPM!xHaP~pCFth+EBA*loEFP{N7H{kx-LNZJq^5zrewjZ2uyLu8erpBGStE@Yoi& zOPqw2Tyn8&>;=D>ZNE|u8amEoB@_1@!)Li=P3@nK1a|PD_n0!0d+0_$Kxp#L+0tax zoth*qrpq)YJ{kl4=yyctPUP3R@ z^ltPZ7i|#FWbh_Y=j3Clt<u0K>-{LdEuZgkP|nOt+VfwWxN$Q5?w77z9ki%6?dyBoLs4>mkJz{qY&KE+ z;cF(>{gf>9Ujai4*q12{m7+NsFV(#!)}m~jN-F>j#E5DSJLlVXfrJs=hJV-&9>?BqBq6`(h%2U^uub9QlP%IT7x|-<{a0 z?2lgd&7`gpe47|00=*S{^hb8`2kAN6&EBYqdAdfx~o7jWxfY1^0far8);qrI}Xv*v@(k3J_$BRAm3wZ6i?S zR{eK_f}xhQBy_)T={cM{(^4W?wx$T2Rtx~XzZU0N@*+28FN#N7uR;UExo53EE8B9| zc&plJg(3rq(0bkyLj>LqqGD!UYXqk@0GvMb@&N)4M=x8IKG@qLnCr0;+Rxs3)eV=f zv~dw~A2T|sf^G3e!MdC*CWS)?>BiBY(1-88doO;qPJjLmtK(8s3y@wv2;K^?ya)xX z$*FY{;3oOxf?}4t;uh0s-&XN69?@`XGU8JkMsyRSYQ2oNO z*x4n}wggA_?saZ7`sgu2ea2Tcce}ai)YUDmIGw(4r)t&Qh?F9hso>OV;?S zO^1>fLde)pxUioey22e)b6W)Zl624Yzu-b}e%BAscj{>U@HtNgSG_Zz*I@-1pCRUs z><9Sxe&Li~^i1IBOE3%GzvJ3l!?2fnValv0dlNDL;u*2QEkI4nz!9XbNgI~Ft|55G zCwhubU^Il+;y=lCC(M(FDG|!xg{}G3{e)}*o_r`q`IItvz4?!R6b>c8{uuoVA4Z1V z3eCR=Q+A<8YyPp##3DR+SK;Qk&oVvW-<9{q>64a&Az>DOu#+=h zCZ0|8Y9x@nwc??56uM{;~11Em1zZvIY1!BV* z*IzpV#gh~g((`B!oqs`qaQZ@9{6{!bAJnIx6cRz7t^AXkiMO?CI(mdn!fm5hg-ekx ztgYFkgjP%sX3RJZH3ksXIt$@4_!PD9KryA1vtkfcXLeX~nR;WMpu1e(>C-}U*L>fm z%x6KcIA&Rp!v5Y+cf4XeM>v5m9%6^|#;^*?{MGe2(z1671I7o;&U7e@MVP7=EwTKr zyX1cADGA9m*capIF)Agu(~_n%F{ojT;hQXl`U+y_vTkeSm+isQq$Bd|es8XtKeU;y z`ZtDih~1YqR;3U30bL(evYt?0!;*FMiD;!706!skqR`%=VVu*`t;tMTLdX6dmTH9- zpiu8b_-MTmzEKUt>=Cd9(y-`25seT$`HVl|3OQ5`5pGtdhK+(ki;O+USTmI4mXH}o z*qelA-}!g7!kinX+$ak}ZabhbcwrA}gLM5Q#Cz?TRZEx;mt4mIQ&tOp==Ctjr<+*z zI6#{8537K)7R%Rzt1mQH2oGR7k-OAN$epJ=gHT`>ajXM8s9&npok@*do|*-u1zWqB zEpBC`>CY!sETWPF%yg@OXp)TS-Ji0jo&hBtC@SU?VM-;iUyTGL?aWWcB~61Am@PbD zCSyC5C8Qi3lk6+}g4R2lufJ*=PChk;psJ8+$Kj6%n21K%p%~I+Kt}wf@vs8r2C;Mq zVI<9KeINjVh zyZ6+Iy+P1jdKrRz+`U=JuVyAW^T8gSm(0xeRUhE?;JRv2I5CA>Xmg%FrM(B`I}L<#j0bOy zqJ~fV`;h~LMXE?I?gYkOu$u}|@9Wl>Uq)*JjFfAuuC^f?y!kk)yxB#YxMiViQx;p> z=YcwgNF~n7kSep~?nDLk1Z5=q7z@W;H30<142-RBO>UhZt#>{rMZ;!1OT9;CqH@2f zEtSPA!<#Z2!uzgsgmhy=#%-KjfjIZuf*J4eAfN1`@dqEjcaz=*9?8z~Troycgf-b9 z)dG%z#!Tj)I(!g3w1d?yr{lk)eo$gDo+04Cd z2lr58nv9H+PFBIW*1LJ=OuSTztnm<5}Gl!dZ85Ba}61PWpgbb z>CDZ;(~OH^<95PeG}!JpJ!dDt1Hg`(OS$`O-(q(2^#-sTvQ|0)CX%)=k|1!PAPPSOiMmD?caZ7lw{PZ8FhY2y3Wp7VF%1^j|t_wD#(#~ z#C}-w(#hbD6L5JZ>)yPV@8#L3*m|n*3Hh2vZB0+u9QOMr15pdY56e*vdRs?m`bY+h zPp?M-a4mLa1aUdtfqRxl+CaAg-jgh0Tb1V2LS=586PWSL4Z}Vl6~GI?solxCKN!q{ zf%#{9hoq)=nIlF$$4?`s}GKR-DuxQFycqZ zoy}*-me9!zYw(iqO6XK8(e}?Gv(JxO7+U>E8#<%v7MwF7is1!qkR?uL&jxwS`(T@< z{I6bh`G)NIlBp{3h0O$ruRm=ms{leRE2Yfs#@AHreg_flxR8_Sy&~s`ycES;=4X23nR4=TY9y zZR-ez4t>$E6w|DtF%czJL&hR}CzMvl9BPLL76{3_OFnu@OAb_pXp6+3)2_~1kdY;HG_R!{>T$^SkcP;qPS0gia=NEzDg+JQjkfp6|>X_V!;=KrNox|NA z2#KB6OsT=cO4eIFTvgnyi`e*HXuW@UBy5}iE;yEBZ28$_b6n2C zn$Es6I}tP057Q8XQ~{>aQF0(f8!aN*x3H+By2s9^ad zJaax-NJ)8#%yct%n3D8SNvFM_kS}=j!g?UHzvajr@W%6BU}E?3Z$<6G zFt`@)MZH!jy~I5ci&L2qJ5D3^pxDQ#i&yU?@=ZBy!!{~zyhbYP2IzLaNNY>61ynso zX4JUDhB4g4WA9k?M!Ebhhd2TlY$MurNT4AcTG6cFK$Tlb#+1l?ago(Vv~Vk4wyPc= z1mc31OY^wv8PQx#tHP#d>8!zW6i0Bam>Af*4H}ESI-si^)4(YPQ=W|Tc@2a1ow>3< z9$6nLJZeqG)E0jOzw(9N#j*hV*J|WM>kD;0^^96px+CUJM-Jc1yBqRYKhWL80gQRy zzd15yw6$A7Cy*TUYodqL(>U4@u8VmuX%pHhArir5hk>d>5qgT@=8*TRioMwBP@V)? zCDWW5L;ITcPEkm#N^yto2e-IN+OX{eP5cVGzFFca(LG3Ehe~cB8Wg&Nkts!MVzmFly(t*XzbcT%g0sr(R6AIef z+cgGl=ogMc5ZC{#EGQaywJqX|P-f3*33?n3anbEDw^g=BGU`3Ycwtl?Mu|53cgx$G zl{=xwN+X`I!l2;PV93B^ZAdFPn--m^#?1s%6LRVSmbAWTE=n^9MpuvNF+KwxutHQX z0;A23L2*NIYOmwA#~05gV6{Bh8CAKyfK%bxII~n6JH+e$48_ik+4UMrjA!lo29zcY z?hBH*-Z-|mqECHIl=yOoOk~a=?P}z(*73~E`pIO_m)_!q3awG^#~KYB22}Dwax}p1 zIet^wIj#B;$Ml%MD^KS&193OlG01R0Srgi3#yu{3JnnLV+%&ijDD}&R(B(s#fh_#} zydUw5a9yIXwO(i$eV#ARu>TE$Nj zk~Hq6&$N3!vq_ko=$h;>EShIlGlC+;b|dK;OEIJu0jqsK#Wfyyoc*Vew5(HcFqekj$dMy^gO_Y(3OgE?wce3;XJN{-hjw8BW-<(^NOl z#VjU)La42#>D`%$(=^|5(pz{b|BBuVGdL zB}vT|qtf=qEj{H$G;mtcgT5y+LmR{uoIGB8VHiuec?DiroUv zoqTwt%~WP~?-TA6H;yZj2ZQ!V;r(uTU7)tQ>5t5(znJj!f`y2wk4v?91oe5vQ1Kws zmD;~PkErSnL~;&L=8lv%8oPzMj_mz{?`bRi+wEJY2t_pZDA^t`>Vz}6t2~C93dz?! zDuzpO2%m&=e|Z?;*rCSuX8Fd(o?(np<-R1d_#c&si|c9%{%ZJj58jpCED)?F*B7Kt zap0x<48=hYLi+?)NwHu(wjWcx6}u!w;4wRGV)4uk*iPeVZw+$e@CYkmXA97WC4@cP zbjeWA*M$P3(NzB!C!>aRN;5|BX_kbr0EJ7^0JCQwp+-My(f;lo<>w~>oY(8aGsfCd z234oWj8iLO9n8#or77yD!v7FNEyT1ssWBa&V-*e&Je8KLvoO4day3152mCt%8%$=g z>;2~dz-GYrjrL8<9&KmcNRtgL4VHcjUs57uyUM)!<9~~GT-g|CL9~DDu{r_x;Q!{0 zN5Z~d-u%0Fqo{xC*<&5<*}6G1)NlxJip-2X_jbQ#q??J#GbZzUGHb>I zpYs{i!x-LC2?_??1ufVl86#0l{q@7r+fQa(Cex@I(8o%`T{8dCe$OUrF%^}S=iS>E zv5K{Dz+W0>JOha`k(k=OOdhm!WH|+8A0{K-sm**3|G<4MmKo{L8>}blO#Zvh>D0yp z(p=J(f8o|qy4n`is}XB$*>4)9yNw%4-FbmVcgR*Jy*=cKJm(OX1Dd*o472;UwQkmsHyN{bTuh_!bfAKg>iG}M+y~#gT(vu&o}eA`H-%)0S^gBCQ+=@ z=^xoc&28%xZxy)g7WPBK+y61iKHzYM=h_N*RKJXWH%am+fJQxR`9xul%5Xn;PXwDj z{o;lc=PKsy$7t)MI3{dXwr=VG1T#&Dxy!~JB*>09(HG{Hj#K)&-|ErSguKZ8Qq1%W zJ*vH3(oL8$#YU9`uBuJ__N4A^2um8g;M`*C#xGAFS)V_`sk_OcQjfcsO@E3z{yJ)j z*_i7>s*w!SwQhMEdqL4_+A%1gfOg`VFWkBDzFNl`vP)T5+3gqeq<)D8(j(l<`$+_5 z+RoslH3KvAB(@zlePQzmYUoGszYsLkNa{SY1#T0o4Hp+wgrge1|IjU}?q z3sfzI9ILs5g%?@YA9KYxAzoQ4Mr9b*&fT0MvHA|K-aq3;`#{s_?p8V8iW}6CAVPND zm(rf+$&uV@Zz;~<_w6guM&YuwTg$byym^7}Z{&`lznT9N*&_!07uhp2v;1FV&&0^U z{J)Vs(|_Up{~y^a!Ez|Szf-o%g<@^~hAqj5X<)>W(g-QLAR!%|z;#MzG@HomGp4St zkUuS^wQ!&bMkz|fCs`GQ%gb+1wx&z2Zu*EWYTx|+_VDd7%RZiX_Sv590CX1-pJX+Q z5mulJd$oll{D$yB*kn!F00{Xywac?;e%i`f`o#u==&2gU}NYjPa0&0BEQz7 zfbXoM%NJCDLojK`IZY8VJc7TXWDP@Fo5R3A2rp*Xbl z^@)>@D0}<8w{6bS1&D)cLB!-i?!X10{?lyfOWlKGYYrGH`)|^UGuYV&q=^$pA%m3$ zfY1J^25~`k#3lYA&;TyGpyNk~d@vR0HVMw+AG`|!LA$Hf3VFRMfZ{flCR#G!%Y&x| z;ot*GF$fCEJ@%Ux4G1y^WBF}_CB6@%zmS6^5Xiyu1A{@03o$p93xuU{AovTynQu@C zLLGE4?Glw8ABwQyXNm#R`>VgUuwPo$G}vCCv-1_{M!(~#Hb*S}hl-(~Hk4B{;@{X1 zrz62H!C1>WzdtIe*IaripyKW}U>Z3veqSIs!e+as=oeVGy#Obffojwf3f@GZ2MD?i zI6`nL@mmNi)(n^c$S!=}%npF(o5%nG*6ViyvjhGns6Fv~Qi^9hHGcB-Dvwf&9WxgL zvSS8p>t<68;4q|+y&>gjF;0yR`64f>8s#0@i83>Dz`!h##(~fgl8!0a5Zd@f@(BWw zMsk5zXD=c2K+<>+XxFRbET<10r@lY9B|LOK(g)5smS`G0nB{iZl|SX~=}E{9|GdxC z;kVJNb>g?=1E41S->A{awaKIRyKer2INF@Zfcn7i0|3|Vdkt&?#f_c0-d6o3C}j7a zQ+@oEjZa*_KS1CwZ_td!JxkhrAk{nY&~z|oFno~)ph&cXL`|23F}Nqf3p*S1K|EyR z=+6)!f)XUdla<2vqLb$RH_b9KRm(3y-mx}QaY7r@%-m-Wi-fkna+*V?J{9Eq(UsX& zmH+6SbUcLt5h%b_e2FW~9=QRK-EFy7mkH*oy74NAwHtDnD$g~IEAs7B2?e#y4u(Dz zt*Fie@x|FIVapZJp{LA{7ra)t7d|zD@kWSC&4=4s6Az~g2o~x#Je^!NwfFLNVe@!+;LMM_4dOjV%OLFH={bK!-vPF6#8&l zCSI*XqhzzS6=i7^RD_I$o(Q$V2N`mHZ((xaQ{|RNNr}KSp>k%MesZ1Dvl-A*v`f2c z&)Py1D6mvZE819qZ3>t7S!_Z+y?MwcP--9T6W9VmL^AVLKRQqJL|{5rxX}N^IZ3xJ@kx$zd$w5W zSl(Td%qgpG6OL-FFt{DcDQxBlR$o;!@+;5!z80XBHT2S^uJhxX`(>>er5>E9(yMT} zoP?F-b9)zwiv}-HQCJu!+8b@WovivT_(WqN8Pssp`HP2flNQAK`n_gz-ZG^{%@J9$tinxAbAyU*fz{)$LwT zp7RziJs=VU2+`Eot}(#RVK(2`i5z{HF5 zY@zMO>sP0y<`k`M0B;LB62sj7R+M@rrJiDJX6f;}-Hg@I08471e%C$tT{UWd-&yTU zD^$sx{kYUN-)4b3N=6zzE2t5_4o&4#8FpVqSBlAvZ${DV)-QJYrelBfErH`z#c@@N~eKa-@b6dP?uK!nL9G@l7nlbgx|?z zc9v{n=c)Qcd0?{XC``BNU7~lDfN^&^41&C+Ze{0bcpKHuahk_Z&Kq*FYDW5H+gW$u zA)Q_sn5)lYF7sIPpYC{=>548zj5z7L| zFbxd0I)do2`+7YkLc;0wr3GHMh$VGgF-|!mRibF!vkP8M9n(+Zns(c;Wxv9&cNoAZ zp*55>IiS{_;&Ndr?w(i8DDmER_JRa^i2AYSOf>>+wWDw;+^*5_wN~{wz^?iT4qquV z{z!Vn;t?Nc!wSSwI4;aI>8*8w=1fcPGr(RNx9r+COAuN;Vk;iI%R38U=gufgFN}>O zR8bKgf~%Jwo`{ASE~Gg;n)cnoZ|xIak2pG?uXjdzDN&ZBeweTSe*k1ao4aK5isW2_4f(?$c3s63G>%_^)q$EX4idEo&N*l`y+sWR~jDKS78lv~bx*utLhPQs{ z=-MzHt?F60)~aDF<(bCQZEjm-N^MOP$OBqIZ9yw56<3tJIdwfzzqKPSSyMT1lhOHT zufs{NrqZZ0SCvAHMcRrL$?nmRaYajrg+XSh6LY+f z`Z{OR$-bCt7Jqm2qjV2XAnHf^YS{W6J`Nt z&*bP%|GY?HpW3#ccDx>rS8j?QXyQrgTL`tCKeL)zJ;&J&>3A8+?$j!chc)+k*0z2A zEUk_ckf5^N0pjGDB<$!LT42|vSZg$-A2SEwS?#0x_%+Zz%se_8Ct1yLS>07Vf z4z#RKKOLF*EWTxEn%coP9}ll*E=iJkJt~`4Gwk}_@_>5Et^WWwdDQEZG5!;m47~v> zmpFm}4g)hXIG2H10Th2RH8D3cAU-|{b98cLVQmU{oUOWJaOH2eCYmzncnSN-nAYprYDtLm=Wq=X8}w1URAhCne} z8z)*uItDI)oVm53v!jx&wVW-d46Q8C*c|XBXN4gp6?Om`IGKOj+K3o90l5I`Kx2Ri z&lG>I{?dH~Q?PY(ax`)< zw{rq~WmOOn`!`M}GXtl8ayy!TsR6boUzWzUM$Z3~^e=ziSC}uYlYzO7Bftsh=JZc4 zLmyV^MAo`b~Lv!{Z9lm00*F{frGIX(9!WL%vbDxy7QlP0{*w^ z4eac!-2dfm`!B2ig~8m(5ol#X2gAtpmD9-SE4Qh+4GjH1vm$9@Vhdno__y5H+3r7d zE9!(EI;J z?tkUzf4jv0ulM=Ch8Ak}cD@a6|%K5{;xVoCxfq+2-=u_(ZWE-@Na*ixucl58_-z6+{wrcU}9kP)vtfa zRc(xc4p!ziz%O3^)lvX0BLl;K(W#i38(G@?Ljdc)RX`i#{|f($s(*o}m(q}uR#l_^ zKP=aO87h1Yfs=~6-50k1S&FQ!@&7vf6GlkL)(zlE%gDw7pk-!Z{JMKzfH>J0y#Eg= z{}q3T@juV922KvJz7BhEvQbfDIml1S0*sioerKrHK z+P23xEo_IgQva!Zzm>D2ChUy6U~V6+#*io7QUc#)6mO-$KWfV@f8!A^Y; zK(AK{pMItu<$1X%vkj)j#-MiaXHro~ujCB^Z@Poo0qXLR(vR4szz>b&!4AR4D78Ko zy%VVs1f{m{^o%U=`0;^!aBO6FsOK8IZy$#`Cl;EN+W^xi`IIop$z9*!uEFR7{KbET z-3~-`%-K#$YE76f-ngkfL)N5flgc-fet^14gYM5#P4&aAwQRClfNqqK^+Sn>qI1ph ze4V&GSj*tx5*|oHTn1q|_={>>?_+e66Ikfj;RDPpI|D0yEw~i(ui93MaMNDY@DmVP z0Izt~;xi^14!;FJSVAoyW$u};c5YBTj%?yv#EB{eMLx}Za zjS3#9Yl3Le#*P(dtSNHe(6k&bnLN&Q4~na;QNxim&^#0ffjjQ_1j;dun5rE^F3i#5 z2cp8atz0hJ>e=IU3ut#3%xUxWWwi8ztrU$r(_gfkpS(DqD}mT_6VKmp7mI)AWT?*x zKEx1(ft5@FKkpe{MS1ZmY~dB{Ca5?~H&_AM98f5UdiK&S5VM?3eV7BA7&+hmn3ENb zq^9Mar>33YFVgj)i`P>*y~?u4n=hjz=N)aR1i1S<^JaG84#`J2;gs6X&Tlo!J3!%O zMf^Rqr0e7sX!T8^|4JvG5>fEb@apnyyk!@~6JeyuE7jJ;cjHU*HBEM**Z$T(;wB zhY1{XzfI31-`b+h@$2>ji0+40%w2qwS5{ojwh6m9tlz{=CA~<|5PyGt=E-%W8CCGl z50jozdb`wL?3sY+qT7s=RO(f(Y03Aq*RkT&Z0-)${r> zXVKf;5aV-J2Z9aaDE0AD&dZox6D)9e`Kf9h9@l@62(>W?5e>=^itCq?D z`k89xBsE=nU<+H$*9*DocjX4&9eILsA6jO(hO4k&*VIwtCO!?)7A4C?Y--v}jZV{N z*3cFQ266-rxIoBp^xI|X-{g^%w>vkQpfkc+^P9Vh_{8!>wse1#R%&?COxQj3!hw4xmgu>U(FGaij7Tt-xj)DFVGU2|3sd@(q(2g0)oAJzxj?4c#a#oZ!+c8h}jl5!wio7t}8^3)^G4Y zi#k~9`m-`QSMJzD>3cX_g{3Ws?&>~M1+EEuVYwEXqll76q zc8 z^_hPqcC21;!Dga+DYtA?2t^7_U$hVYajl+IXUzqPmo!*VS)$gz&cha*)61kvkMo3J z=J(*Si!=8g;ZN5Cl)6xgbfhVRVQEY_^=Y9EZLfV;AS#gX@SJ|Lzw5h);p zV!w89wuOJFA`UV<8(TT{a0$lHM_73K3 zRL3TsCszw)dyP(3@+0$4jwgqWygC^3RmNIJoX-7b2@Ar`ml!%RgC9abQ+?&Fo6@su zf?a>TP;SN_pipE%oeVir9#=Kjv>VB9f8g?G=jQXi_QTXHk?O?|;uPu*2+YSzl-%o1 z`E2fT;;%x}*rUaV?8*sqPgiR(9H6FG??C9CRArjW&2%T?02!Jvd&m^aOL*rUpT#0! zs4rZ1YA?w7YggduWG-F19^s@QdW&Qu{+)mQHyaersI^Ze$3qx~vZ=#o8)*WgZ9Ti_ zh0RV7w$(;;EJl*mwh3{D`M}og5ukie-<@O*WMLY9DNO%%^n%OdAj?E&S?C`B`m9h4 zleYpDc`F{`1SdKqE2ne&3a_v511d18m|OSfbiBcJ7^GKk3RfVf1u1NPxE@(-q6L2v zdJTy#w(M0znT@Ixjo-2nr6ilA2J-5bCK#GESVa3uAg1P7Dt%56J3-KkFTK8S;AjwnXEhE3^kSi;RhI#`)%wU?UI3wmKuh`7y=YD~BNM`waw z(e8|We%ru$_pg<@k%cOo|LEWLH>TqkS&N;1n}%2DDwl?|dMHIm9=QaBV+G1I&%@8i zJJ4q=?CZx4vJt%G+*rQUwk}Rr>`BJX{ZHK*{t!}LH7T|eeIjHQ%)+}LN>zUmAsIhN zYkt&B0LT^2a3pmgy({*8EMsfYq(bnO8@7iNW08`1GW{)drhy)0Cn_EU4JP4!w&UdN zYoW|YTspe*Cmzj~JNLP?<(|S9c>#ooytE5VrVt}T`G`r{sZV|D;50p$LOR~?k$A4* z)FH(i^oo3&OGeEZ^d94zK1qK}X_^L)O%a(@Q(b5vcy{{uZFau}F1_&Q3a)pxs1L)O zuQcLilFAvGsnkBd6B{G4<-roXwAkH)r~EqUr<7_$V&;lXl}ie!?`RP*yrs?Ep1g!f zh~n{8(>RaO775E#2wAaBu2nv}) z?1jL70`7l*1G(#dM2rQ0dnfEJW2AJC>>M{?qMwJL!$5vsW>9PFX|rJC z2!H;B`4%Gt&fWO>ZF=~p=2QAlZ%wC6<`)@|Jz|!&hNHv{X;Qne*z7CD(`9; zB~mD)1Nco8PPF&VPe@~`ylx_a448x(weiw`hL$3dnQ{9~bp0cIf&l|e+Mg+pSD~zuFy8}V za}b;RFJV!!ZBBo%+hI4T{2aog!u{O^QrT1xLW(T3yMi1^*}&!z+*5CTBPHegBRg3{ zu09y^OP{;&LMTzMYE10nesjqbMs~U-YP2EnMU-gcO%|m){ zLeUteOPi#PJoO`sX%p7Qbw|d^%lK0Fqcq<$3(9h~if%Hu_q zG$_R{RCyd&?N=*y69~gpuw;Xhc>2S5(#n8G0X2VIs;oO+n_O(WZ6HyUrSIzXg`X_v zhrb~|leXhT=CW>XoFTE6?AA%oavxj?0+@f!U_I($z=LMTDjFwo)=u?$F4$pJlBt_z z#FT1K!bsSNvx!-(M6)&8RgHKMaf5#JqOgKNk!B3Mp&{C@MxbR_!B`eAXvzMtCyLqP z>wJG1LF1u)z0cK6(uk~g(#NWp$WS3~1HrdguMCmE%)Q}u?O`@|27Q)y;s+5QDQTYI zq6-6T>-0F`zGUMTT5M~4?9nnXy+8tpfA=J0LcP46928b)pl%X#=)r(_H&x;xUrH5O zku$!yk8Zp`rCvdm5UJmhD|n{=NdunP2n~Of8~aFwi1NUn^dBs--)LkomBST8;{I-= z$7uyoDR(bbw+Av7No#{{3O?3CWrm|v(>I4I7Wwtb77I1gpp&JD&@Pjh2^Em<+Oca% zXu2+;bk%`}ERtCXKOKe}aTf?ACHikVJ0_>vwdjO_%IXs9TgglORbzE^m}#x%c3pq5 zjq0qGPA5Gg;ea_JIxh}Y+kc4*SMcHNOSmZ&kvC7L!8-r zwtHuF(tocC`=emwflyO07O{O)egc1t3&wzctj+FUT2h|ipAI>C zo2ce)zkw&~I_Fct+U0$zr82AF0C$EpA-A1G6q*uHHajml)!u+AdiQghggn9x$5$P{ z-35m!o08nj#I-x3=IVru=&RUZ}6caJZ%VsTn>ui>ONZIQogP zRo@8*t$?|_X-<4fKcPP{v zM&17os!(*TzWkmtYi0HG)vQDehK%uHp-RThvE9z$@233t_$92T0sUFHv&vHu>j+tj zoF!}OakXkgVzzP$j1}&^<`DYj?HRN^H!Qx%{JYYU)(@9r%!y;f;_uq0RI43R2M$P5 zny51BQ&i_vm>Xn2<-vdHyC#%~8LW-?3n4AZoDK^2E=XPQl`|sP0>cjsUq^|ol^9h_ zrc|xlCku}pcY@tutZURemKuxeCYiF`oY&26O6d7%O4b9+Ae|=E6;kGuf5@ej^ep1k zb)9H_=8r~~81n3CJ_46Z34=g|OgAFF_bTnT!hvy2ii~G%@1}p@Y%g5xnRg`OE3wC0 z8t4r9>97g5Y4&&w zd;etrwN+w|G!0F|m=c+oq_z_19h;%A|2ol188fk=XQ&Apt!!%RdW-XsfzZ(4p*-Yn zz=!46+9cs60iQTkO3-#RSp zm86U3HC`Y8Y(h3CO&{;QjZLf})^Yb-awRf3)95QPq=0`SCxWe6Epx0`*_fMoj`6l6 z$(lFiFi)24R8%>!xwn~iS})6Y_J)H|X@1)S?tGtCIn?BUb@szzKq%drqyxUf6)a6T z^E=8Gmm!FLFVI-ZF>}93V9n^JF@H>yG8uey?(m@0=2Io^U{IHi{?=b9VsDq1iN)c0 z%D#uVX_S9~6lCF6C_0Q6!;G??I5+DqIT<)2=tD{OnEtDF)UMj9-o(d(e3w+3>yoPj z%kTqpNLvt^Vm~x_4Bad4+1&F(;q}q=?s5rkngVPspwH_`dGnd-TJm8f&XC4N8YT%G z8kNRz^qHxH$4gZuOay8`xmZ~SX=6=Of>v0lW%GX!?&3l;rxJ@x>6X{7dHd?Yra!86 ztt#@xe0SfqJGH~5>wNZ3mFDjQPtX(iAlj30Ck3#zwVx!d#fmk(6a) zIpBZV5@=yQ%6zzwPOmy`EHxc;as@iayc>C03Z}Z#!B=m2PI+HanED>P#v4J-BvQ_} znQlPuoLppT`djSOlA+;bETL^fb+(KFafs9xJwol(hM&p@!d@<5@NhzC;B_W&vi1?N zgVvC4oj}_q^%s;!)uS!rFEDobQNGx+NRWToU!F+KKAm)?;k~BCrv+h46$_MA-l$4D z-~0zhblq5Fwbm``B)>^FA0KuwJT>e^3xV!xa6HsXCA|lhXPq-?g(1~baf#HOnfH25 zL<;NE^XO`rSE)}mQbnGF6|EOJ>G64LN&4B(Pu*inA0}IWv|jU?8Q0pu1$fQCSuKCg z1w>wA@4m_;ax^Mk`1`*psfRjo5T??W6>lT0P>zC`vG-)T8lKU53&XO zCVU{k0NNjQ&(NZ@QqsXh_hzq2Aas9KxK+MX;Py6jk{ZN^+n7uiATmXfnnxCtEslCqo1p$>QYPLYMy|HhU z(lPn=CLB2wPez+gV^)2bDx_rb37~Rppb+7?91Cxj0@Gl1j|O^5rRI*s$iuy7%@Q0^p;UUCsURo1XWpT?}aw8wSp&f;Vdop$efpF zU1EcuA$u4F3?T)@W)rge%;8gXBj+;rut+8 zoNlNaqVbl&6p1f(_dV*yO7D4GwHdF%xSovNmhs=zriY^s6zP`>j?`NfJh6dP*F7F# z>A5k7NPiN2*^L%N4)J2kd@z{=(z}y9OGxjdO*9r_4@D0xy8G-}|Gc-a6wRpFvLPxaSR3+NKwf2X zTXGNnUJ%`9E4;5d@Qi;Ti*7~V{^tx!ml(XCQw*@Rj?s2Yo`?DbwDfI%e)TiEj4Wlt z;ZYA_5oLZcI-2!>=dy3yhx&tN7Dr`j6v;;XSD}uas+!N=Fcj_j^JU<+u9x0Dt`5I{ zP``%g4;tgOYE{tu;9c?ys;nnt9-6@bnX4BRj8wX!@?B1m?7M#wO$;A4ZrKx=N5cfK zx5?EI8bZ}>$s{I8Bb*|s%}wcjZ$2RLTzeuHE?6?F-A;lEM}>wLx1BhrYqjTax4R0F zBACskNx;n7`&c(3tgBx_juc|=#zG2(xxOJ>&d#oaHaXg=fJajtFVE8~-tj*yS6-1{mq&juWpn3;v%FY)Tbm(9lm-Wb z(OJ^RqS|9IfPpf11+RQ}fE9rqxmW!tdZ(`{vgwvGb+i8lPXb~Ij<tm~RBlZ8nJ#+^iG{rYvejaibzq`DKyXY6FuU-q^+Fyq=#bYA?B6BOYGr#RU{lLlf<#4#{YzUiwlc*`N#9lnn+Y=<+OHhp^6W)=Mw9a3rI$qD;+_rrV^Zz= z9{b%u%lyD)St@$C6_10r{@J8(J_HIo0KIIgAmW^Ew-!tNCd*6EUio*+;~ZRQ@OOVX z%Q}U>B#)P>OP;#DS;=F1M6@U?=mI=1T~HJ_9ZHBGR6hnSk}}RAdBxe^v9xd#fk;0b zRuvS4FBwJN*XgVnxhJS5#SawUZL?LdxclYCPr(&6!#V1MAYVODuz&9q2J3+wG{wdc z$e^TtuN0}>F;XagjZn_uuC}fW6GMMjlfdQL(K2x*XYxFQO+tXqp^JD(g`1L@Jnx<_eR0dgI#K9a}JRt9pJ8vd< zk(^0@E>ga|qs(G^#);}pRAfCXHvt~B9{=mKG8QCj$FnXLWy_RJ+CJ zSHvMuw#*j)uArR$P~3Hxqxz4#ySFOlyu&$!RD2H{8#EpPYjbip_f+MZtYrO#Cl3yP zAy{c*hN?IzdyaQkTe;!TvZhDspN+Js3VfUb?jWo5lZK;k^*^e_-uq(+YA)7G``aZ_ z39TzkT8^W~+E!I@GTGk_TAvtnE?%LeG+Vi7mR1j65sX(fLpL|3lloei7< zho*Pgl$__P9WJr$$??O8Cg(FEW{pE{1QxdP7#m2ZnPjmRJ|p_RPa9^U47JQ%H7*T- zZCFQY86Z)|)AgRlr;p*NNiz}&xv{+P^ADsMcal%!QxZANCxf8hoKBV|9)(4bT{!T$ z-A?7cZLVl6nj~fruatkfAEN?2-C8bYKa2r~RvJp99G%=7vL-pfUJicxdKX z>YjI1@2Nuxk@a=khBZ?Vv4bFYlMLH{$E(dIi8dr9U#rmfYhQi?xwmzpLg-HPZkcd zrnzF8I1nHZBXT*+kBbi&$ot3yiJ|$cC*12IQ15~fjLUyEb7VNr^blR_vi>aV%uq^{ z8nht`Bh^V9jz?X4o1NlWGT^PbB3t{TeyCz-R#PZkboB>>v1~5=Kr&+&k}k;pFIU*} z-UP?DeC8NCaQYA)sWCK0u14kJ<7{!;`8TzNEUbT9w#em;_Uva(jzSI5p@Y>E2y)zZ z4)yCqlaq+7f2}4Lv}IyA2gzo~_j4((`?vjg#^NuO+MIwKc3-dvqxYUQ%ntjQERiR{ zSX zCsX(-LyvLn!V00ES<$E>p-29P>Q4PsUbcU*f}-$5bHi(eW@y|d(*V(Y0r=jqH4r?M z$ZaJt(zLzu*vZ@=eS3y1g{32BAFwqJ09Vv*LD0e9zOwn`m=}o-FQBzE=lh+dC0|sE zuTc2B$p@HbQ18I!JX);VSqM4hzhEY_2N5{(39Ij3X%HwMyKz5Q#89S)8WS75ch-N$ zv)P9CMOZSZ=Z41I>mF+V{HEUEC(@#jZ^6C8QTkywtySQDRtpr5(u%ZFhdDeG%rXi! zn1actT?0i!`4!q`VQ(k!%MnPHNtfrd#KZx`+z~B`)A z2H?jj`=>-uP7U1P=`^JWMxO7{1z>+g6e9TpT3yVQqjb9GB#k5?e$8u^B~gb9{&teL zWSUPC_C;EO!XNMS5=TW3gAn_>mzAxbXRF@m4vZd;K0pA6)J9=O3XTdDq|C zDP$otydhRsb`ju+p>x9urTM>GKZ#?&Tfl-~>pl-FRxpha%N1^PS9loJlBa(dJmg|w zW3Ew^utPpVvbT4}pi)#KH!@9a;oM$r?2kR5f}4N{MMmoAdPVe|Jn%uUOoUepW1EI$ zB1V*B&pfMW*i#G#b4g`INh^blXm)tP*+t2^?FHbTr2T}B=qfF50w7jP`sRg#nFl&M zxC)n~n>9{sd-$^>Y#FV45($45&tc=*3Li17EzHW*PQk%IfGxawBd@GG-at9Z5uhhP zb-I8fM^3!=SDF0UtKj3wxj7b~rE94Ct?vDFS4Y}A^Te|bGtT1ymCaI7NqF}W!RD*6 zuHX6^HZV!!LBeAcEqgzm3^%tb91`UJv87^xWZC74Q!0NOBd>d*tdvHu zv^bWJTmf70^Ss-b$sQtNYC*&)W=j*frx@75OiU zRXE*}Yqf5ho#uxmu5>!1-o@C8aED?2_M*p3*Ida#L4D^xl<=^i&?{$ED1VZ5lEbID z=Ko|`Xg@TYJ`#db#U6k9F}2XJoO31i<{`qa25v>CrY!`aq*)t<(bORO9BWPbe?Jdw zs;>lA2*=}}{ZZs84MzN^gwI!62nSSR`ffLBqHT|YH{u@FlRBTT_}F!O)7-rU1~Y+IL%Z5K8@ zI4vHS2RQpV$J`UN=JF;ekSP%`Ju(e(hA{yV*GtYWAJmr-n?p4Bv2cgbGTNps;n!nl zol+0_5H?FP&8o&ehFT>DaxbgUKu^TIKboLhw%y=|l!l=LS2Wdt+@z*jyf~CdVZgQQ zsD?3pP)xy|o(q4!^P#`gtV7MB0Cw+YOtD3f%~C|2lul+4==`+;zs6Z};->53!GJ zt0aWWQY_glk`fkE|!Dj8RKw-+`+B+i(~(D09=M zsDQ@+#V2__RY{X{%k5M|eF^OqE*vcv7M8*?ld#4wxo`Wd@_0g?+7=joaKuK64RV}Q zRhxS$^oD;|Lr%>}I_j9WKIM-(Wm2hI!M~3)RxaZurK{5bOO(uYYH32of7@t^;fI|= z9(m1Bh}LkRx2|{391>qG%tmy?JoagWIG8$$Q4@V$th23GTK2p2C0pKr}_sJ)SVW-2yE~lkUFP{Tgbt zL2Aw>hC-?xM7p(a7jw-l)SxYz>9Da!kRk)&K_F~6k)oqLRFB!%C250YI2x007pD_Y zU|2IrQPHOc=r7Lur<+sAHV7B``^{afx)G_{Xq>3 z&5QB7 zo_iWQbr$OF`Wq%vOHgoN{7iQAjj&PnBg@fOymo z!pG@AmG`cVhHML@cz0ME%Fm%2%$q9Npkbc~j3NDvUJrZgj1O+o~S3ZAY z2$8uWMKr%QNRO~Wy?e3pw6?i@GS4^WAGEim-{)oB;*%&tJ>)k?K^LTL=_Z{I$&LN& z3%iz9j=K1tr;`MbxxGO=h5IPQ=Sym0c}+k2)wkJLmf$Xo57T{qvZV24y##2Z?$oy0 z9GOhTH>Y=09$a=mZJ59{rP3tB3G7{=HX8;Ou{((uP2j z*WU_v2+U*G>l7>I9aC#~JqEOFCG`@VrR2VD9RcG>4aOye$%oKr%Z}t-nc2WiKPSWA z<)<_3NL9Y2s-ZM^apB!T-{0Ex3d(UeZJH1JC&BhMqk7#~>Yc6}sRR2Dh`LB#?>|Xe znos;wKD1{vL6Nz?4tpL~T*rUMFb$t{xi>(Vg&TJ>@**-=b!(&Z6={8vBnp9uMh+R z=somFh{5~7MxF2IEnElAol&HlW{)o$J*WZm*QUj)(G|%3>{#FZ-AjL5j3ouJdi?@q zJ93mpo4_`(%g~+_AaGIn_MVib4_s&>V9@FwsK+xYwpvAPR+7fJ;+G}F3D+43JdQ)z zXAM`}1OFNns7(Sd$0Eo&8|F6p>o3~qD3rAYl*~v5?Q7M|ND~eQ=aInx-rWEs@?T`;PMF!Iu3Oi?UsB)Y1zZs zVTdM)obmXN%j|!?{U}#6IVL(x&LXpL3%79yA$MpF=k)v}g;?YQif{Rkvmh5pW<1$A zS}F8825aad1zemhZ@mn%NxXV;i@%k&5+O7_!5>b6rO8hm(yzvJAw|u5<@t63f%E6i zSPu-ZJMeELLA*D0y|^s>6aqotC~P?%(?dVy!p$P$cfH%0qX{gS<(E6aG1qGqc&RvGvNTpf87I&V=9%4U=giqV&VG|iSE+#DL(1(m zV8NU-R?KsHf;jveJ1L=GlFCvO2THlxyY1nDdE0-Rui}6%vU^e}B+#jx2!p;hJ((MS ze~POSaQXeO?a<-bx8r!uUxu&lv4q$(_|_q^cK`&S6JkD_2Sv2|G19iOcKmJJ!qD20 zY;%ya+=)a1IQ}mF@$dvDdBPuOsw|Oo(D2VCB~|n@OeTOA2H6?vX>o~$tjl*QyLJWU$bW;qp5iRa$7i&~g$3)_v66HMFTW~7Nb@1%IdUcrJ@j%e?4yS*r zee{CiUZr@bI-M7)9qekS`4;mGckvg@h&e;|S)md<7!25$-m_t27Bm~E2@2ndR)gRn zl1M)Anc$WFA}vUv?p)*&!Q++hFAd9DC0deS*c%!+G53I*YA2WaM9KmxU-}s(O0?cOv5`#Uve_zcA{_No=xF$}= z&l3=2&btXCp@veUR`DC>MW*hRC(YB^s;tok4>$@UVwq^YE=4tk?j3EN@IT*z~5L+ zot5eS8tHOYmI`oq@Xcv6n$zEPG9#?rvp<}zE zqvDBR#noD{d2~58yo^Q^y( zD-qppSA|r8muk6P!Hq9DWoCX{5VPe}q!z^-oA6=>-8CAkaKJPJSh>+Dd=A?UHXVGnpy+ zHm_{=^-sf>TR))t*;Nh>gtW(Vo8d@2X#472<=Hfb`v?R5dJu?3vPz;~CeillU^0W6=zk5Cqw{3 z#@&WuHTl^DzMHnmNiBaR1ri}O<317e9KHqCzSrw;az07=n32icUZ~aHn`sIfzt2h^ zv7@(#h)^B=W{=$*Qlb0fu3YAM(+n03U6rrJZBN{&`h8eNeOG-C6NcP*Kwytlr!>1T zVZr-`&hRG-D#;oksC@rZ1Vl4MHaY`6?2s+)12G-=@xn^sA5no42Qz_t*na3aUD}3SdnDM$ z@G1qeU2u~7O?Ac^89z2vfA&D}*;y}2p7dvKg*E&LzpvK#an^>%R*)>(&ru;zZRjDT z#~iw5ZW;rA!fJnYv)Nc^G%QusLBkE7;Bf`{as@HK3>_FEjz{+x@Zp{ER|Nq525(!N z#EtM+3yJmpITxG{;yb}fbDO&48LiiWSU(0n?}hymxY>7(zRNzTCaw4*JU*(AG^v%5 z?Z^oDOSDT4)#5ujF;VK~MT!?(TSL*aETc_}HCm0ZsFq|QjNhK+V4rww` zitM=H&Lw|)Zaj{u>ciCiTavFy^_Z@MeP1|7oXvma+BNTXA!_`=Bs8M7WSVV2%JCk) zSQmS3+-4!>g+wipvq};^CX|_AWvAyHFT4dtjP8hL*uYJX-w}I6&(^0(5HD=_OaS=d zJ9B3AIZ_aFwggK)-T#)p8AIhmIm_!=_)~fNOHzO8QtCX0b1bvd`9u~<^Ar(!uC66< zse~K}%pg(4N&i?&I)JgMlNXoEwi+2#tOctN{u@TYe004tQx@KVGT8HLWqr~kr)7); zbb!J?5LIZDfxA_7e(zehg!8l+$_@v`3(f-uGirBp3 zEaZcFf74eM-Qdx`k!k0A$RfzR=l#Kw9V{#aRetNkp_C?}#YZZpqY5_`!4gnMfOKdb zY?V!gPQUURAr>GIS*`+>F+!nsGpckZG+}@EXG)b}2JVe9{f*B8lSzT=!kRcGAXOJF zX0>N}B8#Tke~tULWEA9>ut$SpSkvzO%<=*Or1Ka_lZczL0;c~|@&xAPgu~RVNum90 zJnG&uKbZNPB{L!EwNWdtImCVD*u%npet_xU}a*jh?6aWFYq*I88L1*8!K?+8dL%c zw*BjeU+FvE7Lkm+%QG*e3)PtlYoVm<%&{5B zeObTO!=SxPSkKJ_HcGNTX=kGk_Z)v$L>;qSow?cwO>Ibr3}SkTIwTrwT6UY#XOctK za0C$PI4vVNIG84fiIvhI>qATz(X^V)^ArCy`((XdfWU(85+(nZ#2l^bt+?s9Nbac{nt+#Lci9DIZYHm%+{%p?o|(nB`SZzYC{A> zLf_+w$Q;0`uVf(nT@as2uzkAaE$|+Us!cIDKZf z^IN(tP(X9y$3}F-cQkS)%$I%YM&v&XWyh1VB|dHb<^pE8=ig6Es!{QDWx(|KGSlN& zWtjIKi~0(j7qcoLQ}=xDfiQo{u zI;5A390S*OX3;?0?pi%5X>P)72h<@Eljd;S>#Rf6DtC$vcs;?idWYra5=4xJ3VCZ; zrLn@RGBZiTiy=9lehhz9ch{y{U#R>|$u7ei2C0ioaTADiLwFN%mU5E0T&zpHW5lCC z8^w|jaBnBKm@{+^0#93Zldrqd+h0Z%^9{44SdXx5Q9A zy$K!ZSbAxnQ1zL)PXAF(AyriDzs~C32jzj%u;`!We=?iivjcw!u;(Wy9`4nl8N*pe z{M!w*v>fPd$2!67(up^@XXW3BpFD%R-{lQP!xFv)MqBgOVi>xh9xoY;_|%xI_IrY^ zZ!b}AJe&rG2-&cO{rTu!^BkDF9^ur9{F_XQ@9|Q~(cjC9HI1GvifcOv!OxKDi&Zrmma#E^4jzw@jn3k91<;)G5!;mUIYRsmovQq5d%0d zGm~N36$LRkI5;wwVZ8wtf2{b9ZQHghsn~a1v2EM7ZKq<}c2coj`RaM!K7D$eulrB; z`LV~?YvP)?=9+tx6Dz6G3!B&(nM&B%I?*#TF!2BsfHp?Xjw*IG3U=Ib^eU$2&Vavi zb~ti!Q3q2)C!n3Jn4yy?4?xq@1R!Q=3}9gaFmrQr!;u3-?d;the}Lu|P5>%(6-{bd zTDt#~{9^(za{mv_Ur$G%xh;U=?~9A6wVl0SV}U~Fe=0{o{mM~1&x z!j1q#fTO*sG4QXOf2o_Xsr^4HI)J^YgALHp@$WkT=m;=(Ftm00+XE*%0MORh+S%lv z1pdm+?EaOIy@TCf3!A^XzhFvsj!uro4nTV+z~87!ViNz()5*fn>7Uq+z`tsMo!MVY z6FXz)e@gn7?k~(=t&<_p))C-j>gM!MEF)8Z3DD8r+R*)Pf9$_t_71>*rQz%dv^D?F z4Cnw3rsjqYCf25oj(=hPV*k^f|Ev@6zf^B%Z*T4XFK@elS^du(fKHC4)@BTF%q)Ln z8aw@sZ4R`BWBg}Uq;1XY0L)DPmYX=+|A)@S)Zt$ZqWWiMsQ)HmXkuq;?G6ApK*+x^ zF*So@RIqdU8xlbEe*?!d!bX1)TZB718 z+y4~&qc(PSaQI8|zZSsXs{eoE{I9t;HFYyJhFe>9A5o)r7>tB)Cc zIM}|lQLU)Jug0#|H!We;I}?#T#_Xaqr(d!Xntus{9xw?l8^y}HUWJCh z$FLM72+$FYi_WOY=+%FBElZ!Ta;#r82=Js?Wv+6^0O60DB9|r8NQ>CF|DbA62}unu zW@?ATn@DLeaiOFuYiUIC&v3HU;|h|C3m`=b)%lH8B<%?mN9%Puc@x6$_kdKZr47_) zpDWQ1^8>-@qnVFgBOZS8F$oE2S%%P@M?FEmsg$$D2=4RYf~9|KHDQTVOj%aV53fN& z3#K*4bfea~%3d9iv%cYkqDpPqG!gMcN#~N^d)+7Nwf6q#?nx784?tWHG?+R0)g)W8 z2jkv2tR>ZR2~s8tD-ffQ=fjq)eg28GXjD7Y)I|3q@>FNH5-+PmBqg&qf@434mmm}H zbj^mfPvIh{o}Yg*ju_$=VTH61GgOBrGY0yo&uGqMeI`@$9kv0$+o>J-?T1;zOMZm7 z4Opzv>YlIM$J8dY=sTE(FIZBg>tM( zGAOpzT(ORQW4it3j0;rOMoOGTk&)G?aSefH3Ir&++LV7lw{o)#Ub$PYi<_F&_LE$e z@`RnK9Jyu`udEksZ?&WeY327JU#W&-xooj&b{iBM|By2MV7Gcl4U{Jrw?KOg=Enjh zR$&k&KnwT7cN8(?d*RC>&6jEtbjS!+AgGDTH~pZTePtmiFq1rmbsvbf+RLW|Mf$wz zSFyt@Hd}vIM}1p2AQszRl(734 zT(HhPUfYq_ap>KCdG2b6_M$>NwJ6d;Mqiqqj1CtARt3H7057-QnF%x5=6Bz1*o9T| zv+Hf?Ux8aKXUV)$Nz1tMC!{ZT53R6-lKOMzVRSnlDVRu@n6&10In%5tYD%iE59sxq;fMV*PL5&A!(?o?Xv(BIwX&oim8u(hg zQ@OBL@!`BWa-wqdJoayj3LOf5t(tUm*g3mkk0m6JMgE$#bO*XJ(m~E4pBNi$je?i$ zmd@_$@#_aR#WF0eYKHXhN2yBnC>VvlcY8K|czwS~pXBdy&NoIB5YcfhprhXS?bm;SZ1Ry?|gkK{+7l`&YBDCY!r4$V4^gMdKt4&^IgoKbM1i3&C1I1Bj`K8Zd7hRr)mblRj@L# zI66h#)vm$(P+*_n{$cf67O|kX>f-98wn!myEW1Slca05^{1F~osT+yCNJe~yiQL8I zocJy8%x*B?v)MAxE=5^4blQKH0&*si`1&Viab3vHv*eESwf-6(+Nge?Nlw3owJkzGJjbgVv_20S&ANRNxq<87;ibZW#e}AP`2y~> zVN#HhmOj~vo@E%af#}|QobZPFaJ**QVTZ^5e6vS`t8D><)0*44xOab_U-6B9 zLZ_I+dtJ^#6`NHv&8RaVDlh4{ECVEfHpF6YJ=Gu6p4{S zgza0$HZ(cq5hjZI)>S*4z;b+>hGFQpQiDIV-}ET4APz5&W8Ve-1O``>1J>~OE9R_t z$%bM2QS6ZRK2?9eseJ665DsyA8}@=Iy|ukM9ds!rNvi|&idA9NGEBGgFMse%0 z%GBQ9YM8bp@Q-snUfK@ZkNDg)6*kdaw&c`jyQ#sHdaT8!Uwb3WT?5ez znk#NHZLKIh4FGHBK87GpCB1^b6I|gW=Z}L&%!+Fp0ttUp;m}=w>?xJJU=KfGofwWu zlt{gpJ02zE;MFhoQ?S4dx<|=C;)A4$D#kIfQ<(Fp9U62CX@+`I=myDH+q~{(|-RJ0hvFZoinF zk~i1hrYke}sKC-JpmLf^VLJHQ1v`7Pje?#OMYMlE2mL*OJ4vV69LZjj`-3t;;}n#o zfQ3H6dD;BNafQFt$}XIGh+*#YO(A1nMgF*rI5{_R_Gca>QPozDfHT%{jV@Y^1(OS7 zS^&T5U8C}_tu^`#cDznfx`}J4@c?!#S0_g>h76)KHUn%}a3{BR50(}L(}Y26X+ATV2?WL;}K<2oVW7r#3S7y!c^1BADuCpoEQPu)X^Q*_0G|% zUR5Bqsgk$C^g)o!+yKE3dQ!W9D4!5$ie>{b+kY=`K~q#j^jx>1_58`D+xxHQx8-?=^P@7g%`o z$>CQ~fozYd)`Q{c^@-+wc*Qwp$U_bF`zgx!bXqwH_!6gfyM*Lra%zLS1G?_-a26KMI;kGwO0 z!jgoY9~bSP+9Y@XBn=PY{$`mFb4#Z@LRbl5{EJKN?E9=9Yqqd?$9I!<)i>gU9l!h* zm7R`HDPMLy2JXc_Z{1iuPp6wfp(cO37n0HqdFa6j`cEJSV}|2AQwUICw+gSd+LU^m z=)y#Mj9Eq8RIivKDjFlY)JnHpXXs&e7MhR(@KFy?`TAiYz+PuoXIW|bbteW&r}E%R zm0Y)O#|6J3heTQ2V~IO#FEQhD8775Lq?}BxD&cMgazohPGTNp0#$hpZ654+&(phf5 zy{GUR^z8Y z?E=w%gO$_`90G%>d6ff2<)*Z}?gtFHjezDIao#+MxSD@=ULS~LZObo=C`74+t(Xb?x?V& zBLuQIEcsN4zLjjl9D1DXw|5;>9$WX6v%Q=UNvu|Y16cE~sBnKY(2c<9hAHJV8UOr} zEp$WiRxY;+pW0ckfiP`~yP%^L)t`@}9176U9|A~9HD>m>EU2}JV0*hQgK%=*ws6B_ zd_l#AJltT7>@uq4`UPW!ZgOjS%Fu#FZdp)ZP@0!Ksw=L|*<&KCjw{K2D(&6GwVn-2 z#fBq*W#OMCbLoGvViW&Y4RH@`x}zS( zl8p5#*AXGt34^XJPcOE~*`%e2QjlI*dI|6usY@DEpX#FLP0{X+G6_}a-0TmdB2-a-Rkh z)8Et9k0vIh#Z^?2)kT^K$*HYWSg;0X{K+!zw`L7sZgGu}z%WfTLA+&sTy3`XruV($gf39o&=k;E8>1X$5$Y)3p&mM#jD)i-L=s736;TA7$OcxhU# z^c;VFj{i{r@Q++rAJCI{Br`uWVgzaWJwllgi&ptkUWF73uwuM3%;p4uk_FYeNDsV) z7S@QZ3AW~~sD#@qGVNulZ02)C`PxR{O_6S!pot3*;U`bk&-O zh~)l`I5*S3@PChT6r-y^D2+hI37Jq3zo_6v0#f)Bi0nw}Se88j7v~mK1ryOThThTUW3fZDVo;fd#K#9#4ALZo%DH z8P8~=K27QgJ(OSA7RizfsUFDg$0b@=t?qOij_=_y89EX8rpD|Ik?S@LjJTT&nmUU7 zxYf&dUNAeCVGik3`39jD4^DsSpXzod$cD)DK_`c7CTnRS#nO~H#}|i$mcQIr$B4H=L=>^FMW$wp)Kc-Bt^j0EO9>93@L$=W#~*=)Arp^PoMd>7zH_*(f8{~Z#Tla8XvHM2pF1G z%d?+7!NTN_Egyfyl|Rz-CjXA)N+7+7)QjrnW<*yd&771awVNaGvZO!tQZAE z@`$vvXdoa~u{=CT(B5GJH7bgS3z>y6iDp=_j! z7aRM9W43>X_~EeC$8N9I#T}9WCaD+@pk<^_EwlT|2oA7V)Mt=OV2oei5nYW~^d%(@ zde#*3<{cAN{~RjtO;oIk*6Pq4nRSQ#i)3?b|ecK|P6^zV|EHtf!2TuK8l6^9O+qTVnkr%X(vo;$C~B zXxjtEZRx<|QuMIaiqVE)y6~(&rl0d(s;?2wJB#M^dg%}p$^BFKx46!fwM3@jQ$1&B zG8g&OOj@(MZ8R>2-0Tc=$zD0XPkb~G1{d|#g0KI=Tj?t~RP=%>#L&z6X>R&cNz1spBbz@5 z-Z1_iM!~Dy~=wRz*8&*9Eldo;@BkZ!5dCc|t94y=x_pyb* z9a{QRrf5(!GOBzcJBKrnW^o506jOgq@}s!>Akm-%Js0L*SUp|9AJrI$8WvFoOmIVK zo%Nyg`v{!5TV6*B{1tK5T-*-nHO%eWtP3pdp8MV&4s0+Aj*gyRhyBhIn^}Cqcw}Ma z&a%G~2{#-X_ZE*DGJbbvnj^s|lu0@~jKiPCk(ZlwGl$iV-#Ui&NrU)-{0M)leA(;Z z4sPWz2J$4qG`AxXKboWhQh9=-f7!`&_Nfr)M#9QHeFaX0+I`0I`!T5A7>l{-1wut@ za;bGw_Eq_N)E#FdCz0sUdRiW=04L`$EeZq5$1tKqbQ1Oo(w>yvQwWVXjuiu?W|y;Y zxgm4)r)xUS9M><_KZ^^6KJBcPrQEqyyX$&WF3MTlnE{tr5-XiCJz*%Avk9gXa7c?p>9tz^QcpeaWWB}o z`#24dEv{Fy{CUp~=(`2xO~=i>-kUwOHsxy@lDrAcFhZBoM5$`8*&Tl);Rt+*9DFVQ z&1rX543%x`SZh|7Wg=s3(9s4*Zz#6hemJ)8{*RfM4M`2t6Rc883xUTS^bI@atYlxEk~n$%N;%j2@~ z$ag&)GfH)FD`BUUb1G9Rx|oAM^VMC$%|t0e|A3OY&fl}1Kwf_~dUL3!$5h zs1e?}$Yg$h{RwtbX5AQr`8_`dwRiN!-1m{pqR#O#_P`JHqG^*Ey=h+aI2RbEX<)hIIea`(kZy~HR6qc14|D1xntd!y_j zak_(rv~2Ta<)44Q76-Af;36}*9H_&K-7)sXH+(wKoAM0V11YE4J#L^aHOv^2rW~F- zg*kQ&bla9CW%ujwQp??*E^ye4!2O`R{U7OqmB2WM-Ce<6Lcx#BBB4j=e?qtigdLn1 zT){}EmIiI6*uhxF%qx`#Fn0${Kzp^jeY=04F*KVdaker8)op~sm$Vg%g=R;* z=7_7Mxxl4Lxm-jJv zb8UYFDBQYwLUJ@pnQ?1On-Ej(p-OlUBRF$Q7^Jp3xQ^L}h(Iy7FM5|OjeAi^FE2AH zkZuZPIUVYLOM3{e2{pH_&o(A0ZR^_w0>Pptl5dJ|x4q?L*B;rc^hhc-2g82RgAOyn zZh1x>=7;)*LrSb8FSl-zwUxRsP_-}DV1<9jViT3cqpl~86lBwWKjnTur8JuBcCP=i z0m4Y}?U%o<^3-XbO#zy(+#>ejLrk|J*dC{VRC(0pH>lbF^<Eex zuNPKEDHYSqJA{u9d(K##@hcgnUV}11j4Kub>zRMwjE|Nz~BVR%s6KOb^hu%^u1T)2YewuJHnub zOGU6+1zuAS6CTNizM&I&-^t0UBNT2D0YNL744q`-t!^hPNzHZoBGtzX*2j(7BNrn}l0XT? z%z3bvhYkRI`aJ0|)*F`l zad(Aa3&ZeoRsiu0d_JW(>^Akd$9yCe7`!>lUaCzy|SIjbK+uAX*I<|eye+9)o4-M15ux?~NV~F>2 zn1}pWNIhd-y0eYx0yWY+eOT!3!stqOwg%vJm`j*qEs=v@UX4HZWlstZt|Iv&&HlBN(wd> zXK)3%bAMVeYj=Mg5r*PU5Q1JNH(YHGNuq8~L|eTdxH5|=*uYIciquH~4+Z*DbyXu# zv9w1t==RZr--xTL1rPjq8|~my@N;Otq2dx@_ZdFBcGcdaRZ(8f8nr2>6xv#SUrX1W zhQU7Y)wC&nP}n@pBci-kS|crrJh*cXG}jM)z9=pdn1O%M#g_ZTu0Q9XrqPkRLpi?^ zE<6XBaOCx5n09-EbM|a%zJH<+DcJ*aM=;EO(hGCsR%nDeRTvFkis>RaC~{hqTxsnP zvBP5HRg6IR&iY!W*x}b>LydcshoL3xKJk#PTp2mmxsvDNwmL^tkJxWf8q{jH96j9T zbRr7QJZgVWGi||BLEg|QhT55yyV7SLFL%2{f+mntWqI0^Ze>QAh;i?|DaRTvvzBG0 zk_MM)G#S4t>72(q_uQVWE_qkiSzrM5DILO37*jo$Lr$6kjHf6Z0R~0?65Cw)h42|Q zbXnLvNUO(coX7l{#A3_9P}M26)Q1$;-^u^IKOcXyG1KMRozZJTnzRNOKg8a!$pe#w z3*s&_OhEi0yLx&ex-()qDb5LXxR!3fv!vEk%(pY zMd!=51F@@>f7h~1oaB1dV+x&7=&tfy$RG4Ti!&^c)&CCJCoZ65I)IJ&kT<*Y_n^i1 zDhGd#e5Rp}Vkd>^C1o9sJD&i!pHn}#Yy6u<+3%{L)9-2EYx{}{I~6O7(UYZq!~P65 zYu^r;mE)jV$3}2g{a|jO6h(Mc(yUu>*Ip9Do!T>I*;+2+*YNzIyUI5F)1Zv6b&>w# z()P!T$nT|~j{E%=f&6aVPckPq`m2`4hrZ z_Zw*jKaKx`4n&^~Vvkl2Tu7<+M#h?GvWQ>^B<1L0H3CkYcnXiO8f(mdt2$8|# z?CTtrq)7bnm;GFd2{m8s$|7!D)Z>_G*9M+@1O|c$4F=xA17LA1@-maQc^Ct3c$TXr z&O(HBvg#fr%v^q;6}mifbQ=iUt>bN}#DNyS?B+9CPNf4XQi&6k38eDOX{~=k_egr; z3FLV!dIxire5S%oD!ukO1fN=TWaMR6Fa=Lar4thg*5d-)c(cLwZkow)b86XY8oF@g z+|-7|P{9~N%~?!IIs%k`Uy#U&6?ztzV~VX+TRbk=1+SeA6{*h?DYyj z$jO4l@17X}`U6hrT?=SLmdgl{aE}{(+e)nn7ILY!w$N)Ub*5TR-(EEQj313ynMQoq z6Caj-5cdnxM+(Z)sh2Aanx5}D@4;^T&VQf&pBggH0Xv1|8j= zj%w0qhis(I_bUf)Q*-fzc$wF8B~SlYElO4 zWOa8&5su;Zy_wlr3L7443Fh3!N_^k(ZatiFE!a56#6`~P2HF386mHpJvkU!)4AzC) z8*1+m7L*fs;l6+WjDQ=CxFO=3oxjJtmVlQbPU>b(y-ZS(`IJ+djckKTtqY%eyHzKU z(ct%x^C$Y?p*VOYoNvB~uVB|QdPGdC*WEGdcf@UV0iE1CKukC18LC>$Q?Jdd=j;e- zAa;IDP4W1T1b~61#4|0I5D|1wv2HruBzq-gt|OoD^K7cvg*f&n#m<4&`V zqglI7%OrS_vc)Z&Ji5A`=&qE#H-s2Vzs*}7Md^S35GbK!-;YrdbN4MYkNO+ORXNLn zDeP&&{&4}2t6O@N>yU5QR>+6o`SACT$=k&eQ5CKrS7}Fc_5SrqTRsEr;i&xqAv~xZ__x+rN<`7>E zm3>TjtPE(Dz}9)*+6>6yA0wwUi9eIUi|Esom5e}N?>b0*X3|oGPCOo8fxua%5F{Ed z1viFezgeU4OK4;Rqw%&;B{Zy61G86Q4MuV z(d`od0cF3mNBvL)U1nc=IV74bclG&1I+7VdJ~Kf0&(D80 zZPp;OjTO{dxIgCq+Kkw-`^u;LL`sk(R^ju==C`Vy1QOW{t#+`s+StCP9#PKEF3OFM zUWQC?`J-pCx;%%k3sc5&cQ)G|SUlfMh52JQ8Gb`nz7eMSxkbgUQbx%Mr4^k+^X(-J z@j_nKB3)G1CJZZVx!4W$C%9tUNHH#Yb73*lpJZ@2_!O3EzZHeb22jG0c%LsNfJIIi4; zm2{6Ia{NPgq9YFsc|G})9Wc=Npo&J!fZ zc|Plf%&ct>FbBU!F2*{cj+n@d()S#0xho)`!w9(jZCV zMK2V$^8x4m37YbCEgXN#%&04II$S2&($5l@k?z%v8s>?O+bg|v@aafcot8B zR_j|yZ6Xxs=t5aX9AQ6E^Ot_7$eSM(@+v{L*m?`@dGIRfsw(OxG)Cl&>1R#S26}uW z*G1uL8@$r!`wQq~`Ri|@0l4)SMZhSC;AS8O<6+qAZyl}2w@k;qA2ENV?3E;h-an1f z8>tY06(urNZpOv5HIv2wsy9M(=s!sFpmXccjGs{ zaf1<16(u4ul?u5bMe_?n6~If!r4%@?-%T3r_utgSb7{iRIDIksYZze1X)C*aArDV! z$#?15Qo2J}ltyPO_s4%JV5zKk3=DX?9z$uw8|9{DO8c0dPeGJ%l)?)1uZ9>7G~thC z4XqwF>WtZjM6t^m6ryTKuW5>r7V(WI#ek=%i(d#{&25-66uqA}9T0kva4)IYww15FAhv>HabG9ai=bKHMg zfv@Z`>wN+5N74ih_{xjlt-5k`)dWRKq^`Bn3$l?}jv3m#qQgIMT)vyl&vvSQhFgVk zFM{Z!)q78_;i7-yCnB720Q{_e|75JghgizoibsBURUN^IojA?q# zh&O#YvID|oP=8vZgJE#ALrl)CXx%~5zUP0Xz2nE6EA?D4XJm`dw!hxbOq{9wIf80`Rclm!2kU+RbROWA0{S$og3wx zLmytrGA3(hrG80}ezAG6m}VmP16v3qT470?HZ{#=C1Re+E0R=bh57LLC=zCUn6&P9 zfbh_Vssewgoz-EO1A!lA+c&S0L93prW-~UCiMU)0j~s-Gyb=&e}BUE0a?oMS-*S5#ySoV=I%SmEcB)17*jxi-)9 zapU-)Di56|HX&-0)3~=o^rtmt+eob|C~;Tyce$FF(KU}Ma{Bi`heJNS!A$1!9JK3+ z@FTm^PT0||*DljBj?%AsM!J|nd>{Z4FT$Z@ zV2#jSY?j3v>8CYFdQVjLVE58_;>TBG**7&aYUQ&wXV{_zfBDm)5mIB zwD`Nupi+c0v%Z7uY>Zs2y9=r=y?C20EUPt81P*msA!?T5;|(AKnfTc(`Uk8XDh%eG zk>%Iu-r|V(3aUJ_@2(#xUs2%-Z>N7-32#Rt)wMAdPyFki{9afGaWtxs1qr`BZI`Yf zxK}i;;=yR6hOmR-v~ji|s`icoj5VI&TqXj31#>@gRfux7U)=oGMuSQmDKfY}KrEp0 zfly|U-bUYfeaHB!)Ko=k--K_`YS4hfEz~a{!}nV zYs@c8lHW#JazrmGW3c?TzaCDHl!wyyb{5r7wRv63G3HYg<#(4j?2%e!=Or{q{$vaU z!08yCbyEmnS^+dglv;kfg-m}_3A!|2jad9FS>1ls?X-kkcfeS6{x#_n-r;{`D?uAZ z{=5{m>t;Xz`%xNq%j3l_KmC*e_=I!BX1=kA$T$$ifr2^F{SzCXXG2bx1J+v+y3k=T zzghE&AqXlBk-9$@*Q$*X1tS?TAAvW^@91lm+taBf?|!$$3Gpk-v=@Ii!3a;Z&Uf5^ zO(aon`0!YZ-+;pUer7ohH_D5~+B8?7jA1zuzu5T4fVsXVeq5?9wXO$EMzOEWmON}9 z75n;O1-h<(J_aZ5)s1qbk>4PODHMO5Lk!tEm}|#B_E^LBx<~we$fnqj~nE?v>ZZ_Wp6X2=gkQeKkPBZMOBiVq*!w1|YVW+o)WtPB%Aq2Ut*xbiiBxJ1J z=r*32!FcQ?#M_%~qrlT%X86K_y~*b9l0Q4GsT{P$L5^*8LFs>?cB8?8g0{tr!|ufk z0LYf_(g=8f!-L;Zzefe?lK{h9uff>|V2rcqBlq!KVoc|{cN))gr`NxRx?Mk0)&(j*ai1tDgAjkGi>!9E1kp#*aF!7$7P_Up z@|<9ZC%7NHt24uiV~bvO#pBq!wMIGNYf}?RDRyrcYxA)gO<(^Oyha_Nu|PqU#VZ+Q zkNd9sw!9Y#A+}7t+ zS*g?QwuO^0xFSj?u!lQXca)!hP#Zi8{K;s|$g_VAKw?a(vZ*H-i1aG|OcFz+1b%&5 zMh&GqwP~i)o-7Id!I5ST@O@^_5QFIlMj%*w2oJDuz*@t0k&Q9JuX_FpNR(ZD*xR2p z**lF9M}UJZfxIP>7S=UHn@9b#+kNSQmFGj8--6v#gLx-(m+!k$hoJaYMQ-85tl2FV z#HoKIlOTDTkt^N5O3~4`96>1phaVa3fxQ~3RcZ$-2sbKs!R9r_fg6_gzDf=zwrnbJ zyBDkIY{esegHbvF2K(`;f@kW{Qk@6HH0Vhm}A+=qZqtO)`1z}UN?P2IW&~0D)Cj?GPo!gW727b*^ zS=Oecy$Wb<%hKHGJ6V@4!e$Ym=HPQdgxafrwDHW#x8r}Huutc&|`XCH|Wd{ z<&fg=+t%gYt#SixbWmM{w!pl!Wg>s!8v>I7Ti>x>DIPCQ-`l&h9YamUnN`S4zy)yA zIZ+HpaabDZ8OA={xlk9n>8DfY167j_^lg+LpuPQjj&MU=*5kz&r|MaoWrZN8U-ynrlgv_9ZB)BvaMT=W{P?tCpYAVdF5+Cry=|D;Ars zd^D$Lplc}{otxFEJ-4sQ{9`J}Mh4}~q9Ek^jlVy;m1r+l#H7o+w&GrC%2~Iz6n}_1 z&LArjJO4Prnw*XFQtMks_whz%+lExRIJH8dvCuvjBC4kHAS{?a6J3aoM~%4>Iy z6Q!pvzKx{gYnw8XLaARwI)o#-g6k#Xa)ZNtL1Qncd+Ft$#Xx`2Vx)pPuJ54)i7lgm zNB~5(`TxR8%C}a9QId?`Ym2ydISJ~NNc{L7V2aVK=+2gqohbeXd3qi7M|nj8?lx(4 zpXih(?#n@3iDJ9TG|mfjxM2d=Tg$jaHl7_$c2h|XJhZX+sf%pi)CcK7MZo_0RDrxU zaXp!B21pR$s7#4t!03%g77K?Di^H`HU{n)$mPfNl z*^hw!?B#s}XWoUqxXTn*F9C=RhSDtXzvl7FA{?brBQ2SL=gJskI`B+c2YFsC>6pBoKPs z(XK=@YotA$9lFhV;`mK##f^V#kC!tUG>t(mO4+Vj8Vjm+YQBgyr`wl6TN zz*&DflXK`6;=aQ(nLGZwRi*xCeJ?5z5krwqz+iaoEl0)Y*qVUwC{&Uv&r-m4>_YaY zE~b1F%?3+3gxW}o7fSyxj~EU#itEjQq6;iNx%YvFc){R|zP%kr#GD2uaTQLl-w$n@ zcmSkox-6niAc}GT+Es}M_{v({}lqYe%jK$O!4b zJNWW42S{waV{j&a(D$2Mv9+b&Z% znyH>&&8wMDcYnWznHYZO=Ba^Q^)#wpGtCzwhHhm?pec1#5#4}-%Q4ri^SJ8S&dvea z9*7H>r_aD&o}kM(M;TGlzU zmmq;a_nUu7=^_IPGhvK}iuc!i`goD4Dot}pV0EK5IVJrk$*sryyeQ3A3pf{gj(T}? zV;V2pP=qUA+?J|TW>b@r(S%i4Z>M+t`Ax)M;@Y^1Qfj}|>`4)3gbr{mICJQ;eX)iJ z+HZ6DSiXu6!oC9hQb7@$ly}F;1Dx6x7uq9$D=EpE^Ym@L&$oY0m(Y4D$);^@=$Fa+ zaoXJz<)CmYnt4k+-O1Jh zp#tk(PZ8*D8C|u+TPMQ=Z!;I~UIkPz2W~!`?OBlmNe+c{gy!Zp&e8D8M6xQG*h@Fc z9PdX$5IFphWrzNmhM1ACblu@rQ>`nWi^kkdbVNt-FmN}6X{|+V^q>L4)chW`*7DA= zieHiQJ2S9hQq(VY?(G+INWnQp|NKyC}P0&=E*z?jvfPCDkN?_Kimn0 z!{E91!`pg;XP^B|gQ1ZWg_8xa>zO6mz7CQh#FPUof6*kS>eF|`4McBD(;b6=FHdZ7 z9X9Ufh%t z?^y|cLuzi85XE0YzhmZAVC%d+rBwZF%^$Ejb4Ra+sDHQ5p|HbR_oLedC_>ObR1s8& z`0n2p(55q{=;2GtRu#h9x0o*)LDfD)Lf~kW;sth7hiB;liK|KoK!vt--DUz}qG5cS zD7(UZ5J)Y>7 z*=(*BiNq@`8VuCV5H&?WZZ^iAe1znp9tY3EpkjXWg;pC z*{g%UH@w!XlrN;R!538HzKxDfH|7xK5ITFF>-Y%zNfuWpZl1mj^i^AEmaaVIXFHQ& zw6E{~0RzvL_KaXgDrBMKeAt581WCz#bP?{}L6P(dNFOU14{TYAaH(ir{v#Y_9D9{G zYi7IouOi%FvZpqZYIed8#kI@GvLlKPLrSOwl_7JOeNhsTM;+wc64&czNdlj#lpc{M zqVAHyzy2FWWUnJ+PZ# zwsz+SYp=5m*LqIdUof=?bAzB^^1?wEUucB>i?T+>gMnON=@5_=kCRs?vpen!S7d|T zFkJH8I}<+BUX4rxWXDqKkE()g-}8Tk|Ikm&wQ*0!h@wTefDEiSlg09y6SJVPxejAe zV6V)l`WDG`8Gh*L3c`yh$GJ)OwW}uxVY4TtQM2*i$~42rbQ09W9Fs*Cx-uM7-!Hs^ zrCuvqnr1KaHZN)0va+u#9uqnGO>?dM18eFxXYpCnlCN7(!ts<9OQPUaDgns3i4T9< zBEIO)rhHHi;3D}iZ4qR|9;Q!ZxDu%hAOaXq;+GSZI&Nno&cxx2_I7`>Rnk_ytm4YL z9)1!Z6Y~Z~26#M$O?p_hH`KS@e*eJy0x6Z*YK!^Mv#tcJGp_l0*p(e*ZfgSc(nNUI z96C%;o47Eg!s`qpcKvl%J{EN}2-StY=4AR*Zq4uoFt_;!#vj(0x*|2p<|q@`ZGNvX z%xXQ>j%V=DdGJt$B5F4;o19{GweCoFN?9DZPgk4_YIZRiS?I{x8!Q-VXzl*Vftyo? ztD!a#RnZiRQtud;G3}L_n#Z>4ikdBXDE13i z+q{^tz~4*IVY?p86Q$@JX25Qh=yCO(U!UQnVki=TaZ_Qnx5}8R*amm_!TlxDsd*NJ2Mt?6i&RmHQGi+T0 z0|-atYX9jMYe}ZdnQ_*A*XJv7gi-gV>6jzD#mpD&uuJ(wtrW+Dz~fI~0R4JcuLOc-uS8TiZrqf`KrZ7zEuq>NfW6Bg{L z6Od&nup&|p%C*+ahqp6ZwerijoZ(xw<5VgZK6Ojk(NQ>tnY{7EB_n@}wV4hfylA;n zQ;{Bg6~mGcG(Y!2+rk?v7SUrap3-B^|31$@DduVygTL`fes`Fd)`m_izy+YC89)K3 zTf@NtD}XcuSO8_?X2EwBg#e&R+AK(GC4dG90n)Tk0F>}^R#hH8ptPt4U9L0IBK1}KoX^>=f z$jibx94Sd*oqPhC0{l?$ZEjU5Q3M=8byi^txM ztRm`w(h*1!pb%DB3J58Dzk)bc?Tzg%WD)9a2<(nOCZjx{%YO#uCQ*)r+(->w(1rZ> zPpkP=Z7?Un9M=S9am}-;KHe*9iFHlX{ z&dC9bT?NrXp_-LMOa7u%g0T_OAY2KXQsNlt!tn9RK(cnS@bP$Q)iKQpO6V!o-(*5U zyhF@=MbRM_M3N==!NTBHlKnUnf)BC~l}TYWlyZN*$6QGaM)o`I0%raXk?C1?vzCf zRE7Ykz(D5*x#&l9$Dr_sROrT&>ztOa$2cIgCoUZ+{7FWG{?VnfsIKK8�sU8OPTQLlZ0_manZTg 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 KVI`{olK%sgX7jiJ delta 112169 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

e>RuL1& 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%0A5TkiD!tPQCh=#>oX$g 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

o-sE(u4sSRzBfq#Ewp8n&ZJPpZ&*N< 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 From 424c3d0c6fb3cb168c29d0bf9ca5b90972466749 Mon Sep 17 00:00:00 2001 From: Leon Date: Sun, 16 Jun 2024 15:34:22 +0200 Subject: [PATCH 08/56] version_16.06 with questions in yellow --- ...k_master_thesis_branching_Leon_Stanzel.pdf | Bin 200223 -> 205905 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/in_work_master_thesis_branching_Leon_Stanzel.pdf b/in_work_master_thesis_branching_Leon_Stanzel.pdf index 1c34bb340886bd14a41309978c4eeaff49084e3a..f18ee7400c48b90fb5b8fa2501e6ad1b42712254 100644 GIT binary patch delta 5523 zcmb_geQX>@6;ERY&^f6D5fVX28BjlLwb`ASo&9QEi?h$yShcaSO_SiB#KpH~UwXbh z_VyA7st$p~{DX>tR<3BO7K$1bi4X}y(+X&-_KyNBQYF+sDMbnhBwDGer~skxX7+2& zcecrgrMvUKotZc9z2E!2dGo~C-EX|Q`)j9fIKA`defw|xsDUu@j~>en4e9wt!w*~Q zx0H8|aB8{mVg^wgi{Fwy>Ni5K5w;K$&-$cSsg+0km3er=$RZTkE-mTP3tkIRDwosePBuLlwCD{F=e$NmC^lhe#|GvRHP&wncHYaW9dE*sn?TfwpWTg{ zvZTH%-4u(q*<(}Ee4gw}4v^l_XWK_ZVZ*`N;!+(xp+1d-3up8qV*2Dj;SP!^!xpiK zVHgyD5#w7i9@J;Ng>W9(6j`pu3`{998P+hS1QX;E&2}wHz{~T9AkAfj*cRd%1CRR6 zb~6csKAJ~F9}T>6So0f&a_DWU@bm3*W!kSn#9&EK;2Mn4OjR%S>Np2$1~=T!eF~wJ zfgKJkX%X8%gjt$xIksVDGSyDyePVk_&rbv1J_lym!gs^)m%t$coCE|Pity6udFc>+ zs_8XQwOns`;CSl9{uMYpKpl-@1E2$lR9qWFGX}P*P(k2?*H{df5XBf&bBOcdsiVgr zbZOj+ez2^IFM$b&#fZ!S)!v?Qoh*kz4U&a`xfs3=z>EW#JJLh}uS^I2!mJn0>(jhY zEJ@e2LWubCo?HeEjiF#Mr`g297DXp=N`%uOEvwQ5VyK?$vB6GhvH}Nj6_hvzB`zpY zty~sQDF*5}CCa^}iLr7`5$wpQEbJnMV;+d3z}+bR|6dG*W0~b7IYp^vSf=Zi^o_oU zfhE98Oidjg2ZtvS2RRpU28;@PNQ~-t2Y$N=Z)WwmpxkIR1=}s0?1+&B2P*ivUN#D} zciKn=&^Eyt?*`iSH*)e&aVoY`lIZZTKDH9xJsXxo?t!T@7(C!49)Pq-z$o4DLgW%Pqyn}tyu?WrjX#0{?)miOrUbGj8RVxHdq%2Gsn`H zYYTEST+MY2*MNVqqd68pJ!N4Y(Xhh8Q61Wrg)@~Z3me$g9NV#7Bh%G$11KH|_8SQH zsX;yI+-oL;EEEr}Daf5Vj%G6ojF8F1fYe-NKqAYy*xAU%JV&L$n@3ZXJpIGkKI(nCkCZ_dX`tg~1x z=M-`348grUPzYkK$g@=hCwG`AsW=OG9ir9^gAQpD`^~u6iMW`{Q(+v0tKedQWt3W1 z$;DhHS#YRK%7z@7%0y0DrbekPm{?gq6^aq2q1m=L{;MN;3N6OB z(AIN$#20c~>5_^p-AHr-j69tQB?+mMdD5grBhw|fw?m9z6sVtUu(YQzT{zk+vrShz zig$Y|ov#i}g`H{{bX5cxSJ{dfkm8MI0}@$Q3|%OOd_!j<5x02?Y+DRX0crs>(U_#L zOPl7nyUmIrr>;^BlVa!)y;!S157D^^tGrS5ns{ z1#-LkxNI zmoKLWcfOn+McwZ1JipB^ubpG ztgJb?0wcGu5&HkEBFYH#Dv0hi6ht{!&FGGTc-L0l33SA%yYlUD$qxnwJ8ovyPxbfh zJsgSPMF)X?dgnH)n{v8@t`-spusziD6#Yz-w)xoPIQO*c%$mW z4HAzY3iCtEv>cK*@|fZLm{p`U!=si-*k~Rb1Y7p-khm!`$DE=&mUkSZ=(15b39ur~ zlQD~0c{W_q4+#!p2(A{#8x;?3P~gG|neYMsLz#tJN+_k!p$KKQ|fJ3jpH|DIcXfW7hh zMBzWr{lIzY`4<}>H=I2eSO2{0r+xgJPp&pkEuFr2=u>O;wR_iovNm;WKYj9n!tjm` b9!Y7W6_$f=1tOoL*fbf*-F)-dR5ABIZVCGG delta 15 Wcmcb3f@l65o`x327N#xC@_Ya_Xa!sV From efd0ed324d035af0866252d1e45908a40458e7d0 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 3 Jul 2024 17:32:24 +0200 Subject: [PATCH 09/56] modified example to use the diffw = Random.rand(Bool, n) * 0.6 .+ 0.3 from approx planted example, also added a \mu for a potential branching score function --- examples/HiGHS_example_PSEUDO_COST.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/HiGHS_example_PSEUDO_COST.jl b/examples/HiGHS_example_PSEUDO_COST.jl index 5385f4ccd..020bf7cc6 100644 --- a/examples/HiGHS_example_PSEUDO_COST.jl +++ b/examples/HiGHS_example_PSEUDO_COST.jl @@ -7,9 +7,9 @@ import MathOptInterface const MOI = MathOptInterface -n = 6 +n = 7 -const diffw = 0.5 * ones(n) +const diffw = Random.rand(Bool, n) * 0.6 .+ 0.3 o = HiGHS.Optimizer() MOI.set(o, MOI.Silent(), true) @@ -33,4 +33,5 @@ end #pseudos = Dict{Int,Array{Float64}}(idx=>zeros(2) for idx in Boscia.get_integer_variables(lmo)) #branch_tracker = Dict{Int, Float64}(idx=> 0 for idx in Boscia.get_integer_variables(lmo)) iterations_stable = 1::Int -x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo), verbose=true) \ No newline at end of file +μ = 0.7 # μ used in the computation of the branching score +x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) \ No newline at end of file From ff5afa75812f01c70d64da126dced01c7166c06c Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 3 Jul 2024 17:34:45 +0200 Subject: [PATCH 10/56] This version should perform updates to pseudocosts without extra effort. Current version runs but on the HiGHS_example with diffw = Random.rand(Bool, n) * 0.6 .+ 0.3 it does not change strategy before solving the problem. --- src/pseudo_branching.jl | 179 +++++++++++----------------------------- 1 file changed, 48 insertions(+), 131 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 965faf09a..235dc1470 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -1,7 +1,10 @@ +using SparseArrays + struct PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int stable::Bool bounded_lmo::BLMO + μ::Float64 end # """ Function that keeps track of which branching candidates are stable """ @@ -15,123 +18,6 @@ end # end -function pseudo_weight_update!( - tree::Bonobo.BnBTree, - node::Bonobo.AbstractNode, - idx::Int, - values, - pseudos::Dict{Int,Array{Float64}}, - branch_tracker::Dict{Int, Int}, - branching::PSEUDO_COST{BLMO} -) where BLMO <: BoundedLinearMinimizationOracle - @assert !isempty(node.active_set) - active_set = copy(node.active_set) - empty!(active_set) - current_dual_gap = node.dual_gap# if this is a fw_node this should be the fw_dual_gap - - fx = floor(values[idx]) - # create LMO - boundsLeft = copy(node.local_bounds) - if haskey(boundsLeft.upper_bounds, idx) - delete!(boundsLeft.upper_bounds, idx) - end - push!(boundsLeft.upper_bounds, (idx => fx)) - build_LMO( - branching.bounded_lmo, - tree.root.problem.integer_variable_bounds, - boundsLeft, - Bonobo.get_branching_indices(tree.root), - ) - status = check_feasibility(branching.bounded_lmo) - if status == OPTIMAL - empty!(active_set) - for (λ, v) in node.active_set - if v[idx] <= values[idx] - push!(active_set, ((λ, v))) - end - end - @assert !isempty(active_set) - FrankWolfe.active_set_renormalize!(active_set) - x, primal, dual_gap, active_set - _, _, primal_relaxed, dual_gap_relaxed, _ = - FrankWolfe.blended_pairwise_conditional_gradient( - tree.root.problem.f, - tree.root.problem.g, - branching.bounded_lmo, - active_set, - verbose=false, - epsilon=branching.solving_epsilon, - max_iteration=5, - ) - left_update = current_dual_gap - dual_gap_relaxed - else - @debug "Left non-optimal status $(status)" - left_update = Inf - end - - #right node: x_i >= floor(̂x_i) - cx = ceil(values[idx]) - boundsRight = copy(node.local_bounds) - if haskey(boundsRight.lower_bounds, idx) - delete!(boundsRight.lower_bounds, idx) - end - push!(boundsRight.lower_bounds, (idx => cx)) - build_LMO( - branching.bounded_lmo, - tree.root.problem.integer_variable_bounds, - boundsRight, - Bonobo.get_branching_indices(tree.root), - ) - status = check_feasibility(branching.bounded_lmo) - if status == OPTIMAL - empty!(active_set) - for (λ, v) in node.active_set - if v[idx] >= values[idx] - push!(active_set, (λ, v)) - end - end - if isempty(active_set) - @show values[idx] - @show length(active_set) - @info [active_set.atoms[idx] for idx in eachindex(active_set)] - error("Empty active set, unreachable") - end - FrankWolfe.active_set_renormalize!(active_set) - _, _, primal_relaxed, dual_gap_relaxed, _ = - FrankWolfe.blended_pairwise_conditional_gradient( - tree.root.problem.f, - tree.root.problem.g, - branching.bounded_lmo, - active_set, - verbose=false, - epsilon=branching.solving_epsilon, - max_iteration=5, - ) - right_update = current_dual_gap - dual_gap_relaxed - else - @debug "Right non-optimal status $(status)" - right_update = Inf - end - # reset LMO - build_LMO( - branching.bounded_lmo, - tree.root.problem.integer_variable_bounds, - node.local_bounds, - Bonobo.get_branching_indices(tree.root), - ) - pseudos[idx][1] = update_avg(left_update, pseudos[idx][1], branch_tracker[idx]) - pseudos[idx][2] = update_avg(right_update, pseudos[idx][2], branch_tracker[idx]) - branch_tracker[idx] += 1 -end - -function best_pseudo_choice(# currently not in use. To be implemented later in order to improve readability - tree::Bonobo.BnBTree, -) - branching_candidates = Bonobo.get_branching_indices(tree.root) - return argmax(map(idx-> maximum(pseudos[idx]), branching_candidates)) -end - - """ get_branching_variable( tree::Bonobo.BnBTree, @@ -148,23 +34,44 @@ function Bonobo.get_branching_variable( branching::PSEUDO_COST{BLMO}, node::Bonobo.AbstractNode, ) where BLMO <: BoundedLinearMinimizationOracle - #the following should create the dictionaries only on first function call and then use existing ones - local pseudos = Dict{Int,Array{Float64}}(idx=>zeros(2) for idx in Boscia.get_integer_variables(branching.bounded_lmo)) - local branch_tracker = Dict{Int, Int}(idx=> 0 for idx in Boscia.get_integer_variables(branching.bounded_lmo)) + #the following should create the arrays and vectors only on first function call and then use existing one + local pseudos = sparse( + repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), + ones(2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) + ) + local branch_tracker = sparse( + repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), + ones(Int64, 2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) + ) + local call_tracker = 0 - + local strategy_switch = branching.iterations_until_stable + 1 + best_idx = -1 all_stable = true for idx in Bonobo.get_branching_indices(tree.root) - if branch_tracker[idx] >= branching.iterations_until_stable - all_stable = true - else + if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch all_stable = false break end end if !all_stable# THEN Use Most Infeasible values = Bonobo.get_relaxed_values(tree, node) + if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + idx = node.branched_on + update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base + if node.branched_right + pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) + branch_tracker[idx, 1] += 1 + + else + pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) + branch_tracker[idx, 2] += 1 + + end + end max_distance_to_feasible = 0.0 for i in Bonobo.get_branching_indices(tree.root) value = values[i] @@ -176,30 +83,40 @@ function Bonobo.get_branching_variable( end end end - if best_idx != -1 - pseudo_weight_update!(tree, node, best_idx, values, pseudos, branch_tracker, branching) - end + + # Instead of doing extra computations it makes more sense to + # save the current fw_dual_gap for the child nodes including which variable has been branched on + # and if the node is a result of an up or down branch + # then one updates the corresponding pseduo once the fw_dual_gap of the child nodes has been computed. + # Implementation idea: + # -> update FrankWolfeNode to store above mentioned information + # -> update get_branching_nodes_info in order for new nodes to be created with updated information + # -> + println(best_idx) return best_idx else - println("Pseudos are stable") + #println("Pseudos are stable") + values = Bonobo.get_relaxed_values(tree, node) # Pseudocosts have stabilized call_tracker +=1 println("pseudocosts have stabilized ", call_tracker) branching_candidates = Bonobo.get_branching_indices(tree.root) best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later + #best_idx = argmax(map(idx-> (1-μ)*minimum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) + μ * maximum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) )) + println(best_idx) return best_idx end end function update_avg(new_val::Float64, avg::Float64, N::Int) # N is the number of values used to compute the current avg - # avg is the current average + # avg is the current average shifted by 1 # new_val is the value that the current average has to be updated with if N > 1 - return 1/(N+1) * (N * avg + new_val) + return 1/(N+1) * (N * (avg - 1) + new_val) + 1 # else - return new_val + return new_val+ avg # note that we initialize the pseudo costs with 1 as such we need to shift pseudocosts correspondingly end end #pseudos = Dict{Int,Array{Float64}}(i=>zeros(2) for idx in get_integer_variables(blmo)) From 0c53bfc6e8ff914ed4dfbf72c36370159ae75487 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 3 Jul 2024 17:36:18 +0200 Subject: [PATCH 11/56] changed FrankWolfeNode to include additional information and added constructor --- src/node.jl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/node.jl b/src/node.jl index c8af87ac3..6a99f44af 100644 --- a/src/node.jl +++ b/src/node.jl @@ -58,8 +58,24 @@ mutable struct FrankWolfeNode{ local_tightenings::Int local_potential_tightenings::Int dual_gap::Float64 + parent_lower_bound_base::Float64 + branched_on::Int + branched_right::Bool end +# For i.e. pseudocost branching we require additional information to be stored in FrankWolfeNode +# this information can be set to a default value if not needed. +FrankWolfeNode( + std, active_set, discarded_vertices, + local_bounds, level, fw_dual_gap_limit, + fw_time, global_tightenings, local_tightenings, + local_potential_tightenings, dual_gap + ) = + FrankWolfeNode(std, active_set, discarded_vertices, + local_bounds, level, fw_dual_gap_limit, + fw_time, global_tightenings, local_tightenings, + local_potential_tightenings, dual_gap, Inf, -1, false) + """ Create the information of the new branching nodes based on their parent and the index of the branching variable @@ -142,6 +158,9 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN local_tightenings=0, local_potential_tightenings=0, dual_gap=NaN, + parent_lower_bound_base=lower_bound_base, + branched_on=vidx, + branched_right=false, ) node_info_right = ( active_set=active_set_right, @@ -154,6 +173,9 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN local_tightenings=0, local_potential_tightenings=0, dual_gap=NaN, + parent_lower_bound_base=lower_bound_base, + branched_on=vidx, + branched_right=true, ) # in case of non trivial domain oracle: Only split if the iterate is still domain feasible From 400063cb53138c6ef35abef2b1f5e597dbc9f268 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 3 Jul 2024 17:36:48 +0200 Subject: [PATCH 12/56] added SparseArrays --- src/Boscia.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Boscia.jl b/src/Boscia.jl index d4361ad91..731132a1f 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -8,6 +8,7 @@ import Bonobo using Printf using Dates using MathOptInterface +using SparseArrays const MOI = MathOptInterface const MOIU = MOI.Utilities import MathOptSetDistances as MOD From 069cd5d0030c60c67949092fac2d392aeff95d77 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 3 Jul 2024 17:38:46 +0200 Subject: [PATCH 13/56] changed Bonbo.set_root! to also have the default information used by pseudocost branching --- src/interface.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interface.jl b/src/interface.jl index 65fe63ad9..a0b370206 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -221,6 +221,9 @@ function solve( local_tightenings=0, local_potential_tightenings=0, dual_gap=-Inf, + parent_lower_bound_base=Inf, + branched_on=-1, + branched_right=false ), ) From b88555b1bc24ea22c08d5b9ba98c004577220a44 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 3 Jul 2024 17:58:37 +0200 Subject: [PATCH 14/56] Modified example only to the extend needed to use pseudocost strategy --- examples/portfolio_pseudocost.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/portfolio_pseudocost.jl b/examples/portfolio_pseudocost.jl index 2aa68759f..91a2826b4 100644 --- a/examples/portfolio_pseudocost.jl +++ b/examples/portfolio_pseudocost.jl @@ -59,8 +59,9 @@ const Mi = (Ai + Ai') / 2 heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.2, :follow_gradient) heuristics = [heu] # heuristics = [] - iterations_stable = 3::Int# how many times until we consider a pseudocost as stable - x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo), verbose=true, time_limit=600, custom_heuristics=heuristics) + iterations_stable = 3 # how many times until we consider a pseudocost as stable + μ = 0.7 # μ used in the computation of the branching score + x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true, time_limit=600, custom_heuristics=heuristics) @test dot(ai, x) <= bi + 1e-2 @test f(x) <= f(result[:raw_solution]) + 1e-6 end From 2fabd322cb1b881ad1f664b0ad2819b79a0e1d73 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 10 Jul 2024 14:20:03 +0200 Subject: [PATCH 15/56] Created a function pseudo_branch! to replace branch! in the case of pseudocost branch. --- src/custom_bonobo.jl | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index 0fcf91775..6e13040d1 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -27,7 +27,9 @@ which are set in the following ways: 2. If the node has a higher lower bound than the incumbent the kwarg `worse_than_incumbent` is set to `true`. """ function Bonobo.optimize!( - tree::Bonobo.BnBTree{<:FrankWolfeNode}; + tree::Bonobo.BnBTree{<:FrankWolfeNode}, + pseudos::SparseMatrixCSC{Float64, Int64}, + branch_tracker::SparseMatrixCSC{Int64, Int64}; callback=(args...; kwargs...) -> (), ) #println("OWN OPTIMIZE") @@ -72,7 +74,11 @@ function Bonobo.optimize!( end Bonobo.close_node!(tree, node) - Bonobo.branch!(tree, node) + if !isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) + Bonobo.branch!(tree, node) + else + pseudo_branch!(tree, node, pseudos, branch_tracker) + end callback(tree, node) end return Bonobo.sort_solutions!(tree.solutions, tree.sense) @@ -115,3 +121,23 @@ function Bonobo.get_solution( end return tree.solutions[result].solution end + +""" + pseudo_branch!(tree, node, pseudos, branch_tracker) + +Get the branching variable with [`get_branching_variable`](@ref) and then calls [`get_branching_nodes_info`](@ref) and [`add_node!`](@ref). +""" +function pseudo_branch!( + tree::Bonobo.BnBTree{<:FrankWolfeNode}, + node::Bonobo.AbstractNode, + pseudos::SparseMatrixCSC{Float64, Int64}, + branch_tracker::SparseMatrixCSC{Int64, Int64} + ) + variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker) + # no branching variable selected => return + variable_idx == -1 && return + nodes_info = Bonobo.get_branching_nodes_info(tree, node, variable_idx) + for node_info in nodes_info + Bonobo.add_node!(tree, node, node_info) + end +end From 7ebecb0f6db2201bd50be9ce602f032193895feb Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 10 Jul 2024 14:22:15 +0200 Subject: [PATCH 16/56] moved pseudos and branch_tracker sparse arrays to be created before calling optimize. Before having them in get_branching_variable caused them to be reset on every call which made a strategy switch impossible --- src/interface.jl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/interface.jl b/src/interface.jl index a0b370206..1aba92b18 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -293,8 +293,19 @@ function solve( tree.root.options[:callback] = fw_callback tree.root.current_node_id[] = Bonobo.get_next_node(tree, tree.options.traverse_strategy).id + #the following should create the arrays and vectors only on first function call and then use existing one + pseudos = sparse( + repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), + ones(2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) + ) + branch_tracker = sparse( + repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), + ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) + ) - Bonobo.optimize!(tree; callback=bnb_callback) + Bonobo.optimize!(tree, pseudos, branch_tracker; callback=bnb_callback) x = postsolve(tree, result, time_ref, verbose, max_iteration_post) From e6768d8174804718f3b02a554e8af60c0219a6c9 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 10 Jul 2024 14:23:13 +0200 Subject: [PATCH 17/56] passed pseudos and branch_tracker as function arguments to get_branching_variable --- src/pseudo_branching.jl | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 235dc1470..61669e250 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -33,21 +33,23 @@ function Bonobo.get_branching_variable( tree::Bonobo.BnBTree, branching::PSEUDO_COST{BLMO}, node::Bonobo.AbstractNode, + pseudos::SparseMatrixCSC{Float64, Int64}, + branch_tracker::SparseMatrixCSC{Int64, Int64}, ) where BLMO <: BoundedLinearMinimizationOracle #the following should create the arrays and vectors only on first function call and then use existing one - local pseudos = sparse( - repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), - ones(2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) - ) - local branch_tracker = sparse( - repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), - ones(Int64, 2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) - ) + # local pseudos = sparse( + # repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), + # vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), + # ones(2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) + # ) + # local branch_tracker = sparse( + # repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), + # vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), + # ones(Int64, 2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) + # ) - local call_tracker = 0 - local strategy_switch = branching.iterations_until_stable + 1 + #local call_tracker = 0 + strategy_switch = branching.iterations_until_stable + 1 best_idx = -1 all_stable = true @@ -60,6 +62,7 @@ function Bonobo.get_branching_variable( if !all_stable# THEN Use Most Infeasible values = Bonobo.get_relaxed_values(tree, node) if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + #println("if clause of update") idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base if node.branched_right @@ -71,6 +74,10 @@ function Bonobo.get_branching_variable( branch_tracker[idx, 2] += 1 end + # println("pseudos") + # display(pseudos) + # println("\n branch_tracker") + # display(branch_tracker) end max_distance_to_feasible = 0.0 for i in Bonobo.get_branching_indices(tree.root) @@ -92,19 +99,19 @@ function Bonobo.get_branching_variable( # -> update FrankWolfeNode to store above mentioned information # -> update get_branching_nodes_info in order for new nodes to be created with updated information # -> - println(best_idx) + #println(best_idx) return best_idx else #println("Pseudos are stable") values = Bonobo.get_relaxed_values(tree, node) # Pseudocosts have stabilized call_tracker +=1 - println("pseudocosts have stabilized ", call_tracker) + println("pseudocosts decision is made") branching_candidates = Bonobo.get_branching_indices(tree.root) - best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later - #best_idx = argmax(map(idx-> (1-μ)*minimum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) + μ * maximum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) )) - println(best_idx) + #best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later + best_idx = argmax(map(idx-> (1-μ)*minimum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) + μ * maximum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) )) + #println(best_idx) return best_idx end end From 0580269f4d9d9aaf9994371a4ded77962f812f8f Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 10 Jul 2024 19:43:17 +0200 Subject: [PATCH 18/56] Example where pseudocost decisions are made occasionaly (depends on the instance generated) --- examples/sparse_regression_pseudocost.jl | 87 ++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 examples/sparse_regression_pseudocost.jl diff --git a/examples/sparse_regression_pseudocost.jl b/examples/sparse_regression_pseudocost.jl new file mode 100644 index 000000000..0f0916382 --- /dev/null +++ b/examples/sparse_regression_pseudocost.jl @@ -0,0 +1,87 @@ +using Statistics +using Boscia +using FrankWolfe +using Random +using LinearAlgebra +using SCIP +#using HiGHS +import Bonobo +import MathOptInterface +const MOI = MathOptInterface +using Dates +using Printf +using Test + +# Sparse regression + +# Constant parameters for the sparse regression +# min norm(y-A β)² + λ_0 ∑ z_i + λ_2 ||β||² +# s.t. -Mz_i <= β_i <= Mz_i +# ∑ z_i <= k +# z_i ∈ {0,1} for i = 1,..,p + +# A - matrix of observations. +# y - vector of results. +# We want to match Aβ as closely as possible to y +# while having relative few non zero entries in β. +# Each continuous variable β_i is assigned a binary z_i, +# z_i = 0 => β_i = 0 + + +n0 = 20; +p = 5 * n0; +k = ceil(n0 / 5); +const lambda_0 = rand(Float64); +const lambda_2 = 10.0 * rand(Float64); +const A = rand(Float64, n0, p) +const y = rand(Float64, n0) +const M = 2 * var(A) + +# "Sparse Regression" +@testset "Sparse regression" begin + o = SCIP.Optimizer() + #o = HiGHS.Optimizer() + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, 2p) + for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() + end + for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) + end + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), + ) + lmo = Boscia.MathOptBLMO(o) + + function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 + end + + function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage + end + iterations_stable = 1::Int + μ = 0.7 # μ used in the computation of the branching score + x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ),verbose=true, fw_epsilon=1e-3, print_iter=10) + + # @show result // too large to be output + @test f(x) <= f(result[:raw_solution]) + 1e-6 +end From 0895df76006271c1bfecc8412ed752adfd29b21b Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 10 Jul 2024 19:54:29 +0200 Subject: [PATCH 19/56] fixed some bugs and the pseudocost updates are now scaled. --- src/pseudo_branching.jl | 66 ++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 61669e250..41ea53012 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -50,69 +50,73 @@ function Bonobo.get_branching_variable( #local call_tracker = 0 strategy_switch = branching.iterations_until_stable + 1 - best_idx = -1 all_stable = true + branching_candidates = Int[]# this shall contain the indices of the potential branching variables + values = Bonobo.get_relaxed_values(tree, node) + branch_counter = [] for idx in Bonobo.get_branching_indices(tree.root) - if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch - all_stable = false - break + value = values[idx] + if !Bonobo.is_approx_feasible(tree, value) + push!(branching_candidates, idx) + push!(branch_counter, (branch_tracker[idx, 1], branch_tracker[idx, 2])) + if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx + all_stable = false + end end end + # if rand() > 0.95# for debugging on if strategy behaves as intended + # println("\n branch_counter") + # println(branch_counter) + # end + + length(branching_candidates) == 0 && return best_idx + length(branching_candidates) == 1 && return branching_candidates[1] if !all_stable# THEN Use Most Infeasible - values = Bonobo.get_relaxed_values(tree, node) if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable #println("if clause of update") idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base if node.branched_right + update = update / (ceil(values[idx]) - values[idx]) pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) branch_tracker[idx, 1] += 1 else + update = update / (values[idx] - floor(values[idx])) pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) branch_tracker[idx, 2] += 1 end # println("pseudos") # display(pseudos) - # println("\n branch_tracker") - # display(branch_tracker) + # if rand() > 0.99# for debugging on if strategy behaves as intended + # println("\n branch_tracker") + # println(sum(branch_tracker)) + # end end max_distance_to_feasible = 0.0 - for i in Bonobo.get_branching_indices(tree.root) + for i in branching_candidates value = values[i] - if !Bonobo.is_approx_feasible(tree, value) - distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) - if distance_to_feasible > max_distance_to_feasible - best_idx = i - max_distance_to_feasible = distance_to_feasible - end + distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) + if distance_to_feasible > max_distance_to_feasible + best_idx = i + max_distance_to_feasible = distance_to_feasible end end - - # Instead of doing extra computations it makes more sense to - # save the current fw_dual_gap for the child nodes including which variable has been branched on - # and if the node is a result of an up or down branch - # then one updates the corresponding pseduo once the fw_dual_gap of the child nodes has been computed. - # Implementation idea: - # -> update FrankWolfeNode to store above mentioned information - # -> update get_branching_nodes_info in order for new nodes to be created with updated information - # -> #println(best_idx) return best_idx else - #println("Pseudos are stable") - values = Bonobo.get_relaxed_values(tree, node) # Pseudocosts have stabilized - call_tracker +=1 println("pseudocosts decision is made") - - branching_candidates = Bonobo.get_branching_indices(tree.root) #best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later - best_idx = argmax(map(idx-> (1-μ)*minimum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) + μ * maximum(pseudos[idx] .* [values[idx] - floor(values[idx]), ceil(values[idx]) - values[idx]]) )) - #println(best_idx) - return best_idx + #inner = pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]) + + branching_scores = map(idx-> ((1 - branching.μ) * min(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx])) + branching.μ * max(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]))), + branching_candidates) + branching_scores = sparsevec(branching_candidates, branching_scores) + best_idx = argmax(branching_scores) + return best_idx end end From 5c5cfbdc1c53fabcf3e8736f2d6c967ea0eb78c0 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 11 Jul 2024 11:06:31 +0200 Subject: [PATCH 20/56] moved pseudo cost updates to also be made when pseudocost decisions are made. --- src/pseudo_branching.jl | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 41ea53012..72b4543fa 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -69,32 +69,32 @@ function Bonobo.get_branching_variable( # println("\n branch_counter") # println(branch_counter) # end + if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + #println("if clause of update") + idx = node.branched_on + update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base + if node.branched_right + update = update / (ceil(values[idx]) - values[idx]) + pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) + branch_tracker[idx, 1] += 1 + + else + update = update / (values[idx] - floor(values[idx])) + pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) + branch_tracker[idx, 2] += 1 + + end + # println("pseudos") + # display(pseudos) + # if rand() > 0.99# for debugging on if strategy behaves as intended + # println("\n branch_tracker") + # println(sum(branch_tracker)) + # end + end length(branching_candidates) == 0 && return best_idx length(branching_candidates) == 1 && return branching_candidates[1] if !all_stable# THEN Use Most Infeasible - if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable - #println("if clause of update") - idx = node.branched_on - update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base - if node.branched_right - update = update / (ceil(values[idx]) - values[idx]) - pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) - branch_tracker[idx, 1] += 1 - - else - update = update / (values[idx] - floor(values[idx])) - pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) - branch_tracker[idx, 2] += 1 - - end - # println("pseudos") - # display(pseudos) - # if rand() > 0.99# for debugging on if strategy behaves as intended - # println("\n branch_tracker") - # println(sum(branch_tracker)) - # end - end max_distance_to_feasible = 0.0 for i in branching_candidates value = values[i] From f448a3d6b13bd0f181dd10d44e0127a97aec7596 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 11 Jul 2024 12:31:39 +0200 Subject: [PATCH 21/56] made changes such that other branching_strategies continue to work. --- src/interface.jl | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 1aba92b18..6f6a41404 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -294,17 +294,22 @@ function solve( tree.root.options[:callback] = fw_callback tree.root.current_node_id[] = Bonobo.get_next_node(tree, tree.options.traverse_strategy).id #the following should create the arrays and vectors only on first function call and then use existing one - pseudos = sparse( - repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), - ones(2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) - ) - branch_tracker = sparse( - repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), - ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) - ) - + if isa(branching_strategy, Boscia.PSEUDO_COST) + pseudos = sparse( + repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), + ones(2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) + ) + branch_tracker = sparse( + repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), + ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) + ) + else + pseudos = sparse([1], [1], [0.0]) + + branch_tracker = sparse([1], [1], Int[0]) + end Bonobo.optimize!(tree, pseudos, branch_tracker; callback=bnb_callback) x = postsolve(tree, result, time_ref, verbose, max_iteration_post) From 33590e60ab3699d319d6abd5b4091cca60613535 Mon Sep 17 00:00:00 2001 From: Leon Date: Sat, 13 Jul 2024 19:54:25 +0200 Subject: [PATCH 22/56] changes to interface in order to match change to nodes --- src/interface.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 6f6a41404..9a76bf2be 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -160,7 +160,7 @@ function solve( 0, 0, 0, - 0.0, + 0.0 ) # Create standard heuristics @@ -223,7 +223,8 @@ function solve( dual_gap=-Inf, parent_lower_bound_base=Inf, branched_on=-1, - branched_right=false + branched_right=false, + distance_to_int=0.0 ), ) From c9f9c21c1934d97d7cecb6ea36efd7ce0915ea58 Mon Sep 17 00:00:00 2001 From: Leon Date: Sat, 13 Jul 2024 19:57:19 +0200 Subject: [PATCH 23/56] added distance to integer feasibility of parent node in order to allow updates to be made scaled to unit cost. Previously this was done incorrectly --- src/node.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/node.jl b/src/node.jl index 6a99f44af..95a5fee08 100644 --- a/src/node.jl +++ b/src/node.jl @@ -61,6 +61,7 @@ mutable struct FrankWolfeNode{ parent_lower_bound_base::Float64 branched_on::Int branched_right::Bool + distance_to_int::Float64 end # For i.e. pseudocost branching we require additional information to be stored in FrankWolfeNode @@ -74,7 +75,7 @@ FrankWolfeNode( FrankWolfeNode(std, active_set, discarded_vertices, local_bounds, level, fw_dual_gap_limit, fw_time, global_tightenings, local_tightenings, - local_potential_tightenings, dual_gap, Inf, -1, false) + local_potential_tightenings, dual_gap, Inf, -1, false, 0.0) """ Create the information of the new branching nodes @@ -90,6 +91,9 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN primal = tree.root.problem.f(x) lower_bound_base = primal - node.dual_gap @assert isfinite(lower_bound_base) + left_distance = x[vidx] - floor(x[vidx]) + right_distance = ceil(x[vidx]) - x[vidx] + # In case of strong convexity, check if a child can be pruned prune_left, prune_right = prune_children(tree, node, lower_bound_base, x, vidx) @@ -161,6 +165,7 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN parent_lower_bound_base=lower_bound_base, branched_on=vidx, branched_right=false, + distance_to_int=left_distance, ) node_info_right = ( active_set=active_set_right, @@ -176,6 +181,7 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN parent_lower_bound_base=lower_bound_base, branched_on=vidx, branched_right=true, + distance_to_int=right_distance, ) # in case of non trivial domain oracle: Only split if the iterate is still domain feasible From 7ebb308a721628dec3322265f3396cb14b563501 Mon Sep 17 00:00:00 2001 From: Leon Date: Sat, 13 Jul 2024 19:59:05 +0200 Subject: [PATCH 24/56] added another decision function (product) and made changes to how updates are scaled. the previous version scaled updates incorrectly resulting in only Inf value updates. --- src/pseudo_branching.jl | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 72b4543fa..bc9324ac0 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -5,6 +5,7 @@ struct PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBran stable::Bool bounded_lmo::BLMO μ::Float64 + decision_function::String end # """ Function that keeps track of which branching candidates are stable """ @@ -65,21 +66,24 @@ function Bonobo.get_branching_variable( end end end - # if rand() > 0.95# for debugging on if strategy behaves as intended - # println("\n branch_counter") - # println(branch_counter) - # end + if rand() > 0.99# for debugging on if strategy behaves as intended + println("\n branch_counter") + println(branch_counter) + end if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable #println("if clause of update") idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base + update = update / node.distance_to_int + if isinf(update) + @debug "update is $(Inf)" + end if node.branched_right - update = update / (ceil(values[idx]) - values[idx]) + #println(update) pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) branch_tracker[idx, 1] += 1 - else - update = update / (values[idx] - floor(values[idx])) + #println(update) pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) branch_tracker[idx, 2] += 1 @@ -108,14 +112,25 @@ function Bonobo.get_branching_variable( return best_idx else # Pseudocosts have stabilized - println("pseudocosts decision is made") + #println("pseudocosts decision is made") #best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later #inner = pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]) - branching_scores = map(idx-> ((1 - branching.μ) * min(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx])) + branching.μ * max(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]))), - branching_candidates) + if branching.decision_function == "weighted_sum" + #println(branching.decision_function) + branching_scores = map(idx-> ((1 - branching.μ) * min(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx])) + branching.μ * max(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]))), + branching_candidates) + + elseif branching.decision_function == "product" + #println(branching.decision_function) + branching_scores = map(idx-> max(pseudos[idx, 1] * (values[idx] - floor(values[idx])), branching.μ) * max(pseudos[idx, 2] * (ceil(values[idx]) - values[idx]), branching.μ), + branching_candidates) + + end branching_scores = sparsevec(branching_candidates, branching_scores) - best_idx = argmax(branching_scores) + #display(branching_scores) + best_idx = argmax(branching_scores) + #println(best_idx) return best_idx end end From 79d033217513123db77a0ad3005753edc5d3eb81 Mon Sep 17 00:00:00 2001 From: Leon Date: Fri, 2 Aug 2024 20:30:34 +0200 Subject: [PATCH 25/56] added a function to write out the content of results into 3 CSV files --- src/utilities.jl | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/utilities.jl b/src/utilities.jl index 2bdbc42ec..0fe2f2afe 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -230,6 +230,67 @@ function sparse_min_via_enum(f, n, k, values=fill(0:1, n)) end +function save_results( + result::Dict{Symbol, Any}, + settings::String, + example_name::String, + seed::UInt64, + file_name::String, + over_write::Bool + ) + + seed = string(seed) + l1 = []# save all keys with one entry only + l2 = []# save all vector results of length equal to that of result[:list_ub] + l3 = []# save all vector results of length equal to that of lmo_calls_per_layer + for key in keys(result) + if length(result[key]) == 1 || isa(result[key], String) + push!(l1, key) + elseif length(result[key]) == length(result[:list_ub]) + push!(l2, key) + elseif length(result[key]) == length(result[:lmo_calls_per_layer]) + push!(l3, key) + end + end + l11 = Dict(string(key) => result[key] for key in l1) + l22 = Dict(string(key) => result[key] for key in l2) + l33 = Dict(string(key) => result[key] for key in l3) + l11 = DataFrame(l11) + l11[:, :example_name] .= example_name + l11[:, :seed] .= seed + l11[:, :settings] .= settings + + l22 = DataFrame(l22) + l22[:, :settings] .= settings + l22[:, :example_name] .= example_name + l22[:, :seed] .= seed + + l33 = DataFrame(l33) + l33[:, :settings] .= settings + l33[:, :example_name] .= example_name + l33[:, :seed] .= seed + + file_name1 = "./results/" * file_name * "_summary.csv" + + + if over_write# will always over write file if true + append = false + else + if isfile(file_name1)# using this method the first line of the file will have column names + append = false + else + append = true + end + end + CSV.write(file_name1, l11, append= append) + + file_name2 = "./results/" * file_name * ".csv" + + CSV.write(file_name2, l22, append= append) + file_name3 = "./results/" * file_name * "_layers.csv" + CSV.write(file_name3, l33, append= append) +end + # utility function to print the values of the parameters _value_to_print(::Bonobo.BestFirstSearch) = "Move best bound" _value_to_print(::PartialStrongBranching) = "Partial strong branching" From f422ecce70d6eeff3733afd129a03a074b97492e Mon Sep 17 00:00:00 2001 From: Leon Date: Sun, 4 Aug 2024 17:51:56 +0200 Subject: [PATCH 26/56] modified the result saving function to be less error prone --- src/Boscia.jl | 2 ++ src/utilities.jl | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Boscia.jl b/src/Boscia.jl index 731132a1f..2c0c707f9 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -9,6 +9,8 @@ using Printf using Dates using MathOptInterface using SparseArrays +using CSV +using DataFrames const MOI = MathOptInterface const MOIU = MOI.Utilities import MathOptSetDistances as MOD diff --git a/src/utilities.jl b/src/utilities.jl index 0fe2f2afe..f9bf509b6 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -234,7 +234,7 @@ function save_results( result::Dict{Symbol, Any}, settings::String, example_name::String, - seed::UInt64, + seed, file_name::String, over_write::Bool ) @@ -244,12 +244,15 @@ function save_results( l2 = []# save all vector results of length equal to that of result[:list_ub] l3 = []# save all vector results of length equal to that of lmo_calls_per_layer for key in keys(result) - if length(result[key]) == 1 || isa(result[key], String) + if string(key) in ["dual_bound","dual_gap","heu_lmo_calls","lmo_calls","number_nodes","primal_objective","rel_dual_gap","status","total_time_in_sec"] push!(l1, key) - elseif length(result[key]) == length(result[:list_ub]) + elseif string(key) in ["global_tightenings", "list_active_set_size", "list_discarded_set_size", + "list_lb","list_lmo_calls_acc","list_num_nodes","list_time","list_ub","local_potential_tightenings","local_tightenings","node_level"] push!(l2, key) - elseif length(result[key]) == length(result[:lmo_calls_per_layer]) + elseif string(key) in ["active_set_size_per_layer", "discarded_set_size_per_layer", "lmo_calls_per_layer"] push!(l3, key) + elseif string(key) != "raw_solution" + println(key, " has not been saved ") end end l11 = Dict(string(key) => result[key] for key in l1) @@ -277,9 +280,9 @@ function save_results( append = false else if isfile(file_name1)# using this method the first line of the file will have column names - append = false - else append = true + else + append = false end end CSV.write(file_name1, l11, append= append) From 4351da9913a216f159748a16fd1f865ae2eb1138 Mon Sep 17 00:00:00 2001 From: Leon Date: Sun, 4 Aug 2024 17:53:05 +0200 Subject: [PATCH 27/56] modified the decision functions for branching variable selection --- src/pseudo_branching.jl | 57 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index bc9324ac0..002bf81d7 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -37,44 +37,36 @@ function Bonobo.get_branching_variable( pseudos::SparseMatrixCSC{Float64, Int64}, branch_tracker::SparseMatrixCSC{Int64, Int64}, ) where BLMO <: BoundedLinearMinimizationOracle - #the following should create the arrays and vectors only on first function call and then use existing one - # local pseudos = sparse( - # repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), - # vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), - # ones(2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) - # ) - # local branch_tracker = sparse( - # repeat(Boscia.get_integer_variables(branching.bounded_lmo), 2), - # vcat(ones(length(Boscia.get_integer_variables(branching.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching.bounded_lmo)))), - # ones(Int64, 2 * length(Boscia.get_integer_variables(branching.bounded_lmo))) - # ) - #local call_tracker = 0 strategy_switch = branching.iterations_until_stable + 1 best_idx = -1 all_stable = true branching_candidates = Int[]# this shall contain the indices of the potential branching variables values = Bonobo.get_relaxed_values(tree, node) - branch_counter = [] - for idx in Bonobo.get_branching_indices(tree.root) + # branch_counter = [] + # for idx in Bonobo.get_branching_indices(tree.root) + for idx in tree.branching_indices value = values[idx] if !Bonobo.is_approx_feasible(tree, value) push!(branching_candidates, idx) - push!(branch_counter, (branch_tracker[idx, 1], branch_tracker[idx, 2])) + # push!(branch_counter, (branch_tracker[idx, 1], branch_tracker[idx, 2])) if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx all_stable = false end end end - if rand() > 0.99# for debugging on if strategy behaves as intended - println("\n branch_counter") - println(branch_counter) - end + # if rand() > 0.5# for debugging on if strategy behaves as intended + # println("\n branch_counter") + # println(branch_counter) + # end if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable #println("if clause of update") idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base update = update / node.distance_to_int + # if rand() > 0.99 + # update += 0.1 + # end if isinf(update) @debug "update is $(Inf)" end @@ -95,7 +87,6 @@ function Bonobo.get_branching_variable( # println(sum(branch_tracker)) # end end - length(branching_candidates) == 0 && return best_idx length(branching_candidates) == 1 && return branching_candidates[1] if !all_stable# THEN Use Most Infeasible @@ -108,7 +99,6 @@ function Bonobo.get_branching_variable( max_distance_to_feasible = distance_to_feasible end end - #println(best_idx) return best_idx else # Pseudocosts have stabilized @@ -118,18 +108,33 @@ function Bonobo.get_branching_variable( if branching.decision_function == "weighted_sum" #println(branching.decision_function) - branching_scores = map(idx-> ((1 - branching.μ) * min(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx])) + branching.μ * max(pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]))), + branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), branching_candidates) elseif branching.decision_function == "product" #println(branching.decision_function) - branching_scores = map(idx-> max(pseudos[idx, 1] * (values[idx] - floor(values[idx])), branching.μ) * max(pseudos[idx, 2] * (ceil(values[idx]) - values[idx]), branching.μ), + branching_scores = map(idx-> max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), branching_candidates) - end branching_scores = sparsevec(branching_candidates, branching_scores) #display(branching_scores) - best_idx = argmax(branching_scores) + best_idx = argmax(branching_scores) + # max_distance_to_feasible = 0.0 + # best_idx_base = -1 + # for i in branching_candidates + # value = values[i] + # distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) + # if distance_to_feasible > max_distance_to_feasible + # best_idx_base = i + # max_distance_to_feasible = distance_to_feasible + # end + # end + # if best_idx != best_idx_base + # println(best_idx, best_idx_base) + # println("different branching decision made") + # end + + #println(pseudos[best_idx, 1], pseudos[best_idx,2]) #println(best_idx) return best_idx end @@ -142,7 +147,7 @@ function update_avg(new_val::Float64, avg::Float64, N::Int) if N > 1 return 1/(N+1) * (N * (avg - 1) + new_val) + 1 # else - return new_val+ avg # note that we initialize the pseudo costs with 1 as such we need to shift pseudocosts correspondingly + return new_val + avg # note that we initialize the pseudo costs with 1 as such we need to shift pseudocosts correspondingly end end #pseudos = Dict{Int,Array{Float64}}(i=>zeros(2) for idx in get_integer_variables(blmo)) From 42f2417271cf4ccfa1b8fd9e5c8a265b940665a4 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 28 Aug 2024 11:35:59 +0200 Subject: [PATCH 28/56] Changes to perform updates for nodes to be discarded due to lb >= incubent --- src/custom_bonobo.jl | 28 +++++++++++++++++++++++++++- src/pseudo_branching.jl | 28 ++++++++++++---------------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index 6e13040d1..b39d22906 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -38,6 +38,8 @@ function Bonobo.optimize!( lb, ub = Bonobo.evaluate_node!(tree, node) # if the problem was infeasible we simply close the node and continue if isnan(lb) && isnan(ub) + @debug "\n node closed without upd\n" + ## add the nodes which become infeasible to a special storage (yet to be implemented) Bonobo.close_node!(tree, node) callback(tree, node; node_infeasible=true) continue @@ -46,7 +48,31 @@ function Bonobo.optimize!( Bonobo.set_node_bound!(tree.sense, node, lb, ub) # if the evaluated lower bound is worse than the best incumbent -> close and continue - if node.lb >= tree.incumbent + if node.lb >= tree.incumbent + if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST)# In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable + #println("node closed but we do update anyway") + if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + #println("if clause of update") + idx = node.branched_on + update = lb - node.parent_lower_bound_base + update = update / node.distance_to_int + if isinf(update) + @debug "update is $(Inf)" + end + if node.branched_right + #println(update) + pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) + branch_tracker[idx, 1] += 1 + else + #println(update) + pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) + branch_tracker[idx, 2] += 1 + end + else + println(string("node.parent_lower_bound_base is ", node.parent_lower_bound_base)) + end + end + Bonobo.close_node!(tree, node) callback( tree, diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 002bf81d7..0679fa282 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -43,27 +43,31 @@ function Bonobo.get_branching_variable( all_stable = true branching_candidates = Int[]# this shall contain the indices of the potential branching variables values = Bonobo.get_relaxed_values(tree, node) - # branch_counter = [] + #branch_counter = [] # for idx in Bonobo.get_branching_indices(tree.root) for idx in tree.branching_indices value = values[idx] if !Bonobo.is_approx_feasible(tree, value) push!(branching_candidates, idx) - # push!(branch_counter, (branch_tracker[idx, 1], branch_tracker[idx, 2])) + #push!(branch_counter, (branch_tracker[idx, 1], branch_tracker[idx, 2])) + #push!(branch_counter, idx) if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx all_stable = false end end end - # if rand() > 0.5# for debugging on if strategy behaves as intended - # println("\n branch_counter") - # println(branch_counter) + # for entry in branch_counter + # if !isequal(branch_tracker[entry, 1], branch_tracker[entry, 2]) + # println("\n", entry,"\n") + # end + # #break # end - if node.parent_lower_bound_base != Inf# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable #println("if clause of update") idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base update = update / node.distance_to_int + # if rand() > 0.99 # update += 0.1 # end @@ -81,11 +85,7 @@ function Bonobo.get_branching_variable( end # println("pseudos") - # display(pseudos) - # if rand() > 0.99# for debugging on if strategy behaves as intended - # println("\n branch_tracker") - # println(sum(branch_tracker)) - # end + #display(pseudos) end length(branching_candidates) == 0 && return best_idx length(branching_candidates) == 1 && return branching_candidates[1] @@ -101,11 +101,7 @@ function Bonobo.get_branching_variable( end return best_idx else - # Pseudocosts have stabilized - #println("pseudocosts decision is made") - #best_idx = argmax(map(idx-> maximum(pseudos[idx]), branching_candidates))# argmax randomly chosen and to be replaced later - #inner = pseudos[idx, 1] * (values[idx] - floor(values[idx])), pseudos[idx, 2] * (ceil(values[idx]) - values[idx]) - + #println("\npd made\n") if branching.decision_function == "weighted_sum" #println(branching.decision_function) branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), From d0d9040d32c0ecf993453ed5c13c789d8d932c72 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 28 Aug 2024 11:40:33 +0200 Subject: [PATCH 29/56] poisson_reg run multiple examples with multiple strategies --- examples/poisson_reg_pseudocost.jl | 270 +++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 examples/poisson_reg_pseudocost.jl diff --git a/examples/poisson_reg_pseudocost.jl b/examples/poisson_reg_pseudocost.jl new file mode 100644 index 000000000..ec1c414db --- /dev/null +++ b/examples/poisson_reg_pseudocost.jl @@ -0,0 +1,270 @@ +using Boscia +using FrankWolfe +using Test +using Random +using HiGHS +# using Statistics +using LinearAlgebra +using Distributions +import MathOptInterface +const MOI = MathOptInterface + +# Poisson sparse regression + +# For bug hunting: +# seed = rand(UInt64) +# @show seed +# #seed = 0xfe03ee83ca373eab +# Random.seed!(seed) + +# min_{w, b, z} ∑_i exp(w x_i + b) - y_i (w x_i + b) + α norm(w)^2 +# s.t. -N z_i <= w_i <= N z_i +# b ∈ [-N, N] +# ∑ z_i <= k +# z_i ∈ {0,1} for i = 1,..,p + +# y_i - data points, poisson distributed +# X_i, b - coefficient for the linear estimation of the expected value of y_i +# w_i - continuous variables +# z_i - binary variables s.t. z_i = 0 => w_i = 0 +# k - max number of non zero entries in w + +# In a poisson regression, we want to model count data. +# It is assumed that y_i is poisson distributed and that the log +# of its expected value can be computed linearly. + +# n = 20 +# p = n + +# # underlying true weights +# const ws = rand(Float64, p) +# # set 50 entries to 0 +# for _ in 1:20 +# ws[rand(1:p)] = 0 +# end +# const bs = rand(Float64) +# const Xs = randn(Float64, n, p) +# const ys = map(1:n) do idx +# a = dot(Xs[idx, :], ws) + bs +# return rand(Distributions.Poisson(exp(a))) +# end +# Ns = 0.10 + +# TODO: document better + + + +function build_function(seed, n; Ns=0.0, use_scale=false) + Random.seed!(seed) + p = n + + # underlying true weights + ws = rand(Float64, p) + # set 50 entries to 0 + for _ in 1:20 + ws[rand(1:p)] = 0 + end + bs = rand(Float64) + Xs = randn(Float64, n, p) + for j in 1:p + Xs[:,j] ./= (maximum(Xs[:,j]) - minimum(Xs[:,j])) + if Ns == 10.0 + Xs[:,j] .*= 0.1 + end + end + ys = map(1:n) do idx + a = dot(Xs[idx, :], ws) + bs + return rand(Distributions.Poisson(exp(a))) + end + + α = 1.3 + scale = exp(n/2) + function f(θ) + #θ = BigFloat.(θ) + w = @view(θ[1:p]) + b = θ[end] + s = sum(1:n) do i + a = dot(w, Xs[:, i]) + b + return 1 / n * (exp(a) - ys[i] * a) + end + if use_scale + return 1/scale * (s + α * norm(w)^2) + end + return s + α * norm(w)^2 + end + function grad!(storage, θ) + #θ = BigFloat.(θ) + w = @view(θ[1:p]) + b = θ[end] + storage[1:p] .= 2α .* w + storage[p+1:2p] .= 0 + storage[end] = 0 + for i in 1:n + xi = @view(Xs[:, i]) + a = dot(w, xi) + b + storage[1:p] .+= 1 / n * xi * exp(a) + storage[1:p] .-= 1 / n * ys[i] * xi + storage[end] += 1 / n * (exp(a) - ys[i]) + end + if use_scale + storage .*= 1/scale + end + return storage + end + # @show bs, Xs, ys, ws + + return f, grad!, p, α, bs, Xs, ys, ws +end + +function build_optimizer(o, p, k, Ns) + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + w = MOI.add_variables(o, p) + z = MOI.add_variables(o, p) + b = MOI.add_variable(o) + # z_i ∈ {0,1} for i = 1,..,p + for i in 1:p + MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, z[i], MOI.ZeroOne()) + end + for i in 1:p + # s.t. -N z_i <= w_i <= N z_i + MOI.add_constraint(o, Ns * z[i] + w[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, -Ns * z[i] + w[i], MOI.LessThan(0.0)) + # Indicator: z[i] = 1 => -N <= w[i] <= N + #=gl = MOI.VectorAffineFunction( + [ MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), + MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, w[i])),], + [0.0, 0.0], ) + gg = MOI.VectorAffineFunction( + [ MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), + MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-1.0, w[i])),], + [0.0, 0.0], ) + MOI.add_constraint(o, gl, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(Ns))) + MOI.add_constraint(o, gg, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(-Ns))) =# + end + # ∑ z_i <= k + MOI.add_constraint(o, sum(z, init=0.0), MOI.LessThan(1.0 * k)) + MOI.add_constraint(o, sum(z, init=0.0), MOI.GreaterThan(1.0)) + # b ∈ [-N, N] + MOI.add_constraint(o, b, MOI.LessThan(Ns)) + MOI.add_constraint(o, b, MOI.GreaterThan(-Ns)) + lmo = Boscia.MathOptBLMO(o) + return lmo, (w,z,b) +end + + +############ Decide which strategies to run ##################### +strategies = Any[ + "Strong_Branching","MOST_INFEASIBLE" +] + +for iterations_stable in Int64[5] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Example sizes ###################### + +example_dimensions = [30] + +seeds = rand(UInt64, 3) +Ns = 0.1 + + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 600 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "poisson_reg_examples_a_c" + +################################################################# +f, grad!, p, α, bs, Xs, ys, ws = build_function(1, 10; Ns=Ns) + k = 10/2 + o = HiGHS.Optimizer() + lmo, _ = build_optimizer(o, p, k, Ns) + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) + + +for seed in seeds + for dim in example_dimensions + n = dim + + example_name = string("poisson_reg_n_", n, "_p_", n) + for branching_strategy in strategies + f, grad!, p, α, bs, Xs, ys, ws = build_function(seed, n; Ns=Ns) + k = n/2 + o = HiGHS.Optimizer() + lmo, _ = build_optimizer(o, p, k, Ns) + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) + + + #lmo, f, grad! = poisson_reg(n, p, 10, seed, 0.10, 1.3) + if branching_strategy == "Strong_Branching" + + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end +end + + From 790f80e24438895ce89940a54c3dd34dcc6c4d42 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 28 Aug 2024 11:47:10 +0200 Subject: [PATCH 30/56] node changed to see if a node gets pruned by strong convexity before it is even created --- src/node.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/node.jl b/src/node.jl index 95a5fee08..aa6847769 100644 --- a/src/node.jl +++ b/src/node.jl @@ -85,6 +85,7 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN if !is_valid_split(tree, vidx) error("Splitting on the same index as parent! Abort!") end + #println(vidx) # get iterate, primal and lower bound x = Bonobo.get_relaxed_values(tree, node) @@ -188,7 +189,13 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN x_left = FrankWolfe.compute_active_set_iterate!(active_set_left) x_right = FrankWolfe.compute_active_set_iterate!(active_set_right) domain_oracle = tree.root.options[:domain_oracle] - + + # the nodes which get pruned by strong convexity do not give pseudocost updates at present. + if prune_left + @debug string("pruned left ", vidx) + elseif prune_right + @debug string("pruned right ", vidx) + end nodes = if !prune_left && !prune_right [node_info_left, node_info_right] elseif prune_left From 91752b246ef6bbfb8b794ebd23005e8eb698cb28 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 28 Aug 2024 17:27:19 +0200 Subject: [PATCH 31/56] hierarchical pseudobranching strategy --- src/custom_bonobo.jl | 44 ++++++++-- src/interface.jl | 11 ++- src/pseudo_branching.jl | 175 +++++++++++++++++++++++++++++++++------- src/utilities.jl | 3 +- 4 files changed, 195 insertions(+), 38 deletions(-) diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index b39d22906..f499a4f68 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -29,7 +29,8 @@ which are set in the following ways: function Bonobo.optimize!( tree::Bonobo.BnBTree{<:FrankWolfeNode}, pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64}; + branch_tracker::SparseMatrixCSC{Int64, Int64}, + infeas_tracker::SparseMatrixCSC{Int64, Int64}; callback=(args...; kwargs...) -> (), ) #println("OWN OPTIMIZE") @@ -39,6 +40,14 @@ function Bonobo.optimize!( # if the problem was infeasible we simply close the node and continue if isnan(lb) && isnan(ub) @debug "\n node closed without upd\n" + if isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) + idx = node.branched_on + if node.branched_right + infeas_tracker[idx, 1] += 1 + else + infeas_tracker[idx, 2] += 1 + end + end ## add the nodes which become infeasible to a special storage (yet to be implemented) Bonobo.close_node!(tree, node) callback(tree, node; node_infeasible=true) @@ -49,7 +58,7 @@ function Bonobo.optimize!( # if the evaluated lower bound is worse than the best incumbent -> close and continue if node.lb >= tree.incumbent - if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST)# In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable + if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) || isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST)# In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable #println("node closed but we do update anyway") if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable #println("if clause of update") @@ -100,10 +109,12 @@ function Bonobo.optimize!( end Bonobo.close_node!(tree, node) - if !isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) - Bonobo.branch!(tree, node) + if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) + Bonobo.pseudo_branch!(tree, node, pseudos, branch_tracker) + elseif isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) + Bonobo.hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker, infeas_tracker) else - pseudo_branch!(tree, node, pseudos, branch_tracker) + branch!(tree, node) end callback(tree, node) end @@ -157,7 +168,7 @@ function pseudo_branch!( tree::Bonobo.BnBTree{<:FrankWolfeNode}, node::Bonobo.AbstractNode, pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64} + branch_tracker::SparseMatrixCSC{Int64, Int64}, ) variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker) # no branching variable selected => return @@ -167,3 +178,24 @@ function pseudo_branch!( Bonobo.add_node!(tree, node, node_info) end end + +""" + hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker) + +Get the branching variable with [`get_branching_variable`](@ref) and then calls [`get_branching_nodes_info`](@ref) and [`add_node!`](@ref). +""" +function hierarchy_pseudo_branch!( + tree::Bonobo.BnBTree{<:FrankWolfeNode}, + node::Bonobo.AbstractNode, + pseudos::SparseMatrixCSC{Float64, Int64}, + branch_tracker::SparseMatrixCSC{Int64, Int64}, + infeas_tracker::SparseMatrixCSC{Int64, Int64} + ) + variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker, infeas_tracker) + # no branching variable selected => return + variable_idx == -1 && return + nodes_info = Bonobo.get_branching_nodes_info(tree, node, variable_idx) + for node_info in nodes_info + Bonobo.add_node!(tree, node, node_info) + end +end diff --git a/src/interface.jl b/src/interface.jl index 9a76bf2be..856fceb4c 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -295,7 +295,7 @@ function solve( tree.root.options[:callback] = fw_callback tree.root.current_node_id[] = Bonobo.get_next_node(tree, tree.options.traverse_strategy).id #the following should create the arrays and vectors only on first function call and then use existing one - if isa(branching_strategy, Boscia.PSEUDO_COST) + if isa(branching_strategy, Boscia.PSEUDO_COST) || isa(branching_strategy, Boscia.HIERARCHY_PSEUDO_COST) pseudos = sparse( repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), @@ -306,12 +306,19 @@ function solve( vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) ) + infeas_tracker = sparse( + repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), + vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), + ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) + ) else pseudos = sparse([1], [1], [0.0]) branch_tracker = sparse([1], [1], Int[0]) + + infeas_tracker = sparse([1], [1], Int[0]) end - Bonobo.optimize!(tree, pseudos, branch_tracker; callback=bnb_callback) + Bonobo.optimize!(tree, pseudos, branch_tracker, infeas_tracker; callback=bnb_callback) x = postsolve(tree, result, time_ref, verbose, max_iteration_post) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 0679fa282..d993d8920 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -23,7 +23,9 @@ end get_branching_variable( tree::Bonobo.BnBTree, branching::PSEUDO_COST, - node::Bonobo.AbstractNode + node::Bonobo.AbstractNode, + pseudos::SparseMatrixCSC, + branch_tracker::SparseMatrixCSC ) Get branching variable using Pseudocost branching after costs have stabilized. @@ -43,20 +45,16 @@ function Bonobo.get_branching_variable( all_stable = true branching_candidates = Int[]# this shall contain the indices of the potential branching variables values = Bonobo.get_relaxed_values(tree, node) - #branch_counter = [] - # for idx in Bonobo.get_branching_indices(tree.root) for idx in tree.branching_indices value = values[idx] if !Bonobo.is_approx_feasible(tree, value) push!(branching_candidates, idx) - #push!(branch_counter, (branch_tracker[idx, 1], branch_tracker[idx, 2])) - #push!(branch_counter, idx) if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx all_stable = false end end end - # for entry in branch_counter + # for entry in branching_candidates # if !isequal(branch_tracker[entry, 1], branch_tracker[entry, 2]) # println("\n", entry,"\n") # end @@ -67,10 +65,6 @@ function Bonobo.get_branching_variable( idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base update = update / node.distance_to_int - - # if rand() > 0.99 - # update += 0.1 - # end if isinf(update) @debug "update is $(Inf)" end @@ -115,23 +109,7 @@ function Bonobo.get_branching_variable( branching_scores = sparsevec(branching_candidates, branching_scores) #display(branching_scores) best_idx = argmax(branching_scores) - # max_distance_to_feasible = 0.0 - # best_idx_base = -1 - # for i in branching_candidates - # value = values[i] - # distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) - # if distance_to_feasible > max_distance_to_feasible - # best_idx_base = i - # max_distance_to_feasible = distance_to_feasible - # end - # end - # if best_idx != best_idx_base - # println(best_idx, best_idx_base) - # println("different branching decision made") - # end - - #println(pseudos[best_idx, 1], pseudos[best_idx,2]) - #println(best_idx) + return best_idx end end @@ -146,6 +124,145 @@ function update_avg(new_val::Float64, avg::Float64, N::Int) return new_val + avg # note that we initialize the pseudo costs with 1 as such we need to shift pseudocosts correspondingly end end -#pseudos = Dict{Int,Array{Float64}}(i=>zeros(2) for idx in get_integer_variables(blmo)) -#branch_tracker = Dict{Int, Int}(idx-> 0 for idx in get_integer_variables(blmo)) \ No newline at end of file + + + + +struct HIERARCHY_PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBranchStrategy + iterations_until_stable::Int + gradient_influence::Bool + bounded_lmo::BLMO + μ::Float64 + decision_function::String +end + + + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + branching::PSEUDO_COST, + node::Bonobo.AbstractNode, + pseudos::SparseMatrixCSC, + branch_tracker::SparseMatrixCSC +) + +Get branching variable using Pseudocost branching after costs have stabilized. +Prior to stabilization an adaptation of the Bonobo MOST_INFEASIBLE is used. + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::HIERARCHY_PSEUDO_COST{BLMO}, + node::Bonobo.AbstractNode, + infeasible_tracker::SparseMatrixCSC{Int64, Int64}, + pseudos::SparseMatrixCSC{Float64, Int64}, + branch_tracker::SparseMatrixCSC{Int64, Int64}, + infeas_tracker::SparseMatrixCSC{Int64, Int64}, +) where BLMO <: BoundedLinearMinimizationOracle + + strategy_switch = branching.iterations_until_stable + 1 + best_idx = -1 + all_stable = true + branching_candidates = Int[]# this shall contain the indices of the potential branching variables + values = Bonobo.get_relaxed_values(tree, node) + for idx in tree.branching_indices + value = values[idx] + if !Bonobo.is_approx_feasible(tree, value) + push!(branching_candidates, idx) + end + end + # for entry in branching_candidates + # if !isequal(branch_tracker[entry, 1], branch_tracker[entry, 2]) + # println("\n", entry,"\n") + # end + # #break + # end + if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + #println("if clause of update") + idx = node.branched_on + update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base + update = update / node.distance_to_int + if isinf(update) + @debug "update is $(Inf)" + end + if node.branched_right + #println(update) + pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) + branch_tracker[idx, 1] += 1 + else + #println(update) + pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) + branch_tracker[idx, 2] += 1 + + end + # println("pseudos") + #display(pseudos) + end + + if length(branching_candidates) == 0 + return best_idx + elseif length(branching_candidates) == 1 + best_idx = branch_tracker[1] + infeas_tracker[best_idx, 2] += 1 + return best_idx + end + + # compute score of how (often) branching on a variable resulted in infeasiblity + best_score = maximum(infeas_score, branching_candidates) + + branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, branch_tracker, infeas_tracker) == best_score] + + if length(branching_candidates) == 1 + best_idx = branching_candidates[1] + infeas_tracker[best_idx, 2] += 1 + return best_idx + end + + for idx in branching_candidates + if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx + all_stable = false + end + end + + + + if !all_stable# THEN Use Most Infeasible + max_distance_to_feasible = 0.0 + for i in branching_candidates + value = values[i] + distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) + if distance_to_feasible > max_distance_to_feasible + best_idx = i + max_distance_to_feasible = distance_to_feasible + end + end + infeas_tracker[best_idx, 2] += 1 + return best_idx + else + #println("\npd made\n") + if branching.decision_function == "weighted_sum" + #println(branching.decision_function) + branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), + branching_candidates) + + elseif branching.decision_function == "product" + #println(branching.decision_function) + branching_scores = map(idx-> max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), + branching_candidates) + end + branching_scores = sparsevec(branching_candidates, branching_scores) + #display(branching_scores) + best_idx = argmax(branching_scores) + + infeas_tracker[best_idx, 2] += 1 + return best_idx + end +end + + +function infeas_score(idx::Int, infeas_tracker::SparseMatrixCSC{Int64, Int64}) + return infeas_tracker[idx, 1] / infeas_tracker[idx, 2]# ratio of how often branching on variable idx leads to node infeasiblity of children +end \ No newline at end of file diff --git a/src/utilities.jl b/src/utilities.jl index f9bf509b6..a5562deeb 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -299,4 +299,5 @@ _value_to_print(::Bonobo.BestFirstSearch) = "Move best bound" _value_to_print(::PartialStrongBranching) = "Partial strong branching" _value_to_print(::HybridStrongBranching) = "Hybrid strong branching" _value_to_print(::Bonobo.MOST_INFEASIBLE) = "Most infeasible" -_value_to_print(::PSEUDO_COST) = "Pseudo Cost" \ No newline at end of file +_value_to_print(::PSEUDO_COST) = "Pseudo Cost" +_value_to_print(::HIERARCHY_PSEUDO_COST) = "Hierarchy-Pseudo Cost" \ No newline at end of file From 5cd06cd9f3ae173235f7560070ee7212286ce740 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 28 Aug 2024 20:26:54 +0200 Subject: [PATCH 32/56] some fixes to make code run --- src/custom_bonobo.jl | 6 +++--- src/pseudo_branching.jl | 37 ++++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index f499a4f68..ea05cbaa8 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -110,11 +110,11 @@ function Bonobo.optimize!( Bonobo.close_node!(tree, node) if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) - Bonobo.pseudo_branch!(tree, node, pseudos, branch_tracker) + pseudo_branch!(tree, node, pseudos, branch_tracker) elseif isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) - Bonobo.hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker, infeas_tracker) + hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker, infeas_tracker) else - branch!(tree, node) + Bonobo.branch!(tree, node) end callback(tree, node) end diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index d993d8920..83e497302 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -157,7 +157,6 @@ function Bonobo.get_branching_variable( tree::Bonobo.BnBTree, branching::HIERARCHY_PSEUDO_COST{BLMO}, node::Bonobo.AbstractNode, - infeasible_tracker::SparseMatrixCSC{Int64, Int64}, pseudos::SparseMatrixCSC{Float64, Int64}, branch_tracker::SparseMatrixCSC{Int64, Int64}, infeas_tracker::SparseMatrixCSC{Int64, Int64}, @@ -202,20 +201,18 @@ function Bonobo.get_branching_variable( #display(pseudos) end - if length(branching_candidates) == 0 - return best_idx - elseif length(branching_candidates) == 1 - best_idx = branch_tracker[1] - infeas_tracker[best_idx, 2] += 1 - return best_idx - end - + println("--- before --- ") + display(branching_candidates) # compute score of how (often) branching on a variable resulted in infeasiblity - best_score = maximum(infeas_score, branching_candidates) + best_score = max_infeas_score(branching_candidates, infeas_tracker) - branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, branch_tracker, infeas_tracker) == best_score] + branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, infeas_tracker) >= best_score] + println("--- after --- ") + display(branching_candidates) - if length(branching_candidates) == 1 + if length(branching_candidates) == 0 + return best_idx + elseif length(branching_candidates) == 1 best_idx = branching_candidates[1] infeas_tracker[best_idx, 2] += 1 return best_idx @@ -264,5 +261,19 @@ end function infeas_score(idx::Int, infeas_tracker::SparseMatrixCSC{Int64, Int64}) - return infeas_tracker[idx, 1] / infeas_tracker[idx, 2]# ratio of how often branching on variable idx leads to node infeasiblity of children + infeas_tracker[idx, 1] == 1 && return 0 + return (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2])# ratio of how often branching on variable idx leads to node infeasiblity of children +end + +function max_infeas_score(idxs::Vector{Int64}, infeas_tracker::SparseMatrixCSC{Int64, Int64}) + max_score = 0 + for idx in idxs + if infeas_tracker[idx, 1] == 1 + continue + else + max_score = max(max_score, (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2])) + end + end + + return max_score end \ No newline at end of file From 338546e89b0146697b1513c242ef760d0ff3fc54 Mon Sep 17 00:00:00 2001 From: Leon Date: Sat, 31 Aug 2024 19:29:12 +0200 Subject: [PATCH 33/56] gradient based branching --- src/pseudo_branching.jl | 40 ++++++++++++++++++++++++++++++++++++++++ src/utilities.jl | 3 ++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index 83e497302..ee2f5c640 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -276,4 +276,44 @@ function max_infeas_score(idxs::Vector{Int64}, infeas_tracker::SparseMatrixCSC{I end return max_score +end + +""" + Largest_Gradient <: AbstractBranchStrategy + +The `LARGEST GRADIENT` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. +""" +struct LARGEST_GRADIENT <: Bonobo.AbstractBranchStrategy end + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + node::Bonobo.AbstractNode +) + +Get branching variable using Largest_Gradient branching + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::LARGEST_GRADIENT, + node::Bonobo.AbstractNode, +) + + values = Bonobo.get_relaxed_values(tree, node) + nabla = similar(values) + x_new = copy(values) + gradiant_at_values = tree.root.problem.g(nabla,x_new) + best_idx = -1 + max_gradient = 0.0 + for i in tree.branching_indices + value = values[i] + if !Bonobo.is_approx_feasible(tree, value) + if abs(gradiant_at_values[i]) > max_gradient + best_idx = i + end + end + end + return best_idx end \ No newline at end of file diff --git a/src/utilities.jl b/src/utilities.jl index a5562deeb..86a752ef9 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -300,4 +300,5 @@ _value_to_print(::PartialStrongBranching) = "Partial strong branching" _value_to_print(::HybridStrongBranching) = "Hybrid strong branching" _value_to_print(::Bonobo.MOST_INFEASIBLE) = "Most infeasible" _value_to_print(::PSEUDO_COST) = "Pseudo Cost" -_value_to_print(::HIERARCHY_PSEUDO_COST) = "Hierarchy-Pseudo Cost" \ No newline at end of file +_value_to_print(::HIERARCHY_PSEUDO_COST) = "Hierarchy-Pseudo Cost" +_value_to_print(::LARGEST_GRADIENT) = "Largest Gradient" \ No newline at end of file From d1c52bade15e0320e31448119979cf3eef50f837 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 17 Sep 2024 21:00:38 +0200 Subject: [PATCH 34/56] alter --- src/Boscia.jl | 1 + src/other_branching.jl | 90 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/other_branching.jl diff --git a/src/Boscia.jl b/src/Boscia.jl index 2c0c707f9..70f874860 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -27,6 +27,7 @@ include("problem.jl") include("heuristics.jl") include("strong_branching.jl") include("pseudo_branching.jl") +include("other_branching.jl") include("utilities.jl") include("interface.jl") include("managed_blmo.jl") diff --git a/src/other_branching.jl b/src/other_branching.jl new file mode 100644 index 000000000..46c694c6f --- /dev/null +++ b/src/other_branching.jl @@ -0,0 +1,90 @@ +""" + Largest_Gradient <: AbstractBranchStrategy + +The `LARGEST GRADIENT` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. +""" +struct LARGEST_GRADIENT <: Bonobo.AbstractBranchStrategy end + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + node::Bonobo.AbstractNode +) + +Get branching variable using Largest_Gradient branching + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::LARGEST_GRADIENT, + node::Bonobo.AbstractNode, +) + values = Bonobo.get_relaxed_values(tree, node) + nabla = similar(values) + x_new = copy(values) + gradient_at_values = tree.root.problem.g(nabla, x_new) + best_idx = -1 + max_gradient = 0.0 + for i in tree.branching_indices + value = values[i] + if !Bonobo.is_approx_feasible(tree, value)# check if variable is branching candidate + if abs(gradient_at_values[i]) > max_gradient + best_idx = i + end + end + end + return best_idx +end + + + +""" + LARGEST_MOST_INFEASIBLE_GRADIENT <: AbstractBranchStrategy + +The `LARGEST_MOST_INFEASIBLE_GRADIENT` strategy always picks the variable which has the largest absolute value +entry in the current gradient multiplied by the maximum distance to being fixed. +""" + +struct LARGEST_MOST_INFEASIBLE_GRADIENT <: Bonobo.AbstractBranchStrategy end + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + node::Bonobo.AbstractNode +) + +Get branching variable using LARGEST_MOST_INFEASIBLE_GRADIENT branching + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::LARGEST_MOST_INFEASIBLE_GRADIENT, + node::Bonobo.AbstractNode, +) + values = Bonobo.get_relaxed_values(tree, node) + best_idx = -1 + nabla = similar(values) + x_new = copy(values) + gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? + max_score = 0.0 + for i in branching_candidates + if !Bonobo.is_approx_feasible(tree, value) + value = values[i] * abs(gradient_at_values[i]) + if value > max_score + best_idx = i + max_score = value + end + end + end + return best_idx +end + + + + + + + + From 389ae3f10dd352fcde643dd556eee80733a96d27 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 17 Sep 2024 21:02:16 +0200 Subject: [PATCH 35/56] alternative branching strategies --- src/custom_bonobo.jl | 7 +--- src/pseudo_branching.jl | 85 ++++++++++++++--------------------------- src/utilities.jl | 3 +- 3 files changed, 31 insertions(+), 64 deletions(-) diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index ea05cbaa8..f63d1c79e 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -41,12 +41,7 @@ function Bonobo.optimize!( if isnan(lb) && isnan(ub) @debug "\n node closed without upd\n" if isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) - idx = node.branched_on - if node.branched_right - infeas_tracker[idx, 1] += 1 - else - infeas_tracker[idx, 2] += 1 - end + infeas_tracker[node.branched_on, 1] += 1 end ## add the nodes which become infeasible to a special storage (yet to be implemented) Bonobo.close_node!(tree, node) diff --git a/src/pseudo_branching.jl b/src/pseudo_branching.jl index ee2f5c640..89618ca87 100644 --- a/src/pseudo_branching.jl +++ b/src/pseudo_branching.jl @@ -126,9 +126,6 @@ function update_avg(new_val::Float64, avg::Float64, N::Int) end - - - struct HIERARCHY_PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int gradient_influence::Bool @@ -138,8 +135,6 @@ struct HIERARCHY_PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.Ab end - - """ get_branching_variable( tree::Bonobo.BnBTree, @@ -201,14 +196,14 @@ function Bonobo.get_branching_variable( #display(pseudos) end - println("--- before --- ") - display(branching_candidates) + #println("--- before --- ") + #display(branching_candidates) # compute score of how (often) branching on a variable resulted in infeasiblity best_score = max_infeas_score(branching_candidates, infeas_tracker) branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, infeas_tracker) >= best_score] - println("--- after --- ") - display(branching_candidates) + #println("--- after --- ") + #display(branching_candidates) if length(branching_candidates) == 0 return best_idx @@ -227,17 +222,32 @@ function Bonobo.get_branching_variable( if !all_stable# THEN Use Most Infeasible - max_distance_to_feasible = 0.0 - for i in branching_candidates - value = values[i] - distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) - if distance_to_feasible > max_distance_to_feasible - best_idx = i - max_distance_to_feasible = distance_to_feasible + if branching.gradient_influence# score function as product of gradient at variable and largest distance to int + nabla = similar(values) + x_new = copy(values) + gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? + max_score = 0.0 + for i in branching_candidates + value = values[i] * abs(gradient_at_values[i]) + if value > max_score + best_idx = i + max_score = value + end end + return best_idx + else + max_distance_to_feasible = 0.0 + for i in branching_candidates + value = values[i] + distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) + if distance_to_feasible > max_distance_to_feasible + best_idx = i + max_distance_to_feasible = distance_to_feasible + end + end + infeas_tracker[best_idx, 2] += 1 + return best_idx end - infeas_tracker[best_idx, 2] += 1 - return best_idx else #println("\npd made\n") if branching.decision_function == "weighted_sum" @@ -278,42 +288,3 @@ function max_infeas_score(idxs::Vector{Int64}, infeas_tracker::SparseMatrixCSC{I return max_score end -""" - Largest_Gradient <: AbstractBranchStrategy - -The `LARGEST GRADIENT` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. -""" -struct LARGEST_GRADIENT <: Bonobo.AbstractBranchStrategy end - - -""" - get_branching_variable( - tree::Bonobo.BnBTree, - node::Bonobo.AbstractNode -) - -Get branching variable using Largest_Gradient branching - -""" -function Bonobo.get_branching_variable( - tree::Bonobo.BnBTree, - branching::LARGEST_GRADIENT, - node::Bonobo.AbstractNode, -) - - values = Bonobo.get_relaxed_values(tree, node) - nabla = similar(values) - x_new = copy(values) - gradiant_at_values = tree.root.problem.g(nabla,x_new) - best_idx = -1 - max_gradient = 0.0 - for i in tree.branching_indices - value = values[i] - if !Bonobo.is_approx_feasible(tree, value) - if abs(gradiant_at_values[i]) > max_gradient - best_idx = i - end - end - end - return best_idx -end \ No newline at end of file diff --git a/src/utilities.jl b/src/utilities.jl index 86a752ef9..ab0b68f83 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -301,4 +301,5 @@ _value_to_print(::HybridStrongBranching) = "Hybrid strong branching" _value_to_print(::Bonobo.MOST_INFEASIBLE) = "Most infeasible" _value_to_print(::PSEUDO_COST) = "Pseudo Cost" _value_to_print(::HIERARCHY_PSEUDO_COST) = "Hierarchy-Pseudo Cost" -_value_to_print(::LARGEST_GRADIENT) = "Largest Gradient" \ No newline at end of file +_value_to_print(::LARGEST_GRADIENT) = "Largest Gradient" +_value_to_print(::LARGEST_MOST_INFEASIBLE_GRADIENT) = "Largest most infeasible gradient " \ No newline at end of file From 9864b2a83b229f6a79e94135f1b021cff333cdb0 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 17 Sep 2024 21:03:28 +0200 Subject: [PATCH 36/56] examples modified to run multiple strategies --- examples/approx_planted_point_pseudocost.jl | 370 ++++++++++++++++ examples/birkhoff_pseudocost.jl | 406 ++++++++++++++++++ examples/int_sparse_reg_pseudocost.jl | 238 ++++++++++ examples/lasso_pseudocost.jl | 253 +++++++++++ examples/low_dim_in_high_dim_pseudocost.jl | 212 +++++++++ examples/mps-example_pseudocost.jl | 202 +++++++++ .../mps-examples/mip-examples_pseudocost.jl | 265 ++++++++++++ examples/nonlinear_pseudocost.jl | 266 ++++++++++++ examples/portfolio_pseudocost.jl | 248 +++++++++-- examples/sparse_regression_pseudocost.jl | 171 ++++++-- ...ression_pseudocost_used_for_emp_results.jl | 403 +++++++++++++++++ 11 files changed, 2975 insertions(+), 59 deletions(-) create mode 100644 examples/approx_planted_point_pseudocost.jl create mode 100644 examples/birkhoff_pseudocost.jl create mode 100644 examples/int_sparse_reg_pseudocost.jl create mode 100644 examples/lasso_pseudocost.jl create mode 100644 examples/low_dim_in_high_dim_pseudocost.jl create mode 100644 examples/mps-example_pseudocost.jl create mode 100644 examples/mps-examples/mip-examples_pseudocost.jl create mode 100644 examples/nonlinear_pseudocost.jl create mode 100644 examples/sparse_regression_pseudocost_used_for_emp_results.jl diff --git a/examples/approx_planted_point_pseudocost.jl b/examples/approx_planted_point_pseudocost.jl new file mode 100644 index 000000000..581d1c585 --- /dev/null +++ b/examples/approx_planted_point_pseudocost.jl @@ -0,0 +1,370 @@ +using Boscia +using FrankWolfe +using Test +using Random +using SCIP +using HiGHS +# using Statistics +using LinearAlgebra +#using Distributions +import MathOptInterface +const MOI = MathOptInterface + +include("cube_blmo.jl") + +n = 20 +diffi = Random.rand(Bool, n) * 0.6 .+ 0.3 + + +function approx_planted_point_integer(n, seed) + Random.seed!(seed) + diffi = Random.rand(Bool, n) * 0.6 .+ 0.3 + function f(x) + return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) + end + function grad!(storage, x) + @. storage = x - diffi + end + # using SCIP + o = SCIP.Optimizer() + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, n) + for xi in x + MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) + MOI.add_constraint(o, xi, MOI.LessThan(1.0)) + MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() + end + lmo = Boscia.MathOptBLMO(o) + return lmo, f, grad! +end + +function approx_planted_point_mixed(n, seed) + Random.seed!(seed) + diffi = Random.rand(Bool, n) * 0.6 .+ 0.3 + function f(x) + return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) + end + function grad!(storage, x) + @. storage = x - diffi + end + int_vars = unique!(rand(collect(1:n), Int(floor(n / 2)))) + o = SCIP.Optimizer() + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, n) + for xi in x + MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) + MOI.add_constraint(o, xi, MOI.LessThan(1.0)) + if xi.value in int_vars + MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() + end + end + lmo = Boscia.MathOptBLMO(o) + + return lmo, f, grad! +end + + + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10,20] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Example sizes ###################### + +example_dimensions = [20, 25] +seeds = rand(UInt64, 3) + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 600 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "approx_planted_point_a_c" +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +################################################################# + +for seed in seeds + for dim in example_dimensions + example_name = string("approx_planted_point_integer_n", dim) + for branching_strategy in strategies + lmo, f, grad! = approx_planted_point_integer(dim, seed) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end +end + +for seed in seeds + for dim in example_dimensions + example_name = string("approx_planted_point_mixed_n", dim) + for branching_strategy in strategies + lmo, f, grad! = approx_planted_point_mixed(dim, seed) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end +end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# @testset "Approximate planted point - Integer" begin + +# function f(x) +# return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) +# end +# function grad!(storage, x) +# @. storage = x - diffi +# end + +# @testset "Using SCIP" begin +# o = SCIP.Optimizer() +# MOI.set(o, MOI.Silent(), true) +# MOI.empty!(o) +# x = MOI.add_variables(o, n) +# for xi in x +# MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) +# MOI.add_constraint(o, xi, MOI.LessThan(1.0)) +# MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() +# end +# lmo = Boscia.MathOptBLMO(o) + +# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) + +# @test x == round.(diffi) +# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) +# end + +# @testset "Using Cube LMO" begin +# int_vars = collect(1:n) + +# bounds = Boscia.IntegerBounds() +# for i in 1:n +# push!(bounds, (i, 0.0), :greaterthan) +# push!(bounds, (i, 1.0), :lessthan) +# end +# blmo = CubeBLMO(n, int_vars, bounds) + +# x, _, result = Boscia.solve(f, grad!, blmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, blmo, μ), verbose=true) + + +# @test x == round.(diffi) +# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) +# end + +# @testset "Using Cube Simple LMO" begin +# int_vars = collect(1:n) +# lbs = zeros(n) +# ubs = ones(n) + +# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) + +# x, _, result = +# Boscia.solve(f, grad!, sblmo, lbs[int_vars], ubs[int_vars], int_vars, n, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, sblmo, μ), verbose=true) + +# @test x == round.(diffi) +# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) +# end +# end + + +# @testset "Approximate planted point - Mixed" begin + +# function f(x) +# return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) +# end +# function grad!(storage, x) +# @. storage = x - diffi +# end + +# int_vars = unique!(rand(collect(1:n), Int(floor(n / 2)))) + +# @testset "Using SCIP" begin +# o = SCIP.Optimizer() +# MOI.set(o, MOI.Silent(), true) +# MOI.empty!(o) +# x = MOI.add_variables(o, n) +# for xi in x +# MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) +# MOI.add_constraint(o, xi, MOI.LessThan(1.0)) +# if xi.value in int_vars +# MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() +# end +# end +# lmo = Boscia.MathOptBLMO(o) + +# x, _, result = Boscia.solve(f, grad!, blmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) + +# sol = diffi +# sol[int_vars] = round.(sol[int_vars]) +# @test sum(isapprox.(x, sol, atol=1e-6, rtol=1e-2)) == n +# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) +# end + +# @testset "Using Cube LMO" begin +# bounds = Boscia.IntegerBounds() +# for i in 1:n +# push!(bounds, (i, 0.0), :greaterthan) +# push!(bounds, (i, 1.0), :lessthan) +# end +# blmo = CubeBLMO(n, int_vars, bounds) + +# x, _, result = Boscia.solve(f, grad!, blmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, blmo, μ), verbose=true) + +# sol = diffi +# sol[int_vars] = round.(sol[int_vars]) +# @test sum(isapprox.(x, sol, atol=1e-6, rtol=1e-2)) == n +# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) +# end + +# @testset "Using Cube Simple LMO" begin +# lbs = zeros(n) +# ubs = ones(n) + +# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) + +# x, _, result = +# Boscia.solve(f, grad!, sblmo, lbs[int_vars], ubs[int_vars], int_vars, n, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, sblmo, μ), verbose=true) + +# sol = diffi +# sol[int_vars] = round.(sol[int_vars]) +# @test sum(isapprox.(x, sol, atol=1e-6, rtol=1e-2)) == n +# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) +# end +# end diff --git a/examples/birkhoff_pseudocost.jl b/examples/birkhoff_pseudocost.jl new file mode 100644 index 000000000..b4937b22e --- /dev/null +++ b/examples/birkhoff_pseudocost.jl @@ -0,0 +1,406 @@ +using Boscia +using FrankWolfe +using Test +using Random +using SCIP +using HiGHS +using LinearAlgebra +import MathOptInterface +const MOI = MathOptInterface +import HiGHS + +# Example on the Birkhoff polytope but using permutation matrices directly +# https://arxiv.org/pdf/2011.02752.pdf +# https://www.sciencedirect.com/science/article/pii/S0024379516001257 + +# For bug hunting: +# seed = rand(UInt64) + +# #seed = 0x3eb09305cecf69f0 +# @show seed +# Random.seed!(seed) + + +# min_{X, θ} 1/2 * || ∑_{i in [k]} θ_i X_i - Xhat ||^2 +# θ ∈ Δ_k (simplex) +# X_i ∈ P_n (permutation matrix) + +# we linearize the bilinear terms in the objective +# min_{X, Y, θ} 1/2 ||∑_{i in [k]} Y - Xhat ||^2 +# θ ∈ Δ_k (simplex) +# X_i ∈ P_n (permutation matrix) +# 0 ≤ Y_i ≤ X_i +# 0 ≤ θ_i - Y_i ≤ 1 - X_i + +# The variables are ordered (Y, X, theta) in the MOI model +# the objective only uses the last n^2 variables +# Small dimensions since the size of the problem grows quickly (2 k n^2 + k variables) +# n = 5 +# k = 3 +# file_name = "birkhoff_examples" +# example_name = "birkhoff_n_" * string(n) * "_k_" * string(k) +# # generate random doubly stochastic matrix +# const Xstar = rand(n, n) +# while norm(sum(Xstar, dims=1) .- 1) > 1e-6 || norm(sum(Xstar, dims=2) .- 1) > 1e-6 +# Xstar ./= sum(Xstar, dims=1) +# Xstar ./= sum(Xstar, dims=2) +# end + +function build_function(n, k, seed) + + Random.seed!(seed) + Xstar = rand(n, n) + while norm(sum(Xstar, dims=1) .- 1) > 1e-6 || norm(sum(Xstar, dims=2) .- 1) > 1e-6 + Xstar ./= sum(Xstar, dims=1) + Xstar ./= sum(Xstar, dims=2) + end + + function f(x) + s = zero(eltype(x)) + for i in eachindex(Xstar) + s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 + end + return s + end + + # note: reshape gives a reference to the same data, so this is updating storage in-place + function grad!(storage, x) + storage .= 0 + for j in 1:k + Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) + @. Sk = -Xstar + for m in 1:k + Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) + @. Sk += Yk + end + end + return storage + end + return f, grad! +end + +function build_birkhoff_lmo(o,n,k) + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + Y = [reshape(MOI.add_variables(o, n^2), n, n) for _ in 1:k] + X = [reshape(MOI.add_variables(o, n^2), n, n) for _ in 1:k] + theta = MOI.add_variables(o, k) + + for i in 1:k + MOI.add_constraint.(o, Y[i], MOI.GreaterThan(0.0)) + MOI.add_constraint.(o, Y[i], MOI.LessThan(1.0)) + MOI.add_constraint.(o, X[i], MOI.ZeroOne()) + MOI.add_constraint(o, theta[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, theta[i], MOI.LessThan(1.0)) + # doubly stochastic constraints + MOI.add_constraint.( + o, + vec(sum(X[i], dims=1, init=MOI.ScalarAffineFunction{Float64}([], 0.0))), + MOI.EqualTo(1.0), + ) + MOI.add_constraint.( + o, + vec(sum(X[i], dims=2, init=MOI.ScalarAffineFunction{Float64}([], 0.0))), + MOI.EqualTo(1.0), + ) + # 0 ≤ Y_i ≤ X_i + MOI.add_constraint.(o, 1.0 * Y[i] - X[i], MOI.LessThan(0.0)) + # 0 ≤ θ_i - Y_i ≤ 1 - X_i + MOI.add_constraint.(o, 1.0 * theta[i] .- Y[i] .+ X[i], MOI.LessThan(1.0)) + end + MOI.add_constraint(o, sum(theta, init=0.0), MOI.EqualTo(1.0)) + return Boscia.MathOptBLMO(o) +end + + + + + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Example sizes ###################### + +n_choices = Int[3, +#40 +] +k_choices = [2] + +seeds = rand(UInt64, 3) + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 60 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "birkhoff_a_c" +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +for _ in [1] + f, grad! = build_function(3,2, 1) + o = SCIP.Optimizer() + lmo = build_birkhoff_lmo(o, 3,2) + println("precompile") + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) +end +# print(lmo.o) +println("actual run")################################################################# + + +for seed in seeds + for dim in n_choices + for k in k_choices + n = dim + for branching_strategy in strategies + f, grad! = build_function(n, k, seed) + o = SCIP.Optimizer() + lmo = build_birkhoff_lmo(o, n,k) + example_name = string("birkhoff_", n, "_k_",k) + if branching_strategy == "Strong_Branching" + #blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end + end +end + + + + + + + + + +# ############## weighted_sum PSEUDO_COST ############################# +# function f(x) +# s = zero(eltype(x)) +# for i in eachindex(Xstar) +# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 +# end +# return s +# end + +# # note: reshape gives a reference to the same data, so this is updating storage in-place +# function grad!(storage, x) +# storage .= 0 +# for j in 1:k +# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) +# @. Sk = -Xstar +# for m in 1:k +# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) +# @. Sk += Yk +# end +# end +# return storage +# end + +# lmo = build_birkhoff_lmo() +# iterations_stable = 10::Int +# decision_function = "weighted_sum" +# if decision_function == "product" +# μ = 1e-6 +# else +# μ = 0.7 # μ used in the computation of the branching score +# end + +# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=2400) +# settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) +# Boscia.save_results(result, settings, example_name, seed, file_name, false) + + +# # ############## product PSEUDO_COST ############################# +# function f(x) +# s = zero(eltype(x)) +# for i in eachindex(Xstar) +# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 +# end +# return s +# end + +# # note: reshape gives a reference to the same data, so this is updating storage in-place +# function grad!(storage, x) +# storage .= 0 +# for j in 1:k +# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) +# @. Sk = -Xstar +# for m in 1:k +# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) +# @. Sk += Yk +# end +# end +# return storage +# end + +# lmo = build_birkhoff_lmo() +# iterations_stable = 10::Int +# decision_function = "product" +# if decision_function == "product" +# μ = 1e-6 +# else +# μ = 0.7 # μ used in the computation of the branching score +# end +# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=2400) +# settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) +# Boscia.save_results(result, settings, example_name, seed, file_name, false) + + +# ############## MOST_INFEASIBLE ############################# +# function f(x) +# s = zero(eltype(x)) +# for i in eachindex(Xstar) +# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 +# end +# return s +# end + +# # note: reshape gives a reference to the same data, so this is updating storage in-place +# function grad!(storage, x) +# storage .= 0 +# for j in 1:k +# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) +# @. Sk = -Xstar +# for m in 1:k +# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) +# @. Sk += Yk +# end +# end +# return storage +# end +# lmo = build_birkhoff_lmo() +# x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=2400) +# settings = "MOST_INFEASIBLE" +# Boscia.save_results(result, settings, example_name, seed, file_name, false) + + + +# ############## Strong_Branching ############################# +# function f(x) +# s = zero(eltype(x)) +# for i in eachindex(Xstar) +# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 +# end +# return s +# end + +# # note: reshape gives a reference to the same data, so this is updating storage in-place +# function grad!(storage, x) +# storage .= 0 +# for j in 1:k +# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) +# @. Sk = -Xstar +# for m in 1:k +# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) +# @. Sk += Yk +# end +# end +# return storage +# end +# lmo = build_birkhoff_lmo() +# blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) +# branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) +# MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + +# x, _, result_strong_branching = +# Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy=branching_strategy, fw_epsilon=1e-3, time_limit=2400) +# settings = "Strong_Branching" +# Boscia.save_results(result_strong_branching, settings, example_name, seed, file_name, false) + + + + + + + + + + + +# # TODO the below needs to be fixed +# # TODO can use the min_via_enum function if not too many solutions +# # build optimal solution +# # xopt = zeros(n) +# # for i in 1:n +# # if diffi[i] > 0.5 +# # xopt[i] = 1 +# # end +# # end + +# # @testset "Birkhoff" begin +# # lmo = build_birkhoff_lmo() +# # x, _, result_baseline = Boscia.solve(f, grad!, lmo, verbose=true) +# # @test f(x) <= f(result_baseline[:raw_solution]) + 1e-6 +# # lmo = build_birkhoff_lmo() +# # blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) +# # branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) +# # MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) +# # x_strong, _, result_strong = +# # Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy=branching_strategy) +# # @test f(x) ≈ f(x_strong) +# # @test f(x) <= f(result_strong[:raw_solution]) + 1e-6 +# # end diff --git a/examples/int_sparse_reg_pseudocost.jl b/examples/int_sparse_reg_pseudocost.jl new file mode 100644 index 000000000..db65dddc7 --- /dev/null +++ b/examples/int_sparse_reg_pseudocost.jl @@ -0,0 +1,238 @@ +using Statistics +using Boscia +using FrankWolfe +using Random +using SCIP +import Bonobo +using Test +import MathOptInterface +const MOI = MathOptInterface + +# Integer sparse regression + +# min norm(y-A x)² +# s.t. 0 <= x_i <= r +# ∑ x_i <= k +# x_i ∈ Z for i = 1,..,n + +# There A represents the collection of data points and +# is a very tall matrix, i.e. number of rows = m >> number of columns = n. +# y - is the vector of results. +# r - controls how often we have to maximal split on a index. +# k - is the sparsity parameter. We only want a few non zero entries. + +# For bug hunting: +# seed = rand(UInt64) +# @show seed +# #seed = 0xeadb922ca734998b +# Random.seed!(seed) + +# n = 10 +# m = 35 +# l = 30 +# k = 4 + +# sol_x = rand(1:l, n) +# for _ in 1:(n-k) +# sol_x[rand(1:n)] = 0 +# end + +#=k=0 # correct k +for i in 1:n + if sol_x[i] == 0 + global k += 1 + end +end +k = n-k =# + +# const D = rand(m, n) +# const y_d = D * sol_x + + +function int_sparse_regression(n, m, l, k, seed) + Random.seed!(seed) + sol_x = rand(1:l, n) + for _ in 1:(n-k) + sol_x[rand(1:n)] = 0 + end + D = rand(m, n) + y_d = D * sol_x + + o = SCIP.Optimizer() + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, n) + z = MOI.add_variables(o, n) + for i in 1:n + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0 * l)) + MOI.add_constraint(o, x[i], MOI.Integer()) + + MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, z[i], MOI.ZeroOne()) + + MOI.add_constraint(o, 1.0 * x[i] - 1.0 * l * z[i], MOI.LessThan(0.0)) + end + MOI.add_constraint(o, sum(z, init=0.0), MOI.LessThan(1.0 * k)) + # MOI.add_constraint(o, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(zeros(n),x), sum(Float64.(iszero.(x)))), MOI.GreaterThan(1.0*(n-k))) + # MOI.add_constraint(o, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(n),z), 0.0), MOI.GreaterThan(1.0*k)) + lmo = Boscia.MathOptBLMO(o) + + function f(x) + xv = @view(x[1:n]) + return 1 / 2 * sum(abs2, y_d - D * xv) #+ lambda_2*FrankWolfe.norm(x)^2 + lambda_0*sum(x[p+1:2p]) + end + + function grad!(storage, x) + storage .= 0 + @view(storage[1:n]) .= transpose(D) * (D * @view(x[1:n]) - y_d) + return storage + end + + return lmo, f, grad! +end + + + +@testset "Integer sparse regression" begin + seed = rand(UInt64) + @show seed + #seed = 0xeadb922ca734998b + Random.seed!(seed) + n = 10 + m = 30 + l = 5 + k = 4 + lmo, f, grad! = int_sparse_regression(n,m,l,k, seed) + + #= function perform_strong_branch(tree, node) + return node.level <= length(tree.root.problem.integer_variables) + end + branching_strategy = Boscia.HybridStrongBranching(10, 1e-3, HiGHS.Optimizer(), perform_strong_branch) + MOI.set(branching_strategy.pstrong.optimizer, MOI.Silent(), true)=# + + + x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, max_fw_iter=10001, rel_dual_gap=1e-3, time_limit=30) + + # val_min, x_min = Boscia.sparse_min_via_enum(f, n, k, fill(0:l, n)) + # #@show x_min + # @show x[1:n] + # @show x_min + # @test val_min == f(x) + # @test isapprox(x[1:n], x_min) + # @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-6) +end + + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10,20] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Example sizes ###################### + +example_dimensions = [10, 15, 20, 25] +fac_choices = [3,5] +seeds = rand(UInt64, 3) + + + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 600 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "int_sparse_reg_examples_a_c" +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +################################################################# +for seed in seeds + for dim in example_dimensions + for fac in fac_choices + n = dim + m = 3*n + l = 30 + k = ceil(n/fac) + example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) + for branching_strategy in strategies + lmo, f, grad! = int_sparse_regression(n,m,l,k, seed) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end + end +end + + + + + + + + + + diff --git a/examples/lasso_pseudocost.jl b/examples/lasso_pseudocost.jl new file mode 100644 index 000000000..2f0f4012d --- /dev/null +++ b/examples/lasso_pseudocost.jl @@ -0,0 +1,253 @@ +using Statistics +using Distributions +using Boscia +using FrankWolfe +using Random +using Test +using SCIP +import Bonobo +import MathOptInterface +const MOI = MathOptInterface +using Dates +using Printf + +# Lasso + +# Constant parameters for the sparse regression +# min norm(y-A β)² + λ_0 ∑ z_i + λ_2 ||β||² +# s.t. -Mz_i<=β_i <= Mz_i +# ∑ z_i <= k +# z_i ∈ {0,1} for i = 1,..,p + + + + +function build_function(seed, n) + p = 5 * n + k = ceil(n / 5) + group_size = convert(Int64, floor(p / k)) + M_g = 5.0 + lambda_0_g = 0.0 + lambda_2_g = 0.0 + A_g = rand(Float64, n, p) + β_sol = rand(Distributions.Uniform(-M_g, M_g), p) + k_int = convert(Int64, k) + for i in 1:k_int + for _ in 1:group_size-1 + β_sol[rand(((i-1)*group_size+1):(i*group_size))] = 0 + end + end + y_g = A_g * β_sol + k = 0 # correct k + for i in 1:p + if β_sol[i] == 0 + global k += 1 + end + end + k = p - k + + groups = [] + for i in 1:(k_int-1) + push!(groups, ((i-1)*group_size+1):(i*group_size)) + end + push!(groups, ((k_int-1)*group_size+1):p) + function f(x) + return sum((y_g - A_g * x[1:p]) .^ 2) + + lambda_0_g * sum(x[p+1:2p]) + + lambda_2_g * FrankWolfe.norm(x[1:p])^2 + end + function grad!(storage, x) + storage .= vcat( + 2 * (transpose(A_g) * A_g * x[1:p] - transpose(A_g) * y_g + lambda_2_g * x[1:p]), + lambda_0_g * ones(p), + ) + return storage + end +end + +# n = 20 +# p = 5 * n +# k = ceil(n / 5) +# group_size = convert(Int64, floor(p / k)) +# M_g = 5.0 + +# const lambda_0_g = 0.0 +# const lambda_2_g = 0.0 +# const A_g = rand(Float64, n, p) +# β_sol = rand(Distributions.Uniform(-M_g, M_g), p) +# k_int = convert(Int64, k) + +# for i in 1:k_int +# for _ in 1:group_size-1 +# β_sol[rand(((i-1)*group_size+1):(i*group_size))] = 0 +# end +# end +# const y_g = A_g * β_sol +# k = 0 # correct k +# for i in 1:p +# if β_sol[i] == 0 +# global k += 1 +# end +# end +# k = p - k + +# groups = [] +# for i in 1:(k_int-1) +# push!(groups, ((i-1)*group_size+1):(i*group_size)) +# end +# push!(groups, ((k_int-1)*group_size+1):p) +function build_optimizer(o,p,k,) + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, p) + z = MOI.add_variables(o, p) + for i in 1:p + MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, z[i], MOI.ZeroOne()) # or MOI.Integer() + end + for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M_g], [x[i], z[i]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M_g], [x[i], z[i]]), 0.0), + MOI.LessThan(0.0), + ) + # Indicator: x[i+p] = 1 => -M_g <= x[i] <= M_g + gl = MOI.VectorAffineFunction( + [ + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), + MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[i])), + ], + [0.0, 0.0], + ) + gg = MOI.VectorAffineFunction( + [ + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), + MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-1.0, x[i])), + ], + [0.0, 0.0], + ) + MOI.add_constraint(o, gl, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(M_g))) + MOI.add_constraint(o, gg, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(-M_g))) + end + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), z), 0.0), + MOI.LessThan(1.0 * k), + ) + for i in 1:k_int + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(group_size), z[groups[i]]), 0.0), + MOI.GreaterThan(1.0), + ) + end + lmo = Boscia.MathOptBLMO(o) + global_bounds = Boscia.IntegerBounds() +end + + + + +@testset "Sparse Regression Group" begin + o = SCIP.Optimizer() + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, p) + z = MOI.add_variables(o, p) + for i in 1:p + MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, z[i], MOI.ZeroOne()) # or MOI.Integer() + end + for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M_g], [x[i], z[i]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M_g], [x[i], z[i]]), 0.0), + MOI.LessThan(0.0), + ) + # Indicator: x[i+p] = 1 => -M_g <= x[i] <= M_g + gl = MOI.VectorAffineFunction( + [ + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), + MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[i])), + ], + [0.0, 0.0], + ) + gg = MOI.VectorAffineFunction( + [ + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), + MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-1.0, x[i])), + ], + [0.0, 0.0], + ) + MOI.add_constraint(o, gl, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(M_g))) + MOI.add_constraint(o, gg, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(-M_g))) + end + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), z), 0.0), + MOI.LessThan(1.0 * k), + ) + for i in 1:k_int + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(group_size), z[groups[i]]), 0.0), + MOI.GreaterThan(1.0), + ) + end + lmo = Boscia.MathOptBLMO(o) + global_bounds = Boscia.IntegerBounds() + for i in 1:p + push!(global_bounds, (i + p, 0.0), :greaterthan) + push!(global_bounds, (i + p, 1.0), :lessthan) + push!(global_bounds, (i, -M_g), :greaterthan) + push!(global_bounds, (i, M_g), :lessthan) + end + + function f(x) + return sum((y_g - A_g * x[1:p]) .^ 2) + + lambda_0_g * sum(x[p+1:2p]) + + lambda_2_g * FrankWolfe.norm(x[1:p])^2 + end + function grad!(storage, x) + storage .= vcat( + 2 * (transpose(A_g) * A_g * x[1:p] - transpose(A_g) * y_g + lambda_2_g * x[1:p]), + lambda_0_g * ones(p), + ) + return storage + end + iterations_stable = 4::Int + + decision_function = "weighted_sum" + if decision_function == "product" + μ = 1e-6 + else + μ = 0.7 # μ used in the computation of the branching score + end + + x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=600) + + #x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, rel_dual_gap=1e-5) + + # println("Solution: $(x[1:p])") + z = x[p+1:2p] + @test sum(z) <= k + for i in 1:k_int + @test sum(z[groups[i]]) >= 1 + end + @test f(x) <= f(result[:raw_solution]) + 1e-6 + @show f(x) + @show f(vcat(β_sol, zeros(p))) + @show x[1:p] +end diff --git a/examples/low_dim_in_high_dim_pseudocost.jl b/examples/low_dim_in_high_dim_pseudocost.jl new file mode 100644 index 000000000..5f9cff5e5 --- /dev/null +++ b/examples/low_dim_in_high_dim_pseudocost.jl @@ -0,0 +1,212 @@ +using Boscia +using FrankWolfe +using Test +using Random +using SCIP +using HiGHS +# using Statistics +using LinearAlgebra +using Distributions +import MathOptInterface +const MOI = MathOptInterface + +# The example from "Optimizing a low-dimensional convex function over a high-dimensional cube" +# by Christoph Hunkenschröder, Sebastian Pokutta, Robert Weismantel +# https://arxiv.org/abs/2204.05266. + +m = 500 # larger dimension +n = 12 # small dimension + +function low_dim_high_dim(o, m, n, seed; alpha=0.00) + Random.seed!(seed) + refpoint = 0.5 * ones(n) + Random.rand(n) * alpha * 1 / n + W = rand(m, n) + Ws = transpose(W) * W + function f(x) + return 0.5 * (dot(x, Ws, x) - dot(refpoint, Ws, x) - dot(x, Ws, refpoint)) + end + + function grad!(storage, x) + return mul!(storage, Ws, (x - refpoint)) + end + + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, n) + for xi in x + MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) + MOI.add_constraint(o, xi, MOI.LessThan(1.0)) + MOI.add_constraint(o, xi, MOI.ZeroOne()) + end + lmo = Boscia.MathOptBLMO(o) + return lmo, f, grad! +end + + + + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Example sizes ###################### + +n_choices = Int[10, +#40 +] +m_choices = [500] +seeds = rand(UInt64, 3) + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 60 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "low_dim_high_dim_a_c" +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +for i in [1] + o = SCIP.Optimizer() + lmo, f, grad! = low_dim_high_dim(o, 500, 10, 1; alpha=0.00) + # println(o) + println("precompile") + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) + # print(lmo.o) +end +println("actual run")################################################################# + + +for seed in seeds + for dim in n_choices + n0 = dim + for branching_strategy in strategies + o = SCIP.Optimizer() + lmo, f, grad! = low_dim_high_dim(o, m, n, seed; alpha= 0.00) + example_name = string("low_dim_high_dim_m_", m, "n_", n) + if branching_strategy == "Strong_Branching" + #blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end +end + + + +# alpha = 0.00 +# const refpoint = 0.5 * ones(n) + Random.rand(n) * alpha * 1 / n +# W = rand(m, n) +# const Ws = transpose(W) * W + +# function f(x) +# return 0.5 * (dot(x, Ws, x) - dot(refpoint, Ws, x) - dot(x, Ws, refpoint)) +# end + +# function grad!(storage, x) +# return mul!(storage, Ws, (x - refpoint)) +# end + +# @testset "Low-dimensional function (SCIP)" begin +# o = SCIP.Optimizer() +# MOI.set(o, MOI.Silent(), true) +# MOI.empty!(o) +# x = MOI.add_variables(o, n) +# for xi in x +# MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) +# MOI.add_constraint(o, xi, MOI.LessThan(1.0)) +# MOI.add_constraint(o, xi, MOI.ZeroOne()) +# end +# lmo = FrankWolfe.MathOptLMO(o) + +# x, _, result = Boscia.solve(f, grad!, lmo, verbose=true) + +# if n < 15 # only do for small n +# valopt, xopt = Boscia.min_via_enum(f, n) +# @test (f(x) - f(xopt)) / abs(f(xopt)) <= 1e-3 +# end + +# @test f(x) <= f(result[:raw_solution]) + 1e-6 +# end + +# @testset "Low-dimensional function (CubeSimpleBLMO)" begin + +# int_vars = collect(1:n) + +# lbs = zeros(n) +# ubs = ones(n) + +# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) + +# # modified solve call from managed_blmo.jl automatically wraps sblmo into a managed_blmo +# x, _, result = Boscia.solve(f, grad!, sblmo, lbs[int_vars], ubs[int_vars], int_vars, n, verbose=true) + +# if n < 15 # only do for small n +# valopt, xopt = Boscia.min_via_enum(f, n) +# @test (f(x) - f(xopt)) / abs(f(xopt)) <= 1e-3 +# end + +# @test f(x) <= f(result[:raw_solution]) + 1e-6 +# end diff --git a/examples/mps-example_pseudocost.jl b/examples/mps-example_pseudocost.jl new file mode 100644 index 000000000..108e8ebf6 --- /dev/null +++ b/examples/mps-example_pseudocost.jl @@ -0,0 +1,202 @@ +using Boscia +using FrankWolfe +using Test +using Random +using SCIP +using HiGHS +using LinearAlgebra +import MathOptInterface +const MOI = MathOptInterface + + +# A MIPLIB instance: 22433 +# https://miplib.zib.de/instance_details_22433.html +# Objective function: Minimize the distance to randomely picked vertices +# Number of variables 429 +# Number of integers 0 +# Number of binaries 231 +# Number of constraints 198 + +# seed = rand(UInt64) +# @show seed +# Random.seed!(seed) + +function build_example(o, seed) + Random.seed!(seed) + MOI.empty!(o) + src = MOI.FileFormats.Model(filename="22433.mps") + MOI.read_from_file(src, joinpath(@__DIR__, "mps-examples/mps-files/22433.mps")) + + MOI.copy_to(o, src) + MOI.set(o, MOI.Silent(), true) + n = MOI.get(o, MOI.NumberOfVariables()) + lmo = Boscia.MathOptBLMO(o) + vs = [FrankWolfe.compute_extreme_point(lmo, randn(n)) for _ in 1:20] + + unique!(vs) + filter!(vs) do v + return v[end] != 21477.0 + end + + @assert !isempty(vs) + b_mps = randn(n) + function f(x) + r = dot(b_mps, x) + for v in vs + r += 1 / 2 * norm(x - v)^2 + end + return r + end + + function grad!(storage, x) + mul!(storage, length(vs) * I, x) + storage .+= b_mps + for v in vs + @. storage -= v + end + end + return lmo, f, grad! +end + + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Example sizes ###################### + +seeds = rand(UInt64, 3) + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 60 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "MPS_22433_instance_a_c" +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +for i in [1] + o = SCIP.Optimizer() + lmo, f, grad! = build_example(o, 1) + # println(o) + println("precompile") + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) + # print(lmo.o) +end +println("actual run")################################################################# + +################################################################# + +for seed in seeds + for branching_strategy in strategies + example_name = "MPS_22433_instance" + o = SCIP.Optimizer() + f, grad!, lmo = build_example(o, seed) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end +end + + + + +# src = MOI.FileFormats.Model(filename="22433.mps") +# MOI.read_from_file(src, joinpath(@__DIR__, "mps-examples/mps-files/22433.mps")) + +# o = SCIP.Optimizer() +# MOI.copy_to(o, src) +# MOI.set(o, MOI.Silent(), true) +# n = MOI.get(o, MOI.NumberOfVariables()) +# lmo = Boscia.MathOptBLMO(o) + +# #trick to push the optimum towards the interior +# const vs = [FrankWolfe.compute_extreme_point(lmo, randn(n)) for _ in 1:20] +# # done to avoid one vertex being systematically selected +# unique!(vs) +# filter!(vs) do v +# return v[end] != 21477.0 +# end + +# @assert !isempty(vs) +# const b_mps = randn(n) + +# function f(x) +# r = dot(b_mps, x) +# for v in vs +# r += 1 / 2 * norm(x - v)^2 +# end +# return r +# end + +# function grad!(storage, x) +# mul!(storage, length(vs) * I, x) +# storage .+= b_mps +# for v in vs +# @. storage -= v +# end +# end + +# @testset "MPS 22433 instance" begin +# iterations_stable = 1::Int +# μ = 0.7 # μ used in the computation of the branching score +# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) +# @test f(x) <= f(result[:raw_solution]) +# end diff --git a/examples/mps-examples/mip-examples_pseudocost.jl b/examples/mps-examples/mip-examples_pseudocost.jl new file mode 100644 index 000000000..7f0f9413b --- /dev/null +++ b/examples/mps-examples/mip-examples_pseudocost.jl @@ -0,0 +1,265 @@ +using Boscia +using FrankWolfe +using Test +using Random +using SCIP +using LinearAlgebra +import MathOptInterface +const MOI = MathOptInterface +import Ipopt + + +# MIPLIB instances +# Objective function: Minimize the distance to randomely picked vertices + +# Possible files +# 22433 https://miplib.zib.de/instance_details_22433.html +# n5-3 https://miplib.zib.de/instance_details_n5-3.html +# neos5 https://miplib.zib.de/instance_details_neos5.html +# pg https://miplib.zib.de/instance_details_pg.html +# pg5_34 https://miplib.zib.de/instance_details_pg5_34.html +# ran14x18-disj-8 https://miplib.zib.de/instance_details_ran14x18-disj-8.html +# timtab1 https://miplib.zib.de/instance_details_timtab1.html (Takes LONG!) + +seed = rand(UInt64) +#seed = 0x1d52d0c243ef0c61 +seed = 7924543777773248845 +@show seed + +#Random.seed!(seed) +file_name = "mip_examples_long" # for saving results in "./results/" +# To see debug statements +#ENV["JULIA_DEBUG"] = "Boscia" + + + +function build_example(example, num_v, seed) + file_name = string(example, ".mps") + src = MOI.FileFormats.Model(filename=file_name) + MOI.read_from_file(src, joinpath(@__DIR__, string("mps-files/", file_name))) + + o = SCIP.Optimizer() + MOI.copy_to(o, src) + MOI.set(o, MOI.Silent(), true) + n = MOI.get(o, MOI.NumberOfVariables()) + lmo = Boscia.MathOptBLMO(o) + + # Disable Presolving + MOI.set(o, MOI.RawOptimizerAttribute("presolving/maxrounds"), 0) + Random.seed!(seed) + #trick to push the optimum towards the interior + vs = [FrankWolfe.compute_extreme_point(lmo, randn(n)) for _ in 1:num_v] + # done to avoid one vertex being systematically selected + unique!(vs) + + @assert !isempty(vs) + b_mps = randn(n) + max_norm = maximum(norm.(vs)) + + function f(x) + r = dot(b_mps, x) + for v in vs + r += 1 / (2 * max_norm) * norm(x - v)^2 + end + return r + end + + function grad!(storage, x) + mul!(storage, length(vs) / max_norm * I, x) + storage .+= b_mps + for v in vs + @. storage -= 1 / max_norm * v + end + end + + return lmo, f, grad! +end +example = "neos5" + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10,20] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + + +############## Set Parameters for all runs ###################### +verbose = true +print_iter=10 +fw_epsilon=1e-1 +min_node_fw_epsilon=1e-3 +time_limit=600 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "mip-examples_a_c" + + +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +################################################################# + + + + +for example in ["neos5", + "pg", "22433", "pg5_34", "ran14x18-disj-8", "n5-3", + "timtab1" ] + num_v = 0 + if example == "neos5" + num_v = 5 + elseif example == "pg" + num_v = 5 + elseif example == "22433" + num_v = 20 + elseif example == "pg5_34" + num_v = 5 + elseif example == "ran14x18-disj-8" + num_v = 5 + elseif example == "n5-3" + num_v = 100 + elseif example == "timtab1" + num_v = 3 + end + + test_instance = string("MPS ", example, " instance") + + #println("Example $(example)") + example_name = test_instance + for branching_strategy in strategies + lmo, f, grad! = build_example(example, num_v, seed) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap, + fw_epsilon=fw_epsilon, + min_node_fw_epsilon=min_node_fw_epsilon + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap, + fw_epsilon=fw_epsilon, + min_node_fw_epsilon=min_node_fw_epsilon + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap, + fw_epsilon=fw_epsilon, + min_node_fw_epsilon=min_node_fw_epsilon + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end +end + + + +# ############## Product PSEUDO_COST ############################### + +# iterations_stable = 10 +# decision_function = "product" +# if decision_function == "product" +# μ = 1e-6 +# else +# μ = 0.7 # μ used in the computation of the branching score +# end + +# x, _, result = Boscia.solve( +# f, +# grad!, +# lmo, +# branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), +# verbose=true, +# print_iter=10, +# fw_epsilon=1e-1, +# min_node_fw_epsilon=1e-3, +# time_limit=3600, +# ) +# settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) +# Boscia.save_results(result, settings, example, seed, file_name, false) + +# ############## MOST_INFEASIBLE ##################### +# lmo, f, grad! = build_example(example, num_v, seed) +# settings = "MOST_INFEASIBLE" +# x, _, result = Boscia.solve( +# f, +# grad!, +# lmo, +# verbose=true, +# print_iter=10, +# fw_epsilon=1e-1, +# min_node_fw_epsilon=1e-3, +# time_limit=3600, +# ) + +# settings = "MOST_INFEASIBLE" +# Boscia.save_results(result, settings, example, seed, file_name, false) + +# ############## Strong_Branching ############################## +# lmo, f, grad! = build_example(example, num_v, seed) +# blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) +# branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) +# MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + +# x, _, result = +# Boscia.solve( +# f, +# grad!, +# lmo, +# branching_strategy=branching_strategy, +# verbose=true, +# print_iter=10, +# fw_epsilon=1e-1, +# min_node_fw_epsilon=1e-3, +# time_limit=3600, +# ) +# settings = "Strong_Branching" +# Boscia.save_results(result, settings, example, seed, file_name, false) +# end \ No newline at end of file diff --git a/examples/nonlinear_pseudocost.jl b/examples/nonlinear_pseudocost.jl new file mode 100644 index 000000000..b0a0cf94c --- /dev/null +++ b/examples/nonlinear_pseudocost.jl @@ -0,0 +1,266 @@ +using FrankWolfe +using LinearAlgebra +import MathOptInterface +using Random +using Boscia +using Bonobo +import Bonobo +using Printf +using Dates +using HiGHS +using SCIP +const MOI = MathOptInterface + +# n = 50 +# seed = rand(UInt64) + +# Random.seed!(seed) +# @show(seed) + +# ## generate constants ### +# const A = let +# A = randn(n, n) +# A' * A +# end + +# @assert isposdef(A) == true + +# const y = Random.rand(Bool, n) * 0.6 .+ 0.3 + +################################################################ +# alternative implementation of LMO using MOI and SCIP +################################################################ + +function build_examples(o, n, seed) + Random.seed!(seed) + A = let + A = randn(n, n) + A' * A + end + + @assert isposdef(A) == true + + y = Random.rand(Bool, n) * 0.6 .+ 0.3 + + MOI.set(o, MOI.Silent(), true) + MOI.empty!(o) + x = MOI.add_variables(o, n) + for xi in x + MOI.add_constraint(o, xi, MOI.ZeroOne()) + MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) + MOI.add_constraint(o, xi, MOI.LessThan(1.0)) + end + lmo = Boscia.MathOptBLMO(o) + + function f(x) + d = x - y + return dot(d, A, d) + end + + function grad!(storage, x) + # storage = Ax + mul!(storage, A, x) + # storage = 2Ax - 2Ay + return mul!(storage, A, y, -2, 2) + end + return f, grad!, lmo +end + + +################################################################ +# LMO via CubeSimpleBLMO +################################################################ +# function build_examples(n, seed) +# Random.seed!(seed) +# int_vars = collect(1:n) + +# lbs = zeros(n) +# ubs = ones(n) + +# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) +# # wrap the sblmo into a bound manager +# lmo = Boscia.ManagedBoundedLMO(sblmo, lbs[int_vars], ubs[int_vars], int_vars, n) + +# const A = let +# A = randn(n, n) +# A' * A +# end + +# @assert isposdef(A) == true + +# const y = Random.rand(Bool, n) * 0.6 .+ 0.3 + +# function f(x) +# d = x - y +# return dot(d, A, d) +# end + +# function grad!(storage, x) +# # storage = Ax +# mul!(storage, A, x) +# # storage = 2Ax - 2Ay +# return mul!(storage, A, y, -2, 2) +# end +# return f, grad!, lmo +# end + + + +################# + + +# are these lmo calls counted as well? + +# ##### +# # follow the gradient for a fixed number of steps and collect solutions on the way +# ##### + +# function follow_gradient_heuristic(tree::Bonobo.BnBTree, blmo::Boscia.BoundedLinearMinimizationOracle, x, k) +# nabla = similar(x) +# x_new = copy(x) +# sols = [] +# for i in 1:k +# tree.root.problem.g(nabla,x_new) +# x_new = Boscia.compute_extreme_point(blmo, nabla) +# push!(sols, x_new) +# end +# return sols, false +# end + +# ##### +# # rounding respecting the hidden feasible region structure +# ##### + +# function rounding_lmo_01_heuristic(tree::Bonobo.BnBTree, blmo::Boscia.BoundedLinearMinimizationOracle, x) +# nabla = zeros(length(x)) +# for idx in tree.branching_indices +# nabla[idx] = 1 - 2*round(x[idx]) # (0.7, 0.3) -> (1, 0) -> (-1, 1) -> min -> (1,0) +# end +# x_rounded = Boscia.compute_extreme_point(blmo, nabla) +# return [x_rounded], false +# end + +##### +# geometric scaling like for a couple of steps +##### + + +# depth = 5 +# heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.8, :follow_gradient) +# heu2 = Boscia.Heuristic(Boscia.rounding_lmo_01_heuristic, 0.8, :lmo_rounding) + +# heuristics = [heu, heu2] +# # heuristics = [] + +# x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy = branching_strategy, print_iter=500, custom_heuristics=heuristics) + +# benchmarking Oracles +# f, grad!, lmo = build_examples(n, A, y) +# FrankWolfe.benchmark_oracles(f, grad!, () -> rand(n), lmo; k=100) + + + +############## Example sizes ###################### + +n_choices = Int[10, +#40 +] +seeds = rand(UInt64, 3) + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[10,20] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7, 0.1,0.5,0.9] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end + end +end + +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 500 +time_limit = 1800 + +# Set parameters for saving results +file_name = "nonlinear_examples_a_c" + + + + + + +for i in [1] + o = SCIP.Optimizer() + f, grad!, lmo = build_examples(o,10, 1) + # println(o) + println("precompile") + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) + # print(lmo.o) +end +println("actual run")################################################################# + + +################################################################# +for n in n_choices + for seed in seeds + for branching_strategy in strategies + example_name = "nonlinear_n_" * string(n) + o = SCIP.Optimizer() + f, grad!, lmo = build_examples(o,n, seed) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end +end + diff --git a/examples/portfolio_pseudocost.jl b/examples/portfolio_pseudocost.jl index 91a2826b4..29a68254a 100644 --- a/examples/portfolio_pseudocost.jl +++ b/examples/portfolio_pseudocost.jl @@ -3,31 +3,67 @@ using FrankWolfe using Test using Random using SCIP +using HiGHS using LinearAlgebra import MathOptInterface const MOI = MathOptInterface # seed = 0x946d4b7835e92ffa takes 90 minutes to solve! -> not anymore -seed = 0x946d4b7835e92ffa -Random.seed!(seed) - -n = 30 -const ri = rand(n) -const ai = rand(n) -const Ωi = rand(Float64) -const bi = sum(ai) -Ai = randn(n, n) -Ai = Ai' * Ai -const Mi = (Ai + Ai') / 2 -@assert isposdef(Mi) - - -@testset "Buchheim et. al. example" begin - o = SCIP.Optimizer() +# seed = 0x946d4b7835e92ffa +# Random.seed!(seed) + +# n = 30 +# const ri = rand(n) +# const ai = rand(n) +# const Ωi = rand(Float64) +# const bi = sum(ai) +# Ai = randn(n, n) +# Ai = Ai' * Ai +# const Mi = (Ai + Ai') / 2 +# @assert isposdef(Mi) + + +function build_function(seed, dimension) + @show seed + Random.seed!(seed) + n = dimension + ri = rand(n) + Ωi = rand() + Ai = randn(n, n) + Ai = Ai' * Ai + Mi = (Ai + Ai') / 2 + @assert isposdef(Mi) + + ai = rand(dimension) + bi = sum(ai) + + function f(x) + return 1 / 2 * Ωi * dot(x, Mi, x) - dot(ri, x) + end + function grad!(storage, x) + mul!(storage, Mi, x, Ωi, 0) + storage .-= ri + return storage + end + return f, grad!, n, ri, Ωi, Ai, Mi, ai, bi +end + +function build_optimizer(o, mode, n, ai, bi) MOI.set(o, MOI.Silent(), true) MOI.empty!(o) + println("build optimizer") + # @show ai, bi + + # MOI.set(o, MOI.TimeLimitSec(), limit) x = MOI.add_variables(o, n) - I = collect(1:n) #rand(1:n0, Int64(floor(n0/2))) + + # integer set + if mode == "integer" + I = collect(1:n) + elseif mode == "mixed" + I = 1:(n÷2) + end + for i in 1:n MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) if i in I @@ -45,23 +81,169 @@ const Mi = (Ai + Ai') / 2 MOI.GreaterThan(1.0), ) lmo = Boscia.MathOptBLMO(o) + return lmo, x +end - function f(x) - return 1 / 2 * Ωi * dot(x, Mi, x) - dot(ri, x) - end - function grad!(storage, x) - mul!(storage, Mi, x, Ωi, 0) - storage .-= ri - return storage +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10,20] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end end +end + + +############## Example sizes ###################### + +example_dimensions = [10] + +#seeds = rand(UInt64, 3) +seeds = [0x946d4b7835e92ffa] +modes = ["integer","mixed"] - depth = 5 - heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.2, :follow_gradient) - heuristics = [heu] - # heuristics = [] - iterations_stable = 3 # how many times until we consider a pseudocost as stable - μ = 0.7 # μ used in the computation of the branching score - x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true, time_limit=600, custom_heuristics=heuristics) - @test dot(ai, x) <= bi + 1e-2 - @test f(x) <= f(result[:raw_solution]) + 1e-6 +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 600 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "portfolio_examples_a_c" +################################################################# + + + +for seed in [1] + f, grad!, n, ri, Ωi, Ai, Mi, ai, bi = build_function(seed, 10) + #o = SCIP.Optimizer() + o = HiGHS.Optimizer() + lmo, _ = build_optimizer(o, "integer", n, ai, bi) + # println(o) + println("presolve") + Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10, use_postsolve=false) end +println("actual solve") + +for seed in seeds + for dim in example_dimensions + for mode in modes + example_name = string("portfolio_dim_", dim, "_mode_", mode) + for branching_strategy in strategies + f, grad!, n, ri, Ωi, Ai, Mi, ai, bi = build_function(seed, dim) + o = SCIP.Optimizer() + #o = HiGHS.Optimizer() + lmo, _ = build_optimizer(o, mode, n, ai, bi) + if branching_strategy == "Strong_Branching" + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end + end +end + + + + + + + + + +# @testset "Buchheim et. al. example" begin +# o = SCIP.Optimizer() +# MOI.set(o, MOI.Silent(), true) +# MOI.empty!(o) +# x = MOI.add_variables(o, n) +# I = collect(1:n) #rand(1:n0, Int64(floor(n0/2))) +# for i in 1:n +# MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) +# if i in I +# MOI.add_constraint(o, x[i], MOI.Integer()) +# end +# end +# MOI.add_constraint( +# o, +# MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ai, x), 0.0), +# MOI.LessThan(bi), +# ) +# MOI.add_constraint( +# o, +# MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(n), x), 0.0), +# MOI.GreaterThan(1.0), +# ) +# lmo = Boscia.MathOptBLMO(o) + +# function f(x) +# return 1 / 2 * Ωi * dot(x, Mi, x) - dot(ri, x) +# end +# function grad!(storage, x) +# mul!(storage, Mi, x, Ωi, 0) +# storage .-= ri +# return storage +# end + +# depth = 5 +# heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.2, :follow_gradient) +# heuristics = [heu] +# # heuristics = [] +# iterations_stable = 3 # how many times until we consider a pseudocost as stable +# μ = 0.7 # μ used in the computation of the branching score +# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true, time_limit=600, custom_heuristics=heuristics) +# @test dot(ai, x) <= bi + 1e-2 +# @test f(x) <= f(result[:raw_solution]) + 1e-6 +# end diff --git a/examples/sparse_regression_pseudocost.jl b/examples/sparse_regression_pseudocost.jl index 0f0916382..c895abf42 100644 --- a/examples/sparse_regression_pseudocost.jl +++ b/examples/sparse_regression_pseudocost.jl @@ -4,7 +4,7 @@ using FrankWolfe using Random using LinearAlgebra using SCIP -#using HiGHS +using HiGHS import Bonobo import MathOptInterface const MOI = MathOptInterface @@ -27,20 +27,42 @@ using Test # Each continuous variable β_i is assigned a binary z_i, # z_i = 0 => β_i = 0 +# example_name = "sparse_regression" +# n0 = 10; +# p = 5 * n0; +# k = ceil(n0 / 5); +# const lambda_0 = rand(Float64); +# const lambda_2 = 10.0 * rand(Float64); +# const A = rand(Float64, n0, p) +# const y = rand(Float64, n0) +# const M = 2 * var(A) -n0 = 20; -p = 5 * n0; -k = ceil(n0 / 5); -const lambda_0 = rand(Float64); -const lambda_2 = 10.0 * rand(Float64); -const A = rand(Float64, n0, p) -const y = rand(Float64, n0) -const M = 2 * var(A) +function build_function(seed, n) + Random.seed!(seed) + p = 5 * n; + k = ceil(n / 5); + lambda_0 = rand(Float64); + lambda_2 = 10.0 * rand(Float64); + A = rand(Float64, n, p) + y = rand(Float64, n) + M = 2 * var(A) + # @show A, y, M, lambda_0, lambda_2 -# "Sparse Regression" -@testset "Sparse regression" begin - o = SCIP.Optimizer() - #o = HiGHS.Optimizer() + function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 + end + + function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage + end + + return f, grad!, p, k, M, A, y, lambda_0, lambda_2 +end + +function build_optimizer(o, p, k, M) MOI.set(o, MOI.Silent(), true) MOI.empty!(o) x = MOI.add_variables(o, 2p) @@ -67,21 +89,118 @@ const M = 2 * var(A) MOI.LessThan(k), ) lmo = Boscia.MathOptBLMO(o) + return lmo, x +end - function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 - end - function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage + + + + +############ Decide which strategies to run ##################### +strategies = Any[ + "MOST_INFEASIBLE", "Strong_Branching" +] + +for iterations_stable in Int64[5,10] + for decision_function in [ + "product", + "weighted_sum" + ] + if decision_function == "product" + μ = 1e-6 + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + else + for μ in [0.7] + push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) + end + end end - iterations_stable = 1::Int - μ = 0.7 # μ used in the computation of the branching score - x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ),verbose=true, fw_epsilon=1e-3, print_iter=10) +end + + +############## Example sizes ###################### + +no_choices = Int[10, +#40 +] + +seeds = rand(UInt64, 3) - # @show result // too large to be output - @test f(x) <= f(result[:raw_solution]) + 1e-6 +############## Set Parameters for all runs ###################### +verbose = true +print_iter = 100 +time_limit = 600 +rel_dual_gap=1e-2 +# Set parameters for saving results +file_name = "sparse_reg_examples_a_c" +#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) +f, grad!, p, k, M, A, y, lambda_0, lambda_2 = build_function(1, 10) +o = SCIP.Optimizer() +lmo, _ = build_optimizer(o, p, k, M) +# println(o) +println("precompile") +Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) +# print(lmo.o) +println("actual run")################################################################# + + +for seed in seeds + for dim in no_choices + n0 = dim + for branching_strategy in strategies + f, grad!, p, k, M, A, y, lambda_0, lambda_2 = build_function(seed, n0) + o = SCIP.Optimizer() + example_name = string("sparse_reg_n0_", n0, "_p_", p, "_k_",k) + lmo, _ = build_optimizer(o, p, k, M) + if branching_strategy == "Strong_Branching" + #blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) + blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) + branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) + MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + x, _, result = + Boscia.solve( + f, + grad!, + lmo, + branching_strategy=branching_strategy,verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "Strong_Branching" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + + elseif branching_strategy == "MOST_INFEASIBLE" + x, _, result = Boscia.solve( + f, + grad!, + lmo, + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "MOST_INFEASIBLE" + Boscia.save_results(result, settings, example_name, seed, file_name, false) + else + iterations_stable = branching_strategy[:iterations_stable] + decision_function = branching_strategy[:decision_function] + μ = branching_strategy[:μ] + x, _, result = Boscia.solve( + f, + grad!, + lmo, + branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), + verbose=verbose, + print_iter=print_iter, + time_limit=time_limit, + rel_dual_gap=rel_dual_gap + ) + settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) + Boscia.save_results(result, settings, example_name, seed, file_name, false) + end + end + end end + diff --git a/examples/sparse_regression_pseudocost_used_for_emp_results.jl b/examples/sparse_regression_pseudocost_used_for_emp_results.jl new file mode 100644 index 000000000..3eca3901e --- /dev/null +++ b/examples/sparse_regression_pseudocost_used_for_emp_results.jl @@ -0,0 +1,403 @@ +using Statistics +using Boscia +using FrankWolfe +using Random +using LinearAlgebra +using HiGHS +#using HiGHS +import Bonobo +import MathOptInterface +const MOI = MathOptInterface +using Dates +using Printf +using Test + +# Sparse regression + +# Constant parameters for the sparse regression +# min norm(y-A β)² + λ_0 ∑ z_i + λ_2 ||β||² +# s.t. -Mz_i <= β_i <= Mz_i +# ∑ z_i <= k +# z_i ∈ {0,1} for i = 1,..,p + +# A - matrix of observations. +# y - vector of results. +# We want to match Aβ as closely as possible to y +# while having relative few non zero entries in β. +# Each continuous variable β_i is assigned a binary z_i, +# z_i = 0 => β_i = 0 + +############################################# Problem set up ################################################# +n0 = 28 +p = 5 * n0; +k = ceil(n0 / 5); +seed = rand(UInt64) +#seed = 0x0c1145c200469bf1 +#seed = 0x2c6d6bd3949ad1f0 +@show seed + +Random.seed!(seed) + + +const lambda_0 = rand(Float64); +const lambda_2 = 10.0 * rand(Float64); +const A = rand(Float64, n0, p) +const y = rand(Float64, n0) +const M = 2 * var(A) +example_name = "sparse_regression_n0_" * string(n0) * "p_" * string(p) +################################################################################################################ +file_name ="sparse_reg_examples_a_c" # for saving results in "./results/" +###### run once to make sure everything is initialized + + +o = HiGHS.Optimizer() +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +lmo = Boscia.MathOptBLMO(o) + +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end + + +x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=30) + + +#################### weighted_sum ################################################################# + + +o = HiGHS.Optimizer() +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +lmo = Boscia.MathOptBLMO(o) + +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end +iterations_stable = 4::Int + +decision_function = "weighted_sum" +if decision_function == "product" + μ = 1e-6 +else + μ = 0.1 # μ used in the computation of the branching score +end + +x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=300) +settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) +Boscia.save_results(result, settings, example_name, seed, file_name, true) + + + +o = HiGHS.Optimizer() +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +lmo = Boscia.MathOptBLMO(o) + +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end +iterations_stable = 10::Int + +decision_function = "weighted_sum" +if decision_function == "product" + μ = 1e-6 +else + μ = 0.1 # μ used in the computation of the branching score +end + +x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=300) +settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) +Boscia.save_results(result, settings, example_name, seed, file_name, false) + + + +# ############################## product rule ############################################################ + + +o = HiGHS.Optimizer() +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +lmo = Boscia.MathOptBLMO(o) + +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end +iterations_stable = 4::Int + +decision_function = "product" +if decision_function == "product" + μ = 1e-6 +else + μ = 0.7 # μ used in the computation of the branching score +end +x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=300) +settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) +Boscia.save_results(result, settings, example_name, seed, file_name, false) + + + +o = HiGHS.Optimizer() +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +lmo = Boscia.MathOptBLMO(o) + +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end +iterations_stable = 10::Int + +decision_function = "product" +if decision_function == "product" + μ = 1e-6 +else + μ = 0.7 # μ used in the computation of the branching score +end +x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, time_limit=300) +settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) +Boscia.save_results(result, settings, example_name, seed, file_name, false) + +# ######################### MOST_INFEASIBLE ########################################################## +o = HiGHS.Optimizer() +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +lmo = Boscia.MathOptBLMO(o) + +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end + +x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, fw_epsilon=1e-3, time_limit=300) +settings = "MOST_INFEASIBLE" +Boscia.save_results(result, settings, example_name, seed, file_name, false) + + + + + +o = HiGHS.Optimizer() + +MOI.set(o, MOI.Silent(), true) +MOI.empty!(o) +x = MOI.add_variables(o, 2p) +for i in p+1:2p + MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) + MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) + MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() +end +for i in 1:p + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), + MOI.GreaterThan(0.0), + ) + MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), + MOI.LessThan(0.0), + ) +end +MOI.add_constraint( + o, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), + MOI.LessThan(k), +) +function f(x) + xv = @view(x[1:p]) + return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 +end + +function grad!(storage, x) + storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) + storage[p+1:2p] .= lambda_0 + return storage +end +lmo = Boscia.MathOptBLMO(o) +blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) +branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) +MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) + +x, _, result_strong_branching = + Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy=branching_strategy, time_limit=300) +settings = "Strong_Branching" +Boscia.save_results(result_strong_branching, settings, example_name, seed, file_name, false) \ No newline at end of file From 77625bde2a3e69d30c033eb8ad552c0f215b43ce Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:11:21 +0200 Subject: [PATCH 37/56] Deleted anything non src related to enable future merge of new branching strategies --- examples/HiGHS_example_PSEUDO_COST.jl | 37 -- examples/approx_planted_point_pseudocost.jl | 370 ---------------- examples/birkhoff_pseudocost.jl | 406 ------------------ examples/int_sparse_reg_pseudocost.jl | 238 ---------- examples/lasso_pseudocost.jl | 253 ----------- examples/low_dim_in_high_dim_pseudocost.jl | 212 --------- examples/mps-example_pseudocost.jl | 202 --------- examples/nonlinear_pseudocost.jl | 266 ------------ examples/poisson_reg_pseudocost.jl | 270 ------------ examples/portfolio_pseudocost.jl | 249 ----------- examples/sparse_regression_pseudocost.jl | 206 --------- ...ression_pseudocost_used_for_emp_results.jl | 403 ----------------- 12 files changed, 3112 deletions(-) delete mode 100644 examples/HiGHS_example_PSEUDO_COST.jl delete mode 100644 examples/approx_planted_point_pseudocost.jl delete mode 100644 examples/birkhoff_pseudocost.jl delete mode 100644 examples/int_sparse_reg_pseudocost.jl delete mode 100644 examples/lasso_pseudocost.jl delete mode 100644 examples/low_dim_in_high_dim_pseudocost.jl delete mode 100644 examples/mps-example_pseudocost.jl delete mode 100644 examples/nonlinear_pseudocost.jl delete mode 100644 examples/poisson_reg_pseudocost.jl delete mode 100644 examples/portfolio_pseudocost.jl delete mode 100644 examples/sparse_regression_pseudocost.jl delete mode 100644 examples/sparse_regression_pseudocost_used_for_emp_results.jl diff --git a/examples/HiGHS_example_PSEUDO_COST.jl b/examples/HiGHS_example_PSEUDO_COST.jl deleted file mode 100644 index 020bf7cc6..000000000 --- a/examples/HiGHS_example_PSEUDO_COST.jl +++ /dev/null @@ -1,37 +0,0 @@ -using Boscia -using FrankWolfe -using Random -using HiGHS -using LinearAlgebra -import MathOptInterface - -const MOI = MathOptInterface - -n = 7 - -const diffw = Random.rand(Bool, n) * 0.6 .+ 0.3 -o = HiGHS.Optimizer() - -MOI.set(o, MOI.Silent(), true) - -x = MOI.add_variables(o, n) - -for xi in x - MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) - MOI.add_constraint(o, xi, MOI.LessThan(1.0)) - MOI.add_constraint(o, xi, MOI.ZeroOne()) -end -lmo = Boscia.MathOptBLMO(o) - -function f(x) - return 0.5 * sum((x .- diffw) .^ 2) -end - -function grad!(storage, x) - @. storage = x - diffw -end -#pseudos = Dict{Int,Array{Float64}}(idx=>zeros(2) for idx in Boscia.get_integer_variables(lmo)) -#branch_tracker = Dict{Int, Float64}(idx=> 0 for idx in Boscia.get_integer_variables(lmo)) -iterations_stable = 1::Int -μ = 0.7 # μ used in the computation of the branching score -x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) \ No newline at end of file diff --git a/examples/approx_planted_point_pseudocost.jl b/examples/approx_planted_point_pseudocost.jl deleted file mode 100644 index 581d1c585..000000000 --- a/examples/approx_planted_point_pseudocost.jl +++ /dev/null @@ -1,370 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using SCIP -using HiGHS -# using Statistics -using LinearAlgebra -#using Distributions -import MathOptInterface -const MOI = MathOptInterface - -include("cube_blmo.jl") - -n = 20 -diffi = Random.rand(Bool, n) * 0.6 .+ 0.3 - - -function approx_planted_point_integer(n, seed) - Random.seed!(seed) - diffi = Random.rand(Bool, n) * 0.6 .+ 0.3 - function f(x) - return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) - end - function grad!(storage, x) - @. storage = x - diffi - end - # using SCIP - o = SCIP.Optimizer() - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, n) - for xi in x - MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) - MOI.add_constraint(o, xi, MOI.LessThan(1.0)) - MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() - end - lmo = Boscia.MathOptBLMO(o) - return lmo, f, grad! -end - -function approx_planted_point_mixed(n, seed) - Random.seed!(seed) - diffi = Random.rand(Bool, n) * 0.6 .+ 0.3 - function f(x) - return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) - end - function grad!(storage, x) - @. storage = x - diffi - end - int_vars = unique!(rand(collect(1:n), Int(floor(n / 2)))) - o = SCIP.Optimizer() - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, n) - for xi in x - MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) - MOI.add_constraint(o, xi, MOI.LessThan(1.0)) - if xi.value in int_vars - MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() - end - end - lmo = Boscia.MathOptBLMO(o) - - return lmo, f, grad! -end - - - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10,20] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -example_dimensions = [20, 25] -seeds = rand(UInt64, 3) - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 600 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "approx_planted_point_a_c" -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -################################################################# - -for seed in seeds - for dim in example_dimensions - example_name = string("approx_planted_point_integer_n", dim) - for branching_strategy in strategies - lmo, f, grad! = approx_planted_point_integer(dim, seed) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end -end - -for seed in seeds - for dim in example_dimensions - example_name = string("approx_planted_point_mixed_n", dim) - for branching_strategy in strategies - lmo, f, grad! = approx_planted_point_mixed(dim, seed) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end -end - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# @testset "Approximate planted point - Integer" begin - -# function f(x) -# return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) -# end -# function grad!(storage, x) -# @. storage = x - diffi -# end - -# @testset "Using SCIP" begin -# o = SCIP.Optimizer() -# MOI.set(o, MOI.Silent(), true) -# MOI.empty!(o) -# x = MOI.add_variables(o, n) -# for xi in x -# MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) -# MOI.add_constraint(o, xi, MOI.LessThan(1.0)) -# MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() -# end -# lmo = Boscia.MathOptBLMO(o) - -# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) - -# @test x == round.(diffi) -# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) -# end - -# @testset "Using Cube LMO" begin -# int_vars = collect(1:n) - -# bounds = Boscia.IntegerBounds() -# for i in 1:n -# push!(bounds, (i, 0.0), :greaterthan) -# push!(bounds, (i, 1.0), :lessthan) -# end -# blmo = CubeBLMO(n, int_vars, bounds) - -# x, _, result = Boscia.solve(f, grad!, blmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, blmo, μ), verbose=true) - - -# @test x == round.(diffi) -# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) -# end - -# @testset "Using Cube Simple LMO" begin -# int_vars = collect(1:n) -# lbs = zeros(n) -# ubs = ones(n) - -# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) - -# x, _, result = -# Boscia.solve(f, grad!, sblmo, lbs[int_vars], ubs[int_vars], int_vars, n, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, sblmo, μ), verbose=true) - -# @test x == round.(diffi) -# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) -# end -# end - - -# @testset "Approximate planted point - Mixed" begin - -# function f(x) -# return 0.5 * sum((x[i] - diffi[i])^2 for i in eachindex(x)) -# end -# function grad!(storage, x) -# @. storage = x - diffi -# end - -# int_vars = unique!(rand(collect(1:n), Int(floor(n / 2)))) - -# @testset "Using SCIP" begin -# o = SCIP.Optimizer() -# MOI.set(o, MOI.Silent(), true) -# MOI.empty!(o) -# x = MOI.add_variables(o, n) -# for xi in x -# MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) -# MOI.add_constraint(o, xi, MOI.LessThan(1.0)) -# if xi.value in int_vars -# MOI.add_constraint(o, xi, MOI.ZeroOne()) # or MOI.Integer() -# end -# end -# lmo = Boscia.MathOptBLMO(o) - -# x, _, result = Boscia.solve(f, grad!, blmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) - -# sol = diffi -# sol[int_vars] = round.(sol[int_vars]) -# @test sum(isapprox.(x, sol, atol=1e-6, rtol=1e-2)) == n -# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) -# end - -# @testset "Using Cube LMO" begin -# bounds = Boscia.IntegerBounds() -# for i in 1:n -# push!(bounds, (i, 0.0), :greaterthan) -# push!(bounds, (i, 1.0), :lessthan) -# end -# blmo = CubeBLMO(n, int_vars, bounds) - -# x, _, result = Boscia.solve(f, grad!, blmo, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, blmo, μ), verbose=true) - -# sol = diffi -# sol[int_vars] = round.(sol[int_vars]) -# @test sum(isapprox.(x, sol, atol=1e-6, rtol=1e-2)) == n -# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) -# end - -# @testset "Using Cube Simple LMO" begin -# lbs = zeros(n) -# ubs = ones(n) - -# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) - -# x, _, result = -# Boscia.solve(f, grad!, sblmo, lbs[int_vars], ubs[int_vars], int_vars, n, branching_strategy = Boscia.PSEUDO_COST(iterations_stable,false, sblmo, μ), verbose=true) - -# sol = diffi -# sol[int_vars] = round.(sol[int_vars]) -# @test sum(isapprox.(x, sol, atol=1e-6, rtol=1e-2)) == n -# @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-3) -# end -# end diff --git a/examples/birkhoff_pseudocost.jl b/examples/birkhoff_pseudocost.jl deleted file mode 100644 index b4937b22e..000000000 --- a/examples/birkhoff_pseudocost.jl +++ /dev/null @@ -1,406 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using SCIP -using HiGHS -using LinearAlgebra -import MathOptInterface -const MOI = MathOptInterface -import HiGHS - -# Example on the Birkhoff polytope but using permutation matrices directly -# https://arxiv.org/pdf/2011.02752.pdf -# https://www.sciencedirect.com/science/article/pii/S0024379516001257 - -# For bug hunting: -# seed = rand(UInt64) - -# #seed = 0x3eb09305cecf69f0 -# @show seed -# Random.seed!(seed) - - -# min_{X, θ} 1/2 * || ∑_{i in [k]} θ_i X_i - Xhat ||^2 -# θ ∈ Δ_k (simplex) -# X_i ∈ P_n (permutation matrix) - -# we linearize the bilinear terms in the objective -# min_{X, Y, θ} 1/2 ||∑_{i in [k]} Y - Xhat ||^2 -# θ ∈ Δ_k (simplex) -# X_i ∈ P_n (permutation matrix) -# 0 ≤ Y_i ≤ X_i -# 0 ≤ θ_i - Y_i ≤ 1 - X_i - -# The variables are ordered (Y, X, theta) in the MOI model -# the objective only uses the last n^2 variables -# Small dimensions since the size of the problem grows quickly (2 k n^2 + k variables) -# n = 5 -# k = 3 -# file_name = "birkhoff_examples" -# example_name = "birkhoff_n_" * string(n) * "_k_" * string(k) -# # generate random doubly stochastic matrix -# const Xstar = rand(n, n) -# while norm(sum(Xstar, dims=1) .- 1) > 1e-6 || norm(sum(Xstar, dims=2) .- 1) > 1e-6 -# Xstar ./= sum(Xstar, dims=1) -# Xstar ./= sum(Xstar, dims=2) -# end - -function build_function(n, k, seed) - - Random.seed!(seed) - Xstar = rand(n, n) - while norm(sum(Xstar, dims=1) .- 1) > 1e-6 || norm(sum(Xstar, dims=2) .- 1) > 1e-6 - Xstar ./= sum(Xstar, dims=1) - Xstar ./= sum(Xstar, dims=2) - end - - function f(x) - s = zero(eltype(x)) - for i in eachindex(Xstar) - s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 - end - return s - end - - # note: reshape gives a reference to the same data, so this is updating storage in-place - function grad!(storage, x) - storage .= 0 - for j in 1:k - Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) - @. Sk = -Xstar - for m in 1:k - Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) - @. Sk += Yk - end - end - return storage - end - return f, grad! -end - -function build_birkhoff_lmo(o,n,k) - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - Y = [reshape(MOI.add_variables(o, n^2), n, n) for _ in 1:k] - X = [reshape(MOI.add_variables(o, n^2), n, n) for _ in 1:k] - theta = MOI.add_variables(o, k) - - for i in 1:k - MOI.add_constraint.(o, Y[i], MOI.GreaterThan(0.0)) - MOI.add_constraint.(o, Y[i], MOI.LessThan(1.0)) - MOI.add_constraint.(o, X[i], MOI.ZeroOne()) - MOI.add_constraint(o, theta[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, theta[i], MOI.LessThan(1.0)) - # doubly stochastic constraints - MOI.add_constraint.( - o, - vec(sum(X[i], dims=1, init=MOI.ScalarAffineFunction{Float64}([], 0.0))), - MOI.EqualTo(1.0), - ) - MOI.add_constraint.( - o, - vec(sum(X[i], dims=2, init=MOI.ScalarAffineFunction{Float64}([], 0.0))), - MOI.EqualTo(1.0), - ) - # 0 ≤ Y_i ≤ X_i - MOI.add_constraint.(o, 1.0 * Y[i] - X[i], MOI.LessThan(0.0)) - # 0 ≤ θ_i - Y_i ≤ 1 - X_i - MOI.add_constraint.(o, 1.0 * theta[i] .- Y[i] .+ X[i], MOI.LessThan(1.0)) - end - MOI.add_constraint(o, sum(theta, init=0.0), MOI.EqualTo(1.0)) - return Boscia.MathOptBLMO(o) -end - - - - - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -n_choices = Int[3, -#40 -] -k_choices = [2] - -seeds = rand(UInt64, 3) - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 60 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "birkhoff_a_c" -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -for _ in [1] - f, grad! = build_function(3,2, 1) - o = SCIP.Optimizer() - lmo = build_birkhoff_lmo(o, 3,2) - println("precompile") - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) -end -# print(lmo.o) -println("actual run")################################################################# - - -for seed in seeds - for dim in n_choices - for k in k_choices - n = dim - for branching_strategy in strategies - f, grad! = build_function(n, k, seed) - o = SCIP.Optimizer() - lmo = build_birkhoff_lmo(o, n,k) - example_name = string("birkhoff_", n, "_k_",k) - if branching_strategy == "Strong_Branching" - #blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end - end -end - - - - - - - - - -# ############## weighted_sum PSEUDO_COST ############################# -# function f(x) -# s = zero(eltype(x)) -# for i in eachindex(Xstar) -# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 -# end -# return s -# end - -# # note: reshape gives a reference to the same data, so this is updating storage in-place -# function grad!(storage, x) -# storage .= 0 -# for j in 1:k -# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) -# @. Sk = -Xstar -# for m in 1:k -# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) -# @. Sk += Yk -# end -# end -# return storage -# end - -# lmo = build_birkhoff_lmo() -# iterations_stable = 10::Int -# decision_function = "weighted_sum" -# if decision_function == "product" -# μ = 1e-6 -# else -# μ = 0.7 # μ used in the computation of the branching score -# end - -# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=2400) -# settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) -# Boscia.save_results(result, settings, example_name, seed, file_name, false) - - -# # ############## product PSEUDO_COST ############################# -# function f(x) -# s = zero(eltype(x)) -# for i in eachindex(Xstar) -# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 -# end -# return s -# end - -# # note: reshape gives a reference to the same data, so this is updating storage in-place -# function grad!(storage, x) -# storage .= 0 -# for j in 1:k -# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) -# @. Sk = -Xstar -# for m in 1:k -# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) -# @. Sk += Yk -# end -# end -# return storage -# end - -# lmo = build_birkhoff_lmo() -# iterations_stable = 10::Int -# decision_function = "product" -# if decision_function == "product" -# μ = 1e-6 -# else -# μ = 0.7 # μ used in the computation of the branching score -# end -# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=2400) -# settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) -# Boscia.save_results(result, settings, example_name, seed, file_name, false) - - -# ############## MOST_INFEASIBLE ############################# -# function f(x) -# s = zero(eltype(x)) -# for i in eachindex(Xstar) -# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 -# end -# return s -# end - -# # note: reshape gives a reference to the same data, so this is updating storage in-place -# function grad!(storage, x) -# storage .= 0 -# for j in 1:k -# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) -# @. Sk = -Xstar -# for m in 1:k -# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) -# @. Sk += Yk -# end -# end -# return storage -# end -# lmo = build_birkhoff_lmo() -# x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=2400) -# settings = "MOST_INFEASIBLE" -# Boscia.save_results(result, settings, example_name, seed, file_name, false) - - - -# ############## Strong_Branching ############################# -# function f(x) -# s = zero(eltype(x)) -# for i in eachindex(Xstar) -# s += 0.5 * (sum(x[(j-1)*n^2+i] for j in 1:k) - Xstar[i])^2 -# end -# return s -# end - -# # note: reshape gives a reference to the same data, so this is updating storage in-place -# function grad!(storage, x) -# storage .= 0 -# for j in 1:k -# Sk = reshape(@view(storage[(j-1)*n^2+1:j*n^2]), n, n) -# @. Sk = -Xstar -# for m in 1:k -# Yk = reshape(@view(x[(m-1)*n^2+1:m*n^2]), n, n) -# @. Sk += Yk -# end -# end -# return storage -# end -# lmo = build_birkhoff_lmo() -# blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) -# branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) -# MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - -# x, _, result_strong_branching = -# Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy=branching_strategy, fw_epsilon=1e-3, time_limit=2400) -# settings = "Strong_Branching" -# Boscia.save_results(result_strong_branching, settings, example_name, seed, file_name, false) - - - - - - - - - - - -# # TODO the below needs to be fixed -# # TODO can use the min_via_enum function if not too many solutions -# # build optimal solution -# # xopt = zeros(n) -# # for i in 1:n -# # if diffi[i] > 0.5 -# # xopt[i] = 1 -# # end -# # end - -# # @testset "Birkhoff" begin -# # lmo = build_birkhoff_lmo() -# # x, _, result_baseline = Boscia.solve(f, grad!, lmo, verbose=true) -# # @test f(x) <= f(result_baseline[:raw_solution]) + 1e-6 -# # lmo = build_birkhoff_lmo() -# # blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) -# # branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) -# # MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) -# # x_strong, _, result_strong = -# # Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy=branching_strategy) -# # @test f(x) ≈ f(x_strong) -# # @test f(x) <= f(result_strong[:raw_solution]) + 1e-6 -# # end diff --git a/examples/int_sparse_reg_pseudocost.jl b/examples/int_sparse_reg_pseudocost.jl deleted file mode 100644 index db65dddc7..000000000 --- a/examples/int_sparse_reg_pseudocost.jl +++ /dev/null @@ -1,238 +0,0 @@ -using Statistics -using Boscia -using FrankWolfe -using Random -using SCIP -import Bonobo -using Test -import MathOptInterface -const MOI = MathOptInterface - -# Integer sparse regression - -# min norm(y-A x)² -# s.t. 0 <= x_i <= r -# ∑ x_i <= k -# x_i ∈ Z for i = 1,..,n - -# There A represents the collection of data points and -# is a very tall matrix, i.e. number of rows = m >> number of columns = n. -# y - is the vector of results. -# r - controls how often we have to maximal split on a index. -# k - is the sparsity parameter. We only want a few non zero entries. - -# For bug hunting: -# seed = rand(UInt64) -# @show seed -# #seed = 0xeadb922ca734998b -# Random.seed!(seed) - -# n = 10 -# m = 35 -# l = 30 -# k = 4 - -# sol_x = rand(1:l, n) -# for _ in 1:(n-k) -# sol_x[rand(1:n)] = 0 -# end - -#=k=0 # correct k -for i in 1:n - if sol_x[i] == 0 - global k += 1 - end -end -k = n-k =# - -# const D = rand(m, n) -# const y_d = D * sol_x - - -function int_sparse_regression(n, m, l, k, seed) - Random.seed!(seed) - sol_x = rand(1:l, n) - for _ in 1:(n-k) - sol_x[rand(1:n)] = 0 - end - D = rand(m, n) - y_d = D * sol_x - - o = SCIP.Optimizer() - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, n) - z = MOI.add_variables(o, n) - for i in 1:n - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0 * l)) - MOI.add_constraint(o, x[i], MOI.Integer()) - - MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, z[i], MOI.ZeroOne()) - - MOI.add_constraint(o, 1.0 * x[i] - 1.0 * l * z[i], MOI.LessThan(0.0)) - end - MOI.add_constraint(o, sum(z, init=0.0), MOI.LessThan(1.0 * k)) - # MOI.add_constraint(o, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(zeros(n),x), sum(Float64.(iszero.(x)))), MOI.GreaterThan(1.0*(n-k))) - # MOI.add_constraint(o, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(n),z), 0.0), MOI.GreaterThan(1.0*k)) - lmo = Boscia.MathOptBLMO(o) - - function f(x) - xv = @view(x[1:n]) - return 1 / 2 * sum(abs2, y_d - D * xv) #+ lambda_2*FrankWolfe.norm(x)^2 + lambda_0*sum(x[p+1:2p]) - end - - function grad!(storage, x) - storage .= 0 - @view(storage[1:n]) .= transpose(D) * (D * @view(x[1:n]) - y_d) - return storage - end - - return lmo, f, grad! -end - - - -@testset "Integer sparse regression" begin - seed = rand(UInt64) - @show seed - #seed = 0xeadb922ca734998b - Random.seed!(seed) - n = 10 - m = 30 - l = 5 - k = 4 - lmo, f, grad! = int_sparse_regression(n,m,l,k, seed) - - #= function perform_strong_branch(tree, node) - return node.level <= length(tree.root.problem.integer_variables) - end - branching_strategy = Boscia.HybridStrongBranching(10, 1e-3, HiGHS.Optimizer(), perform_strong_branch) - MOI.set(branching_strategy.pstrong.optimizer, MOI.Silent(), true)=# - - - x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, max_fw_iter=10001, rel_dual_gap=1e-3, time_limit=30) - - # val_min, x_min = Boscia.sparse_min_via_enum(f, n, k, fill(0:l, n)) - # #@show x_min - # @show x[1:n] - # @show x_min - # @test val_min == f(x) - # @test isapprox(x[1:n], x_min) - # @test isapprox(f(x), f(result[:raw_solution]), atol=1e-6, rtol=1e-6) -end - - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10,20] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -example_dimensions = [10, 15, 20, 25] -fac_choices = [3,5] -seeds = rand(UInt64, 3) - - - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 600 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "int_sparse_reg_examples_a_c" -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -################################################################# -for seed in seeds - for dim in example_dimensions - for fac in fac_choices - n = dim - m = 3*n - l = 30 - k = ceil(n/fac) - example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) - for branching_strategy in strategies - lmo, f, grad! = int_sparse_regression(n,m,l,k, seed) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end - end -end - - - - - - - - - - diff --git a/examples/lasso_pseudocost.jl b/examples/lasso_pseudocost.jl deleted file mode 100644 index 2f0f4012d..000000000 --- a/examples/lasso_pseudocost.jl +++ /dev/null @@ -1,253 +0,0 @@ -using Statistics -using Distributions -using Boscia -using FrankWolfe -using Random -using Test -using SCIP -import Bonobo -import MathOptInterface -const MOI = MathOptInterface -using Dates -using Printf - -# Lasso - -# Constant parameters for the sparse regression -# min norm(y-A β)² + λ_0 ∑ z_i + λ_2 ||β||² -# s.t. -Mz_i<=β_i <= Mz_i -# ∑ z_i <= k -# z_i ∈ {0,1} for i = 1,..,p - - - - -function build_function(seed, n) - p = 5 * n - k = ceil(n / 5) - group_size = convert(Int64, floor(p / k)) - M_g = 5.0 - lambda_0_g = 0.0 - lambda_2_g = 0.0 - A_g = rand(Float64, n, p) - β_sol = rand(Distributions.Uniform(-M_g, M_g), p) - k_int = convert(Int64, k) - for i in 1:k_int - for _ in 1:group_size-1 - β_sol[rand(((i-1)*group_size+1):(i*group_size))] = 0 - end - end - y_g = A_g * β_sol - k = 0 # correct k - for i in 1:p - if β_sol[i] == 0 - global k += 1 - end - end - k = p - k - - groups = [] - for i in 1:(k_int-1) - push!(groups, ((i-1)*group_size+1):(i*group_size)) - end - push!(groups, ((k_int-1)*group_size+1):p) - function f(x) - return sum((y_g - A_g * x[1:p]) .^ 2) + - lambda_0_g * sum(x[p+1:2p]) + - lambda_2_g * FrankWolfe.norm(x[1:p])^2 - end - function grad!(storage, x) - storage .= vcat( - 2 * (transpose(A_g) * A_g * x[1:p] - transpose(A_g) * y_g + lambda_2_g * x[1:p]), - lambda_0_g * ones(p), - ) - return storage - end -end - -# n = 20 -# p = 5 * n -# k = ceil(n / 5) -# group_size = convert(Int64, floor(p / k)) -# M_g = 5.0 - -# const lambda_0_g = 0.0 -# const lambda_2_g = 0.0 -# const A_g = rand(Float64, n, p) -# β_sol = rand(Distributions.Uniform(-M_g, M_g), p) -# k_int = convert(Int64, k) - -# for i in 1:k_int -# for _ in 1:group_size-1 -# β_sol[rand(((i-1)*group_size+1):(i*group_size))] = 0 -# end -# end -# const y_g = A_g * β_sol -# k = 0 # correct k -# for i in 1:p -# if β_sol[i] == 0 -# global k += 1 -# end -# end -# k = p - k - -# groups = [] -# for i in 1:(k_int-1) -# push!(groups, ((i-1)*group_size+1):(i*group_size)) -# end -# push!(groups, ((k_int-1)*group_size+1):p) -function build_optimizer(o,p,k,) - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, p) - z = MOI.add_variables(o, p) - for i in 1:p - MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, z[i], MOI.ZeroOne()) # or MOI.Integer() - end - for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M_g], [x[i], z[i]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M_g], [x[i], z[i]]), 0.0), - MOI.LessThan(0.0), - ) - # Indicator: x[i+p] = 1 => -M_g <= x[i] <= M_g - gl = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[i])), - ], - [0.0, 0.0], - ) - gg = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-1.0, x[i])), - ], - [0.0, 0.0], - ) - MOI.add_constraint(o, gl, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(M_g))) - MOI.add_constraint(o, gg, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(-M_g))) - end - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), z), 0.0), - MOI.LessThan(1.0 * k), - ) - for i in 1:k_int - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(group_size), z[groups[i]]), 0.0), - MOI.GreaterThan(1.0), - ) - end - lmo = Boscia.MathOptBLMO(o) - global_bounds = Boscia.IntegerBounds() -end - - - - -@testset "Sparse Regression Group" begin - o = SCIP.Optimizer() - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, p) - z = MOI.add_variables(o, p) - for i in 1:p - MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, z[i], MOI.ZeroOne()) # or MOI.Integer() - end - for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M_g], [x[i], z[i]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M_g], [x[i], z[i]]), 0.0), - MOI.LessThan(0.0), - ) - # Indicator: x[i+p] = 1 => -M_g <= x[i] <= M_g - gl = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[i])), - ], - [0.0, 0.0], - ) - gg = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-1.0, x[i])), - ], - [0.0, 0.0], - ) - MOI.add_constraint(o, gl, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(M_g))) - MOI.add_constraint(o, gg, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(-M_g))) - end - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), z), 0.0), - MOI.LessThan(1.0 * k), - ) - for i in 1:k_int - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(group_size), z[groups[i]]), 0.0), - MOI.GreaterThan(1.0), - ) - end - lmo = Boscia.MathOptBLMO(o) - global_bounds = Boscia.IntegerBounds() - for i in 1:p - push!(global_bounds, (i + p, 0.0), :greaterthan) - push!(global_bounds, (i + p, 1.0), :lessthan) - push!(global_bounds, (i, -M_g), :greaterthan) - push!(global_bounds, (i, M_g), :lessthan) - end - - function f(x) - return sum((y_g - A_g * x[1:p]) .^ 2) + - lambda_0_g * sum(x[p+1:2p]) + - lambda_2_g * FrankWolfe.norm(x[1:p])^2 - end - function grad!(storage, x) - storage .= vcat( - 2 * (transpose(A_g) * A_g * x[1:p] - transpose(A_g) * y_g + lambda_2_g * x[1:p]), - lambda_0_g * ones(p), - ) - return storage - end - iterations_stable = 4::Int - - decision_function = "weighted_sum" - if decision_function == "product" - μ = 1e-6 - else - μ = 0.7 # μ used in the computation of the branching score - end - - x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=600) - - #x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, rel_dual_gap=1e-5) - - # println("Solution: $(x[1:p])") - z = x[p+1:2p] - @test sum(z) <= k - for i in 1:k_int - @test sum(z[groups[i]]) >= 1 - end - @test f(x) <= f(result[:raw_solution]) + 1e-6 - @show f(x) - @show f(vcat(β_sol, zeros(p))) - @show x[1:p] -end diff --git a/examples/low_dim_in_high_dim_pseudocost.jl b/examples/low_dim_in_high_dim_pseudocost.jl deleted file mode 100644 index 5f9cff5e5..000000000 --- a/examples/low_dim_in_high_dim_pseudocost.jl +++ /dev/null @@ -1,212 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using SCIP -using HiGHS -# using Statistics -using LinearAlgebra -using Distributions -import MathOptInterface -const MOI = MathOptInterface - -# The example from "Optimizing a low-dimensional convex function over a high-dimensional cube" -# by Christoph Hunkenschröder, Sebastian Pokutta, Robert Weismantel -# https://arxiv.org/abs/2204.05266. - -m = 500 # larger dimension -n = 12 # small dimension - -function low_dim_high_dim(o, m, n, seed; alpha=0.00) - Random.seed!(seed) - refpoint = 0.5 * ones(n) + Random.rand(n) * alpha * 1 / n - W = rand(m, n) - Ws = transpose(W) * W - function f(x) - return 0.5 * (dot(x, Ws, x) - dot(refpoint, Ws, x) - dot(x, Ws, refpoint)) - end - - function grad!(storage, x) - return mul!(storage, Ws, (x - refpoint)) - end - - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, n) - for xi in x - MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) - MOI.add_constraint(o, xi, MOI.LessThan(1.0)) - MOI.add_constraint(o, xi, MOI.ZeroOne()) - end - lmo = Boscia.MathOptBLMO(o) - return lmo, f, grad! -end - - - - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -n_choices = Int[10, -#40 -] -m_choices = [500] -seeds = rand(UInt64, 3) - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 60 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "low_dim_high_dim_a_c" -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -for i in [1] - o = SCIP.Optimizer() - lmo, f, grad! = low_dim_high_dim(o, 500, 10, 1; alpha=0.00) - # println(o) - println("precompile") - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) - # print(lmo.o) -end -println("actual run")################################################################# - - -for seed in seeds - for dim in n_choices - n0 = dim - for branching_strategy in strategies - o = SCIP.Optimizer() - lmo, f, grad! = low_dim_high_dim(o, m, n, seed; alpha= 0.00) - example_name = string("low_dim_high_dim_m_", m, "n_", n) - if branching_strategy == "Strong_Branching" - #blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end -end - - - -# alpha = 0.00 -# const refpoint = 0.5 * ones(n) + Random.rand(n) * alpha * 1 / n -# W = rand(m, n) -# const Ws = transpose(W) * W - -# function f(x) -# return 0.5 * (dot(x, Ws, x) - dot(refpoint, Ws, x) - dot(x, Ws, refpoint)) -# end - -# function grad!(storage, x) -# return mul!(storage, Ws, (x - refpoint)) -# end - -# @testset "Low-dimensional function (SCIP)" begin -# o = SCIP.Optimizer() -# MOI.set(o, MOI.Silent(), true) -# MOI.empty!(o) -# x = MOI.add_variables(o, n) -# for xi in x -# MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) -# MOI.add_constraint(o, xi, MOI.LessThan(1.0)) -# MOI.add_constraint(o, xi, MOI.ZeroOne()) -# end -# lmo = FrankWolfe.MathOptLMO(o) - -# x, _, result = Boscia.solve(f, grad!, lmo, verbose=true) - -# if n < 15 # only do for small n -# valopt, xopt = Boscia.min_via_enum(f, n) -# @test (f(x) - f(xopt)) / abs(f(xopt)) <= 1e-3 -# end - -# @test f(x) <= f(result[:raw_solution]) + 1e-6 -# end - -# @testset "Low-dimensional function (CubeSimpleBLMO)" begin - -# int_vars = collect(1:n) - -# lbs = zeros(n) -# ubs = ones(n) - -# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) - -# # modified solve call from managed_blmo.jl automatically wraps sblmo into a managed_blmo -# x, _, result = Boscia.solve(f, grad!, sblmo, lbs[int_vars], ubs[int_vars], int_vars, n, verbose=true) - -# if n < 15 # only do for small n -# valopt, xopt = Boscia.min_via_enum(f, n) -# @test (f(x) - f(xopt)) / abs(f(xopt)) <= 1e-3 -# end - -# @test f(x) <= f(result[:raw_solution]) + 1e-6 -# end diff --git a/examples/mps-example_pseudocost.jl b/examples/mps-example_pseudocost.jl deleted file mode 100644 index 108e8ebf6..000000000 --- a/examples/mps-example_pseudocost.jl +++ /dev/null @@ -1,202 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using SCIP -using HiGHS -using LinearAlgebra -import MathOptInterface -const MOI = MathOptInterface - - -# A MIPLIB instance: 22433 -# https://miplib.zib.de/instance_details_22433.html -# Objective function: Minimize the distance to randomely picked vertices -# Number of variables 429 -# Number of integers 0 -# Number of binaries 231 -# Number of constraints 198 - -# seed = rand(UInt64) -# @show seed -# Random.seed!(seed) - -function build_example(o, seed) - Random.seed!(seed) - MOI.empty!(o) - src = MOI.FileFormats.Model(filename="22433.mps") - MOI.read_from_file(src, joinpath(@__DIR__, "mps-examples/mps-files/22433.mps")) - - MOI.copy_to(o, src) - MOI.set(o, MOI.Silent(), true) - n = MOI.get(o, MOI.NumberOfVariables()) - lmo = Boscia.MathOptBLMO(o) - vs = [FrankWolfe.compute_extreme_point(lmo, randn(n)) for _ in 1:20] - - unique!(vs) - filter!(vs) do v - return v[end] != 21477.0 - end - - @assert !isempty(vs) - b_mps = randn(n) - function f(x) - r = dot(b_mps, x) - for v in vs - r += 1 / 2 * norm(x - v)^2 - end - return r - end - - function grad!(storage, x) - mul!(storage, length(vs) * I, x) - storage .+= b_mps - for v in vs - @. storage -= v - end - end - return lmo, f, grad! -end - - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -seeds = rand(UInt64, 3) - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 60 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "MPS_22433_instance_a_c" -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -for i in [1] - o = SCIP.Optimizer() - lmo, f, grad! = build_example(o, 1) - # println(o) - println("precompile") - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) - # print(lmo.o) -end -println("actual run")################################################################# - -################################################################# - -for seed in seeds - for branching_strategy in strategies - example_name = "MPS_22433_instance" - o = SCIP.Optimizer() - f, grad!, lmo = build_example(o, seed) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end -end - - - - -# src = MOI.FileFormats.Model(filename="22433.mps") -# MOI.read_from_file(src, joinpath(@__DIR__, "mps-examples/mps-files/22433.mps")) - -# o = SCIP.Optimizer() -# MOI.copy_to(o, src) -# MOI.set(o, MOI.Silent(), true) -# n = MOI.get(o, MOI.NumberOfVariables()) -# lmo = Boscia.MathOptBLMO(o) - -# #trick to push the optimum towards the interior -# const vs = [FrankWolfe.compute_extreme_point(lmo, randn(n)) for _ in 1:20] -# # done to avoid one vertex being systematically selected -# unique!(vs) -# filter!(vs) do v -# return v[end] != 21477.0 -# end - -# @assert !isempty(vs) -# const b_mps = randn(n) - -# function f(x) -# r = dot(b_mps, x) -# for v in vs -# r += 1 / 2 * norm(x - v)^2 -# end -# return r -# end - -# function grad!(storage, x) -# mul!(storage, length(vs) * I, x) -# storage .+= b_mps -# for v in vs -# @. storage -= v -# end -# end - -# @testset "MPS 22433 instance" begin -# iterations_stable = 1::Int -# μ = 0.7 # μ used in the computation of the branching score -# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true) -# @test f(x) <= f(result[:raw_solution]) -# end diff --git a/examples/nonlinear_pseudocost.jl b/examples/nonlinear_pseudocost.jl deleted file mode 100644 index b0a0cf94c..000000000 --- a/examples/nonlinear_pseudocost.jl +++ /dev/null @@ -1,266 +0,0 @@ -using FrankWolfe -using LinearAlgebra -import MathOptInterface -using Random -using Boscia -using Bonobo -import Bonobo -using Printf -using Dates -using HiGHS -using SCIP -const MOI = MathOptInterface - -# n = 50 -# seed = rand(UInt64) - -# Random.seed!(seed) -# @show(seed) - -# ## generate constants ### -# const A = let -# A = randn(n, n) -# A' * A -# end - -# @assert isposdef(A) == true - -# const y = Random.rand(Bool, n) * 0.6 .+ 0.3 - -################################################################ -# alternative implementation of LMO using MOI and SCIP -################################################################ - -function build_examples(o, n, seed) - Random.seed!(seed) - A = let - A = randn(n, n) - A' * A - end - - @assert isposdef(A) == true - - y = Random.rand(Bool, n) * 0.6 .+ 0.3 - - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, n) - for xi in x - MOI.add_constraint(o, xi, MOI.ZeroOne()) - MOI.add_constraint(o, xi, MOI.GreaterThan(0.0)) - MOI.add_constraint(o, xi, MOI.LessThan(1.0)) - end - lmo = Boscia.MathOptBLMO(o) - - function f(x) - d = x - y - return dot(d, A, d) - end - - function grad!(storage, x) - # storage = Ax - mul!(storage, A, x) - # storage = 2Ax - 2Ay - return mul!(storage, A, y, -2, 2) - end - return f, grad!, lmo -end - - -################################################################ -# LMO via CubeSimpleBLMO -################################################################ -# function build_examples(n, seed) -# Random.seed!(seed) -# int_vars = collect(1:n) - -# lbs = zeros(n) -# ubs = ones(n) - -# sblmo = Boscia.CubeSimpleBLMO(lbs, ubs, int_vars) -# # wrap the sblmo into a bound manager -# lmo = Boscia.ManagedBoundedLMO(sblmo, lbs[int_vars], ubs[int_vars], int_vars, n) - -# const A = let -# A = randn(n, n) -# A' * A -# end - -# @assert isposdef(A) == true - -# const y = Random.rand(Bool, n) * 0.6 .+ 0.3 - -# function f(x) -# d = x - y -# return dot(d, A, d) -# end - -# function grad!(storage, x) -# # storage = Ax -# mul!(storage, A, x) -# # storage = 2Ax - 2Ay -# return mul!(storage, A, y, -2, 2) -# end -# return f, grad!, lmo -# end - - - -################# - - -# are these lmo calls counted as well? - -# ##### -# # follow the gradient for a fixed number of steps and collect solutions on the way -# ##### - -# function follow_gradient_heuristic(tree::Bonobo.BnBTree, blmo::Boscia.BoundedLinearMinimizationOracle, x, k) -# nabla = similar(x) -# x_new = copy(x) -# sols = [] -# for i in 1:k -# tree.root.problem.g(nabla,x_new) -# x_new = Boscia.compute_extreme_point(blmo, nabla) -# push!(sols, x_new) -# end -# return sols, false -# end - -# ##### -# # rounding respecting the hidden feasible region structure -# ##### - -# function rounding_lmo_01_heuristic(tree::Bonobo.BnBTree, blmo::Boscia.BoundedLinearMinimizationOracle, x) -# nabla = zeros(length(x)) -# for idx in tree.branching_indices -# nabla[idx] = 1 - 2*round(x[idx]) # (0.7, 0.3) -> (1, 0) -> (-1, 1) -> min -> (1,0) -# end -# x_rounded = Boscia.compute_extreme_point(blmo, nabla) -# return [x_rounded], false -# end - -##### -# geometric scaling like for a couple of steps -##### - - -# depth = 5 -# heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.8, :follow_gradient) -# heu2 = Boscia.Heuristic(Boscia.rounding_lmo_01_heuristic, 0.8, :lmo_rounding) - -# heuristics = [heu, heu2] -# # heuristics = [] - -# x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy = branching_strategy, print_iter=500, custom_heuristics=heuristics) - -# benchmarking Oracles -# f, grad!, lmo = build_examples(n, A, y) -# FrankWolfe.benchmark_oracles(f, grad!, () -> rand(n), lmo; k=100) - - - -############## Example sizes ###################### - -n_choices = Int[10, -#40 -] -seeds = rand(UInt64, 3) - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[10,20] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7, 0.1,0.5,0.9] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 500 -time_limit = 1800 - -# Set parameters for saving results -file_name = "nonlinear_examples_a_c" - - - - - - -for i in [1] - o = SCIP.Optimizer() - f, grad!, lmo = build_examples(o,10, 1) - # println(o) - println("precompile") - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) - # print(lmo.o) -end -println("actual run")################################################################# - - -################################################################# -for n in n_choices - for seed in seeds - for branching_strategy in strategies - example_name = "nonlinear_n_" * string(n) - o = SCIP.Optimizer() - f, grad!, lmo = build_examples(o,n, seed) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end -end - diff --git a/examples/poisson_reg_pseudocost.jl b/examples/poisson_reg_pseudocost.jl deleted file mode 100644 index ec1c414db..000000000 --- a/examples/poisson_reg_pseudocost.jl +++ /dev/null @@ -1,270 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using HiGHS -# using Statistics -using LinearAlgebra -using Distributions -import MathOptInterface -const MOI = MathOptInterface - -# Poisson sparse regression - -# For bug hunting: -# seed = rand(UInt64) -# @show seed -# #seed = 0xfe03ee83ca373eab -# Random.seed!(seed) - -# min_{w, b, z} ∑_i exp(w x_i + b) - y_i (w x_i + b) + α norm(w)^2 -# s.t. -N z_i <= w_i <= N z_i -# b ∈ [-N, N] -# ∑ z_i <= k -# z_i ∈ {0,1} for i = 1,..,p - -# y_i - data points, poisson distributed -# X_i, b - coefficient for the linear estimation of the expected value of y_i -# w_i - continuous variables -# z_i - binary variables s.t. z_i = 0 => w_i = 0 -# k - max number of non zero entries in w - -# In a poisson regression, we want to model count data. -# It is assumed that y_i is poisson distributed and that the log -# of its expected value can be computed linearly. - -# n = 20 -# p = n - -# # underlying true weights -# const ws = rand(Float64, p) -# # set 50 entries to 0 -# for _ in 1:20 -# ws[rand(1:p)] = 0 -# end -# const bs = rand(Float64) -# const Xs = randn(Float64, n, p) -# const ys = map(1:n) do idx -# a = dot(Xs[idx, :], ws) + bs -# return rand(Distributions.Poisson(exp(a))) -# end -# Ns = 0.10 - -# TODO: document better - - - -function build_function(seed, n; Ns=0.0, use_scale=false) - Random.seed!(seed) - p = n - - # underlying true weights - ws = rand(Float64, p) - # set 50 entries to 0 - for _ in 1:20 - ws[rand(1:p)] = 0 - end - bs = rand(Float64) - Xs = randn(Float64, n, p) - for j in 1:p - Xs[:,j] ./= (maximum(Xs[:,j]) - minimum(Xs[:,j])) - if Ns == 10.0 - Xs[:,j] .*= 0.1 - end - end - ys = map(1:n) do idx - a = dot(Xs[idx, :], ws) + bs - return rand(Distributions.Poisson(exp(a))) - end - - α = 1.3 - scale = exp(n/2) - function f(θ) - #θ = BigFloat.(θ) - w = @view(θ[1:p]) - b = θ[end] - s = sum(1:n) do i - a = dot(w, Xs[:, i]) + b - return 1 / n * (exp(a) - ys[i] * a) - end - if use_scale - return 1/scale * (s + α * norm(w)^2) - end - return s + α * norm(w)^2 - end - function grad!(storage, θ) - #θ = BigFloat.(θ) - w = @view(θ[1:p]) - b = θ[end] - storage[1:p] .= 2α .* w - storage[p+1:2p] .= 0 - storage[end] = 0 - for i in 1:n - xi = @view(Xs[:, i]) - a = dot(w, xi) + b - storage[1:p] .+= 1 / n * xi * exp(a) - storage[1:p] .-= 1 / n * ys[i] * xi - storage[end] += 1 / n * (exp(a) - ys[i]) - end - if use_scale - storage .*= 1/scale - end - return storage - end - # @show bs, Xs, ys, ws - - return f, grad!, p, α, bs, Xs, ys, ws -end - -function build_optimizer(o, p, k, Ns) - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - w = MOI.add_variables(o, p) - z = MOI.add_variables(o, p) - b = MOI.add_variable(o) - # z_i ∈ {0,1} for i = 1,..,p - for i in 1:p - MOI.add_constraint(o, z[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, z[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, z[i], MOI.ZeroOne()) - end - for i in 1:p - # s.t. -N z_i <= w_i <= N z_i - MOI.add_constraint(o, Ns * z[i] + w[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, -Ns * z[i] + w[i], MOI.LessThan(0.0)) - # Indicator: z[i] = 1 => -N <= w[i] <= N - #=gl = MOI.VectorAffineFunction( - [ MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, w[i])),], - [0.0, 0.0], ) - gg = MOI.VectorAffineFunction( - [ MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, z[i])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-1.0, w[i])),], - [0.0, 0.0], ) - MOI.add_constraint(o, gl, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(Ns))) - MOI.add_constraint(o, gg, MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(-Ns))) =# - end - # ∑ z_i <= k - MOI.add_constraint(o, sum(z, init=0.0), MOI.LessThan(1.0 * k)) - MOI.add_constraint(o, sum(z, init=0.0), MOI.GreaterThan(1.0)) - # b ∈ [-N, N] - MOI.add_constraint(o, b, MOI.LessThan(Ns)) - MOI.add_constraint(o, b, MOI.GreaterThan(-Ns)) - lmo = Boscia.MathOptBLMO(o) - return lmo, (w,z,b) -end - - -############ Decide which strategies to run ##################### -strategies = Any[ - "Strong_Branching","MOST_INFEASIBLE" -] - -for iterations_stable in Int64[5] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -example_dimensions = [30] - -seeds = rand(UInt64, 3) -Ns = 0.1 - - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 600 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "poisson_reg_examples_a_c" - -################################################################# -f, grad!, p, α, bs, Xs, ys, ws = build_function(1, 10; Ns=Ns) - k = 10/2 - o = HiGHS.Optimizer() - lmo, _ = build_optimizer(o, p, k, Ns) - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) - - -for seed in seeds - for dim in example_dimensions - n = dim - - example_name = string("poisson_reg_n_", n, "_p_", n) - for branching_strategy in strategies - f, grad!, p, α, bs, Xs, ys, ws = build_function(seed, n; Ns=Ns) - k = n/2 - o = HiGHS.Optimizer() - lmo, _ = build_optimizer(o, p, k, Ns) - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) - - - #lmo, f, grad! = poisson_reg(n, p, 10, seed, 0.10, 1.3) - if branching_strategy == "Strong_Branching" - - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end -end - - diff --git a/examples/portfolio_pseudocost.jl b/examples/portfolio_pseudocost.jl deleted file mode 100644 index 29a68254a..000000000 --- a/examples/portfolio_pseudocost.jl +++ /dev/null @@ -1,249 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using SCIP -using HiGHS -using LinearAlgebra -import MathOptInterface -const MOI = MathOptInterface - -# seed = 0x946d4b7835e92ffa takes 90 minutes to solve! -> not anymore -# seed = 0x946d4b7835e92ffa -# Random.seed!(seed) - -# n = 30 -# const ri = rand(n) -# const ai = rand(n) -# const Ωi = rand(Float64) -# const bi = sum(ai) -# Ai = randn(n, n) -# Ai = Ai' * Ai -# const Mi = (Ai + Ai') / 2 -# @assert isposdef(Mi) - - -function build_function(seed, dimension) - @show seed - Random.seed!(seed) - n = dimension - ri = rand(n) - Ωi = rand() - Ai = randn(n, n) - Ai = Ai' * Ai - Mi = (Ai + Ai') / 2 - @assert isposdef(Mi) - - ai = rand(dimension) - bi = sum(ai) - - function f(x) - return 1 / 2 * Ωi * dot(x, Mi, x) - dot(ri, x) - end - function grad!(storage, x) - mul!(storage, Mi, x, Ωi, 0) - storage .-= ri - return storage - end - return f, grad!, n, ri, Ωi, Ai, Mi, ai, bi -end - -function build_optimizer(o, mode, n, ai, bi) - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - println("build optimizer") - # @show ai, bi - - # MOI.set(o, MOI.TimeLimitSec(), limit) - x = MOI.add_variables(o, n) - - # integer set - if mode == "integer" - I = collect(1:n) - elseif mode == "mixed" - I = 1:(n÷2) - end - - for i in 1:n - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - if i in I - MOI.add_constraint(o, x[i], MOI.Integer()) - end - end - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ai, x), 0.0), - MOI.LessThan(bi), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(n), x), 0.0), - MOI.GreaterThan(1.0), - ) - lmo = Boscia.MathOptBLMO(o) - return lmo, x -end - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10,20] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -example_dimensions = [10] - -#seeds = rand(UInt64, 3) -seeds = [0x946d4b7835e92ffa] -modes = ["integer","mixed"] - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 600 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "portfolio_examples_a_c" -################################################################# - - - -for seed in [1] - f, grad!, n, ri, Ωi, Ai, Mi, ai, bi = build_function(seed, 10) - #o = SCIP.Optimizer() - o = HiGHS.Optimizer() - lmo, _ = build_optimizer(o, "integer", n, ai, bi) - # println(o) - println("presolve") - Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10, use_postsolve=false) -end -println("actual solve") - -for seed in seeds - for dim in example_dimensions - for mode in modes - example_name = string("portfolio_dim_", dim, "_mode_", mode) - for branching_strategy in strategies - f, grad!, n, ri, Ωi, Ai, Mi, ai, bi = build_function(seed, dim) - o = SCIP.Optimizer() - #o = HiGHS.Optimizer() - lmo, _ = build_optimizer(o, mode, n, ai, bi) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end - end -end - - - - - - - - - -# @testset "Buchheim et. al. example" begin -# o = SCIP.Optimizer() -# MOI.set(o, MOI.Silent(), true) -# MOI.empty!(o) -# x = MOI.add_variables(o, n) -# I = collect(1:n) #rand(1:n0, Int64(floor(n0/2))) -# for i in 1:n -# MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) -# if i in I -# MOI.add_constraint(o, x[i], MOI.Integer()) -# end -# end -# MOI.add_constraint( -# o, -# MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ai, x), 0.0), -# MOI.LessThan(bi), -# ) -# MOI.add_constraint( -# o, -# MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(n), x), 0.0), -# MOI.GreaterThan(1.0), -# ) -# lmo = Boscia.MathOptBLMO(o) - -# function f(x) -# return 1 / 2 * Ωi * dot(x, Mi, x) - dot(ri, x) -# end -# function grad!(storage, x) -# mul!(storage, Mi, x, Ωi, 0) -# storage .-= ri -# return storage -# end - -# depth = 5 -# heu = Boscia.Heuristic((tree, blmo, x) -> Boscia.follow_gradient_heuristic(tree,blmo,x, depth), 0.2, :follow_gradient) -# heuristics = [heu] -# # heuristics = [] -# iterations_stable = 3 # how many times until we consider a pseudocost as stable -# μ = 0.7 # μ used in the computation of the branching score -# x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ), verbose=true, time_limit=600, custom_heuristics=heuristics) -# @test dot(ai, x) <= bi + 1e-2 -# @test f(x) <= f(result[:raw_solution]) + 1e-6 -# end diff --git a/examples/sparse_regression_pseudocost.jl b/examples/sparse_regression_pseudocost.jl deleted file mode 100644 index c895abf42..000000000 --- a/examples/sparse_regression_pseudocost.jl +++ /dev/null @@ -1,206 +0,0 @@ -using Statistics -using Boscia -using FrankWolfe -using Random -using LinearAlgebra -using SCIP -using HiGHS -import Bonobo -import MathOptInterface -const MOI = MathOptInterface -using Dates -using Printf -using Test - -# Sparse regression - -# Constant parameters for the sparse regression -# min norm(y-A β)² + λ_0 ∑ z_i + λ_2 ||β||² -# s.t. -Mz_i <= β_i <= Mz_i -# ∑ z_i <= k -# z_i ∈ {0,1} for i = 1,..,p - -# A - matrix of observations. -# y - vector of results. -# We want to match Aβ as closely as possible to y -# while having relative few non zero entries in β. -# Each continuous variable β_i is assigned a binary z_i, -# z_i = 0 => β_i = 0 - -# example_name = "sparse_regression" -# n0 = 10; -# p = 5 * n0; -# k = ceil(n0 / 5); -# const lambda_0 = rand(Float64); -# const lambda_2 = 10.0 * rand(Float64); -# const A = rand(Float64, n0, p) -# const y = rand(Float64, n0) -# const M = 2 * var(A) - -function build_function(seed, n) - Random.seed!(seed) - p = 5 * n; - k = ceil(n / 5); - lambda_0 = rand(Float64); - lambda_2 = 10.0 * rand(Float64); - A = rand(Float64, n, p) - y = rand(Float64, n) - M = 2 * var(A) - # @show A, y, M, lambda_0, lambda_2 - - function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 - end - - function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage - end - - return f, grad!, p, k, M, A, y, lambda_0, lambda_2 -end - -function build_optimizer(o, p, k, M) - MOI.set(o, MOI.Silent(), true) - MOI.empty!(o) - x = MOI.add_variables(o, 2p) - for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() - end - for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) - end - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), - ) - lmo = Boscia.MathOptBLMO(o) - return lmo, x -end - - - - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Example sizes ###################### - -no_choices = Int[10, -#40 -] - -seeds = rand(UInt64, 3) - -############## Set Parameters for all runs ###################### -verbose = true -print_iter = 100 -time_limit = 600 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "sparse_reg_examples_a_c" -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -f, grad!, p, k, M, A, y, lambda_0, lambda_2 = build_function(1, 10) -o = SCIP.Optimizer() -lmo, _ = build_optimizer(o, p, k, M) -# println(o) -println("precompile") -Boscia.solve(f, grad!, lmo, verbose=false, time_limit=10) -# print(lmo.o) -println("actual run")################################################################# - - -for seed in seeds - for dim in no_choices - n0 = dim - for branching_strategy in strategies - f, grad!, p, k, M, A, y, lambda_0, lambda_2 = build_function(seed, n0) - o = SCIP.Optimizer() - example_name = string("sparse_reg_n0_", n0, "_p_", p, "_k_",k) - lmo, _ = build_optimizer(o, p, k, M) - if branching_strategy == "Strong_Branching" - #blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) - blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy,verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end - end -end - diff --git a/examples/sparse_regression_pseudocost_used_for_emp_results.jl b/examples/sparse_regression_pseudocost_used_for_emp_results.jl deleted file mode 100644 index 3eca3901e..000000000 --- a/examples/sparse_regression_pseudocost_used_for_emp_results.jl +++ /dev/null @@ -1,403 +0,0 @@ -using Statistics -using Boscia -using FrankWolfe -using Random -using LinearAlgebra -using HiGHS -#using HiGHS -import Bonobo -import MathOptInterface -const MOI = MathOptInterface -using Dates -using Printf -using Test - -# Sparse regression - -# Constant parameters for the sparse regression -# min norm(y-A β)² + λ_0 ∑ z_i + λ_2 ||β||² -# s.t. -Mz_i <= β_i <= Mz_i -# ∑ z_i <= k -# z_i ∈ {0,1} for i = 1,..,p - -# A - matrix of observations. -# y - vector of results. -# We want to match Aβ as closely as possible to y -# while having relative few non zero entries in β. -# Each continuous variable β_i is assigned a binary z_i, -# z_i = 0 => β_i = 0 - -############################################# Problem set up ################################################# -n0 = 28 -p = 5 * n0; -k = ceil(n0 / 5); -seed = rand(UInt64) -#seed = 0x0c1145c200469bf1 -#seed = 0x2c6d6bd3949ad1f0 -@show seed - -Random.seed!(seed) - - -const lambda_0 = rand(Float64); -const lambda_2 = 10.0 * rand(Float64); -const A = rand(Float64, n0, p) -const y = rand(Float64, n0) -const M = 2 * var(A) -example_name = "sparse_regression_n0_" * string(n0) * "p_" * string(p) -################################################################################################################ -file_name ="sparse_reg_examples_a_c" # for saving results in "./results/" -###### run once to make sure everything is initialized - - -o = HiGHS.Optimizer() -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -lmo = Boscia.MathOptBLMO(o) - -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end - - -x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=30) - - -#################### weighted_sum ################################################################# - - -o = HiGHS.Optimizer() -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -lmo = Boscia.MathOptBLMO(o) - -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end -iterations_stable = 4::Int - -decision_function = "weighted_sum" -if decision_function == "product" - μ = 1e-6 -else - μ = 0.1 # μ used in the computation of the branching score -end - -x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=300) -settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) -Boscia.save_results(result, settings, example_name, seed, file_name, true) - - - -o = HiGHS.Optimizer() -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -lmo = Boscia.MathOptBLMO(o) - -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end -iterations_stable = 10::Int - -decision_function = "weighted_sum" -if decision_function == "product" - μ = 1e-6 -else - μ = 0.1 # μ used in the computation of the branching score -end - -x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=300) -settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) -Boscia.save_results(result, settings, example_name, seed, file_name, false) - - - -# ############################## product rule ############################################################ - - -o = HiGHS.Optimizer() -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -lmo = Boscia.MathOptBLMO(o) - -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end -iterations_stable = 4::Int - -decision_function = "product" -if decision_function == "product" - μ = 1e-6 -else - μ = 0.7 # μ used in the computation of the branching score -end -x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, print_iter=100, time_limit=300) -settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) -Boscia.save_results(result, settings, example_name, seed, file_name, false) - - - -o = HiGHS.Optimizer() -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -lmo = Boscia.MathOptBLMO(o) - -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end -iterations_stable = 10::Int - -decision_function = "product" -if decision_function == "product" - μ = 1e-6 -else - μ = 0.7 # μ used in the computation of the branching score -end -x, _, result = Boscia.solve(f, grad!, lmo, branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function),verbose=true, fw_epsilon=1e-3, time_limit=300) -settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) -Boscia.save_results(result, settings, example_name, seed, file_name, false) - -# ######################### MOST_INFEASIBLE ########################################################## -o = HiGHS.Optimizer() -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -lmo = Boscia.MathOptBLMO(o) - -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end - -x, _, result = Boscia.solve(f, grad!, lmo, verbose=true, fw_epsilon=1e-3, time_limit=300) -settings = "MOST_INFEASIBLE" -Boscia.save_results(result, settings, example_name, seed, file_name, false) - - - - - -o = HiGHS.Optimizer() - -MOI.set(o, MOI.Silent(), true) -MOI.empty!(o) -x = MOI.add_variables(o, 2p) -for i in p+1:2p - MOI.add_constraint(o, x[i], MOI.GreaterThan(0.0)) - MOI.add_constraint(o, x[i], MOI.LessThan(1.0)) - MOI.add_constraint(o, x[i], MOI.ZeroOne()) # or MOI.Integer() -end -for i in 1:p - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, M], [x[i], x[i+p]]), 0.0), - MOI.GreaterThan(0.0), - ) - MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -M], [x[i], x[i+p]]), 0.0), - MOI.LessThan(0.0), - ) -end -MOI.add_constraint( - o, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(p), x[p+1:2p]), 0.0), - MOI.LessThan(k), -) -function f(x) - xv = @view(x[1:p]) - return norm(y - A * xv)^2 + lambda_0 * sum(x[p+1:2p]) + lambda_2 * norm(xv)^2 -end - -function grad!(storage, x) - storage[1:p] .= 2 * (transpose(A) * A * x[1:p] - transpose(A) * y + lambda_2 * x[1:p]) - storage[p+1:2p] .= lambda_0 - return storage -end -lmo = Boscia.MathOptBLMO(o) -blmo = Boscia.MathOptBLMO(HiGHS.Optimizer()) -branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) -MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - -x, _, result_strong_branching = - Boscia.solve(f, grad!, lmo, verbose=true, branching_strategy=branching_strategy, time_limit=300) -settings = "Strong_Branching" -Boscia.save_results(result_strong_branching, settings, example_name, seed, file_name, false) \ No newline at end of file From 28f2b78d569b16a1ad6f9256ac55607541474cb0 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:18:13 +0200 Subject: [PATCH 38/56] removed function which is used to save experiments from non experiment branch --- src/utilities.jl | 64 ------------------------------------------------ 1 file changed, 64 deletions(-) diff --git a/src/utilities.jl b/src/utilities.jl index ab0b68f83..cf6e0ed57 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -230,70 +230,6 @@ function sparse_min_via_enum(f, n, k, values=fill(0:1, n)) end -function save_results( - result::Dict{Symbol, Any}, - settings::String, - example_name::String, - seed, - file_name::String, - over_write::Bool - ) - - seed = string(seed) - l1 = []# save all keys with one entry only - l2 = []# save all vector results of length equal to that of result[:list_ub] - l3 = []# save all vector results of length equal to that of lmo_calls_per_layer - for key in keys(result) - if string(key) in ["dual_bound","dual_gap","heu_lmo_calls","lmo_calls","number_nodes","primal_objective","rel_dual_gap","status","total_time_in_sec"] - push!(l1, key) - elseif string(key) in ["global_tightenings", "list_active_set_size", "list_discarded_set_size", - "list_lb","list_lmo_calls_acc","list_num_nodes","list_time","list_ub","local_potential_tightenings","local_tightenings","node_level"] - push!(l2, key) - elseif string(key) in ["active_set_size_per_layer", "discarded_set_size_per_layer", "lmo_calls_per_layer"] - push!(l3, key) - elseif string(key) != "raw_solution" - println(key, " has not been saved ") - end - end - l11 = Dict(string(key) => result[key] for key in l1) - l22 = Dict(string(key) => result[key] for key in l2) - l33 = Dict(string(key) => result[key] for key in l3) - l11 = DataFrame(l11) - l11[:, :example_name] .= example_name - l11[:, :seed] .= seed - l11[:, :settings] .= settings - - l22 = DataFrame(l22) - l22[:, :settings] .= settings - l22[:, :example_name] .= example_name - l22[:, :seed] .= seed - - l33 = DataFrame(l33) - l33[:, :settings] .= settings - l33[:, :example_name] .= example_name - l33[:, :seed] .= seed - - file_name1 = "./results/" * file_name * "_summary.csv" - - - if over_write# will always over write file if true - append = false - else - if isfile(file_name1)# using this method the first line of the file will have column names - append = true - else - append = false - end - end - CSV.write(file_name1, l11, append= append) - - file_name2 = "./results/" * file_name * ".csv" - - CSV.write(file_name2, l22, append= append) - file_name3 = "./results/" * file_name * "_layers.csv" - CSV.write(file_name3, l33, append= append) -end - # utility function to print the values of the parameters _value_to_print(::Bonobo.BestFirstSearch) = "Move best bound" _value_to_print(::PartialStrongBranching) = "Partial strong branching" From 6342af45fc2c49c1b29471cd4aa3dc5441695cd5 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:20:36 +0200 Subject: [PATCH 39/56] deleted mps-example copy for pseudocost experiments of non experiment branch --- .../mps-examples/mip-examples_pseudocost.jl | 265 ------------------ 1 file changed, 265 deletions(-) delete mode 100644 examples/mps-examples/mip-examples_pseudocost.jl diff --git a/examples/mps-examples/mip-examples_pseudocost.jl b/examples/mps-examples/mip-examples_pseudocost.jl deleted file mode 100644 index 7f0f9413b..000000000 --- a/examples/mps-examples/mip-examples_pseudocost.jl +++ /dev/null @@ -1,265 +0,0 @@ -using Boscia -using FrankWolfe -using Test -using Random -using SCIP -using LinearAlgebra -import MathOptInterface -const MOI = MathOptInterface -import Ipopt - - -# MIPLIB instances -# Objective function: Minimize the distance to randomely picked vertices - -# Possible files -# 22433 https://miplib.zib.de/instance_details_22433.html -# n5-3 https://miplib.zib.de/instance_details_n5-3.html -# neos5 https://miplib.zib.de/instance_details_neos5.html -# pg https://miplib.zib.de/instance_details_pg.html -# pg5_34 https://miplib.zib.de/instance_details_pg5_34.html -# ran14x18-disj-8 https://miplib.zib.de/instance_details_ran14x18-disj-8.html -# timtab1 https://miplib.zib.de/instance_details_timtab1.html (Takes LONG!) - -seed = rand(UInt64) -#seed = 0x1d52d0c243ef0c61 -seed = 7924543777773248845 -@show seed - -#Random.seed!(seed) -file_name = "mip_examples_long" # for saving results in "./results/" -# To see debug statements -#ENV["JULIA_DEBUG"] = "Boscia" - - - -function build_example(example, num_v, seed) - file_name = string(example, ".mps") - src = MOI.FileFormats.Model(filename=file_name) - MOI.read_from_file(src, joinpath(@__DIR__, string("mps-files/", file_name))) - - o = SCIP.Optimizer() - MOI.copy_to(o, src) - MOI.set(o, MOI.Silent(), true) - n = MOI.get(o, MOI.NumberOfVariables()) - lmo = Boscia.MathOptBLMO(o) - - # Disable Presolving - MOI.set(o, MOI.RawOptimizerAttribute("presolving/maxrounds"), 0) - Random.seed!(seed) - #trick to push the optimum towards the interior - vs = [FrankWolfe.compute_extreme_point(lmo, randn(n)) for _ in 1:num_v] - # done to avoid one vertex being systematically selected - unique!(vs) - - @assert !isempty(vs) - b_mps = randn(n) - max_norm = maximum(norm.(vs)) - - function f(x) - r = dot(b_mps, x) - for v in vs - r += 1 / (2 * max_norm) * norm(x - v)^2 - end - return r - end - - function grad!(storage, x) - mul!(storage, length(vs) / max_norm * I, x) - storage .+= b_mps - for v in vs - @. storage -= 1 / max_norm * v - end - end - - return lmo, f, grad! -end -example = "neos5" - - - -############ Decide which strategies to run ##################### -strategies = Any[ - "MOST_INFEASIBLE", "Strong_Branching" -] - -for iterations_stable in Int64[5,10,20] - for decision_function in [ - "product", - "weighted_sum" - ] - if decision_function == "product" - μ = 1e-6 - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - else - for μ in [0.7] - push!(strategies, Dict(:iterations_stable => iterations_stable, :μ => μ, :decision_function => decision_function)) - end - end - end -end - - -############## Set Parameters for all runs ###################### -verbose = true -print_iter=10 -fw_epsilon=1e-1 -min_node_fw_epsilon=1e-3 -time_limit=600 -rel_dual_gap=1e-2 -# Set parameters for saving results -file_name = "mip-examples_a_c" - - -#example_name = string("int_sparse_reg_n_", n, "_m_", m, "_l_",l, "_k_", k) -################################################################# - - - - -for example in ["neos5", - "pg", "22433", "pg5_34", "ran14x18-disj-8", "n5-3", - "timtab1" ] - num_v = 0 - if example == "neos5" - num_v = 5 - elseif example == "pg" - num_v = 5 - elseif example == "22433" - num_v = 20 - elseif example == "pg5_34" - num_v = 5 - elseif example == "ran14x18-disj-8" - num_v = 5 - elseif example == "n5-3" - num_v = 100 - elseif example == "timtab1" - num_v = 3 - end - - test_instance = string("MPS ", example, " instance") - - #println("Example $(example)") - example_name = test_instance - for branching_strategy in strategies - lmo, f, grad! = build_example(example, num_v, seed) - if branching_strategy == "Strong_Branching" - blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) - branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) - MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - x, _, result = - Boscia.solve( - f, - grad!, - lmo, - branching_strategy=branching_strategy, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap, - fw_epsilon=fw_epsilon, - min_node_fw_epsilon=min_node_fw_epsilon - ) - settings = "Strong_Branching" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - - elseif branching_strategy == "MOST_INFEASIBLE" - x, _, result = Boscia.solve( - f, - grad!, - lmo, - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap, - fw_epsilon=fw_epsilon, - min_node_fw_epsilon=min_node_fw_epsilon - ) - settings = "MOST_INFEASIBLE" - Boscia.save_results(result, settings, example_name, seed, file_name, false) - else - iterations_stable = branching_strategy[:iterations_stable] - decision_function = branching_strategy[:decision_function] - μ = branching_strategy[:μ] - x, _, result = Boscia.solve( - f, - grad!, - lmo, - branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), - verbose=verbose, - print_iter=print_iter, - time_limit=time_limit, - rel_dual_gap=rel_dual_gap, - fw_epsilon=fw_epsilon, - min_node_fw_epsilon=min_node_fw_epsilon - ) - settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) - Boscia.save_results(result, settings, example_name, seed, file_name, false) - end - end -end - - - -# ############## Product PSEUDO_COST ############################### - -# iterations_stable = 10 -# decision_function = "product" -# if decision_function == "product" -# μ = 1e-6 -# else -# μ = 0.7 # μ used in the computation of the branching score -# end - -# x, _, result = Boscia.solve( -# f, -# grad!, -# lmo, -# branching_strategy=Boscia.PSEUDO_COST(iterations_stable,false, lmo, μ, decision_function), -# verbose=true, -# print_iter=10, -# fw_epsilon=1e-1, -# min_node_fw_epsilon=1e-3, -# time_limit=3600, -# ) -# settings = "PSEUDO_COST_" * decision_function * "_" * string(iterations_stable) * "_μ=" * string(μ) -# Boscia.save_results(result, settings, example, seed, file_name, false) - -# ############## MOST_INFEASIBLE ##################### -# lmo, f, grad! = build_example(example, num_v, seed) -# settings = "MOST_INFEASIBLE" -# x, _, result = Boscia.solve( -# f, -# grad!, -# lmo, -# verbose=true, -# print_iter=10, -# fw_epsilon=1e-1, -# min_node_fw_epsilon=1e-3, -# time_limit=3600, -# ) - -# settings = "MOST_INFEASIBLE" -# Boscia.save_results(result, settings, example, seed, file_name, false) - -# ############## Strong_Branching ############################## -# lmo, f, grad! = build_example(example, num_v, seed) -# blmo = Boscia.MathOptBLMO(SCIP.Optimizer()) -# branching_strategy = Boscia.PartialStrongBranching(10, 1e-3, blmo) -# MOI.set(branching_strategy.bounded_lmo.o, MOI.Silent(), true) - -# x, _, result = -# Boscia.solve( -# f, -# grad!, -# lmo, -# branching_strategy=branching_strategy, -# verbose=true, -# print_iter=10, -# fw_epsilon=1e-1, -# min_node_fw_epsilon=1e-3, -# time_limit=3600, -# ) -# settings = "Strong_Branching" -# Boscia.save_results(result, settings, example, seed, file_name, false) -# end \ No newline at end of file From 627493746c38b27e1b87a96149dc5a0e4040d1d3 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:21:50 +0200 Subject: [PATCH 40/56] removed a pdf from branch --- ...rk_master_thesis_branching_Leon_Stanzel.pdf | Bin 205905 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 in_work_master_thesis_branching_Leon_Stanzel.pdf diff --git a/in_work_master_thesis_branching_Leon_Stanzel.pdf b/in_work_master_thesis_branching_Leon_Stanzel.pdf deleted file mode 100644 index f18ee7400c48b90fb5b8fa2501e6ad1b42712254..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205905 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�B283-;B2^}37vR@mBUalPf9&&JVFT+Sb{ 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 From fa3f29b12985974cda369c616db8ebf0a6444582 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:40:16 +0200 Subject: [PATCH 41/56] bug fixes for gradient (+) most infeasible strategy --- src/other_branching.jl | 21 +++++++++++---------- src/utilities.jl | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/other_branching.jl b/src/other_branching.jl index 46c694c6f..0c9da8722 100644 --- a/src/other_branching.jl +++ b/src/other_branching.jl @@ -1,9 +1,9 @@ """ - Largest_Gradient <: AbstractBranchStrategy + LargestGradient <: AbstractBranchStrategy -The `LARGEST GRADIENT` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. +The `LargestGradient` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. """ -struct LARGEST_GRADIENT <: Bonobo.AbstractBranchStrategy end +struct LargestGradient <: Bonobo.AbstractBranchStrategy end """ @@ -17,7 +17,7 @@ Get branching variable using Largest_Gradient branching """ function Bonobo.get_branching_variable( tree::Bonobo.BnBTree, - branching::LARGEST_GRADIENT, + branching::LargestGradient, node::Bonobo.AbstractNode, ) values = Bonobo.get_relaxed_values(tree, node) @@ -40,13 +40,13 @@ end """ - LARGEST_MOST_INFEASIBLE_GRADIENT <: AbstractBranchStrategy + LargestMostInfeasibleGradient <: AbstractBranchStrategy -The `LARGEST_MOST_INFEASIBLE_GRADIENT` strategy always picks the variable which has the largest absolute value +The `LargestMostInfeasibleGradient` strategy always picks the variable which has the largest absolute value entry in the current gradient multiplied by the maximum distance to being fixed. """ -struct LARGEST_MOST_INFEASIBLE_GRADIENT <: Bonobo.AbstractBranchStrategy end +struct LargestMostInfeasibleGradient <: Bonobo.AbstractBranchStrategy end """ @@ -60,7 +60,7 @@ Get branching variable using LARGEST_MOST_INFEASIBLE_GRADIENT branching """ function Bonobo.get_branching_variable( tree::Bonobo.BnBTree, - branching::LARGEST_MOST_INFEASIBLE_GRADIENT, + branching::LargestMostInfeasibleGradient, node::Bonobo.AbstractNode, ) values = Bonobo.get_relaxed_values(tree, node) @@ -69,9 +69,10 @@ function Bonobo.get_branching_variable( x_new = copy(values) gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? max_score = 0.0 - for i in branching_candidates + for i in tree.branching_indices + value = values[i] if !Bonobo.is_approx_feasible(tree, value) - value = values[i] * abs(gradient_at_values[i]) + value *= abs(gradient_at_values[i]) if value > max_score best_idx = i max_score = value diff --git a/src/utilities.jl b/src/utilities.jl index cf6e0ed57..609c8422b 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -237,5 +237,5 @@ _value_to_print(::HybridStrongBranching) = "Hybrid strong branching" _value_to_print(::Bonobo.MOST_INFEASIBLE) = "Most infeasible" _value_to_print(::PSEUDO_COST) = "Pseudo Cost" _value_to_print(::HIERARCHY_PSEUDO_COST) = "Hierarchy-Pseudo Cost" -_value_to_print(::LARGEST_GRADIENT) = "Largest Gradient" -_value_to_print(::LARGEST_MOST_INFEASIBLE_GRADIENT) = "Largest most infeasible gradient " \ No newline at end of file +_value_to_print(::LargestGradient) = "Largest Gradient" +_value_to_print(::LargestMostInfeasibleGradient) = "Largest most infeasible gradient " \ No newline at end of file From f15325759887e1e77e4bd9bf23d11549e8abc73a Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:46:35 +0200 Subject: [PATCH 42/56] added all Boscia branching strategies with the exception of strong branching related ones to a new script called branchings_strategies.jl --- src/Boscia.jl | 3 +- ...o_branching.jl => branching_strategies.jl} | 96 ++++++++++++++++++- src/other_branching.jl | 91 ------------------ 3 files changed, 96 insertions(+), 94 deletions(-) rename src/{pseudo_branching.jl => branching_strategies.jl} (82%) delete mode 100644 src/other_branching.jl diff --git a/src/Boscia.jl b/src/Boscia.jl index 70f874860..bdf3e3fd1 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -26,8 +26,7 @@ include("callbacks.jl") include("problem.jl") include("heuristics.jl") include("strong_branching.jl") -include("pseudo_branching.jl") -include("other_branching.jl") +include("branching_strategies.jl") include("utilities.jl") include("interface.jl") include("managed_blmo.jl") diff --git a/src/pseudo_branching.jl b/src/branching_strategies.jl similarity index 82% rename from src/pseudo_branching.jl rename to src/branching_strategies.jl index 89618ca87..d9ef4a0c9 100644 --- a/src/pseudo_branching.jl +++ b/src/branching_strategies.jl @@ -138,7 +138,7 @@ end """ get_branching_variable( tree::Bonobo.BnBTree, - branching::PSEUDO_COST, + branching::HIERARCHY_PSEUDO_COST, node::Bonobo.AbstractNode, pseudos::SparseMatrixCSC, branch_tracker::SparseMatrixCSC @@ -288,3 +288,97 @@ function max_infeas_score(idxs::Vector{Int64}, infeas_tracker::SparseMatrixCSC{I return max_score end + + + +""" + LargestGradient <: AbstractBranchStrategy + +The `LargestGradient` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. +""" +struct LargestGradient <: Bonobo.AbstractBranchStrategy end + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + node::Bonobo.AbstractNode +) + +Get branching variable using Largest_Gradient branching + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::LargestGradient, + node::Bonobo.AbstractNode, +) + values = Bonobo.get_relaxed_values(tree, node) + nabla = similar(values) + x_new = copy(values) + gradient_at_values = tree.root.problem.g(nabla, x_new) + best_idx = -1 + max_gradient = 0.0 + for i in tree.branching_indices + value = values[i] + if !Bonobo.is_approx_feasible(tree, value)# check if variable is branching candidate + if abs(gradient_at_values[i]) > max_gradient + best_idx = i + end + end + end + return best_idx +end + + + +""" + LargestMostInfeasibleGradient <: AbstractBranchStrategy + +The `LargestMostInfeasibleGradient` strategy always picks the variable which has the largest absolute value +entry in the current gradient multiplied by the maximum distance to being fixed. +""" + +struct LargestMostInfeasibleGradient <: Bonobo.AbstractBranchStrategy end + + +""" + get_branching_variable( + tree::Bonobo.BnBTree, + node::Bonobo.AbstractNode +) + +Get branching variable using LARGEST_MOST_INFEASIBLE_GRADIENT branching + +""" +function Bonobo.get_branching_variable( + tree::Bonobo.BnBTree, + branching::LargestMostInfeasibleGradient, + node::Bonobo.AbstractNode, +) + values = Bonobo.get_relaxed_values(tree, node) + best_idx = -1 + nabla = similar(values) + x_new = copy(values) + gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? + max_score = 0.0 + for i in tree.branching_indices + value = values[i] + if !Bonobo.is_approx_feasible(tree, value) + value *= abs(gradient_at_values[i]) + if value > max_score + best_idx = i + max_score = value + end + end + end + return best_idx +end + + + + + + + + diff --git a/src/other_branching.jl b/src/other_branching.jl deleted file mode 100644 index 0c9da8722..000000000 --- a/src/other_branching.jl +++ /dev/null @@ -1,91 +0,0 @@ -""" - LargestGradient <: AbstractBranchStrategy - -The `LargestGradient` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. -""" -struct LargestGradient <: Bonobo.AbstractBranchStrategy end - - -""" - get_branching_variable( - tree::Bonobo.BnBTree, - node::Bonobo.AbstractNode -) - -Get branching variable using Largest_Gradient branching - -""" -function Bonobo.get_branching_variable( - tree::Bonobo.BnBTree, - branching::LargestGradient, - node::Bonobo.AbstractNode, -) - values = Bonobo.get_relaxed_values(tree, node) - nabla = similar(values) - x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla, x_new) - best_idx = -1 - max_gradient = 0.0 - for i in tree.branching_indices - value = values[i] - if !Bonobo.is_approx_feasible(tree, value)# check if variable is branching candidate - if abs(gradient_at_values[i]) > max_gradient - best_idx = i - end - end - end - return best_idx -end - - - -""" - LargestMostInfeasibleGradient <: AbstractBranchStrategy - -The `LargestMostInfeasibleGradient` strategy always picks the variable which has the largest absolute value -entry in the current gradient multiplied by the maximum distance to being fixed. -""" - -struct LargestMostInfeasibleGradient <: Bonobo.AbstractBranchStrategy end - - -""" - get_branching_variable( - tree::Bonobo.BnBTree, - node::Bonobo.AbstractNode -) - -Get branching variable using LARGEST_MOST_INFEASIBLE_GRADIENT branching - -""" -function Bonobo.get_branching_variable( - tree::Bonobo.BnBTree, - branching::LargestMostInfeasibleGradient, - node::Bonobo.AbstractNode, -) - values = Bonobo.get_relaxed_values(tree, node) - best_idx = -1 - nabla = similar(values) - x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? - max_score = 0.0 - for i in tree.branching_indices - value = values[i] - if !Bonobo.is_approx_feasible(tree, value) - value *= abs(gradient_at_values[i]) - if value > max_score - best_idx = i - max_score = value - end - end - end - return best_idx -end - - - - - - - - From a7dc57f007fbe26a39cdbfb3fb32ba77c10c962c Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 15:50:00 +0200 Subject: [PATCH 43/56] removed CSV, DataFrames from non experiment branch --- src/Boscia.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Boscia.jl b/src/Boscia.jl index bdf3e3fd1..dff93d8a2 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -9,8 +9,6 @@ using Printf using Dates using MathOptInterface using SparseArrays -using CSV -using DataFrames const MOI = MathOptInterface const MOIU = MOI.Utilities import MathOptSetDistances as MOD From be486bcf2a5f965abe722e917e4251aefe7c99b9 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 18 Sep 2024 16:43:03 +0200 Subject: [PATCH 44/56] removed unwanted whitespace --- src/utilities.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities.jl b/src/utilities.jl index 609c8422b..6d3666ccc 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -238,4 +238,4 @@ _value_to_print(::Bonobo.MOST_INFEASIBLE) = "Most infeasible" _value_to_print(::PSEUDO_COST) = "Pseudo Cost" _value_to_print(::HIERARCHY_PSEUDO_COST) = "Hierarchy-Pseudo Cost" _value_to_print(::LargestGradient) = "Largest Gradient" -_value_to_print(::LargestMostInfeasibleGradient) = "Largest most infeasible gradient " \ No newline at end of file +_value_to_print(::LargestMostInfeasibleGradient) = "Largest most infeasible gradient" \ No newline at end of file From b5194320fac87357e48260c436c725acb81a5e2e Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 25 Sep 2024 16:14:45 +0200 Subject: [PATCH 45/56] removing debug prints etc. --- src/branching_strategies.jl | 81 +++++++++++++------------------------ src/custom_bonobo.jl | 14 +++---- src/node.jl | 2 - 3 files changed, 32 insertions(+), 65 deletions(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index d9ef4a0c9..b67d57528 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -54,14 +54,8 @@ function Bonobo.get_branching_variable( end end end - # for entry in branching_candidates - # if !isequal(branch_tracker[entry, 1], branch_tracker[entry, 2]) - # println("\n", entry,"\n") - # end - # #break - # end - if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable - #println("if clause of update") + # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + if !isinf(node.parent_lower_bound_base) idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base update = update / node.distance_to_int @@ -69,17 +63,13 @@ function Bonobo.get_branching_variable( @debug "update is $(Inf)" end if node.branched_right - #println(update) pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) branch_tracker[idx, 1] += 1 else - #println(update) pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) branch_tracker[idx, 2] += 1 end - # println("pseudos") - #display(pseudos) end length(branching_candidates) == 0 && return best_idx length(branching_candidates) == 1 && return branching_candidates[1] @@ -95,19 +85,15 @@ function Bonobo.get_branching_variable( end return best_idx else - #println("\npd made\n") if branching.decision_function == "weighted_sum" - #println(branching.decision_function) branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), branching_candidates) elseif branching.decision_function == "product" - #println(branching.decision_function) branching_scores = map(idx-> max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), branching_candidates) end branching_scores = sparsevec(branching_candidates, branching_scores) - #display(branching_scores) best_idx = argmax(branching_scores) return best_idx @@ -121,7 +107,8 @@ function update_avg(new_val::Float64, avg::Float64, N::Int) if N > 1 return 1/(N+1) * (N * (avg - 1) + new_val) + 1 # else - return new_val + avg # note that we initialize the pseudo costs with 1 as such we need to shift pseudocosts correspondingly + # note that we initialize the pseudo costs with 1 as such we need to shift pseudocosts correspondingly + return new_val + avg end end @@ -143,9 +130,14 @@ end pseudos::SparseMatrixCSC, branch_tracker::SparseMatrixCSC ) - -Get branching variable using Pseudocost branching after costs have stabilized. -Prior to stabilization an adaptation of the Bonobo MOST_INFEASIBLE is used. +This strategy first chooses the branching varaibles which have most often led to infeasiblity. +If there are multiple such candidates then among these candidates another strategy is used + if candidate pseudocosts are stable then a pseudocost decision is made + else + if gradient_influence=false + decision is made based on MOST_INFEASIBLE strategy + else + decision is made on LARGEST_MOST_INFEASIBLE_GRADIENT """ function Bonobo.get_branching_variable( @@ -160,7 +152,8 @@ function Bonobo.get_branching_variable( strategy_switch = branching.iterations_until_stable + 1 best_idx = -1 all_stable = true - branching_candidates = Int[]# this shall contain the indices of the potential branching variables + # the following shall contain the indices of the potential branching variables + branching_candidates = Int[] values = Bonobo.get_relaxed_values(tree, node) for idx in tree.branching_indices value = values[idx] @@ -168,14 +161,8 @@ function Bonobo.get_branching_variable( push!(branching_candidates, idx) end end - # for entry in branching_candidates - # if !isequal(branch_tracker[entry, 1], branch_tracker[entry, 2]) - # println("\n", entry,"\n") - # end - # #break - # end - if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable - #println("if clause of update") + # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + if !isinf(node.parent_lower_bound_base) idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base update = update / node.distance_to_int @@ -183,28 +170,17 @@ function Bonobo.get_branching_variable( @debug "update is $(Inf)" end if node.branched_right - #println(update) pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) branch_tracker[idx, 1] += 1 else - #println(update) pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) branch_tracker[idx, 2] += 1 end - # println("pseudos") - #display(pseudos) end - - #println("--- before --- ") - #display(branching_candidates) # compute score of how (often) branching on a variable resulted in infeasiblity best_score = max_infeas_score(branching_candidates, infeas_tracker) - branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, infeas_tracker) >= best_score] - #println("--- after --- ") - #display(branching_candidates) - if length(branching_candidates) == 0 return best_idx elseif length(branching_candidates) == 1 @@ -214,18 +190,18 @@ function Bonobo.get_branching_variable( end for idx in branching_candidates - if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx + # check if pseudocost is stable for this idx + if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch all_stable = false end end - - if !all_stable# THEN Use Most Infeasible - if branching.gradient_influence# score function as product of gradient at variable and largest distance to int + if branching.gradient_influence + # score function as product of gradient at variable and largest distance to int nabla = similar(values) x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? + gradient_at_values = tree.root.problem.g(nabla,x_new) max_score = 0.0 for i in branching_candidates value = values[i] * abs(gradient_at_values[i]) @@ -249,21 +225,16 @@ function Bonobo.get_branching_variable( return best_idx end else - #println("\npd made\n") if branching.decision_function == "weighted_sum" - #println(branching.decision_function) branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), branching_candidates) elseif branching.decision_function == "product" - #println(branching.decision_function) branching_scores = map(idx-> max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), branching_candidates) end branching_scores = sparsevec(branching_candidates, branching_scores) - #display(branching_scores) best_idx = argmax(branching_scores) - infeas_tracker[best_idx, 2] += 1 return best_idx end @@ -272,7 +243,8 @@ end function infeas_score(idx::Int, infeas_tracker::SparseMatrixCSC{Int64, Int64}) infeas_tracker[idx, 1] == 1 && return 0 - return (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2])# ratio of how often branching on variable idx leads to node infeasiblity of children + # ratio of how often branching on variable idx leads to node infeasiblity of children + return (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2]) end function max_infeas_score(idxs::Vector{Int64}, infeas_tracker::SparseMatrixCSC{Int64, Int64}) @@ -305,7 +277,7 @@ struct LargestGradient <: Bonobo.AbstractBranchStrategy end node::Bonobo.AbstractNode ) -Get branching variable using Largest_Gradient branching +Get branching variable which has the largest absolute value in the gradient """ function Bonobo.get_branching_variable( @@ -321,7 +293,8 @@ function Bonobo.get_branching_variable( max_gradient = 0.0 for i in tree.branching_indices value = values[i] - if !Bonobo.is_approx_feasible(tree, value)# check if variable is branching candidate + # check if variable is branching candidate + if !Bonobo.is_approx_feasible(tree, value) if abs(gradient_at_values[i]) > max_gradient best_idx = i end @@ -360,7 +333,7 @@ function Bonobo.get_branching_variable( best_idx = -1 nabla = similar(values) x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla,x_new)# is this information already computed elsewhere? + gradient_at_values = tree.root.problem.g(nabla,x_new) max_score = 0.0 for i in tree.branching_indices value = values[i] diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index f63d1c79e..df7f6ba73 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -53,10 +53,10 @@ function Bonobo.optimize!( # if the evaluated lower bound is worse than the best incumbent -> close and continue if node.lb >= tree.incumbent - if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) || isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST)# In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable - #println("node closed but we do update anyway") - if !isinf(node.parent_lower_bound_base)# if this node is a result of branching on some variable then update pseudocost of corresponding branching variable - #println("if clause of update") + # In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable + if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) || isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) + # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + if !isinf(node.parent_lower_bound_base) idx = node.branched_on update = lb - node.parent_lower_bound_base update = update / node.distance_to_int @@ -64,16 +64,12 @@ function Bonobo.optimize!( @debug "update is $(Inf)" end if node.branched_right - #println(update) pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) branch_tracker[idx, 1] += 1 else - #println(update) pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) branch_tracker[idx, 2] += 1 - end - else - println(string("node.parent_lower_bound_base is ", node.parent_lower_bound_base)) + end end end diff --git a/src/node.jl b/src/node.jl index aa6847769..e91cef1c9 100644 --- a/src/node.jl +++ b/src/node.jl @@ -85,8 +85,6 @@ function Bonobo.get_branching_nodes_info(tree::Bonobo.BnBTree, node::FrankWolfeN if !is_valid_split(tree, vidx) error("Splitting on the same index as parent! Abort!") end - #println(vidx) - # get iterate, primal and lower bound x = Bonobo.get_relaxed_values(tree, node) primal = tree.root.problem.f(x) From eef7f20ed74f66e7cc02b6f91d80e102f2d70a8f Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 26 Sep 2024 16:45:34 +0200 Subject: [PATCH 46/56] Readability change --- src/branching_strategies.jl | 554 ++++++++++++++++++++++++++++-------- 1 file changed, 443 insertions(+), 111 deletions(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index b67d57528..9560b8f2f 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -8,16 +8,6 @@ struct PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBran decision_function::String end -# """ Function that keeps track of which branching candidates are stable """ -# function is_stable(idx::Int, branching::PSEUDO_COST{BLMO}) -# local branch_tracker = Dict{Int, Float64}(idx=> 0 for idx in Boscia.get_integer_variables(branching.bounded_lmo)) -# if branch_tracker[idx] >= branching.iterations_until_stable -# return true -# else -# return false -# end -# end - """ get_branching_variable( @@ -86,11 +76,11 @@ function Bonobo.get_branching_variable( return best_idx else if branching.decision_function == "weighted_sum" - branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), + branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 2] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 1] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 2] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 1] - 1) * (ceil(values[idx]) - values[idx]))), branching_candidates) elseif branching.decision_function == "product" - branching_scores = map(idx-> max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), + branching_scores = map(idx-> max((pseudos[idx, 2] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 1] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), branching_candidates) end branching_scores = sparsevec(branching_candidates, branching_scores) @@ -100,10 +90,17 @@ function Bonobo.get_branching_variable( end end -function update_avg(new_val::Float64, avg::Float64, N::Int) - # N is the number of values used to compute the current avg - # avg is the current average shifted by 1 - # new_val is the value that the current average has to be updated with +""" + update_avg( + new_val::Float64, + avg::Float64, + N::Int) + N is the number of values used to compute the current avg + avg is the current average shifted by 1 + new_val is the value that the current average has to be updated with +""" + function update_avg(new_val::Float64, avg::Float64, N::Int) + if N > 1 return 1/(N+1) * (N * (avg - 1) + new_val) + 1 # else @@ -113,15 +110,50 @@ function update_avg(new_val::Float64, avg::Float64, N::Int) end -struct HIERARCHY_PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBranchStrategy +mutable struct HIERARCHY_PSEUDO_COST <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int - gradient_influence::Bool - bounded_lmo::BLMO + alternative::String μ::Float64 decision_function::String + pseudos::SparseMatrixCSC{Float64, Int64} + branch_tracker::SparseMatrixCSC{Int64, Int64} + infeas_tracker::SparseMatrixCSC{Int64, Int64} + + function HIERARCHY_PSEUDO_COST( + iterations_until_stable, + alternative, + bounded_lmo, + μ, + decision_function + ) + int_vars = Boscia.get_integer_variables(bounded_lmo) + int_var_number = length(int_vars) + # create sparse array for pseudocosts + pseudos = sparse( + repeat(int_vars, 2), + vcat(ones(int_var_number), 2*ones(int_var_number)), + ones(2 * int_var_number) + ) + # create sparse array for keeping track of how often a pseudocost has been updated + branch_tracker = sparse( + repeat(int_vars, 2), + vcat(ones(int_var_number), 2*ones(int_var_number)), + ones(Int64, 2 * int_var_number) + ) + # create sparse array for keeping track of how often a branching has resulted in infeas. + # of resulting node + infeas_tracker = deepcopy(branch_tracker) + new( + iterations_until_stable, + alternative, + μ, + decision_function, + pseudos, + branch_tracker, + infeas_tracker) + end end - """ get_branching_variable( tree::Bonobo.BnBTree, @@ -130,7 +162,8 @@ end pseudos::SparseMatrixCSC, branch_tracker::SparseMatrixCSC ) -This strategy first chooses the branching varaibles which have most often led to infeasiblity. +Description: +This strategy first chooses the branching variables which have most often led to infeasiblity. If there are multiple such candidates then among these candidates another strategy is used if candidate pseudocosts are stable then a pseudocost decision is made else @@ -142,26 +175,182 @@ If there are multiple such candidates then among these candidates another strate """ function Bonobo.get_branching_variable( tree::Bonobo.BnBTree, - branching::HIERARCHY_PSEUDO_COST{BLMO}, + branching::HIERARCHY_PSEUDO_COST, node::Bonobo.AbstractNode, - pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64}, - infeas_tracker::SparseMatrixCSC{Int64, Int64}, -) where BLMO <: BoundedLinearMinimizationOracle +) + # indices of branching candidates + values = Bonobo.get_relaxed_values(tree, node) + branching_candidates = get_branching_candidates(tree, node, values) + update_pseudocost!(tree, node, branching, values) + if isempty(branching_candidates) + #branching is no longer possible + return -1 + end + # Top level Selection criteria: Choose what leads most often to infeasible child nodes + best_score = max_infeas_score(branching_candidates, branching.infeas_tracker) + # keep candidates with highest score only + branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, branching.infeas_tracker) >= best_score] - strategy_switch = branching.iterations_until_stable + 1 + if length(branching_candidates) == 1 + # if only one candidate exists all strategies will choose it + best_idx = branching_candidates[1] + elseif !candidates_pseudo_stable(branching, branching_candidates) + if branching.alternative == "largest_most_infeasible_gradient" + best_idx = largest_most_infeasible_gradient_decision(tree, branching_candidates, values) + elseif branching.alternative == "largest_gradient" + best_idx = largest_gradient_decision(tree, branching_candidates, values) + else + best_idx = most_infeasible_decision(tree, branching_candidates, values) + end + else + best_idx = pseudocost_decision(branching, branching_candidates, values) + end + # update number of times the candidate has been branched on + branching.infeas_tracker[best_idx, 2] += 1 + return best_idx +end + + +""" +largest_most_infeasible_gradient_decision( + tree::Bonobo.BnBTree, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) +\nDescription: +\n choose by LARGEST_MOST_INFEASIBLE_GRADIENT +among candidates in branching_candidates + +""" +function largest_most_infeasible_gradient_decision( + tree::Bonobo.BnBTree, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) + nabla = similar(values) + x_new = copy(values) + gradient_at_values = tree.root.problem.g(nabla,x_new) + max_score = 0.0 best_idx = -1 - all_stable = true - # the following shall contain the indices of the potential branching variables - branching_candidates = Int[] - values = Bonobo.get_relaxed_values(tree, node) - for idx in tree.branching_indices + for i in branching_candidates + value = values[i] + value = abs(value - round(value)) * abs(gradient_at_values[i]) + if value >= max_score + best_idx = i + max_score = value + end + end + return best_idx +end + + +""" +most_infeasible_decision( + tree::Bonobo.BnBTree, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) +\nDescription: +\n Choose by largest distance to next integer feasible solution +among the candidates in branching_candidates +""" +function most_infeasible_decision( + tree::Bonobo.BnBTree, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) + best_idx = -1 + max_distance_to_feasible = 0.0 + for idx in branching_candidates value = values[idx] - if !Bonobo.is_approx_feasible(tree, value) - push!(branching_candidates, idx) + distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) + if distance_to_feasible > max_distance_to_feasible + best_idx = idx + max_distance_to_feasible = distance_to_feasible end end - # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable + return best_idx +end + +""" +largest_gradient_decision( + tree::Bonobo.BnBTree, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) +\nDescription: +\n Decision is made based on highest abs value entry in gradient for branching candidates +""" +function largest_gradient_decision( + tree::Bonobo.BnBTree, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) + nabla = similar(values) + gradient_at_values = tree.root.problem.g(nabla, nabla) + best_idx = -1 + max_gradient = 0.0 + for idx in branching_candidates + if abs(gradient_at_values[idx]) >= max_gradient + best_idx = idx + end + end + return best_idx +end + + +""" +pseudocost_decision( + branching::Bonobo.AbstractBranchStrategy, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) +\nDescription: +\nPerform a pseudocost decision based +on the choice of decision function defined in +branching.decision_function +Returns: index of chosen candidate variable +""" +function pseudocost_decision( + branching::Bonobo.AbstractBranchStrategy, + branching_candidates::Vector{Int}, + values::Vector{Float64} +) + if branching.decision_function == "weighted_sum" + return weighted_sum_decision( + branching_candidates, + branching.μ, + branching.pseudos, + values + ) + elseif branching.decision_function == "product" + return product_decision( + branching_candidates, + branching.μ, + branching.pseudos, + values + ) + end +end +""" +update_pseudocost!( + tree::Bonobo.BnBTree, + node::FrankWolfeNode, + branching::Bonobo.AbstractBranchStrategy, + values::Vector{Float64} +) +\nDescription: +\n-Updates the pseudocost of the index that +the current node resulted from.\n +-Distinction being made if it was a left or right branch +and if node is a result of branching at all. +""" +function update_pseudocost!( + tree::Bonobo.BnBTree, + node::FrankWolfeNode, + branching::Bonobo.AbstractBranchStrategy, + values::Vector{Float64} +) if !isinf(node.parent_lower_bound_base) idx = node.branched_on update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base @@ -170,93 +359,236 @@ function Bonobo.get_branching_variable( @debug "update is $(Inf)" end if node.branched_right - pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) - branch_tracker[idx, 1] += 1 + branching.pseudos[idx, 1] = update_avg(update, branching.pseudos[idx, 1], branching.branch_tracker[idx, 1]) + branching.branch_tracker[idx, 1] += 1 else - pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) - branch_tracker[idx, 2] += 1 - + branching.pseudos[idx, 2] = update_avg(update, branching.pseudos[idx, 2], branching.branch_tracker[idx, 2]) + branching.branch_tracker[idx, 2] += 1 end end - # compute score of how (often) branching on a variable resulted in infeasiblity - best_score = max_infeas_score(branching_candidates, infeas_tracker) - branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, infeas_tracker) >= best_score] - if length(branching_candidates) == 0 - return best_idx - elseif length(branching_candidates) == 1 - best_idx = branching_candidates[1] - infeas_tracker[best_idx, 2] += 1 - return best_idx - end +end + +""" +candidates_pseudo_stable( + branching::Bonobo.AbstractBranchStrategy, + branching_candidates::Vector{Int} +) +\nDescription: +\n Checks if all branching candidates have stable pseudocosts. +\n Returns: true or false +""" +function candidates_pseudo_stable( + branching::Bonobo.AbstractBranchStrategy, + branching_candidates::Vector{Int} +) + strategy_switch = branching.iterations_until_stable + 1 + all_stable = true for idx in branching_candidates - # check if pseudocost is stable for this idx - if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch + # check if pseudocost is stable for this candidate + if branching.branch_tracker[idx, 1] < strategy_switch || branching.branch_tracker[idx, 2] < strategy_switch all_stable = false + break end end - - if !all_stable# THEN Use Most Infeasible - if branching.gradient_influence - # score function as product of gradient at variable and largest distance to int - nabla = similar(values) - x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla,x_new) - max_score = 0.0 - for i in branching_candidates - value = values[i] * abs(gradient_at_values[i]) - if value > max_score - best_idx = i - max_score = value - end - end - return best_idx - else - max_distance_to_feasible = 0.0 - for i in branching_candidates - value = values[i] - distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) - if distance_to_feasible > max_distance_to_feasible - best_idx = i - max_distance_to_feasible = distance_to_feasible - end - end - infeas_tracker[best_idx, 2] += 1 - return best_idx + return all_stable +end + +""" +get_branching_candidates( + tree::Bonobo.BnBTree, + node::FrankWolfeNode, + values::Vector{Float64} +) +\nDescription: +\n finds all possible branching candidates at the current node +""" +function get_branching_candidates( + tree::Bonobo.BnBTree, + node::FrankWolfeNode, + values::Vector{Float64} +) + branching_candidates = Int[] + for idx in tree.branching_indices + value = values[idx] + if !Bonobo.is_approx_feasible(tree, value) + push!(branching_candidates, idx) end - else - if branching.decision_function == "weighted_sum" - branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]))), - branching_candidates) - - elseif branching.decision_function == "product" - branching_scores = map(idx-> max((pseudos[idx, 1] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 2] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), - branching_candidates) + end + return branching_candidates +end +""" +weighted_sum_decision( + idx::Int, + branching_candidates::Vector{Int}, + branching::Bonobo.AbstractBranchStrategy, + pseudos::SparseMatrixCSC{Float64, Int64}, + values::Vector{Float64} +) +\nDescription: +\nThis method first scales pseudocosts of candidate variables +by distance to integer solution. Then it calculates a score as a convex combination +of each pseudocost pair using the branching.μ parameter. Lastly it chooses the +candidate which has the highest score, i.e. whose convex combination value is largest. +""" +function weighted_sum_decision( + branching_candidates::Vector{Int}, + μ::Float64, + pseudos::SparseMatrixCSC{Float64, Int64}, + values::Vector{Float64} +) + best_idx = branching_candidates[1] + best_score = 0 + for idx in branching_candidates + unit_cost_pseudos = unit_cost_pseudo_tuple( + pseudos[idx, 2], + pseudos[idx, 1], + values[idx] + ) + score = pseudocost_convex_combination(unit_cost_pseudos, μ) + if score > best_score + best_idx = idx + best_score = best_score end - branching_scores = sparsevec(branching_candidates, branching_scores) - best_idx = argmax(branching_scores) - infeas_tracker[best_idx, 2] += 1 - return best_idx end + # calc convex comb. of each unit cost scaled pseudo pair + branching_scores = map( + idx-> pseudocost_convex_combination( + unit_cost_pseudo_tuple( + pseudos[idx, 2], + pseudos[idx, 1], + values[idx] + ), + μ + ), + branching_candidates) + # return candidate with highest value + return argmax(sparsevec(branching_candidates, branching_scores)) +end + +""" +function product_decision( + branching_candidates::Vector{Int}, + μ::Float64, + pseudos::SparseMatrixCSC{Float64, Int64}, + values::Vector{Float64} +) +\nDescription: +\nMakes decision based on highest μ_product of pseudocosts +for branching candidate +""" +function product_decision( + branching_candidates::Vector{Int}, + μ::Float64, + pseudos::SparseMatrixCSC{Float64, Int64}, + values::Vector{Float64} +) +# calc μ_product of each unit cost scaled pseudo pair + branching_scores = map( + idx-> μ_product( + unit_cost_pseudo_tuple( + pseudos[idx, 2], + pseudos[idx, 1], + values[idx] + ), + μ + ), + branching_candidates) + # return candidate with highest μ_product + return argmax(sparsevec(branching_candidates, branching_scores)) +end + + +""" +pseudocost_convex_combination( + pseudocost_tuple::Tuple{Float64,Float64}, + μ::Float64 + ) +Description: Calculates a convex combination of elements contained in the tuple pseudocost_tuple +""" +function pseudocost_convex_combination( + pseudocost_tuple::Tuple{Float64,Float64}, + μ::Float64 + ) + return (1 - μ) * minimum(pseudocost_tuple) + μ * maximum(pseudocost_tuple) +end + +""" + unit_cost_pseudo_tuple( + pd::Float64, + pu::Float64, + value::Float64 +) +\nDescription: +\nMultiply up and down branch pseudocost of branching candidate +by the distance of the current solution (value) to the respective +next integer solution. +\nThereby performing unit cost scaling of pseudocosts. +The -1 is a result of pseudocosts being intitalized as 1. +\nReturns: tuple containing the two unit cost scaled pseudocosts. +""" +function unit_cost_pseudo_tuple( + left_pseudo::Float64, + right_pseudo::Float64, + value::Float64 +) + return ((left_pseudo - 1) * (value - floor(value)), + (right_pseudo - 1) * (ceil(value) - value)) end -function infeas_score(idx::Int, infeas_tracker::SparseMatrixCSC{Int64, Int64}) +""" +μ_product( + pseudocost_tuple::Tuple{Float64, Float64}, + μ::Float64 +) +\nDescription: +\nMultiplies elements of tuple while replacing elements +smaller than μ by μ in the product +""" +function μ_product( + pseudocost_tuple::Tuple{Float64, Float64}, + μ::Float64 +) + return max(pseudocost_tuple[1], μ) * max(pseudocost_tuple[2], μ) +end + + +""" +infeas_score( + idx::Int, + infeas_tracker::SparseMatrixCSC{Int64, Int64} + ) +Description: calculates ratio of how often branching on candidate idx + has led to infeasibilty of a resulting node. +""" +function infeas_score( + idx::Int, + infeas_tracker::SparseMatrixCSC{Int64, Int64} + ) infeas_tracker[idx, 1] == 1 && return 0 # ratio of how often branching on variable idx leads to node infeasiblity of children return (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2]) end -function max_infeas_score(idxs::Vector{Int64}, infeas_tracker::SparseMatrixCSC{Int64, Int64}) +""" +max_infeas_score( + idxs::Vector{Int64}, + infeas_tracker::SparseMatrixCSC{Int64, Int64} + ) +\nDescription: +\nCalculates maximum infeasibilty score over all branching candidates +\n Infeasibility score as ratio of how (often) branching on a variable resulted in infeasiblity of resulting node + +""" +function max_infeas_score( + idxs::Vector{Int64}, + infeas_tracker::SparseMatrixCSC{Int64, Int64} + ) max_score = 0 for idx in idxs - if infeas_tracker[idx, 1] == 1 - continue - else - max_score = max(max_score, (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2])) - end + max_score = max(max_score, infeas_score(idx, infeas_tracker)) end - return max_score end @@ -266,7 +598,9 @@ end """ LargestGradient <: AbstractBranchStrategy -The `LargestGradient` strategy always picks the variable which has the largest absolute value entry in the current gradient and can be branched on. +The `LargestGradient` strategy always picks the variable which +has the largest absolute value entry in the current gradient +and can be branched on. """ struct LargestGradient <: Bonobo.AbstractBranchStrategy end @@ -287,15 +621,14 @@ function Bonobo.get_branching_variable( ) values = Bonobo.get_relaxed_values(tree, node) nabla = similar(values) - x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla, x_new) + gradient_at_values = tree.root.problem.g(nabla, nabla) best_idx = -1 max_gradient = 0.0 for i in tree.branching_indices value = values[i] # check if variable is branching candidate if !Bonobo.is_approx_feasible(tree, value) - if abs(gradient_at_values[i]) > max_gradient + if abs(gradient_at_values[i]) >= max_gradient best_idx = i end end @@ -304,14 +637,13 @@ function Bonobo.get_branching_variable( end - """ LargestMostInfeasibleGradient <: AbstractBranchStrategy -The `LargestMostInfeasibleGradient` strategy always picks the variable which has the largest absolute value -entry in the current gradient multiplied by the maximum distance to being fixed. +The `LargestMostInfeasibleGradient` strategy always picks the variable which +has the largest absolute value entry in the current gradient multiplied +by the maximum distance to being fixed. """ - struct LargestMostInfeasibleGradient <: Bonobo.AbstractBranchStrategy end @@ -332,14 +664,14 @@ function Bonobo.get_branching_variable( values = Bonobo.get_relaxed_values(tree, node) best_idx = -1 nabla = similar(values) - x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla,x_new) + gradient_at_values = tree.root.problem.g(nabla,nabla) max_score = 0.0 for i in tree.branching_indices value = values[i] if !Bonobo.is_approx_feasible(tree, value) + value = abs(value - round(value)) value *= abs(gradient_at_values[i]) - if value > max_score + if value >= max_score best_idx = i max_score = value end From cc4a8a45ad3f16dd806136a8dc3c8c722ddd8425 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 26 Sep 2024 16:46:27 +0200 Subject: [PATCH 47/56] changes made for code readability and simplicity. Only for hierarchy so far to test if it will still work. --- src/custom_bonobo.jl | 68 +++++++++++++++++++++++++++++--------------- src/interface.jl | 2 +- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index df7f6ba73..10856afcc 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -41,7 +41,7 @@ function Bonobo.optimize!( if isnan(lb) && isnan(ub) @debug "\n node closed without upd\n" if isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) - infeas_tracker[node.branched_on, 1] += 1 + tree.options.branch_strategy.infeas_tracker[node.branched_on, 1] += 1 end ## add the nodes which become infeasible to a special storage (yet to be implemented) Bonobo.close_node!(tree, node) @@ -54,7 +54,7 @@ function Bonobo.optimize!( # if the evaluated lower bound is worse than the best incumbent -> close and continue if node.lb >= tree.incumbent # In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable - if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) || isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) + if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable if !isinf(node.parent_lower_bound_base) idx = node.branched_on @@ -71,6 +71,30 @@ function Bonobo.optimize!( branch_tracker[idx, 2] += 1 end end + elseif isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) + if !isinf(node.parent_lower_bound_base) + idx = node.branched_on + update = lb - node.parent_lower_bound_base + update = update / node.distance_to_int + if isinf(update) + @debug "update is $(Inf)" + end + if node.branched_right + tree.options.branch_strategy.pseudos[idx, 1] = update_avg( + update, + tree.options.branch_strategy.pseudos[idx, 1], + tree.options.branch_strategy.branch_tracker[idx, 1] + ) + tree.options.branch_strategy.branch_tracker[idx, 1] += 1 + else + tree.options.branch_strategy.pseudos[idx, 2] = update_avg( + update, + tree.options.branch_strategy.pseudos[idx, 2], + tree.options.branch_strategy.branch_tracker[idx, 2] + ) + tree.options.branch_strategy.branch_tracker[idx, 2] += 1 + end + end end Bonobo.close_node!(tree, node) @@ -102,8 +126,6 @@ function Bonobo.optimize!( Bonobo.close_node!(tree, node) if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) pseudo_branch!(tree, node, pseudos, branch_tracker) - elseif isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) - hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker, infeas_tracker) else Bonobo.branch!(tree, node) end @@ -170,23 +192,23 @@ function pseudo_branch!( end end -""" - hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker) +# """ +# hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker) -Get the branching variable with [`get_branching_variable`](@ref) and then calls [`get_branching_nodes_info`](@ref) and [`add_node!`](@ref). -""" -function hierarchy_pseudo_branch!( - tree::Bonobo.BnBTree{<:FrankWolfeNode}, - node::Bonobo.AbstractNode, - pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64}, - infeas_tracker::SparseMatrixCSC{Int64, Int64} - ) - variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker, infeas_tracker) - # no branching variable selected => return - variable_idx == -1 && return - nodes_info = Bonobo.get_branching_nodes_info(tree, node, variable_idx) - for node_info in nodes_info - Bonobo.add_node!(tree, node, node_info) - end -end +# Get the branching variable with [`get_branching_variable`](@ref) and then calls [`get_branching_nodes_info`](@ref) and [`add_node!`](@ref). +# """ +# function hierarchy_pseudo_branch!( +# tree::Bonobo.BnBTree{<:FrankWolfeNode}, +# node::Bonobo.AbstractNode, +# pseudos::SparseMatrixCSC{Float64, Int64}, +# branch_tracker::SparseMatrixCSC{Int64, Int64}, +# infeas_tracker::SparseMatrixCSC{Int64, Int64} +# ) +# variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker, infeas_tracker) +# # no branching variable selected => return +# variable_idx == -1 && return +# nodes_info = Bonobo.get_branching_nodes_info(tree, node, variable_idx) +# for node_info in nodes_info +# Bonobo.add_node!(tree, node, node_info) +# end +# end diff --git a/src/interface.jl b/src/interface.jl index 856fceb4c..57b44c5fb 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -295,7 +295,7 @@ function solve( tree.root.options[:callback] = fw_callback tree.root.current_node_id[] = Bonobo.get_next_node(tree, tree.options.traverse_strategy).id #the following should create the arrays and vectors only on first function call and then use existing one - if isa(branching_strategy, Boscia.PSEUDO_COST) || isa(branching_strategy, Boscia.HIERARCHY_PSEUDO_COST) + if isa(branching_strategy, Boscia.PSEUDO_COST) pseudos = sparse( repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), From 242794ce7255be44e8d5bd82cf3392d6342cc586 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 2 Oct 2024 10:12:28 +0200 Subject: [PATCH 48/56] moving pseudocost storage and branch_tracker for pseudocost strategy into the branching strategy which now is a mutable structure --- src/branching_strategies.jl | 77 ++++++++++++++++++------------------- src/custom_bonobo.jl | 71 ++-------------------------------- src/interface.jl | 27 +------------ 3 files changed, 43 insertions(+), 132 deletions(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 9560b8f2f..2e58cb051 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -1,11 +1,38 @@ using SparseArrays -struct PSEUDO_COST{BLMO<:BoundedLinearMinimizationOracle} <: Bonobo.AbstractBranchStrategy +mutable struct PSEUDO_COST <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int - stable::Bool - bounded_lmo::BLMO μ::Float64 decision_function::String + pseudos::SparseMatrixCSC{Float64, Int64} + branch_tracker::SparseMatrixCSC{Int64, Int64} + function PSEUDO_COST( + iterations_until_stable, + bounded_lmo, + μ, + decision_function + ) + int_vars = Boscia.get_integer_variables(bounded_lmo) + int_var_number = length(int_vars) + # create sparse array for pseudocosts + pseudos = sparse( + repeat(int_vars, 2), + vcat(ones(int_var_number), 2*ones(int_var_number)), + ones(2 * int_var_number) + ) + # create sparse array for keeping track of how often a pseudocost has been updated + branch_tracker = sparse( + repeat(int_vars, 2), + vcat(ones(int_var_number), 2*ones(int_var_number)), + ones(Int64, 2 * int_var_number) + ) + new( + iterations_until_stable, + μ, + decision_function, + pseudos, + branch_tracker) + end end @@ -24,43 +51,25 @@ Prior to stabilization an adaptation of the Bonobo MOST_INFEASIBLE is used. """ function Bonobo.get_branching_variable( tree::Bonobo.BnBTree, - branching::PSEUDO_COST{BLMO}, + branching::PSEUDO_COST, node::Bonobo.AbstractNode, - pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64}, -) where BLMO <: BoundedLinearMinimizationOracle - +) strategy_switch = branching.iterations_until_stable + 1 best_idx = -1 all_stable = true - branching_candidates = Int[]# this shall contain the indices of the potential branching variables + # this shall contain the indices of the potential branching variables + branching_candidates = Int[] values = Bonobo.get_relaxed_values(tree, node) for idx in tree.branching_indices value = values[idx] if !Bonobo.is_approx_feasible(tree, value) push!(branching_candidates, idx) - if branch_tracker[idx, 1] < strategy_switch || branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx + if branching.branch_tracker[idx, 1] < strategy_switch || branching.branch_tracker[idx, 2] < strategy_switch# check if pseudocost is stable for this idx all_stable = false end end end - # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable - if !isinf(node.parent_lower_bound_base) - idx = node.branched_on - update = (tree.root.problem.f(values) - node.dual_gap) - node.parent_lower_bound_base - update = update / node.distance_to_int - if isinf(update) - @debug "update is $(Inf)" - end - if node.branched_right - pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) - branch_tracker[idx, 1] += 1 - else - pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) - branch_tracker[idx, 2] += 1 - - end - end + update_pseudocost!(tree, node, branching, values) length(branching_candidates) == 0 && return best_idx length(branching_candidates) == 1 && return branching_candidates[1] if !all_stable# THEN Use Most Infeasible @@ -75,18 +84,8 @@ function Bonobo.get_branching_variable( end return best_idx else - if branching.decision_function == "weighted_sum" - branching_scores = map(idx-> ((1 - branching.μ) * min((pseudos[idx, 2] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 1] - 1) * (ceil(values[idx]) - values[idx])) + branching.μ * max((pseudos[idx, 2] - 1) * (values[idx] - floor(values[idx])), (pseudos[idx, 1] - 1) * (ceil(values[idx]) - values[idx]))), - branching_candidates) - - elseif branching.decision_function == "product" - branching_scores = map(idx-> max((pseudos[idx, 2] - 1) * (values[idx] - floor(values[idx])), branching.μ) * max((pseudos[idx, 1] - 1) * (ceil(values[idx]) - values[idx]), branching.μ), - branching_candidates) - end - branching_scores = sparsevec(branching_candidates, branching_scores) - best_idx = argmax(branching_scores) - - return best_idx + # All candidates pseudo stable thus make pseudocost decision + return pseudocost_decision(branching, branching_candidates, values) end end diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index 10856afcc..f8cf61d13 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -27,10 +27,7 @@ which are set in the following ways: 2. If the node has a higher lower bound than the incumbent the kwarg `worse_than_incumbent` is set to `true`. """ function Bonobo.optimize!( - tree::Bonobo.BnBTree{<:FrankWolfeNode}, - pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64}, - infeas_tracker::SparseMatrixCSC{Int64, Int64}; + tree::Bonobo.BnBTree{<:FrankWolfeNode}; callback=(args...; kwargs...) -> (), ) #println("OWN OPTIMIZE") @@ -43,7 +40,6 @@ function Bonobo.optimize!( if isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) tree.options.branch_strategy.infeas_tracker[node.branched_on, 1] += 1 end - ## add the nodes which become infeasible to a special storage (yet to be implemented) Bonobo.close_node!(tree, node) callback(tree, node; node_infeasible=true) continue @@ -54,24 +50,7 @@ function Bonobo.optimize!( # if the evaluated lower bound is worse than the best incumbent -> close and continue if node.lb >= tree.incumbent # In pseudocost branching we need to perform the update now for nodes which will never be seen by get_branching_variable - if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) - # if this node is a result of branching on some variable then update pseudocost of corresponding branching variable - if !isinf(node.parent_lower_bound_base) - idx = node.branched_on - update = lb - node.parent_lower_bound_base - update = update / node.distance_to_int - if isinf(update) - @debug "update is $(Inf)" - end - if node.branched_right - pseudos[idx, 1] = update_avg(update, pseudos[idx, 1], branch_tracker[idx, 1]) - branch_tracker[idx, 1] += 1 - else - pseudos[idx, 2] = update_avg(update, pseudos[idx, 2], branch_tracker[idx, 2]) - branch_tracker[idx, 2] += 1 - end - end - elseif isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) + if isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) || isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) if !isinf(node.parent_lower_bound_base) idx = node.branched_on update = lb - node.parent_lower_bound_base @@ -124,11 +103,7 @@ function Bonobo.optimize!( end Bonobo.close_node!(tree, node) - if isa(tree.options.branch_strategy, Boscia.PSEUDO_COST) - pseudo_branch!(tree, node, pseudos, branch_tracker) - else - Bonobo.branch!(tree, node) - end + Bonobo.branch!(tree, node) callback(tree, node) end return Bonobo.sort_solutions!(tree.solutions, tree.sense) @@ -172,43 +147,3 @@ function Bonobo.get_solution( return tree.solutions[result].solution end -""" - pseudo_branch!(tree, node, pseudos, branch_tracker) - -Get the branching variable with [`get_branching_variable`](@ref) and then calls [`get_branching_nodes_info`](@ref) and [`add_node!`](@ref). -""" -function pseudo_branch!( - tree::Bonobo.BnBTree{<:FrankWolfeNode}, - node::Bonobo.AbstractNode, - pseudos::SparseMatrixCSC{Float64, Int64}, - branch_tracker::SparseMatrixCSC{Int64, Int64}, - ) - variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker) - # no branching variable selected => return - variable_idx == -1 && return - nodes_info = Bonobo.get_branching_nodes_info(tree, node, variable_idx) - for node_info in nodes_info - Bonobo.add_node!(tree, node, node_info) - end -end - -# """ -# hierarchy_pseudo_branch!(tree, node, pseudos, branch_tracker) - -# Get the branching variable with [`get_branching_variable`](@ref) and then calls [`get_branching_nodes_info`](@ref) and [`add_node!`](@ref). -# """ -# function hierarchy_pseudo_branch!( -# tree::Bonobo.BnBTree{<:FrankWolfeNode}, -# node::Bonobo.AbstractNode, -# pseudos::SparseMatrixCSC{Float64, Int64}, -# branch_tracker::SparseMatrixCSC{Int64, Int64}, -# infeas_tracker::SparseMatrixCSC{Int64, Int64} -# ) -# variable_idx = Bonobo.get_branching_variable(tree, tree.options.branch_strategy, node, pseudos, branch_tracker, infeas_tracker) -# # no branching variable selected => return -# variable_idx == -1 && return -# nodes_info = Bonobo.get_branching_nodes_info(tree, node, variable_idx) -# for node_info in nodes_info -# Bonobo.add_node!(tree, node, node_info) -# end -# end diff --git a/src/interface.jl b/src/interface.jl index 57b44c5fb..ab9daa4d3 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -294,31 +294,8 @@ function solve( tree.root.options[:callback] = fw_callback tree.root.current_node_id[] = Bonobo.get_next_node(tree, tree.options.traverse_strategy).id - #the following should create the arrays and vectors only on first function call and then use existing one - if isa(branching_strategy, Boscia.PSEUDO_COST) - pseudos = sparse( - repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), - ones(2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) - ) - branch_tracker = sparse( - repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), - ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) - ) - infeas_tracker = sparse( - repeat(Boscia.get_integer_variables(branching_strategy.bounded_lmo), 2), - vcat(ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))), 2*ones(length(Boscia.get_integer_variables(branching_strategy.bounded_lmo)))), - ones(Int64, 2 * length(Boscia.get_integer_variables(branching_strategy.bounded_lmo))) - ) - else - pseudos = sparse([1], [1], [0.0]) - - branch_tracker = sparse([1], [1], Int[0]) - - infeas_tracker = sparse([1], [1], Int[0]) - end - Bonobo.optimize!(tree, pseudos, branch_tracker, infeas_tracker; callback=bnb_callback) + + Bonobo.optimize!(tree; callback=bnb_callback) x = postsolve(tree, result, time_ref, verbose, max_iteration_post) From 0a6690a958a65834799913576021d3e5360cc814 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 2 Oct 2024 13:16:34 +0200 Subject: [PATCH 49/56] Modified pseudocost branching to allow multiple alternative strats --- src/branching_strategies.jl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 2e58cb051..1fdc217c0 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -2,6 +2,7 @@ using SparseArrays mutable struct PSEUDO_COST <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int + alternative::String μ::Float64 decision_function::String pseudos::SparseMatrixCSC{Float64, Int64} @@ -28,6 +29,7 @@ mutable struct PSEUDO_COST <: Bonobo.AbstractBranchStrategy ) new( iterations_until_stable, + alternative, μ, decision_function, pseudos, @@ -72,15 +74,13 @@ function Bonobo.get_branching_variable( update_pseudocost!(tree, node, branching, values) length(branching_candidates) == 0 && return best_idx length(branching_candidates) == 1 && return branching_candidates[1] - if !all_stable# THEN Use Most Infeasible - max_distance_to_feasible = 0.0 - for i in branching_candidates - value = values[i] - distance_to_feasible = Bonobo.get_distance_to_feasible(tree, value) - if distance_to_feasible > max_distance_to_feasible - best_idx = i - max_distance_to_feasible = distance_to_feasible - end + if !all_stable# THEN Use alternative + if branching.alternative == "largest_most_infeasible_gradient" + best_idx = largest_most_infeasible_gradient_decision(tree, branching_candidates, values) + elseif branching.alternative == "largest_gradient" + best_idx = largest_gradient_decision(tree, branching_candidates, values) + else + best_idx = most_infeasible_decision(tree, branching_candidates, values) end return best_idx else From 1cc243cce32a287883276cef4d29f1c04a22af2a Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 2 Oct 2024 16:02:28 +0200 Subject: [PATCH 50/56] bug fix in pseudo branching mutable struct creation --- src/branching_strategies.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 1fdc217c0..a09e91c5e 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -9,6 +9,7 @@ mutable struct PSEUDO_COST <: Bonobo.AbstractBranchStrategy branch_tracker::SparseMatrixCSC{Int64, Int64} function PSEUDO_COST( iterations_until_stable, + alternative, bounded_lmo, μ, decision_function From 753be8dfa752a06fb756d19bf3f32474599a333a Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 23 Oct 2024 13:49:36 +0200 Subject: [PATCH 51/56] hierarchy branching change --- src/Boscia.jl | 1 + src/branching_strategies.jl | 138 ++++++++++++++++++++---------------- src/custom_bonobo.jl | 4 -- 3 files changed, 77 insertions(+), 66 deletions(-) diff --git a/src/Boscia.jl b/src/Boscia.jl index dff93d8a2..6e9a15245 100644 --- a/src/Boscia.jl +++ b/src/Boscia.jl @@ -4,6 +4,7 @@ using FrankWolfe import FrankWolfe: compute_extreme_point export compute_extreme_point using Random +using Statistics import Bonobo using Printf using Dates diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index a09e91c5e..1537d15ae 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -113,18 +113,20 @@ end mutable struct HIERARCHY_PSEUDO_COST <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int alternative::String + stable_alternative::String μ::Float64 decision_function::String pseudos::SparseMatrixCSC{Float64, Int64} branch_tracker::SparseMatrixCSC{Int64, Int64} - infeas_tracker::SparseMatrixCSC{Int64, Int64} - + cutoff::Float64 function HIERARCHY_PSEUDO_COST( iterations_until_stable, alternative, + stable_alternative, bounded_lmo, μ, - decision_function + decision_function; + cutoff=1e-3 ) int_vars = Boscia.get_integer_variables(bounded_lmo) int_var_number = length(int_vars) @@ -140,17 +142,15 @@ mutable struct HIERARCHY_PSEUDO_COST <: Bonobo.AbstractBranchStrategy vcat(ones(int_var_number), 2*ones(int_var_number)), ones(Int64, 2 * int_var_number) ) - # create sparse array for keeping track of how often a branching has resulted in infeas. - # of resulting node - infeas_tracker = deepcopy(branch_tracker) new( iterations_until_stable, alternative, + stable_alternative, μ, decision_function, pseudos, branch_tracker, - infeas_tracker) + cutoff) end end @@ -186,30 +186,84 @@ function Bonobo.get_branching_variable( #branching is no longer possible return -1 end - # Top level Selection criteria: Choose what leads most often to infeasible child nodes - best_score = max_infeas_score(branching_candidates, branching.infeas_tracker) - # keep candidates with highest score only - branching_candidates = Int[idx for idx in branching_candidates if infeas_score(idx, branching.infeas_tracker) >= best_score] - - if length(branching_candidates) == 1 - # if only one candidate exists all strategies will choose it - best_idx = branching_candidates[1] - elseif !candidates_pseudo_stable(branching, branching_candidates) + fractional_scores = Float64[Bonobo.get_distance_to_feasible(tree, values[idx]) for idx in branching_candidates] + # Check if branching candidates are fractional enough + frac_enough_cand = Int[] + + infeas_cutoff = (maximum(fractional_scores) + mean(fractional_scores))/2 + for (i, idx) in enumerate(branching_candidates) + if fractional_scores[i] > max(infeas_cutoff, branching.cutoff) + push!(frac_enough_cand, idx) + end + end + if isempty(frac_enough_cand) + # no candidate looks promising so we choose any + return rand(branching_candidates) + end + if length(frac_enough_cand) == 1 + # if only one candidate remains we choose it + return frac_enough_cand[1] + end + + if !candidates_pseudo_stable(branching, frac_enough_cand) if branching.alternative == "largest_most_infeasible_gradient" - best_idx = largest_most_infeasible_gradient_decision(tree, branching_candidates, values) + best_idx = largest_most_infeasible_gradient_decision(tree, frac_enough_cand, values) elseif branching.alternative == "largest_gradient" - best_idx = largest_gradient_decision(tree, branching_candidates, values) + best_idx = largest_gradient_decision(tree, frac_enough_cand, values) else - best_idx = most_infeasible_decision(tree, branching_candidates, values) + best_idx = most_infeasible_decision(tree, frac_enough_cand, values) end else - best_idx = pseudocost_decision(branching, branching_candidates, values) + pseudo_approved_candidates = pseudo_selection(branching, frac_enough_cand, values) + if branching.stable_alternative == "largest_most_infeasible_gradient" + best_idx = largest_most_infeasible_gradient_decision(tree, pseudo_approved_candidates, values) + elseif branching.stable_alternative == "largest_gradient" + best_idx = largest_gradient_decision(tree, pseudo_approved_candidates, values) + else + best_idx = most_infeasible_decision(tree, pseudo_approved_candidates, values) + end end - # update number of times the candidate has been branched on - branching.infeas_tracker[best_idx, 2] += 1 return best_idx end +function pseudo_selection( + branching::Bonobo.AbstractBranchStrategy, + candidates::Vector{Int}, + values::Vector{Float64} +) + if branching.decision_function == "product" + branching_scores = map( + idx-> μ_product( + unit_cost_pseudo_tuple( + branching.pseudos[idx, 2], + branching.pseudos[idx, 1], + values[idx] + ), + branching.μ + ), + candidates) + elseif branching.decision_function == "weighted_sum" + branching_scores = map( + idx-> pseudocost_convex_combination( + unit_cost_pseudo_tuple( + branching.pseudos[idx, 2], + branching.pseudos[idx, 1], + values[idx] + ), + branching.μ + ), + candidates) + end + #pseudo_cutoff = (mean(branching_scores) + maximum(branching_scores))/2 + pseudo_cutoff = 3/4 * maximum(branching_scores) + 1/4 * mean(branching_scores) + pseudo_approved_candidates = Int[] + for (i, idx) in enumerate(candidates) + if branching_scores[i] >= pseudo_cutoff + push!(pseudo_approved_candidates, idx) + end + end + return pseudo_approved_candidates +end """ largest_most_infeasible_gradient_decision( @@ -554,46 +608,6 @@ function μ_product( end -""" -infeas_score( - idx::Int, - infeas_tracker::SparseMatrixCSC{Int64, Int64} - ) -Description: calculates ratio of how often branching on candidate idx - has led to infeasibilty of a resulting node. -""" -function infeas_score( - idx::Int, - infeas_tracker::SparseMatrixCSC{Int64, Int64} - ) - infeas_tracker[idx, 1] == 1 && return 0 - # ratio of how often branching on variable idx leads to node infeasiblity of children - return (infeas_tracker[idx, 1]) / (infeas_tracker[idx, 2]) -end - -""" -max_infeas_score( - idxs::Vector{Int64}, - infeas_tracker::SparseMatrixCSC{Int64, Int64} - ) -\nDescription: -\nCalculates maximum infeasibilty score over all branching candidates -\n Infeasibility score as ratio of how (often) branching on a variable resulted in infeasiblity of resulting node - -""" -function max_infeas_score( - idxs::Vector{Int64}, - infeas_tracker::SparseMatrixCSC{Int64, Int64} - ) - max_score = 0 - for idx in idxs - max_score = max(max_score, infeas_score(idx, infeas_tracker)) - end - return max_score -end - - - """ LargestGradient <: AbstractBranchStrategy diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index f8cf61d13..1562af975 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -36,10 +36,6 @@ function Bonobo.optimize!( lb, ub = Bonobo.evaluate_node!(tree, node) # if the problem was infeasible we simply close the node and continue if isnan(lb) && isnan(ub) - @debug "\n node closed without upd\n" - if isa(tree.options.branch_strategy, Boscia.HIERARCHY_PSEUDO_COST) - tree.options.branch_strategy.infeas_tracker[node.branched_on, 1] += 1 - end Bonobo.close_node!(tree, node) callback(tree, node; node_infeasible=true) continue From 85f22eba477f8e5b3af2d4c5a4b70088b7d9897c Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 31 Oct 2024 16:28:54 +0100 Subject: [PATCH 52/56] added best minimum decision function for pseudocost strategies --- src/branching_strategies.jl | 41 ++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 1537d15ae..4a3419a71 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -384,6 +384,13 @@ function pseudocost_decision( branching.pseudos, values ) + elseif branching.decision_function == "minimum" + return best_minimum_decision( + branching_candidates, + branching.μ, + branching.pseudos, + values + ) end end """ @@ -520,6 +527,38 @@ function weighted_sum_decision( return argmax(sparsevec(branching_candidates, branching_scores)) end + +""" +function best_minimum_decision( + branching_candidates::Vector{Int}, + μ::Float64, + pseudos::SparseMatrixCSC{Float64, Int64}, + values::Vector{Float64} +) +\nDescription: +\nMakes decision based on highest minimum of pseudocosts +for branching candidates +""" +function best_minimum_decision( + branching_candidates::Vector{Int}, + μ::Float64, + pseudos::SparseMatrixCSC{Float64, Int64}, + values::Vector{Float64} +) + branching_scores = map( + idx-> minimum( + unit_cost_pseudo_tuple( + pseudos[idx, 2], + pseudos[idx, 1], + values[idx] + ), + μ + ), + branching_candidates) + + # return candidate with highest minimum + return argmax(sparsevec(branching_candidates, branching_scores)) +end """ function product_decision( branching_candidates::Vector{Int}, @@ -529,7 +568,7 @@ function product_decision( ) \nDescription: \nMakes decision based on highest μ_product of pseudocosts -for branching candidate +for branching candidates """ function product_decision( branching_candidates::Vector{Int}, From b58b3b6b3b296cb81a30af7558c9c0e22d0dfcdd Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 13 Nov 2024 14:34:04 +0100 Subject: [PATCH 53/56] removed import of package at wrong place --- src/branching_strategies.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 4a3419a71..91b25ed05 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -1,4 +1,4 @@ -using SparseArrays + mutable struct PSEUDO_COST <: Bonobo.AbstractBranchStrategy iterations_until_stable::Int From 9591fe5804c490178dc03259a012cef8531cb411 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 13 Nov 2024 15:14:17 +0100 Subject: [PATCH 54/56] added minimum pseudocost for hierarchy branching as an option --- src/branching_strategies.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 91b25ed05..2ae8e6811 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -253,6 +253,16 @@ function pseudo_selection( branching.μ ), candidates) + elseif branching.decision_function == "minimum" + branching_scores = map( + idx-> minimum( + unit_cost_pseudo_tuple( + branching.pseudos[idx, 2], + branching.pseudos[idx, 1], + values[idx] + ) + ), + candidates) end #pseudo_cutoff = (mean(branching_scores) + maximum(branching_scores))/2 pseudo_cutoff = 3/4 * maximum(branching_scores) + 1/4 * mean(branching_scores) From 511015e1b1dfc1d3a740e446ee61e100d4ae2d75 Mon Sep 17 00:00:00 2001 From: Leon Date: Fri, 6 Dec 2024 17:46:11 +0100 Subject: [PATCH 55/56] fixed bug for gradient based branching strategies --- src/branching_strategies.jl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 2ae8e6811..3a26c284e 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -293,12 +293,12 @@ function largest_most_infeasible_gradient_decision( ) nabla = similar(values) x_new = copy(values) - gradient_at_values = tree.root.problem.g(nabla,x_new) + tree.root.problem.g(nabla,x_new) max_score = 0.0 best_idx = -1 for i in branching_candidates value = values[i] - value = abs(value - round(value)) * abs(gradient_at_values[i]) + value = abs(value - round(value)) * abs(nabla[i]) if value >= max_score best_idx = i max_score = value @@ -351,11 +351,12 @@ function largest_gradient_decision( values::Vector{Float64} ) nabla = similar(values) - gradient_at_values = tree.root.problem.g(nabla, nabla) + x_new = copy(values) + tree.root.problem.g(nabla,x_new) best_idx = -1 max_gradient = 0.0 for idx in branching_candidates - if abs(gradient_at_values[idx]) >= max_gradient + if abs(nabla[idx]) >= max_gradient best_idx = idx end end @@ -684,14 +685,15 @@ function Bonobo.get_branching_variable( ) values = Bonobo.get_relaxed_values(tree, node) nabla = similar(values) - gradient_at_values = tree.root.problem.g(nabla, nabla) + x_new = copy(values) + tree.root.problem.g(nabla,x_new) best_idx = -1 max_gradient = 0.0 for i in tree.branching_indices value = values[i] # check if variable is branching candidate if !Bonobo.is_approx_feasible(tree, value) - if abs(gradient_at_values[i]) >= max_gradient + if abs(nabla[i]) >= max_gradient best_idx = i end end @@ -727,13 +729,14 @@ function Bonobo.get_branching_variable( values = Bonobo.get_relaxed_values(tree, node) best_idx = -1 nabla = similar(values) - gradient_at_values = tree.root.problem.g(nabla,nabla) + x_new = copy(values) + tree.root.problem.g(nabla,x_new) max_score = 0.0 for i in tree.branching_indices value = values[i] if !Bonobo.is_approx_feasible(tree, value) value = abs(value - round(value)) - value *= abs(gradient_at_values[i]) + value *= abs(nabla[i]) if value >= max_score best_idx = i max_score = value From 07b02d9bb2b40abe547760f325867a744d832e7c Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 11 Dec 2024 14:37:19 +0100 Subject: [PATCH 56/56] fixed a problem with minimum decision function for pseudocost strats --- src/branching_strategies.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/branching_strategies.jl b/src/branching_strategies.jl index 3a26c284e..cf5a9f5e2 100644 --- a/src/branching_strategies.jl +++ b/src/branching_strategies.jl @@ -562,8 +562,7 @@ function best_minimum_decision( pseudos[idx, 2], pseudos[idx, 1], values[idx] - ), - μ + ) ), branching_candidates)

j-m{Y~? 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