code: def permutation_to_disjoint_cycles(permutation):
      
      if not check_permutation(permutation):
          raise BadPermutationError('Malformed permutation %r' % permutation)
  
      p_index = 0
      current_cycle = [0]
  
      # keep track of all remaining/unvisited indices
      permutation_nums = list(range(1,len(permutation)))
  
      cycles = []
      while True:
          # find next image point in cycle
          p_index = permutation[p_index]
  
          # if back at start of cycle
          if p_index == current_cycle[0]:
  
              # store cycle
              cycles.append(current_cycle)
  
              try:
                  # retrieve the next lowest un-used image point
                  p_index = permutation_nums.pop(0)
                  current_cycle = [p_index]
  
              except IndexError:
                  break
          else:
              permutation_nums.remove(p_index)
              current_cycle.append(p_index)
  
      return cycles
docs: Any permutation sigma can be represented as a product of cycles.
      A cycle (c_1, .. c_n) is a closed sequence of indices such that
  
        sigma(c_1) == c_2, sigma(c_2) == sigma^2(c_1)== c_3, ..., sigma(c_(n-1)) == c_n, sigma(c_n) == c_1
  
      Any single length-n cycle admits n equivalent representations in
      correspondence with which element one defines as c_1.
  
          (0,1,2) == (1,2,0) == (2,0,1)
  
      A decomposition into *disjoint* cycles can be made unique, by requiring
      that the cycles are sorted by their smallest element, which is also the
      left-most element of each cycle. Note that permutations generated by
      disjoint cycles commute.  E.g.,
  
          (1, 0, 3, 2) == ((1,0),(3,2)) --> ((0,1),(2,3)) normal form
  
      :param permutation: A valid permutation image tuple
      :type permutation: tuple
      :return: A list of disjoint cycles, that when comb
      :rtype: list
      :raise: BadPermutationError