Skip to content

Commit

Permalink
Merge pull request #5 from ZIB-IOL/spanning_and_matching_lmo
Browse files Browse the repository at this point in the history
Matching and Spanning Tree LMO
  • Loading branch information
matbesancon authored Jul 10, 2024
2 parents cffcff3 + 5b8c6c4 commit b0e1b18
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
GraphsFlows = "06909019-6f44-4949-96fc-b9d9aaa02889"
GraphsMatching = "c3af3a8c-b79e-4b01-bf44-c718d7e0e0d6"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
FrankWolfe = "f55ce6ea-fdc5-4628-88c5-0087fe54bd30"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[compat]
Graphs = "1"
Expand Down
11 changes: 10 additions & 1 deletion src/CombinatorialLinearOracles.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
module CombinatorialLinearOracles

# Write your package code here.
import FrankWolfe
using Graphs
using SparseArrays
using GraphsMatching

include("MatchingLinearOracle.jl")
include("SpanningTreeLinearOracle.jl")




end
39 changes: 39 additions & 0 deletions src/MatchingLinearOracle.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""
MatchingLMO{G}(g::Graphs)
Return a vector v corresponding to edges(g), where if v[i] = 1,
the edge i is in the matching, and if v[i] = 0, the edge i is not in the matching.
If there is not possible perfect matching, all elements of v are set to 0.
"""
struct MatchingLMO{G} <: FrankWolfe.LinearMinimizationOracle
graph::G
end

function compute_extreme_point(
lmo::MatchingLMO,
direction::M;
v=nothing,
kwargs...,
) where {M}
N = length(direction)
v = spzeros(N)
if(nv(lmo.graph) % 2 != 0)
return v
end
iter = collect(Graphs.edges(lmo.graph))
w = Dict{typeof(iter[1]),typeof(direction[1])}()
for i in 1:N
w[iter[i]] = direction[i]
end

match = GraphsMatching.minimum_weight_perfect_matching(lmo.graph,w)
K = length(match.mate)
for i in 1:K
for j in 1:N
if(match.mate[i] == src(iter[j]) && dst(iter[j]) == i)
v[j] = 1
end
end
end
return v
end
37 changes: 37 additions & 0 deletions src/SpanningTreeLinearOracle.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
SpanningTreeLMO{G}(g::Graphs)
Return a vector v corresponding to edges(g), where if v[i] = 1,
the edge i is in the minimum spanning tree, and if v[i] = 0,
the edge i is not in the minimum spanning tree.
"""
struct SpanningTreeLMO{G} <: FrankWolfe.LinearMinimizationOracle
graph::G
end

function compute_extreme_point(
lmo::SpanningTreeLMO,
direction::M;
v=nothing,
kwargs...,
) where {M}
N = length(direction)
iter = collect(Graphs.edges(lmo.graph))
distmx = spzeros(N,N)
for idx in 1:N
if(direction[idx] > 0)
distmx[src(iter[idx]),dst(iter[idx])] = direction[idx]
distmx[dst(iter[idx]),src(iter[idx])] = direction[idx]
end
end
span = Graphs.kruskal_mst(lmo.graph,distmx)
v = spzeros(N)
for edge in span
for i in 1:N
if(src(edge) == src(iter[i]) && dst(edge) == dst(iter[i]))
v[i] = 1
end
end
end
return v
end
47 changes: 44 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,47 @@
using CombinatorialLinearOracles
using .CombinatorialLinearOracles
using Test
using Random
using Graphs

@testset "CombinatorialLinearOracles.jl" begin
# Write your tests here.
@testset "Matching LMO" begin
N = Int(1e3)
Random.seed!(4321)
g = Graphs.complete_graph(N)
iter = collect(Graphs.edges(g))
M = length(iter)
direction = randn(M)
lmo = CombinatorialLinearOracles.MatchingLMO(g)
v = CombinatorialLinearOracles.compute_extreme_point(lmo,direction)
tab = zeros(M)
is_matching = true
for i in 1:M
if(v[i] == 1)
is_matching = (tab[src(iter[i])] == 0 && tab[dst(iter[i])] == 0)
if(!is_matching)
break
end
tab[src(iter[i])] = 1
tab[dst(iter[i])] = 1
end
end
@test is_matching == true
end

@testset "SpanningTreeLMO" begin
N = 500
Random.seed!(1645)
g = Graphs.complete_graph(N)
iter = collect(Graphs.edges(g))
M = length(iter)
direction = randn(M)
lmo = CombinatorialLinearOracles.SpanningTreeLMO(g)
v = CombinatorialLinearOracles.compute_extreme_point(lmo,direction)
tree = Array{Edge}(undef,(0,))
for i in 1:M
if(v[i] == 1)
push!(tree,iter[i])
end
end
@test Graphs.is_tree(SimpleGraphFromIterator(tree)) == true
end

0 comments on commit b0e1b18

Please sign in to comment.