Satsuma
a delicious .NET graph library
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Pages
Path.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 
7 namespace Satsuma
8 {
24  public interface IPath : IGraph
25  {
27  Node FirstNode { get; }
30  Node LastNode { get; }
34  Arc NextArc(Node node);
38  Arc PrevArc(Node node);
39  }
40 
42  public static class PathExtensions
43  {
45  public static bool IsCycle(this IPath path)
46  {
47  return path.FirstNode == path.LastNode && path.ArcCount() > 0;
48  }
49 
53  public static Node NextNode(this IPath path, Node node)
54  {
55  var arc = path.NextArc(node);
56  if (arc == Arc.Invalid) return Node.Invalid;
57  return path.Other(arc, node);
58  }
59 
63  public static Node PrevNode(this IPath path, Node node)
64  {
65  var arc = path.PrevArc(node);
66  if (arc == Arc.Invalid) return Node.Invalid;
67  return path.Other(arc, node);
68  }
69 
71  internal static IEnumerable<Arc> ArcsHelper(this IPath path, Node u, ArcFilter filter)
72  {
73  Arc arc1 = path.PrevArc(u), arc2 = path.NextArc(u);
74  if (arc1 == arc2) arc2 = Arc.Invalid; // avoid duplicates
75  for (int i = 0; i < 2; i++)
76  {
77  Arc arc = (i == 0 ? arc1 : arc2);
78  if (arc == Arc.Invalid) continue;
79  switch (filter)
80  {
81  case ArcFilter.All: yield return arc; break;
82  case ArcFilter.Edge: if (path.IsEdge(arc)) yield return arc; break;
83  case ArcFilter.Forward: if (path.IsEdge(arc) || path.U(arc) == u) yield return arc; break;
84  case ArcFilter.Backward: if (path.IsEdge(arc) || path.V(arc) == u) yield return arc; break;
85  }
86  }
87  }
88  }
89 
109  public sealed class Path : IPath, IClearable
110  {
112  public IGraph Graph { get; private set; }
113  public Node FirstNode { get; private set; }
114  public Node LastNode { get; private set; }
115 
116  private int nodeCount;
117  private Dictionary<Node, Arc> nextArc;
118  private Dictionary<Node, Arc> prevArc;
119  private HashSet<Arc> arcs;
120  private int edgeCount;
121 
123  public Path(IGraph graph)
124  {
125  Graph = graph;
126 
127  nextArc = new Dictionary<Node, Arc>();
128  prevArc = new Dictionary<Node, Arc>();
129  arcs = new HashSet<Arc>();
130 
131  Clear();
132  }
133 
135  public void Clear()
136  {
139 
140  nodeCount = 0;
141  nextArc.Clear();
142  prevArc.Clear();
143  arcs.Clear();
144  edgeCount = 0;
145  }
146 
149  public void Begin(Node node)
150  {
151  if (nodeCount > 0)
152  throw new InvalidOperationException("Path not empty.");
153 
154  nodeCount = 1;
155  FirstNode = LastNode = node;
156  }
157 
162  public void AddFirst(Arc arc)
163  {
164  Node u = U(arc), v = V(arc);
165  Node newNode = (u == FirstNode ? v : u);
166  if ((u != FirstNode && v != FirstNode) || nextArc.ContainsKey(newNode) || prevArc.ContainsKey(FirstNode))
167  throw new ArgumentException("Arc not valid or path is a cycle.");
168 
169  if (newNode != LastNode) nodeCount++;
170  nextArc[newNode] = arc;
171  prevArc[FirstNode] = arc;
172  if (!arcs.Contains(arc))
173  {
174  arcs.Add(arc);
175  if (IsEdge(arc)) edgeCount++;
176  }
177 
178  FirstNode = newNode;
179  }
180 
185  public void AddLast(Arc arc)
186  {
187  Node u = U(arc), v = V(arc);
188  Node newNode = (u == LastNode ? v : u);
189  if ((u != LastNode && v != LastNode) || nextArc.ContainsKey(LastNode) || prevArc.ContainsKey(newNode))
190  throw new ArgumentException("Arc not valid or path is a cycle.");
191 
192  if (newNode != FirstNode) nodeCount++;
193  nextArc[LastNode] = arc;
194  prevArc[newNode] = arc;
195  if (!arcs.Contains(arc))
196  {
197  arcs.Add(arc);
198  if (IsEdge(arc)) edgeCount++;
199  }
200 
201  LastNode = newNode;
202  }
203 
206  public void Reverse()
207  {
208  { var tmp = FirstNode; FirstNode = LastNode; LastNode = tmp; }
209  { var tmp = nextArc; nextArc = prevArc; prevArc = tmp; }
210  }
211 
212  public Arc NextArc(Node node)
213  {
214  Arc arc;
215  return nextArc.TryGetValue(node, out arc) ? arc : Arc.Invalid;
216  }
217 
218  public Arc PrevArc(Node node)
219  {
220  Arc arc;
221  return prevArc.TryGetValue(node, out arc) ? arc : Arc.Invalid;
222  }
223 
224  public Node U(Arc arc)
225  {
226  return Graph.U(arc);
227  }
228 
229  public Node V(Arc arc)
230  {
231  return Graph.V(arc);
232  }
233 
234  public bool IsEdge(Arc arc)
235  {
236  return Graph.IsEdge(arc);
237  }
238 
239  public IEnumerable<Node> Nodes()
240  {
241  Node n = FirstNode;
242  if (n == Node.Invalid) yield break;
243  while (true)
244  {
245  yield return n;
246  Arc arc = NextArc(n);
247  if (arc == Arc.Invalid) yield break;
248  n = Graph.Other(arc, n);
249  if (n == FirstNode) yield break;
250  }
251  }
252 
253  public IEnumerable<Arc> Arcs(ArcFilter filter = ArcFilter.All)
254  {
255  if (filter == ArcFilter.All) return arcs;
256  if (edgeCount == 0) return Enumerable.Empty<Arc>();
257  return arcs.Where(arc => IsEdge(arc));
258  }
259 
260  public IEnumerable<Arc> Arcs(Node u, ArcFilter filter = ArcFilter.All)
261  {
262  return this.ArcsHelper(u, filter);
263  }
264 
265  public IEnumerable<Arc> Arcs(Node u, Node v, ArcFilter filter = ArcFilter.All)
266  {
267  return Arcs(u, filter).Where(arc => this.Other(arc, u) == v);
268  }
269 
270  public int NodeCount()
271  {
272  return nodeCount;
273  }
274 
275  public int ArcCount(ArcFilter filter = ArcFilter.All)
276  {
277  return filter == ArcFilter.All ? arcs.Count : edgeCount;
278  }
279 
280  public int ArcCount(Node u, ArcFilter filter = ArcFilter.All)
281  {
282  return Arcs(u, filter).Count();
283  }
284 
285  public int ArcCount(Node u, Node v, ArcFilter filter = ArcFilter.All)
286  {
287  return Arcs(u, v, filter).Count();
288  }
289 
290  public bool HasNode(Node node)
291  {
292  return prevArc.ContainsKey(node) || (node != Node.Invalid && node == FirstNode);
293  }
294 
295  public bool HasArc(Arc arc)
296  {
297  return arcs.Contains(arc);
298  }
299  }
300 
310  public sealed class PathGraph : IPath
311  {
312  private readonly int nodeCount;
313  private readonly bool isCycle, directed;
314 
315  public Node FirstNode { get { return nodeCount > 0 ? new Node(1) : Node.Invalid; } }
316  public Node LastNode { get { return nodeCount > 0 ? new Node(isCycle ? 1 : nodeCount) : Node.Invalid; } }
317 
318  public enum Topology
319  {
321  Path,
323  Cycle
324  }
325 
326  public PathGraph(int nodeCount, Topology topology, Directedness directedness)
327  {
328  this.nodeCount = nodeCount;
329  isCycle = (topology == Topology.Cycle);
330  directed = (directedness == Directedness.Directed);
331  }
332 
335  public Node GetNode(int index)
336  {
337  return new Node(1L + index);
338  }
339 
342  public int GetNodeIndex(Node node)
343  {
344  return (int)(node.Id - 1);
345  }
346 
347  public Arc NextArc(Node node)
348  {
349  if (!isCycle && node.Id == nodeCount) return Arc.Invalid;
350  return new Arc(node.Id);
351  }
352 
353  public Arc PrevArc(Node node)
354  {
355  if (node.Id == 1)
356  return isCycle ? new Arc(nodeCount) : Arc.Invalid;
357  return new Arc(node.Id - 1);
358  }
359 
360  public Node U(Arc arc)
361  {
362  return new Node(arc.Id);
363  }
364 
365  public Node V(Arc arc)
366  {
367  return new Node(arc.Id == nodeCount ? 1 : arc.Id + 1);
368  }
369 
370  public bool IsEdge(Arc arc)
371  {
372  return !directed;
373  }
374 
375  public IEnumerable<Node> Nodes()
376  {
377  for (int i = 1; i <= nodeCount; i++)
378  yield return new Node(i);
379  }
380 
381  public IEnumerable<Arc> Arcs(ArcFilter filter = ArcFilter.All)
382  {
383  if (directed && filter == ArcFilter.Edge) yield break;
384  for (int i = 1, n = ArcCountInternal(); i <= n; i++)
385  yield return new Arc(i);
386  }
387 
388  public IEnumerable<Arc> Arcs(Node u, ArcFilter filter = ArcFilter.All)
389  {
390  return this.ArcsHelper(u, filter);
391  }
392 
393  public IEnumerable<Arc> Arcs(Node u, Node v, ArcFilter filter = ArcFilter.All)
394  {
395  return Arcs(u, filter).Where(arc => this.Other(arc, u) == v);
396  }
397 
398  public int NodeCount()
399  {
400  return nodeCount;
401  }
402 
403  private int ArcCountInternal()
404  {
405  return nodeCount == 0 ? 0 : (isCycle ? nodeCount : nodeCount - 1);
406  }
407 
408  public int ArcCount(ArcFilter filter = ArcFilter.All)
409  {
410  return directed && filter == ArcFilter.Edge ? 0 : ArcCountInternal();
411  }
412 
413  public int ArcCount(Node u, ArcFilter filter = ArcFilter.All)
414  {
415  return Arcs(u, filter).Count();
416  }
417 
418  public int ArcCount(Node u, Node v, ArcFilter filter = ArcFilter.All)
419  {
420  return Arcs(u, v, filter).Count();
421  }
422 
423  public bool HasNode(Node node)
424  {
425  return node.Id >= 1 && node.Id <= nodeCount;
426  }
427 
428  public bool HasArc(Arc arc)
429  {
430  return arc.Id >= 1 && arc.Id <= ArcCountInternal();
431  }
432  }
433 }