symop.devices.models.beamsplitters.beamsplitter¶
Path beamsplitter device.
This module defines BeamSplitter, a path-based two-port mixing
device that prepares mode-pair information for backend execution.
For each matched pair of modes on the two input paths, the planning stage
records a pair specification in action.params["pairs"] for the backend
kernel. The physical two-mode unitary is not applied during planning.
The high-level device parameter theta is interpreted through
t = cos(theta) and r = sin(theta). Therefore theta = pi / 4
corresponds to a balanced 50/50 beamsplitter.
Notes
The backend kernel is expected to realize the full beamsplitter rewrite, including creation of output-path modes. Planning is purely semantic and does not modify amplitudes or apply label edits.
Classes
|
Ideal path beamsplitter device. |
- class BeamSplitter(theta: float, phi_t: float = 0.0, phi_r: float = 0.0) None¶
Bases:
DeviceBaseIdeal path beamsplitter device.
A beamsplitter acts on matched mode pairs drawn from two input paths. Planning records the participating input modes, output paths, and beamsplitter parameters for backend execution.
The device uses the package Heisenberg convention, where creation operators transform as
\[\hat a^\dagger_{\mathrm{out},k} = \sum_j U_{k j}\,\hat a^\dagger_{\mathrm{in},j}.\]The angle
thetadetermines the transmission and reflection amplitudes by\[t = \cos(\theta), \qquad r = \sin(\theta).\]With phases
phi_tandphi_r, the two-mode unitary is\[\begin{split}U = \begin{pmatrix} t e^{i\phi_t} & r e^{i\phi_r} \\ -r e^{-i\phi_r} & t e^{-i\phi_t} \end{pmatrix}.\end{split}\]Thus
theta = pi / 4gives a balanced 50/50 beamsplitter.In this implementation, transmission corresponds to remaining on the same path index, while reflection corresponds to switching to the opposite path:
in0 -> out0: transmissionin0 -> out1: reflectionin1 -> out1: transmissionin1 -> out0: reflection, with the phase determined by the lower-left
unitary element
Thus a fully transmitting beamsplitter (theta = 0) leaves paths unchanged, while a fully reflecting beamsplitter (theta = pi/2) swaps the two paths.
- Parameters:
Examples
Create a balanced (50/50) beamsplitter and apply it to two paths:
>>> import numpy as np >>> bs = BeamSplitter(theta=np.pi / 4) >>> state_out = bs( ... state_in, ... ports={ ... "in0": Path("a"), ... "in1": Path("b"), ... "out0": Path("c"), ... "out1": Path("d"), ... }, ... )
Notes
Planning does not relabel existing modes. The actual two-mode rewrite, including construction of output-path modes, is delegated to the runtime kernel through
action.params["pairs"].- _abc_impl = <_abc._abc_data object>¶
- apply(state: State, *, ports: Mapping[str, Path], selection: object | None = None, runtime: DeviceRuntime | None = None, ctx: ApplyContext | None = None, out_kind: Literal['ket', 'density'] | None = None) State¶
Apply the device to a state through a runtime.
- property kind: DeviceKind¶
Return the device kind identifier.
- plan(*, state: State, ports: Mapping[str, Path], selection: object | None = None, ctx: ApplyContext | None = None) DeviceAction¶
Plan beamsplitter mixing on matched mode pairs.
- Parameters:
state (
State) – Input state whose mode labels are inspected.ports (
Mapping[str,Path]) – Mapping from device-port names to path labels. Must contain"in0","in1","out0", and"out1".selection (
object|None) – Optional selection object forwarded by the runtime. It is not used by this device.ctx (
ApplyContext|None) – Optional apply context forwarded by the runtime. It is not used by this device.
- Returns:
Planned action containing:
params["pairs"]: tuple of beamsplitter pair specificationsedits: always empty for this device
- Return type:
- Raises:
TypeError – If the state does not support path-based mode lookup.
ValueError – If both inputs are populated but contain incompatible numbers of modes.
Notes
The unitary itself is not applied here. This method only prepares semantic pairing and kernel parameters. If one side is missing, the backend kernel is expected to synthesize a matching vacuum partner.