protected void AssertRootInGraph([NotNull] TVertex root) { if (!VisitedGraph.ContainsVertex(root)) { throw new VertexNotFoundException("Root vertex is not part of the graph."); } }
/// <inheritdoc /> protected override void Initialize() { base.Initialize(); FoundNegativeCycle = false; // Initialize colors and distances VerticesColors.Clear(); foreach (TVertex vertex in VisitedGraph.Vertices) { VerticesColors[vertex] = GraphColor.White; SetVertexDistance(vertex, double.PositiveInfinity); OnInitializeVertex(vertex); } if (!TryGetRootVertex(out TVertex root)) { // Try to fallback on first vertex, will throw if the graph is empty root = VisitedGraph.Vertices.First(); } else if (!VisitedGraph.ContainsVertex(root)) { throw new VertexNotFoundException("Root vertex is not part of the graph."); } SetVertexDistance(root, 0); }
/// <inheritdoc /> protected override void Initialize() { base.Initialize(); if (!_reverserAlgorithm.Augmented) { throw new InvalidOperationException( $"The graph has not been augmented yet.{Environment.NewLine}" + $"Call {nameof(ReversedEdgeAugmentorAlgorithm<int, Edge<int>>)}.{nameof(ReversedEdgeAugmentorAlgorithm<int, Edge<int>>.AddReversedEdges)}() before running this algorithm."); } if (Source == null) { throw new InvalidOperationException("Source is not specified."); } if (Sink == null) { throw new InvalidOperationException("Sink is not specified."); } if (!VisitedGraph.ContainsVertex(Source)) { throw new VertexNotFoundException("Source vertex is not part of the graph."); } if (!VisitedGraph.ContainsVertex(Sink)) { throw new VertexNotFoundException("Sink vertex is not part of the graph."); } }
private void ComputeFromRoot([NotNull] TVertex rootVertex) { Debug.Assert(rootVertex != null); Debug.Assert(VisitedGraph.ContainsVertex(rootVertex)); Debug.Assert(VerticesColors[rootVertex] == GraphColor.White); VerticesColors[rootVertex] = GraphColor.Gray; SetVertexDistance(rootVertex, 0); ComputeNoInit(rootVertex); }
/// <summary> /// Runs the algorithm with the given <paramref name="root"/> vertex. /// </summary> /// <param name="root">Root vertex.</param> /// <exception cref="T:System.ArgumentNullException"><paramref name="root"/> is <see langword="null"/>.</exception> /// <exception cref="T:System.ArgumentException"><paramref name="root"/> is not part of <see cref="AlgorithmBase{TGraph}.VisitedGraph"/>.</exception> /// <exception cref="T:System.InvalidOperationException">Something went wrong when running the algorithm.</exception> public virtual void Compute([NotNull] TVertex root) { SetRootVertex(root); if (!VisitedGraph.ContainsVertex(root)) { throw new ArgumentException("Graph does not contain the provided root vertex.", nameof(root)); } Compute(); }
/// <summary> /// Runs a random tree generation starting at <paramref name="root"/> vertex. /// </summary> /// <param name="root">Tree starting vertex.</param> public void RandomTreeWithRoot([NotNull] TVertex root) { if (!VisitedGraph.ContainsVertex(root)) { throw new ArgumentException("The vertex must be in the graph.", nameof(root)); } SetRootVertex(root); Compute(); }
/// <summary> /// Sets the target vertex. /// </summary> /// <param name="target">Target vertex.</param> public void SetTargetVertex([NotNull] TVertex target) { if (!VisitedGraph.ContainsVertex(target)) { throw new ArgumentException("Target must be in the graph.", nameof(target)); } _target = target; _hasTargetVertex = true; }
/// <summary> /// Runs the algorithm with the given <paramref name="root"/> vertex. /// </summary> /// <param name="root">Root vertex.</param> /// <param name="target">Target vertex.</param> public void Compute(TVertex root, TVertex target) { if (!VisitedGraph.ContainsVertex(root)) { throw new ArgumentException("Root must be in the graph.", nameof(root)); } SetRootVertex(root); SetTargetVertex(target); Compute(); }
/// <summary> /// Runs the algorithm with the given <paramref name="root"/> vertex. /// </summary> /// <param name="root">Root vertex.</param> /// <param name="target">Target vertex.</param> /// <exception cref="T:System.ArgumentNullException"><paramref name="root"/> is <see langword="null"/>.</exception> /// <exception cref="T:System.ArgumentNullException"><paramref name="target"/> is <see langword="null"/>.</exception> /// <exception cref="T:System.ArgumentException"><paramref name="root"/> is not part of <see cref="AlgorithmBase{TGraph}.VisitedGraph"/>.</exception> /// <exception cref="T:System.ArgumentException"><paramref name="target"/> is not part of <see cref="AlgorithmBase{TGraph}.VisitedGraph"/>.</exception> /// <exception cref="T:System.InvalidOperationException">Something went wrong when running the algorithm.</exception> public void Compute([NotNull] TVertex root, [NotNull] TVertex target) { if (root == null) { throw new ArgumentNullException(nameof(root)); } SetTargetVertex(target); if (!VisitedGraph.ContainsVertex(target)) { throw new ArgumentException("Graph does not contain the provided target vertex.", nameof(target)); } Compute(root); }
private void ComputeNoInit([NotNull] TVertex root) { Debug.Assert(root != null); Debug.Assert(VisitedGraph.ContainsVertex(root)); UndirectedBreadthFirstSearchAlgorithm <TVertex, TEdge> bfs = null; try { bfs = new UndirectedBreadthFirstSearchAlgorithm <TVertex, TEdge>( this, VisitedGraph, _vertexQueue, VerticesColors); bfs.InitializeVertex += InitializeVertex; bfs.DiscoverVertex += DiscoverVertex; bfs.StartVertex += StartVertex; bfs.ExamineEdge += ExamineEdge; #if DEBUG bfs.ExamineEdge += edge => AssertHeap(); #endif bfs.ExamineVertex += ExamineVertex; bfs.FinishVertex += FinishVertex; bfs.TreeEdge += OnDijkstraTreeEdge; bfs.GrayTarget += OnGrayTarget; bfs.Visit(root); } finally { if (bfs != null) { bfs.InitializeVertex -= InitializeVertex; bfs.DiscoverVertex -= DiscoverVertex; bfs.StartVertex -= StartVertex; bfs.ExamineEdge -= ExamineEdge; bfs.ExamineVertex -= ExamineVertex; bfs.FinishVertex -= FinishVertex; bfs.TreeEdge -= OnDijkstraTreeEdge; bfs.GrayTarget -= OnGrayTarget; } } }
private void GenerateFromTransitionFactory( [NotNull] TVertex current, [NotNull] ITransitionFactory <TVertex, TEdge> transitionFactory) { if (current == null) { throw new ArgumentNullException(nameof(current)); } if (transitionFactory is null) { throw new ArgumentNullException(nameof(transitionFactory)); } if (!transitionFactory.IsValid(current)) { return; } foreach (TEdge transition in transitionFactory.Apply(current)) { if (!AddVertexPredicate(transition.Target) || !AddEdgePredicate(transition)) { OnEdgeSkipped(transition); continue; } bool backEdge = VisitedGraph.ContainsVertex(transition.Target); if (!backEdge) { OnVertexDiscovered(transition.Target); } VisitedGraph.AddEdge(transition); if (backEdge) { OnBackEdge(transition); } else { OnTreeEdge(transition); } } }
/// <summary> /// Initializes a new instance of the <see cref="GraphBalancerAlgorithm{TVertex,TEdge}"/> class. /// </summary> /// <param name="visitedGraph">Graph to visit.</param> /// <param name="source">Flow source vertex.</param> /// <param name="sink">Flow sink vertex.</param> /// <param name="vertexFactory">Vertex factory method.</param> /// <param name="edgeFactory">Edge factory method.</param> /// <param name="capacities">Edges capacities.</param> public GraphBalancerAlgorithm( [NotNull] IMutableBidirectionalGraph <TVertex, TEdge> visitedGraph, [NotNull] VertexFactory <TVertex> vertexFactory, [NotNull] EdgeFactory <TVertex, TEdge> edgeFactory, [NotNull] TVertex source, [NotNull] TVertex sink, [NotNull] IDictionary <TEdge, double> capacities) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (sink == null) { throw new ArgumentNullException(nameof(sink)); } VisitedGraph = visitedGraph ?? throw new ArgumentNullException(nameof(visitedGraph)); VertexFactory = vertexFactory ?? throw new ArgumentNullException(nameof(vertexFactory)); EdgeFactory = edgeFactory ?? throw new ArgumentNullException(nameof(edgeFactory)); if (!VisitedGraph.ContainsVertex(source)) { throw new ArgumentException("Source must be in the graph", nameof(source)); } if (!VisitedGraph.ContainsVertex(sink)) { throw new ArgumentException("Sink must be in the graph", nameof(sink)); } Source = source; Sink = sink; Capacities = capacities ?? throw new ArgumentNullException(nameof(capacities)); // Setting preflow = l(e) = 1 foreach (TEdge edge in VisitedGraph.Edges) { _preFlow.Add(edge, 1); } }
/// <summary> /// Initializes a new instance of the <see cref="GraphBalancerAlgorithm{TVertex,TEdge}"/> class. /// </summary> /// <param name="visitedGraph">Graph to visit.</param> /// <param name="source">Flow source vertex.</param> /// <param name="sink">Flow sink vertex.</param> /// <param name="vertexFactory">Vertex factory method.</param> /// <param name="edgeFactory">Edge factory method.</param> public GraphBalancerAlgorithm( IMutableBidirectionalGraph <TVertex, TEdge> visitedGraph, TVertex source, TVertex sink, VertexFactory <TVertex> vertexFactory, EdgeFactory <TVertex, TEdge> edgeFactory) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (sink == null) { throw new ArgumentNullException(nameof(sink)); } VisitedGraph = visitedGraph ?? throw new ArgumentNullException(nameof(visitedGraph)); VertexFactory = vertexFactory ?? throw new ArgumentNullException(nameof(vertexFactory)); EdgeFactory = edgeFactory ?? throw new ArgumentNullException(nameof(edgeFactory)); if (!VisitedGraph.ContainsVertex(source)) { throw new ArgumentException("Source must be in the graph", nameof(source)); } if (!VisitedGraph.ContainsVertex(sink)) { throw new ArgumentException("Sink must be in the graph", nameof(sink)); } Source = source; Sink = sink; foreach (TEdge edge in VisitedGraph.Edges) { // Setting capacities = u(e) = +infinity Capacities.Add(edge, double.MaxValue); // Setting preflow = l(e) = 1 _preFlow.Add(edge, 1); } }
/// <summary> /// Sets vertices pairs. /// </summary> /// <param name="pairs">Vertices pairs.</param> /// <exception cref="T:System.ArgumentNullException"><paramref name="pairs"/> is <see langword="null"/>.</exception> /// <exception cref="T:System.ArgumentException"><paramref name="pairs"/> is empty or any vertex from pairs is not part of <see cref="AlgorithmBase{TGraph}.VisitedGraph"/>.</exception> public void SetVertexPairs([NotNull] IEnumerable <SEquatableEdge <TVertex> > pairs) { if (pairs is null) { throw new ArgumentNullException(nameof(pairs)); } _pairs = pairs.ToArray(); if (_pairs.Length == 0) { throw new ArgumentException("Must have at least one vertex pair.", nameof(pairs)); } if (_pairs.Any(pair => !VisitedGraph.ContainsVertex(pair.Source))) { throw new ArgumentException("All pairs sources must be in the graph.", nameof(pairs)); } if (_pairs.Any(pair => !VisitedGraph.ContainsVertex(pair.Target))) { throw new ArgumentException("All pairs targets must be in the graph.", nameof(pairs)); } }
/// <inheritdoc /> protected override void InternalCompute() { TVertex root = GetAndAssertRootInGraph(); if (!TryGetTargetVertex(out TVertex target)) { throw new InvalidOperationException("Target vertex not set."); } if (!VisitedGraph.ContainsVertex(target)) { throw new VertexNotFoundException("Target vertex is not part of the graph."); } // Start by building the minimum tree starting from the target vertex. ComputeMinimumTree( target, out IDictionary <TVertex, TEdge> successors, out IDictionary <TVertex, double> distances); ThrowIfCancellationRequested(); var queue = new FibonacciQueue <DeviationPath, double>(deviationPath => deviationPath.Weight); int vertexCount = VisitedGraph.VertexCount; // First shortest path EnqueueFirstShortestPath(queue, successors, distances, root); while (queue.Count > 0 && ComputedShortestPathCount < ShortestPathCount) { ThrowIfCancellationRequested(); DeviationPath deviation = queue.Dequeue(); // Turn into path var path = new List <TEdge>(); for (int i = 0; i < deviation.DeviationIndex; ++i) { path.Add(deviation.ParentPath[i]); } path.Add(deviation.DeviationEdge); int startEdge = path.Count; AppendShortestPath(path, successors, deviation.DeviationEdge.Target); Debug.Assert(Math.Abs(deviation.Weight - path.Sum(e => _edgeWeights(e))) < float.Epsilon); Debug.Assert(path.Count > 0); // Add to list if has no cycle if (!path.HasCycles <TVertex, TEdge>()) { AddComputedShortestPath(path); } // Append new deviation paths if (path.Count < vertexCount) { EnqueueDeviationPaths( queue, root, distances, path.ToArray(), startEdge); } } }
/// <inheritdoc /> protected override void InternalCompute() { TVertex root = GetAndAssertRootInGraph(); if (!TryGetTargetVertex(out TVertex target)) { throw new InvalidOperationException("Target vertex not set."); } if (!VisitedGraph.ContainsVertex(target)) { throw new VertexNotFoundException("Target vertex is not part of the graph."); } // Little shortcut if (root.Equals(target)) { OnTargetReached(); return; // Found it } ICancelManager cancelManager = Services.CancelManager; var open = new BinaryHeap <double, TVertex>(_distanceRelaxer.Compare); // (1) Place the initial node in Open, with all its operators marked unused open.Add(0, root); Dictionary <TEdge, GraphColor> operators = VisitedGraph.OutEdges(root).ToDictionary(edge => edge, edge => GraphColor.White); while (open.Count > 0) { if (cancelManager.IsCancelling) { return; } // (3) Else, choose an Open node n of lowest cost for expansion KeyValuePair <double, TVertex> entry = open.RemoveMinimum(); double cost = entry.Key; TVertex n = entry.Value; // (4) If node n is a target node, terminate with success if (n.Equals(target)) { OnTargetReached(); return; } // (5) Else, expand node n, generating all // successors n' reachable via unused legal operators, // compute their cost and delete node n ExpandNode(n, operators, cost, open); #if DEBUG OperatorMaxCount = Math.Max(OperatorMaxCount, operators.Count); #endif // (6) In a directed graph, generate each predecessor node n via an unused operator // and create dummy nodes for each with costs of infinity foreach (TEdge edge in VisitedGraph.InEdges(n)) { if (operators.TryGetValue(edge, out GraphColor edgeColor) && edgeColor == GraphColor.Gray) { // Delete node n operators.Remove(edge); } } } }