merlin.measurement package

Sampling and autodiff utilities.

class merlin.measurement.Amplitudes

Bases: Module

Output the Fock state vector (also called amplitudes) directly. This can only be done with a simulator because amplitudes cannot be retrieved from the per state probabilities obtained with a QPU.

forward(x)

Return the fock state vector amplitudes.

Return type:

Tensor

class merlin.measurement.AutoDiffProcess(sampling_method='multinomial')

Bases: object

Handles automatic differentiation backend and sampling noise integration.

autodiff_backend(needs_gradient, apply_sampling, shots)

Determine sampling configuration based on gradient requirements.

Return type:

tuple[bool, int]

class merlin.measurement.DetectorTransform(simulation_keys, detectors, *, dtype=None, device=None, partial_measurement=False)

Bases: Module

Linear map applying per-mode detector rules to a Fock probability vector.

Args:
simulation_keys: Iterable describing the raw Fock states produced by the

simulator (as tuples or lists of integers).

detectors: One detector per optical mode. Each detector must expose the

detect() method from perceval.Detector.

dtype: Optional torch dtype for the transform matrix. Defaults to

torch.float32.

device: Optional device used to stage the transform matrix. partial_measurement: When True, only the modes whose detector entry is

not None are measured. The transform then operates on complex amplitudes and returns per-outcome dictionaries (see forward()).

forward(tensor)

Apply the detector transform.

Return type:

Tensor | list[dict[tuple[int, ...], list[tuple[Tensor, Tensor]]]]

Args:
tensor: Probability distribution (complete mode) or amplitudes

(partial measurement). The last dimension must match the simulator basis.

Returns:
  • Complete mode: real probability tensor expressed in the detector basis.

  • Partial mode: list indexed by remaining photon count. Each entry is a dictionary whose keys are full-length mode tuples (unmeasured modes set to None) and whose values are lists of (probability, normalized remaining-mode amplitudes) pairs – one per perfect measurement branch.

property is_identity: bool

Whether the transform reduces to the identity (ideal PNR detectors).

property output_keys: list[tuple[int, ...]]

Return the classical detection outcome keys.

property output_size: int

Number of classical outcomes produced by the detectors.

property partial_measurement: bool

Return True when the transform runs in partial measurement mode.

remaining_basis(remaining_n=None)

Return the ordered Fock-state basis for the unmeasured modes.

Return type:

list[tuple[int, ...]]

Args:
remaining_n: Optional photon count used to select a specific block.

When omitted, the method returns the concatenation of every remaining-mode basis enumerated during detector initialisation.

Returns:

List of tuples describing the photon distribution over the unmeasured modes.

row(index, *, dtype=None, device=None)

Return a single detector transform row as a dense tensor.

Return type:

Tensor

enum merlin.measurement.MeasurementStrategy(value)

Bases: Enum

Strategy for measuring quantum states or counts and possibly apply mapping to classical outputs.

Valid values are as follows:

PROBABILITIES = <MeasurementStrategy.PROBABILITIES: 'probabilities'>
MODE_EXPECTATIONS = <MeasurementStrategy.MODE_EXPECTATIONS: 'mode_expectations'>
AMPLITUDES = <MeasurementStrategy.AMPLITUDES: 'amplitudes'>
class merlin.measurement.ModeExpectations(computation_space, keys)

Bases: Module

Maps quantum state amplitudes or probabilities to the per mode expected number of photons.

forward(x)

Convert the per state amplitudes to per state probabilities if x are amplitudes. Then, marginalize the per state probability distribution into a per mode expected value.

Return type:

Tensor

Args:

x: Input Fock states amplitudes or probabilities of shape (n_batch, num_states) or (num_states,)

Returns:

Expected value tensor of shape (batch_size, num_modes)

marginalize_per_mode(probability_distribution)

Marginalize Fock state probabilities to get per-mode occupation expected values.

Return type:

Tensor

Args:
probability_distribution (torch.Tensor): Tensor of shape (N, num_keys) with probabilities

for each Fock state, with requires_grad=True

Returns:

torch.Tensor: Shape (N, num_modes) with marginal per mode expected number of photons

class merlin.measurement.OutputMapper

Bases: object

Handles mapping quantum state amplitudes or probabilities to classical outputs.

This class provides factory methods for creating different types of output mappers that convert quantum state amplitudes or probabilities to classical outputs.

static create_mapping(strategy, computation_space=ComputationSpace.FOCK, keys=None)

Create an output mapping based on the specified strategy.

Args:

strategy: The measurement mapping strategy to use no_bunching: (Only used for ModeExpectations measurement strategy) If True (default), the per-mode probability of finding at least one photon is returned.

Otherwise, it is the per-mode expected number of photons that is returned.

keys: (Only used for ModeExpectations measurement strategy) List of tuples that represent the possible quantum Fock states.

For example, keys = [(0,1,0,2), (1,0,1,0), …]

Returns:

A PyTorch module that maps the per state amplitudes or probabilities to the desired format.

Raises:

ValueError: If strategy is unknown

class merlin.measurement.Probabilities

Bases: Module

Maps quantum state amplitudes or probabilities to the complete Fock state probability distribution.

forward(x)

Compute the probability distribution of possible Fock states from amplitudes or probabilities.

Args:

x: Input Fock states amplitudes or probabilities of shape (n_batch, num_states) or (num_states,)

Returns:

Fock states probability tensor of shape (batch_size, num_states) or (num_states,)

class merlin.measurement.SamplingProcess(method='multinomial')

Bases: object

Handles quantum measurement sampling with different methods.

This class provides functionality to simulate quantum measurement noise by applying different sampling strategies to probability distributions.

pcvl_sampler(distribution, shots, method=None)

Apply sampling noise to a probability distribution.

Return type:

Tensor

Args:

distribution: Input probability distribution tensor method: Sampling method to use (‘multinomial’, ‘binomial’, or ‘gaussian’), defaults to the initialized method shots: Number of measurement shots to simulate

Returns:

Noisy probability distribution after sampling

Raises:

ValueError: If method is not one of the valid options

merlin.measurement.resolve_detectors(experiment, n_modes)

Build a per-mode detector list from a Perceval experiment.

Return type:

tuple[list[Detector], bool]

Args:

experiment: Perceval experiment carrying detector configuration. n_modes: Number of photonic modes to cover.

Returns:
normalized: list[pcvl.Detector]

List of detectors (defaulting to ideal PNR where unspecified),

empty_detectors: bool

If True, no Detector was defined in experiment. If False, at least one Detector was defined in experiement.

Submodules