1
1
"""
2
- mincost_flow(graph, capacity, demand, cost , solver, [, source][, sink] )
2
+ mincost_flow(graph, node_demand, edge_capacity, edge_cost , solver,<keyword arguments> )
3
3
4
- Find a flow satisfying the `demand` and `capacity ` constraints for each edge
5
- while minimizing the `sum(cost .*flow)`.
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)`.
6
6
7
- - If `source` and `sink` are specified, they are allowed a net flow production,
8
- consumption respectively. All other nodes must respect the flow conservation
9
- property.
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
10
9
11
- - The problem can be seen as a linear programming problem and uses a LP
10
+ - The problem can be seen as a linear programming problem and uses a LP
12
11
solver under the hood. We use Clp in the examples and tests.
13
12
14
13
Returns a flow matrix, flow[i,j] corresponds to the flow on the (i,j) arc.
14
+ # 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
15
20
16
21
### Usage Example:
17
22
@@ -31,52 +36,87 @@ julia> w[1,3] = 10.
31
36
julia> w[1,4] = 5.
32
37
julia> w[2,3] = 2.
33
38
julia> w[2,4] = 2.
34
- julia> # v2 -> sink have demand of one
35
- julia> demand = spzeros(6,6)
36
- julia> demand[3,6] = 1
37
- julia> demand[4,6] = 1
39
+ julia> demand = spzeros(6)
40
+ julia> demand[5] = 2
41
+ julia> demand[6] = -2
38
42
julia> capacity = ones(6,6)
39
- julia> flow = mincost_flow(g, capacity, demand , w, ClpSolver(), 5, 6 )
43
+ julia> flow = mincost_flow(g, demand, capacity , w, ClpSolver())
40
44
```
41
45
"""
46
+
47
+
42
48
function mincost_flow (g:: lg.DiGraph ,
43
- capacity:: AbstractMatrix ,
44
- demand:: AbstractMatrix ,
45
- cost:: AbstractMatrix ,
46
- solver:: AbstractMathProgSolver ,
47
- source:: Int = - 1 , # if source and/or sink omitted or not in nodes, circulation problem
48
- sink:: Int = - 1 )
49
- flat_cap = collect (Iterators. flatten (capacity))
50
- flat_dem = collect (Iterators. flatten (demand))
51
- flat_cost = collect (Iterators. flatten (cost))
52
- n = lg. nv (g)
53
- b = zeros (n+ n* n)
54
- A = spzeros (n+ n* n,n* n)
55
- sense = [' =' for _ in 1 : n]
56
- append! (sense, [' >' for _ in 1 : n* n])
57
- for node in 1 : n
58
- if sink == node
59
- sense[sink] = ' >'
60
- elseif source == node
61
- sense[source] = ' <'
62
- end
63
- col_idx = (node- 1 )* n+ 1 : node* n
64
- line_idx = node: n: n* n
65
- for jdx in col_idx
66
- A[node,jdx] = A[node,jdx]+ 1.0
67
- end
68
- for idx in line_idx
69
- A[node,idx] = A[node,idx]- 1.0
49
+ node_demand:: AbstractVector ,
50
+ edge_capacity:: AbstractMatrix ,
51
+ edge_cost:: AbstractMatrix ,
52
+ solver:: AbstractMathProgSolver ;
53
+ 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]
70
86
end
87
+
88
+ edge_costs[n] = edge_cost[s,t]
71
89
end
72
- for src in 1 : n
73
- for dst in 1 : n
74
- if lg. Edge (src,dst) ∉ lg. edges (g)
75
- A[n+ src+ n* (dst- 1 ),src+ n* (dst- 1 )] = 1
76
- sense[n+ src+ n* (dst- 1 )] = ' <'
77
- end
78
- end
90
+ for n = 1 : nv
91
+ b[n] = node_demand[n]
79
92
end
80
- sol = linprog (flat_cost, A, sense, b, flat_dem, flat_cap, solver)
81
- [sol. sol[idx + n* (jdx- 1 )] for idx= 1 : n,jdx= 1 : n]
93
+
94
+ for n in source_nodes
95
+ sense[n] = ' >'
96
+ end
97
+ for n in sink_nodes
98
+ sense[n] = ' <'
99
+ end
100
+
101
+
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
82
107
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)
0 commit comments