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

def permutation_to_disjoint_cycles(permutation):
    """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
    """
    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