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 reference.qubit for testing and reference #6181

Merged
merged 80 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
15247a9
Implement ReferenceQubit
astralcai Sep 3, 2024
6060ad6
make isort happy
astralcai Sep 4, 2024
f1f6557
Merge branch 'master' into mini-dev-new
astralcai Sep 4, 2024
5a0bea6
Fix bug in reference.qubit
astralcai Sep 4, 2024
2068b19
Add `reference.qubit` to autograd tests
astralcai Sep 4, 2024
66b3769
add reference.qubit to autograd qnode tests
astralcai Sep 5, 2024
db63bb6
xfail unsupported test
astralcai Sep 5, 2024
5b7b10b
Add reference.qubit to test_jax
astralcai Sep 5, 2024
74bc82b
fix bug
dwierichs Sep 5, 2024
a7a53de
-a
dwierichs Sep 5, 2024
d78e4e1
changelog
dwierichs Sep 5, 2024
a699575
Merge branch 'fix-jvp-shots' of https://github.com/PennyLaneAI/pennyl…
astralcai Sep 5, 2024
91c198d
more test cases in test_jax
astralcai Sep 5, 2024
0fdcc03
update test_jax_qnode
astralcai Sep 5, 2024
4cf6c28
add reference.qubit to test_jax_jit_qnode
astralcai Sep 5, 2024
f08d9df
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
astralcai Sep 5, 2024
df4c2a1
fix test_spsa_gradient after autograd change
astralcai Sep 5, 2024
54b46e6
fix more spsa test
astralcai Sep 5, 2024
7d48f9a
add reference.qubit to tensorflow tests
astralcai Sep 5, 2024
0025281
fix failing test in test_lightning_qubit
astralcai Sep 5, 2024
c62ce82
Add _to_autograd to autograd execute
astralcai Sep 5, 2024
58e5d52
move changes to a different branch
astralcai Sep 5, 2024
6bb842d
revert lightning test change
astralcai Sep 5, 2024
26111be
stop treating numpy as autograd internally
astralcai Sep 5, 2024
5e8740b
Merge branch 'master' into autograd-bug
astralcai Sep 5, 2024
26d16bc
bug fixes
astralcai Sep 6, 2024
c45b750
uncomment line
astralcai Sep 6, 2024
dfacd7f
Merge branch 'master' into autograd-bug
astralcai Sep 6, 2024
8fd09d7
Merge branch 'master' into mini-dev-new
astralcai Sep 6, 2024
48f73c4
fix changelog
astralcai Sep 6, 2024
0633dc0
fix tiny bug
astralcai Sep 6, 2024
f1213cb
Merge branch 'master' into autograd-bug
astralcai Sep 6, 2024
e1a1fc5
Apply suggestions from code review
dwierichs Sep 9, 2024
c529637
Merge branch 'master' into fix-jvp-shots
dwierichs Sep 9, 2024
5bd7176
minor updates
astralcai Sep 9, 2024
ffb9d3c
more fix
astralcai Sep 9, 2024
e2a67d2
Merge branch 'fix-jvp-shots' of https://github.com/PennyLaneAI/pennyl…
astralcai Sep 9, 2024
a11ef48
changelog
astralcai Sep 9, 2024
2ecd8ab
Merge branch 'master' into mini-dev-new
astralcai Sep 9, 2024
8333c19
format
astralcai Sep 9, 2024
3ad1921
fix isort
astralcai Sep 9, 2024
5d6e8eb
fix bug
astralcai Sep 9, 2024
6776c01
fix tests
astralcai Sep 9, 2024
eca0f14
fix black
astralcai Sep 9, 2024
33f4f63
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
astralcai Sep 9, 2024
2e4f55c
revert change
astralcai Sep 9, 2024
8c4a72a
add sparse matrix to Hermitian
astralcai Sep 9, 2024
3c8a691
bug fix
astralcai Sep 9, 2024
71561f9
bug fix
astralcai Sep 9, 2024
676d85b
bug fix
astralcai Sep 9, 2024
63525a2
Merge branch 'master' into autograd-bug
astralcai Sep 9, 2024
b34b48c
clean up handling of interface
astralcai Sep 10, 2024
9810b68
Merge branch 'master' into autograd-bug
astralcai Sep 10, 2024
c21eee3
fix isort
astralcai Sep 10, 2024
ffd41a9
update
astralcai Sep 10, 2024
cee3976
fix some tests
astralcai Sep 10, 2024
b7ac5e7
Merge branch 'master' into mini-dev-new
astralcai Sep 10, 2024
087dc22
fix tests
astralcai Sep 10, 2024
535e66b
make pylint happy
astralcai Sep 10, 2024
18c5fa6
update name
astralcai Sep 10, 2024
7fde693
fix isort
astralcai Sep 10, 2024
9e86111
fix tests
astralcai Sep 10, 2024
c4415a8
Update pennylane/workflow/qnode.py
astralcai Sep 11, 2024
6ac5315
Merge branch 'master' into autograd-bug
astralcai Sep 11, 2024
125e06c
Add reference.qubit to torch tests
astralcai Sep 11, 2024
b91fc7b
add reference.qubit to more tensorflow tests
astralcai Sep 11, 2024
b6ad427
changelog
astralcai Sep 12, 2024
c41572e
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
astralcai Sep 12, 2024
fee0af9
Merge branch 'master' into autograd-bug
astralcai Sep 12, 2024
23e8142
Merge branch 'autograd-bug' of https://github.com/PennyLaneAI/pennyla…
astralcai Sep 12, 2024
8fe18d1
fix test
astralcai Sep 12, 2024
5b6427f
Update pennylane/devices/reference_qubit.py
astralcai Sep 13, 2024
52caafc
Update pennylane/devices/reference_qubit.py
astralcai Sep 13, 2024
b6fadc6
update skip message
astralcai Sep 13, 2024
d31c0c7
add tape assertion
astralcai Sep 13, 2024
34fe756
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
astralcai Sep 16, 2024
bf4b212
Update pennylane/devices/reference_qubit.py
astralcai Sep 16, 2024
449a0cd
add ReferenceQubit to devices
astralcai Sep 16, 2024
ba1560a
Merge branch 'master' into mini-dev-new
astralcai Sep 16, 2024
d7d9861
Merge branch 'master' into mini-dev-new
astralcai Sep 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
unique representation of the object.
[(#6167)](https://github.com/PennyLaneAI/pennylane/pull/6167)

* A `ReferenceQubit` is introduced for testing purposes and as a reference for future plugin development.
[(#6181)](https://github.com/PennyLaneAI/pennylane/pull/6181)

* The `to_mat` methods for `FermiWord` and `FermiSentence` now optionally return
a sparse matrix.
[(#6173)](https://github.com/PennyLaneAI/pennylane/pull/6173)
Expand Down
3 changes: 3 additions & 0 deletions pennylane/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
_qubit_device
_qutrit_device
null_qubit
reference_qubit
tests

Next generation devices
Expand All @@ -58,6 +59,7 @@
DefaultQubit
DefaultTensor
NullQubit
ReferenceQubit
DefaultQutritMixed
LegacyDeviceFacade

Expand Down Expand Up @@ -160,6 +162,7 @@ def execute(self, circuits, execution_config = qml.devices.DefaultExecutionConfi
from .default_clifford import DefaultClifford
from .default_tensor import DefaultTensor
from .null_qubit import NullQubit
from .reference_qubit import ReferenceQubit
from .default_qutrit import DefaultQutrit
from .default_qutrit_mixed import DefaultQutritMixed
from ._legacy_device import Device as LegacyDevice
Expand Down
154 changes: 154 additions & 0 deletions pennylane/devices/reference_qubit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Copyright 2018-2024 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.
"""
Contains the ReferenceQubit device, a minimal device that can be used for testing
and plugin development purposes.
"""

import numpy as np

import pennylane as qml

from .device_api import Device
from .execution_config import DefaultExecutionConfig
from .modifiers import simulator_tracking, single_tape_support
from .preprocess import decompose, validate_device_wires, validate_measurements


def sample_state(state: np.ndarray, shots: int, seed=None):
"""Generate samples from the provided state and number of shots."""

probs = np.imag(state) ** 2 + np.real(state) ** 2
basis_states = np.arange(len(probs))

num_wires = int(np.log2(len(probs)))

rng = np.random.default_rng(seed)
basis_samples = rng.choice(basis_states, shots, p=probs)

# convert basis state integers to array of booleans
bin_strings = (format(s, f"0{num_wires}b") for s in basis_samples)
return np.array([[int(val) for val in s] for s in bin_strings])


def simulate(tape: qml.tape.QuantumTape, seed=None) -> qml.typing.Result:
"""Simulate a tape and turn it into results.

Args:
tape (.QuantumTape): a representation of a circuit
seed (Any): A seed to use to control the generation of samples.

"""
# 1) create the initial state
state = np.zeros(2 ** len(tape.wires))
state[0] = 1.0

# 2) apply all the operations
for op in tape.operations:
op_mat = op.matrix(wire_order=tape.wires)
state = qml.math.matmul(op_mat, state)

# 3) perform measurements
# note that shots are pulled from the tape, not from the device
if tape.shots:
samples = sample_state(state, shots=tape.shots.total_shots, seed=seed)
# Shot vector support
results = []
for lower, upper in tape.shots.bins():
sub_samples = samples[lower:upper]
results.append(
tuple(mp.process_samples(sub_samples, tape.wires) for mp in tape.measurements)
)
if len(tape.measurements) == 1:
results = [res[0] for res in results]
if not tape.shots.has_partitioned_shots:
results = results[0]
else:
results = tuple(results)
else:
results = tuple(mp.process_state(state, tape.wires) for mp in tape.measurements)
if len(tape.measurements) == 1:
results = results[0]

return results


operations = frozenset({"PauliX", "PauliY", "PauliZ", "Hadamard", "CNOT", "CZ", "RX", "RY", "RZ"})


def supports_operation(op: qml.operation.Operator) -> bool:
"""This function used by preprocessing determines what operations
are natively supported by the device.

While in theory ``simulate`` can support any operation with a matrix, we limit the target
gate set for improved testing and reference purposes.

"""
return getattr(op, "name", None) in operations


@simulator_tracking # update device.tracker with some relevant information
@single_tape_support # add support for device.execute(tape) in addition to device.execute((tape,))
class ReferenceQubit(Device):
"""A slimmed down numpy-based simulator for reference and testing purposes.

Args:
wires (int, Iterable[Number, str]): Number of wires present on the device, or iterable that
contains unique labels for the wires as numbers (i.e., ``[-1, 0, 2]``) or strings
(``['aux', 'q1', 'q2']``). Default ``None`` if not specified. While this device allows
for ``wires`` to be unspecified at construction time, other devices may make this argument
mandatory. Devices can also implement additional restrictions on the possible wires.
shots (int, Sequence[int], Sequence[Union[int, Sequence[int]]]): The default number of shots
to use in executions involving this device. Note that during execution, shots
are pulled from the circuit, not from the device.
seed (Union[str, None, int, array_like[int], SeedSequence, BitGenerator, Generator, jax.random.PRNGKey]): A
seed-like parameter matching that of ``seed`` for ``numpy.random.default_rng``. This is an optional
keyword argument added to follow recommend NumPy best practices. Other devices do not need
this parameter if it does not make sense for them.

"""

name = "reference.qubit"

def __init__(self, wires=None, shots=None, seed=None):
super().__init__(wires=wires, shots=shots)

# seed and rng not necessary for a device, but part of recommended
# numpy practices to use a local random number generator
self._rng = np.random.default_rng(seed)

def preprocess(self, execution_config=DefaultExecutionConfig):

# Here we convert an arbitrary tape into one natively supported by the device
program = qml.transforms.core.TransformProgram()
program.add_transform(validate_device_wires, wires=self.wires, name="reference.qubit")
program.add_transform(qml.defer_measurements)
program.add_transform(qml.transforms.split_non_commuting)
program.add_transform(qml.transforms.diagonalize_measurements)
program.add_transform(
decompose,
stopping_condition=supports_operation,
skip_initial_state_prep=False,
name="reference.qubit",
)
program.add_transform(validate_measurements, name="reference.qubit")
program.add_transform(qml.transforms.broadcast_expand)

# no need to preprocess the config as the device does not support derivatives
return program, execution_config

def execute(self, circuits, execution_config=DefaultExecutionConfig):
for tape in circuits:
assert all(supports_operation(op) for op in tape.operations)
return tuple(simulate(tape, seed=self._rng) for tape in circuits)
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"default.qubit.legacy = pennylane.devices:DefaultQubitLegacy",
"default.gaussian = pennylane.devices:DefaultGaussian",
"default.mixed = pennylane.devices.default_mixed:DefaultMixed",
"reference.qubit = pennylane.devices.reference_qubit:ReferenceQubit",
"null.qubit = pennylane.devices.null_qubit:NullQubit",
"default.qutrit = pennylane.devices.default_qutrit:DefaultQutrit",
"default.clifford = pennylane.devices.default_clifford:DefaultClifford",
Expand Down
Loading
Loading