Skip to content

Commit 5e0fa92

Browse files
committed
add LEMONWPMPAlgorithm and make it default instead of the BlossomV
1 parent 2ecb87e commit 5e0fa92

File tree

4 files changed

+50
-16
lines changed

4 files changed

+50
-16
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
name = "GraphsMatching"
22
uuid = "c3af3a8c-b79e-4b01-bf44-c718d7e0e0d6"
33
authors = ["JuliaGraphs"]
4-
version = "0.2.0"
4+
version = "0.2.1"
55

66
[deps]
77
BlossomV = "6c721016-9dae-5d90-abf6-67daaccb2332"
88
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
99
Hungarian = "e91730f6-4275-51fb-a7a0-7064cfbd3b39"
1010
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
1111
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
12+
LEMONGraphs = "14b1564f-c77f-4800-9e89-efd961faef7c"
1213
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
1314
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1415

@@ -17,6 +18,7 @@ BlossomV = "0.4"
1718
Graphs = "1.4, 1.7"
1819
Hungarian = "0.4, 0.6, 0.7"
1920
JuMP = "1"
21+
LEMONGraphs = "0.1.0"
2022
MathOptInterface = "1"
2123
julia = "1"
2224

src/GraphsMatching.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@ using SparseArrays: spzeros
77
using JuMP
88
using MathOptInterface
99
const MOI = MathOptInterface
10-
import BlossomV # 'using BlossomV' leads to naming conflicts with JuMP
10+
import BlossomV
11+
import LEMONGraphs
1112
using Hungarian
1213

13-
export MatchingResult, maximum_weight_matching, maximum_weight_matching_reduction, maximum_weight_maximal_matching, minimum_weight_perfect_matching, HungarianAlgorithm, LPAlgorithm
14+
export MatchingResult,
15+
maximum_weight_matching,
16+
maximum_weight_matching_reduction,
17+
maximum_weight_maximal_matching,
18+
minimum_weight_perfect_matching,
19+
HungarianAlgorithm,
20+
LPAlgorithm,
21+
BlossomVAlgorithm,
22+
LEMONMWPMAlgorithm
1423

1524
"""
1625
struct MatchingResult{U}

src/blossomv.jl

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ Edges in `g` not present in `w` will not be considered for the matching.
1313
You can use the `algorithm` argument to specify the algorithm to use.
1414
1515
A `cutoff` argument can be given, to reduce the computational time by
16-
excluding edges with weights higher than the cutoff.
16+
excluding edges with weights higher than the cutoff (effective only for some algorithms,
17+
not for the default `LEMONMWPMAlgorithm`).
1718
1819
When the weights are non-integer types, the keyword argument `tmaxscale` can be used to
1920
scale the weights to integer values.
@@ -56,18 +57,27 @@ If BlossomV.jl does not work on your system,
5657
consider using the LEMONGraphs.jl algorithm instead (the default algorithm),
5758
which we distribute precompiled on all platforms.
5859
59-
See also: [`minimum_weight_perfect_matching`](@ref)
60+
See also: [`minimum_weight_perfect_matching`](@ref), [`LEMONMWPMAlgorithm`](@ref)
6061
"""
6162
struct BlossomVAlgorithm <: AbstractMinimumWeightPerfectMatchingAlgorithm end
6263

64+
"""
65+
LEMONMWPMAlgorithm()
66+
67+
Use the LEMON C++ implementation of minimum weight perfect matching.
68+
69+
See also: [`minimum_weight_perfect_matching`](@ref), [`BlossomVAlgorithm`](@ref)
70+
"""
71+
struct LEMONMWPMAlgorithm <: AbstractMinimumWeightPerfectMatchingAlgorithm end
72+
6373
function minimum_weight_perfect_matching(
6474
g::Graph, w::Dict{E,U}
6575
) where {U<:Integer,E<:Edge}
66-
return minimum_weight_perfect_matching(g, w, BlossomVAlgorithm())
76+
return minimum_weight_perfect_matching(g, w, LEMONMWPMAlgorithm())
6777
end
6878

6979
function minimum_weight_perfect_matching(
70-
g::Graph, w::Dict{E,U}, cutoff, algorithm::AbstractMinimumWeightPerfectMatchingAlgorithm=BlossomVAlgorithm(); kws...
80+
g::Graph, w::Dict{E,U}, cutoff, algorithm::AbstractMinimumWeightPerfectMatchingAlgorithm=LEMONMWPMAlgorithm(); kws...
7181
) where {U<:Real,E<:Edge}
7282
wnew = Dict{E,U}()
7383
for (e, c) in w
@@ -79,7 +89,7 @@ function minimum_weight_perfect_matching(
7989
end
8090

8191
function minimum_weight_perfect_matching(
82-
g::Graph, w::Dict{E,U}, algorithm::AbstractMinimumWeightPerfectMatchingAlgorithm=BlossomVAlgorithm(); tmaxscale=10.0
92+
g::Graph, w::Dict{E,U}, algorithm::AbstractMinimumWeightPerfectMatchingAlgorithm=LEMONMWPMAlgorithm(); tmaxscale=10.0
8393
) where {U<:AbstractFloat,E<:Edge}
8494
wnew = Dict{E,Int32}()
8595
cmax = maximum(values(w))
@@ -95,7 +105,7 @@ function minimum_weight_perfect_matching(
95105
for i in 1:nv(g)
96106
j = match.mate[i]
97107
if j > i
98-
weight += w[E(i, j)]
108+
weight += get(w, E(i, j), zero(U))
99109
end
100110
end
101111
return MatchingResult(weight, match.mate)
@@ -119,3 +129,10 @@ function minimum_weight_perfect_matching(g::Graph, w::Dict{E,U}, ::BlossomVAlgor
119129
end
120130
return MatchingResult(totweight, mate)
121131
end
132+
133+
function minimum_weight_perfect_matching(g::Graph, w::Dict{E,U}, ::LEMONMWPMAlgorithm) where {U<:Integer,E<:Edge}
134+
max = 2*abs(maximum(values(w)))
135+
weights = [-get(w, e, max) for e in edges(g)]
136+
totweight, mate = LEMONGraphs.maxweightedperfectmatching(g, weights)
137+
return MatchingResult(-totweight, mate)
138+
end

test/runtests.jl

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,15 @@ using LinearAlgebra: I
259259

260260

261261
@testset "minimum_weight_perfect_matching" begin
262+
for algorithm in [
263+
BlossomVAlgorithm(),
264+
LEMONMWPMAlgorithm(),
265+
]
262266

263267
w = Dict(Edge(1, 2) => 500)
264268
g = Graph(2)
265269
add_edge!(g, 1, 2)
266-
match = minimum_weight_perfect_matching(g, w)
270+
match = minimum_weight_perfect_matching(g, w, algorithm)
267271
@test match.mate[1] == 2
268272

269273

@@ -276,7 +280,7 @@ using LinearAlgebra: I
276280
)
277281

278282
g = complete_graph(4)
279-
match = minimum_weight_perfect_matching(g, w)
283+
match = minimum_weight_perfect_matching(g, w, algorithm)
280284
@test match.mate[1] == 2
281285
@test match.mate[2] == 1
282286
@test match.mate[3] == 4
@@ -291,7 +295,7 @@ using LinearAlgebra: I
291295
Edge(2, 4) => 1000,
292296
)
293297
g = complete_graph(4)
294-
match = minimum_weight_perfect_matching(g, w)
298+
match = minimum_weight_perfect_matching(g, w, algorithm)
295299
@test match.mate[1] == 3
296300
@test match.mate[2] == 4
297301
@test match.mate[3] == 1
@@ -305,7 +309,7 @@ using LinearAlgebra: I
305309
w[Edge(2, 3)] = -11
306310
w[Edge(2, 4)] = -1
307311

308-
match = minimum_weight_perfect_matching(g, w)
312+
match = minimum_weight_perfect_matching(g, w, algorithm)
309313
@test match.mate[1] == 4
310314
@test match.mate[4] == 1
311315
@test match.mate[2] == 3
@@ -321,7 +325,7 @@ using LinearAlgebra: I
321325
w[Edge(2, 4)] = 2
322326
w[Edge(1, 2)] = 100
323327

324-
match = minimum_weight_perfect_matching(g, w, 50)
328+
match = minimum_weight_perfect_matching(g, w, 50, algorithm)
325329
@test match.mate[1] == 4
326330
@test match.mate[4] == 1
327331
@test match.mate[2] == 3
@@ -338,9 +342,11 @@ using LinearAlgebra: I
338342
g = Graph([Edge(1, 2)])
339343
wFloat = Dict(Edge(1, 2) => 2.0)
340344
wInt = Dict(Edge(1, 2) => 2)
341-
matchFloat = minimum_weight_perfect_matching(g, wFloat)
342-
matchInt = minimum_weight_perfect_matching(g, wInt)
345+
matchFloat = minimum_weight_perfect_matching(g, wFloat, algorithm)
346+
matchInt = minimum_weight_perfect_matching(g, wInt, algorithm)
343347
@test matchFloat.mate == matchInt.mate
344348
@test matchFloat.weight == matchInt.weight
349+
350+
end
345351
end
346352
end

0 commit comments

Comments
 (0)