merlin.core.partial_measurement
PartialMeasurementBranch
- class merlin.core.partial_measurement.PartialMeasurementBranch(outcome, probability, amplitudes)
Bases:
objectSingle branch of a partial measurement for a specific measured-mode outcome.
- Args:
outcome: Outcome restricted to measured modes, in detector order. probability: Per-batch probability for this outcome. amplitudes: Conditional state vector on unmeasured modes.
PartialMeasurement
- class merlin.core.partial_measurement.PartialMeasurement(branches, measured_modes, unmeasured_modes, grouping=None)
Bases:
objectCollection 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.
- verify_branches_order()
Verify that branches are ordered lexicographically by their outcomes.
- Return type:
None
- reorder_branches()
Reorder branches lexicographically by their outcomes.
- Return type:
None
- property probability_tensor_shape: tuple[int, int]
Return the expected (batch, n_outcomes) shape for the probability tensor.
- property n_measured_modes: int
- property n_unmeasured_modes: int
- 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.
- 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 amplitudes
- property outcomes
- 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.
- static from_detector_transform_output(detector_output, *, grouping=None)
Branch-based PartialMeasurement wrapper from DetectorTransform(partial_measurement=True) output.
- Return type:
Notes and Examples
Basic Structure
A PartialMeasurement represents the outcome of measuring a subset of modes in a quantum system.
It consists of a collection of PartialMeasurementBranch objects, each corresponding to a specific
measurement outcome on the measured modes, along with the conditional quantum state on the unmeasured modes.
from merlin.core.partial_measurement import PartialMeasurement, PartialMeasurementBranch
from merlin.core.state_vector import StateVector
import torch
# Create branches manually
outcome_1 = (1, 0) # measurement result on measured modes 0 and 1
prob_1 = torch.tensor([0.5]) # probability for this outcome
amps_1 = StateVector.from_basic_state([1, 0], sparse=False) # conditional state on unmeasured modes
branch_1 = PartialMeasurementBranch(outcome_1, prob_1, amps_1)
branch_2 = PartialMeasurementBranch((0, 1), torch.tensor([0.5]), StateVector.from_basic_state([0, 1], sparse=False))
# Combine into PartialMeasurement
pm = PartialMeasurement(
branches=(branch_1, branch_2),
measured_modes=(0, 1),
unmeasured_modes=(2, 3)
)
Accessing Measurement Results
The PartialMeasurement class provides convenient access to the measurement outcomes and their associated probabilities.
# Access properties
print(f"Measured modes: {pm.measured_modes}")
print(f"Unmeasured modes: {pm.unmeasured_modes}")
print(f"Number of branches: {len(pm.branches)}")
# Get probability distribution across all outcomes
prob_tensor = pm.tensor # shape: (batch_size, n_branches)
# Get individual outcomes and amplitudes
for outcome, branch in zip(pm.outcomes, pm.branches):
print(f"Outcome {outcome}: probability={branch.probability}, amplitude shape={branch.amplitudes.shape}")
Working with Grouped Probabilities
The PartialMeasurement supports optional grouping of probabilities, which allows you to aggregate outcomes
according to a custom grouping function (e.g., for classical post-processing or symmetry-based grouping).
from merlin.utils.grouping import ModGrouping
# Define a grouping function
grouping = ModGrouping(input_size = 4,output_size=2) # example grouping
# Apply grouping to PartialMeasurement
pm.set_grouping(grouping)
# Grouped probabilities now have shape (batch_size, output_size) instead of (batch_size, n_branches)
grouped_probs = pm.probabilities
print(grouped_probs.shape) # (batch_size, 2)
Creating from DetectorTransform Output
PartialMeasurement objects are typically created from the output of a detector transformation in the measurement pipeline.
from merlin.core.partial_measurement import PartialMeasurement
# When DetectorTransform produces partial measurement output (partial_measurement=True),
# it returns a structure that can be converted to PartialMeasurement
detector_output = [...] # output from DetectorTransform
pm = PartialMeasurement.from_detector_transform_output(
detector_output,
grouping=None
)
Batch Processing
Probabilities are stored per-batch in each branch, allowing for efficient handling of batch-processed quantum circuits.
import torch
# Batch-wise probabilities
batch_probs = torch.tensor([[0.3, 0.7], [0.6, 0.4]]) # shape: (batch_size=2, n_outcomes=2)
# When creating a branch with batched probabilities
branch = PartialMeasurementBranch(
outcome=(1, 0),
probability=batch_probs[:, 0], # shape: (batch_size,)
amplitudes=StateVector.from_basic_state([1, 0])
)