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