@@ -16,7 +16,7 @@
Loading
16 16
  # Build the optimisation model behind solve_linear.
17 17
  solver.model = Model(solver.solver)
18 18
  indices = collect((i, j) for i in 1:n_arms, j in 1:n_arms)
19 -
  solver.x = @variable(solver.model, [indices], lower_bound=0, upper_bound=1)
19 +
  solver.x = @variable(solver.model, [indices], binary=true)
20 20
21 21
  for i in 1:n_arms # Left nodes.
22 22
    @constraint(solver.model, sum(solver.x[(i, j)] for j in 1:n_arms) <= 1)

@@ -311,8 +311,9 @@
Loading
311 311
  # This is based on http://people.idsia.ch/~grandoni/Pubblicazioni/BBGS08ipco.pdf, Theorem 1.
312 312
313 313
  # If there are too few vertices, not much to do. The smallest side of the bipartite graph must have at least 4 vertices,
314 -
  # so that 4 of them can be fixed. (Should rather perform an exhaustive exploration.)
314 +
  # so that 4 of them can be fixed.
315 315
  if i.matching.n_left <= 4 || i.matching.n_right <= 4
316 +
    # TODO: Should rather perform an exhaustive exploration.
316 317
    return matching_hungarian_budgeted_lagrangian_refinement(i; kwargs...)
317 318
  end
318 319
@@ -340,13 +341,17 @@
Loading
340 341
          # Filter out the edges that have a higher value than any of these two edges. Give a very large reward to them both.
341 342
          cutoff = min(i.matching.reward[e1], i.matching.reward[e2], i.matching.reward[e3], i.matching.reward[e4])
342 343
          reward = copy(i.matching.reward)
343 -
          filter!(kv -> kv[2] < cutoff, reward)
344 -
          filter!(kv -> _edge_any_end_match(kv[1], e1), reward)
345 -
          filter!(kv -> _edge_any_end_match(kv[1], e2), reward)
346 -
          filter!(kv -> _edge_any_end_match(kv[1], e3), reward)
347 -
          filter!(kv -> _edge_any_end_match(kv[1], e4), reward)
344 +
          filter!(kv -> kv[2] <= cutoff, reward)
345 +
          filter!(kv -> ! _edge_any_end_match(kv[1], e1), reward)
346 +
          filter!(kv -> ! _edge_any_end_match(kv[1], e2), reward)
347 +
          filter!(kv -> ! _edge_any_end_match(kv[1], e3), reward)
348 +
          filter!(kv -> ! _edge_any_end_match(kv[1], e4), reward)
348 349
          reward[e1] = reward[e2] = reward[e3] = reward[e4] = prevfloat(Inf)
349 350
351 +
          if length(keys(reward)) == 4 # Nothing left? Skip.
352 +
            continue
353 +
          end
354 +
350 355
          graph = SimpleGraph(nv(i.matching.graph))
351 356
          for e in keys(reward)
352 357
            add_edge!(graph, e)

@@ -1,4 +1,4 @@
Loading
1 -
struct BudgetedLongestPathInstance{T}
1 +
struct BudgetedElementaryPathInstance{T}
2 2
  graph::AbstractGraph{T}
3 3
  rewards::Dict{Edge{T}, Float64}
4 4
  weights::Dict{Edge{T}, Int}
@@ -6,12 +6,11 @@
Loading
6 6
  dst::T
7 7
8 8
  budget::Int # weights * solution >= budget
9 -
  max_weight::Int
10 9
11 -
  function BudgetedLongestPathInstance(graph::AbstractGraph{T}, rewards::Dict{Edge{T}, Float64},
12 -
                                       weights::Dict{Edge{T}, Int}, src::T, dst::T;
13 -
                                       budget::Union{Nothing, Int}=nothing,
14 -
                                       max_weight::Union{Nothing, Int}=nothing) where T
10 +
  function BudgetedElementaryPathInstance(graph::AbstractGraph{T}, rewards::Dict{Edge{T}, Float64},
11 +
                                          weights::Dict{Edge{T}, Int}, src::T, dst::T;
12 +
                                          budget::Union{Nothing, Int}=nothing,
13 +
                                          max_weight::Union{Nothing, Int}=nothing) where T
15 14
    # Error checking.
16 15
    if src == dst
17 16
      error("Source node is the same as destination node.")
@@ -30,7 +29,7 @@
Loading
30 29
    end
31 30
32 31
    # Complete the optional parameters.
33 -
    if isnothing(max_weight)
32 +
    if isnothing(max_weight) # Not useful to store, it is just used to compute the max budget if it is not given.
34 33
      max_weight = maximum(collect(values(weights)))
35 34
    end
36 35
@@ -40,41 +39,50 @@
Loading
40 39
    end
41 40
42 41
    # Return a new instance.
43 -
    new{T}(graph, rewards, weights, src, dst, budget, max_weight)
42 +
    new{T}(graph, rewards, weights, src, dst, budget)
44 43
  end
45 44
end
46 45
47 -
graph(i::BudgetedLongestPathInstance{T}) where T = i.graph
48 -
rewards(i::BudgetedLongestPathInstance{T}) where T = i.rewards
49 -
weights(i::BudgetedLongestPathInstance{T}) where T = i.weights
50 -
src(i::BudgetedLongestPathInstance{T}) where T = i.src
51 -
dst(i::BudgetedLongestPathInstance{T}) where T = i.dst
52 -
budget(i::BudgetedLongestPathInstance{T}) where T = i.budget
53 -
max_weight(i::BudgetedLongestPathInstance{T}) where T = i.max_weight
46 +
graph(i::BudgetedElementaryPathInstance{T}) where T = i.graph
47 +
rewards(i::BudgetedElementaryPathInstance{T}) where T = i.rewards
48 +
weights(i::BudgetedElementaryPathInstance{T}) where T = i.weights
49 +
src(i::BudgetedElementaryPathInstance{T}) where T = i.src
50 +
dst(i::BudgetedElementaryPathInstance{T}) where T = i.dst
51 +
budget(i::BudgetedElementaryPathInstance{T}) where T = i.budget
54 52
55 -
dimension(i::BudgetedLongestPathInstance{T}) where T = ne(graph(i))
56 -
reward(i::BudgetedLongestPathInstance{T}, u::T, v::T) where T = rewards(i)[Edge(u, v)]
57 -
weight(i::BudgetedLongestPathInstance{T}, u::T, v::T) where T = weights(i)[Edge(u, v)]
53 +
# dimension(i::BudgetedElementaryPathInstance{T}) where T = ne(graph(i))
54 +
reward(i::BudgetedElementaryPathInstance{T}, u::T, v::T) where T = rewards(i)[Edge(u, v)]
55 +
weight(i::BudgetedElementaryPathInstance{T}, u::T, v::T) where T = weights(i)[Edge(u, v)]
58 56
59 -
struct BudgetedLongestPathSolution{T}
60 -
  instance::BudgetedLongestPathInstance{T}
57 +
struct BudgetedElementaryPathSolution{T}
58 +
  instance::BudgetedElementaryPathInstance{T}
61 59
  path::Vector{Edge{T}}
62 60
  states::Dict{Tuple{T, Int}, Float64}
63 61
  solutions::Dict{Tuple{T, Int}, Vector{Edge{T}}}
64 62
end
65 63
66 -
function paths_all_budgets(s::BudgetedLongestPathSolution{T}, max_budget::Int) where T
64 +
function paths_all_budgets(s::BudgetedElementaryPathSolution{T}, max_budget::Int) where T
65 +
  if max_budget > budget(s.instance)
66 +
    @warn "The asked maximum budget $max_budget is higher than the instance budget $(budget(s.instance)). Therefore, some values have not been computed and are unavailable."
67 +
  end
68 +
69 +
  mb = min(max_budget, budget(s.instance))
67 70
  return Dict{Int, Vector{Edge{T}}}(
68 -
    budget => s.solutions[s.instance.dst, budget] for budget in 0:max_budget)
71 +
    budget => s.solutions[s.instance.dst, budget] for budget in 0:mb)
69 72
end
70 73
71 -
function paths_all_budgets_as_tuples(s::BudgetedLongestPathSolution{T}, max_budget::Int) where T
74 +
function paths_all_budgets_as_tuples(s::BudgetedElementaryPathSolution{T}, max_budget::Int) where T
75 +
  if max_budget > budget(s.instance)
76 +
    @warn "The asked maximum budget $max_budget is higher than the instance budget $(budget(s.instance)). Therefore, some values have not been computed and are unavailable."
77 +
  end
78 +
79 +
  mb = min(max_budget, budget(s.instance))
72 80
  return Dict{Int, Vector{Tuple{T, T}}}(
73 81
    budget => [(src(e), dst(e)) for e in s.solutions[s.instance.dst, budget]]
74 -
    for budget in 0:max_budget)
82 +
    for budget in 0:mb)
75 83
end
76 84
77 -
function budgeted_lp_dp(i::BudgetedLongestPathInstance{T}) where T
85 +
function budgeted_lp_dp(i::BudgetedElementaryPathInstance{T}) where T
78 86
  V = Dict{Tuple{T, Int}, Float64}()
79 87
  S = Dict{Tuple{T, Int}, Vector{Edge{T}}}()
80 88
@@ -98,7 +106,7 @@
Loading
98 106
99 107
  # Dynamic part.
100 108
  for β in 1:budget(i)
101 -
    # Loop needed when at least a weight is equal to zero. TODO: remove it when all weights are nonzero? 
109 +
    # Loop needed when at least a weight is equal to zero. TODO: remove it when all weights are nonzero?
102 110
    while true
103 111
      changed = false
104 112
@@ -143,5 +151,5 @@
Loading
143 151
    end
144 152
  end
145 153
146 -
  return BudgetedLongestPathSolution(i, S[dst(i), budget(i)], V, S)
154 +
  return BudgetedElementaryPathSolution(i, S[dst(i), budget(i)], V, S)
147 155
end

@@ -30,7 +30,7 @@
Loading
30 30
                               reward::Dict{Tuple{Int, Int}, Float64},
31 31
                               weights::Dict{Tuple{Int, Int}, Int},
32 32
                               budget::Int)
33 -
  i = BudgetedLongestPathInstance(solver.graph,
33 +
  i = BudgetedElementaryPathInstance(solver.graph,
34 34
    _tuple_dict_to_edge_dict(reward), _tuple_dict_to_edge_dict(weights),
35 35
    solver.source, solver.destination, budget=budget)
36 36
  s = budgeted_lp_dp(i).path
@@ -41,7 +41,7 @@
Loading
41 41
                                   reward::Dict{Tuple{Int, Int}, Float64},
42 42
                                   weights::Dict{Tuple{Int, Int}, Int},
43 43
                                   max_budget::Int)
44 -
  i = BudgetedLongestPathInstance(solver.graph,
44 +
  i = BudgetedElementaryPathInstance(solver.graph,
45 45
    _tuple_dict_to_edge_dict(reward), _tuple_dict_to_edge_dict(weights),
46 46
    solver.source, solver.destination, budget=max_budget)
47 47
  return paths_all_budgets_as_tuples(budgeted_lp_dp(i), max_budget)

@@ -26,7 +26,7 @@
Loading
26 26
         MSetInstance, MSetSolution, dimension, m, value, values, msets_greedy, msets_dp, msets_lp,
27 27
         BudgetedMSetInstance, BudgetedMSetSolution, weight, weights, budget, max_weight, items, items_all_budgets, budgeted_msets_dp, budgeted_msets_lp, budgeted_msets_lp_select, budgeted_msets_lp_all,
28 28
         ElementaryPathInstance, ElementaryPathSolution, graph, costs, src, dst, cost, lp_dp,
29 -
         BudgetedLongestPathInstance, BudgetedLongestPathSolution, rewards, reward, budgeted_lp_dp,
29 +
         BudgetedElementaryPathInstance, BudgetedElementaryPathSolution, rewards, reward, budgeted_lp_dp,
30 30
         SpanningTreeInstance, SpanningTreeSolution, st_prim,
31 31
         BudgetedSpanningTreeInstance, BudgetedSpanningTreeSolution, BudgetedSpanningTreeLagrangianSolution, SimpleBudgetedSpanningTreeSolution, _budgeted_spanning_tree_compute_value, _budgeted_spanning_tree_compute_weight, st_prim_budgeted_lagrangian, st_prim_budgeted_lagrangian_search, _solution_symmetric_difference, _solution_symmetric_difference_size, st_prim_budgeted_lagrangian_refinement, st_prim_budgeted_lagrangian_approx_half,
32 32
         BipartiteMatchingInstance, BipartiteMatchingSolution, matching_hungarian, BudgetedBipartiteMatchingInstance, BudgetedBipartiteMatchingSolution, BudgetedBipartiteMatchingLagrangianSolution, SimpleBudgetedBipartiteMatchingSolution, matching_hungarian_budgeted_lagrangian, matching_hungarian_budgeted_lagrangian_search, matching_hungarian_budgeted_lagrangian_refinement, matching_hungarian_budgeted_lagrangian_approx_half
@@ -215,8 +215,8 @@
Loading
215 215
216 216
  ## Combinatorial algorithms. TODO: put this in another package.
217 217
  include("algos/helpers.jl")
218 -
  include("algos/lp.jl")
219 -
  include("algos/lp_budgeted.jl")
218 +
  include("algos/ep.jl")
219 +
  include("algos/ep_budgeted.jl")
220 220
  include("algos/matching.jl")
221 221
  include("algos/matching_budgeted.jl")
222 222
  include("algos/msets.jl")
223 223
imilarity index 100%
224 224
ename from src/algos/lp.jl
225 225
ename to src/algos/ep.jl
226 226
imilarity index 60%
227 227
ename from src/algos/lp_budgeted.jl
228 228
ename to src/algos/ep_budgeted.jl
Files Coverage
src 67.42%
Project Totals (35 files) 67.42%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading