docs: def block_perm_and_perms_within_blocks(permutation, block_structure):
      """Decompose a permutation into a block permutation and into permutations
      acting within each block.
  
      :param permutation: The overall permutation to be factored.
      :type permutation: tuple
      :param block_structure: The channel dimensions of the blocks
      :type block_structure: tuple
      :return: ``(block_permutation, permutations_within_blocks)``
       Where ``block_permutations`` is an image tuple for a permutation of the block indices
       and ``permutations_within_blocks`` is a list of image tuples for the permutations of the channels
       within each block
      :rtype: tuple
      """
      nblocks = len(block_structure)
  
      offsets = [sum(block_structure[:k]) for k in range(nblocks)]
      images = [permutation[offset: offset + length] for (offset, length) in zip(offsets, block_structure)]
  
      images_mins = list(map(min, images))
  
  
      key_block_perm_inv = lambda block_index: images_mins[block_index]
  
      block_perm_inv = tuple(sorted(range(nblocks), key = key_block_perm_inv))
      # print(images_mins)
      # print(permutation, block_structure, "-->", block_perm, invert_permutation(block_perm))
      block_perm = invert_permutation(block_perm_inv)
  
      assert images_mins[block_perm_inv[0]] == min(images_mins)
      assert images_mins[block_perm_inv[-1]] == max(images_mins)
  
      # block_perm = tuple(invert_permutation(block_perm_inv))
  
      perms_within_blocks = []
      for (offset, length, image) in zip(offsets, block_structure, images):
          block_key = lambda elt_index: image[elt_index]
          within_inv = sorted(range(length), key = block_key)
          within = invert_permutation(tuple(within_inv))
          assert permutation[within_inv[0] + offset] == min(image)
          assert permutation[within_inv[-1] + offset] == max(image)
          perms_within_blocks.append(within)
  
      return block_perm, perms_within_blocks