Source code for qugradlab.hilbert_spaces._qudit_hilbert_spaces
1from typing import Optional, Iterable, Union
2from abc import ABC, abstractmethod
3from ._get_digit import get_digit
4
5import numpy as np
6
7from qugrad import HilbertSpace
8
9
[docs]
10class QuditSpace(HilbertSpace, ABC):
11 """
12 An abstract class defining the Hilbert space for a collection of qudits.
13 """
[docs]
14 @abstractmethod
15 def computational_projector(self) -> np.ndarray[bool]:
16 """
17 Important
18 ---------
19 This is an abstract method.
20
21
22 Generates a boolean filter for the computation basis states in
23 :attr:`basis`.
24
25 Returns
26 -------
27 NDArray[Shape[:attr:`dim`], bool]
28 A boolean filter for the computation basis states in
29 :attr:`basis`.
30 """
31 ...
[docs]
32 def computational_subspace(self) -> HilbertSpace:
33 """
34 Initialises a :class:`qugrad.HilbertSpace` corresponding the computation
35 subspace.
36
37 Returns
38 -------
39 qugrad.HilbertSpace
40 The computational subspace
41 """
42 return self.get_subspace(self.computational_projector())
[docs]
43 def dialate_operator(self, operator: np.ndarray) -> np.ndarray:
44 r"""
45 Dialates an operator $\hat O$ that acts on the computational subspace to
46 an operator $\hat O\oplus 0$ that acts on the whole Hilbert space.
47
48 Parameters
49 ----------
50 operator : NDArray[Shape[``computational_subspace().dim``, ``computational_subspace().dim``] complex]
51 The operator that acts on the computational subspace
52
53 Returns
54 -------
55 NDArray[Shape[:attr:`dim`, :attr:`dim`] complex]
56 The dialated operator that acts on the whole Hilbert space
57 """
58 proj = np.identity(self.dim)[self.computational_projector()]
59 return proj.T@operator@proj
[docs]
60 def project_operator(self, operator: np.ndarray) -> np.ndarray:
61 """
62 Projects an operator that acts on the Hilbert space to an
63 operator that acts only on the computational subspace.
64
65 Parameters
66 ----------
67 operator : NDArray[Shape[:attr:`dim`, :attr:`dim`] complex]
68 The operator that acts on the whole Hilbert space
69
70 Returns
71 -------
72 NDArray[Shape[``computational_subspace().dim``, ``computational_subspace().dim``] complex]
73 The projected operator that acts on the computational subspace.
74 """
75 proj = self.computational_projector()
76 return operator[proj][:, proj]
77
[docs]
78class QubitSpace(QuditSpace):
79 """
80 A computational Hilbert space.
81 """
82
83 _qubits: int
84 "The number of qubits"
85
[docs]
86 def __init__(self, qubits: int):
87 """
88 Initialises a :class:`QubitSpace`
89
90 Parameters
91 ----------
92 qubits : int
93 The number of qubits
94 """
95 self._qubits = qubits
96 super().__init__(np.arange(2**qubits))
97 @property
98 def qubits(self) -> int:
99 "The number of qubits"
100 return self._qubits
[docs]
101 def computational_projector(self):
102 """
103 Generates a boolean filter for the computation basis states in
104 :attr:`basis`.
105
106 Returns
107 -------
108 NDArray[Shape[:attr:`dim`], bool]
109 A boolean filter for the computation basis states in
110 :attr:`basis`.
111 """
112 return np.ones(len(self), dtype=bool)
113 @staticmethod
114 def _labels(digits: Iterable[str]) -> str:
115 """
116 Generates a strings that represent the state specified by the `digits`.
117
118 Parameters
119 ----------
120 digits : Iterable[str]
121 The digits representing the state
122
123 Returns
124 -------
125 str
126 The label for the specified state.
127 """
128 return f"|{''.join(digits)}⟩"
[docs]
129 def labels(self,
130 states: Optional[Union[int, list[int]]] = None
131 ) -> Union[str, list[str]]:
132 """
133 Generates a string (list of strings) that represent the state(s).
134
135 Parameters
136 ----------
137 states : int | list[int], optional
138 The state(s) to label. If ``None`` then the labels for all states in
139 :attr:`basis` are returned. By default ``None``.
140
141 Returns
142 -------
143 str | list[str]
144 The label(s) for the specified states.
145 """
146 if states is None: states = self.basis
147 digits = get_digit(states,
148 2,
149 np.arange(self._qubits)
150 ).astype(str)
151 if isinstance(states, int):
152 return self._labels(digits)
153 return [self._labels(d) for d in digits]