Coverage for qml_essentials / states.py: 97%

29 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-09-03 21:15 +0000

1r"""State-preparation utilities. 

2 

3Constructors for input statevectors used in trainability and barren-plateau 

4analysis. All functions return a dense statevector of shape :math:`(2^n,)` 

5with qubit 0 leftmost (most significant), consistent with 

6:mod:`qml_essentials.algebra` and ``g_purity_from_basis``. The arrays are plain 

7numpy and auto-convert to the jnp ``initial_state`` accepted by 

8:meth:`jaqsi.script.Script.execute`. 

9 

10- :func:`dicke_state` builds the permutation-symmetric Dicke state 

11 :math:`|D_{n,k}\rangle`. 

12- :func:`haar_state` builds a Haar-random pure state. 

13- :func:`graph_state_vector` builds the graph state :math:`\prod_{(i,j)} CZ_{ij} 

14 H^{\otimes n}|0\rangle` for a given edge set, with :func:`matching_edges`, 

15 :func:`path_edges`, and :func:`complete_edges` as standard edge-set 

16 constructors. 

17""" 

18 

19from typing import Iterable, List, Tuple, Union 

20 

21import numpy as np 

22 

23 

24def dicke_state(n: int, k: int) -> np.ndarray: 

25 r"""Return the Dicke state :math:`|D_{n,k}\rangle`. 

26 

27 The permutation-symmetric equal superposition of all computational basis 

28 states of Hamming weight :math:`k`. 

29 

30 Args: 

31 n: Number of qubits. 

32 k: Hamming weight, with :math:`0 \leq k \leq n`. 

33 

34 Returns: 

35 The normalised statevector of shape :math:`(2^n,)` (qubit 0 leftmost). 

36 

37 Raises: 

38 ValueError: If ``n < 1`` or ``k`` is outside ``[0, n]``. 

39 """ 

40 if n < 1: 

41 raise ValueError(f"n must be at least 1, got {n}") 

42 if not 0 <= k <= n: 

43 raise ValueError(f"k must satisfy 0 <= k <= n, got k={k} for n={n}") 

44 psi = np.zeros(2**n, dtype=complex) 

45 idx = [x for x in range(2**n) if bin(x).count("1") == k] 

46 psi[idx] = 1.0 

47 return psi / np.linalg.norm(psi) 

48 

49 

50def haar_state( 

51 n: int, seed: Union[int, np.random.Generator, None] = None 

52) -> np.ndarray: 

53 r"""Return a Haar-random pure state. 

54 

55 Drawn as a normalised complex Gaussian vector, which is uniform with respect 

56 to the Haar measure on pure states. 

57 

58 Args: 

59 n: Number of qubits. 

60 seed: Source of randomness. An ``int`` seed, a 

61 :class:`numpy.random.Generator`, or ``None`` for fresh entropy. 

62 

63 Returns: 

64 The normalised statevector of shape :math:`(2^n,)`. 

65 """ 

66 rng = seed if isinstance(seed, np.random.Generator) else np.random.default_rng(seed) 

67 v = rng.normal(size=2**n) + 1j * rng.normal(size=2**n) 

68 return v / np.linalg.norm(v) 

69 

70 

71def graph_state_vector(n: int, edges: Iterable[Tuple[int, int]]) -> np.ndarray: 

72 r"""Return the explicit graph-state statevector for the given edges. 

73 

74 The graph state is :math:`\prod_{(i,j) \in E} CZ_{ij} H^{\otimes n}|0\rangle`. 

75 Each :math:`CZ` flips the sign of the amplitudes whose two qubits are both 

76 one. 

77 

78 Args: 

79 n: Number of qubits. 

80 edges: Iterable of qubit-index pairs :math:`(i, j)`. 

81 

82 Returns: 

83 The statevector of shape :math:`(2^n,)` (qubit 0 leftmost). 

84 """ 

85 psi = np.ones(2**n, dtype=complex) / np.sqrt(2**n) # H^n|0> 

86 idx = np.arange(2**n) 

87 for i, j in edges: 

88 bi = (idx >> (n - 1 - i)) & 1 # qubit 0 is most significant 

89 bj = (idx >> (n - 1 - j)) & 1 

90 psi = psi * np.where(bi & bj, -1.0, 1.0) 

91 return psi 

92 

93 

94def matching_edges(n: int) -> List[Tuple[int, int]]: 

95 r"""Return the perfect-matching edges :math:`(0,1),(2,3),\dots`. 

96 

97 Yields a disconnected graph state (a product of two-qubit graph states) with 

98 low entanglement. 

99 

100 Args: 

101 n: Number of qubits. 

102 

103 Returns: 

104 The list of edge pairs. 

105 """ 

106 return [(i, i + 1) for i in range(0, n - 1, 2)] 

107 

108 

109def path_edges(n: int) -> List[Tuple[int, int]]: 

110 r"""Return the path edges :math:`0\text{-}1\text{-}\dots\text{-}(n-1)`. 

111 

112 Yields a connected one-dimensional cluster state. 

113 

114 Args: 

115 n: Number of qubits. 

116 

117 Returns: 

118 The list of edge pairs. 

119 """ 

120 return [(i, i + 1) for i in range(n - 1)] 

121 

122 

123def complete_edges(n: int) -> List[Tuple[int, int]]: 

124 r"""Return the complete-graph edges of :math:`K_n`. 

125 

126 Yields a connected, permutation-symmetric graph state. 

127 

128 Args: 

129 n: Number of qubits. 

130 

131 Returns: 

132 The list of edge pairs :math:`(i, j)` with :math:`i < j`. 

133 """ 

134 return [(i, j) for i in range(n) for j in range(i + 1, n)]