import itertools


def _get_all_changes(num_chunks, max_num_flips):
  """Get all changes of Hamming distance up to max_num_flips.

  Args:
    num_chunks: Positive integer, the total number of chunks that can be
        flipped.
    max_num_flips: Positive integer, the maximum number of indices of the
        bang-bang protocol that can be changed (k).

  Returns:
    A generator over all possible changes of Hamming distance k, each described
    by a list of indices of length at most k, where each index corresponds
    to a change.

  Raises:
    ValueError: If 0 < max_num_flips <= num_chunks is not true.
  """
  if max_num_flips <= 0:
    raise ValueError('max_num_flips should be positive, not %d' % max_num_flips)
  if num_chunks < max_num_flips:
    raise ValueError('num_chunks should be at least max_num_flips')
  return itertools.chain.from_iterable(
      itertools.combinations(range(num_chunks), i)
      for i in range(1, max_num_flips + 1)
  )