Satsuma
a delicious .NET graph library
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Pages
NetworkSimplex.cs
Go to the documentation of this file.
1 #region License
2 /*This file is part of Satsuma Graph Library
3 Copyright © 2013 Balázs Szalkai
4 
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17 
18  2. Altered source versions must be plainly marked as such, and must not be
19  misrepresented as being the original software.
20 
21  3. This notice may not be removed or altered from any source
22  distribution.*/
23 #endregion
24 
25 using System;
26 using System.Collections.Generic;
27 using System.Linq;
28 
29 namespace Satsuma
30 {
32  public enum SimplexState
33  {
35  FirstPhase,
37  Infeasible,
41  Unbounded,
43  Optimal
44  }
45 
50  public sealed class NetworkSimplex : IClearable
51  {
52  public IGraph Graph { get; private set; }
56  public Func<Arc, long> LowerBound { get; private set; }
61  public Func<Arc, long> UpperBound { get; private set; }
65  public Func<Node, long> Supply { get; private set; }
68  public Func<Arc, double> Cost { get; private set; }
69 
70  private double Epsilon;
71 
72  // *** Current state
73  // This is the graph augmented with a node and artificial arcs
74  private Supergraph MyGraph;
75  private Node ArtificialNode;
76  private HashSet<Arc> ArtificialArcs;
77  // During execution, the network simplex method maintains a basis.
78  // This consists of:
79  // - a spanning tree
80  // - a partition of the non-tree arcs into empty and saturated arcs
81  // ** Primal vector
82  private Dictionary<Arc, long> Tree;
83  private Subgraph TreeSubgraph;
84  private HashSet<Arc> Saturated;
85  // ** Dual vector
86  private Dictionary<Node, double> Potential;
87  // An enumerator for finding an entering arc
88  private IEnumerator<Arc> EnteringArcEnumerator;
89 
91  public SimplexState State { get; private set; }
92 
94  public NetworkSimplex(IGraph graph,
95  Func<Arc, long> lowerBound = null, Func<Arc, long> upperBound = null,
96  Func<Node, long> supply = null, Func<Arc, double> cost = null)
97  {
98  Graph = graph;
99  LowerBound = lowerBound ?? (x => 0);
100  UpperBound = upperBound ?? (x => long.MaxValue);
101  Supply = supply ?? (x => 0);
102  Cost = cost ?? (x => 1);
103 
104  Epsilon = 1;
105  foreach (var arc in graph.Arcs())
106  {
107  double x = Math.Abs(Cost(arc));
108  if (x > 0 && x < Epsilon) Epsilon = x;
109  }
110  Epsilon *= 1e-12;
111 
112  Clear();
113  }
114 
116  public long Flow(Arc arc)
117  {
118  if (Saturated.Contains(arc)) return UpperBound(arc);
119  long result;
120  if (Tree.TryGetValue(arc, out result)) return result;
121  result = LowerBound(arc);
122  return result == long.MinValue ? 0 : result;
123  }
124 
126  public IEnumerable<KeyValuePair<Arc, long>> Forest
127  {
128  get
129  {
130  return Tree.Where(kv => Graph.HasArc(kv.Key));
131  }
132  }
133 
136  public IEnumerable<Arc> UpperBoundArcs { get { return Saturated; } }
137 
139  public void Clear()
140  {
141  Dictionary<Node, long> excess = new Dictionary<Node, long>();
142  foreach (var n in Graph.Nodes()) excess[n] = Supply(n);
143 
144  Saturated = new HashSet<Arc>();
145  foreach (var arc in Graph.Arcs())
146  {
147  long f = LowerBound(arc);
148  long g = UpperBound(arc);
149  if (g < long.MaxValue) Saturated.Add(arc);
150  long flow = Flow(arc);
151  excess[Graph.U(arc)] -= flow;
152  excess[Graph.V(arc)] += flow;
153  }
154 
155  Potential = new Dictionary<Node, double>();
156  MyGraph = new Supergraph(Graph);
157  ArtificialNode = MyGraph.AddNode();
158  Potential[ArtificialNode] = 0;
159  ArtificialArcs = new HashSet<Arc>();
160  var artificialArcOf = new Dictionary<Node, Arc>();
161  foreach (var n in Graph.Nodes())
162  {
163  long e = excess[n];
164  Arc arc = e > 0 ? MyGraph.AddArc(n, ArtificialNode, Directedness.Directed) :
165  MyGraph.AddArc(ArtificialNode, n, Directedness.Directed);
166  Potential[n] = (e > 0 ? -1 : 1);
167  ArtificialArcs.Add(arc);
168  artificialArcOf[n] = arc;
169  }
170 
171  Tree = new Dictionary<Arc, long>();
172  TreeSubgraph = new Subgraph(MyGraph);
173  TreeSubgraph.EnableAllArcs(false);
174  foreach (var kv in artificialArcOf)
175  {
176  Tree[kv.Value] = Math.Abs(excess[kv.Key]);
177  TreeSubgraph.Enable(kv.Value, true);
178  }
179 
180  State = SimplexState.FirstPhase;
181  EnteringArcEnumerator = MyGraph.Arcs().GetEnumerator();
182  EnteringArcEnumerator.MoveNext();
183  }
184 
185  private long ActualLowerBound(Arc arc)
186  {
187  return ArtificialArcs.Contains(arc) ? 0 : LowerBound(arc);
188  }
189 
190  private long ActualUpperBound(Arc arc)
191  {
192  return ArtificialArcs.Contains(arc) ?
193  (State == SimplexState.FirstPhase ? long.MaxValue : 0) : UpperBound(arc);
194  }
195 
196  private double ActualCost(Arc arc)
197  {
198  return ArtificialArcs.Contains(arc) ? 1 : (State == SimplexState.FirstPhase ? 0 : Cost(arc));
199  }
200 
201  // Recalculates the potential at the beginning of the second phase
202  private class RecalculatePotentialDfs : Dfs
203  {
204  public NetworkSimplex Parent;
205 
206  protected override void Start(out Direction direction)
207  {
208  direction = Direction.Undirected;
209  }
210 
211  protected override bool NodeEnter(Node node, Arc arc)
212  {
213  if (arc == Arc.Invalid)
214  Parent.Potential[node] = 0;
215  else
216  {
217  Node other = Parent.MyGraph.Other(arc, node);
218  Parent.Potential[node] = Parent.Potential[other] +
219  (node == Parent.MyGraph.V(arc) ? Parent.ActualCost(arc) : -Parent.ActualCost(arc));
220  }
221  return true;
222  }
223  }
224 
225  private class UpdatePotentialDfs : Dfs
226  {
227  public NetworkSimplex Parent;
228  public double Diff;
229 
230  protected override void Start(out Direction direction)
231  {
232  direction = Direction.Undirected;
233  }
234 
235  protected override bool NodeEnter(Node node, Arc arc)
236  {
237  Parent.Potential[node] += Diff;
238  return true;
239  }
240  }
241 
243  private static ulong MySubtract(long a, long b)
244  {
245  if (a == long.MaxValue || b == long.MinValue) return ulong.MaxValue;
246  return (ulong)(a - b);
247  }
248 
251  public void Step()
252  {
253  if (State != SimplexState.FirstPhase && State != SimplexState.SecondPhase) return;
254 
255  // calculate reduced costs and find an entering arc
256  Arc firstArc = EnteringArcEnumerator.Current;
257  Arc enteringArc = Arc.Invalid;
258  double enteringReducedCost = double.NaN;
259  bool enteringSaturated = false;
260  while (true)
261  {
262  Arc arc = EnteringArcEnumerator.Current;
263  if (!Tree.ContainsKey(arc))
264  {
265  bool saturated = Saturated.Contains(arc);
266  double reducedCost = ActualCost(arc) - (Potential[MyGraph.V(arc)] - Potential[MyGraph.U(arc)]);
267  if ((reducedCost < -Epsilon && !saturated) ||
268  (reducedCost > Epsilon && (saturated || ActualLowerBound(arc) == long.MinValue)))
269  {
270  enteringArc = arc;
271  enteringReducedCost = reducedCost;
272  enteringSaturated = saturated;
273  break;
274  }
275  }
276 
277  // iterate
278  if (!EnteringArcEnumerator.MoveNext())
279  {
280  EnteringArcEnumerator = MyGraph.Arcs().GetEnumerator();
281  EnteringArcEnumerator.MoveNext();
282  }
283  if (EnteringArcEnumerator.Current == firstArc) break;
284  }
285 
286  if (enteringArc == Arc.Invalid)
287  {
288  if (State == SimplexState.FirstPhase)
289  {
290  State = SimplexState.SecondPhase;
291  foreach (var arc in ArtificialArcs) if (Flow(arc) > 0)
292  {
293  State = SimplexState.Infeasible;
294  break;
295  }
296  if (State == SimplexState.SecondPhase)
297  new RecalculatePotentialDfs() { Parent = this }.Run(TreeSubgraph);
298  }
299  else State = SimplexState.Optimal;
300 
301  return;
302  }
303 
304  // find the basic circle of the arc: this consists of forward and reverse arcs
305  Node u = MyGraph.U(enteringArc), v = MyGraph.V(enteringArc);
306  List<Arc> forwardArcs = new List<Arc>();
307  List<Arc> backwardArcs = new List<Arc>();
308  IPath pathu = TreeSubgraph.FindPath(v, u, Dfs.Direction.Undirected);
309  foreach (var n in pathu.Nodes())
310  {
311  var arc = pathu.NextArc(n);
312  (MyGraph.U(arc) == n ? forwardArcs : backwardArcs).Add(arc);
313  }
314 
315  // calculate flow modification delta and exiting arc/root
316  ulong delta = enteringReducedCost < 0 ? MySubtract(ActualUpperBound(enteringArc), Flow(enteringArc)) :
317  MySubtract(Flow(enteringArc), ActualLowerBound(enteringArc));
318  Arc exitingArc = enteringArc;
319  bool exitingSaturated = !enteringSaturated;
320  foreach (var arc in forwardArcs)
321  {
322  ulong q = enteringReducedCost < 0 ? MySubtract(ActualUpperBound(arc), Tree[arc]) :
323  MySubtract(Tree[arc], ActualLowerBound(arc));
324  if (q < delta)
325  { delta = q; exitingArc = arc; exitingSaturated = (enteringReducedCost < 0); }
326  }
327  foreach (var arc in backwardArcs)
328  {
329  ulong q = enteringReducedCost > 0 ? MySubtract(ActualUpperBound(arc), Tree[arc]) :
330  MySubtract(Tree[arc], ActualLowerBound(arc));
331  if (q < delta)
332  { delta = q; exitingArc = arc; exitingSaturated = (enteringReducedCost > 0); }
333  }
334 
335  // modify the primal solution along the circle
336  long signedDelta = 0;
337  if (delta != 0)
338  {
339  if (delta == ulong.MaxValue) { State = SimplexState.Unbounded; return; }
340  signedDelta = enteringReducedCost < 0 ? (long)delta : -(long)delta;
341  foreach (var arc in forwardArcs) Tree[arc] += signedDelta;
342  foreach (var arc in backwardArcs) Tree[arc] -= signedDelta;
343  }
344 
345  // modify the basis
346  if (exitingArc == enteringArc)
347  {
348  if (enteringSaturated) Saturated.Remove(enteringArc); else Saturated.Add(enteringArc);
349  }
350  else
351  {
352  // remove exiting arc/root
353  Tree.Remove(exitingArc);
354  TreeSubgraph.Enable(exitingArc, false);
355  if (exitingSaturated) Saturated.Add(exitingArc);
356 
357  // modify the dual solution along a cut
358  double diff = ActualCost(enteringArc) - (Potential[v] - Potential[u]);
359  if (diff != 0) new UpdatePotentialDfs() { Parent = this, Diff = diff }.
360  Run(TreeSubgraph, new Node[] { v });
361 
362  // add entering arc
363  Tree[enteringArc] = Flow(enteringArc) + signedDelta;
364  if (enteringSaturated) Saturated.Remove(enteringArc);
365  TreeSubgraph.Enable(enteringArc, true);
366  }
367  }
368 
371  public void Run()
372  {
373  while (State == SimplexState.FirstPhase || State == SimplexState.SecondPhase) Step();
374  }
375  }
376 }