superquantx 0.1.0__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.
- superquantx/__init__.py +321 -0
- superquantx/algorithms/__init__.py +55 -0
- superquantx/algorithms/base_algorithm.py +413 -0
- superquantx/algorithms/hybrid_classifier.py +628 -0
- superquantx/algorithms/qaoa.py +406 -0
- superquantx/algorithms/quantum_agents.py +1006 -0
- superquantx/algorithms/quantum_kmeans.py +575 -0
- superquantx/algorithms/quantum_nn.py +544 -0
- superquantx/algorithms/quantum_pca.py +499 -0
- superquantx/algorithms/quantum_svm.py +346 -0
- superquantx/algorithms/vqe.py +553 -0
- superquantx/algorithms.py +863 -0
- superquantx/backends/__init__.py +265 -0
- superquantx/backends/base_backend.py +321 -0
- superquantx/backends/braket_backend.py +420 -0
- superquantx/backends/cirq_backend.py +466 -0
- superquantx/backends/ocean_backend.py +491 -0
- superquantx/backends/pennylane_backend.py +419 -0
- superquantx/backends/qiskit_backend.py +451 -0
- superquantx/backends/simulator_backend.py +455 -0
- superquantx/backends/tket_backend.py +519 -0
- superquantx/circuits.py +447 -0
- superquantx/cli/__init__.py +28 -0
- superquantx/cli/commands.py +528 -0
- superquantx/cli/main.py +254 -0
- superquantx/client.py +298 -0
- superquantx/config.py +326 -0
- superquantx/exceptions.py +287 -0
- superquantx/gates.py +588 -0
- superquantx/logging_config.py +347 -0
- superquantx/measurements.py +702 -0
- superquantx/ml.py +936 -0
- superquantx/noise.py +760 -0
- superquantx/utils/__init__.py +83 -0
- superquantx/utils/benchmarking.py +523 -0
- superquantx/utils/classical_utils.py +575 -0
- superquantx/utils/feature_mapping.py +467 -0
- superquantx/utils/optimization.py +410 -0
- superquantx/utils/quantum_utils.py +456 -0
- superquantx/utils/visualization.py +654 -0
- superquantx/version.py +33 -0
- superquantx-0.1.0.dist-info/METADATA +365 -0
- superquantx-0.1.0.dist-info/RECORD +46 -0
- superquantx-0.1.0.dist-info/WHEEL +4 -0
- superquantx-0.1.0.dist-info/entry_points.txt +2 -0
- superquantx-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,456 @@
|
|
1
|
+
"""Quantum-specific utility functions.
|
2
|
+
|
3
|
+
This module provides utility functions for quantum information processing,
|
4
|
+
including fidelity calculations, quantum distances, and entanglement measures.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import warnings
|
8
|
+
from typing import Tuple
|
9
|
+
|
10
|
+
import numpy as np
|
11
|
+
from scipy.linalg import sqrtm
|
12
|
+
|
13
|
+
|
14
|
+
def fidelity(
|
15
|
+
state1: np.ndarray,
|
16
|
+
state2: np.ndarray,
|
17
|
+
validate: bool = True
|
18
|
+
) -> float:
|
19
|
+
"""Calculate quantum fidelity between two quantum states.
|
20
|
+
|
21
|
+
For pure states |ψ₁⟩ and |ψ₂⟩:
|
22
|
+
F(ψ₁, ψ₂) = |⟨ψ₁|ψ₂⟩|²
|
23
|
+
|
24
|
+
For mixed states ρ₁ and ρ₂:
|
25
|
+
F(ρ₁, ρ₂) = Tr(√(√ρ₁ ρ₂ √ρ₁))²
|
26
|
+
|
27
|
+
Args:
|
28
|
+
state1: First quantum state (vector or density matrix)
|
29
|
+
state2: Second quantum state (vector or density matrix)
|
30
|
+
validate: Whether to validate inputs
|
31
|
+
|
32
|
+
Returns:
|
33
|
+
Fidelity value between 0 and 1
|
34
|
+
|
35
|
+
"""
|
36
|
+
if validate:
|
37
|
+
_validate_quantum_state(state1)
|
38
|
+
_validate_quantum_state(state2)
|
39
|
+
|
40
|
+
# Check if states are vectors (pure states) or matrices (mixed states)
|
41
|
+
is_pure1 = len(state1.shape) == 1
|
42
|
+
is_pure2 = len(state2.shape) == 1
|
43
|
+
|
44
|
+
if is_pure1 and is_pure2:
|
45
|
+
# Both pure states
|
46
|
+
overlap = np.vdot(state1, state2)
|
47
|
+
return abs(overlap) ** 2
|
48
|
+
|
49
|
+
elif is_pure1 and not is_pure2:
|
50
|
+
# state1 pure, state2 mixed
|
51
|
+
rho2 = state2
|
52
|
+
psi1 = state1.reshape(-1, 1)
|
53
|
+
return np.real(np.conj(psi1).T @ rho2 @ psi1)[0, 0]
|
54
|
+
|
55
|
+
elif not is_pure1 and is_pure2:
|
56
|
+
# state1 mixed, state2 pure
|
57
|
+
rho1 = state1
|
58
|
+
psi2 = state2.reshape(-1, 1)
|
59
|
+
return np.real(np.conj(psi2).T @ rho1 @ psi2)[0, 0]
|
60
|
+
|
61
|
+
else:
|
62
|
+
# Both mixed states
|
63
|
+
rho1, rho2 = state1, state2
|
64
|
+
|
65
|
+
# F = Tr(√(√ρ₁ ρ₂ √ρ₁))²
|
66
|
+
sqrt_rho1 = sqrtm(rho1)
|
67
|
+
M = sqrt_rho1 @ rho2 @ sqrt_rho1
|
68
|
+
sqrt_M = sqrtm(M)
|
69
|
+
|
70
|
+
fid = np.real(np.trace(sqrt_M)) ** 2
|
71
|
+
|
72
|
+
# Ensure fidelity is in [0, 1] (numerical errors can cause small violations)
|
73
|
+
return np.clip(fid, 0, 1)
|
74
|
+
|
75
|
+
|
76
|
+
def trace_distance(
|
77
|
+
state1: np.ndarray,
|
78
|
+
state2: np.ndarray,
|
79
|
+
validate: bool = True
|
80
|
+
) -> float:
|
81
|
+
"""Calculate trace distance between two quantum states.
|
82
|
+
|
83
|
+
For quantum states ρ₁ and ρ₂:
|
84
|
+
D(ρ₁, ρ₂) = (1/2) * Tr(|ρ₁ - ρ₂|)
|
85
|
+
|
86
|
+
Args:
|
87
|
+
state1: First quantum state
|
88
|
+
state2: Second quantum state
|
89
|
+
validate: Whether to validate inputs
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Trace distance between 0 and 1
|
93
|
+
|
94
|
+
"""
|
95
|
+
if validate:
|
96
|
+
_validate_quantum_state(state1)
|
97
|
+
_validate_quantum_state(state2)
|
98
|
+
|
99
|
+
# Convert to density matrices if needed
|
100
|
+
rho1 = _to_density_matrix(state1)
|
101
|
+
rho2 = _to_density_matrix(state2)
|
102
|
+
|
103
|
+
# Compute difference
|
104
|
+
diff = rho1 - rho2
|
105
|
+
|
106
|
+
# Compute eigenvalues and take absolute values
|
107
|
+
eigenvals = np.linalg.eigvals(diff)
|
108
|
+
abs_eigenvals = np.abs(eigenvals)
|
109
|
+
|
110
|
+
# Trace distance is half the sum of absolute eigenvalues
|
111
|
+
return 0.5 * np.sum(abs_eigenvals)
|
112
|
+
|
113
|
+
|
114
|
+
def quantum_mutual_information(
|
115
|
+
joint_state: np.ndarray,
|
116
|
+
subsystem_dims: Tuple[int, int],
|
117
|
+
validate: bool = True
|
118
|
+
) -> float:
|
119
|
+
"""Calculate quantum mutual information between two subsystems.
|
120
|
+
|
121
|
+
I(A:B) = S(ρₐ) + S(ρᵦ) - S(ρₐᵦ)
|
122
|
+
|
123
|
+
where S(ρ) is the von Neumann entropy.
|
124
|
+
|
125
|
+
Args:
|
126
|
+
joint_state: Joint quantum state of both subsystems
|
127
|
+
subsystem_dims: Dimensions of subsystems (dim_A, dim_B)
|
128
|
+
validate: Whether to validate inputs
|
129
|
+
|
130
|
+
Returns:
|
131
|
+
Quantum mutual information
|
132
|
+
|
133
|
+
"""
|
134
|
+
if validate:
|
135
|
+
_validate_quantum_state(joint_state)
|
136
|
+
|
137
|
+
rho_AB = _to_density_matrix(joint_state)
|
138
|
+
dim_A, dim_B = subsystem_dims
|
139
|
+
|
140
|
+
if rho_AB.shape[0] != dim_A * dim_B:
|
141
|
+
raise ValueError(f"State dimension {rho_AB.shape[0]} doesn't match subsystem dims {dim_A * dim_B}")
|
142
|
+
|
143
|
+
# Partial traces
|
144
|
+
rho_A = partial_trace(rho_AB, (dim_A, dim_B), trace_out=1)
|
145
|
+
rho_B = partial_trace(rho_AB, (dim_A, dim_B), trace_out=0)
|
146
|
+
|
147
|
+
# Von Neumann entropies
|
148
|
+
S_A = von_neumann_entropy(rho_A)
|
149
|
+
S_B = von_neumann_entropy(rho_B)
|
150
|
+
S_AB = von_neumann_entropy(rho_AB)
|
151
|
+
|
152
|
+
return S_A + S_B - S_AB
|
153
|
+
|
154
|
+
|
155
|
+
def entanglement_measure(
|
156
|
+
state: np.ndarray,
|
157
|
+
subsystem_dims: Tuple[int, int],
|
158
|
+
measure: str = 'negativity',
|
159
|
+
validate: bool = True
|
160
|
+
) -> float:
|
161
|
+
"""Calculate entanglement measure for a bipartite quantum state.
|
162
|
+
|
163
|
+
Args:
|
164
|
+
state: Quantum state (pure or mixed)
|
165
|
+
subsystem_dims: Dimensions of subsystems (dim_A, dim_B)
|
166
|
+
measure: Type of measure ('negativity', 'concurrence', 'entropy')
|
167
|
+
validate: Whether to validate inputs
|
168
|
+
|
169
|
+
Returns:
|
170
|
+
Entanglement measure value
|
171
|
+
|
172
|
+
"""
|
173
|
+
if validate:
|
174
|
+
_validate_quantum_state(state)
|
175
|
+
|
176
|
+
if measure == 'negativity':
|
177
|
+
return negativity(state, subsystem_dims)
|
178
|
+
elif measure == 'concurrence':
|
179
|
+
return concurrence(state, subsystem_dims)
|
180
|
+
elif measure == 'entropy':
|
181
|
+
return entanglement_entropy(state, subsystem_dims)
|
182
|
+
else:
|
183
|
+
raise ValueError(f"Unknown entanglement measure: {measure}")
|
184
|
+
|
185
|
+
|
186
|
+
def negativity(
|
187
|
+
state: np.ndarray,
|
188
|
+
subsystem_dims: Tuple[int, int]
|
189
|
+
) -> float:
|
190
|
+
"""Calculate negativity entanglement measure.
|
191
|
+
|
192
|
+
Negativity is defined as:
|
193
|
+
N(ρ) = (||ρᵀᴬ||₁ - 1) / 2
|
194
|
+
|
195
|
+
where ρᵀᴬ is the partial transpose with respect to subsystem A.
|
196
|
+
|
197
|
+
Args:
|
198
|
+
state: Quantum state
|
199
|
+
subsystem_dims: Dimensions of subsystems
|
200
|
+
|
201
|
+
Returns:
|
202
|
+
Negativity value
|
203
|
+
|
204
|
+
"""
|
205
|
+
rho = _to_density_matrix(state)
|
206
|
+
|
207
|
+
# Partial transpose
|
208
|
+
rho_TA = partial_transpose(rho, subsystem_dims, transpose_subsystem=0)
|
209
|
+
|
210
|
+
# Calculate trace norm (sum of absolute eigenvalues)
|
211
|
+
eigenvals = np.linalg.eigvals(rho_TA)
|
212
|
+
trace_norm = np.sum(np.abs(eigenvals))
|
213
|
+
|
214
|
+
return (trace_norm - 1) / 2
|
215
|
+
|
216
|
+
|
217
|
+
def concurrence(
|
218
|
+
state: np.ndarray,
|
219
|
+
subsystem_dims: Tuple[int, int]
|
220
|
+
) -> float:
|
221
|
+
"""Calculate concurrence for two-qubit systems.
|
222
|
+
|
223
|
+
Note: This implementation is only valid for 2×2 systems.
|
224
|
+
|
225
|
+
Args:
|
226
|
+
state: Two-qubit quantum state
|
227
|
+
subsystem_dims: Should be (2, 2) for two qubits
|
228
|
+
|
229
|
+
Returns:
|
230
|
+
Concurrence value
|
231
|
+
|
232
|
+
"""
|
233
|
+
if subsystem_dims != (2, 2):
|
234
|
+
raise ValueError("Concurrence is only implemented for two-qubit systems")
|
235
|
+
|
236
|
+
rho = _to_density_matrix(state)
|
237
|
+
|
238
|
+
# Pauli Y matrix
|
239
|
+
sigma_y = np.array([[0, -1j], [1j, 0]])
|
240
|
+
|
241
|
+
# Two-qubit Y tensor product
|
242
|
+
Y_tensor = np.kron(sigma_y, sigma_y)
|
243
|
+
|
244
|
+
# Spin-flipped state
|
245
|
+
rho_tilde = Y_tensor @ np.conj(rho) @ Y_tensor
|
246
|
+
|
247
|
+
# R matrix
|
248
|
+
R = rho @ rho_tilde
|
249
|
+
|
250
|
+
# Eigenvalues in descending order
|
251
|
+
eigenvals = np.sqrt(np.real(np.linalg.eigvals(R)))
|
252
|
+
eigenvals = np.sort(eigenvals)[::-1]
|
253
|
+
|
254
|
+
# Concurrence
|
255
|
+
C = max(0, eigenvals[0] - eigenvals[1] - eigenvals[2] - eigenvals[3])
|
256
|
+
|
257
|
+
return C
|
258
|
+
|
259
|
+
|
260
|
+
def entanglement_entropy(
|
261
|
+
state: np.ndarray,
|
262
|
+
subsystem_dims: Tuple[int, int]
|
263
|
+
) -> float:
|
264
|
+
"""Calculate entanglement entropy (von Neumann entropy of reduced state).
|
265
|
+
|
266
|
+
Args:
|
267
|
+
state: Quantum state
|
268
|
+
subsystem_dims: Dimensions of subsystems
|
269
|
+
|
270
|
+
Returns:
|
271
|
+
Entanglement entropy
|
272
|
+
|
273
|
+
"""
|
274
|
+
rho = _to_density_matrix(state)
|
275
|
+
|
276
|
+
# Reduced state of first subsystem
|
277
|
+
rho_A = partial_trace(rho, subsystem_dims, trace_out=1)
|
278
|
+
|
279
|
+
return von_neumann_entropy(rho_A)
|
280
|
+
|
281
|
+
|
282
|
+
def von_neumann_entropy(rho: np.ndarray) -> float:
|
283
|
+
"""Calculate von Neumann entropy of a quantum state.
|
284
|
+
|
285
|
+
S(ρ) = -Tr(ρ log ρ)
|
286
|
+
|
287
|
+
Args:
|
288
|
+
rho: Density matrix
|
289
|
+
|
290
|
+
Returns:
|
291
|
+
von Neumann entropy
|
292
|
+
|
293
|
+
"""
|
294
|
+
eigenvals = np.linalg.eigvals(rho)
|
295
|
+
|
296
|
+
# Remove zero eigenvalues to avoid log(0)
|
297
|
+
eigenvals = eigenvals[eigenvals > 1e-12]
|
298
|
+
|
299
|
+
if len(eigenvals) == 0:
|
300
|
+
return 0.0
|
301
|
+
|
302
|
+
return -np.sum(eigenvals * np.log2(eigenvals))
|
303
|
+
|
304
|
+
|
305
|
+
def partial_trace(
|
306
|
+
rho: np.ndarray,
|
307
|
+
subsystem_dims: Tuple[int, int],
|
308
|
+
trace_out: int
|
309
|
+
) -> np.ndarray:
|
310
|
+
"""Compute partial trace of a density matrix.
|
311
|
+
|
312
|
+
Args:
|
313
|
+
rho: Density matrix
|
314
|
+
subsystem_dims: Dimensions of subsystems (dim_A, dim_B)
|
315
|
+
trace_out: Which subsystem to trace out (0 for A, 1 for B)
|
316
|
+
|
317
|
+
Returns:
|
318
|
+
Reduced density matrix
|
319
|
+
|
320
|
+
"""
|
321
|
+
dim_A, dim_B = subsystem_dims
|
322
|
+
|
323
|
+
if rho.shape != (dim_A * dim_B, dim_A * dim_B):
|
324
|
+
raise ValueError("Density matrix dimensions don't match subsystem dimensions")
|
325
|
+
|
326
|
+
if trace_out == 0:
|
327
|
+
# Trace out subsystem A, keep B
|
328
|
+
rho_B = np.zeros((dim_B, dim_B), dtype=complex)
|
329
|
+
for i in range(dim_A):
|
330
|
+
rho_B += rho[i*dim_B:(i+1)*dim_B, i*dim_B:(i+1)*dim_B]
|
331
|
+
return rho_B
|
332
|
+
|
333
|
+
elif trace_out == 1:
|
334
|
+
# Trace out subsystem B, keep A
|
335
|
+
rho_A = np.zeros((dim_A, dim_A), dtype=complex)
|
336
|
+
for i in range(dim_A):
|
337
|
+
for j in range(dim_A):
|
338
|
+
for k in range(dim_B):
|
339
|
+
rho_A[i, j] += rho[i*dim_B + k, j*dim_B + k]
|
340
|
+
return rho_A
|
341
|
+
|
342
|
+
else:
|
343
|
+
raise ValueError("trace_out must be 0 or 1")
|
344
|
+
|
345
|
+
|
346
|
+
def partial_transpose(
|
347
|
+
rho: np.ndarray,
|
348
|
+
subsystem_dims: Tuple[int, int],
|
349
|
+
transpose_subsystem: int
|
350
|
+
) -> np.ndarray:
|
351
|
+
"""Compute partial transpose of a density matrix.
|
352
|
+
|
353
|
+
Args:
|
354
|
+
rho: Density matrix
|
355
|
+
subsystem_dims: Dimensions of subsystems
|
356
|
+
transpose_subsystem: Which subsystem to transpose (0 for A, 1 for B)
|
357
|
+
|
358
|
+
Returns:
|
359
|
+
Partially transposed density matrix
|
360
|
+
|
361
|
+
"""
|
362
|
+
dim_A, dim_B = subsystem_dims
|
363
|
+
|
364
|
+
if transpose_subsystem == 0:
|
365
|
+
# Transpose subsystem A
|
366
|
+
rho_TA = np.zeros_like(rho)
|
367
|
+
for i in range(dim_A):
|
368
|
+
for j in range(dim_A):
|
369
|
+
for k in range(dim_B):
|
370
|
+
for l in range(dim_B):
|
371
|
+
# Transpose indices for subsystem A
|
372
|
+
rho_TA[i*dim_B + k, j*dim_B + l] = rho[j*dim_B + k, i*dim_B + l]
|
373
|
+
return rho_TA
|
374
|
+
|
375
|
+
elif transpose_subsystem == 1:
|
376
|
+
# Transpose subsystem B
|
377
|
+
rho_TB = np.zeros_like(rho)
|
378
|
+
for i in range(dim_A):
|
379
|
+
for j in range(dim_A):
|
380
|
+
for k in range(dim_B):
|
381
|
+
for l in range(dim_B):
|
382
|
+
# Transpose indices for subsystem B
|
383
|
+
rho_TB[i*dim_B + k, j*dim_B + l] = rho[i*dim_B + l, j*dim_B + k]
|
384
|
+
return rho_TB
|
385
|
+
|
386
|
+
else:
|
387
|
+
raise ValueError("transpose_subsystem must be 0 or 1")
|
388
|
+
|
389
|
+
|
390
|
+
def _validate_quantum_state(state: np.ndarray) -> None:
|
391
|
+
"""Validate that input represents a valid quantum state."""
|
392
|
+
if len(state.shape) == 1:
|
393
|
+
# Pure state vector
|
394
|
+
if not np.isclose(np.linalg.norm(state), 1.0, atol=1e-10):
|
395
|
+
warnings.warn("State vector is not normalized")
|
396
|
+
|
397
|
+
elif len(state.shape) == 2:
|
398
|
+
# Density matrix
|
399
|
+
if state.shape[0] != state.shape[1]:
|
400
|
+
raise ValueError("Density matrix must be square")
|
401
|
+
|
402
|
+
# Check if Hermitian
|
403
|
+
if not np.allclose(state, np.conj(state.T), atol=1e-10):
|
404
|
+
warnings.warn("Density matrix is not Hermitian")
|
405
|
+
|
406
|
+
# Check if positive semidefinite
|
407
|
+
eigenvals = np.linalg.eigvals(state)
|
408
|
+
if np.any(eigenvals < -1e-10):
|
409
|
+
warnings.warn("Density matrix is not positive semidefinite")
|
410
|
+
|
411
|
+
# Check trace
|
412
|
+
if not np.isclose(np.trace(state), 1.0, atol=1e-10):
|
413
|
+
warnings.warn("Density matrix trace is not 1")
|
414
|
+
|
415
|
+
else:
|
416
|
+
raise ValueError("Invalid quantum state format")
|
417
|
+
|
418
|
+
|
419
|
+
def _to_density_matrix(state: np.ndarray) -> np.ndarray:
|
420
|
+
"""Convert state vector to density matrix if needed."""
|
421
|
+
if len(state.shape) == 1:
|
422
|
+
# Pure state vector -> density matrix
|
423
|
+
psi = state.reshape(-1, 1)
|
424
|
+
return psi @ np.conj(psi.T)
|
425
|
+
else:
|
426
|
+
# Already a density matrix
|
427
|
+
return state
|
428
|
+
|
429
|
+
|
430
|
+
def quantum_state_distance(
|
431
|
+
state1: np.ndarray,
|
432
|
+
state2: np.ndarray,
|
433
|
+
metric: str = 'fidelity'
|
434
|
+
) -> float:
|
435
|
+
"""Calculate distance between quantum states using various metrics.
|
436
|
+
|
437
|
+
Args:
|
438
|
+
state1: First quantum state
|
439
|
+
state2: Second quantum state
|
440
|
+
metric: Distance metric ('fidelity', 'trace_distance', 'hilbert_schmidt')
|
441
|
+
|
442
|
+
Returns:
|
443
|
+
Distance value
|
444
|
+
|
445
|
+
"""
|
446
|
+
if metric == 'fidelity':
|
447
|
+
return 1 - fidelity(state1, state2)
|
448
|
+
elif metric == 'trace_distance':
|
449
|
+
return trace_distance(state1, state2)
|
450
|
+
elif metric == 'hilbert_schmidt':
|
451
|
+
rho1 = _to_density_matrix(state1)
|
452
|
+
rho2 = _to_density_matrix(state2)
|
453
|
+
diff = rho1 - rho2
|
454
|
+
return np.sqrt(np.real(np.trace(np.conj(diff.T) @ diff)))
|
455
|
+
else:
|
456
|
+
raise ValueError(f"Unknown metric: {metric}")
|