Measurement Strategy Guide
The type of output from a QuantumLayer depends on the measurement strategy. The quantum-to-classical conversion relies on two orthogonal concepts:
MeasurementStrategyselects how results are extracted from the quantum simulation or hardware backend.LexGroupingandModGroupingprovide optional post-processing of outputs (see Grouping Guide).
The quantum-to-classical conversion can also be handled by the user with a typed object being returned by a forward() call. Take a look at merlin.algorithms.layer module for more details about returned typed objects per measurement strategy.
PROBABILITIES
Produces the probability of observing each Fock state. In the case of strong simulation (as detailed in the SLOS: Strong Linear Optical Simulator documentation), the SLOS algorithm returns complex amplitudes, which are internally converted into probabilities using the standard quantum operation: \(a \rightarrow |a|^2\).
The output vector contains real numbers and has a size of combination(m + n - 1, n) in the Fock space (many photons can arrive at the same mode), combination(m, n) in the unbunched space, and \(2^{(m/2)}\) in the dual rail computation space where n is the number of photons and m the number of modes. See Computation Spaces for more details on computation spaces.
builder = CircuitBuilder(n_modes=5)
# Add whatever to your builder
quantum_layer = QuantumLayer(.
input_size=4,
builder=builder,
n_photons=2,
measurement_strategy=MeasurementStrategy.probs(), # Optional because this is its default value
)
Characteristics:
Output shape matches the number of Fock states generated by the experiment.
Values are real, non-negative, and sum to one.
Ideal to exploit nearly all the quantum layer expressivity.
Return type (forward call):
return_object=False:
torch.Tensorreturn_object=True:
merlin.ProbabilityDistribution
Extensions:
Add
torch.nn.Linearor any classical layer after the quantum layer to map the probabilities to logits/regression targets.Combine with
LexGroupingorModGroupingwhen you need fewer output features and don’t want to increase the number of parameters.
MODE_EXPECTATIONS
The output vector is real and has a size equal to the number of modes. Each element represents the expected number of photons in the corresponding mode. In the unbunched computation space, the vector instead provides the probability of detecting at least one photon in each respective mode.
builder = CircuitBuilder(n_modes=5)
# Add whatever to your builder
quantum_layer = QuantumLayer(.
input_size=4,
builder=builder,
n_photons=2,
measurement_strategy=MeasurementStrategy.mode_expectations(),
)
Use mode_expectations if you only need an m-sized vector that summarizes the quantum layer output by providing expectations values.
Key properties:
ComputationSpace.FOCKreturns the expected photon count per mode.ComputationSpace.UNBUNCHEDreports occupancy probabilities per mode.Output size always equals the number of modes.
Return type (forward call):
return_object=False:
torch.Tensorreturn_object=True:
torch.Tensor
AMPLITUDES
Returns the complex amplitudes directly. The output size is the same as with MeasurementStrategy.probs(), which is dependent on the computation space. This strategy is only meaningful in simulation, because amplitudes cannot be measured or obtained on hardware. Indeed, returning amplitudes is physically non-realizable and should mainly be used for connecting two quantum layers (e.g. when the second one uses amplitude encoding) or for analytical purposes when studying quantum systems.
builder = CircuitBuilder(n_modes=5)
# Add whatever to your builder
quantum_layer = QuantumLayer(.
input_size=4,
builder=builder,
n_photons=2,
measurement_strategy=MeasurementStrategy.amplitudes(),
)
Use this strategy for debugging, algorithmic research, or when a classical routine manipulates complex amplitudes directly. The output is a complex tensor normalised to unit norm.
Return type (forward call):
return_object=False:
torch.Tensorreturn_object=True:
merlin.StateVector
Note
Adding photon loss or detectors corresponds to performing a measurement of the quantum state, which collapses it and is therefore incompatible with amplitude retrieval. Thus, this measurement strategy requires that no noise model or detectors are defined.
PARTIAL MEASUREMENT
Partial measurement is a specific kind of measurement strategy. With this measurement strategy, only some modes are measured while amplitudes are preserved on the other modes. For more details, checkout the Partial Measurement page.
Photon Loss-aware & Detector-aware execution
When a pcvl.Experiment is provided, the QuantumLayer
derives a photon loss transform and a detector transform that remaps raw Fock-state probabilities to the classical
outcomes defined by the experiment. The photon loss mapping is applied first. Then, the detector mapping is applied. Lastly, the
measurement strategy converts the distribution into classical features. As a consequence:
MeasurementStrategy.probs()andMeasurementStrategy.mode_expectations()transparently work with any noise model and detector setup.MeasurementStrategy.amplitudes()requires direct access to the complex amplitudes and therefore cannot be used when a noise model or custom detectors are defined (the layer will raise aRuntimeError).
Computation space and grouping
The measurement strategy is now a first class object that contains all of the informations of the output of the layer for SLOS optimizations. The MeasurementStrategy now gets two arguments in input.
computation_space: AComputationSpaceobject that defines the output computation space.It will be the only way to define the computation space as the
no_bunchingflag is deprecated.Warning
Deprecated since version 0.3: The use of the
no_bunchingflag is deprecated and is removed since version 0.3.0. Use thecomputation_spaceflag insidemeasurement_strategyinstead. See Migration guide.grouping: The grouping strategy to use betweenLexGroupingandModGrouping. By default, no grouping is applied.
Returning typed objects
When return_object is set to True in the constructor of QuantumLayer, the output of a forward() call depends of the measurement_strategy. By default,
it is set to False. See the following output matrix to see what to expect as the return of a forward call.
measurement_strategy |
return_object=False |
return_object=True |
|---|---|---|
AMPLTITUDES |
torch.Tensor |
StateVector |
PROBABILITIES |
torch.Tensor |
ProbabilityDistribution |
PARTIAL_MEASUREMENT |
PartialMeasurement |
PartialMeasurement |
MODE_EXPECTATIONS |
torch.Tensor |
torch.Tensor |
Most of the typed objects can give the torch.Tensor as an output with the .tensor parameter. Only the
PartialMeasurement object is a little different. See its according documentation.
These object could be quite useful to access metadata like the number of photons, modes and measurement_strategy behind the output tensors. For example, a better access to specific
states is available with StateVector and ProbabilityDistribution by indexing the desired state. The objects are interoperable with Perceval, enabling seamless interaction between the two libraries.
For more information on the typed output capabilities, follow the following links:
StateVector: StateVectorProbabilityDistribution: ProbabilityDistributionPartialMeasurement: PartialMeasurement
The snippet below prepares a basic quantum layer and returns a ProbabilityDistribution object:
import torch
import perceval as pcvl
from merlin.algorithms.layer import QuantumLayer
from merlin.core import ComputationSpace, ProbabilityDistribution
from merlin.measurement.strategies import MeasurementStrategy
circuit = ML.CircuitBuilder(n_modes=4)
circuit.add_entangling_layer()
bell = pcvl.StateVector()
bell += pcvl.BasicState([1, 0, 1, 0])
bell += pcvl.BasicState([0, 1, 0, 1])
print(bell) # bell is a state vector of 2 photons in 4 modes
layer = QuantumLayer(
builder=circuit,
n_photons=2,
input_state=bell,
measurement_strategy=MeasurementStrategy.probs(computation_space=ComputationSpace.DUAL_RAIL),
return_object=True,
)
x = torch.rand(10, circuit.m) # batch of classical parameters
probs = layer(x)
assert isinstance(probs,ProbabilityDistribution)
assert isinstance(probs.tensor,torch.Tensor)
Migrating from OutputMappingStrategy (legacy)
Earlier releases exposed QuantumLayer through
OutputMappingStrategy. Newc code should rely on MeasurementStrategy
instead. The mapping is:
OutputMappingStrategy.NONE→MeasurementStrategy.probs()OutputMappingStrategy.LINEAR→MeasurementStrategy.probs()followed by atorch.nn.LinearlayerOutputMappingStrategy.LEXGROUPINGorGROUPING→MeasurementStrategy.probs()+LexGroupingOutputMappingStrategy.MODGROUPING→MeasurementStrategy.probs()+ModGrouping
Selection Cheat Sheet
Scenario |
Recommended Pipeline |
Notes |
|---|---|---|
Classification / Regression |
|
Obtain logits or arbitrary ranges with |
Structured probability outputs |
|
Preserves probability mass while reducing dimensionality. |
Hardware-friendly analytics |
|
Outputs one feature per mode, easy to interpret. |
Algorithm debugging |
|
Complex amplitudes, simulation only. |
Next steps
Experiment with the different measurement strategies.
Explore the two external grouping methods
LexGroupingandModGrouping.Take a look at the Angle Encoding and Amplitude Encoding documentation to learn about data encoding using MerLin.