예제 #1
0
 protected void AssertRootInGraph([NotNull] TVertex root)
 {
     if (!VisitedGraph.ContainsVertex(root))
     {
         throw new VertexNotFoundException("Root vertex is not part of the graph.");
     }
 }
예제 #2
0
        /// <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);
        }
예제 #3
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.");
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        /// <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);
                    }
                }
            }
        }