mimiqcircuits.operations.operators.lossyoperator

Classes

LossyOperator(mat[, lossy])

N-qubit operator specified by a \(2^N \times 2^N\) matrix and a set of lossy qubit indices.

class mimiqcircuits.operations.operators.lossyoperator.LossyOperator(mat, lossy=None)[source]

Bases: AbstractOperator

N-qubit operator specified by a \(2^N \times 2^N\) matrix and a set of lossy qubit indices.

Note

Only one and two qubit lossy operators are supported.

A LossyOperator represents a tagged custom operator used as a loss branch inside a Kraus channel. The matrix is expressed in the computational basis, exactly like Operator, while lossy marks which of the operator’s local qubits leak when this branch is selected.

The lossy indices are local to the operator and use 1:N numbering, following the Julia implementation. They are not circuit-global qubit indices. When a surrounding Kraus channel is applied to circuit targets (q_1, ..., q_N), each local index i in lossy maps to the corresponding physical target q_i.

A Kraus channel that contains one or more LossyOperator branches is a loss-aware channel. The helpers Kraus.hasloss(), Kraus.lossoperators(), Kraus.survivaloperators(), and Kraus.losseffect() inspect those branches.

See also

AbstractOperator, Operator, Kraus

Parameters:
  • mat (symengine.Matrix | sympy.Matrix | np.ndarray) – The \(2^N \times 2^N\) matrix representing the operator.

  • lossy (int | tuple | list, optional) – One or more local qubit indices in 1:N that leak when this branch is selected. For one-qubit operators, the default is (1,). For multi-qubit operators, the lossy qubits must be specified explicitly.

Examples

>>> from mimiqcircuits import *
>>> from symengine import Matrix, sqrt
>>> op = LossyOperator(Matrix([[0, 1], [0, 0]]))
>>> op
1-qubit LossyOperator (lossy=(1,)):
├── 0 1
└── 0 0
>>> c = Circuit()
>>> c.push(Kraus([Matrix([[1, 0], [0, sqrt(0.9)]]),
...               LossyOperator(Matrix([[0, sqrt(0.1)], [0, 0]]))]), 1)
2-qubit circuit with 1 instruction:
└── Kraus(Operator([[1, 0], [0, 0.948683298050514]]), LossyOperator([[0, 0.316227766016838], [0, 0]]; lossy=(1,))) @ q[1]
__init__(mat, lossy=None)[source]
static is_valid_power_of_2(n)[source]
opname()[source]
iswrapper()[source]

Check if the operator is a wrapper around another operator.

This method should be overridden in subclasses to return True if the operator is acting as a wrapper around another operation or object, and False otherwise.

Returns:

Always returns False in the base class. Subclasses should override this method to provide the appropriate logic.

Return type:

bool

property parnames
lossyqubits()[source]
lossytargets(*targets)[source]
unwrappedmatrix()[source]

Numeric matrix representation as a numpy.ndarray[complex128].

This is the Python analogue of Julia’s unwrappedmatrix(::AbstractOperator): simulators and anything else that wants raw numbers (e.g. TensorWeaver) should call this instead of matrix(). It bypasses SymEngine entirely for gates that override _matrix_numeric() — see mimiqcircuits.numerics — and otherwise falls back to building the SymEngine matrix and casting it.

Constant gates cache the result at class level.

Raises:

UnexpectedSymbolics – If any parameter is still symbolic.

Returns:

complex128 matrix.

Return type:

numpy.ndarray

evaluate(values)[source]

Substitute the symbolic parameters of the operator with numerical values.

This method evaluates the operator’s symbolic parameters using the values provided in the dictionary d. If the operator has no parameters, it returns the same instance. Otherwise, it creates a new instance of the operator with updated numerical parameters.

Parameters:

d (dict) – A dictionary where keys are symbolic parameter names and values are values for substitution.

Example

>>> from symengine import *
>>> from mimiqcircuits import *
>>> theta = symbols('theta')
>>> op = GateRX(theta)
>>> evaluated_op = op.evaluate({'theta': 0.5})
>>> print(evaluated_op)
RX(0.5)
opsquared()[source]
rescale(scale)[source]
rescale_inplace(scale)[source]
pretty_print()[source]