You're reading the documentation of the 0.2. For the latest released version, please have a look at 0.4.
merlin.pcvl_pytorch.locirc_to_tensor module
- class merlin.pcvl_pytorch.locirc_to_tensor.AComponent(m, name=None)
Bases:
ABC- DEFAULT_NAME = None
- class merlin.pcvl_pytorch.locirc_to_tensor.BS(theta=pi / 2, phi_tl=0, phi_bl=0, phi_tr=0, phi_br=0, convention=BSConvention.Rx)
Bases:
ACircuitBeam Splitter
Beam splitters couple two spatial modes together, acting on \(\ket{1,0}\) and \(\ket{0,1}\).
- Parameters:
- DEFAULT_NAME = 'BS'
- static H(theta=pi / 2, phi_tl=0, phi_bl=0, phi_tr=0, phi_br=0)
Convenient named constructor for a Beam Splitter following Hadamard convention. Its parameters are the same as the main constructor.
- static Rx(theta=pi / 2, phi_tl=0, phi_bl=0, phi_tr=0, phi_br=0)
Convenient named constructor for a Beam Splitter following Rotation X convention. Its parameters are the same as the main constructor.
- static Ry(theta=pi / 2, phi_tl=0, phi_bl=0, phi_tr=0, phi_br=0)
Convenient named constructor for a Beam Splitter following Rotation Y convention. Its parameters are the same as the main constructor.
- property convention
Beam splitter convention
- definition()
Gives mathematical definition of the circuit
Only defined for elementary circuits
- describe()
Describe the component as the Python code that generates it.
- Returns:
str– code generating the component
- get_variables()
- inverse(v=False, h=False)
- property name
Returns component name
- static r_to_theta(r)
Compute theta given a reflectivity value. Supports symbolic computing.
- Parameters:
r (
float|Parameter) – reflectivity value (can be variable)- Returns:
float|Expression– theta value or symbolic expression
- property reflectivity
Beam Splitter reflectivity
- Returns:
reflectivity of the current Beam Splitter
- static theta_to_r(theta)
Compute reflectivity given a theta value. Supports symbolic computing.
- Parameters:
- Returns:
float|Expression– reflectivity value or symbolic expression
- enum merlin.pcvl_pytorch.locirc_to_tensor.BSConvention(value)
Bases:
IntEnumBeam splitter conventions
- Member Type:
Valid values are as follows:
- Rx = <BSConvention.Rx: 0>
- Ry = <BSConvention.Ry: 1>
- H = <BSConvention.H: 2>
- class merlin.pcvl_pytorch.locirc_to_tensor.Barrier(m, visible=True)
Bases:
ACircuitA barrier is a visual component which has no effect on photons (it behaves as an identity unitary). It may be used to separate or align multiple components in a given Circuit.
- Parameters:
- DEFAULT_NAME = 'I'
- apply(r, sv)
- definition()
Gives mathematical definition of the circuit
Only defined for elementary circuits
- describe()
Describe the component as the Python code that generates it.
- Returns:
code generating the component
- inverse(v=False, h=False)
- property visible
- class merlin.pcvl_pytorch.locirc_to_tensor.Circuit(m, name=None)
Bases:
ACircuitClass to represent any circuit composed of one or multiple components
- DEFAULT_NAME = 'CPLX'
- add(port_range, component, merge=False)
Add a component in a circuit
- Parameters:
port_range (
int|tuple[int,...]) – the port range as a tuple of consecutive ports, or the initial port where to add the componentcomponent (
ACircuit) – the component to add, must be a linear component or circuitmerge (
bool) – when the component is a complex circuit, if True, flatten the added circuit. Otherwise, keep the nested structure (default False)
- Returns:
Circuit– the circuit itself, allowing to add multiple components in a same line- Raise:
AssertionErrorif parameters are not valid
- barrier()
Add a barrier to a circuit
The barrier is a visual marker to break down a circuit into sections. Behind the scenes, it is implemented as a Barrier unitary operating on all modes.
At the moment, the barrier behaves exactly like a component with a unitary equal to identity.
- compute_unitary(assign=None, use_symbolic=False, use_polarization=None)
Compute the unitary matrix corresponding to the current circuit
- Parameters:
- Returns:
Matrix– the unitary matrix, will be aMatrixSif symbolic, or a ~`MatrixN` if not.
- copy()
Return a deep copy of the current circuit
- static decomposition(U, component, phase_shifter_fn=None, shape=InterferometerShape.TRIANGLE, permutation=None, inverse_v=False, inverse_h=False, constraints=None, merge=True, precision=1e-06, max_try=10, allow_error=False, ignore_identity_block=True)
Decompose a given unitary matrix U into a circuit with a specified component type
- Parameters:
U (
MatrixN) – the matrix to decomposecomponent (
ACircuit) – a circuit, to solve any decomposition must have up to 2 independent parametersphase_shifter_fn (
Callable[[int],ACircuit]) – a function generating a phase_shifter circuit. If None, residual phase will be ignoredshape (
str|InterferometerShape) – shape of the decomposition (triangle is natively supported in Perceval)permutation (
type[ACircuit]) – if provided, type of permutation operator to avoid unnecessary operatorsinverse_v (
bool) – inverse the decomposition verticallyinverse_h (
bool) – inverse the decomposition horizontallyconstraints – constraints to apply on both parameters, it is a list of individual constraints. Each constraint should have the numbers of free parameters of the system.
merge (
bool) – don’t use sub-circuitsprecision (
float) – for intermediate values - norm below precision are considered 0. If not - use global_paramsmax_try (
int) – number of times to try the decompositionallow_error (
bool) – allow decomposition error - when the actual solution is not locally reachableignore_identity_block (
bool) – If true, do not insert a component when it’s not needed (component is an identity) Otherwise, insert a component everytime (default True).
- Returns:
a circuit
- definition()
Gives mathematical definition of the circuit
Only defined for elementary circuits
- Return type:
- depths()
- Returns:
the depth of the circuit for each mode
- describe()
Describe a circuit
- Returns:
str– a string describing the circuit that be re-used to define the circuit
- find_subnodes(pos)
find the subnodes of a given component (Udef for pos==None)
- get_parameters(all_params=False, expressions=False)
Return the parameters of the circuit
- getitem(idx, only_parameterized=False)
Direct access to components of the circuit :type idx:
tuple[int,int] :param idx: index of the component as (row, col) :type only_parameterized:bool:param only_parameterized: if True, only count components with parameters :return:ACircuit– the component
- inverse(v=False, h=False)
Inverts a circuit in place, depending on the values of
handv.- Parameters:
h – Stands for horizontal. If True, the circuit will be reversed such that its final unitary matrix is the inverse of the original one.
v – Stands for vertical. If True, the circuit will be reversed such that the mode 0 becomes the mode \(m-1\), the mode 1 becomes the mode \(m - 2\)…
- is_composite()
- Returns:
True if the component is itself composed of subcomponents
- isolate(lc, name=None, color=None)
- match(pattern, pos=None, pattern_pos=0, browse=False, match=None, actual_pos=None, actual_pattern_pos=None, reverse=False)
match a sub-circuit at a given position
- Parameters:
match (
Match) – the partial matchbrowse (
bool) – true if we want to search the pattern at any location in the current circuit, if true, pos should be Nonepattern (
ACircuit) – the pattern to search forpos (
int) – the start position in the current circuitpattern_pos (
int) – the start position in the patternactual_pos (
int) – unused, parameter only used by parent classactual_pattern_pos (
int) – unused, parameter only used by parent classreverse (
bool) – true if we want to search the pattern from the end of the circuit to pos (or the 0 if browse)
- Returns:
Optional[Match] –:
- ncomponents()
- Returns:
number of actual components in the circuit
- replace(p, pattern, merge=False)
- property requires_polarization: bool
Does the circuit require polarization?
- Returns:
is True if the circuit has a polarization component
- transfer_from(source, force=False)
Transfer parameters of a circuit to the current one
- class merlin.pcvl_pytorch.locirc_to_tensor.CircuitConverter(circuit, input_specs=None, dtype=torch.complex64, device=device(type='cpu'))
Bases:
objectConvert a parameterized Perceval circuit into a differentiable PyTorch unitary matrix.
This class converts Perceval quantum circuits into PyTorch tensors that can be used in neural network training with automatic differentiation. It supports batch processing for efficient training and handles various quantum components like beam splitters, phase shifters, and unitary operations.
- Supported Components:
PS (Phase Shifter)
BS (Beam Splitter)
PERM (Permutation)
Unitary (Generic unitary matrix)
Barrier (no-op, removed during compilation)
- Attributes:
circuit: The Perceval circuit to convert param_mapping: Maps parameter names to tensor indices device: PyTorch device for tensor operations tensor_cdtype: Complex tensor dtype tensor_fdtype: Float tensor dtype
- Example:
Basic usage with a single phase shifter:
>>> import torch >>> import perceval as pcvl >>> from merlin.pcvl_pytorch.locirc_to_tensor import CircuitConverter >>> >>> # Create a simple circuit with one phase shifter >>> circuit = pcvl.Circuit(1) // pcvl.PS(pcvl.P("phi")) >>> >>> # Convert to PyTorch with gradient tracking >>> converter = CircuitConverter(circuit, input_specs=["phi"]) >>> phi_params = torch.tensor([0.5], requires_grad=True) >>> unitary = converter.to_tensor(phi_params) >>> print(unitary.shape) # torch.Size([1, 1])
Multiple parameters with grouping:
>>> # Circuit with multiple phase shifters >>> circuit = (pcvl.Circuit(2) ... // pcvl.PS(pcvl.P("theta1")) ... // (1, pcvl.PS(pcvl.P("theta2")))) >>> >>> converter = CircuitConverter(circuit, input_specs=["theta"]) >>> theta_params = torch.tensor([0.1, 0.2], requires_grad=True) >>> unitary = converter.to_tensor(theta_params) >>> print(unitary.shape) # torch.Size([2, 2])
Batch processing for training:
>>> # Batch of parameter values >>> batch_params = torch.tensor([[0.1], [0.2], [0.3]], requires_grad=True) >>> converter = CircuitConverter(circuit, input_specs=["phi"]) >>> batch_unitary = converter.to_tensor(batch_params) >>> print(batch_unitary.shape) # torch.Size([3, 1, 1])
Training integration:
>>> # Training loop with beam splitter >>> circuit = pcvl.Circuit(2) // pcvl.BS.Rx(pcvl.P("theta")) >>> converter = CircuitConverter(circuit, ["theta"]) >>> theta = torch.tensor([0.5], requires_grad=True) >>> optimizer = torch.optim.Adam([theta], lr=0.01) >>> >>> for step in range(10): ... optimizer.zero_grad() ... unitary = converter.to_tensor(theta) ... loss = some_loss_function(unitary) ... loss.backward() ... optimizer.step()
- set_dtype(dtype)
Set the tensor data types for float and complex operations.
- Args:
dtype: Target dtype (float32/complex64 or float64/complex128)
- Raises:
TypeError: If dtype is not supported
- to(dtype, device)
Move the converter to a specific device and dtype.
- Args:
dtype: Target tensor dtype (float32/complex64 or float64/complex128) device: Target device (string or torch.device)
- Returns:
Self for method chaining
- Raises:
TypeError: If device type or dtype is not supported
- to_tensor(*input_params, batch_size=None)
Convert the parameterized circuit to a PyTorch unitary tensor.
- Return type:
- Args:
*input_params: Variable number of parameter tensors. Each tensor has shape (num_params,) or (batch_size, num_params) corresponding to input_specs order. batch_size: Explicit batch size. If None, inferred from input tensors.
- Returns:
- Complex unitary tensor of shape (circuit.m, circuit.m) for single samples
or (batch_size, circuit.m, circuit.m) for batched inputs.
- Raises:
ValueError: If wrong number of input tensors provided. TypeError: If input_params is not a list or tuple.
- class merlin.pcvl_pytorch.locirc_to_tensor.PERM(perm)
Bases:
UnitaryPermutation
A swap between any number of consecutive spatial modes.
>>> permutation = PERM([2, 3, 1, 0]) # respectively swaps mode 0 to 2, 1 to 3, 2 to 1 and 3 to 0.
- DEFAULT_NAME = 'PERM'
- apply(r, sv)
Apply the permutation to a state
- break_in_2_mode_perms()
Breaks any n-mode permutation into an equivalent circuit made of only 2-mode permutations.
- Returns:
An equivalent Circuit made of only 2-mode permutations
- definition()
Gives mathematical definition of the circuit
Only defined for elementary circuits
- describe()
Describe the component as the Python code that generates it.
- Returns:
code generating the component
- property perm_vector
Return the permutation vector
- class merlin.pcvl_pytorch.locirc_to_tensor.PS(phi, max_error=0)
Bases:
ACircuitPhase shifter
A phase shifter adds a phase \(\phi\) on a spatial mode, which corresponds to a Z rotation in the Bloch sphere.
- Parameters:
- DEFAULT_NAME = 'PS'
- definition()
Gives mathematical definition of the circuit
Only defined for elementary circuits
- Return type:
- describe()
Describe the component as the Python code that generates it.
- Returns:
code generating the component
- get_variables()
- inverse(v=False, h=False)
- merlin.pcvl_pytorch.locirc_to_tensor.SUPPORTED_COMPONENTS = (<class 'perceval.components.unitary_components.PS'>, <class 'perceval.components.unitary_components.BS'>, <class 'perceval.components.unitary_components.PERM'>, <class 'perceval.components.unitary_components.Unitary'>, <class 'perceval.components.unitary_components.Barrier'>)
Tuple of quantum components supported by CircuitConverter.
- Components:
PS: Phase shifter with single phi parameter BS: Beam splitter with theta and four phi parameters PERM: Mode permutation (no parameters) Unitary: Generic unitary matrix (no parameters) Barrier: Synchronization barrier (removed during compilation)
- class merlin.pcvl_pytorch.locirc_to_tensor.Unitary(U, name=None, use_polarization=False)
Bases:
ACircuitGeneric component defined by a unitary matrix
- Parameters:
- DEFAULT_NAME = 'Unitary'
- describe()
Describe the component as the Python code that generates it.
- Returns:
code generating the component
- static fourier(m, adjoint=False)
Static method generating a Fourier interferometer unitary.
- inverse(v=False, h=False)
- merlin.pcvl_pytorch.locirc_to_tensor.dispatch(*types, **kwargs)
Dispatch function on the types of the inputs
Supports dispatch on all non-keyword arguments.
Collects implementations based on the function name. Ignores namespaces.
If ambiguous type signatures occur a warning is raised when the function is defined suggesting the additional method to break the ambiguity.
Examples
>>> @dispatch(int) ... def f(x): ... return x + 1
>>> @dispatch(float) ... def f(x): ... return x - 1
>>> f(3) 4 >>> f(3.0) 2.0
Specify an isolated namespace with the namespace keyword argument
>>> my_namespace = dict() >>> @dispatch(int, namespace=my_namespace) ... def foo(x): ... return x + 1
Dispatch on instance methods within classes
>>> class MyClass(object): ... @dispatch(list) ... def __init__(self, data): ... self.data = data ... @dispatch(int) ... def __init__(self, datum): ... self.data = [datum]
- merlin.pcvl_pytorch.locirc_to_tensor.resolve_float_complex(dtype)
Given a torch dtype representing either the float or complex side, return the matching pair.
- Args:
dtype: torch float or complex dtype.
- Returns:
Tuple (float_dtype, complex_dtype) ensuring the pair is internally consistent.
- Raises:
TypeError: If the dtype is not one of the supported float/complex types.