/// <summary>
        /// Attempts to break cycles in the graph by removing the deepest remove edge, as defined
        /// by the supplied predicate function.
        /// </summary>
        /// <param name="graph">The bidirectional graph to be processed.</param>
        /// <param name="isRemovable">A function indicating whether or not a particular edge can be removed (i.e. is a "soft" dependency).</param>
        /// <typeparam name="TVertex">The <see cref="Type" /> of the vertices of the graph.</typeparam>
        /// <typeparam name="TEdge">The <see cref="Type" /> of the edges of the graph.</typeparam>
        /// <returns>The list of edges that were removed to break the cycle(s).</returns>
        /// <exception cref="NonAcyclicGraphException">Occurs if one or more of the cycles present in the graph cannot be broken by removing one of its edges.</exception>
        public static IReadOnlyList <TEdge> BreakCycles <TVertex, TEdge>(this BidirectionalGraph <TVertex, TEdge> graph, Func <TEdge, bool> isRemovable)
            where TEdge : IEdge <TVertex>
        {
            var removedEdges = new List <TEdge>();

            // Get cyclical dependencies found in the graph
            var cycles = graph.GetCycles();

            // Break circular dependencies
            foreach (var cycle in cycles)
            {
                // Last element of Path repeats first element (so ignore duplicate)
                var distinctPathVertices = cycle.Path.Take(cycle.Path.Count - 1).ToArray();

                var sacrificialDependency = distinctPathVertices
                                            .Select(
                    (e, i) =>
                {
                    // Get the next entity in the path (circling around to the first entity on the last item)
                    var dependentVertex = distinctPathVertices[(i + 1) % distinctPathVertices.Length];

                    return(new
                    {
                        DependentVertex = dependentVertex,
                        CycleEdges = graph.InEdges(dependentVertex).Where(IsCycleEdge)
                    });
                })
                                            .Reverse()
                                            .FirstOrDefault(x => x.CycleEdges.All(isRemovable));

                if (sacrificialDependency == null)
                {
                    graph.ValidateGraph();

                    // Should never get here in this situation, but throw an exception to satisfy code analysis warnings
                    throw new NonAcyclicGraphException();
                }

                // Remove the chosen graph edge(s) to break the cyclical dependency
                foreach (TEdge edge in sacrificialDependency.CycleEdges.ToArray())
                {
                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug($"Edge '{edge.ToString()}' removed to prevent the following cycle: {string.Join(" --> ", cycle.Path.Select(x => x.ToString()))}");
                    }

                    graph.RemoveEdge(edge);
                    removedEdges.Add(edge);
                }

                bool IsCycleEdge(TEdge edge) => distinctPathVertices.Contains(edge.Source);
            }

            if (_logger.IsDebugEnabled)
            {
                _logger.Debug($@"The following edges were removed from the graph to prevent cycles:
{string.Join(Environment.NewLine, removedEdges.Select(x => x.ToString()))}");
            }

            return(removedEdges);
        }