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.
Files changed (46) hide show
  1. superquantx/__init__.py +321 -0
  2. superquantx/algorithms/__init__.py +55 -0
  3. superquantx/algorithms/base_algorithm.py +413 -0
  4. superquantx/algorithms/hybrid_classifier.py +628 -0
  5. superquantx/algorithms/qaoa.py +406 -0
  6. superquantx/algorithms/quantum_agents.py +1006 -0
  7. superquantx/algorithms/quantum_kmeans.py +575 -0
  8. superquantx/algorithms/quantum_nn.py +544 -0
  9. superquantx/algorithms/quantum_pca.py +499 -0
  10. superquantx/algorithms/quantum_svm.py +346 -0
  11. superquantx/algorithms/vqe.py +553 -0
  12. superquantx/algorithms.py +863 -0
  13. superquantx/backends/__init__.py +265 -0
  14. superquantx/backends/base_backend.py +321 -0
  15. superquantx/backends/braket_backend.py +420 -0
  16. superquantx/backends/cirq_backend.py +466 -0
  17. superquantx/backends/ocean_backend.py +491 -0
  18. superquantx/backends/pennylane_backend.py +419 -0
  19. superquantx/backends/qiskit_backend.py +451 -0
  20. superquantx/backends/simulator_backend.py +455 -0
  21. superquantx/backends/tket_backend.py +519 -0
  22. superquantx/circuits.py +447 -0
  23. superquantx/cli/__init__.py +28 -0
  24. superquantx/cli/commands.py +528 -0
  25. superquantx/cli/main.py +254 -0
  26. superquantx/client.py +298 -0
  27. superquantx/config.py +326 -0
  28. superquantx/exceptions.py +287 -0
  29. superquantx/gates.py +588 -0
  30. superquantx/logging_config.py +347 -0
  31. superquantx/measurements.py +702 -0
  32. superquantx/ml.py +936 -0
  33. superquantx/noise.py +760 -0
  34. superquantx/utils/__init__.py +83 -0
  35. superquantx/utils/benchmarking.py +523 -0
  36. superquantx/utils/classical_utils.py +575 -0
  37. superquantx/utils/feature_mapping.py +467 -0
  38. superquantx/utils/optimization.py +410 -0
  39. superquantx/utils/quantum_utils.py +456 -0
  40. superquantx/utils/visualization.py +654 -0
  41. superquantx/version.py +33 -0
  42. superquantx-0.1.0.dist-info/METADATA +365 -0
  43. superquantx-0.1.0.dist-info/RECORD +46 -0
  44. superquantx-0.1.0.dist-info/WHEEL +4 -0
  45. superquantx-0.1.0.dist-info/entry_points.txt +2 -0
  46. superquantx-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,467 @@
1
+ """Quantum feature mapping utilities.
2
+
3
+ This module provides functions and classes for creating quantum feature maps,
4
+ which encode classical data into quantum states for machine learning algorithms.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass
9
+ from typing import Any, Callable, Dict, List, Optional, Tuple
10
+
11
+ import numpy as np
12
+
13
+
14
+ @dataclass
15
+ class FeatureMapConfig:
16
+ """Configuration for quantum feature maps."""
17
+
18
+ n_qubits: int
19
+ n_features: int
20
+ reps: int = 1
21
+ entanglement: str = 'full'
22
+ parameter_prefix: str = 'x'
23
+ insert_barriers: bool = False
24
+ data_map_func: Optional[Callable] = None
25
+
26
+
27
+ class QuantumFeatureMap(ABC):
28
+ """Abstract base class for quantum feature maps.
29
+
30
+ Feature maps encode classical data into quantum states by applying
31
+ parameterized quantum gates based on the input features.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ n_features: int,
37
+ reps: int = 1,
38
+ entanglement: str = 'full',
39
+ parameter_prefix: str = 'x'
40
+ ):
41
+ self.n_features = n_features
42
+ self.reps = reps
43
+ self.entanglement = entanglement
44
+ self.parameter_prefix = parameter_prefix
45
+ self.n_qubits = n_features
46
+ self._parameters = []
47
+
48
+ @abstractmethod
49
+ def _build_circuit(self, parameters: np.ndarray) -> Dict[str, Any]:
50
+ """Build the quantum circuit for the feature map."""
51
+ pass
52
+
53
+ def map_data_point(self, x: np.ndarray) -> Dict[str, Any]:
54
+ """Map a single data point to quantum circuit parameters.
55
+
56
+ Args:
57
+ x: Input data point of length n_features
58
+
59
+ Returns:
60
+ Circuit representation with parameters
61
+
62
+ """
63
+ if len(x) != self.n_features:
64
+ raise ValueError(f"Expected {self.n_features} features, got {len(x)}")
65
+
66
+ # Repeat the data point for each repetition
67
+ parameters = np.tile(x, self.reps)
68
+
69
+ return self._build_circuit(parameters)
70
+
71
+ def map_data(self, X: np.ndarray) -> List[Dict[str, Any]]:
72
+ """Map multiple data points to quantum circuits.
73
+
74
+ Args:
75
+ X: Input data of shape (n_samples, n_features)
76
+
77
+ Returns:
78
+ List of circuit representations
79
+
80
+ """
81
+ return [self.map_data_point(x) for x in X]
82
+
83
+ @property
84
+ def num_parameters(self) -> int:
85
+ """Number of parameters in the feature map."""
86
+ return self.n_features * self.reps
87
+
88
+
89
+ class ZFeatureMap(QuantumFeatureMap):
90
+ """Z-axis rotation feature map.
91
+
92
+ This feature map applies RZ rotations to encode features:
93
+ RZ(2 * x_i) for each feature x_i
94
+ """
95
+
96
+ def __init__(
97
+ self,
98
+ n_features: int,
99
+ reps: int = 1,
100
+ parameter_prefix: str = 'x'
101
+ ):
102
+ super().__init__(n_features, reps, 'none', parameter_prefix)
103
+
104
+ def _build_circuit(self, parameters: np.ndarray) -> Dict[str, Any]:
105
+ """Build Z feature map circuit."""
106
+ gates = []
107
+
108
+ for rep in range(self.reps):
109
+ for i in range(self.n_features):
110
+ param_idx = rep * self.n_features + i
111
+ gates.append({
112
+ 'type': 'RZ',
113
+ 'qubit': i,
114
+ 'parameter': 2.0 * parameters[param_idx],
115
+ 'parameter_name': f'{self.parameter_prefix}_{param_idx}'
116
+ })
117
+
118
+ return {
119
+ 'n_qubits': self.n_qubits,
120
+ 'gates': gates,
121
+ 'parameters': parameters.tolist(),
122
+ 'feature_map_type': 'Z'
123
+ }
124
+
125
+
126
+ class ZZFeatureMap(QuantumFeatureMap):
127
+ """ZZ entangling feature map.
128
+
129
+ This feature map uses both single-qubit Z rotations and two-qubit ZZ interactions:
130
+ - Single qubit: RZ(2 * x_i)
131
+ - Two qubit: RZZ(2 * x_i * x_j) for entangled qubits
132
+ """
133
+
134
+ def __init__(
135
+ self,
136
+ n_features: int,
137
+ reps: int = 1,
138
+ entanglement: str = 'linear',
139
+ alpha: float = 2.0,
140
+ parameter_prefix: str = 'x'
141
+ ):
142
+ super().__init__(n_features, reps, entanglement, parameter_prefix)
143
+ self.alpha = alpha
144
+
145
+ def _build_circuit(self, parameters: np.ndarray) -> Dict[str, Any]:
146
+ """Build ZZ feature map circuit."""
147
+ gates = []
148
+
149
+ for rep in range(self.reps):
150
+ # Single qubit Z rotations
151
+ for i in range(self.n_features):
152
+ param_idx = rep * self.n_features + i
153
+ gates.append({
154
+ 'type': 'RZ',
155
+ 'qubit': i,
156
+ 'parameter': self.alpha * parameters[param_idx],
157
+ 'parameter_name': f'{self.parameter_prefix}_{param_idx}'
158
+ })
159
+
160
+ # Two-qubit ZZ entangling gates
161
+ entangling_pairs = self._get_entangling_pairs()
162
+
163
+ for i, j in entangling_pairs:
164
+ param_i = rep * self.n_features + i
165
+ param_j = rep * self.n_features + j
166
+
167
+ gates.append({
168
+ 'type': 'RZZ',
169
+ 'qubits': [i, j],
170
+ 'parameter': self.alpha * parameters[param_i] * parameters[param_j],
171
+ 'parameter_names': [f'{self.parameter_prefix}_{param_i}',
172
+ f'{self.parameter_prefix}_{param_j}']
173
+ })
174
+
175
+ return {
176
+ 'n_qubits': self.n_qubits,
177
+ 'gates': gates,
178
+ 'parameters': parameters.tolist(),
179
+ 'feature_map_type': 'ZZ',
180
+ 'entanglement': self.entanglement
181
+ }
182
+
183
+ def _get_entangling_pairs(self) -> List[Tuple[int, int]]:
184
+ """Get pairs of qubits for entangling gates."""
185
+ pairs = []
186
+
187
+ if self.entanglement == 'linear':
188
+ # Linear chain: (0,1), (1,2), (2,3), ...
189
+ for i in range(self.n_qubits - 1):
190
+ pairs.append((i, i + 1))
191
+
192
+ elif self.entanglement == 'circular':
193
+ # Circular: linear + (n-1, 0)
194
+ pairs = self._get_linear_pairs()
195
+ pairs.append((self.n_qubits - 1, 0))
196
+
197
+ elif self.entanglement == 'full':
198
+ # Full connectivity: all pairs
199
+ for i in range(self.n_qubits):
200
+ for j in range(i + 1, self.n_qubits):
201
+ pairs.append((i, j))
202
+
203
+ elif self.entanglement == 'sca':
204
+ # Strongly correlated ansatz
205
+ for i in range(0, self.n_qubits - 1, 2):
206
+ if i + 1 < self.n_qubits:
207
+ pairs.append((i, i + 1))
208
+
209
+ return pairs
210
+
211
+
212
+ class PauliFeatureMap(QuantumFeatureMap):
213
+ """Pauli feature map with arbitrary Pauli strings.
214
+
215
+ This feature map applies rotations based on Pauli operators:
216
+ exp(i * alpha * phi * P) where P is a Pauli string and phi is the feature value.
217
+ """
218
+
219
+ def __init__(
220
+ self,
221
+ n_features: int,
222
+ reps: int = 1,
223
+ paulis: List[str] = ['Z', 'ZZ'],
224
+ entanglement: str = 'full',
225
+ alpha: float = 2.0,
226
+ parameter_prefix: str = 'x'
227
+ ):
228
+ super().__init__(n_features, reps, entanglement, parameter_prefix)
229
+ self.paulis = paulis
230
+ self.alpha = alpha
231
+
232
+ def _build_circuit(self, parameters: np.ndarray) -> Dict[str, Any]:
233
+ """Build Pauli feature map circuit."""
234
+ gates = []
235
+
236
+ for rep in range(self.reps):
237
+ for pauli_string in self.paulis:
238
+ if len(pauli_string) == 1:
239
+ # Single qubit Pauli
240
+ self._add_single_pauli_gates(
241
+ gates, pauli_string, parameters, rep
242
+ )
243
+ else:
244
+ # Multi-qubit Pauli
245
+ self._add_multi_pauli_gates(
246
+ gates, pauli_string, parameters, rep
247
+ )
248
+
249
+ return {
250
+ 'n_qubits': self.n_qubits,
251
+ 'gates': gates,
252
+ 'parameters': parameters.tolist(),
253
+ 'feature_map_type': 'Pauli',
254
+ 'paulis': self.paulis
255
+ }
256
+
257
+ def _add_single_pauli_gates(
258
+ self,
259
+ gates: List[Dict],
260
+ pauli: str,
261
+ parameters: np.ndarray,
262
+ rep: int
263
+ ):
264
+ """Add single-qubit Pauli rotation gates."""
265
+ for i in range(self.n_features):
266
+ param_idx = rep * self.n_features + i
267
+
268
+ if pauli == 'X':
269
+ gate_type = 'RX'
270
+ elif pauli == 'Y':
271
+ gate_type = 'RY'
272
+ elif pauli == 'Z':
273
+ gate_type = 'RZ'
274
+ else:
275
+ continue
276
+
277
+ gates.append({
278
+ 'type': gate_type,
279
+ 'qubit': i,
280
+ 'parameter': self.alpha * parameters[param_idx],
281
+ 'parameter_name': f'{self.parameter_prefix}_{param_idx}'
282
+ })
283
+
284
+ def _add_multi_pauli_gates(
285
+ self,
286
+ gates: List[Dict],
287
+ pauli_string: str,
288
+ parameters: np.ndarray,
289
+ rep: int
290
+ ):
291
+ """Add multi-qubit Pauli rotation gates."""
292
+ # For simplicity, handle ZZ case
293
+ if pauli_string == 'ZZ':
294
+ entangling_pairs = self._get_entangling_pairs()
295
+
296
+ for i, j in entangling_pairs:
297
+ param_i = rep * self.n_features + i
298
+ param_j = rep * self.n_features + j
299
+
300
+ gates.append({
301
+ 'type': 'RZZ',
302
+ 'qubits': [i, j],
303
+ 'parameter': self.alpha * parameters[param_i] * parameters[param_j],
304
+ 'parameter_names': [f'{self.parameter_prefix}_{param_i}',
305
+ f'{self.parameter_prefix}_{param_j}']
306
+ })
307
+
308
+
309
+ def create_feature_map(
310
+ feature_map_type: str,
311
+ n_features: int,
312
+ **kwargs
313
+ ) -> QuantumFeatureMap:
314
+ """Factory function to create quantum feature maps.
315
+
316
+ Args:
317
+ feature_map_type: Type of feature map ('Z', 'ZZ', 'Pauli')
318
+ n_features: Number of input features
319
+ **kwargs: Additional arguments for specific feature maps
320
+
321
+ Returns:
322
+ QuantumFeatureMap instance
323
+
324
+ """
325
+ feature_map_type = feature_map_type.upper()
326
+
327
+ if feature_map_type == 'Z':
328
+ return ZFeatureMap(n_features, **kwargs)
329
+ elif feature_map_type == 'ZZ':
330
+ return ZZFeatureMap(n_features, **kwargs)
331
+ elif feature_map_type == 'PAULI':
332
+ return PauliFeatureMap(n_features, **kwargs)
333
+ else:
334
+ raise ValueError(f"Unknown feature map type: {feature_map_type}")
335
+
336
+
337
+ def pauli_feature_map(
338
+ n_features: int,
339
+ paulis: List[str] = ['Z', 'ZZ'],
340
+ reps: int = 1,
341
+ alpha: float = 2.0,
342
+ entanglement: str = 'full'
343
+ ) -> PauliFeatureMap:
344
+ """Create a Pauli feature map with specified Pauli strings.
345
+
346
+ Args:
347
+ n_features: Number of input features
348
+ paulis: List of Pauli strings to use
349
+ reps: Number of repetitions
350
+ alpha: Scaling factor
351
+ entanglement: Entanglement pattern
352
+
353
+ Returns:
354
+ PauliFeatureMap instance
355
+
356
+ """
357
+ return PauliFeatureMap(
358
+ n_features=n_features,
359
+ paulis=paulis,
360
+ reps=reps,
361
+ alpha=alpha,
362
+ entanglement=entanglement
363
+ )
364
+
365
+
366
+ def zz_feature_map(
367
+ n_features: int,
368
+ reps: int = 1,
369
+ entanglement: str = 'linear',
370
+ alpha: float = 2.0
371
+ ) -> ZZFeatureMap:
372
+ """Create a ZZ feature map with specified parameters.
373
+
374
+ Args:
375
+ n_features: Number of input features
376
+ reps: Number of repetitions
377
+ entanglement: Entanglement pattern ('linear', 'circular', 'full')
378
+ alpha: Scaling factor
379
+
380
+ Returns:
381
+ ZZFeatureMap instance
382
+
383
+ """
384
+ return ZZFeatureMap(
385
+ n_features=n_features,
386
+ reps=reps,
387
+ entanglement=entanglement,
388
+ alpha=alpha
389
+ )
390
+
391
+
392
+ def feature_map_from_config(config: FeatureMapConfig) -> QuantumFeatureMap:
393
+ """Create feature map from configuration.
394
+
395
+ Args:
396
+ config: FeatureMapConfig instance
397
+
398
+ Returns:
399
+ QuantumFeatureMap instance
400
+
401
+ """
402
+ # Determine feature map type based on config
403
+ # This is a simplified approach - in practice, you'd need more logic
404
+ if config.entanglement == 'none':
405
+ return ZFeatureMap(
406
+ n_features=config.n_features,
407
+ reps=config.reps,
408
+ parameter_prefix=config.parameter_prefix
409
+ )
410
+ else:
411
+ return ZZFeatureMap(
412
+ n_features=config.n_features,
413
+ reps=config.reps,
414
+ entanglement=config.entanglement,
415
+ parameter_prefix=config.parameter_prefix
416
+ )
417
+
418
+
419
+ def evaluate_feature_map_expressibility(
420
+ feature_map: QuantumFeatureMap,
421
+ n_samples: int = 1000,
422
+ random_state: Optional[int] = None
423
+ ) -> Dict[str, float]:
424
+ """Evaluate the expressibility of a quantum feature map.
425
+
426
+ Expressibility measures how well a feature map can generate
427
+ diverse quantum states across the Hilbert space.
428
+
429
+ Args:
430
+ feature_map: QuantumFeatureMap to evaluate
431
+ n_samples: Number of random data points to sample
432
+ random_state: Random seed
433
+
434
+ Returns:
435
+ Dictionary with expressibility metrics
436
+
437
+ """
438
+ if random_state is not None:
439
+ np.random.seed(random_state)
440
+
441
+ # Generate random data points
442
+ X_random = np.random.uniform(-1, 1, (n_samples, feature_map.n_features))
443
+
444
+ # Map to quantum circuits
445
+ circuits = feature_map.map_data(X_random)
446
+
447
+ # Compute diversity metrics
448
+ # This is a simplified version - real implementation would need
449
+ # to simulate the circuits and compute state overlaps
450
+
451
+ parameter_diversity = []
452
+ for circuit in circuits:
453
+ params = circuit['parameters']
454
+ # Measure parameter diversity (standard deviation)
455
+ param_std = np.std(params)
456
+ parameter_diversity.append(param_std)
457
+
458
+ metrics = {
459
+ 'parameter_diversity_mean': np.mean(parameter_diversity),
460
+ 'parameter_diversity_std': np.std(parameter_diversity),
461
+ 'n_samples': n_samples,
462
+ 'n_features': feature_map.n_features,
463
+ 'n_qubits': feature_map.n_qubits,
464
+ 'reps': feature_map.reps
465
+ }
466
+
467
+ return metrics