Kernels: Advanced Guide and Theory
This page dives into the implementation of MerLin’s photonic kernel stack,
backing the API documented in merlin.algorithms.kernels.
Mathematical definition
For a photonic feature map that embeds a datapoint \(x\) as a unitary matrix \(U(x)\) and a chosen input Fock state \(|s\rangle\), the fidelity kernel is
MerLin evaluates this quantity by constructing the composite circuit \(U^{\dagger}(x_2)U(x_1)\) and computing the transition probability from the input state to itself under that circuit. When an experiment provides noise and detectors, the raw probabilities are transformed accordingly before reading the scalar result.
Architecture overview
Four components cooperate to build and evaluate kernels:
FeatureMap– a descriptor that storesthe photonic circuit and its parameter layout. It accepts:
a
pcvl.Circuit(manual construction),a
CircuitBuilder(declarative), ora
pcvl.Experiment(unitary circuit + measurement semantics).
FeatureMapis a pure descriptor.FidelityKernelreads its fields (experiment, parameter prefixes, input size, dtype, device) to configure the computation backend and does not call any method on it for encoding or unitary construction.
_CCInvQuantumLayer– the internal computation backend, aQuantumLayersubclass constructed byFidelityKernel. It owns encoding, unitary computation, SLOS simulation, pairwise kernel-matrix assembly, and the photon-loss/detector pipeline. All circuit-level work is delegated to this object.
FidelityKernel– validates the featuremap, builds
_CCInvQuantumLayer, normalizes public inputs, and delegates kernel-matrix construction to the backend.
CircuitBuilder– declarativehelper to build circuits for
FeatureMap(builder=...)(and thereforeFidelityKernel).
Data encoding pipeline
FidelityKernel encodes datapoints through _CCInvQuantumLayer._encode_single,
which maps a flat feature tensor to the parameter shape the circuit expects.
The supported encoding contract has two cases:
- If the feature map was created from a
CircuitBuilder, use its angle‑encoding metadata (combinationsand per‑indexscales) to compute linear forms of the input vector via_prepare_input_encoding. This guarantees the encoded vector length matches the converter specification for the declared input prefix.
- Otherwise (plain
pcvl.Circuitorpcvl.Experiment construction),
FeatureMap.input_sizemust exactly match the number of circuit input parameters selected byFeatureMap.input_parameters. The input is passed through with that parameter dimension.For compatibility, direct circuit and experiment feature maps may still use the legacy
FeatureMap.encodercallable or the legacy subset/truncation behavior whenFeatureMap.input_sizediffers from the circuit input parameter count. This compatibility path emits aDeprecationWarningand will be removed in a future release.
- Otherwise (plain
Deprecated since version 0.4: The encoder callable accepted by FeatureMap
is only consulted by the legacy compute_unitary()
path (FeatureMap._encode_x) and by FidelityKernel only for
deprecated compatibility with older direct-circuit feature maps. Pass
encoding logic through a CircuitBuilder
or pass inputs with the circuit parameter dimension instead.
Unitary construction
The CircuitConverter holds a compiled representation of the photonic
model (unitary compute graph) and exposes to_tensor(...) to produce a
complex matrix on the configured device/dtype. When the feature map is
trainable, the trainable torch.nn.Parameter objects are registered on
_CCInvQuantumLayer (accessible via QuantumLayer.thetas) and
concatenated before the encoded inputs when calling the converter.
Note
FeatureMap._training_dict still holds a copy of the trainable
parameters for the deprecated compute_unitary()
path. FidelityKernel does not read this dictionary.
Pairwise circuit evaluation and vectorization
Given batches X1 of size \(N\) and (optionally) X2 of size
\(M\), _CCInvQuantumLayer evaluates the transition probabilities for
all pairs by constructing the set of composite circuits
U_forward @ U_adjoint where U_forward = U(x1) and
U_adjoint = U(x2)^{\dagger}:
- For train Gram matrices (
x2 is None), only the upper triangular pairs are simulated; results are mirrored and the diagonal is filled with ones.
- For train Gram matrices (
- For test Gram matrices (
x2provided), the full \(N\times M\) set is simulated.
- For test Gram matrices (
The resulting batch of composite unitaries is forwarded to the SLOS compute graph.
SLOS compute graph
The kernel builds a SLOS distribution graph via
build_slos_distribution_computegraph with parameters:
number of modes \(m\), total photons \(n\),
computation_spaceclass, andkeep_keys=True.
The graph exposes the list of Fock states (final_keys) and a
compute_probs(unitaries, input_state) method that returns transition
probabilities from the given input state to every output state for each
unitary. Internally, the implementation is vectorised (TorchScript‑friendly)
and reuses pre‑computed sparse transitions per layer.
Photon loss and detectors
If the FeatureMap comes from an experiment (or if the kernel creates
one from its circuit), two transforms may be applied to raw probabilities:
PhotonLossTransform– composes theexperiment’s
pcvl.NoiseModelinto survival probabilities. This returns a new probability vector and a new set of output keys.
DetectorTransform– projects (or maps)the post‑loss probabilities to the detector outcome basis (threshold, PNR, etc.).
The scalar fidelity value is then read either at the unique index that matches the (surviving) input detection event or as a weighted sum across the detection vector when several detection outcomes are compatible with the input pattern.
Note
Only ComputationSpace.FOCK can be combined with experiments that define
detectors. The kernel raises a RuntimeError if at least one
pcvl.Detector is present in the experiment and any non-FOCK
computation space (e.g. UNBUNCHED or DUAL_RAIL) is requested.
Sampling and autodiff
If shots > 0, the kernel converts exact detection probabilities to sampled
counts via the configured pseudo‑sampler (multinomial/binomial/gaussian) from
the AutoDiffProcess. This enables
benchmarking robustness to shot noise. For gradient‑based learning of trainable
feature maps, keep shots=0 to work with exact probabilities.
PSD projection and numerical safeguards
With force_psd=True (default), the symmetric train Gram matrix is
projected to the closest positive semi‑definite matrix by zeroing negative
eigenvalues in an eigendecomposition. This prevents downstream solvers from
failing due to small numerical inconsistencies. For test matrices, PSD
projection is applied only when inputs are equal (X2 is None or
X2 == X1).
Shapes, devices and dtypes
- Inputs are reshaped to
[N, input_size](and[M, input_size]when x2is provided). Scalars and 1D vectors are validated byis_datapoint()for single‑pair evaluations.
- Inputs are reshaped to
- All intermediate tensors are created on the feature map’s device/dtype unless
explicit overrides are passed to the kernel.
- The SLOS graph internally operates on complex dtypes that match the chosen
float precision.
Complexity and performance tips
- Reduce
m(modes) orn(photons) to shrink the Fock space; use the ComputationSpace.UNBUNCHEDcomputation space instead ofComputationSpace.FOCKwhen your circuit forbids multi‑occupancy per mode.
- Reduce
- Reuse feature maps and kernels across batches to amortize converter/setup
costs.
Keep inputs contiguous and on the same device to minimise transfers.
Avoid sampling during model selection; add
shotswhen stress‑testing.
Limitations
- The kernel API encodes classical inputs via angle encoding; amplitude‑encoded
state vectors are not part of this kernel stack.
- Experiments passed to the kernel must be unitary and without post‑selection
or heralding. Non‑unitary experiments are rejected.
For class/method signatures and basic usage examples, see the API reference:
merlin.algorithms.kernels.