merlin.core.components module
The merlin.core.components module defines the fundamental building blocks for photonic quantum circuits in Merlin. These components are platform-agnostic, descriptive objects that specify what should be present in a circuit (such as rotations, beam splitters, interferometers, and measurements), rather than how they are implemented on a specific backend.
Why use components?
Components provide a clear, modular, and backend-independent way to describe quantum circuits.
They enable high-level circuit construction, parameter management (fixed, trainable, or input-driven), and facilitate translation to various simulation or hardware platforms.
By separating intent from implementation, components make it easy to prototype, optimize, and analyze quantum circuits in a flexible and extensible manner.
Main components include:
Rotation: Describes a phase shifter (single-mode rotation), with configurable axis, value, and parameter role (fixed, trainable, or input).
BeamSplitter: Represents a two-mode mixing operation, with tunable mixing angle (theta) and phase (phi), both of which can be fixed or trainable.
EntanglingBlock: Specifies a block of entangling operations (e.g., nearest-neighbor beam splitters) to increase circuit expressivity.
GenericInterferometer: Encodes a universal linear optical transformation over multiple modes, optionally trainable.
These components are used by higher-level tools (like CircuitBuilder) to assemble, manipulate, and compile quantum circuits for simulation or execution.
Pure descriptive components that describe WHAT we want, not HOW to implement it. Components are platform-agnostic and focus on intent rather than implementation.
- class merlin.core.components.Any(*args, **kwargs)
Bases:
objectSpecial type indicating an unconstrained type.
Any is compatible with every type.
Any assumed to have all methods.
All values assumed to be instances of Any.
Note that all the above statements are true from the point of view of static type checkers. At runtime, Any should not be used with instance checks.
- class merlin.core.components.BeamSplitter(targets, theta_role=ParameterRole.FIXED, theta_value=0.7854, phi_role=ParameterRole.FIXED, phi_value=0.0, theta_name=None, phi_name=None)
Bases:
objectBeam splitter description.
- get_params()
Describe which phase shifter angles should be exposed as parameters.
- Return type:
dict[str,Any]
- Returns:
Dict[str, Any]: Parameter placeholders keyed by their symbolic names.
-
phi_name:
Optional[str] = None
-
phi_role:
ParameterRole= 'fixed'
-
phi_value:
float= 0.0
-
targets:
tuple
-
theta_name:
Optional[str] = None
-
theta_role:
ParameterRole= 'fixed'
-
theta_value:
float= 0.7854
- class merlin.core.components.Component
Bases:
objectBase class for backward compatibility.
- class merlin.core.components.EntanglingBlock(targets='all', pattern='nearest_neighbor', depth=1, trainable=True, name_prefix=None)
Bases:
objectEntangling block description.
-
depth:
int= 1
- get_params()
Entangling blocks themselves carry no direct parameters.
- Return type:
dict[str,Any]
- Returns:
Dict[str, Any]: Always empty because entangling blocks are metadata-only.
-
name_prefix:
Optional[str] = None
-
pattern:
str= 'nearest_neighbor'
-
targets:
str|list[int] = 'all'
-
trainable:
bool= True
-
depth:
- enum merlin.core.components.Enum(value)
Bases:
objectCreate a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3
Access them by:
attribute access:
>>> Color.RED <Color.RED: 1>
value lookup:
>>> Color(1) <Color.RED: 1>
name lookup:
>>> Color['RED'] <Color.RED: 1>
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3
>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
The
Enumand its members have the following methods:- name
The name of the Enum member.
- value
The value of the Enum member.
- class merlin.core.components.GenericInterferometer(start_mode, span, trainable=True, name_prefix=None, model='mzi', trainable_inner=None, trainable_outer=None)
Bases:
objectGeneric interferometer block spanning multiple modes.
- get_params()
Return placeholder names for every internal interferometer parameter.
- Return type:
dict[str,Any]
- Returns:
Dict[str, Any]: Mapping of generated parameter names to
Noneplaceholders.
-
model:
str= 'mzi'
-
name_prefix:
Optional[str] = None
-
span:
int
-
start_mode:
int
-
trainable:
bool= True
-
trainable_inner:
Optional[bool] = None
-
trainable_outer:
Optional[bool] = None
- enum merlin.core.components.ParameterRole(value)
Bases:
EnumClear role definition for parameters.
Valid values are as follows:
- FIXED = <ParameterRole.FIXED: 'fixed'>
- INPUT = <ParameterRole.INPUT: 'input'>
- TRAINABLE = <ParameterRole.TRAINABLE: 'trainable'>
- class merlin.core.components.Rotation(target, role=ParameterRole.FIXED, value=0.0, axis='z', custom_name=None)
Bases:
objectRotation gate description.
The actual parameter name will be generated by the backend based on role.
-
axis:
str= 'z'
-
custom_name:
Optional[str] = None
- get_params()
Return declared parameter placeholders for the rotation.
Non-fixed rotations expose either their custom name or the automatically generated identifier so that downstream tooling can bind data or trainable tensors to the gate.
- Return type:
dict[str,Any]
- Returns:
Dict[str, Any]: Mapping from parameter name to placeholder value.
-
role:
ParameterRole= 'fixed'
-
target:
int
-
value:
float= 0.0
-
axis:
- merlin.core.components.dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False)
Add dunder methods based on the fields defined in the class.
Examines PEP 526 __annotations__ to determine fields.
If init is true, an __init__() method is added to the class. If repr is true, a __repr__() method is added. If order is true, rich comparison dunder methods are added. If unsafe_hash is true, a __hash__() method is added. If frozen is true, fields may not be assigned to after instance creation. If match_args is true, the __match_args__ tuple is added. If kw_only is true, then by default all fields are keyword-only. If slots is true, a new class with a __slots__ attribute is returned.