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

Commit

Permalink
Fixes for julia v1.0 (#12)
Browse files Browse the repository at this point in the history
* fixes for julia v1.0

* updated travis and appveyor scripts

* Update REQUIRE

Co-Authored-By: simonschoelly <sischoel@gmail.com>

* Update test/REQUIRE

Co-Authored-By: simonschoelly <sischoel@gmail.com>

* changed required versions
  • Loading branch information
simonschoelly authored and matbesancon committed Nov 5, 2018
1 parent 50edcb4 commit 9883489
Show file tree
Hide file tree
Showing 9 changed files with 296 additions and 293 deletions.
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

0 comments on commit 9883489

Please sign in to comment.