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

Commit 6506631

Browse files
authored
Mathprog (#5)
* added mincost func * added default solver * added tests for mincost, export function * default sink and source, circulation tests * changed LP solver, added doc, conservation tests * added mincost docs * replace JuMP with basic MathProg * removed JuMP from require
1 parent 7fac8ca commit 6506631

File tree

7 files changed

+43
-46
lines changed

7 files changed

+43
-46
lines changed

REQUIRE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
julia 0.6
22
LightGraphs
33
SimpleTraits
4-
JuMP
54
MathProgBase
65
GLPK
76
GLPKMathProgInterface

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ makedocs(
1111
"Getting started" => "index.md",
1212
"Maxflow algorithms" => "maxflow.md",
1313
"Multiroute flows" => "multiroute.md",
14+
"Min-cost flows" => "mincost.md",
1415
]
1516
)

docs/src/mincost.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Min-cost flow
2+
3+
```@autodocs
4+
Modules = [LightGraphsFlows]
5+
Pages = ["mincost.jl"]
6+
Order = [:function, :type]
7+
```

src/LightGraphsFlows.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const lg = LightGraphs
55
using SimpleTraits: @traitfn, @traitimpl
66
import SimpleTraits
77

8-
import JuMP
8+
using MathProgBase.HighLevelInterface: linprog
99
using MathProgBase.SolverInterface: AbstractMathProgSolver
1010
using GLPKMathProgInterface: GLPKSolverLP
1111

src/mincost.jl

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Returns a flow matrix, flow[i,j] corresponds to the flow on the (i,j) arc.
1515
1616
### Usage Example:
1717
18-
```jldoctest
18+
```julia
1919
julia> g = lg.DiGraph(6) # Create a flow-graph
2020
julia> lg.add_edge!(g, 5, 1)
2121
julia> lg.add_edge!(g, 5, 2)
@@ -45,47 +45,37 @@ function mincost_flow(g::lg.DiGraph,
4545
source::Int = -1, # if source and/or sink omitted or not in nodes, circulation problem
4646
sink::Int = -1,
4747
solver::AbstractMathProgSolver = GLPKSolverLP())
48-
m = JuMP.Model(solver = solver)
49-
flow = JuMP.@variable(m, x[1:lg.nv(g),1:lg.nv(g)] >= 0.)
50-
JuMP.@constraint(m,
51-
[i=1:lg.nv(g),j=1:lg.nv(g)],
52-
flow[i,j] - demand[i,j] >= 0.
53-
)
54-
JuMP.@constraint(m,
55-
[i=1:lg.nv(g),j=1:lg.nv(g)],
56-
capacity[i,j] - flow[i,j] >= 0.
57-
)
58-
for n1 in 1:lg.nv(g)
59-
for n2 in 1:lg.nv(g)
60-
if !lg.has_edge(g,n1,n2)
61-
JuMP.@constraint(m, flow[n1,n2] <= 0.)
62-
end
48+
flat_cap = collect(Iterators.flatten(capacity))
49+
flat_dem = collect(Iterators.flatten(demand))
50+
flat_cost = collect(Iterators.flatten(cost))
51+
n = lg.nv(g)
52+
b = zeros(n+n*n)
53+
A = spzeros(n+n*n,n*n)
54+
sense = ['=' for _ in 1:n]
55+
append!(sense, ['>' for _ in 1:n*n])
56+
for node in 1:n
57+
if sink == node
58+
sense[sink] = '>'
59+
elseif source == node
60+
sense[source] = '<'
6361
end
64-
end
65-
# flow conservation constraints
66-
for node in 1:lg.nv(g)
67-
if node != source && node != sink
68-
JuMP.@constraint(m,
69-
sum(flow[node,j] for j in 1:lg.nv(g)) -
70-
sum(flow[i,node] for i in 1:lg.nv(g)) == 0
71-
)
62+
col_idx = (node-1)*n+1:node*n
63+
line_idx = node:n:n*n
64+
for jdx in col_idx
65+
A[node,jdx] = A[node,jdx]+1.0
66+
end
67+
for idx in line_idx
68+
A[node,idx] = A[node,idx]-1.0
7269
end
7370
end
74-
# source is a net flow producer
75-
if source 1:lg.nv(g)
76-
JuMP.@constraint(m,
77-
sum(flow[source,j] for j in 1:lg.nv(g)) -
78-
sum(flow[i,source] for i in 1:lg.nv(g)) >= 0
79-
)
80-
end
81-
# source is a net flow consumer
82-
if sink 1:lg.nv(g)
83-
JuMP.@constraint(m,
84-
sum(flow[sink,j] for j in 1:lg.nv(g)) -
85-
sum(flow[i,sink] for i in 1:lg.nv(g)) <= 0
86-
)
71+
for src in 1:n
72+
for dst in 1:n
73+
if lg.Edge(src,dst) lg.edges(g)
74+
A[n+src+n*(dst-1),src+n*(dst-1)] = 1
75+
sense[n+src+n*(dst-1)] = '<'
76+
end
77+
end
8778
end
88-
JuMP.@objective(m, :Min, sum(flow[i,j]*cost[i,j] for i=1:lg.nv(g),j=1:lg.nv(g)))
89-
solution = JuMP.solve(m)
90-
return JuMP.getvalue(flow)
79+
sol = linprog(flat_cost, A, sense, b, flat_dem, flat_cap, solver)
80+
[sol.sol[idx + n*(jdx-1)] for idx=1:n,jdx=1:n]
9181
end

test/boykov_kolmogorov.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
for g in testdigraphs(gg)
1212
# default capacity
13-
capacity_matrix = lg.DefaultCapacity(g)
14-
residual_graph = @inferred(lg.residual(g))
13+
capacity_matrix = LightGraphsFlows.DefaultCapacity(g)
14+
residual_graph = @inferred(LightGraphsFlows.residual(g))
1515
T = eltype(g)
1616
flow_matrix = zeros(T, 3, 3)
1717
TREE = zeros(T, 3)
@@ -21,7 +21,7 @@
2121
A = [T(source), T(target)]
2222
# see https://github.com/JuliaLang/julia/issues/21077
2323
# @show("testing $g with eltype $T, residual_graph type is $(eltype(residual_graph)), flow_matrix type is $(eltype(flow_matrix)), capacity_matrix type is $(eltype(capacity_matrix))")
24-
path = lg.find_path!(
24+
path = LightGraphsFlows.find_path!(
2525
residual_graph, source, target, flow_matrix,
2626
capacity_matrix, PARENT, TREE, A)
2727

test/dinic.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
# Construct the residual graph
2121
for fg in (flow_graph, lg.DiGraph{UInt8}(flow_graph), lg.DiGraph{Int16}(flow_graph))
22-
residual_graph = @inferred(lg.residual(fg))
22+
residual_graph = @inferred(LightGraphsFlows.residual(fg))
2323

2424
# Test with default distances
2525
@test @inferred(LightGraphsFlows.dinic_impl(residual_graph, 1, 8, LightGraphsFlows.DefaultCapacity(residual_graph)))[1] == 3

0 commit comments

Comments
 (0)