@@ -6,8 +6,8 @@ using JuMP, HiGHS
66import .. OperationsResearchModels: solve
77
88
9- export MaximumFlowProblem
10- export MaximumFlowResult
9+ export MaximumFlowProblem, MaximumFlowResult
10+ export MinimumCostFlowProblem, MinimumCostFlowResult
1111
1212
1313struct MaximumFlowResult
@@ -19,6 +19,66 @@ struct MaximumFlowProblem
1919 connections:: Vector{Connection}
2020end
2121
22+ struct MinimumCostFlowProblem
23+ connections:: Vector{Connection}
24+ costs:: Vector{Connection}
25+ end
26+
27+ struct MinimumCostFlowResult
28+ path:: Vector{Connection}
29+ cost:: Float64
30+ end
31+
32+
33+ function leftexpressions (x:: Matrix{JuMP.VariableRef} , node:: Int64 , nodes:: Vector{Connection} , model)
34+ lst = []
35+ for conn in nodes
36+ if conn. to == node
37+ push! (lst, conn)
38+ end
39+ end
40+ if length (lst) == 0
41+ return :f
42+ end
43+ expr = @expression (model, 0 )
44+ for i = eachindex (lst)
45+ expr += x[lst[i]. from, lst[i]. to]
46+ end
47+ return expr
48+ end
49+
50+ function rightexpressions (x:: Matrix{JuMP.VariableRef} , node:: Int64 , nodes:: Vector{Connection} , model)
51+ lst = []
52+ for conn in nodes
53+ if conn. from == node
54+ push! (lst, conn)
55+ end
56+ end
57+ if length (lst) == 0
58+ return :f
59+ end
60+ expr = @expression (model, 0 )
61+ for i = eachindex (lst)
62+ expr += x[lst[i]. from, lst[i]. to]
63+ end
64+ return expr
65+ end
66+
67+
68+ function hassameorder (a:: Vector{Connection} , b:: Vector{Connection} ):: Bool
69+
70+ if length (a) != length (b)
71+ return false
72+ end
73+
74+ for i = 1 : length (a)
75+ if a[i]. from != b[i]. from || a[i]. to != b[i]. to
76+ return false
77+ end
78+ end
79+
80+ return true
81+ end
2282
2383"""
2484
@@ -65,45 +125,10 @@ julia> result.flow
651257.0
66126```
67127"""
68- function solve (problem:: MaximumFlowProblem )
128+ function solve (problem:: MaximumFlowProblem ):: MaximumFlowResult
69129
70130 cns = problem. connections
71131
72- function leftexpressions (node:: Int64 , nodes:: Vector{Connection} , model)
73- lst = []
74- for conn in nodes
75- if conn. to == node
76- push! (lst, conn)
77- end
78- end
79- if length (lst) == 0
80- return :f
81- end
82- expr = @expression (model, 0 )
83- for i = eachindex (lst)
84- expr += x[lst[i]. from, lst[i]. to]
85- end
86- return expr
87- end
88-
89- function rightexpressions (node:: Int64 , nodes:: Vector{Connection} , model)
90- lst = []
91- for conn in nodes
92- if conn. from == node
93- push! (lst, conn)
94- end
95- end
96- if length (lst) == 0
97- return :f
98- end
99- expr = @expression (model, 0 )
100- for i = eachindex (lst)
101- expr += x[lst[i]. from, lst[i]. to]
102- end
103- return expr
104- end
105-
106-
107132 model = Model (HiGHS. Optimizer)
108133 MOI. set (model, MOI. Silent (), true )
109134
@@ -122,8 +147,8 @@ function solve(problem::MaximumFlowProblem)
122147
123148 # Constraints
124149 for nextnode in mynodes
125- leftexpr = leftexpressions (nextnode, cns, model)
126- rightexpr = rightexpressions (nextnode, cns, model)
150+ leftexpr = leftexpressions (x, nextnode, cns, model)
151+ rightexpr = rightexpressions (x, nextnode, cns, model)
127152 if leftexpr == :f
128153 @constraint (model, rightexpr == f)
129154 elseif rightexpr == :f
@@ -157,4 +182,101 @@ end
157182
158183
159184
185+ """
186+ solve(problem, flow)
187+
188+ # Description
189+
190+ This function solves the Minimum Cost Flow problem given a flow value.
191+
192+ # Arguments
193+
194+ - `problem::MinimumCostFlowProblem`: The problem in type of MinimumCostFlowProblem
195+ - `flow::Float64`: The flow value to be used in the problem.
196+
197+
198+ """
199+ function solve (problem:: MinimumCostFlowProblem , flow:: Float64 ):: MinimumCostFlowResult
200+ cns = problem. connections
201+ costs = problem. costs
202+
203+ if ! hassameorder (cns, costs)
204+ throw (ArgumentError (" Connections and costs must have the same order." ))
205+ end
206+
207+ model = Model (HiGHS. Optimizer)
208+ MOI. set (model, MOI. Silent (), true )
209+
210+ mynodes = nodes (cns)
211+ n = length (mynodes)
212+
213+ startnode = start (cns)
214+ finishnode = finish (cns)
215+
216+ # Variables
217+ @variable (model, x[1 : n, 1 : n] .>= 0 )
218+
219+ # Objective Function
220+ @objective (model, Max, sum (x[conn. from, conn. to] * conn. value for conn in costs))
221+
222+ # Constraints
223+ for nextnode in mynodes
224+ leftexpr = leftexpressions (x, nextnode, cns, model)
225+ rightexpr = rightexpressions (x, nextnode, cns, model)
226+ if leftexpr == :f
227+ @constraint (model, rightexpr == flow)
228+ elseif rightexpr == :f
229+ @constraint (model, leftexpr == flow)
230+ else
231+ @constraint (model, leftexpr - rightexpr == 0 )
232+ end
233+ end
234+
235+ for nd in cns
236+ @constraint (model, x[nd. from, nd. to] <= nd. value)
237+ end
238+
239+ optimize! (model)
240+
241+ xs = value .(x)
242+ cost = JuMP. objective_value (model)
243+ solutionnodes = []
244+ for i = 1 : n
245+ for j = 1 : n
246+ if xs[i, j] > 0
247+ push! (solutionnodes, Connection (i, j, xs[i, j]))
248+ end
249+ end
250+ end
251+
252+ return MinimumCostFlowResult (solutionnodes, cost)
253+ end
254+
255+
256+ """
257+ solve(problem)
258+
259+ # Description
260+
261+ This function solves the Minimum Cost Flow problem by first solving the Maximum Flow problem and
262+ then using the flow value to solve the Minimum Cost Flow problem.
263+
264+ # Arguments
265+
266+ - `problem::MinimumCostFlowProblem`: The problem in type of MinimumCostFlowProblem
267+
268+ """
269+ function solve (problem:: MinimumCostFlowProblem ):: MinimumCostFlowResult
270+
271+ maximumflowproblem = MaximumFlowProblem (problem. connections)
272+
273+ maximumflowresult = solve (maximumflowproblem)
274+
275+ f = maximumflowresult. flow
276+
277+ result:: MinimumCostFlowResult = solve (problem, f)
278+
279+ return result
280+ end
281+
160282end # end of module
0 commit comments