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,466 @@
|
|
1
|
+
"""Cirq backend implementation for SuperQuantX.
|
2
|
+
|
3
|
+
This module provides integration with Google's Cirq for quantum computing
|
4
|
+
operations and access to Google Quantum AI hardware.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
9
|
+
|
10
|
+
import numpy as np
|
11
|
+
|
12
|
+
from .base_backend import BaseBackend
|
13
|
+
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
import cirq
|
17
|
+
|
18
|
+
logger = logging.getLogger(__name__)
|
19
|
+
|
20
|
+
# Try to import Cirq
|
21
|
+
try:
|
22
|
+
import cirq
|
23
|
+
CIRQ_AVAILABLE = True
|
24
|
+
except ImportError:
|
25
|
+
CIRQ_AVAILABLE = False
|
26
|
+
cirq = None
|
27
|
+
|
28
|
+
class CirqBackend(BaseBackend):
|
29
|
+
"""Cirq backend for quantum computing operations.
|
30
|
+
|
31
|
+
This backend provides access to Cirq simulators and Google Quantum AI
|
32
|
+
hardware for quantum algorithm execution.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
device: Cirq device name ('simulator', 'sycamore', etc.)
|
36
|
+
processor_id: Google Quantum AI processor ID
|
37
|
+
shots: Number of measurement shots
|
38
|
+
**kwargs: Additional backend parameters
|
39
|
+
|
40
|
+
"""
|
41
|
+
|
42
|
+
def __init__(self, device: str = 'simulator', processor_id: Optional[str] = None,
|
43
|
+
shots: int = 1024, **kwargs):
|
44
|
+
if not CIRQ_AVAILABLE:
|
45
|
+
raise ImportError("Cirq is required for CirqBackend. Install with: pip install cirq")
|
46
|
+
|
47
|
+
super().__init__(device=device, shots=shots, **kwargs)
|
48
|
+
|
49
|
+
self.processor_id = processor_id
|
50
|
+
self.simulator = None
|
51
|
+
self.quantum_engine = None
|
52
|
+
self.capabilities = {
|
53
|
+
'supports_gradient': False,
|
54
|
+
'supports_parameter_shift': True,
|
55
|
+
'supports_finite_diff': True,
|
56
|
+
'supports_hardware': processor_id is not None,
|
57
|
+
'supports_noise_models': True,
|
58
|
+
}
|
59
|
+
|
60
|
+
def _initialize_backend(self) -> None:
|
61
|
+
"""Initialize Cirq backend."""
|
62
|
+
try:
|
63
|
+
if self.device == 'simulator':
|
64
|
+
self.simulator = cirq.Simulator()
|
65
|
+
logger.info("Initialized Cirq Simulator")
|
66
|
+
|
67
|
+
elif self.processor_id:
|
68
|
+
try:
|
69
|
+
import cirq_google
|
70
|
+
# Initialize Google Quantum Engine
|
71
|
+
self.quantum_engine = cirq_google.get_engine()
|
72
|
+
logger.info(f"Initialized Google Quantum Engine with processor {self.processor_id}")
|
73
|
+
except ImportError:
|
74
|
+
logger.error("cirq-google required for hardware access")
|
75
|
+
self.simulator = cirq.Simulator()
|
76
|
+
logger.warning("Falling back to simulator")
|
77
|
+
|
78
|
+
else:
|
79
|
+
self.simulator = cirq.Simulator()
|
80
|
+
logger.info("Initialized default Cirq Simulator")
|
81
|
+
|
82
|
+
except Exception as e:
|
83
|
+
logger.error(f"Failed to initialize Cirq backend: {e}")
|
84
|
+
self.simulator = cirq.Simulator()
|
85
|
+
logger.warning("Falling back to default simulator")
|
86
|
+
|
87
|
+
def create_circuit(self, n_qubits: int) -> Any:
|
88
|
+
"""Create a quantum circuit with n qubits."""
|
89
|
+
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
|
90
|
+
circuit = cirq.Circuit()
|
91
|
+
return circuit, qubits # Return both circuit and qubits for convenience
|
92
|
+
|
93
|
+
def add_gate(self, circuit_info: Tuple[Any, List], gate: str,
|
94
|
+
qubits: Union[int, List[int]], params: Optional[List[float]] = None) -> Tuple[Any, List]:
|
95
|
+
"""Add a quantum gate to the circuit."""
|
96
|
+
circuit, qubit_list = circuit_info
|
97
|
+
|
98
|
+
if isinstance(qubits, int):
|
99
|
+
qubits = [qubits]
|
100
|
+
|
101
|
+
params = params or []
|
102
|
+
|
103
|
+
try:
|
104
|
+
if gate.upper() == 'H' or gate.upper() == 'HADAMARD':
|
105
|
+
circuit.append(cirq.H(qubit_list[qubits[0]]))
|
106
|
+
elif gate.upper() == 'X' or gate.upper() == 'PAULI_X':
|
107
|
+
circuit.append(cirq.X(qubit_list[qubits[0]]))
|
108
|
+
elif gate.upper() == 'Y' or gate.upper() == 'PAULI_Y':
|
109
|
+
circuit.append(cirq.Y(qubit_list[qubits[0]]))
|
110
|
+
elif gate.upper() == 'Z' or gate.upper() == 'PAULI_Z':
|
111
|
+
circuit.append(cirq.Z(qubit_list[qubits[0]]))
|
112
|
+
elif gate.upper() == 'RX':
|
113
|
+
circuit.append(cirq.rx(params[0] if params else 0)(qubit_list[qubits[0]]))
|
114
|
+
elif gate.upper() == 'RY':
|
115
|
+
circuit.append(cirq.ry(params[0] if params else 0)(qubit_list[qubits[0]]))
|
116
|
+
elif gate.upper() == 'RZ':
|
117
|
+
circuit.append(cirq.rz(params[0] if params else 0)(qubit_list[qubits[0]]))
|
118
|
+
elif gate.upper() == 'CNOT' or gate.upper() == 'CX':
|
119
|
+
circuit.append(cirq.CNOT(qubit_list[qubits[0]], qubit_list[qubits[1]]))
|
120
|
+
elif gate.upper() == 'CZ':
|
121
|
+
circuit.append(cirq.CZ(qubit_list[qubits[0]], qubit_list[qubits[1]]))
|
122
|
+
elif gate.upper() == 'SWAP':
|
123
|
+
circuit.append(cirq.SWAP(qubit_list[qubits[0]], qubit_list[qubits[1]]))
|
124
|
+
elif gate.upper() == 'CCX' or gate.upper() == 'TOFFOLI':
|
125
|
+
circuit.append(cirq.CCX(qubit_list[qubits[0]], qubit_list[qubits[1]], qubit_list[qubits[2]]))
|
126
|
+
else:
|
127
|
+
logger.warning(f"Unknown gate: {gate}")
|
128
|
+
|
129
|
+
except Exception as e:
|
130
|
+
logger.error(f"Failed to add gate {gate}: {e}")
|
131
|
+
|
132
|
+
return circuit, qubit_list
|
133
|
+
|
134
|
+
def add_measurement(self, circuit_info: Tuple[Any, List],
|
135
|
+
qubits: Optional[List[int]] = None) -> Tuple[Any, List]:
|
136
|
+
"""Add measurement operations to the circuit."""
|
137
|
+
circuit, qubit_list = circuit_info
|
138
|
+
|
139
|
+
if qubits is None:
|
140
|
+
qubits = list(range(len(qubit_list)))
|
141
|
+
|
142
|
+
measurement_qubits = [qubit_list[i] for i in qubits]
|
143
|
+
circuit.append(cirq.measure(*measurement_qubits, key='result'))
|
144
|
+
|
145
|
+
return circuit, qubit_list
|
146
|
+
|
147
|
+
def execute_circuit(self, circuit_info: Union[Any, Tuple], shots: Optional[int] = None) -> Dict[str, Any]:
|
148
|
+
"""Execute quantum circuit and return results."""
|
149
|
+
if isinstance(circuit_info, tuple):
|
150
|
+
circuit, qubit_list = circuit_info
|
151
|
+
else:
|
152
|
+
circuit = circuit_info
|
153
|
+
qubit_list = sorted(circuit.all_qubits())
|
154
|
+
|
155
|
+
shots = shots or self.shots
|
156
|
+
|
157
|
+
try:
|
158
|
+
if self.simulator:
|
159
|
+
# Run on simulator
|
160
|
+
result = self.simulator.run(circuit, repetitions=shots)
|
161
|
+
|
162
|
+
# Convert to counts format
|
163
|
+
if 'result' in result.measurements:
|
164
|
+
measurements = result.measurements['result']
|
165
|
+
counts = {}
|
166
|
+
for measurement in measurements:
|
167
|
+
bitstring = ''.join(str(bit) for bit in measurement)
|
168
|
+
counts[bitstring] = counts.get(bitstring, 0) + 1
|
169
|
+
else:
|
170
|
+
counts = {'0' * len(qubit_list): shots}
|
171
|
+
|
172
|
+
return {
|
173
|
+
'counts': counts,
|
174
|
+
'shots': shots,
|
175
|
+
'backend': 'cirq_simulator',
|
176
|
+
}
|
177
|
+
|
178
|
+
elif self.quantum_engine and self.processor_id:
|
179
|
+
# Run on Google Quantum AI hardware
|
180
|
+
processor = self.quantum_engine.get_processor(self.processor_id)
|
181
|
+
job = processor.run(circuit, repetitions=shots)
|
182
|
+
result = job.results()[0]
|
183
|
+
|
184
|
+
# Convert to counts format
|
185
|
+
measurements = result.measurements['result']
|
186
|
+
counts = {}
|
187
|
+
for measurement in measurements:
|
188
|
+
bitstring = ''.join(str(bit) for bit in measurement)
|
189
|
+
counts[bitstring] = counts.get(bitstring, 0) + 1
|
190
|
+
|
191
|
+
return {
|
192
|
+
'counts': counts,
|
193
|
+
'shots': shots,
|
194
|
+
'backend': f'google_quantum_{self.processor_id}',
|
195
|
+
'job_id': job.id(),
|
196
|
+
}
|
197
|
+
|
198
|
+
else:
|
199
|
+
raise ValueError("No execution backend available")
|
200
|
+
|
201
|
+
except Exception as e:
|
202
|
+
logger.error(f"Circuit execution failed: {e}")
|
203
|
+
raise
|
204
|
+
|
205
|
+
def get_statevector(self, circuit_info: Union[Any, Tuple]) -> np.ndarray:
|
206
|
+
"""Get the statevector from a quantum circuit."""
|
207
|
+
if isinstance(circuit_info, tuple):
|
208
|
+
circuit, qubit_list = circuit_info
|
209
|
+
else:
|
210
|
+
circuit = circuit_info
|
211
|
+
qubit_list = sorted(circuit.all_qubits())
|
212
|
+
|
213
|
+
try:
|
214
|
+
# Remove measurements for statevector simulation
|
215
|
+
circuit_copy = circuit.copy()
|
216
|
+
circuit_copy = cirq.Circuit([op for op in circuit_copy.all_operations()
|
217
|
+
if not isinstance(op.gate, cirq.MeasurementGate)])
|
218
|
+
|
219
|
+
# Simulate
|
220
|
+
result = self.simulator.simulate(circuit_copy)
|
221
|
+
statevector = result.final_state_vector
|
222
|
+
|
223
|
+
return np.array(statevector)
|
224
|
+
|
225
|
+
except Exception as e:
|
226
|
+
logger.error(f"Statevector computation failed: {e}")
|
227
|
+
n_qubits = len(qubit_list)
|
228
|
+
return np.array([1.0] + [0.0] * (2**n_qubits - 1))
|
229
|
+
|
230
|
+
def _get_n_qubits(self, circuit_info: Union[Any, Tuple]) -> int:
|
231
|
+
"""Get number of qubits in circuit."""
|
232
|
+
if isinstance(circuit_info, tuple):
|
233
|
+
circuit, qubit_list = circuit_info
|
234
|
+
return len(qubit_list)
|
235
|
+
else:
|
236
|
+
return len(circuit_info.all_qubits())
|
237
|
+
|
238
|
+
# ========================================================================
|
239
|
+
# Enhanced Cirq-specific implementations
|
240
|
+
# ========================================================================
|
241
|
+
|
242
|
+
def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Tuple[Any, List]:
|
243
|
+
"""Create quantum feature map for data encoding."""
|
244
|
+
qubits = [cirq.LineQubit(i) for i in range(n_features)]
|
245
|
+
circuit = cirq.Circuit()
|
246
|
+
|
247
|
+
if feature_map == 'ZZFeatureMap':
|
248
|
+
circuit_info = self._create_zz_feature_map(n_features, reps)
|
249
|
+
elif feature_map == 'PauliFeatureMap':
|
250
|
+
circuit_info = self._create_pauli_feature_map(n_features, reps)
|
251
|
+
elif feature_map == 'AmplitudeMap':
|
252
|
+
circuit_info = self._create_amplitude_map(n_features)
|
253
|
+
else:
|
254
|
+
logger.warning(f"Unknown feature map '{feature_map}', using angle encoding")
|
255
|
+
circuit_info = self._create_angle_encoding_map(n_features)
|
256
|
+
|
257
|
+
return circuit_info
|
258
|
+
|
259
|
+
def _create_zz_feature_map(self, n_features: int, reps: int) -> Tuple[Any, List]:
|
260
|
+
"""Create ZZ feature map circuit."""
|
261
|
+
qubits = [cirq.LineQubit(i) for i in range(n_features)]
|
262
|
+
circuit = cirq.Circuit()
|
263
|
+
|
264
|
+
for r in range(reps):
|
265
|
+
# Hadamard layer
|
266
|
+
circuit.append([cirq.H(q) for q in qubits])
|
267
|
+
|
268
|
+
# Parameterized rotations (placeholders)
|
269
|
+
for i, q in enumerate(qubits):
|
270
|
+
circuit.append(cirq.rz(cirq.Symbol(f'x_{i}'))(q))
|
271
|
+
|
272
|
+
# ZZ interactions
|
273
|
+
for i in range(n_features - 1):
|
274
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
275
|
+
circuit.append(cirq.rz(cirq.Symbol(f'x_{i}_x_{i+1}'))(qubits[i + 1]))
|
276
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
277
|
+
|
278
|
+
return circuit, qubits
|
279
|
+
|
280
|
+
def _create_pauli_feature_map(self, n_features: int, reps: int) -> Tuple[Any, List]:
|
281
|
+
"""Create Pauli feature map circuit."""
|
282
|
+
qubits = [cirq.LineQubit(i) for i in range(n_features)]
|
283
|
+
circuit = cirq.Circuit()
|
284
|
+
|
285
|
+
for r in range(reps):
|
286
|
+
# Pauli rotations
|
287
|
+
for i, q in enumerate(qubits):
|
288
|
+
circuit.append(cirq.rx(cirq.Symbol(f'x_{i}_rx_{r}'))(q))
|
289
|
+
circuit.append(cirq.ry(cirq.Symbol(f'x_{i}_ry_{r}'))(q))
|
290
|
+
circuit.append(cirq.rz(cirq.Symbol(f'x_{i}_rz_{r}'))(q))
|
291
|
+
|
292
|
+
# Entangling layer
|
293
|
+
for i in range(n_features - 1):
|
294
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
295
|
+
|
296
|
+
return circuit, qubits
|
297
|
+
|
298
|
+
def _create_amplitude_map(self, n_features: int) -> Tuple[Any, List]:
|
299
|
+
"""Create amplitude encoding map."""
|
300
|
+
n_qubits = int(np.ceil(np.log2(n_features)))
|
301
|
+
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
|
302
|
+
circuit = cirq.Circuit()
|
303
|
+
|
304
|
+
# Amplitude encoding would require state preparation
|
305
|
+
# This is a simplified placeholder
|
306
|
+
logger.warning("Amplitude encoding not fully implemented")
|
307
|
+
|
308
|
+
return circuit, qubits
|
309
|
+
|
310
|
+
def _create_angle_encoding_map(self, n_features: int) -> Tuple[Any, List]:
|
311
|
+
"""Create angle encoding map."""
|
312
|
+
qubits = [cirq.LineQubit(i) for i in range(n_features)]
|
313
|
+
circuit = cirq.Circuit()
|
314
|
+
|
315
|
+
for i, q in enumerate(qubits):
|
316
|
+
circuit.append(cirq.ry(cirq.Symbol(f'x_{i}'))(q))
|
317
|
+
|
318
|
+
return circuit, qubits
|
319
|
+
|
320
|
+
def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
|
321
|
+
include_custom_gates: bool = False) -> Tuple[Any, List]:
|
322
|
+
"""Create parameterized ansatz circuit."""
|
323
|
+
if ansatz_type == 'RealAmplitudes':
|
324
|
+
return self._create_real_amplitudes_ansatz(n_qubits, params)
|
325
|
+
elif ansatz_type == 'EfficientSU2':
|
326
|
+
return self._create_efficient_su2_ansatz(n_qubits, params)
|
327
|
+
elif ansatz_type == 'TwoLocal':
|
328
|
+
return self._create_two_local_ansatz(n_qubits, params)
|
329
|
+
elif ansatz_type == 'UCCSD':
|
330
|
+
return self._create_uccsd_ansatz(n_qubits, params)
|
331
|
+
else:
|
332
|
+
logger.warning(f"Unknown ansatz '{ansatz_type}', using RealAmplitudes")
|
333
|
+
return self._create_real_amplitudes_ansatz(n_qubits, params)
|
334
|
+
|
335
|
+
def _create_real_amplitudes_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
|
336
|
+
"""Create RealAmplitudes ansatz."""
|
337
|
+
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
|
338
|
+
circuit = cirq.Circuit()
|
339
|
+
|
340
|
+
n_layers = len(params) // (n_qubits * 2)
|
341
|
+
param_idx = 0
|
342
|
+
|
343
|
+
for layer in range(n_layers):
|
344
|
+
# RY rotations
|
345
|
+
for i, q in enumerate(qubits):
|
346
|
+
if param_idx < len(params):
|
347
|
+
circuit.append(cirq.ry(params[param_idx])(q))
|
348
|
+
param_idx += 1
|
349
|
+
|
350
|
+
# Entangling layer
|
351
|
+
for i in range(n_qubits - 1):
|
352
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
353
|
+
|
354
|
+
# RZ rotations
|
355
|
+
for i, q in enumerate(qubits):
|
356
|
+
if param_idx < len(params):
|
357
|
+
circuit.append(cirq.rz(params[param_idx])(q))
|
358
|
+
param_idx += 1
|
359
|
+
|
360
|
+
return circuit, qubits
|
361
|
+
|
362
|
+
def _create_efficient_su2_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
|
363
|
+
"""Create EfficientSU2 ansatz."""
|
364
|
+
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
|
365
|
+
circuit = cirq.Circuit()
|
366
|
+
|
367
|
+
n_layers = len(params) // (n_qubits * 3)
|
368
|
+
param_idx = 0
|
369
|
+
|
370
|
+
for layer in range(n_layers):
|
371
|
+
# SU(2) rotations
|
372
|
+
for i, q in enumerate(qubits):
|
373
|
+
if param_idx + 2 < len(params):
|
374
|
+
circuit.append(cirq.ry(params[param_idx])(q))
|
375
|
+
circuit.append(cirq.rz(params[param_idx + 1])(q))
|
376
|
+
circuit.append(cirq.ry(params[param_idx + 2])(q))
|
377
|
+
param_idx += 3
|
378
|
+
|
379
|
+
# Entangling layer
|
380
|
+
for i in range(n_qubits - 1):
|
381
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
382
|
+
|
383
|
+
return circuit, qubits
|
384
|
+
|
385
|
+
def _create_two_local_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
|
386
|
+
"""Create TwoLocal ansatz."""
|
387
|
+
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
|
388
|
+
circuit = cirq.Circuit()
|
389
|
+
|
390
|
+
n_layers = len(params) // (n_qubits * 2)
|
391
|
+
param_idx = 0
|
392
|
+
|
393
|
+
for layer in range(n_layers):
|
394
|
+
# Local rotations
|
395
|
+
for i, q in enumerate(qubits):
|
396
|
+
if param_idx + 1 < len(params):
|
397
|
+
circuit.append(cirq.ry(params[param_idx])(q))
|
398
|
+
circuit.append(cirq.rz(params[param_idx + 1])(q))
|
399
|
+
param_idx += 2
|
400
|
+
|
401
|
+
# Two-qubit gates
|
402
|
+
for i in range(0, n_qubits - 1, 2):
|
403
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
404
|
+
for i in range(1, n_qubits - 1, 2):
|
405
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
406
|
+
|
407
|
+
return circuit, qubits
|
408
|
+
|
409
|
+
def _create_uccsd_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
|
410
|
+
"""Create UCCSD ansatz (simplified)."""
|
411
|
+
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
|
412
|
+
circuit = cirq.Circuit()
|
413
|
+
|
414
|
+
param_idx = 0
|
415
|
+
|
416
|
+
# Single excitations
|
417
|
+
for i in range(0, n_qubits, 2):
|
418
|
+
for j in range(1, n_qubits, 2):
|
419
|
+
if param_idx < len(params) and i != j:
|
420
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[j]))
|
421
|
+
circuit.append(cirq.ry(params[param_idx])(qubits[j]))
|
422
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[j]))
|
423
|
+
param_idx += 1
|
424
|
+
|
425
|
+
# Double excitations (simplified)
|
426
|
+
for i in range(0, n_qubits - 3, 2):
|
427
|
+
if param_idx < len(params):
|
428
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
429
|
+
circuit.append(cirq.CNOT(qubits[i + 2], qubits[i + 3]))
|
430
|
+
circuit.append(cirq.ry(params[param_idx])(qubits[i + 1]))
|
431
|
+
circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
|
432
|
+
circuit.append(cirq.CNOT(qubits[i + 2], qubits[i + 3]))
|
433
|
+
param_idx += 1
|
434
|
+
|
435
|
+
return circuit, qubits
|
436
|
+
|
437
|
+
def compute_expectation(self, circuit_info: Union[Any, Tuple], hamiltonian: Any,
|
438
|
+
shots: Optional[int] = None) -> float:
|
439
|
+
"""Compute expectation value of Hamiltonian."""
|
440
|
+
try:
|
441
|
+
if isinstance(hamiltonian, np.ndarray):
|
442
|
+
# Compute expectation using statevector
|
443
|
+
statevector = self.get_statevector(circuit_info)
|
444
|
+
expectation = np.real(np.conj(statevector) @ hamiltonian @ statevector)
|
445
|
+
return float(expectation)
|
446
|
+
else:
|
447
|
+
logger.warning("Hamiltonian expectation not fully implemented")
|
448
|
+
return 0.0
|
449
|
+
|
450
|
+
except Exception as e:
|
451
|
+
logger.error(f"Expectation computation failed: {e}")
|
452
|
+
return 0.0
|
453
|
+
|
454
|
+
def get_version_info(self) -> Dict[str, Any]:
|
455
|
+
"""Get Cirq version information."""
|
456
|
+
info = super().get_version_info()
|
457
|
+
|
458
|
+
try:
|
459
|
+
info.update({
|
460
|
+
'cirq_version': cirq.__version__,
|
461
|
+
'processor_id': self.processor_id,
|
462
|
+
})
|
463
|
+
except Exception as e:
|
464
|
+
info['version_error'] = str(e)
|
465
|
+
|
466
|
+
return info
|