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