Source code for quantum_launcher.routines.cirq_routines

 1"""
 2Routine file for Cirq library
 3"""
 4from typing import Literal
 5from collections.abc import Sequence
 6
 7from quantum_launcher.base import Backend
 8from quantum_launcher.base.translator import Translation
 9from quantum_launcher.import_management import DependencyError
10try:
11    import cirq
12    from cirq.sim.sparse_simulator import Simulator
13except ImportError as e:
14    raise DependencyError(e, install_hint='cirq') from e
15try:
16    import qiskit
17    from qiskit.primitives import Sampler
18    from qiskit.primitives.base.sampler_result import SamplerResult
19    from qiskit.result import QuasiDistribution
20    from qiskit_algorithms.optimizers import COBYLA
21except ImportError as e:
22    raise DependencyError(e, install_hint='qiskit') from e
23
24
25class _CirqRunner:
26    simulator = Simulator()
27    repetitions = 1024
28
29    @classmethod
30    def calculate_circuit(cls, circuit: qiskit.QuantumCircuit) -> dict:
31        circuit = circuit.measure_all(inplace=False)
32        cirq_circ = Translation.get_translation(circuit, 'cirq')
33        result = cls.simulator.run(cirq_circ, repetitions=cls.repetitions)
34        return cls._result_to_dist(result)
35
36    @classmethod
37    def _result_to_dist(cls, result) -> dict:
38        return cirq_result_to_probabilities(result)
39
40
[docs] 41class CirqSampler(Sampler): 42 """ Sampler adapter for Cirq """ 43 44 def _call(self, circuits: Sequence[int], parameter_values: Sequence[Sequence[float]], **run_options) -> SamplerResult: 45 bound_circuits = [] 46 for i, value in zip(circuits, parameter_values): 47 bound_circuits.append( 48 self._circuits[i] 49 if len(value) == 0 50 else self._circuits[i].assign_parameters(dict(zip(self._parameters[i], value))) 51 ) 52 distributions = [_CirqRunner.calculate_circuit(circuit) for circuit in bound_circuits] 53 quasi_dists = list(map(QuasiDistribution, distributions)) 54 return SamplerResult(quasi_dists, [{} for _ in range(len(parameter_values))])
55 56
[docs] 57class CirqBackend(Backend): 58 """ 59 60 Args: 61 Backend (_type_): _description_ 62 """ 63 64 def __init__(self, name: Literal['local_simulator'] = 'local_simulator'): 65 self.sampler = self.samplerV1 = CirqSampler() 66 self.optimizer = COBYLA() 67 super().__init__(name)
68 69
[docs] 70def cirq_result_to_probabilities( 71 result: cirq.Result, 72 integer_keys: bool = False 73) -> dict: 74 measurements = result.measurements 75 76 sorted_keys = list(measurements.keys()) 77 78 bitstrings = [] 79 num_shots = len(measurements[sorted_keys[0]]) 80 81 for shot_index in range(num_shots): 82 bits = [] 83 for key in sorted_keys: 84 bits.extend(str(b) for b in measurements[key][shot_index]) 85 86 bitstring = "".join(bits) 87 bitstrings.append(bitstring) 88 89 counts = {} 90 for bs in bitstrings: 91 counts[bs] = counts.get(bs, 0) + 1 92 93 total_shots = sum(counts.values()) 94 if integer_keys: 95 prob_dict = {int(k, 2): v / total_shots for k, v in counts.items()} 96 else: 97 prob_dict = {k: v / total_shots for k, v in counts.items()} 98 99 return prob_dict