docs: def dirac_notation(state: Sequence, decimals: int=2) -> str:
      """Returns the wavefunction as a string in Dirac notation.
  
      For example:
  
          state = np.array([1/np.sqrt(2), 1/np.sqrt(2)], dtype=np.complex64)
          print(dirac_notation(state)) -> 0.71|0⟩ + 0.71|1⟩
  
      Args:
          state: A sequence representing a wave function in which the ordering
              mapping to qubits follows the standard Kronecker convention of
              numpy.kron.
          decimals: How many decimals to include in the pretty print.
  
      Returns:
          A pretty string consisting of a sum of computational basis kets
          and non-zero floats of the specified accuracy.
      """
      perm_list = ["".join(seq) for seq in itertools.product(
          "01", repeat=int(len(state)).bit_length() - 1)]
      components = []
      ket = "|{}⟩"
      for x in range(len(perm_list)):
          format_str = "({:." + str(decimals) + "g})"
          # Python 2 rounds imaginary numbers to 0, so need to round separately.
          val = (round(state[x].real, decimals)
                 + 1j * round(state[x].imag, decimals))
          if round(val.real, decimals) == 0 and round(val.imag, decimals) != 0:
              val = val.imag
              format_str = "{:." + str(decimals) + "g}j"
          elif round(val.imag, decimals) == 0 and round(val.real, decimals) != 0:
              val = val.real
              format_str = "{:." + str(decimals) + "g}"
          if val != 0:
              if round(state[x], decimals) == 1:
                  components.append(ket.format(perm_list[x]))
              else:
                  components.append((format_str + ket).format(val, perm_list[x]))
      if not components:
          return '0'
  
      return ' + '.join(components).replace(' + -', ' - ')