docs: def measure_density_matrix(
      density_matrix: np.ndarray,
      indices: List[int],
      out: np.ndarray = None) -> Tuple[List[bool], np.ndarray]:
      """Performs a measurement of the density matrix in the computational basis.
  
      This does not modify `density_matrix` unless the optional `out` is
      `density_matrix`.
  
      Args:
          density_matrix: The density matrix to be measured. This matrix is
              assumed to be positive semidefinite and trace one. The matrix is
              assumed to be of shape (2 ** integer, 2 ** integer) or
              (2, 2, ..., 2).
          indices: Which qubits are measured. The matrix is assumed to be supplied
              in big endian order. That is the xth index of v, when expressed as
              a bitstring, has the largest values in the 0th index.
          out: An optional place to store the result. If `out` is the same as
              the `density_matrix` parameter, then `density_matrix` will be
              modified inline. If `out` is not None, then the result is put into
              `out`.  If `out` is None a new value will be allocated. In all of
              these cases `out` will be the same as the returned ndarray of the
              method. The shape and dtype of `out` will match that of
              `density_matrix` if `out` is None, otherwise it will match the
              shape and dtype of `out`.
  
      Returns:
          A tuple of a list and an numpy array. The list is an array of booleans
          corresponding to the measurement values (ordered by the indices). The
          numpy array is the post measurement matrix. This matrix has the same
          shape and dtype as the input matrix.
  
      Raises:
          ValueError if the dimension of the matrix is not compatible with a
              matrix of n qubits.
          IndexError if the indices are out of range for the number of qubits
              corresponding to the density matrix.
      """
      num_qubits = _validate_num_qubits(density_matrix)
      _validate_indices(num_qubits, indices)
  
      if len(indices) == 0:
          if out is None:
              out = np.copy(density_matrix)
          elif out is not density_matrix:
              np.copyto(dst=out, src=density_matrix)
          return ([], out)
          # Final else: if out is matrix then matrix will be modified in place.
  
      # Cache initial shape.
      initial_shape = density_matrix.shape
  
      # Calculate the measurement probabilities and then make the measurement.
      probs = _probs(density_matrix, indices, num_qubits)
      result = np.random.choice(len(probs), p=probs)
      measurement_bits = [(1 & (result >> i)) for i in range(len(indices))]
  
      # Calculate the slice for the measurement result.
      result_slice = linalg.slice_for_qubits_equal_to(indices, result,
                                                      num_qubits=num_qubits)
      # Create a mask which is False for only the slice.
      mask = np.ones([2] * 2 * num_qubits, dtype=bool)
      # Remove ellipses from last element of
      mask[result_slice * 2] = False
  
      if out is None:
          out = np.copy(density_matrix)
      elif out is not density_matrix:
          np.copyto(dst=out, src=density_matrix)
      # Final else: if out is matrix then matrix will be modified in place.
  
      # Potentially reshape to tensor, and then set masked values to 0.
      out.shape = [2] * num_qubits * 2
      out[mask] = 0
  
      # Restore original shape (if necessary) and renormalize.
      out.shape = initial_shape
      out /= probs[result]
  
      return measurement_bits, out