def collapse(pah, **m):
  """Returns the marginal for the dimensions supplied.

  First we slice the matrix where we want
  Then we marginalize over the dimensions we want

  :param pah: the histogram
  :param m: each keyword argument must match a dimension
            if the value of the argument is None, then we keep that dimension
            if the value is a tuple (i, j), we slice out i:j from that dimension and then marginalize
            dimensions not mentioned are fully marginalized
  :return:
  """
  assert all(n in pah.dims for n in m.keys()), 'Mistake in dimension names'
  slices = tuple(slice(*(m.get(k, None) or [None])) for k in pah.dims)
  # slices = [..., slice(None), slice(i, j), .... ]
  # here slice(None) is for both the margin dimensions as well as the fully marginalized dimensions
  # slice(i, j) is for the partially marginalized dimensions
  collapse_idx_l = tuple(i for i in range(len(pah.dims))
                         if pah.dims[i] not in [d for d, v in m.items() if v is None])

  new_pah = pah[slices].sum(axis=collapse_idx_l)
  new_pah.attrs = pah.attrs  # sum does not copy these over, unfortunately
  return new_pah