 
 // MARK: - cycle
 extension DIGraph {
-  fileprivate struct Cycle: Hashable {
-    let vertexIndices: [Int]
-    let edges: [DIEdge]
-  }
+  fileprivate typealias Cycle = CycleFinder.Cycle
 
   private func checkGraphForCycles() -> Bool {
-    let edgeCount = adjacencyList.map { $0.map { $0.toIndices.count }.reduce(0, +) }.reduce(0, +)
-
-    let cycles = findAllCycles()
+    let cycles = CycleFinder(in: self).findAllCycles()
 
     func calculateAverageLength() -> Double {
       let summaryVerticesCount = cycles.map { $0.vertexIndices.count }.reduce(0, +)

    return visited
  }

  private func findCycles(from vertexIndex: Int) -> [DIGraph.Cycle] {
    startVertexIndex = vertexIndex
    counterVertices = 0
    maxDepth = 0
    result = []
    noCycleVertices = []
    // dfs
    findCycles(currentVertexIndex: vertexIndex,
               visitedVertices: [],
               visitedEdges: [])

    print("Found: \(result.count) cycles. Saw vertices \(counterVertices) max depth: \(maxDepth)")
    return result
  }

  private func findCycles(currentVertexIndex: Int,
                          visitedVertices: [Int], // need order for subcycle
                          visitedEdges: [DIEdge]) {
    if currentVertexIndex == startVertexIndex && !visitedVertices.isEmpty {
      assert(visitedVertices.count == visitedEdges.count)

      let cycle = DIGraph.Cycle(vertexIndices: visitedVertices, edges: visitedEdges)
      result.append(cycle)
      return
    }


      return
    }

    // first check - current vertex find ALL cycles via current vertex.
    // Second check - current vertex guaranted not cycles via startVertexIndex.
    if currentVertexIndex < startVertexIndex || !reachability[currentVertexIndex].contains(startVertexIndex) {
      return
    }

    let visitedVertices = visitedVertices + [currentVertexIndex]

    for (edge, toIndices) in graph.adjacencyList[currentVertexIndex] {
      let visitedEdges = visitedEdges + [edge]
