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

CMP #5: Add Sample MP class #3288

Merged
merged 63 commits into from Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
5a65371
Add process abstract method to MeasurementProcess class
AlbertMitjans Nov 8, 2022
22a20f6
Add TODO comment.
AlbertMitjans Nov 8, 2022
5ab2e4f
Add docstring
AlbertMitjans Nov 8, 2022
f449a94
Add _Sample class
AlbertMitjans Nov 8, 2022
ab602dc
Merge branch 'master' into measurement-process
AlbertMitjans Nov 8, 2022
5c1f355
Add process method to ClassicalShadow class
AlbertMitjans Nov 8, 2022
3e66a2a
Merge branch 'measurement-process' of github.com:PennyLaneAI/pennylan…
AlbertMitjans Nov 8, 2022
64f4fb9
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 8, 2022
92d6dcc
Add tests
AlbertMitjans Nov 8, 2022
69a1e0a
Fix coverage
AlbertMitjans Nov 8, 2022
2976034
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 8, 2022
128a3bf
TODO
AlbertMitjans Nov 8, 2022
53a2766
Fix test
AlbertMitjans Nov 8, 2022
8928069
Fix equal
AlbertMitjans Nov 8, 2022
4428bd1
Fix test
AlbertMitjans Nov 8, 2022
ff9901a
Support python3.7
AlbertMitjans Nov 8, 2022
1b4c96a
Revert
AlbertMitjans Nov 8, 2022
357ecbb
Skip python@3.7 test
AlbertMitjans Nov 9, 2022
8e746be
Improve sample code
AlbertMitjans Nov 9, 2022
4bdcf38
Coverage
AlbertMitjans Nov 9, 2022
10f8497
Merge branch 'master' into measurement-process
AlbertMitjans Nov 10, 2022
d6a853e
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
595e1a4
Improve tests
AlbertMitjans Nov 10, 2022
e37dcee
Add process_state method
AlbertMitjans Nov 10, 2022
c921937
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
50ec152
Remove abstract
AlbertMitjans Nov 10, 2022
fc6ddc4
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
420439b
Merge branch 'master' into measurement-process
AlbertMitjans Nov 10, 2022
9354df8
Coverage
AlbertMitjans Nov 10, 2022
942caec
Merge branch 'measurement-process' of github.com:PennyLaneAI/pennylan…
AlbertMitjans Nov 10, 2022
94d2b87
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
478d268
Add StateMeasurement and SampleMeasurement classes
AlbertMitjans Nov 10, 2022
eff99b8
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
c1df52a
Change inheritance
AlbertMitjans Nov 10, 2022
19c07c9
Revert
AlbertMitjans Nov 10, 2022
366e8ff
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
7c5c14d
Add changelog entry
AlbertMitjans Nov 10, 2022
d24f519
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 10, 2022
7f58fa9
Add changelog entry
AlbertMitjans Nov 10, 2022
85ec312
Add changelog entry
AlbertMitjans Nov 11, 2022
89c36a1
Merge branch 'master' into measurement-process
AlbertMitjans Nov 11, 2022
0176f4b
Merge
AlbertMitjans Nov 11, 2022
3ecaecb
Merge branch 'master' into measurement-process
AlbertMitjans Nov 15, 2022
2d36253
Address comments
AlbertMitjans Nov 16, 2022
859ca99
Change state type
AlbertMitjans Nov 16, 2022
7eb52de
Merge branch 'master' into measurement-process
AlbertMitjans Nov 16, 2022
77cfec0
Remove error
AlbertMitjans Nov 16, 2022
33cd441
Merge branch 'measurement-process' of github.com:PennyLaneAI/pennylan…
AlbertMitjans Nov 16, 2022
4e8a2b1
Merge branch 'measurement-process' into sample
AlbertMitjans Nov 16, 2022
b122d3a
Small fix
AlbertMitjans Nov 16, 2022
36c1cdc
Merge branch 'master' into sample
AlbertMitjans Nov 18, 2022
71a87e8
Merge branch 'master' into sample
AlbertMitjans Nov 18, 2022
07e65d7
Add wire_order to process_samples
AlbertMitjans Nov 18, 2022
508f59f
Docstring
AlbertMitjans Nov 18, 2022
883bf1e
Merge branch 'master' into sample
AlbertMitjans Nov 18, 2022
a0a8be7
Small fix
AlbertMitjans Nov 18, 2022
b73fb0b
Merge branch 'sample' of github.com:PennyLaneAI/pennylane into sample
AlbertMitjans Nov 18, 2022
69567d2
Add wire_order to process_samples
AlbertMitjans Nov 21, 2022
078c4a7
Change tests
AlbertMitjans Nov 21, 2022
5e4759b
Add wire_order to process_samples
AlbertMitjans Nov 21, 2022
4ff7278
Add breaking change message
AlbertMitjans Nov 21, 2022
a2f6378
Merge branch 'master' into sample
AlbertMitjans Nov 21, 2022
1ccfe41
Merge branch 'master' into sample
AlbertMitjans Nov 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 2 additions & 3 deletions pennylane/circuit_graph.py
Expand Up @@ -18,11 +18,10 @@
# pylint: disable=too-many-branches,too-many-arguments,too-many-instance-attributes
from collections import namedtuple

import retworkx as rx
import numpy as np
import retworkx as rx

import pennylane as qml

from pennylane.wires import Wires


Expand Down Expand Up @@ -125,7 +124,7 @@ def __init__(self, ops, obs, wires, par_info=None, trainable_params=None):

elif op.return_type is qml.measurements.Sample and op.wires == Wires([]):
# Sampling without specifying wires is treated as sampling all wires
op = qml.measurements.MeasurementProcess(qml.measurements.Sample, wires=wires)
op = qml.sample(wires=wires)

op.queue_idx = k

Expand Down
6 changes: 6 additions & 0 deletions pennylane/measurements/classical_shadow.py
Expand Up @@ -16,6 +16,7 @@
This module contains the qml.classical_shadow measurement.
"""
from collections.abc import Iterable
from typing import Sequence, Tuple

import numpy as np

Expand Down Expand Up @@ -293,3 +294,8 @@ def __copy__(self):
obj.H = self.H
obj.k = self.k
return obj

def process(
self, samples: Sequence[complex], shot_range: Tuple[int] = None, bin_size: int = None
):
"""TODO: Implement this method."""
23 changes: 20 additions & 3 deletions pennylane/measurements/measurements.py
Expand Up @@ -21,12 +21,14 @@
import contextlib
import copy
import functools
from abc import abstractmethod
from enum import Enum
from typing import Sequence, Tuple, Union

import numpy as np

import pennylane as qml
from pennylane.operation import Operator
from pennylane.operation import Observable
from pennylane.wires import Wires

# =============================================================================
Expand Down Expand Up @@ -106,7 +108,7 @@ class MeasurementShapeError(ValueError):
quantum tape."""


class MeasurementProcess:
class MeasurementProcess: # TODO: Inherit from ABC
"""Represents a measurement process occurring at the end of a
quantum variational circuit.

Expand All @@ -131,7 +133,7 @@ class MeasurementProcess:
def __init__(
self,
return_type: ObservableReturnTypes,
obs: Operator = None,
obs: Union[Observable, None] = None,
wires=None,
eigvals=None,
id=None,
Expand Down Expand Up @@ -692,3 +694,18 @@ def map_wires(self, wire_map: dict):
if self.obs is not None:
new_measurement.obs = self.obs.map_wires(wire_map=wire_map)
return new_measurement

@abstractmethod
def process(
self, samples: Sequence[complex], shot_range: Tuple[int] = None, bin_size: int = None
):
"""Process the given samples.

Args:
samples (Sequence[complex]): computational basis samples generated for all wires
shot_range (tuple[int]): 2-tuple of integers specifying the range of samples
to use. If not specified, all samples are used.
bin_size (int): Divides the shot range into bins of size ``bin_size``, and
returns the measurement statistic separately over each bin. If not
provided, the entire shot range is treated as a single bin.
"""
52 changes: 50 additions & 2 deletions pennylane/measurements/sample.py
Expand Up @@ -16,13 +16,18 @@
This module contains the qml.sample measurement.
"""
import warnings
from typing import Tuple, Union

import numpy as np

import pennylane as qml
from pennylane.operation import Observable
from pennylane.wires import Wires

from .measurements import MeasurementProcess, Sample


def sample(op=None, wires=None):
def sample(op: Union[Observable, None] = None, wires=None):
r"""Sample from the supplied observable, with the number of shots
determined from the ``dev.shots`` attribute of the corresponding device,
returning raw samples. If no observable is provided then basis state samples are returned
Expand Down Expand Up @@ -106,4 +111,47 @@ def circuit(x):
)
wires = Wires(wires)

return MeasurementProcess(Sample, obs=op, wires=wires)
return _Sample(Sample, obs=op, wires=wires)


# TODO: Make public when removing the ObservableReturnTypes enum
class _Sample(MeasurementProcess):
"""Measurement process that returns the samples of a given observable."""

def process(self, samples: np.ndarray, shot_range: Tuple[int] = None, bin_size: int = None):
name = self.obs.name if self.obs is not None else None
# Select the samples from samples that correspond to ``shot_range`` if provided
if shot_range is not None:
# Indexing corresponds to: (potential broadcasting, shots, wires). Note that the last
# colon (:) is required because shots is the second-to-last axis and the
# Ellipsis (...) otherwise would take up broadcasting and shots axes.
samples = samples[..., slice(*shot_range), :]

if len(self.wires) != 0:
# if wires are provided, then we only return samples from those wires
samples = samples[..., np.array(self.wires)]

num_wires = samples.shape[-1] # wires is the last dimension

if self.obs is None:
# if no observable was provided then return the raw samples
return samples if bin_size is None else samples.reshape(num_wires, bin_size, -1)
AlbertMitjans marked this conversation as resolved.
Show resolved Hide resolved

if name in {"PauliX", "PauliY", "PauliZ", "Hadamard"}:
# Process samples for observables with eigenvalues {1, -1}
samples = 1 - 2 * qml.math.squeeze(samples)
eddddddy marked this conversation as resolved.
Show resolved Hide resolved
else:
# Replace the basis state in the computational basis with the correct eigenvalue.
# Extract only the columns of the basis samples required based on ``wires``.
powers_of_two = 2 ** np.arange(num_wires)[::-1]
indices = samples @ powers_of_two
eddddddy marked this conversation as resolved.
Show resolved Hide resolved
indices = np.array(indices) # Add np.array here for Jax support.
try:
samples = self.obs.eigvals()[indices]
except qml.operation.EigvalsUndefinedError as e:
# if observable has no info on eigenvalues, we cannot return this measurement
raise qml.operation.EigvalsUndefinedError(
f"Cannot compute samples of {self.obs.name}."
) from e

return samples if bin_size is None else samples.reshape((bin_size, -1))
9 changes: 5 additions & 4 deletions pennylane/ops/functions/equal.py
Expand Up @@ -16,6 +16,7 @@
"""
# pylint: disable=too-many-arguments,too-many-return-statements
from typing import Union

import pennylane as qml
from pennylane.measurements import MeasurementProcess, ShadowMeasurementProcess
from pennylane.operation import Operator
Expand Down Expand Up @@ -85,12 +86,12 @@ def equal(
if op1.__class__ is not op2.__class__:
return False

if op1.__class__ is MeasurementProcess:
return equal_measurements(op1, op2)

if op1.__class__ is ShadowMeasurementProcess:
if isinstance(op1, ShadowMeasurementProcess):
return equal_shadow_measurements(op1, op2)

if isinstance(op1, MeasurementProcess):
return equal_measurements(op1, op2)

return equal_operator(op1, op2, check_interface, check_trainability, rtol, atol)


Expand Down