Skip to content
This repository was archived by the owner on Oct 22, 2021. It is now read-only.

Fixes for julia v1.0 #12

Merged
merged 5 commits into from
Nov 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
## Documentation: http://docs.travis-ci.com/user/languages/julia/
# Documentation: http://docs.travis-ci.com/user/languages/julia/
language: julia
os:
- linux
- osx
julia:
- 0.6
- nightly
- 0.7
- 1.0
- nightly

matrix:
allow_failures:
Expand All @@ -15,12 +17,6 @@ notifications:
git:
depth: 99999999

## uncomment the following lines to allow failures on nightly julia
## (tests will run but not make your overall status red)
#matrix:
# allow_failures:
# - julia: nightly

## uncomment and modify the following lines to manually install system packages
#addons:
# apt: # apt-get for linux
Expand Down
10 changes: 5 additions & 5 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
julia 0.6
LightGraphs 0.12
JuMP 0.13
MatrixDepot
BlossomV 0.3
julia 0.7
LightGraphs 1.2
JuMP 0.18
MathProgBase 0.7
BlossomV 0.4
45 changes: 18 additions & 27 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
platform:
- x86 # 32-bit
- x64 # 64-bit

## uncomment the following lines to allow failures on nightly julia
## (tests will run but not make your overall status red)
#matrix:
# allow_failures:
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
# # Uncomment the following lines to allow failures on nightly julia
# # (tests will run but not make your overall status red)
matrix:
allow_failures:
- julia_version: nightly

branches:
only:
Expand All @@ -24,24 +20,19 @@ notifications:
on_build_status_changed: false

install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# If there's a newer build queued for the same PR, cancel this one
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." }
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile(
$env:JULIA_URL,
"C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
- ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))

build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo();
Pkg.clone(pwd(), \"LightGraphsMatching\"); Pkg.build(\"LightGraphsMatching\")"
- C:\julia\bin\julia -e "using InteractiveUtils, Pkg; versioninfo();
Pkg.clone(pwd(), \"LightGraphsMatching\"); Pkg.build(\"LightGraphsMatching\")"

test_script:
- C:\projects\julia\bin\julia -e "Pkg.test(\"LightGraphsMatching\")"
- C:\julia\bin\julia -e "using Pkg; Pkg.test(\"LightGraphsMatching\")"

# # Uncomment to support code coverage upload. Should only be enabled for packages
# # which would have coverage gaps without running on Windows
# on_success:
# - echo "%JL_CODECOV_SCRIPT%"
# - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%"
23 changes: 13 additions & 10 deletions src/LightGraphsMatching.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
__precompile__(true)
module LightGraphsMatching

using LightGraphs

using SparseArrays: spzeros

using JuMP
using MathProgBase: AbstractMathProgSolver
import BlossomV # 'using BlossomV' leads to naming conflicts with JuMP

export MatchingResult, maximum_weight_matching, maximum_weight_maximal_matching, minimum_weight_perfect_matching

"""
type MatchingResult{T}
weight::T
struct MatchingResult{U}
weight::U
mate::Vector{Int}
end

Expand All @@ -16,18 +23,14 @@ A type representing the result of a matching algorithm.
mate: `mate[i] = j` if vertex `i` is matched to vertex `j`.
`mate[i] = -1` for unmatched vertices.
"""
struct MatchingResult{T<:Real}
weight::T
struct MatchingResult{U<:Real}
weight::U
mate::Vector{Int}
end

import BlossomV
include("blossomv.jl")

using JuMP
using MathProgBase: AbstractMathProgSolver
include("lp.jl")
include("maximum_weight_matching.jl")
include("blossomv.jl")

end # module

18 changes: 9 additions & 9 deletions src/blossomv.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
minimum_weight_perfect_matching{T<:Real}(g, w::Dict{Edge,T})
minimum_weight_perfect_matching{T<:Real}(g, w::Dict{Edge,T}, cutoff)
minimum_weight_perfect_matching(g, w::Dict{Edge,Real})
minimum_weight_perfect_matching(g, w::Dict{Edge,Real}, cutoff)

Given a graph `g` and an edgemap `w` containing weights associated to edges,
returns a matching with the mimimum total weight among the ones containing
Expand All @@ -20,8 +20,8 @@ In case of error try to change the optional argument `tmaxscale` (default is `tm
"""
function minimum_weight_perfect_matching end

function minimum_weight_perfect_matching(g::Graph, w::Dict{E,T}, cutoff, kws...) where {T<:Real, E<:Edge}
wnew = Dict{E, T}()
function minimum_weight_perfect_matching(g::Graph, w::Dict{E,U}, cutoff, kws...) where {U<:Real, E<:Edge}
wnew = Dict{E, U}()
for (e, c) in w
if c <= cutoff
wnew[e] = c
Expand All @@ -30,17 +30,17 @@ function minimum_weight_perfect_matching(g::Graph, w::Dict{E,T}, cutoff, kws...)
return minimum_weight_perfect_matching(g, wnew; kws...)
end

function minimum_weight_perfect_matching(g::Graph, w::Dict{E,T}; tmaxscale=10.) where {T<:AbstractFloat, E<:Edge}
function minimum_weight_perfect_matching(g::Graph, w::Dict{E,U}; tmaxscale=10.) where {U<:AbstractFloat, E<:Edge}
wnew = Dict{E, Int32}()
cmax = maximum(values(w))
cmin = minimum(values(w))
tmax = typemax(Int32) / tmaxscale # /10 is kinda arbitrary,
# hopefully high enough to not incurr in overflow problems
# hopefully high enough to not occur in overflow problems
for (e, c) in w
wnew[e] = round(Int32, (c-cmin) / (cmax-cmin) * tmax)
end
match = minimum_weight_perfect_matching(g, wnew)
weight = T(0)
weight = zero(U)
for i=1:nv(g)
j = match.mate[i]
if j > i
Expand All @@ -50,15 +50,15 @@ function minimum_weight_perfect_matching(g::Graph, w::Dict{E,T}; tmaxscale=10.)
return MatchingResult(weight, match.mate)
end

function minimum_weight_perfect_matching(g::Graph, w::Dict{E,T}) where {T<:Integer, E<:Edge}
function minimum_weight_perfect_matching(g::Graph, w::Dict{E,U}) where {U<:Integer, E<:Edge}
m = BlossomV.Matching(nv(g))
for (e, c) in w
BlossomV.add_edge(m, src(e)-1, dst(e)-1, c)
end
BlossomV.solve(m)

mate = fill(-1, nv(g))
totweight = T(0)
totweight = zero(U)
for i=1:nv(g)
j = BlossomV.get_match(m, i-1) + 1
mate[i] = j <= 0 ? -1 : j
Expand Down
20 changes: 10 additions & 10 deletions src/lp.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
maximum_weight_maximal_matching{T<:Real}(g, w::Dict{Edge,T})
maximum_weight_maximal_matching{T<:Real}(g, w::Dict{Edge,T}, cutoff)
maximum_weight_maximal_matching(g, w::Dict{Edge,Real})
maximum_weight_maximal_matching(g, w::Dict{Edge,Real}, cutoff)

Given a bipartite graph `g` and an edgemap `w` containing weights associated to edges,
returns a matching with the maximum total weight among the ones containing the
Expand All @@ -20,17 +20,17 @@ The returned object is of type `MatchingResult`.
"""
function maximum_weight_maximal_matching end

function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real}
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{U}, cutoff::R) where {U<:Real, R<:Real}
return maximum_weight_maximal_matching(g, solver, cutoff_weights(w, cutoff))
end

function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{T}) where {T<:Real}
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{U}) where {U<:Real}
# TODO support for graphs with zero degree nodes
# TODO apply separately on each connected component
bpmap = bipartite_map(g)
length(bpmap) != nv(g) && error("Graph is not bipartite")
v1 = findin(bpmap, 1)
v2 = findin(bpmap, 2)
v1 = findall(isequal(1), bpmap)
v2 = findall(isequal(2), bpmap)
if length(v1) > length(v2)
v1, v2 = v2, v1
end
Expand Down Expand Up @@ -88,7 +88,7 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve

mate = fill(-1, nv(g))
for e in edges(g)
if w[src(e),dst(e)] > zero(T)
if w[src(e),dst(e)] > zero(U)
inmatch = convert(Bool, sol[edgemap[e]])
if inmatch
mate[src(e)] = dst(e)
Expand All @@ -103,14 +103,14 @@ end
"""
cutoff_weights copies the weight matrix with all elements below cutoff set to 0
"""
function cutoff_weights(w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real}
function cutoff_weights(w::AbstractMatrix{U}, cutoff::R) where {U<:Real, R<:Real}
wnew = copy(w)
for j in 1:size(w,2)
for i in 1:size(w,1)
if wnew[i,j] < cutoff
wnew[i,j] = zero(T)
wnew[i,j] = zero(U)
end
end
end
wnew
end
end
28 changes: 12 additions & 16 deletions src/maximum_weight_matching.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
maximum_weight_matching{T <:Real}(g::Graph, w::Dict{Edge,T} = Dict{Edge,Int64}())
maximum_weight_matching(g::Graph, w::Dict{Edge,Real} -> Dict{Edge,Int64}

Given a graph `g` and an edgemap `w` containing weights associated to edges,
returns a matching with the maximum total weight.
Expand All @@ -23,7 +23,7 @@ function maximum_weight_matching end

function maximum_weight_matching(g::Graph,
solver::AbstractMathProgSolver,
w::AbstractMatrix{T} = default_weights(g)) where {T <:Real}
w::AbstractMatrix{U} = default_weights(g)) where {U <:Real}

model = Model(solver = solver)
n = nv(g)
Expand All @@ -32,11 +32,11 @@ function maximum_weight_matching(g::Graph,
# put the edge weights in w in the right order to be compatible with edge_list
for j in 1:n
for i in 1:n
if i > j && w[i,j] > zero(T) && w[j,i] < w[i,j]
if i > j && w[i,j] > zero(U) && w[j,i] < w[i,j]
w[j,i] = w[i,j]
end
if Edge(i,j) ∉ edge_list
w[i,j] = zero(T)
w[i,j] = zero(U)
end
end
end
Expand All @@ -47,26 +47,22 @@ function maximum_weight_matching(g::Graph,
@variable(model, x[edge_list] >= 0, Int) # requires MIP solver
end
@objective(model, Max, sum(x[e]*w[src(e),dst(e)] for e in edge_list))
@constraint(model, c1[i=1:n],
sum(x[Edge(i,j)] for j=filter(l -> l > i, neighbors(g,i))) +
sum(x[Edge(j,i)] for j=filter(l -> l <= i, neighbors(g,i)))
<= 1)

@constraint(model, c1[i=1:n], sum(x[Edge(minmax(i,j))] for j in neighbors(g,i)) <= 1)
status = solve(model)
solution = getvalue(x)
cost = getobjectivevalue(model)
## TODO: add the option of returning the solve status as part of the MatchingResult type.
return MatchingResult(cost, dict_to_arr(n, solution))
return MatchingResult(cost, dict_to_arr(n, solution, edge_list))
end

""" Returns an array of mates from a dictionary that maps edges to {0,1} """
function dict_to_arr(n::Int64, solution::JuMP.JuMPArray{T,1,Tuple{Array{E,1}}}) where {T<: Real, E<: Edge}
function dict_to_arr(n::Int64, solution::JuMP.JuMPArray{U,1,Tuple{Array{E,1}}}, edge_list::AbstractVector{E}) where {U<: Real, E<: Edge}
mate = fill(-1,n)
for i in keys(solution)
key = i[1] # i is a tuple with 1 element.
if solution[key] >= 1 - 1e-5 # Some tolerance to numerical approximations by the solver.
mate[src(key)] = dst(key)
mate[dst(key)] = src(key)
for e in edge_list
if solution[e] >= 1 - 1e-5 # Some tolerance to numerical approximations by the solver.
mate[src(e)] = dst(e)
mate[dst(e)] = src(e)
end
end
return mate
Expand All @@ -79,4 +75,4 @@ function default_weights(g::G) where {G<:AbstractGraph}
m[src(e),dst(e)] = 1
end
return m
end
end
2 changes: 1 addition & 1 deletion test/REQUIRE
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Cbc
Cbc 0.4
Loading