merlin.measurement.strategies module

Overview

The measurement API is now centered on MeasurementStrategy, an immutable object that fully describes how quantum outputs are converted into classical outputs. The new API uses explicit factory methods instead of enum-style access.

Partial measurement

Partial measurement is explicit and validated. It returns a merlin.core.partial_measurement.PartialMeasurement.

from merlin.core.computation_space import ComputationSpace
from merlin.measurement.strategies import MeasurementStrategy

# Measure only modes 0 and 2
strategy = MeasurementStrategy.partial(
    modes=[0, 2],
    computation_space=ComputationSpace.FOCK,
)

Deprecations and Migration Guide

Enum-style access is deprecated and will be removed in v0.4:

  • MeasurementStrategy.PROBABILITIES

  • MeasurementStrategy.MODE_EXPECTATIONS

  • MeasurementStrategy.AMPLITUDES

  • MeasurementStrategy.NONE (aliases amplitudes)

Passing measurement_strategy as a string is also deprecated (e.g. "PROBABILITIES").

Old to new mappings

Deprecated

Recommended replacement

MeasurementStrategy.PROBABILITIES

MeasurementStrategy.probs(computation_space=...)

MeasurementStrategy.MODE_EXPECTATIONS

MeasurementStrategy.mode_expectations(computation_space=...)

MeasurementStrategy.AMPLITUDES

MeasurementStrategy.amplitudes(computation_space=...)

MeasurementStrategy.NONE

MeasurementStrategy.amplitudes(computation_space=...)

"PROBABILITIES" (string)

MeasurementStrategy.probs(computation_space=...)

Computation space now lives inside the strategy. If you already use the new factory methods, do not also pass computation_space separately in constructors such as QuantumLayer.

# Deprecated (legacy enum + separate computation_space)
# QuantumLayer(..., measurement_strategy=MeasurementStrategy.PROBABILITIES,
#             computation_space=ComputationSpace.FOCK)

# Recommended
QuantumLayer(..., measurement_strategy=MeasurementStrategy.probs(ComputationSpace.FOCK))

Reference

Measurement strategy definitions for quantum-to-classical conversion.

class merlin.measurement.strategies.AmplitudesStrategy

Bases: BaseMeasurementStrategy

New API: return raw amplitudes (sampling is not supported).

process(*, amplitudes, **kwargs)

Return the processed result for the selected measurement strategy.

Return type:

Tensor

class merlin.measurement.strategies.BaseMeasurementStrategy

Bases: object

New API: internal strategy interface for post-processing implementations.

process(*, distribution, amplitudes, apply_sampling, effective_shots, sample_fn, apply_photon_loss, apply_detectors, grouping=None)

Return the processed result for the selected measurement strategy.

Return type:

Tensor | PartialMeasurement

supports_sampling()

Return whether the strategy can apply sampling to distributions.

Return type:

bool

class merlin.measurement.strategies.Callable

Bases: object

enum merlin.measurement.strategies.ComputationSpace(value)

Bases: str, Enum

Enumeration of supported computational subspaces.

Member Type:

str

Valid values are as follows:

FOCK = <ComputationSpace.FOCK: 'fock'>
UNBUNCHED = <ComputationSpace.UNBUNCHED: 'unbunched'>
DUAL_RAIL = <ComputationSpace.DUAL_RAIL: 'dual_rail'>

The Enum and its members also have the following methods:

classmethod default(*, no_bunching)

Derive the default computation space from the legacy no_bunching flag.

Return type:

ComputationSpace

classmethod coerce(value)

Normalize user-provided values (enum instances or case-insensitive strings).

Return type:

ComputationSpace

class merlin.measurement.strategies.DistributionStrategy

Bases: BaseMeasurementStrategy

New API: shared logic for distribution-based strategies.

process(*, distribution, amplitudes, apply_sampling, effective_shots, sample_fn, apply_photon_loss, apply_detectors, grouping=None)

Return the processed result for the selected measurement strategy.

Return type:

Tensor

supports_sampling()

Return whether the strategy can apply sampling to distributions.

Return type:

bool

enum merlin.measurement.strategies.Enum(value)

Bases: object

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access:

>>> Color.RED
<Color.RED: 1>
  • value lookup:

>>> Color(1)
<Color.RED: 1>
  • name lookup:

>>> Color['RED']
<Color.RED: 1>

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.

The Enum and its members have the following methods:

name

The name of the Enum member.

value

The value of the Enum member.

class merlin.measurement.strategies.LexGrouping(input_size, output_size)

Bases: Module

Maps tensor to a lexical grouping of its components.

This mapper groups consecutive elements of the input tensor into equal-sized buckets and sums them to produce the output. If the input size is not evenly divisible by the output size, padding is applied.

forward(x)

Map the input tensor to the desired output_size utilizing lexical grouping.

Args:

x: Input tensor of shape (n_batch, input_size) or (input_size,)

Returns:

Grouped tensor of shape (batch_size, output_size) or (output_size,)

enum merlin.measurement.strategies.MeasurementKind(value)

Bases: Enum

New API: internal measurement kinds used by MeasurementStrategy.

Valid values are as follows:

PROBABILITIES = <MeasurementKind.PROBABILITIES: 'PROBABILITIES'>
MODE_EXPECTATIONS = <MeasurementKind.MODE_EXPECTATIONS: 'MODE_EXPECTATIONS'>
AMPLITUDES = <MeasurementKind.AMPLITUDES: 'AMPLITUDES'>
PARTIAL = <MeasurementKind.PARTIAL: 'PARTIAL'>
class merlin.measurement.strategies.MeasurementStrategy(type, measured_modes=(), computation_space=None, grouping=None)

Bases: object

New API: immutable definition of a measurement strategy for output post-processing.

AMPLITUDES: ClassVar[_LegacyMeasurementStrategy] = 'amplitudes'
MODE_EXPECTATIONS: ClassVar[_LegacyMeasurementStrategy] = 'mode_expectations'
NONE: ClassVar[MeasurementStrategy] = MeasurementStrategy(type=<MeasurementKind.AMPLITUDES: 'AMPLITUDES'>, measured_modes=(), computation_space=<ComputationSpace.UNBUNCHED: 'unbunched'>, grouping=None)
PROBABILITIES: ClassVar[_LegacyMeasurementStrategy] = 'probabilities'
static amplitudes(computation_space=ComputationSpace.UNBUNCHED)
Return type:

MeasurementStrategy

computation_space: Optional[ComputationSpace]
get_unmeasured_modes(n_modes)

Return the complement of the measured modes after validation.

Return type:

tuple[int, ...]

grouping: UnionType[LexGrouping, ModGrouping, None]
measured_modes: tuple[int, ...]
static mode_expectations(computation_space=ComputationSpace.UNBUNCHED)
Return type:

MeasurementStrategy

static partial(modes, computation_space=ComputationSpace.UNBUNCHED, grouping=None)

Create a partial measurement on the given mode indices. Note that the specified grouping only applies on the resulting probabilities, not on the amplitudes.

Return type:

MeasurementStrategy

static probs(computation_space=ComputationSpace.UNBUNCHED, grouping=None)
Return type:

MeasurementStrategy

type: MeasurementKind
validate_modes(n_modes)

Validate mode indices and warn when the selection covers all modes.

Return type:

None

class merlin.measurement.strategies.ModGrouping(input_size, output_size)

Bases: Module

Maps tensor to a modulo grouping of its components.

This mapper groups elements of the input tensor based on their index modulo the output size. Elements with the same modulo value are summed together to produce the output.

forward(x)

Map the input tensor to the desired output_size utilizing modulo grouping.

Args:

x: Input tensor of shape (n_batch, input_size) or (input_size,)

Returns:

Grouped tensor of shape (batch_size, output_size) or (output_size,)

class merlin.measurement.strategies.ModeExpectationsStrategy

Bases: DistributionStrategy

New API: return per-mode expectations (optionally sampled).

class merlin.measurement.strategies.PartialMeasurement(branches, measured_modes, unmeasured_modes, grouping=None)

Bases: object

Collection of measurement branches along with measured/unmeasured mode metadata.

Args:

branches: Tuple of branches, ordered lexicographically by outcome. measured_modes: Indices of measured modes in the full system. unmeasured_modes: Indices of unmeasured modes in the full system. grouping: Optional grouping callable to group probabilities.

property amplitudes
static from_detector_transform_output(detector_output, *, grouping=None)

Branch-based PartialMeasurement wrapper from DetectorTransform(partial_measurement=True) output.

Return type:

PartialMeasurement

property n_measured_modes: int
property n_unmeasured_modes: int
property outcomes
property probabilities: Tensor

Return the probabilities of all branches as a tensor of shape (batch, n_branches) unless a grouping was set in which case, the probabilities are grouped and the returned tensor has shape (batch, grouping_output_size).

Same property as self.tensor.

property probability_tensor_shape: tuple[int, int]

Return the expected (batch, n_outcomes) shape for the probability tensor.

reorder_branches()

Reorder branches lexicographically by their outcomes.

Return type:

None

set_grouping(grouping)

Set the grouping used to group probabilities.

Once the grouping is set, the properties probabilities and tensor return grouped probabilities.

Return type:

None

Args:

grouping: Grouping object used to group probabilities.

property tensor: Tensor

Return the probabilities of all branches as a tensor of shape (batch, n_branches). unless a grouping was set in which case, the probabilities are grouped and the returned tensor has shape (batch, grouping_output_size).

This property assumes that all branches are ordered lexicographically by their outcomes so the stacking of probabilities follows the same order.

verify_branches_order()

Verify that branches are ordered lexicographically by their outcomes.

Return type:

None

class merlin.measurement.strategies.PartialMeasurementStrategy(measured_modes)

Bases: BaseMeasurementStrategy

New API: return a PartialMeasurement from detector partial-measurement output.

process(*, distribution, amplitudes, apply_sampling, effective_shots, sample_fn, apply_photon_loss, apply_detectors, grouping=None)

Return the processed result for the selected measurement strategy.

Return type:

PartialMeasurement

class merlin.measurement.strategies.ProbabilitiesStrategy

Bases: DistributionStrategy

New API: return output probabilities (optionally sampled).

merlin.measurement.strategies.dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False)

Add dunder methods based on the fields defined in the class.

Examines PEP 526 __annotations__ to determine fields.

If init is true, an __init__() method is added to the class. If repr is true, a __repr__() method is added. If order is true, rich comparison dunder methods are added. If unsafe_hash is true, a __hash__() method is added. If frozen is true, fields may not be assigned to after instance creation. If match_args is true, the __match_args__ tuple is added. If kw_only is true, then by default all fields are keyword-only. If slots is true, a new class with a __slots__ attribute is returned.

merlin.measurement.strategies.partial_measurement(detector_output, *, grouping=None)

Build a PartialMeasurement from DetectorTransform(partial_measurement=True) output.

Return type:

PartialMeasurement

merlin.measurement.strategies.resolve_measurement_strategy(measurement_strategy)

Return the concrete strategy implementation for the enum value.

Return type:

BaseMeasurementStrategy

merlin.measurement.strategies.warn_deprecated_enum_access(owner, name)

Warn on deprecated enum-style attribute access and return True if handled.

Return type:

bool