From 51391a3c7d1b757101041e3c6d0bf3c872544502 Mon Sep 17 00:00:00 2001 From: Daria Van Hende <33431368+dariavh@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:39:50 +0200 Subject: [PATCH] Bugfix: change API to modularized `cirq` package. (#308) * Refactor circuit build to `cirq_google` module. * Add check for `cirq_google`, add test. * Update ci_backends.yml --- .github/workflows/ci_backends.yml | 2 +- requirements.txt | 1 + src/tequila/simulators/simulator_cirq.py | 40 +++++++++--------------- tests/test_simulator_backends.py | 15 +++++++++ 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci_backends.yml b/.github/workflows/ci_backends.yml index 16382a2b..c9c5852c 100644 --- a/.github/workflows/ci_backends.yml +++ b/.github/workflows/ci_backends.yml @@ -32,7 +32,7 @@ jobs: # myqlm does not work in python3.7 pip install "cirq" "qiskit>=0.30" "qulacs" "qibo==0.1.1" elif [ $ver -eq 8 ]; then - pip install "cirq" "qiskit>=0.30" "qulacs" "qibo==0.1.1" "myqlm" + pip install "cirq" "qiskit>=0.30" "qulacs" "qibo==0.1.1" "myqlm" "cirq-google" fi pip install -e . - name: Lint with flake8 diff --git a/requirements.txt b/requirements.txt index a67423b5..6f9ae975 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ qulacs # default simulator (best integration), remove if the installation gives #optional quantum backends #cirq >= 0.9.2 # +#cirq_google #qiskit>=0.30 #pyquil<3.0 # you also need to install the forest-sdk #qulacs-gpu # you can't have qulacs and qulacs-gpu at the same time diff --git a/src/tequila/simulators/simulator_cirq.py b/src/tequila/simulators/simulator_cirq.py index 782124f2..5115f90f 100755 --- a/src/tequila/simulators/simulator_cirq.py +++ b/src/tequila/simulators/simulator_cirq.py @@ -5,10 +5,12 @@ import sympy from tequila.utils import to_float +import importlib import numpy as np import typing, numbers import cirq +import cirq_google map_1 = lambda x: {'exponent': x} map_2 = lambda x: {'exponent': x / np.pi, 'global_shift': -0.5} @@ -356,35 +358,23 @@ def build_device_circuit(self, ignore_failures=False): line = None circuit = None if isinstance(device, cirq.Device): - if isinstance(device, cirq.google.devices.XmonDevice) or isinstance(device, - cirq.google.devices.serializable_device.SerializableDevice): - options = ['xmon', 'xmon_partial_cz', 'sqrt_iswap', 'sycamore'] - if device in [cirq.google.Sycamore, cirq.google.Sycamore23]: - options = ['sycamore', 'sqrt_iswap', 'xmon', 'xmon_partial_cz'] - for option in options: - try: - line = cirq.google.line_on_device(device, length=len(self.abstract_circuit.qubits)) - - circuit = cirq.google.optimized_for_sycamore(circuit=c, new_device=device, - optimizer_type=option, - qubit_map=lambda q: line[q.x]) - except: - line = None - pass - if circuit is None: - raise TequilaCirqException('could not optimize for device={}'.format(device)) - + HAS_GOOGLE = importlib.util.find_spec('cirq_google') + assert HAS_GOOGLE, TequilaCirqException(' cirq_google package is not installed.') + + if device in [cirq_google.Sycamore, cirq_google.Sycamore23]: + try: + circuit = cirq.optimize_for_target_gateset(circuit=c, gateset=cirq_google.SycamoreTargetGateset()) + except ValueError as E: + original_message = str(E) + raise TequilaCirqException('original message:\n{}\n\ncould not optimize for device={}'.format(original_message,device)) else: ### under construction (potentially on other branches) - raise TequilaException('Only known and Xmon devices currently functional. Sorry!') + raise TequilaException('Only Sycamore and Sycamore23 devices currently functional. Sorry!') + else: raise TequilaException( 'build_device_circuit demands a cirq.Device object; received {}, of type {}'.format(str(device), type(device))) - - if line is not None: - for k in self.qubit_map.keys(): - self.qubit_map[k].instance = line[self.qubit_map[k].instance.x] return circuit def build_noisy_circuit(self, noise): @@ -447,7 +437,7 @@ def retrieve_device(self, device): the device on which to execute cirq circuits. """ if isinstance(device, str): - return getattr(cirq.google, device) + return getattr(cirq_google, device) else: if device is None: return device @@ -474,7 +464,7 @@ def check_device(self, device): return else: assert isinstance(device, str) - if device.lower() in ['foxtail', 'sycamore', 'sycamore23', 'bristlecone']: + if device.lower() in ['sycamore', 'sycamore23']: pass else: raise TequilaException('requested device {} could not be found!'.format(device)) diff --git a/tests/test_simulator_backends.py b/tests/test_simulator_backends.py index e0461548..4c22976f 100644 --- a/tests/test_simulator_backends.py +++ b/tests/test_simulator_backends.py @@ -2,6 +2,7 @@ All Backends need to be installed for full testing """ +import importlib import numpy import pytest import random @@ -16,6 +17,20 @@ import os, glob +HAS_GOOGLE = importlib.util.find_spec('cirq_google') +@pytest.mark.skipif(condition=HAS_GOOGLE, reason="cirq_google not installed") +def test_cirq_google_devices(): + import cirq_google + + U = tq.paulis.X(0) + U += tq.gates.Givens(0, 1, angle=numpy.pi/4) # Givens rotation with angle = pi/4 gives 1/sqrt(2)|01> + 1/sqrt(2)|10> (up to a phase factor). + wfn = tq.simulate(U, device="Sycamore", backend="cirq") + wfnx0 = tq.simulate(tq.paulis.X(0)) + assert numpy.isclose(numpy.abs(wfn.inner(wfnx0))**2, 0.5) + wfnx1 = tq.simulate(tq.paulis.X(1)) + assert numpy.isclose(numpy.abs(wfn.inner(wfnx1))**2, 0.5) + + def teardown_function(function): [os.remove(x) for x in glob.glob("*.npy")] [os.remove(x) for x in glob.glob("qvm.log")]