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,420 @@
|
|
1
|
+
"""AWS Braket backend implementation for SuperQuantX.
|
2
|
+
|
3
|
+
This module provides integration with Amazon Braket for quantum computing
|
4
|
+
on AWS quantum hardware and simulators.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
9
|
+
|
10
|
+
import numpy as np
|
11
|
+
|
12
|
+
from .base_backend import BaseBackend
|
13
|
+
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
# Try to import AWS Braket
|
18
|
+
try:
|
19
|
+
from braket.circuits import Circuit as BraketCircuit
|
20
|
+
from braket.circuits import Gate, Instruction
|
21
|
+
from braket.circuits.gates import *
|
22
|
+
from braket.devices import LocalSimulator
|
23
|
+
try:
|
24
|
+
from braket.aws import AwsDevice
|
25
|
+
AWS_AVAILABLE = True
|
26
|
+
except:
|
27
|
+
AWS_AVAILABLE = False
|
28
|
+
BRAKET_AVAILABLE = True
|
29
|
+
except ImportError:
|
30
|
+
BRAKET_AVAILABLE = False
|
31
|
+
AWS_AVAILABLE = False
|
32
|
+
BraketCircuit = None
|
33
|
+
LocalSimulator = None
|
34
|
+
|
35
|
+
class BraketBackend(BaseBackend):
|
36
|
+
"""AWS Braket backend for quantum computing operations.
|
37
|
+
|
38
|
+
This backend provides access to AWS Braket's quantum devices including
|
39
|
+
local simulators, managed simulators, and QPU hardware from IonQ, Rigetti,
|
40
|
+
and other providers available on AWS.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
device: Device name or ARN (e.g., 'local:braket/braket_sv', 'arn:aws:braket::device/qpu/ionq/ionQdevice')
|
44
|
+
shots: Number of measurement shots
|
45
|
+
aws_session: Optional AWS session for authentication
|
46
|
+
s3_folder: S3 bucket folder for results (required for hardware)
|
47
|
+
**kwargs: Additional device configuration
|
48
|
+
|
49
|
+
Example:
|
50
|
+
>>> # Local simulator
|
51
|
+
>>> backend = BraketBackend(device='local:braket/braket_sv')
|
52
|
+
>>>
|
53
|
+
>>> # AWS hardware (requires authentication)
|
54
|
+
>>> backend = BraketBackend(
|
55
|
+
... device='arn:aws:braket::device/qpu/ionq/ionQdevice',
|
56
|
+
... s3_folder=('my-bucket', 'quantum-results')
|
57
|
+
... )
|
58
|
+
|
59
|
+
"""
|
60
|
+
|
61
|
+
def __init__(
|
62
|
+
self,
|
63
|
+
device: str = 'local:braket/braket_sv',
|
64
|
+
shots: int = 1024,
|
65
|
+
aws_session = None,
|
66
|
+
s3_folder: Optional[Tuple[str, str]] = None,
|
67
|
+
**kwargs
|
68
|
+
) -> None:
|
69
|
+
if not BRAKET_AVAILABLE:
|
70
|
+
raise ImportError(
|
71
|
+
"AWS Braket not available. Install with: pip install amazon-braket-sdk"
|
72
|
+
)
|
73
|
+
|
74
|
+
self.device_name = device
|
75
|
+
self.aws_session = aws_session
|
76
|
+
self.s3_folder = s3_folder
|
77
|
+
self._device = None
|
78
|
+
|
79
|
+
super().__init__(device=device, shots=shots, **kwargs)
|
80
|
+
|
81
|
+
def _initialize_backend(self) -> None:
|
82
|
+
"""Initialize AWS Braket backend and device."""
|
83
|
+
try:
|
84
|
+
if self.device_name.startswith('local:'):
|
85
|
+
# Local simulator
|
86
|
+
simulator_name = self.device_name.split('local:')[1]
|
87
|
+
self._device = LocalSimulator(simulator_name)
|
88
|
+
logger.info(f"Initialized Braket local simulator: {simulator_name}")
|
89
|
+
|
90
|
+
elif self.device_name.startswith('arn:aws:braket'):
|
91
|
+
# AWS hardware/managed simulators
|
92
|
+
if not AWS_AVAILABLE:
|
93
|
+
raise ImportError("AWS Braket cloud access not available")
|
94
|
+
|
95
|
+
self._device = AwsDevice(
|
96
|
+
arn=self.device_name,
|
97
|
+
aws_session=self.aws_session
|
98
|
+
)
|
99
|
+
logger.info(f"Initialized AWS Braket device: {self.device_name}")
|
100
|
+
|
101
|
+
# Verify S3 folder for hardware
|
102
|
+
if 'qpu' in self.device_name.lower() and not self.s3_folder:
|
103
|
+
logger.warning("QPU devices typically require S3 folder for results")
|
104
|
+
|
105
|
+
else:
|
106
|
+
raise ValueError(f"Invalid device name: {self.device_name}")
|
107
|
+
|
108
|
+
self.capabilities = {
|
109
|
+
'supports_measurements': True,
|
110
|
+
'supports_parameterized_circuits': True,
|
111
|
+
'supports_classical_control': False, # Limited support
|
112
|
+
'max_qubits': self._get_max_qubits(),
|
113
|
+
'native_gates': self._get_native_gates(),
|
114
|
+
}
|
115
|
+
|
116
|
+
except Exception as e:
|
117
|
+
logger.error(f"Failed to initialize Braket backend: {e}")
|
118
|
+
raise
|
119
|
+
|
120
|
+
def _get_max_qubits(self) -> int:
|
121
|
+
"""Get maximum number of qubits for the device."""
|
122
|
+
if hasattr(self._device, 'properties'):
|
123
|
+
try:
|
124
|
+
return self._device.properties.paradigm.qubit_count
|
125
|
+
except:
|
126
|
+
pass
|
127
|
+
# Default estimates
|
128
|
+
if 'sv' in self.device_name:
|
129
|
+
return 34 # SV1 simulator
|
130
|
+
elif 'tn1' in self.device_name:
|
131
|
+
return 50 # TN1 tensor network
|
132
|
+
elif 'dm1' in self.device_name:
|
133
|
+
return 17 # DM1 density matrix
|
134
|
+
else:
|
135
|
+
return 30 # Conservative estimate for hardware
|
136
|
+
|
137
|
+
def _get_native_gates(self) -> List[str]:
|
138
|
+
"""Get native gates supported by the device."""
|
139
|
+
# Common Braket gates
|
140
|
+
return [
|
141
|
+
'i', 'x', 'y', 'z', 'h', 's', 'si', 't', 'ti',
|
142
|
+
'rx', 'ry', 'rz', 'cnot', 'cz', 'cy', 'swap',
|
143
|
+
'iswap', 'pswap', 'phaseshift', 'cphaseshift',
|
144
|
+
'ccnot', 'cswap'
|
145
|
+
]
|
146
|
+
|
147
|
+
# ========================================================================
|
148
|
+
# Core Circuit Operations
|
149
|
+
# ========================================================================
|
150
|
+
|
151
|
+
def create_circuit(self, n_qubits: int) -> BraketCircuit:
|
152
|
+
"""Create a Braket quantum circuit."""
|
153
|
+
if n_qubits > self._get_max_qubits():
|
154
|
+
logger.warning(f"Requested {n_qubits} qubits exceeds device limit")
|
155
|
+
|
156
|
+
return BraketCircuit()
|
157
|
+
|
158
|
+
def add_gate(self, circuit: BraketCircuit, gate: str, qubits: Union[int, List[int]],
|
159
|
+
params: Optional[List[float]] = None) -> BraketCircuit:
|
160
|
+
"""Add a quantum gate to the circuit."""
|
161
|
+
if isinstance(qubits, int):
|
162
|
+
qubits = [qubits]
|
163
|
+
|
164
|
+
params = params or []
|
165
|
+
|
166
|
+
# Map gate names to Braket gates
|
167
|
+
gate_mapping = {
|
168
|
+
'i': I, 'x': X, 'y': Y, 'z': Z, 'h': H,
|
169
|
+
's': S, 'sdg': Si, 't': T, 'tdg': Ti,
|
170
|
+
'rx': RX, 'ry': RY, 'rz': RZ,
|
171
|
+
'cnot': CNot, 'cx': CNot, 'cz': CZ, 'cy': CY,
|
172
|
+
'swap': Swap, 'iswap': ISwap,
|
173
|
+
'ccnot': CCNot, 'toffoli': CCNot,
|
174
|
+
'cswap': CSwap, 'fredkin': CSwap
|
175
|
+
}
|
176
|
+
|
177
|
+
gate_lower = gate.lower()
|
178
|
+
if gate_lower not in gate_mapping:
|
179
|
+
raise ValueError(f"Gate '{gate}' not supported in Braket backend")
|
180
|
+
|
181
|
+
gate_class = gate_mapping[gate_lower]
|
182
|
+
|
183
|
+
try:
|
184
|
+
if len(params) == 0:
|
185
|
+
# Parameter-less gates
|
186
|
+
if len(qubits) == 1:
|
187
|
+
circuit.add_instruction(Instruction(gate_class(), qubits[0]))
|
188
|
+
elif len(qubits) == 2:
|
189
|
+
circuit.add_instruction(Instruction(gate_class(), qubits))
|
190
|
+
elif len(qubits) == 3:
|
191
|
+
circuit.add_instruction(Instruction(gate_class(), qubits))
|
192
|
+
else:
|
193
|
+
raise ValueError(f"Too many qubits for gate {gate}")
|
194
|
+
|
195
|
+
else:
|
196
|
+
# Parameterized gates
|
197
|
+
if gate_lower in ['rx', 'ry', 'rz']:
|
198
|
+
circuit.add_instruction(Instruction(gate_class(params[0]), qubits[0]))
|
199
|
+
elif gate_lower == 'phaseshift':
|
200
|
+
circuit.add_instruction(Instruction(PhaseShift(params[0]), qubits[0]))
|
201
|
+
elif gate_lower == 'cphaseshift':
|
202
|
+
circuit.add_instruction(Instruction(CPhaseShift(params[0]), qubits))
|
203
|
+
else:
|
204
|
+
raise ValueError(f"Parameters not supported for gate {gate}")
|
205
|
+
|
206
|
+
except Exception as e:
|
207
|
+
logger.error(f"Failed to add gate {gate} to circuit: {e}")
|
208
|
+
raise
|
209
|
+
|
210
|
+
return circuit
|
211
|
+
|
212
|
+
def add_measurement(self, circuit: BraketCircuit, qubits: Union[int, List[int]]) -> BraketCircuit:
|
213
|
+
"""Add measurement instructions to specified qubits."""
|
214
|
+
if isinstance(qubits, int):
|
215
|
+
qubits = [qubits]
|
216
|
+
|
217
|
+
# Braket doesn't use explicit measurement instructions in circuits
|
218
|
+
# Measurements are handled during task submission
|
219
|
+
# Store measurement info for later use
|
220
|
+
if not hasattr(circuit, '_measurement_qubits'):
|
221
|
+
circuit._measurement_qubits = set()
|
222
|
+
circuit._measurement_qubits.update(qubits)
|
223
|
+
|
224
|
+
return circuit
|
225
|
+
|
226
|
+
def execute_circuit(self, circuit: BraketCircuit, shots: Optional[int] = None) -> Dict[str, Any]:
|
227
|
+
"""Execute quantum circuit and return results."""
|
228
|
+
shots = shots or self.shots
|
229
|
+
|
230
|
+
try:
|
231
|
+
# Get measurement qubits (all qubits if not specified)
|
232
|
+
if hasattr(circuit, '_measurement_qubits'):
|
233
|
+
measure_qubits = sorted(circuit._measurement_qubits)
|
234
|
+
else:
|
235
|
+
# Measure all qubits that have gates applied
|
236
|
+
measure_qubits = list(range(circuit.qubit_count))
|
237
|
+
|
238
|
+
# Add measurement to circuit copy
|
239
|
+
measured_circuit = circuit.copy()
|
240
|
+
for qubit in measure_qubits:
|
241
|
+
measured_circuit.add_instruction(Instruction(Measure(), qubit))
|
242
|
+
|
243
|
+
# Execute task
|
244
|
+
if self.s3_folder and hasattr(self._device, 'run'):
|
245
|
+
# AWS device with S3 storage
|
246
|
+
task = self._device.run(measured_circuit, shots=shots, s3_destination_folder=self.s3_folder)
|
247
|
+
result = task.result()
|
248
|
+
else:
|
249
|
+
# Local simulator
|
250
|
+
task = self._device.run(measured_circuit, shots=shots)
|
251
|
+
result = task.result()
|
252
|
+
|
253
|
+
# Process measurement results
|
254
|
+
measurement_counts = result.measurement_counts
|
255
|
+
|
256
|
+
# Convert to standard format
|
257
|
+
counts = {}
|
258
|
+
for bitstring, count in measurement_counts.items():
|
259
|
+
counts[bitstring] = count
|
260
|
+
|
261
|
+
return {
|
262
|
+
'counts': counts,
|
263
|
+
'shots': shots,
|
264
|
+
'success': True,
|
265
|
+
'measurement_qubits': measure_qubits,
|
266
|
+
'task_arn': getattr(task, 'id', 'local'),
|
267
|
+
'device': self.device_name,
|
268
|
+
}
|
269
|
+
|
270
|
+
except Exception as e:
|
271
|
+
logger.error(f"Circuit execution failed: {e}")
|
272
|
+
return {
|
273
|
+
'counts': {},
|
274
|
+
'shots': shots,
|
275
|
+
'success': False,
|
276
|
+
'error': str(e),
|
277
|
+
'device': self.device_name,
|
278
|
+
}
|
279
|
+
|
280
|
+
# ========================================================================
|
281
|
+
# Algorithm-Specific Operations
|
282
|
+
# ========================================================================
|
283
|
+
|
284
|
+
def create_parameterized_circuit(self, n_qubits: int, n_params: int) -> Tuple[BraketCircuit, List[str]]:
|
285
|
+
"""Create a parameterized quantum circuit for variational algorithms."""
|
286
|
+
circuit = self.create_circuit(n_qubits)
|
287
|
+
|
288
|
+
# Create parameter names
|
289
|
+
param_names = [f"theta_{i}" for i in range(n_params)]
|
290
|
+
|
291
|
+
# Store parameter info
|
292
|
+
circuit._param_names = param_names
|
293
|
+
circuit._n_params = n_params
|
294
|
+
|
295
|
+
return circuit, param_names
|
296
|
+
|
297
|
+
def bind_parameters(self, circuit: BraketCircuit, param_values: Dict[str, float]) -> BraketCircuit:
|
298
|
+
"""Bind parameter values to parameterized circuit."""
|
299
|
+
# Braket handles parameterization differently - would need custom implementation
|
300
|
+
# For now, create a new circuit with bound parameters
|
301
|
+
bound_circuit = circuit.copy()
|
302
|
+
|
303
|
+
# This is a simplified implementation
|
304
|
+
# In practice, you'd need to track parameterized gates and substitute values
|
305
|
+
logger.warning("Parameter binding in Braket backend is simplified")
|
306
|
+
|
307
|
+
return bound_circuit
|
308
|
+
|
309
|
+
def expectation_value(self, circuit: BraketCircuit, observable: Union[str, np.ndarray],
|
310
|
+
shots: Optional[int] = None) -> float:
|
311
|
+
"""Calculate expectation value of observable."""
|
312
|
+
shots = shots or self.shots
|
313
|
+
|
314
|
+
try:
|
315
|
+
# Simple implementation for Pauli observables
|
316
|
+
if isinstance(observable, str):
|
317
|
+
if observable.upper() == 'Z':
|
318
|
+
# Measure in Z basis
|
319
|
+
result = self.execute_circuit(circuit, shots)
|
320
|
+
counts = result['counts']
|
321
|
+
|
322
|
+
# Calculate <Z> expectation
|
323
|
+
expectation = 0.0
|
324
|
+
total_counts = sum(counts.values())
|
325
|
+
|
326
|
+
for bitstring, count in counts.items():
|
327
|
+
# Z expectation: +1 for |0>, -1 for |1>
|
328
|
+
prob = count / total_counts
|
329
|
+
if bitstring == '0' or (len(bitstring) > 0 and bitstring[0] == '0'):
|
330
|
+
expectation += prob
|
331
|
+
else:
|
332
|
+
expectation -= prob
|
333
|
+
|
334
|
+
return expectation
|
335
|
+
else:
|
336
|
+
logger.warning(f"Observable {observable} not fully implemented")
|
337
|
+
return 0.0
|
338
|
+
else:
|
339
|
+
logger.warning("Matrix observables not implemented")
|
340
|
+
return 0.0
|
341
|
+
|
342
|
+
except Exception as e:
|
343
|
+
logger.error(f"Expectation value calculation failed: {e}")
|
344
|
+
return 0.0
|
345
|
+
|
346
|
+
# ========================================================================
|
347
|
+
# Backend Information
|
348
|
+
# ========================================================================
|
349
|
+
|
350
|
+
def get_backend_info(self) -> Dict[str, Any]:
|
351
|
+
"""Get information about the Braket backend."""
|
352
|
+
info = {
|
353
|
+
'backend_name': 'braket',
|
354
|
+
'device': self.device_name,
|
355
|
+
'provider': 'AWS Braket',
|
356
|
+
'shots': self.shots,
|
357
|
+
'capabilities': self.capabilities,
|
358
|
+
'local_simulator': self.device_name.startswith('local:'),
|
359
|
+
}
|
360
|
+
|
361
|
+
if hasattr(self._device, 'properties'):
|
362
|
+
try:
|
363
|
+
props = self._device.properties
|
364
|
+
info.update({
|
365
|
+
'device_type': getattr(props, 'deviceType', 'unknown'),
|
366
|
+
'provider_name': getattr(props, 'providerName', 'AWS'),
|
367
|
+
'max_qubits': getattr(props.paradigm, 'qubit_count', 'unknown') if hasattr(props, 'paradigm') else 'unknown',
|
368
|
+
})
|
369
|
+
except:
|
370
|
+
pass
|
371
|
+
|
372
|
+
return info
|
373
|
+
|
374
|
+
def get_version_info(self) -> Dict[str, str]:
|
375
|
+
"""Get version information for Braket dependencies."""
|
376
|
+
import braket
|
377
|
+
return {
|
378
|
+
'braket_sdk': getattr(braket, '__version__', 'unknown'),
|
379
|
+
'backend_version': '1.0.0',
|
380
|
+
}
|
381
|
+
|
382
|
+
def is_available(self) -> bool:
|
383
|
+
"""Check if the backend is available and properly configured."""
|
384
|
+
return BRAKET_AVAILABLE and self._device is not None
|
385
|
+
|
386
|
+
def get_circuit_info(self) -> Dict[str, Any]:
|
387
|
+
"""Get information about circuit execution capabilities."""
|
388
|
+
return {
|
389
|
+
'max_qubits': self._get_max_qubits(),
|
390
|
+
'native_gates': self._get_native_gates(),
|
391
|
+
'supports_mid_circuit_measurement': False,
|
392
|
+
'supports_reset': False,
|
393
|
+
'supports_conditional': False,
|
394
|
+
}
|
395
|
+
|
396
|
+
def _get_n_qubits(self, circuit: BraketCircuit) -> int:
|
397
|
+
"""Get number of qubits in Braket circuit."""
|
398
|
+
return circuit.qubit_count
|
399
|
+
|
400
|
+
def get_statevector(self, circuit: BraketCircuit) -> np.ndarray:
|
401
|
+
"""Get statevector from Braket circuit."""
|
402
|
+
try:
|
403
|
+
# Use local simulator for statevector
|
404
|
+
from braket.devices import LocalSimulator
|
405
|
+
sv_device = LocalSimulator("braket_sv")
|
406
|
+
|
407
|
+
# Execute without measurements for statevector
|
408
|
+
task = sv_device.run(circuit, shots=0)
|
409
|
+
result = task.result()
|
410
|
+
|
411
|
+
if hasattr(result, 'get_value_by_result_type'):
|
412
|
+
from braket.circuits.result_types import StateVector
|
413
|
+
return result.get_value_by_result_type(StateVector())
|
414
|
+
else:
|
415
|
+
logger.warning("Statevector not available")
|
416
|
+
return np.zeros(2**circuit.qubit_count, dtype=complex)
|
417
|
+
|
418
|
+
except Exception as e:
|
419
|
+
logger.error(f"Failed to get statevector: {e}")
|
420
|
+
return np.zeros(2**circuit.qubit_count, dtype=complex)
|