private void OnVertexDiscovered([NotNull] TVertex vertex)
        {
            Debug.Assert(vertex != null);

            VisitedGraph.AddVertex(vertex);
            _unExploredVertices.Enqueue(vertex);

            DiscoverVertex?.Invoke(vertex);
        }
        /// <inheritdoc />
        protected override void InternalCompute()
        {
            foreach (DataTable table in DataSet.Tables)
            {
                VisitedGraph.AddVertex(table);
            }

            foreach (DataRelation relation in DataSet.Relations)
            {
                VisitedGraph.AddEdge(new DataRelationEdge(relation));
            }
        }
        /// <inheritdoc />
        protected override void InternalCompute()
        {
            if (Augmented)
            {
                throw new InvalidOperationException("Graph already augmented.");
            }

            SuperSource = VertexFactory();
            VisitedGraph.AddVertex(SuperSource);
            OnSuperSourceAdded(SuperSource);

            SuperSink = VertexFactory();
            VisitedGraph.AddVertex(SuperSink);
            OnSuperSinkAdded(SuperSink);

            AugmentGraph();
            Augmented = true;
        }
        /// <summary>
        /// Runs the graph balancing algorithm.
        /// </summary>
        /// <exception cref="InvalidOperationException">If the graph is already balanced.</exception>
        public void Balance()
        {
            if (Balanced)
            {
                throw new InvalidOperationException("Graph already balanced.");
            }

            // Step 0
            // Create new balancing source and sink
            BalancingSource = VertexFactory();
            VisitedGraph.AddVertex(BalancingSource);
            OnBalancingSourceAdded();

            BalancingSink = VertexFactory();
            VisitedGraph.AddVertex(BalancingSink);
            OnBalancingSinkAdded();

            // Step 1
            // Link balancing source to the flow source
            BalancingSourceEdge = EdgeFactory(BalancingSource, Source);
            VisitedGraph.AddEdge(BalancingSourceEdge);
            Capacities.Add(BalancingSourceEdge, double.MaxValue);
            _preFlow.Add(BalancingSourceEdge, 0);
            OnEdgeAdded(BalancingSourceEdge);

            // Link the flow sink to the balancing sink
            BalancingSinkEdge = EdgeFactory(Sink, BalancingSink);
            VisitedGraph.AddEdge(BalancingSinkEdge);
            Capacities.Add(BalancingSinkEdge, double.MaxValue);
            _preFlow.Add(BalancingSinkEdge, 0);
            OnEdgeAdded(BalancingSinkEdge);

            // Step 2
            // For each surplus vertex v, add (source -> v)
            foreach (TVertex vertex in VisitedGraph.Vertices.Where(v => !IsSourceOrSink(v)))
            {
                int balancingIndex = GetBalancingIndex(vertex);
                if (balancingIndex == 0)
                {
                    continue;
                }

                if (balancingIndex < 0)
                {
                    // Surplus vertex
                    TEdge edge = EdgeFactory(BalancingSource, vertex);
                    VisitedGraph.AddEdge(edge);

                    _surplusEdges.Add(edge);
                    _surplusVertices.Add(vertex);

                    _preFlow.Add(edge, 0);

                    Capacities.Add(edge, -balancingIndex);

                    OnSurplusVertexAdded(vertex);
                    OnEdgeAdded(edge);
                }
                else
                {
                    // Deficient vertex
                    TEdge edge = EdgeFactory(vertex, BalancingSink);

                    _deficientEdges.Add(edge);
                    _deficientVertices.Add(vertex);

                    _preFlow.Add(edge, 0);

                    Capacities.Add(edge, balancingIndex);

                    OnDeficientVertexAdded(vertex);
                    OnEdgeAdded(edge);
                }
            }

            Balanced = true;

            #region Local function

            bool IsSourceOrSink(TVertex v)
            {
                return(v.Equals(BalancingSource) ||
                       v.Equals(BalancingSink) ||
                       v.Equals(Source) ||
                       v.Equals(Sink));
            }

            #endregion
        }