merlin.pcvl_pytorch.locirc_to_tensor module
- class merlin.pcvl_pytorch.locirc_to_tensor.AComponent(m, name=None)
Bases:
ABC- DEFAULT_NAME = None
- is_composite()
- Return type:
bool- Returns:
True if the component is itself composed of subcomponents
- property m: int
- property name: str
Returns component name
- 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:
theta (
Parameter|float) – theta parameterphi_tl (
Parameter|float) – top-left phase parameterphi_bl (
Parameter|float) – bottom-left phase parameterphi_tr (
Parameter|float) – top-right phase parameterphi_br (
Parameter|float) – bottom-right phase parameter
- 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.
- Return type:
str- Returns:
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)- Return type:
float|Expression- Returns:
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:
theta (
float|Parameter) – theta angle (can be variable)- Return type:
float|Expression- Returns:
reflectivity value or symbolic expression
- enum merlin.pcvl_pytorch.locirc_to_tensor.BSConvention(value)
Bases:
IntEnumBeam splitter conventions
- Member Type:
int
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:
m (
int) – Number of consecutive modes it coversvisible (
bool) – The barrier is rendered if True, and is invisible otherwise
- 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
- Parameters:
m (
int) – The number of port of the circuitname (
str) – Name of the circuit
- 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)
- Return type:
- Returns:
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:
use_polarization (
bool) – ask for polarized circuit to double size unitary matrixassign (
dict) – optional mapping between parameter names and their corresponding valuesuse_symbolic (
bool) – if the matrix should use symbolic calculation
- Return type:
Matrix- Returns:
the unitary matrix, will be a
MatrixSif 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:
Matrix
- depths()
- Returns:
the depth of the circuit for each mode
- describe()
Describe a circuit
- Return type:
str- Returns:
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)
- Parameters:
pos (
int) – the position of the current node- Return type:
list[int]- Returns:
- get_parameters(all_params=False, expressions=False)
Return the parameters of the circuit
- Parameters:
all_params (
bool) – if False, only returns the variable parameters- Expressions:
if True, returns highest level Expressions and parameters only. If False, returns the raw parameters that make up the expressions only. Default False.
- Return type:
list[Parameter]- Returns:
the list of parameters
- 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 :rtype:ACircuit:return: 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)
- Return type:
Optional[Match]- Returns:
- 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
- Parameters:
source (
ACircuit) – the circuit to transfer the parameters from. The shape of the circuit to transfer from should be a subset of the current circuit.force (
bool) – force changing fixed parameter if necessary
- 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.
- Parameters:
perm (
list[int]) – Vector of mode index defining the permutation.
>>> 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
- Parameters:
r (
tuple[int,...]) – Range of consecutive modes where the permutation occurs- Sv:
State on which the permutation is applied
- 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:
phi (
Parameter|float) – Phase anglemax_error (
Parameter|float) – Maximum random error to apply. The error is uniformly drawn in \([\phi - max_{error}, \phi + max_{error}]\). A global phase error noise parameter can also be set in the NoiseModel for all the phase shifters of a given Experiment.
- DEFAULT_NAME = 'PS'
- definition()
Gives mathematical definition of the circuit
Only defined for elementary circuits
- Return type:
Matrix
- 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:
U (
Matrix) – numeric matrix. Does not support symbolic computation.name (
str) – Custom name for the component it represents (default is “Unitary”).use_polarization (
bool) – True if the unitary represents a polarized component.
- DEFAULT_NAME = 'Unitary'
- describe()
Describe the component as the Python code that generates it.
- Returns:
code generating the component
- 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.
- Return type:
tuple[dtype,dtype]
- 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.