@@ -21,34 +21,40 @@ Returns MatchingResult containing:
2121"""
2222function maximum_weight_matching end
2323
24- function maximum_weight_matching (g:: Graph ,
25- optimizer,
26- w:: AbstractMatrix{U} = default_weights (g)) where {U <: Real }
24+ function maximum_weight_matching (
25+ g:: Graph ,
26+ optimizer,
27+ w:: AbstractMatrix{U} = default_weights (g),
28+ ) where {U<: Real }
2729
2830 model = Model (optimizer)
2931 n = nv (g)
3032 edge_list = collect (edges (g))
3133
3234 # put the edge weights in w in the right order to be compatible with edge_list
33- for j in 1 : n
34- for i in 1 : n
35- if i > j && w[i,j] > zero (U) && w[j,i] < w[i,j]
36- w[j,i] = w[i,j]
35+ for j = 1 : n
36+ for i = 1 : n
37+ if i > j && w[i, j] > zero (U) && w[j, i] < w[i, j]
38+ w[j, i] = w[i, j]
39+ end
40+ if Edge (i, j) ∉ edge_list
41+ w[i, j] = zero (U)
42+ end
3743 end
38- if Edge (i,j) ∉ edge_list
39- w[i,j] = zero (U)
40- end
41- end
4244 end
4345
4446 if is_bipartite (g)
45- @variable (model, x[edge_list] >= 0 ) # no need to enforce integrality
47+ @variable (model, x[edge_list] >= 0 ) # no need to enforce integrality
4648 else
47- @variable (model, x[edge_list] >= 0 , Int) # requires MIP solver
49+ @variable (model, x[edge_list] >= 0 , Int) # requires MIP solver
4850 end
49- @objective (model, Max, sum (x[e]* w[src (e),dst (e)] for e in edge_list))
51+ @objective (model, Max, sum (x[e] * w[src (e), dst (e)] for e in edge_list))
5052
51- @constraint (model, c1[i= 1 : n], sum (x[Edge (minmax (i,j))] for j in neighbors (g,i)) <= 1 )
53+ @constraint (
54+ model,
55+ c1[i = 1 : n],
56+ sum (x[Edge (minmax (i, j))] for j in neighbors (g, i)) <= 1
57+ )
5258 optimize! (model)
5359 status = JuMP. termination_status (model)
5460 status != MOI. OPTIMAL && error (" JuMP solver failed to find optimal solution." )
@@ -58,22 +64,69 @@ function maximum_weight_matching(g::Graph,
5864end
5965
6066""" Returns an array of mates from a dictionary that maps edges to {0,1} """
61- function dict_to_arr (n:: Int64 , solution:: JuMP.Containers.DenseAxisArray{U,1,Tuple{Array{E,1}}} , edge_list:: AbstractVector{E} ) where {U<: Real , E<: Edge }
62- mate = fill (- 1 ,n)
63- for e in edge_list
64- if solution[e] >= 1 - 1e-5 # Some tolerance to numerical approximations by the solver.
65- mate[src (e)] = dst (e)
66- mate[dst (e)] = src (e)
67+ function dict_to_arr (
68+ n:: Int64 ,
69+ solution:: JuMP.Containers.DenseAxisArray{U,1,Tuple{Array{E,1}}} ,
70+ edge_list:: AbstractVector{E} ,
71+ ) where {U<: Real ,E<: Edge }
72+ mate = fill (- 1 , n)
73+ for e in edge_list
74+ if solution[e] >= 1 - 1e-5 # Some tolerance to numerical approximations by the solver.
75+ mate[src (e)] = dst (e)
76+ mate[dst (e)] = src (e)
77+ end
6778 end
68- end
69- return mate
79+ return mate
7080end
7181
7282
7383function default_weights (g:: G ) where {G<: AbstractGraph }
74- m = spzeros (nv (g),nv (g))
75- for e in edges (g)
76- m[src (e),dst (e)] = 1
77- end
78- return m
84+ m = spzeros (nv (g), nv (g))
85+ for e in edges (g)
86+ m[src (e), dst (e)] = 1
87+ end
88+ return m
89+ end
90+
91+ """
92+ maximum_weight_matching_reduction(g::Graph, w::Matrix{Real}) -> Array{Edge}
93+
94+ Given a graph `g` and an edgemap `w` containing weights associated to edges,
95+ returns a matching with the maximum total weight.
96+ `w` is an adjacent matrix that maps edges i => j to weights.
97+ If no weight parameter is given, all edges will be considered to have weight 1
98+
99+ This algorithm uses a reduction based on the minimum_weight_perfect_matching function
100+ to find the maximum weight matching (see https://homepages.cwi.nl/~schaefer/ftp/pdf/masters-thesis.pdf section 1.5.1).
101+
102+ Return an array of edges contained in the matching.
103+ """
104+ function maximum_weight_matching_reduction (
105+ g:: Graph ,
106+ w:: AbstractMatrix{U} = default_weights (g),
107+ ) where {U<: Real }
108+
109+ h = deepcopy (g)
110+ # collect needed since we modify the edges later
111+ edge_iter = collect (edges (h))
112+ l = nv (h)
113+ add_vertices! (h, l)
114+ weights = Dict {edgetype(g), eltype(w)} ()
115+ for edge in edge_iter
116+ add_edge! (h, src (edge) + l, dst (edge) + l)
117+ weights[edge] = - w[src (edge), dst (edge)]
118+ weights[Edge (dst (edge), src (edge))] = - w[src (edge), dst (edge)]
119+ weights[Edge (src (edge) + l, dst (edge) + l)] = - w[src (edge), dst (edge)]
120+ weights[Edge (dst (edge) + l, src (edge) + l)] = - w[src (edge), dst (edge)]
121+ end
122+ for i = 1 : l
123+ add_edge! (g, i, i + l)
124+ weights[Edge (i, i + l)] = 0
125+ end
126+
127+ match = minimum_weight_perfect_matching (h, weights)
128+
129+ result = [Edge (i, match. mate[i]) for i in 1 : l if match. mate[i] <= l && match. mate[i] > 0 ]
130+
131+ return result
79132end
0 commit comments