oqubit 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,278 @@
1
+ from ..core.operators import Gate
2
+ from ..core.statevector import StateVector
3
+ from ..core.qubit import Qubit
4
+ from ..measurement import measure, sample
5
+ from .instruction import Instruction
6
+ class Circuit:
7
+ """
8
+ Represents a quantum circuit.
9
+
10
+ Parameters
11
+ ----------
12
+ num_qubits : int
13
+ Number of qubits in the circuit.
14
+ """
15
+ def __init__(self, num_qubits):
16
+ if not isinstance(num_qubits, int):
17
+ raise TypeError("num_qubits must be an integer.")
18
+ if num_qubits < 1:
19
+ raise ValueError("num_qubits must be at least 1.")
20
+ self.num_qubits = num_qubits
21
+ self.instructions = []
22
+ def _validate_qubit(self, qubit):
23
+ if not isinstance(qubit, int):
24
+ raise TypeError("Qubit index must be an integer.")
25
+ if qubit < 0 or qubit >= self.num_qubits:
26
+ raise IndexError(
27
+ f"Qubit index {qubit} is out of range for "
28
+ f"{self.num_qubits} qubits."
29
+ )
30
+ def _validate_qubits(self, qubits):
31
+ for qubit in qubits:
32
+ self._validate_qubit(qubit)
33
+ def _add_instruction(self, gate, controls=None, targets=None):
34
+ instruction = Instruction(
35
+ gate=gate,
36
+ controls=controls,
37
+ targets=targets,
38
+ )
39
+ self._validate_qubits(instruction.qubits)
40
+ self.instructions.append(instruction)
41
+ return self
42
+ def append(self, gate, controls=None, targets=None):
43
+ return self._add_instruction(
44
+ gate,
45
+ controls=controls,
46
+ targets=targets,
47
+ )
48
+ def x(self, qubit):
49
+ from ..gates.single import X
50
+
51
+ return self._add_instruction(
52
+ X,
53
+ targets=qubit,
54
+ )
55
+
56
+ def y(self, qubit):
57
+ from ..gates.single import Y
58
+
59
+ return self._add_instruction(
60
+ Y,
61
+ targets=qubit,
62
+ )
63
+
64
+ def z(self, qubit):
65
+ from ..gates.single import Z
66
+
67
+ return self._add_instruction(
68
+ Z,
69
+ targets=qubit,
70
+ )
71
+
72
+ def h(self, qubit):
73
+ from ..gates.single import H
74
+
75
+ return self._add_instruction(
76
+ H,
77
+ targets=qubit,
78
+ )
79
+
80
+ def s(self, qubit):
81
+ from ..gates.single import S
82
+
83
+ return self._add_instruction(
84
+ S,
85
+ targets=qubit,
86
+ )
87
+
88
+ def t(self, qubit):
89
+ from ..gates.single import T
90
+
91
+ return self._add_instruction(
92
+ T,
93
+ targets=qubit,
94
+ )
95
+
96
+ def sx(self, qubit):
97
+ from ..gates.single import SX
98
+
99
+ return self._add_instruction(
100
+ SX,
101
+ targets=qubit,
102
+ )
103
+ def cx(self, control, target):
104
+ from ..gates.controlled import CX
105
+
106
+ return self._add_instruction(
107
+ CX,
108
+ controls=control,
109
+ targets=target,
110
+ )
111
+
112
+ def cy(self, control, target):
113
+ from ..gates.controlled import CY
114
+
115
+ return self._add_instruction(
116
+ CY,
117
+ controls=control,
118
+ targets=target,
119
+ )
120
+
121
+ def cz(self, control, target):
122
+ from ..gates.controlled import CZ
123
+
124
+ return self._add_instruction(
125
+ CZ,
126
+ controls=control,
127
+ targets=target,
128
+ )
129
+
130
+ def ch(self, control, target):
131
+ from ..gates.controlled import CH
132
+
133
+ return self._add_instruction(
134
+ CH,
135
+ controls=control,
136
+ targets=target,
137
+ )
138
+
139
+ def cs(self, control, target):
140
+ from ..gates.controlled import CS
141
+
142
+ return self._add_instruction(
143
+ CS,
144
+ controls=control,
145
+ targets=target,
146
+ )
147
+
148
+ def ct(self, control, target):
149
+ from ..gates.controlled import CT
150
+
151
+ return self._add_instruction(
152
+ CT,
153
+ controls=control,
154
+ targets=target,
155
+ )
156
+
157
+ def csx(self, control, target):
158
+ from ..gates.controlled import CSX
159
+
160
+ return self._add_instruction(
161
+ CSX,
162
+ controls=control,
163
+ targets=target,
164
+ )
165
+ def swap(self, qubit1, qubit2):
166
+ from ..gates.multi import SWAP
167
+
168
+ return self._add_instruction(
169
+ SWAP,
170
+ targets=[qubit1, qubit2],
171
+ )
172
+
173
+ def iswap(self, qubit1, qubit2):
174
+ from ..gates.multi import ISWAP
175
+
176
+ return self._add_instruction(
177
+ ISWAP,
178
+ targets=[qubit1, qubit2],
179
+ )
180
+
181
+ def sqrt_swap(self, qubit1, qubit2):
182
+ from ..gates.multi import SQRT_SWAP
183
+
184
+ return self._add_instruction(
185
+ SQRT_SWAP,
186
+ targets=[qubit1, qubit2],
187
+ )
188
+
189
+ def ccx(self, control1, control2, target):
190
+ from ..gates.multi import CCX
191
+
192
+ return self._add_instruction(
193
+ CCX,
194
+ controls=[control1, control2],
195
+ targets=target,
196
+ )
197
+
198
+ def cswap(self, control, target1, target2):
199
+ from ..gates.multi import CSWAP
200
+
201
+ return self._add_instruction(
202
+ CSWAP,
203
+ controls=control,
204
+ targets=[target1, target2],
205
+ )
206
+ def initial_state(self):
207
+ qubits = [
208
+ Qubit.zero()
209
+ for _ in range(self.num_qubits)
210
+ ]
211
+
212
+ return StateVector(qubits)
213
+
214
+ def run(self, state=None):
215
+ if state is None:
216
+ state = self.initial_state()
217
+
218
+ if not isinstance(state, StateVector):
219
+ raise TypeError("state must be a StateVector.")
220
+
221
+ if state.num_qubits != self.num_qubits:
222
+ raise ValueError(
223
+ f"Circuit requires {self.num_qubits} qubits, "
224
+ f"but state contains {state.num_qubits}."
225
+ )
226
+
227
+ for instruction in self.instructions:
228
+ state.apply(
229
+ instruction.gate,
230
+ controls=instruction.controls,
231
+ targets=instruction.targets,
232
+ )
233
+
234
+ return state
235
+ def measure(self, state=None, qubits=None):
236
+ if state is None:
237
+ state = self.run()
238
+
239
+ return measure(
240
+ state,
241
+ qubits=qubits,
242
+ )
243
+
244
+ def sample(self, shots=1024, state=None, qubits=None):
245
+ if state is None:
246
+ state = self.run()
247
+
248
+ return sample(
249
+ state,
250
+ shots=shots,
251
+ qubits=qubits,
252
+ )
253
+ @property
254
+ def depth(self):
255
+ return len(self.instructions)
256
+ @property
257
+ def notation(self):
258
+ return self.run().notation
259
+ @property
260
+ def size(self):
261
+ return len(self.instructions)
262
+ def clear(self):
263
+ self.instructions.clear()
264
+ return self
265
+ def __repr__(self):
266
+ return (
267
+ f"Circuit("
268
+ f"num_qubits={self.num_qubits}, "
269
+ f"instructions={len(self.instructions)})"
270
+ )
271
+ def __len__(self):
272
+ return len(self.instructions)
273
+ def __str__(self):
274
+ return "\n".join(
275
+ str(instruction)
276
+ for instruction in self.instructions
277
+ )
278
+ __all__ = ["Circuit"]
@@ -0,0 +1,64 @@
1
+ from ..core.operators import Gate
2
+ class Instruction:
3
+ """
4
+ Represents a single gate operation in a quantum circuit.
5
+
6
+ Parameters
7
+ ----------
8
+ gate : Gate
9
+ Gate to apply.
10
+ controls : int | list[int] | None
11
+ Control qubit index or indices.
12
+ targets : int | list[int] | None
13
+ Target qubit index or indices.
14
+ """
15
+
16
+ def __init__(self, gate, controls=None, targets=None):
17
+ if not isinstance(gate, Gate):
18
+ raise TypeError("gate must be a Gate object.")
19
+
20
+ self.gate = gate
21
+ self.controls = self._normalize_qubits(controls)
22
+ self.targets = self._normalize_qubits(targets)
23
+
24
+ if len(self.controls) != gate.num_controls:
25
+ raise ValueError(
26
+ f"{gate.name} requires {gate.num_controls} control qubit(s), "
27
+ f"got {len(self.controls)}."
28
+ )
29
+
30
+ if len(self.targets) != gate.num_targets:
31
+ raise ValueError(
32
+ f"{gate.name} requires {gate.num_targets} target qubit(s), "
33
+ f"got {len(self.targets)}."
34
+ )
35
+
36
+ qubits = self.controls + self.targets
37
+
38
+ if len(set(qubits)) != len(qubits):
39
+ raise ValueError(
40
+ "A qubit cannot be used more than once in the same instruction."
41
+ )
42
+
43
+ @staticmethod
44
+ def _normalize_qubits(qubits):
45
+ if qubits is None:
46
+ return []
47
+
48
+ if isinstance(qubits, int):
49
+ return [qubits]
50
+
51
+ return list(qubits)
52
+
53
+ @property
54
+ def qubits(self):
55
+ return self.controls + self.targets
56
+
57
+ def __repr__(self):
58
+ return (
59
+ f"Instruction("
60
+ f"gate={self.gate.name!r}, "
61
+ f"controls={self.controls}, "
62
+ f"targets={self.targets})"
63
+ )
64
+ __all__ = ["Instruction"]
@@ -0,0 +1,4 @@
1
+ from .qubit import Qubit
2
+ from .statevector import StateVector
3
+ from .operators import Operator
4
+ __all__ = ["Qubit","StateVector","Operator","Gate"]
@@ -0,0 +1,79 @@
1
+ """
2
+ Core operator definitions for OQubit.
3
+
4
+ This module provides the base Operator class for linear operators
5
+ and the Gate class for quantum gates.
6
+ """
7
+ import numpy as np
8
+ class Operator:
9
+ """
10
+ Represents a linear operator acting on a quantum state.
11
+
12
+ Parameters
13
+ ----------
14
+ matrix : array-like
15
+ Square matrix representing the operator.
16
+ """
17
+
18
+ def __init__(self, matrix):
19
+ self.matrix = np.asarray(matrix, dtype=complex)
20
+ if self.matrix.ndim != 2:
21
+ raise ValueError("Operator matrix must be two-dimensional.")
22
+ if self.matrix.shape[0] != self.matrix.shape[1]:
23
+ raise ValueError("Operator matrix must be square.")
24
+ @property
25
+ def dimension(self):
26
+ """Return the dimension of the operator."""
27
+ return self.matrix.shape[0]
28
+ def __matmul__(self, other):
29
+ """Apply the operator using the @ operator."""
30
+ return self.matrix @ other
31
+ def __repr__(self):
32
+ return (f"Operator("f"dimension={self.dimension})")
33
+ class Gate(Operator):
34
+ """
35
+ Represents a quantum gate.
36
+
37
+ A Gate is a specialized Operator that also describes
38
+ how many qubits it acts on and its control/target structure.
39
+
40
+ Parameters
41
+ ----------
42
+ matrix : array-like
43
+ Square matrix representing the quantum gate.
44
+
45
+ name : str
46
+ Name of the gate.
47
+
48
+ num_qubits : int
49
+ Number of qubits the gate acts on.
50
+
51
+ num_controls : int, default=0
52
+ Number of control qubits.
53
+
54
+ num_targets : int, default=0
55
+ Number of target qubits.
56
+ """
57
+
58
+ def __init__(self,matrix,name,num_qubits,num_controls=0,num_targets=0,):
59
+ super().__init__(matrix)
60
+ if not isinstance(name, str):
61
+ raise TypeError("Gate name must be a string.")
62
+ if not isinstance(num_qubits, int) or num_qubits < 1:
63
+ raise ValueError("num_qubits must be a positive integer.")
64
+ if not isinstance(num_controls, int) or num_controls < 0:
65
+ raise ValueError("num_controls must be a non-negative integer.")
66
+ if not isinstance(num_targets, int) or num_targets < 0:
67
+ raise ValueError("num_targets must be a non-negative integer.")
68
+ if num_controls + num_targets != num_qubits:
69
+ raise ValueError("num_controls + num_targets must equal num_qubits.")
70
+ expected_dimension = 2 ** num_qubits
71
+ if self.dimension != expected_dimension:
72
+ raise ValueError(f"{name} is a {num_qubits}-qubit gate, "f"so its matrix must be "f"{expected_dimension}x{expected_dimension}.")
73
+ self.name = name
74
+ self.num_qubits = num_qubits
75
+ self.num_controls = num_controls
76
+ self.num_targets = num_targets
77
+ def __repr__(self):
78
+ return (f"Gate("f"name='{self.name}', "f"num_qubits={self.num_qubits}, "f"num_controls={self.num_controls}, "f"num_targets={self.num_targets})")
79
+ __all__ = ["Operator","Gate",]
oqubit/core/qubit.py ADDED
@@ -0,0 +1,68 @@
1
+ import numpy as np
2
+ class Qubit():
3
+ """
4
+ Qubit represents a single-qubit quantum state of the form
5
+
6
+ |ψ⟩ = α|0⟩ + β|1⟩
7
+
8
+ where alpha and beta are the probability amplitudes.
9
+ The normalize parameter determines whether the state is
10
+ normalized during initialization.
11
+ """
12
+ def __init__(self,alpha=1,beta=0,normalize=True):
13
+ self.alpha=complex(alpha)
14
+ self.beta=complex(beta)
15
+ self.normalize=normalize
16
+ if (normalize==True):
17
+ self._normalize()
18
+ def _normalize(self):
19
+ norm = np.sqrt(abs(self.alpha) ** 2 +abs(self.beta) ** 2)
20
+ if np.isclose(norm, 0):
21
+ raise ValueError("Cannot normalize zero state.")
22
+ self.alpha /= norm
23
+ self.beta /= norm
24
+ def apply(self, gate):
25
+ if gate.num_qubits!=1:
26
+ raise ValueError(f"{gate.name} requires {gate.num_qubits} qubits. \n""Use StateVector.apply() for multi-qubit gates.")
27
+ result = gate @ self.state
28
+ self.alpha = result[0]
29
+ self.beta = result[1]
30
+ return self
31
+ @classmethod
32
+ def i(cls):
33
+ return cls(1 / np.sqrt(2), 1j / np.sqrt(2))
34
+ @classmethod
35
+ def minus_i(cls):
36
+ return cls(1 / np.sqrt(2), -1j / np.sqrt(2))
37
+ @classmethod
38
+ def plus(cls):
39
+ return cls(1/np.sqrt(2), 1/np.sqrt(2))
40
+ @classmethod
41
+ def minus(cls):
42
+ return cls(1/np.sqrt(2),-1/np.sqrt(2))
43
+ @classmethod
44
+ def zero(cls):
45
+ return cls(1,0)
46
+ @classmethod
47
+ def one(cls):
48
+ return cls(0,1)
49
+ @property
50
+ def state(self):
51
+ return np.array([self.alpha,self.beta],dtype=complex)
52
+ @property
53
+ def prob_0(self):
54
+ norm = np.sqrt(abs(self.alpha) ** 2 +abs(self.beta) ** 2)
55
+ if np.isclose(norm, 0):
56
+ raise ValueError("Cannot normalize zero state.")
57
+ alpha=abs(self.alpha)/norm
58
+ return (alpha)**2
59
+ @property
60
+ def prob_1(self):
61
+ norm = np.sqrt(abs(self.alpha) ** 2 +abs(self.beta) ** 2)
62
+ if np.isclose(norm, 0):
63
+ raise ValueError("Cannot normalize zero state.")
64
+ beta=abs(self.beta)/norm
65
+ return (beta)**2
66
+ def __repr__(self):
67
+ return f"Qubit:\t{self.alpha} |0\u27E9 \t {self.beta}|1\u27E9"
68
+ __all__=["Qubit"]
@@ -0,0 +1,151 @@
1
+ import numpy as np
2
+ from .qubit import Qubit
3
+ from .operators import Gate
4
+ class StateVector:
5
+ """
6
+ Represents the quantum state of an n-qubit system.
7
+
8
+ A state vector is a complex vector containing the probability
9
+ amplitudes of all computational basis states.
10
+
11
+ For example, a two-qubit state can be written as:
12
+
13
+ |ψ⟩ = α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩
14
+
15
+ The amplitudes satisfy:
16
+
17
+ |α|² + |β|² + |γ|² + |δ|² = 1
18
+
19
+ for a normalized state.
20
+
21
+ Qubit ordering follows the order supplied to StateVector:
22
+
23
+ StateVector([q0, q1, q2])
24
+
25
+ corresponds to:
26
+
27
+ |q0 q1 q2⟩
28
+ """
29
+
30
+ def __init__(self, qubits):
31
+ self.qubits = list(qubits)
32
+ if not self.qubits:
33
+ raise ValueError("StateVector requires at least one qubit.")
34
+ if not all(isinstance(q, Qubit) for q in self.qubits):
35
+ raise TypeError("All elements must be Qubit objects.")
36
+ self._state = self._build_state()
37
+ def _build_state(self):
38
+ state = self.qubits[0].state
39
+ for qubit in self.qubits[1:]:
40
+ state = np.kron(state, qubit.state)
41
+ return state
42
+ def apply(self, gate, controls=None, targets=None):
43
+ if not isinstance(gate, Gate):
44
+ raise TypeError("gate must be a Gate object.")
45
+ if gate.num_qubits > self.num_qubits:
46
+ raise ValueError(
47
+ f"{gate.name} requires {gate.num_qubits} qubits, "
48
+ f"but the state contains only "
49
+ f"{self.num_qubits} qubits."
50
+ )
51
+ if controls is None:
52
+ controls = []
53
+ elif isinstance(controls, int):
54
+ controls = [controls]
55
+ else:
56
+ controls = list(controls)
57
+ if targets is None:
58
+ targets = []
59
+ elif isinstance(targets, int):
60
+ targets = [targets]
61
+ else:
62
+ targets = list(targets)
63
+ if len(controls) != gate.num_controls:
64
+ raise ValueError(f"{gate.name} requires "f"{gate.num_controls} control qubits, "f"but {len(controls)} were provided.")
65
+ if len(targets) != gate.num_targets:
66
+ raise ValueError(f"{gate.name} requires "f"{gate.num_targets} target qubits, "f"but {len(targets)} were provided.")
67
+ qubits = controls + targets
68
+ if len(qubits) != gate.num_qubits:
69
+ raise ValueError(f"{gate.name} requires "f"{gate.num_qubits} qubits.")
70
+ for index in qubits:
71
+ if not isinstance(index, int):
72
+ raise TypeError("Qubit indices must be integers.")
73
+ if index < 0 or index >= self.num_qubits:
74
+ raise IndexError(f"Qubit index {index} is out of range.")
75
+ if len(set(qubits)) != len(qubits):
76
+ raise ValueError("A qubit cannot be used more than once in the same gate.")
77
+ if gate.num_qubits == 1:
78
+ self._apply_single_qubit_gate(gate,targets[0])
79
+ return self
80
+ self._apply_multi_qubit_gate(gate,qubits)
81
+ return self
82
+ def _apply_single_qubit_gate(self, gate, target):
83
+ matrix = gate.matrix
84
+ step = 2 ** (self.num_qubits - target - 1)
85
+ block = step * 2
86
+ old_state = self._state.copy()
87
+ for start in range(0,len(old_state),block):
88
+ for offset in range(step):
89
+ i0 = start + offset
90
+ i1 = i0 + step
91
+ a = old_state[i0]
92
+ b = old_state[i1]
93
+ self._state[i0] = (matrix[0, 0] * a+ matrix[0, 1] * b)
94
+ self._state[i1] = (matrix[1, 0] * a+ matrix[1, 1] * b)
95
+ def _apply_multi_qubit_gate(self, gate, qubits):
96
+ n = self.num_qubits
97
+ k = gate.num_qubits
98
+ matrix = gate.matrix
99
+ old_state = self._state.copy()
100
+ new_state = np.zeros_like(old_state)
101
+ bit_positions = [n - qubit - 1
102
+ for qubit in qubits
103
+ ]
104
+ untouched_positions = [position
105
+ for position in range(n)
106
+ if position not in bit_positions
107
+ ]
108
+ for base in range(2 ** len(untouched_positions)):
109
+ base_index = 0
110
+ for i, position in enumerate(untouched_positions):
111
+ bit = (base >> i) & 1
112
+ base_index |= (bit << position)
113
+ indices = []
114
+ for local_index in range(2 ** k):
115
+ index = base_index
116
+ for j, position in enumerate(bit_positions):
117
+ bit = (local_index>> (k - j - 1)) & 1
118
+ index |= (bit << position)
119
+ indices.append(index)
120
+ amplitudes = old_state[indices]
121
+ transformed = (matrix @ amplitudes)
122
+ for i, index in enumerate(indices):
123
+ new_state[index] = (transformed[i])
124
+ self._state = new_state
125
+ @property
126
+ def state(self):
127
+ return self._state
128
+ @property
129
+ def num_qubits(self):
130
+ return len(self.qubits)
131
+ @property
132
+ def dimension(self):
133
+ return 2 ** self.num_qubits
134
+ def normalize(self):
135
+ norm = np.linalg.norm(self._state)
136
+ if np.isclose(norm, 0):
137
+ raise ValueError("Cannot normalize zero state.")
138
+ self._state = (self._state / norm)
139
+ return self
140
+ @property
141
+ def notation(self):
142
+ terms = []
143
+ for index, amplitude in enumerate(self._state):
144
+ if np.isclose(amplitude,0):
145
+ continue
146
+ basis = format(index,f"0{self.num_qubits}b")
147
+ terms.append(f"{amplitude}|{basis}⟩")
148
+ return " + ".join(terms)
149
+ def __repr__(self):
150
+ return (f"StateVector("f"num_qubits={self.num_qubits}, "f"dimension={self.dimension})")
151
+ __all__ = ["StateVector"]
@@ -0,0 +1,5 @@
1
+ from ..core.operators import Operator,Gate
2
+ from .single import X,Y,Z,H,S,T,SX
3
+ from .controlled import CX,CY,CZ,CH,CS,CSX,CT
4
+ from .multi import SWAP,ISWAP,SQRT_SWAP,CCX,CSWAP
5
+ __all__=["X","Y","Z","H","S","T","SX","CX","CY","CZ","CH","CS","CSX","CT","SWAP","ISWAP","SQRT_SWAP","CCX","CSWAP"]
@@ -0,0 +1,17 @@
1
+ from ..core.operators import Gate,Operator
2
+ import numpy as np
3
+ """
4
+ These are Qubit gates which are cotrolled and requires atleast one Qubit control state to change the state of the other Qubit.
5
+
6
+ Qubit gates such as CX (also known as CNOT), CY ,CZ , CH, CS, CT, CSX Gates are present.
7
+
8
+ I hope you will enjoy learning creating new logical interpretation by using various series of Quantum Gates to Encode and Decode Informations.
9
+ """
10
+ CX = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 0, 1],[0, 0, 1, 0],],"CX",num_qubits=2,num_controls=1,num_targets=1,)
11
+ CY = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 0, -1j],[0, 0, 1j, 0],],"CY",num_qubits=2,num_controls=1,num_targets=1,)
12
+ CZ = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, -1],],"CZ",num_qubits=2,num_controls=1,num_targets=1,)
13
+ CH = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1 / np.sqrt(2), 1 / np.sqrt(2)],[0, 0, 1 / np.sqrt(2), -1 / np.sqrt(2)],],"CH",num_qubits=2,num_controls=1,num_targets=1,)
14
+ CS = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, 1j],],"CS",num_qubits=2,num_controls=1,num_targets=1,)
15
+ CT = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, np.exp(1j * np.pi / 4)],],"CT",num_qubits=2,num_controls=1,num_targets=1,)
16
+ CSX = Gate([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, (1 + 1j) / 2, (1 - 1j) / 2],[0, 0, (1 - 1j) / 2, (1 + 1j) / 2],],"CSX",num_qubits=2,num_controls=1,num_targets=1,)
17
+ __all__ = ["CX","CY","CZ","CH","CS","CT","CSX"]