def hamiltonian_cycles_brute_force(operational_limit=nil)
      stack = DS::Stack.new
      return [] if @vertices.empty?

      origin_vertex = @vertices.to_a[0]
      hamiltonians = []
      num_operations = 0

      path = Path.new
      path << origin_vertex
      stack.push path
      while path = stack.pop
        last_vertex = path[path.length-1]
        if last_vertex == origin_vertex and path.length > 1
          # Cycle of some sort detected. Is it Hamiltonian?
          if path.length == vertices.length + 1
            # Found a Hamiltonian path. Yield or save it for later
            hpath = path.copy[0...(path.length-1)]
            if block_given?
              yield hpath
            else
              hamiltonians << hpath
            end
          else
            # non-Hamiltonian path found. Ignore
          end

        elsif path.find_index(last_vertex) != path.length - 1
          # Found a loop, go no further

        else
          # No loop, just another regular thing.
          neighbours(last_vertex).each do |neighbour|
            unless operational_limit.nil?
              num_operations += 1
              if num_operations > operational_limit
                raise OperationalLimitReachedException
              end
            end
            new_path = Path.new(path.copy+[neighbour])
            stack.push new_path
          end
        end
      end

      return hamiltonians
    end
def hamiltonian_cycles_brute_force(operational_limit=nil)
      stack = DS::Stack.new
      return [] if @vertices.empty?

      origin_vertex = @vertices.to_a[0]
      hamiltonians = []
      num_operations = 0

      path = Path.new
      path << origin_vertex
      stack.push path
      while path = stack.pop
        last_vertex = path[path.length-1]
        if last_vertex == origin_vertex and path.length > 1
          # Cycle of some sort detected. Is it Hamiltonian?
          if path.length == vertices.length + 1
            # Found a Hamiltonian path. Yield or save it for later
            hpath = path.copy[0...(path.length-1)]
            if block_given?
              yield hpath
            else
              hamiltonians << hpath
            end
          else
            # non-Hamiltonian path found. Ignore
          end

        elsif path.find_index(last_vertex) != path.length - 1
          # Found a loop, go no further

        else
          # No loop, just another regular thing.
          neighbours(last_vertex).each do |neighbour|
            unless operational_limit.nil?
              num_operations += 1
              if num_operations > operational_limit
                raise OperationalLimitReachedException
              end
            end
            new_path = Path.new(path.copy+[neighbour])
            stack.push new_path
          end
        end
      end

      return hamiltonians
    end
Run depth first search, returning an array of Hamiltonian paths.
 Or, if a block is given, yield each Hamiltonian path that comes
 along (in no defined order), and don't return the array (to potentially
 save RAM).

 The operational limit is used to make sure this algorithm doesn't
 get out of hand - only this many 'operations' are used when traversing
 the graph, as in #hamiltonian_paths_brute_force. When nil, there is no operational
 limit