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

Commit 838078f

Browse files
committed
fix conflicts
2 parents 46c22c8 + f8d29ff commit 838078f

File tree

12 files changed

+172
-285
lines changed

12 files changed

+172
-285
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "LightGraphsFlows"
22
uuid = "2f5eb75a-258c-59e0-affc-f41c55f75335"
33
authors = ["Mathieu Besançon <mathieu.besancon@gmail.com>"]
4-
version = "0.3.1"
4+
version = "0.4.0"
55

66
[deps]
77
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
@@ -12,6 +12,7 @@ SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
1212
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1313

1414
[compat]
15+
JuMP = "0.20"
1516
LightGraphs = "1"
1617
SimpleTraits = "0.9"
1718
julia = "1"

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ Mincost flow is solving a linear optimization problem and thus requires a LP sol
8181
defined by [MathProgBase.jl](http://mathprogbasejl.readthedocs.io).
8282

8383
```julia
84-
using Clp: ClpSolver
84+
using SparseArrays: spzeros
85+
import Clp
86+
using JuMP: with_optimizer
87+
8588
g = lg.DiGraph(6)
8689
lg.add_edge!(g, 5, 1)
8790
lg.add_edge!(g, 5, 2)
@@ -91,16 +94,17 @@ lg.add_edge!(g, 1, 3)
9194
lg.add_edge!(g, 1, 4)
9295
lg.add_edge!(g, 2, 3)
9396
lg.add_edge!(g, 2, 4)
94-
w = zeros(6,6)
95-
w[1,3] = 10.
96-
w[1,4] = 5.
97-
w[2,3] = 2.
98-
w[2,4] = 2.
97+
cost = zeros(6,6)
98+
cost[1,3] = 10.
99+
cost[1,4] = 5.
100+
cost[2,3] = 2.
101+
cost[2,4] = 2.
99102
# v2 -> sink have demand of one
100103
demand = spzeros(6,6)
101104
demand[3,6] = 1
102105
demand[4,6] = 1
106+
node_demand = spzeros(6)
103107
capacity = ones(6,6)
104108

105-
flow = mincost_flow(g, capacity, demand, w, ClpSolver(), 5, 6)
109+
flow = mincost_flow(g, node_demand, capacity, cost, with_optimizer(Clp.Optimizer), edge_demand=demand, source_nodes=[5], sink_nodes=[6])
106110
```

REQUIRE

Lines changed: 0 additions & 4 deletions
This file was deleted.

docs/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[deps]
2+
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d"
4+
LightGraphsFlows = "2f5eb75a-258c-59e0-affc-f41c55f75335"

docs/make.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Documenter
22
using LightGraphsFlows
3-
import LightGraphs
3+
using LightGraphs
44
const lg = LightGraphs
55

66
makedocs(
@@ -20,6 +20,5 @@ deploydocs(
2020
deps = nothing,
2121
make = nothing,
2222
repo = "github.com/JuliaGraphs/LightGraphsFlows.jl.git",
23-
target = "build",
24-
osname = "linux"
23+
versions = ["stable" => "v^", "v#.#", "dev" => "master"],
2524
)

docs/src/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Order = [:function, :type]
1818
This is the documentation page for `LightGraphsFlows`. In all pages, we assume
1919
LightGraphsFlows has been imported into scope and that LightGraphs is
2020
available with the alias `lg`:
21+
2122
```julia
2223
using LightGraphsFlows
2324
import LightGraphs

src/LightGraphsFlows.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
module LightGraphsFlows
22

3-
import LightGraphs
3+
using LightGraphs
44
const lg = LightGraphs
5+
56
using SimpleTraits: @traitfn, @traitimpl
67
import SimpleTraits
78

8-
using MathProgBase.HighLevelInterface: linprog
9-
using MathProgBase.SolverInterface: AbstractMathProgSolver
9+
using JuMP
1010

1111
using SparseArrays: spzeros, sparse, sparsevec
1212
using Markdown: @doc_str
@@ -28,5 +28,4 @@ export
2828
maximum_flow, EdmondsKarpAlgorithm, DinicAlgorithm, BoykovKolmogorovAlgorithm, PushRelabelAlgorithm,
2929
multiroute_flow, KishimotoAlgorithm, ExtendedMultirouteFlowAlgorithm, mincost_flow
3030

31-
3231
end

src/mincost.jl

Lines changed: 98 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,119 @@
11
"""
2-
mincost_flow(graph, node_demand, edge_capacity, edge_cost, solver,<keyword arguments>)
2+
function mincost_flow(g::AbstractGraph,
3+
node_demand::AbstractVector,
4+
edge_capacity::AbstractMatrix,
5+
edge_cost::AbstractMatrix,
6+
optimizer;
7+
edge_demand::Union{Nothing,AbstractMatrix} = nothing,
8+
source_nodes = (),
9+
sink_nodes = ()
10+
)
311
4-
Find a flow satisfying the `node_demand` at each node and `edge_capacity` constraints for each edge
5-
while minimizing the `sum(edge_cost.*flow)`.
12+
Find a flow over a directed graph `g` satisfying the `node_demand` at each
13+
node and `edge_capacity` constraints for each edge while minimizing `dot(edge_cost, flow)`.
614
7-
-`node_demand` is a vector of nodal values, which should be positive for sources and
8-
negative at sink nodes, any node with zero demand is a transport node
15+
Returns a sparse flow matrix, flow[i,j] corresponds to the flow on the (i,j) arc.
916
10-
- The problem can be seen as a linear programming problem and uses a LP
11-
solver under the hood. We use Clp in the examples and tests.
12-
13-
Returns a flow matrix, flow[i,j] corresponds to the flow on the (i,j) arc.
1417
# Arguments
15-
- `edge_demand::AbstractMatrix`: demand a minimum flow for a given edge.
16-
- `edge_demand_exact=true`: changes the capacity of a non zero edge to the demanded value
17-
- `source_nodes::AbstractVector` Sources at which the nodal netflow is allowed to be greater than nodal demand **
18-
- `sink_nodes::AbstractVector` Sinks at which the nodal netflow is allowed to be less than nodal demand **
19-
** source_nodes & sink_nodes are only needed when nodal flow are not explictly set in node_demand
18+
19+
- `g` is a directed `LightGraphs.AbstractGraph`.
20+
-`node_demand` is a vector of nodal demand values, which should be negative for sources,
21+
positive for sink nodes, and zero for all other nodes.
22+
- `edge_capacity::AbstractMatrix` sets an upper bound on the flow of each arc.
23+
- `edge_cost::AbstractMatrix` the cost per unit of flow on each arc.
24+
- `optimizer` is an optimizer factory as defined in JuMP, passed at the construction of the `JuMP.Model`.
25+
26+
# Keyword arguments
27+
28+
- `edge_demand::Union{Nothing,AbstractMatrix}`: require a minimum flow for edges, or nothing.
29+
- `source_nodes` Collection of sources at which the nodal netflow is allowed to be greater than nodal demand, defaults to an empty tuple.
30+
- `sink_nodes` Collection of sinks at which the nodal netflow is allowed to be less than nodal demand, defaults to an empty tuple.
31+
32+
`source_nodes` & `sink_nodes` are only needed when nodal flow are not explictly set in node_demand
2033
2134
### Usage Example:
2235
2336
```julia
24-
julia> using Clp: ClpSolver # use your favorite LP solver here
25-
julia> g = lg.DiGraph(6) # Create a flow-graph
26-
julia> lg.add_edge!(g, 5, 1)
27-
julia> lg.add_edge!(g, 5, 2)
28-
julia> lg.add_edge!(g, 3, 6)
29-
julia> lg.add_edge!(g, 4, 6)
30-
julia> lg.add_edge!(g, 1, 3)
31-
julia> lg.add_edge!(g, 1, 4)
32-
julia> lg.add_edge!(g, 2, 3)
33-
julia> lg.add_edge!(g, 2, 4)
34-
julia> w = zeros(6,6)
35-
julia> w[1,3] = 10.
36-
julia> w[1,4] = 5.
37-
julia> w[2,3] = 2.
38-
julia> w[2,4] = 2.
37+
julia> import LightGraphs
38+
julia> const LG = LightGraphs
39+
julia> using LightGraphsFlows: mincost_flow
40+
julia> import Clp # use your favorite LP solver here
41+
julia> import JuMP
42+
julia> using SparseArrays: spzeros
43+
julia> g = LG.DiGraph(6) # Create a flow-graph
44+
julia> LG.add_edge!(g, 5, 1)
45+
julia> LG.add_edge!(g, 5, 2)
46+
julia> LG.add_edge!(g, 3, 6)
47+
julia> LG.add_edge!(g, 4, 6)
48+
julia> LG.add_edge!(g, 1, 3)
49+
julia> LG.add_edge!(g, 1, 4)
50+
julia> LG.add_edge!(g, 2, 3)
51+
julia> LG.add_edge!(g, 2, 4)
52+
julia> cost = zeros(6,6)
53+
julia> cost[1,3] = 10
54+
julia> cost[1,4] = 5
55+
julia> cost[2,3] = 2
56+
julia> cost[2,4] = 2
3957
julia> demand = spzeros(6)
40-
julia> demand[5] = 2
41-
julia> demand[6] = -2
58+
julia> demand[5] = -2
59+
julia> demand[6] = 2
4260
julia> capacity = ones(6,6)
43-
julia> flow = mincost_flow(g, demand, capacity, w, ClpSolver())
61+
julia> flow = mincost_flow(g, demand, capacity, cost, JuMP.with_optimizer(Clp.Optimizer))
4462
```
4563
"""
64+
function mincost_flow end
4665

47-
48-
function mincost_flow(g::lg.DiGraph,
66+
@traitfn function mincost_flow(g::AG::lg.IsDirected,
4967
node_demand::AbstractVector,
5068
edge_capacity::AbstractMatrix,
5169
edge_cost::AbstractMatrix,
52-
solver::AbstractMathProgSolver;
70+
optimizer;
5371
edge_demand::Union{Nothing,AbstractMatrix} = nothing,
54-
edge_demand_exact::Bool = false, #If true changes capacity of that node to the value in edge demand
55-
source_nodes::AbstractVector{<:Integer} = Vector{Integer}(), #Source nodes at which to allow a netflow greater than nodal demand
56-
sink_nodes::AbstractVector{<:Integer} = Vector{Integer}() #Sink nodes at which to allow a netflow less than nodal demand
57-
)
58-
T = eltype(g)
59-
VT = promote_type(eltype(edge_capacity),eltype(node_demand),eltype(edge_cost))
60-
61-
nv = lg.nv(g)
62-
ne = lg.ne(g)
63-
b = Vector{VT}(undef,nv)
64-
AI = Vector{T}(undef,2*ne)
65-
AJ = Vector{T}(undef,2*ne)
66-
AV = Vector{VT}(undef,2*ne)
67-
edge_costs = Vector{VT}(undef,ne)
68-
upperbounds = Vector{VT}(undef,ne)
69-
lowerbounds = Vector{VT}(undef,ne)
70-
sense = ['=' for _ in 1:nv]
71-
72-
has_edge_demand= edge_demand !== nothing
73-
74-
inds = [-1,0]
75-
for (n,e) in enumerate(lg.edges(g))
76-
inds .+= 2
77-
s = lg.src(e)
78-
t = lg.dst(e)
79-
AI[inds] = [s,t] #the node index
80-
AJ[inds] = [n,n] #the edge index
81-
AV[inds] = [1,-1]
82-
upperbounds[n] = edge_capacity[s,t]
83-
lowerbounds[n] = has_edge_demand ? edge_demand[s,t] : zero(VT)
84-
if edge_demand_exact && has_edge_demand && lowerbounds[n] != 0
85-
upperbounds[n] = lowerbounds[n]
86-
end
87-
88-
edge_costs[n] = edge_cost[s,t]
89-
end
90-
for n = 1:nv
91-
b[n] = node_demand[n]
92-
end
93-
94-
for n in source_nodes
95-
sense[n] = '>'
72+
source_nodes = (), # Source nodes at which to allow a netflow greater than nodal demand
73+
sink_nodes = () # Sink nodes at which to allow a netflow less than nodal demand
74+
) where {AG <: lg.AbstractGraph}
75+
76+
m = JuMP.Model(optimizer)
77+
vtxs = vertices(g)
78+
79+
source_nodes = [v for v in vtxs if v in source_nodes || node_demand[v] < 0]
80+
sink_nodes = [v for v in vtxs if v in sink_nodes || node_demand[v] > 0]
81+
82+
@variable(m, 0 <= f[i=vtxs,j=vtxs; (i,j) in lg.edges(g)] <= edge_capacity[i, j])
83+
@objective(m, Min, sum(f[src(e),dst(e)] * edge_cost[src(e), dst(e)] for e in lg.edges(g)))
84+
85+
for v in lg.vertices(g)
86+
if v in source_nodes
87+
@constraint(m,
88+
sum(f[v, vout] for vout in outneighbors(g, v)) - sum(f[vin, v] for vin in lg.inneighbors(g, v)) >= -node_demand[v]
89+
)
90+
elseif v in sink_nodes
91+
@constraint(m,
92+
sum(f[vin, v] for vin in lg.inneighbors(g, v)) - sum(f[v, vout] for vout in outneighbors(g, v)) >= node_demand[v]
93+
)
94+
else
95+
@constraint(m,
96+
sum(f[vin, v] for vin in lg.inneighbors(g, v)) == sum(f[v, vout] for vout in outneighbors(g, v))
97+
)
98+
end
9699
end
97-
for n in sink_nodes
98-
sense[n] = '<'
99-
end
100-
101100

102-
A = sparse(AI,AJ,AV,nv,ne)
103-
# return (edge_costs, A, sense, b, lowerbounds, upperbounds, solver)
104-
sol = linprog(edge_costs, A, sense, b, lowerbounds, upperbounds, solver)
105-
sol_sparse = sparse(view(AI,1:2:2*ne),view(AI,2:2:2*ne),sol.sol,nv,nv)
106-
return sol_sparse
101+
if edge_demand isa AbstractMatrix
102+
for e in lg.edges(g)
103+
(i,j) = Tuple(e)
104+
JuMP.set_lower_bound(f[i,j], edge_demand[i,j])
105+
end
106+
end
107+
optimize!(m)
108+
ts = termination_status(m)
109+
result_flow = spzeros(nv(g), nv(g))
110+
if ts != MOI.OPTIMAL
111+
@warn "Problem does not have an optimal solution, status: $(ts)"
112+
return result_flow
113+
end
114+
for e in lg.edges(g)
115+
(i,j) = Tuple(e)
116+
result_flow[i,j] = JuMP.value(f[i,j])
117+
end
118+
return result_flow
107119
end
108-
109-
@deprecate mincost_flow(g::lg.DiGraph,
110-
capacity::AbstractMatrix,
111-
demand::AbstractMatrix,
112-
cost::AbstractMatrix,
113-
solver::AbstractMathProgSolver,
114-
source::Int, # if source and/or sink omitted or not in nodes, circulation problem
115-
sink::Int) mincost_flow(g,spzeros(lg.nv(g)),capacity,cost,solver,edge_demand=demand,source_nodes=[source],sink_nodes=[sink])
116-
117-
@deprecate mincost_flow(g::lg.DiGraph,
118-
capacity::AbstractMatrix,
119-
demand::AbstractMatrix,
120-
cost::AbstractMatrix,
121-
solver::AbstractMathProgSolver
122-
) mincost_flow(g,spzeros(lg.nv(g)),capacity,cost,solver,edge_demand=demand)

test/REQUIRE

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)