Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pasqal device #31

Merged
merged 11 commits into from
Jul 8, 2020
1 change: 1 addition & 0 deletions pennylane_cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
===============
"""
from .simulator_device import SimulatorDevice, MixedStateSimulatorDevice
from .pasqal_device import PasqalDevice

from .ops import BitFlip, PhaseFlip, PhaseDamp, AmplitudeDamp, Depolarize
from ._version import __version__
2 changes: 1 addition & 1 deletion pennylane_cirq/cirq_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CirqDevice(QubitDevice, abc.ABC):
"""Abstract base device for PennyLane-Cirq.

Args:
wires (int): the number of modes to initialize the device in
wires (int): the number of wires to initialize the device with
shots (int): Number of circuit evaluations/random samples used
to estimate expectation values of observables. Shots need to be >= 1.
qubits (List[cirq.Qubit]): a list of Cirq qubits that are used
Expand Down
52 changes: 52 additions & 0 deletions pennylane_cirq/pasqal_device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Copyright 2018 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=too-many-arguments
"""
This module provides the ``PasqalDevice`` from Cirq.
"""
from cirq import pasqal

from .simulator_device import SimulatorDevice


class PasqalDevice(SimulatorDevice):
r"""Cirq Pasqal device for PennyLane.

Args:
wires (int): the number of wires to initialize the device with
shots (int): Number of circuit evaluations/random samples used
to estimate expectation values of observables. Shots need
to be >= 1. In analytic mode, shots indicates the number of entries
that are returned by ``device.sample``.
analytic (bool): Indicates whether expectation values and variances should
be calculated analytically. Defaults to ``True``.
co9olguy marked this conversation as resolved.
Show resolved Hide resolved
qubits (List[cirq.ThreeDGridQubit]): A list of Cirq ThreeDGridQubits that are used
as wires. If not specified, the ThreeDGridQubits are put in a linear
arrangement along the first coordinate axis,
i.e., (0,0,0), (1,0,0), (2,0,0), etc.
co9olguy marked this conversation as resolved.
Show resolved Hide resolved
control_radius (float): The maximum distance between qubits for a controlled
gate. Distance is measured in units of the indices passed into
the qubits keyword argument.
co9olguy marked this conversation as resolved.
Show resolved Hide resolved
"""
name = "Cirq Pasqal device for PennyLane"
short_name = "cirq.pasqal"

def __init__(self, wires, shots=1000, analytic=True, qubits=None, control_radius=1.0):

if not qubits:
qubits = [pasqal.ThreeDGridQubit(wire, 0, 0) for wire in range(wires)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another future option is to make use of the ThreeDGridQubit static methods, such as parallelep and rect to construct the array of qubits (https://github.com/lhenriet/Cirq/blob/125722761ca56a641db7e15c89303ed55f076441/cirq/pasqal/pasqal_qubits.py#L102)

self.control_radius = float(control_radius)
if self.control_radius < 0:
raise ValueError("The control_radius must be a non-negative real number.")
super().__init__(wires, shots, analytic, qubits)
co9olguy marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pennylane>=0.9
cirq>=0.7
google-api-core[grpc]<=1.14.0
co9olguy marked this conversation as resolved.
Show resolved Hide resolved
git+https://github.com/lhenriet/Cirq.git
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we want to deal with this requirement when merging into master? The issue I see is that this fork has diverged from Cirq master (it hasn't been kept up to date).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this in a separate branch, and undocumented, until that fork is successfully merged in. I'll try to keep abreast of when that might happen. In the meantime, we can continue our next steps (developing a tutorial) using the holding branch

numpy~=1.16
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"license": "Apache License 2.0",
"packages": ["pennylane_cirq"],
"entry_points": {"pennylane.plugins": ["cirq.simulator = pennylane_cirq:SimulatorDevice",
"cirq.mixedsimulator = pennylane_cirq:MixedStateSimulatorDevice"],},
"cirq.mixedsimulator = pennylane_cirq:MixedStateSimulatorDevice",
"cirq.pasqal = pennylane_cirq:PasqalDevice"],},
# Place a one line description here. This will be shown by pip
"description": "PennyLane plugin for Cirq",
"long_description": open("README.rst").read(),
Expand Down
80 changes: 80 additions & 0 deletions tests/test_pasqal_device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright 2018 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Unit tests for the PasqalDevice
"""
import pytest

import pennylane as qml
from pennylane_cirq import PasqalDevice, SimulatorDevice
from cirq.pasqal import ThreeDGridQubit


class TestDeviceIntegration:
"""Tests that the SimulatorDevice integrates well with PennyLane"""

def test_device_loading(self):
"""Tests that the cirq.pasqal device is properly loaded"""

dev = qml.device("cirq.pasqal", wires=2)

assert dev.num_wires == 2
assert len(dev.qubits) == 2
assert dev.shots == 1000
assert dev.short_name == "cirq.pasqal"
assert dev.analytic == True
assert dev.control_radius == 1.0
assert dev.qubits == [ThreeDGridQubit(0, 0, 0), ThreeDGridQubit(1, 0, 0)]
assert isinstance(dev, SimulatorDevice)


class TestDevice:
"""Unit tests for the PasqalDevice"""

def test_device_creation(self):
"""Tests that the cirq.pasqal device is properly created"""

dev = PasqalDevice(wires=2, shots=123, control_radius=5.0)

assert dev.num_wires == 2
assert len(dev.qubits) == 2
assert dev.shots == 123
assert dev.short_name == "cirq.pasqal"
assert dev.analytic == True
assert dev.control_radius == 5.0
assert dev.qubits == [ThreeDGridQubit(0, 0, 0), ThreeDGridQubit(1, 0, 0)]
assert isinstance(dev, SimulatorDevice)

@pytest.mark.parametrize(
"coord_idxs",
[
[(0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0)],
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)],
[(1, 2, 3), (3, 2, 1), (0, 0, 0), (-1, -1, -10)],
],
)
def test_device_creation(self, coord_idxs):
"""Tests that ThreeDGridQubits can be passed as an argument"""

qubits = [ThreeDGridQubit(*idxs) for idxs in coord_idxs]
dev = PasqalDevice(wires=4, qubits=qubits)

assert dev.qubits == qubits

def test_control_radius_negative_exception(self):
"""Tests that an exception is raised when the supplied control_radius parameter
is a negative real number"""

with pytest.raises(ValueError, match="must be a non-negative real number"):
dev = PasqalDevice(wires=2, shots=123, control_radius=-5.0)