mimiqcircuits package#
- class mimiqcircuits.AbstractAnnotation[source]#
Bases:
Operation
Abstract base class for annotations in quantum circuits.
This class is used as a base for defining various annotation types, such as Detector, QubitCoordinates, ShiftCoordinates,`Tick`, ObservableInclude, which provide metadata or structural information for quantum circuits.
- class mimiqcircuits.AbstractOperator[source]#
Bases:
Operation
Supertype for all N-qubit operators.
Note that objects of type AbstractOperator do not need to be unitary.
Operators can be used to define Kraus channels (noise) (see
krauschannel
), or to compute expectation values (seeExpectationValue
). However, they will return an error if directly applied to states.See also
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- static isunitary()[source]#
Check if the object is unitary.
This static method returns False for all instances, indicating that the object is not unitary by default.
- Returns:
Always returns False.
- Return type:
bool
- 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
- matrix()[source]#
Compute the matrix representation of the operator.
This method returns a symengine Matrix object representing the operator. It simplifies the matrix expression and evaluates it to a floating-point precision.
- Returns:
The matrix representation of the operator.
- Return type:
symengine.Matrix
- power(n)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- unwrappedmatrix()[source]#
Compute the matrix representation with all parameters evaluated.
This method returns the matrix representation of the operator with all symbolic parameters substituted with their numerical values. If any parameter cannot be evaluated to a numerical value, a ValueError is raised.
- Returns:
The evaluated matrix representation of the operator.
- Return type:
symengine.Matrix
- Raises:
ValueError – If a parameter cannot be evaluated to a numerical value.
- class mimiqcircuits.Amplitude(bs: BitString)[source]#
Bases:
Operation
Amplitude operation
multi qubit Amplitude operation in the computational basis
The operation projects the quantum states complex variables and stores in a z-register.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(Amplitude(BitString(2)),0) 0-qubit circuit with 1 instructions: └── Amplitude(bs"00") @ z[0]
- property zregsizes#
- class mimiqcircuits.AmplitudeDamping(gamma)[source]#
Bases:
krauschannel
One-qubit amplitude damping noise channel.
The amplitude damping channel is defined by the Kraus operators .. seealso::
GeneralizedAmplitudeDamping()
Kraus Matrices representation:
\[\begin{split}\operatorname E_1 = \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1-\gamma} \end{pmatrix} ,\quad \operatorname E_2 = \begin{pmatrix} 0 & \sqrt{\gamma} \\ 0 & 0 \end{pmatrix},\end{split}\]- Parameters:
gamma –
gamma in [0,1]
.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(AmplitudeDamping(0.1), 0) 1-qubit circuit with 1 instructions: └── AmplitudeDamping(0.1) @ q[0]
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- property opname#
- property parnames#
- class mimiqcircuits.Barrier(*args)[source]#
Bases:
Operation
Barrier operation.
A barrier is a special operation that does not affect the quantum state or the execution of a circuit, but it prevents compression or optimization operation from being applied across it.
Examples
Adding Barrier operation to the Circuit (The args can be: range, list, tuple, set or int)
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Barrier(1), 1) 2-qubit circuit with 1 instructions: └── Barrier @ q[1]
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Barrier(1), range(0,4)) 4-qubit circuit with 4 instructions: ├── Barrier @ q[0] ├── Barrier @ q[1] ├── Barrier @ q[2] └── Barrier @ q[3]
Adding Barrier to the circuit as a multi-qubits gate
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Barrier(5),1,2,3,4,5) 6-qubit circuit with 1 instructions: └── Barrier @ q[1,2,3,4,5]
- class mimiqcircuits.BitString(arg, indices=None)[source]#
Bases:
object
BitString for the quantum states.
Representation of the quantum state of a quantum register with definite values for each qubit.
Examples
Initialization:
>>> from mimiqcircuits import * >>> from bitarray import bitarray >>> BitString(16) # number of qubits bs"0000000000000000" >>> BitString('10101') # binary string bs"10101" >>> BitString([1,0,0,0,1]) # binary string bs"10001" >>> BitString((1,0,0,0,1)) # binary string bs"10001"
>>> BitString(bitarray('101010')) # bitarray bs"101010"
Other initializations:
>>> BitString.fromnonzeros(16, [1, 3, 5, 7, 9, 11, 13, 15]) bs"0101010101010101" >>> BitString.fromfunction(16, lambda i: i % 2 == 1) bs"0101010101010101" >>> BitString.fromstring('10101') bs"10101" >>> BitString.fromint(16, 21) bs"1010100000000000" >>> BitString.fromint(16, 21, 'little') bs"0000000000010101"
Accessing the bits:
>>> bs = BitString(16) >>> bs[0] # get the 0th bit 0 >>> bs[0:4] # get the first 4 bits bs"0000"
Bitwise operations:
>>> bs1 = BitString('10101') >>> bs2 = BitString('11100') >>> bs1 | bs2 # OR bs"11101" >>> bs1 & bs2 # AND bs"10100" >>> bs1 ^ bs2 # XOR bs"01001" >>> ~bs1 # NOT bs"01010" >>> bs1 << 2 # left shift bs"10100" >>> bs1 >> 2 # right shift bs"00101"
Other operations:
>>> bs1 + bs2 # concatenation bs"1010111100" >>> bs1 * 2 # repetition bs"1010110101"
- property bits#
- static fromfunction(num_qubits: int, f: type[~mimiqcircuits.bitstrings.BitString.<lambda>])[source]#
Initialize a BitString from a function.
- Parameters:
num_qubits (int) – The number of qubits in the BitString.
f (function) – A function that takes an integer and returns a boolean.
- Returns:
A BitString.
- static fromint(num_qubits: int, integer: int, endianess: str = 'big')[source]#
Initialize a BitString from an integer.
- Parameters:
num_qubits (int) – The number of qubits in the BitString.
integer (int) – The integer value of the BitString.
endianess (str) – The endianess of the integer. Default is ‘big’.
- Returns:
A BitString.
- static fromnonzeros(num_qubits: int, nonzeros: list)[source]#
Initialize a BitString with specific non-zero qubits.
- Parameters:
num_qubits (int) – The number of qubits in the BitString.
nonzeros (list) – A list of non-zero qubit indices to set in the BitString.
- Returns:
A BitString with the specified non-zero qubits.
- static fromstring(bitstring: str)[source]#
Initialize a BitString from a string.
- Parameters:
bitstring (str) – The string representation of the BitString.
- Returns:
A BitString.
- to01(endianess='big')[source]#
Return the binary string representation of the BitString.
- Parameters:
endianess (str) – The endianess of the integer. Default is ‘big’
- Retruns:
The binary string representation of the BitString.
- toindex(endianess: str = 'big')[source]#
Return the integer index of the BitString.
- Parameters:
endianess (str) – The endianess of the integer. Default is ‘big’.
- Returns:
The integer index of the BitString.
- class mimiqcircuits.BondDim[source]#
Bases:
Operation
Operation to get the bond dimension between two halves of the system and store it in a z-register.
The bond dimension is only defined for a matrix-product state (MPS), which can be written as:
State Representation
\[|\psi \rangle = \sum_{s_1,s_2,\ldots=1}^2 \sum_{i_1}^{\chi_1} \sum_{i_2}^{\chi_2} \ldots \sum_{i_N}^{\chi_N} A^{(s_1)}_{i_0i_1} A^{(s_2)}_{i_1 i_2} A^{(s_3)}_{i_2 i_3} \ldots A^{(s_N)}_{i_{N-1}i_N} | s_1, s_2, s_3, \ldots, s_N \rangle .\]Here, \(\chi_k\) is the bond dimension, i.e., the dimension of the index \(i_k\). The first and last bond dimensions are dummies, \(\chi_0=\chi_N=1\). A bond dimension of 1 means there is no entanglement between the two halves of the system.
See also
Examples
When pushing to a circuit, the qubit index k that we give will return the bond dimension \(i_{k-1}\) in the above notation. In other words, we associate link k with qubit k+1. For k=1, the bond dimension returned will always be 1.
>>> from mimiqcircuits import * >>> k = 5 >>> c = Circuit() >>> c.push(BondDim(), k, 1) 6-qubit circuit with 1 instructions: └── BondDim @ q[5], z[1]
- property num_qubits#
- property parnames#
- class mimiqcircuits.Circuit(instructions=None)[source]#
Bases:
object
Representation of a quantum circuit.
Operation can be added one by one to a circuit with the
c.push(operation, targets...)
function- Parameters:
instructions (list of Instruction) – Instructiuons to add at construction.
- Raises:
TypeError – If initialization list contains non-Instruction objects.
Examples
>>> from mimiqcircuits import * >>> from symengine import pi
Create a new circuit object
>>> c = Circuit()
Add a GateX (Pauli-X) gate on qubit 0
>>> c.push(GateX(), 0) 1-qubit circuit with 1 instructions: └── X @ q[0]
Add a Controlled-NOT (CX) gate with control qubit 0 and target qubit 1
>>> c.push(GateCX(), 0, 1) 2-qubit circuit with 2 instructions: ├── X @ q[0] └── CX @ q[0], q[1]
Add a Parametric GateRX gate with parameters pi/4
>>> c.push(GateRX(pi / 4),0) 2-qubit circuit with 3 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] └── RX((1/4)*pi) @ q[0]
Add a Reset gate on qubit 0
>>> c.push(Reset(), 0) 2-qubit circuit with 4 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] ├── RX((1/4)*pi) @ q[0] └── Reset @ q[0]
Add a Barrier gate on qubits 0 and 1
>>> c.push(Barrier(2), 0, 1) 2-qubit circuit with 5 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] ├── RX((1/4)*pi) @ q[0] ├── Reset @ q[0] └── Barrier @ q[0,1]
Add a Measurement gate on qubit 0, storing the result in bit 0.
>>> c.push(Measure(), 0, 0) 2-qubit circuit with 6 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] ├── RX((1/4)*pi) @ q[0] ├── Reset @ q[0] ├── Barrier @ q[0,1] └── M @ q[0], c[0]
Add a Control gate with GateX as the target gate. The first 3 qubits are the control qubits.
>>> c.push(Control(3, GateX()), 0, 1, 2, 3) 4-qubit circuit with 7 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] ├── RX((1/4)*pi) @ q[0] ├── Reset @ q[0] ├── Barrier @ q[0,1] ├── M @ q[0], c[0] └── C₃X @ q[0,1,2], q[3]
Add a 3-qubit Parallel gate with GateX
>>> c.push(Parallel(3,GateX()),0, 1, 2) 4-qubit circuit with 8 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] ├── RX((1/4)*pi) @ q[0] ├── Reset @ q[0] ├── Barrier @ q[0,1] ├── M @ q[0], c[0] ├── C₃X @ q[0,1,2], q[3] └── ⨷ ³ X @ q[0], q[1], q[2]
To add operations without constructing them first, use the c.emplace(…) function.
Available operations#
Gates
- Single qubit gates
GateX()
GateY()
GateZ()
GateH()
GateS()
GateSDG()
GateT()
GateTDG()
GateSX()
GateSXDG()
GateID()
- Single qubit gates (parametric)
- Two qubit gates
GateCX()
GateCY()
GateCZ()
GateCH()
GateSWAP()
GateISWAP()
GateCS()
GateCSX()
GateECR()
GateDCX()
- Two qubit gates (parametric)
GateCU()
GateCP()
GateCRX()
GateCRY()
GateCRZ()
GateRXX()
GateRYY()
GateRZZ()
GateXXplusYY()
GateXXminusYY()
- Other
- No-ops
- Non-unitary operations
- Composite operations
- Power & Inverse operations
- Generalized gates
- add_noise(g: Operation | List[Operation], kraus: krauschannel | Gate | List[Gate] | List[krauschannel], before: bool | List[bool] = False, parallel: bool | List[bool] = False)[source]#
Adds a noise operation kraus to every instance of the operation g in the circuit.
The noise operation kraus can be a Kraus channel or a gate and will act on the same qubits as the operation g to which it is being added.
The operations g and kraus must act on the same number of qubits.
- Parameters:
g (Operation or list of Operation) – The operation(s) to which the noise will be added.
kraus (krauschannel or list of krauschannel) – The noise operation(s) to be added.
before (bool or list of bool, optional) – If True, the noise is added before the operation. Default is False.
parallel (bool or list of bool, optional) – If True, noise is added as a block. Default is False.
- Raises:
ValueError – If g and kraus are not of the same length, or if their number of qubits differ.
TypeError – If before or parallel are not a bool or a list of bool.
- Returns:
The modified circuit with the noise added.
- Return type:
Examples:
Adding noise sequentially (not parallel):
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(GateH(), [1,2,3]) 4-qubit circuit with 3 instructions: ├── H @ q[1] ├── H @ q[2] └── H @ q[3] >>> c.add_noise(GateH(), AmplitudeDamping(0.2)) 4-qubit circuit with 6 instructions: ├── H @ q[1] ├── AmplitudeDamping(0.2) @ q[1] ├── H @ q[2] ├── AmplitudeDamping(0.2) @ q[2] ├── H @ q[3] └── AmplitudeDamping(0.2) @ q[3]
Adding noise in parallel:
>>> c = Circuit() >>> c.push(GateH(), [1, 2, 3]) 4-qubit circuit with 3 instructions: ├── H @ q[1] ├── H @ q[2] └── H @ q[3] >>> c.add_noise(GateH(), AmplitudeDamping(0.2), parallel=True) 4-qubit circuit with 6 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── AmplitudeDamping(0.2) @ q[1] ├── AmplitudeDamping(0.2) @ q[2] └── AmplitudeDamping(0.2) @ q[3]
Parallel will not work if gates aren’t transversal.
>>> c = Circuit() >>> c.push(GateCZ(), 1, range(2,5)) 5-qubit circuit with 3 instructions: ├── CZ @ q[1], q[2] ├── CZ @ q[1], q[3] └── CZ @ q[1], q[4] >>> c.add_noise(GateCZ(), Depolarizing2(0.1), parallel=True) 5-qubit circuit with 6 instructions: ├── CZ @ q[1], q[2] ├── Depolarizing(0.1) @ q[1,2] ├── CZ @ q[1], q[3] ├── Depolarizing(0.1) @ q[1,3] ├── CZ @ q[1], q[4] └── Depolarizing(0.1) @ q[1,4]
Adding noise before measurement (The before=True option is mostly used for Measure):
>>> c = Circuit() >>> c.push(Measure(), [1, 2, 3], [1, 2, 3]) 4-qubit circuit with 3 instructions: ├── M @ q[1], c[1] ├── M @ q[2], c[2] └── M @ q[3], c[3] >>> c.add_noise(Measure(), PauliX(0.1), before=True) 4-qubit circuit with 6 instructions: ├── PauliX(0.1) @ q[1] ├── M @ q[1], c[1] ├── PauliX(0.1) @ q[2] ├── M @ q[2], c[2] ├── PauliX(0.1) @ q[3] └── M @ q[3], c[3]
Adding unitary gates as noise in the same way:
>>> c = Circuit() >>> c.push(GateH(), [1, 2, 3]) 4-qubit circuit with 3 instructions: ├── H @ q[1] ├── H @ q[2] └── H @ q[3] >>> c.add_noise(GateH(), GateRX(0.01)) 4-qubit circuit with 6 instructions: ├── H @ q[1] ├── RX(0.01) @ q[1] ├── H @ q[2] ├── RX(0.01) @ q[2] ├── H @ q[3] └── RX(0.01) @ q[3]
- add_noise_to_gate_parallel(g, kraus: krauschannel | Gate, before=False)[source]#
Adds a block of noise operations kraus after/before every block of a given operation g.
The function identifies blocks of consecutive transversal operations of type g and adds a block of transversal noise operations kraus after each such block. The noise operation kraus can be a Kraus channel or a gate and will act on the same qubits as the operation g to which it is being added.
- Parameters:
- Raises:
ValueError – If the noise operation is the same as the operation g, to avoid recursion.
See also
add_noise()
: Adds noise to multiple operations at once or in a parallel block.
- add_noise_to_gate_single(g, kraus: krauschannel | Gate, before=False)[source]#
Adds a noise operation kraus before or after every instance of a given operation g.
The noise operation kraus can be a Kraus channel or a gate and will act on the same qubits as the operation g to which it is being added.
- Parameters:
- Raises:
ValueError – If the noise operation is the same as the operation g, to avoid recursion.
See also
add_noise()
: Adds noise to multiple operations at once or in a parallel block.
- append(other)[source]#
Appends all the gates of the given circuit at the end of the current circuit.
- Parameters:
other (Circuit) – the circuit to append.
- decompose()[source]#
Decompose all the gates in the circuit.
If applied multiple times, will reduce the circuit to a basis set of U and CX gates.
- draw()[source]#
Draws the entire quantum circuit on the ASCII canvas and handles the layout of various quantum operations.
This method iterates through all instructions in the circuit, determines the required width for each operation, and delegates the drawing of each operation to the appropriate specialized method based on the operation type. If an operation’s width exceeds the available space in the current row of the canvas, the canvas is printed and reset to continue drawing from a new starting point.
The method manages different operation types including control, measurement, reset, barrier, parallel, and conditional (if) operations using specific drawing methods from the AsciiCircuit class.
- Raises:
TypeError – If any item in the circuit’s instructions is not an instance of Instruction.
ValueError – If an operation cannot be drawn because it exceeds the available canvas width even after a reset.
- Prints:
The current state of the ASCII canvas, either incrementally after each operation if space runs out, or entirely at the end of processing all instructions.
- Returns:
None
- emplace(op, *regs)[source]#
Constructs and adds an Operation to the end of the circuit.
It is useful to add to the circuit operations that are dependent on the number of qubits.
- Parameters:
operation (Type subclass of Operation) – the type of operation to add.
args (vararg of list) – A variable number of arguments compriseing a list of parameters (if the operation is parametric), one list of qubits for each quantum register, and one list of bits of every classical register supported.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.emplace(GateX(), [0]) 1-qubit circuit with 1 instructions: └── X @ q[0] >>> c.emplace(GateRX(0.2), [0]) 1-qubit circuit with 2 instructions: ├── X @ q[0] └── RX(0.2) @ q[0] >>> c.emplace(QFT(), range(10)) 10-qubit circuit with 3 instructions: ├── X @ q[0] ├── RX(0.2) @ q[0] └── QFT @ q[0,1,2,3,4,5,6,7,8,9]
- get_on_qubits(target_qubits)[source]#
Get instructions that involve the specified target qubits.
- Parameters:
target_qubits (list or int) – Qubits for which to retrieve instructions.
- Returns:
A new Circuit containing only the instructions that involve the specified qubits.
- Return type:
- insert(index: int, operation, *args)[source]#
Inserts an operation or another circuit at a specific index in the circuit.
- Parameters:
index (int) – The index at which the operation should be inserted.
operation (Operation or Instruction) – the quantum operation to add.
args (integers or iterables) – Target qubits and bits for the operation (not instruction), given as variable number of arguments.
- Raises:
TypeError – If operation is not an Operation object.
ValueError – If the number of arguments is incorrect or the target qubits specified are invalid.
Examples
Inserting an operation to the specify index of the circuit
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(GateX(), 0) 1-qubit circuit with 1 instructions: └── X @ q[0] >>> c.push(GateCX(),0,1) 2-qubit circuit with 2 instructions: ├── X @ q[0] └── CX @ q[0], q[1] >>> c.insert(1, GateH(), 0) 2-qubit circuit with 3 instructions: ├── X @ q[0] ├── H @ q[0] └── CX @ q[0], q[1]
- is_symbolic()[source]#
Check whether the circuit contains any symbolic (unevaluated) parameters.
This method examines each instruction in the circuit to determine if any parameter remains symbolic (i.e., unevaluated). It recursively checks through each instruction and its nested operations, if any.
- Returns:
True if any parameter is symbolic (unevaluated), False if all parameters are fully evaluated.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> x, y = symbols("x y") >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instructions: └── H @ q[0] >>> c.is_symbolic() False >>> c.push(GateP(x), 0) 1-qubit circuit with 2 instructions: ├── H @ q[0] └── P(x) @ q[0] >>> c.is_symbolic() True >>> c = c.evaluate({x: 1, y: 2}) >>> c 1-qubit circuit with 2 instructions: ├── H @ q[0] └── P(1) @ q[0] >>> c.is_symbolic() False
- static loadproto(file)[source]#
Loads a circuit from a protobuf (binary) file.
- Parameters:
filename (str) – The name of the file to load the circuit from.
- Returns:
The circuit loaded from the file.
- Return type:
Note
Look for example in
Circuit.saveproto()
- push(operation, *args)[source]#
Adds an Operation or an Instruction to the end of the circuit.
- Parameters:
operation (Operation or Instruction) – the quantum operation to add.
args (integers or iterables) – Target qubits and bits for the operation (not instruction), given as variable number of arguments.
- Raises:
TypeError – If operation is not an Operation object.
ValueError – If the number of arguments is incorrect or the target qubits specified are invalid.
Examples
Adding multiple operations to the Circuit (The args can be integers or integer-valued iterables)
>>> from mimiqcircuits import * >>> from symengine import pi >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instructions: └── H @ q[0] >>> c.push(GateT(), 0) 1-qubit circuit with 2 instructions: ├── H @ q[0] └── T @ q[0] >>> c.push(GateH(), [0,2]) 3-qubit circuit with 4 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] └── H @ q[2] >>> c.push(GateS(), 0) 3-qubit circuit with 5 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] ├── H @ q[2] └── S @ q[0] >>> c.push(GateCX(), [2, 0], 1) 3-qubit circuit with 7 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] ├── H @ q[2] ├── S @ q[0] ├── CX @ q[2], q[1] └── CX @ q[0], q[1] >>> c.push(GateH(), 0) 3-qubit circuit with 8 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] ├── H @ q[2] ├── S @ q[0] ├── CX @ q[2], q[1] ├── CX @ q[0], q[1] └── H @ q[0] >>> c.push(Barrier(3), *range(3)) # equivalent to c.push(Barrier(3), 0, 1, 2) 3-qubit circuit with 9 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] ├── H @ q[2] ├── S @ q[0] ├── CX @ q[2], q[1] ├── CX @ q[0], q[1] ├── H @ q[0] └── Barrier @ q[0,1,2] >>> c.push(Measure(), range(3), range(3)) 3-qubit circuit with 12 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] ├── H @ q[2] ├── S @ q[0] ├── CX @ q[2], q[1] ├── CX @ q[0], q[1] ├── H @ q[0] ├── Barrier @ q[0,1,2] ├── M @ q[0], c[0] ├── M @ q[1], c[1] └── M @ q[2], c[2] >>> c 3-qubit circuit with 12 instructions: ├── H @ q[0] ├── T @ q[0] ├── H @ q[0] ├── H @ q[2] ├── S @ q[0] ├── CX @ q[2], q[1] ├── CX @ q[0], q[1] ├── H @ q[0] ├── Barrier @ q[0,1,2] ├── M @ q[0], c[0] ├── M @ q[1], c[1] └── M @ q[2], c[2]
- remove(index: int)[source]#
Removes an instruction at a specific index from the circuit.
- Parameters:
index (int) – The index of the gate to remove.
- Raises:
IndexError – If index is out of range.
- sample_mixedunitaries(rng=None, ids=False)[source]#
sample_mixedunitaries(rng=None, ids=False)
Samples one unitary gate for each mixed unitary Kraus channel in the circuit.
This is possible because for mixed unitary noise channels, the probabilities of each Kraus operator are fixed (state-independent).
Note: This function is internally called (before applying any gate) when executing a circuit with noise using trajectories. It can also be used to generate samples of circuits without running them.
- Parameters:
rng (optional) – Random number generator. If not provided, Python’s default random number generator is used.
ids (optional) – Boolean, default=False. Determines whether to include identity Kraus operators in the sampled circuit. If True, identity gates are added to the circuit; otherwise, they are omitted. Usually, most selected Kraus operators will be identity gates.
- Returns:
A copy of the circuit with every mixed unitary Kraus channel replaced by one of the unitary gates of the channel. Identity gates are omitted unless ids=True.
- Return type:
Examples
Gates and non-mixed-unitary Kraus channels remain unchanged:
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(GateH(), [1, 2, 3]) 4-qubit circuit with 3 instructions: ├── H @ q[1] ├── H @ q[2] └── H @ q[3] >>> c.push(Depolarizing1(0.5), [1, 2, 3]) 4-qubit circuit with 6 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── Depolarizing(0.5) @ q[1] ├── Depolarizing(0.5) @ q[2] └── Depolarizing(0.5) @ q[3] >>> c.push(AmplitudeDamping(0.5), [1, 2, 3]) 4-qubit circuit with 9 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── Depolarizing(0.5) @ q[1] ├── Depolarizing(0.5) @ q[2] ├── Depolarizing(0.5) @ q[3] ├── AmplitudeDamping(0.5) @ q[1] ├── AmplitudeDamping(0.5) @ q[2] └── AmplitudeDamping(0.5) @ q[3]
>>> rng = random.Random(42)
>>> new_circuit = c.sample_mixedunitaries(rng=rng, ids=True) >>> print(new_circuit) 4-qubit circuit with 9 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── X @ q[1] ├── I @ q[2] ├── I @ q[3] ├── AmplitudeDamping(0.5) @ q[1] ├── AmplitudeDamping(0.5) @ q[2] └── AmplitudeDamping(0.5) @ q[3]
By default, identities are not included:
>>> new_circuit = c.sample_mixedunitaries(rng=rng) >>> print(new_circuit) 4-qubit circuit with 8 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── Y @ q[2] ├── Y @ q[3] ├── AmplitudeDamping(0.5) @ q[1] ├── AmplitudeDamping(0.5) @ q[2] └── AmplitudeDamping(0.5) @ q[3]
Different calls to the function generate different results:
>>> new_circuit = c.sample_mixedunitaries(rng=rng) >>> print(new_circuit) 4-qubit circuit with 7 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── Z @ q[1] ├── AmplitudeDamping(0.5) @ q[1] ├── AmplitudeDamping(0.5) @ q[2] └── AmplitudeDamping(0.5) @ q[3]
>>> new_circuit = c.sample_mixedunitaries(rng=rng) >>> print(new_circuit) 4-qubit circuit with 7 instructions: ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── X @ q[3] ├── AmplitudeDamping(0.5) @ q[1] ├── AmplitudeDamping(0.5) @ q[2] └── AmplitudeDamping(0.5) @ q[3]
- saveproto(file)[source]#
Saves the circuit as a protobuf (binary) file.
- Parameters:
filename (str) – The name of the file to save the circuit to.
- Returns:
The number of bytes written to the file.
- Return type:
int
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> import tempfile >>> x, y = symbols("x y") >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instructions: └── H @ q[0] >>> c.push(GateXXplusYY(x**2, y),0,1) 2-qubit circuit with 2 instructions: ├── H @ q[0] └── XXplusYY(x**2, y) @ q[0,1] >>> c.push(Measure(),0,0) 2-qubit circuit with 3 instructions: ├── H @ q[0] ├── XXplusYY(x**2, y) @ q[0,1] └── M @ q[0], c[0] >>> tmpfile = tempfile.NamedTemporaryFile(suffix=".pb", delete=True) >>> c.saveproto(tmpfile.name) 64 >>> c.loadproto(tmpfile.name) 2-qubit circuit with 3 instructions: ├── H @ q[0] ├── XXplusYY(x**2, y) @ q[0,1] └── M @ q[0], c[0]
- Note:
This example uses a temporary file to demonstrate the save and load functionality. You can save your file with any name at any location using:
c.saveproto("example.pb") c.loadproto("example.pb")
- specify_operations()[source]#
Summarizes the types and numbers of operations in the circuit.
This function inspects each instruction in the circuit and categorizes it by the number of qubits, bits, and z-variables involved in the operation. It then prints a summary of the total number of operations in the circuit and a breakdown of the number of operations grouped by their type.
Examples
>>> from mimiqcircuits import * >>> c = Circuit()
Add a Pauli-X (GateX) gate on qubit 0
>>> c.push(GateX(), 0) 1-qubit circuit with 1 instructions: └── X @ q[0]
Add a Controlled-NOT (CX) gate with control qubit 0 and target qubit 1
>>> c.push(GateCX(), 0, 1) 2-qubit circuit with 2 instructions: ├── X @ q[0] └── CX @ q[0], q[1]
Add a Measurement operation on qubit 0, storing the result in bit 0
>>> c.push(Measure(), 0, 0) 2-qubit circuit with 3 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] └── M @ q[0], c[0]
Add an ExpectationValue operation with GateX on qubit 1, storing the result in z-variable 2.
>>> c.push(ExpectationValue(GateX()), 1, 2) 2-qubit circuit with 4 instructions: ├── X @ q[0] ├── CX @ q[0], q[1] ├── M @ q[0], c[0] └── ⟨X⟩ @ q[1], z[2]
Print a summary of the types and numbers of operations
>>> c.specify_operations() Total number of operations: 4 ├── 1 x 1_qubits ├── 1 x 2_qubits ├── 1 x 1_qubits & 1_bits └── 1 x 1_qubits & 1_zvars
- class mimiqcircuits.Control(num_controls, operation, *args, **kwargs)[source]#
Bases:
Gate
Control operation.
A Control is a special operation that applies multi-control gates to the Circuit at once.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(Control(3,GateX()),1,2,3,4) 5-qubit circuit with 1 instructions: └── C₃X @ q[1,2,3], q[4] >>> Control(2, GateX()).matrix() [1.0, 0, 0, 0, 0, 0, 0, 0] [0, 1.0, 0, 0, 0, 0, 0, 0] [0, 0, 1.0, 0, 0, 0, 0, 0] [0, 0, 0, 1.0, 0, 0, 0, 0] [0, 0, 0, 0, 1.0, 0, 0, 0] [0, 0, 0, 0, 0, 1.0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 1.0] [0, 0, 0, 0, 0, 0, 1.0, 0]
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- 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 num_controls#
- property num_targets#
- property op#
- power(*args)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- class mimiqcircuits.Delay(t)[source]#
Bases:
Gate
1-qubit delay gate
This gate is equivalent to a GateID gate, except that it is parametrized by a time parameter t. The parameter does not affect the action of the gate. The only purpose of this gate is to act as a placeholder to indicate idle noise, in which case the parameter t can later be used to further specify the noise properties.
The gate can be created by calling Delay(t) where t is a number.
Matrix representation:
\[\begin{split}\operatorname{Delay}(t) = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}\end{split}\]Examples
>>> Delay(0.3) Delay(0.3)
>>> delay_gate = Delay(0.1) >>> delay_gate.matrix() [1.0, 0] [0, 1.0]
>>> c = Circuit() >>> c.push(delay_gate, 0) 1-qubit circuit with 1 instructions: └── Delay(0.1) @ q[0]
Decomposition
>>> delay_gate = Delay(0.2) >>> delay_gate.decompose() 1-qubit circuit with 1 instructions: └── ID @ q[0]
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- power(_)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- class mimiqcircuits.Depolarizing(N, p)[source]#
Bases:
krauschannel
N-qubit depolarizing noise channel.
The Kraus operators for the depolarizing channel are given by:
\[E_1 = \sqrt{1-p} I_N, \quad E_i = \sqrt{p/(4^N-1)} P_i,\]where \(p \in [0,1]\) is a probability, and \(P_i\) is an \(N\)-qubit Pauli string operator, i.e., a tensor product of one-qubit Pauli operators.
There is exactly one Kraus operator \(E_{i>1}\) for each distinct combination of Pauli operators \(P_i\), except for the \(N\)-qubit identity \(I_N = I \otimes I \otimes I \otimes \dots\).
For example:
For one qubit, we have 3 operators \(P_i \in \{X, Y, Z\}\).
For two qubits, we have 15 operators \(P_i \in \{ I\otimes X, I\otimes Y, I\otimes Z, X\otimes I, Y\otimes I, Z\otimes I, X\otimes X, X\otimes Y, X\otimes Z, Y\otimes X, Y\otimes Y, Y\otimes Z, Z\otimes X, Z\otimes Y, Z\otimes Z \}\).
This channel is a mixed unitary channel (see
ismixedunitary()
), and is a special case ofPauliNoise
.See also
- Parameters:
N (int) – Number of qubits.
p (float) – Probability of error, i.e., the probability of not applying the identity.
Examples
Depolarizing channels can be defined for any number of qubits:
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(Depolarizing(1, 0.1), 1) 2-qubit circuit with 1 instructions: └── Depolarizing(0.1) @ q[1]
>>> c.push(Depolarizing(5, 0.1), 1, 2, 3, 4, 5) 6-qubit circuit with 2 instructions: ├── Depolarizing(0.1) @ q[1] └── Depolarizing(0.1) @ q[1,2,3,4,5]
For one and two qubits, you can use the shorthand notation:
>>> c.push(Depolarizing(1, 0.1), 1) 6-qubit circuit with 3 instructions: ├── Depolarizing(0.1) @ q[1] ├── Depolarizing(0.1) @ q[1,2,3,4,5] └── Depolarizing(0.1) @ q[1]
>>> c.push(Depolarizing(2, 0.1), 1, 2) 6-qubit circuit with 4 instructions: ├── Depolarizing(0.1) @ q[1] ├── Depolarizing(0.1) @ q[1,2,3,4,5] ├── Depolarizing(0.1) @ q[1] └── Depolarizing(0.1) @ q[1,2]
- classmethod ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- property num_qubits#
- property parnames#
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- class mimiqcircuits.Depolarizing1(p)[source]#
Bases:
krauschannel
- class mimiqcircuits.Depolarizing2(p)[source]#
Bases:
krauschannel
- class mimiqcircuits.Detector(*args)[source]#
Bases:
AbstractAnnotation
Detector operation.#
An annotation class representing a detector in a quantum circuit.
The Detector operation monitors the parity of measurement results over N classical bits, where the parity should remain deterministic under ideal, noiseless execution. The Detector ensures that the combined parity (even or odd) of a set of measurement results is consistent. If noise or errors disrupt the circuit, the Detector can identify this through unexpected changes in parity, signaling potential measurement errors. This functionality helps in error detection by revealing inconsistencies caused by disturbances.
Examples
Adding Detector operation to a Circuit (applied to classical bits):
>>> from mimiqcircuits import * >>> op = Detector([0.1,0.9]) >>> op lazy Detector(?, [0.1, 0.9])
Fill the Lazy argument by calling the number of bits
>>> op_filled = op(1) >>> op_filled Detector(0.1, 0.9) >>> op_filled.num_bits 1
Getting the nots
>>> op_filled.get_notes() [0.1, 0.9]
Define a new Operation
>>> op = Detector(1, [0.5, 1.0]) >>> op.get_notes() [0.5, 1.0]
Add to the Circuit
>>> c = Circuit() >>> c.push(Detector(1), 0) 0-qubit circuit with 1 instructions: └── Detector() @ c[0] >>> c.push(Detector(1, [0.5, 1.0]), 1) 0-qubit circuit with 2 instructions: ├── Detector() @ c[0] └── Detector(0.5, 1.0) @ c[1]
- class mimiqcircuits.DiagonalOp(a, b)[source]#
Bases:
AbstractOperator
One-qubit diagonal operator.
The corresponding matrix is given by:
Matrix Representation
\[\begin{split}\begin{pmatrix} a & 0 \\ 0 & b \end{pmatrix}\end{split}\]where a and b are complex numbers.
See also
- Parameters:
a (complex) – The top-left entry of the diagonal matrix.
b (complex) – The bottom-right entry of the diagonal matrix.
Examples
>>> from mimiqcircuits import * >>> op = DiagonalOp(1, 0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(DiagonalOp(1, 0.5)), 1, 2) 2-qubit circuit with 1 instructions: └── ⟨D(1, 0.5)⟩ @ q[1], z[2]
- property parnames#
- class mimiqcircuits.Diffusion(*args)[source]#
Bases:
Gate
Grover’s diffusion operator.
- Parameters:
num_qubits (int) – The number of qubits.
- Raises:
ValueError – If the number of qubits is not an integer or less than 1.
- Returns:
Grover’s diffusion operator.
- Return type:
- num_qubits#
The number of qubits for the diffusion operator.
- Type:
int
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(Diffusion(2), 1, 2) 3-qubit circuit with 1 instructions: └── Diffusion @ q[1,2]
- class mimiqcircuits.ExpectationValue(op: AbstractOperator)[source]#
Bases:
Operation
Operation to compute and store the expectation value of an Operator in a z-register.
An expectation value for a pure state \(| \psi \rangle\) is defined as:
Expectation Value for Pure State
\[\langle O \rangle = \langle \psi | O | \psi \rangle\]where \(O\) is an operator. With respect to a density matrix \(\rho\), it’s given by:
Expectation Value for Density Matrix
\[\langle O \rangle = \mathrm{Tr}(\rho O).\]However, when using quantum trajectories to solve noisy circuits, the expectation value is computed with respect to the pure state of each trajectory.
The argument op can be any gate or non-unitary operator.
Note
ExpectationValue is currently restricted to one and two qubit operators.
See also
Examples
In push!, the first argument corresponds to the qubit, and the second to the z-register.
>>> from mimiqcircuits import * >>> ExpectationValue(GateX()) ⟨X⟩
>>> c = Circuit() >>> c.push(ExpectationValue(GateX()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨X⟩ @ q[1], z[1]
>>> c.push(ExpectationValue(SigmaPlus()), 1, 2) 2-qubit circuit with 2 instructions: ├── ⟨X⟩ @ q[1], z[1] └── ⟨SigmaPlus(1)⟩ @ q[1], z[2]
- property cregsizes#
- property qregsizes#
- property zregsizes#
- class mimiqcircuits.Gate[source]#
Bases:
AbstractOperator
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- 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
- power(*args)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- class mimiqcircuits.GateC3X[source]#
Bases:
Control
Four qubit Controlled-Controlled-Controlled-X gate.
By convention, the first three qubits are the controls and the fourth is the target
Examples
>>> from mimiqcircuits import * >>> GateC3X(), GateC3X().num_controls, GateC3X().num_targets, GateC3X().num_qubits (C₃X, 3, 1, 4) >>> GateC3X().matrix() [1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0] >>> c = Circuit().push(GateC3X(), 0, 1, 2, 3) >>> c 4-qubit circuit with 1 instructions: └── C₃X @ q[0,1,2], q[3] >>> GateC3X().power(2), GateC3X().inverse() (C₃ID, C₃X) >>> GateC3X().decompose() 4-qubit circuit with 31 instructions: ├── H @ q[3] ├── P((1/8)*pi) @ q[0] ├── P((1/8)*pi) @ q[1] ├── P((1/8)*pi) @ q[2] ├── P((1/8)*pi) @ q[3] ├── CX @ q[0], q[1] ├── P((-1/8)*pi) @ q[1] ├── CX @ q[0], q[1] ├── CX @ q[1], q[2] ├── P((-1/8)*pi) @ q[2] ├── CX @ q[0], q[2] ├── P((1/8)*pi) @ q[2] ├── CX @ q[1], q[2] ├── P((-1/8)*pi) @ q[2] ├── CX @ q[0], q[2] ├── CX @ q[2], q[3] ├── P((-1/8)*pi) @ q[3] ├── CX @ q[1], q[3] ├── P((1/8)*pi) @ q[3] ⋮ ⋮ └── H @ q[3]
- class mimiqcircuits.GateCCP(*args, **kwargs)[source]#
Bases:
Control
Three qubit Controlled-Controlled-Phase gate.
By convention, the first two qubits are the controls and the third is the target
- Parameters:
lmbda – Phase angle.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> lmbda = Symbol('lmbda') >>> GateCCP(lmbda), GateCCP(lmbda).num_controls, GateCCP(lmbda).num_targets, GateCCP(lmbda).num_qubits (C₂P(lmbda), 2, 1, 3) >>> GateCCP(lmbda).matrix() [1.0, 0, 0, 0, 0, 0, 0, 0] [0, 1.0, 0, 0, 0, 0, 0, 0] [0, 0, 1.0, 0, 0, 0, 0, 0] [0, 0, 0, 1.0, 0, 0, 0, 0] [0, 0, 0, 0, 1.0, 0, 0, 0] [0, 0, 0, 0, 0, 1.0, 0, 0] [0, 0, 0, 0, 0, 0, 1.0, 0] [0, 0, 0, 0, 0, 0, 0, exp(I*lmbda)] >>> c = Circuit().push(GateCCP(lmbda), 0, 1, 2) >>> c 3-qubit circuit with 1 instructions: └── C₂P(lmbda) @ q[0,1], q[2] >>> GateCCP(lmbda).power(2), GateCCP(lmbda).inverse() (C₂P(2*lmbda), C₂P(-lmbda)) >>> GateCCP(lmbda).decompose() 3-qubit circuit with 5 instructions: ├── CP((1/2)*lmbda) @ q[1], q[2] ├── CX @ q[0], q[1] ├── CP((-1/2)*lmbda) @ q[1], q[2] ├── CX @ q[0], q[1] └── CP((1/2)*lmbda) @ q[0], q[2]
- class mimiqcircuits.GateCCX[source]#
Bases:
Control
Three qubit Controlled-Controlled-X gate.
By convention, the first two qubits are the controls and the third is the target.
Examples
>>> from mimiqcircuits import * >>> GateCCX(), GateCCX().num_controls, GateCCX().num_targets, GateCCX().num_qubits (C₂X, 2, 1, 3) >>> GateCCX().matrix() [1.0, 0, 0, 0, 0, 0, 0, 0] [0, 1.0, 0, 0, 0, 0, 0, 0] [0, 0, 1.0, 0, 0, 0, 0, 0] [0, 0, 0, 1.0, 0, 0, 0, 0] [0, 0, 0, 0, 1.0, 0, 0, 0] [0, 0, 0, 0, 0, 1.0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 1.0] [0, 0, 0, 0, 0, 0, 1.0, 0] >>> c = Circuit().push(GateCCX(), 0, 1, 2) >>> c 3-qubit circuit with 1 instructions: └── C₂X @ q[0,1], q[2] >>> GateCCX().power(2), GateCCX().inverse() (C₂ID, C₂X) >>> GateCCX().decompose() 3-qubit circuit with 15 instructions: ├── H @ q[2] ├── CX @ q[1], q[2] ├── T† @ q[2] ├── CX @ q[0], q[2] ├── T @ q[2] ├── CX @ q[1], q[2] ├── T† @ q[2] ├── CX @ q[0], q[2] ├── T @ q[1] ├── T @ q[2] ├── H @ q[2] ├── CX @ q[0], q[1] ├── T @ q[0] ├── T† @ q[1] └── CX @ q[0], q[1]
- class mimiqcircuits.GateCH[source]#
Bases:
Control
Two qubit Controlled-Hadamard gate.
By convention, the first qubit is the control and the second is the target
Matrix representation:
\[\begin{split}\operatorname{CH} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ 0 & 0 & \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCH(), GateCH().num_controls, GateCH().num_targets, GateCH().num_qubits (CH, 1, 1, 2) >>> GateCH().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 0.707106781186548, 0.707106781186548] [0, 0, 0.707106781186548, -0.707106781186548] >>> c = Circuit().push(GateCH(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CH @ q[0], q[1] >>> GateCH().power(2), GateCH().inverse() (CID, CH) >>> GateCH().decompose() 2-qubit circuit with 7 instructions: ├── S @ q[1] ├── H @ q[1] ├── T @ q[1] ├── CX @ q[0], q[1] ├── T† @ q[1] ├── H @ q[1] └── S† @ q[1]
- class mimiqcircuits.GateCP(*args, **kwargs)[source]#
Bases:
Control
Two qubit Controlled-Phase gate.
By convention, the first qubit is the control and the second is the target
See Also
GateP()
Matrix representation:
\[\begin{split}\operatorname{CP}(\lambda) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i\lambda} \end{pmatrix}\end{split}\]- Parameters:
lambda – Phase angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> lmbda = Symbol('lambda') >>> GateCP(lmbda), GateCP(lmbda).num_controls, GateCP(lmbda).num_targets, GateCP(lmbda).num_qubits (CP(lambda), 1, 1, 2) >>> GateCP(lmbda).matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 1.0, 0] [0, 0, 0, exp(I*lambda)] >>> c = Circuit().push(GateCP(lmbda), 10, 11) >>> c 12-qubit circuit with 1 instructions: └── CP(lambda) @ q[10], q[11] >>> GateCP(lmbda).decompose() 2-qubit circuit with 5 instructions: ├── P((1/2)*lambda) @ q[0] ├── CX @ q[0], q[1] ├── P((-1/2)*lambda) @ q[1] ├── CX @ q[0], q[1] └── P((1/2)*lambda) @ q[1]
- class mimiqcircuits.GateCRX(*args, **kwargs)[source]#
Bases:
Control
Two qubit Controlled-RX gate.
By convention, the first qubit is the control and the second is the target
See Also
GateRX()
,GateCRY()
,GateCRZ()
Matrix representation:
\[\begin{split}\operatorname{CRX}(\theta) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \cos\frac{\theta}{2} & -i\sin\frac{\theta}{2} \\ 0 & 0 & -i\sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{pmatrix}\end{split}\]- Parameters:
theta – The rotation angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateCRZ(theta), GateCRZ(theta).num_controls, GateCRZ(theta).num_targets, GateCRZ(theta).num_qubits (CRZ(theta), 1, 1, 2) >>> GateCRZ(theta).matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, exp(-1/2*I*theta), 0] [0, 0, 0, exp(1/2*I*theta)] >>> c = Circuit().push(GateCRZ(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CRZ(theta) @ q[0], q[1] >>> GateCRZ(theta).power(2), GateCRZ(theta).inverse() (CRZ(2*theta), CRZ(-theta)) >>> GateCRZ(theta).decompose() 2-qubit circuit with 4 instructions: ├── RZ((1/2)*theta) @ q[1] ├── CX @ q[0], q[1] ├── RZ((-1/2)*theta) @ q[1] └── CX @ q[0], q[1]
- class mimiqcircuits.GateCRY(*args, **kwargs)[source]#
Bases:
Control
Two qubit Controlled-RY gate.
By convention, the first qubit is the control and the second is the target
See Also
GateRY()
,GateCRX()
,GateCRZ()
Matrix representation:
\[\begin{split}\operatorname{CRY}(\theta) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \cos\frac{\theta}{2} & -\sin\frac{\theta}{2} \\ 0 & 0 & \sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{pmatrix}\end{split}\]- Parameters:
theta – The rotation angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateCRY(theta), GateCRY(theta).num_controls, GateCRY(theta).num_targets, GateCRY(theta).num_qubits (CRY(theta), 1, 1, 2) >>> GateCRY(theta).matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, cos((1/2)*theta), -sin((1/2)*theta)] [0, 0, sin((1/2)*theta), cos((1/2)*theta)] >>> c = Circuit().push(GateCRY(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CRY(theta) @ q[0], q[1] >>> GateCRY(theta).power(2), GateCRY(theta).inverse() (CRY(2*theta), CRY(-theta)) >>> GateCRY(theta).decompose() 2-qubit circuit with 4 instructions: ├── RY((1/2)*theta) @ q[1] ├── CX @ q[0], q[1] ├── RY((-1/2)*theta) @ q[1] └── CX @ q[0], q[1]
- class mimiqcircuits.GateCRZ(*args, **kwargs)[source]#
Bases:
Control
Two qubit Controlled-RZ gate.
By convention, the first qubit is the control and the second is the target
See Also
GateRZ()
,GateCRX()
,GateCRY()
Matrix representation:
\[\begin{split}\operatorname{CRZ}(\theta) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & e^{-i\frac{\lambda}{2}} & 0 \\ 0 & 0 & 0 & e^{i\frac{\lambda}{2}} \end{pmatrix}\end{split}\]- Parameters:
theta – The rotation angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> lmbda = Symbol('lambda') >>> GateCRZ(lmbda), GateCRZ(lmbda).num_controls, GateCRZ(lmbda).num_targets, GateCRZ(lmbda).num_qubits (CRZ(lambda), 1, 1, 2) >>> GateCRZ(lmbda).matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, exp(-1/2*I*lambda), 0] [0, 0, 0, exp(1/2*I*lambda)] >>> c = Circuit().push(GateCRZ(lmbda), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CRZ(lambda) @ q[0], q[1] >>> GateCRZ(lmbda).power(2), GateCRZ(lmbda).inverse() (CRZ(2*lambda), CRZ(-lambda)) >>> GateCRZ(lmbda).decompose() 2-qubit circuit with 4 instructions: ├── RZ((1/2)*lambda) @ q[1] ├── CX @ q[0], q[1] ├── RZ((-1/2)*lambda) @ q[1] └── CX @ q[0], q[1]
- class mimiqcircuits.GateCS[source]#
Bases:
Control
Two qubit Controlled-S gate.
By convention, the first qubit is the control and the second is the target
See Also
GateS()
Matrix representation::
\[\begin{split}\operatorname{CS} =\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & i \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCS(), GateCS().num_controls, GateCS().num_targets, GateCS().num_qubits (CS, 1, 1, 2) >>> GateCS().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 1.0, 0] [0, 0, 0, 0.0 + 1.0*I] >>> c = Circuit().push(GateCS(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CS @ q[0], q[1] >>> GateCS().power(2), GateCS().inverse() (CZ, CS†) >>> GateCS().decompose() 2-qubit circuit with 1 instructions: └── CP((1/2)*pi) @ q[0], q[1]
- class mimiqcircuits.GateCSDG[source]#
Bases:
Control
Adjoint of two qubit Controlled-S gate.
By convention, the first qubit is the control and the second is the target
Matrix representation:
\[\begin{split}\operatorname{CS}^{\dagger} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & -i \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCSDG(), GateCSDG().num_controls, GateCSDG().num_targets, GateCSDG().num_qubits (CS†, 1, 1, 2) >>> GateCSDG().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 1.0, 0] [0, 0, 0, 6.12323399573677e-17 - 1.0*I] >>> c = Circuit().push(GateCSDG(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CS† @ q[0], q[1] >>> GateCSDG().power(2), GateCSDG().inverse() (C(S†**2), CS) >>> GateCSDG().decompose() 2-qubit circuit with 1 instructions: └── CP((-1/2)*pi) @ q[0], q[1]
- class mimiqcircuits.GateCSWAP[source]#
Bases:
Control
Three qubit Controlled-SWAP gate.
By convention, the first qubit is the control and last two are the targets.
Examples
>>> from mimiqcircuits import * >>> GateCSWAP(), GateCSWAP().num_controls, GateCSWAP().num_targets, GateCSWAP().num_qubits (CSWAP, 1, 2, 3) >>> GateCSWAP().matrix() [1.0, 0, 0, 0, 0, 0, 0, 0] [0, 1.0, 0, 0, 0, 0, 0, 0] [0, 0, 1.0, 0, 0, 0, 0, 0] [0, 0, 0, 1.0, 0, 0, 0, 0] [0, 0, 0, 0, 1.0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 1.0, 0] [0, 0, 0, 0, 0, 1.0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 1.0] >>> c = Circuit().push(GateCSWAP(), 0, 1, 2) >>> GateCSWAP().power(2), GateCSWAP().inverse() (C(⨷ ² ID), CSWAP) >>> c = Circuit().push(GateCSWAP(), 0, 1, 2) >>> c 3-qubit circuit with 1 instructions: └── CSWAP @ q[0], q[1,2] >>> GateCSWAP().power(2), GateCSWAP().inverse() (C(⨷ ² ID), CSWAP) >>> GateCSWAP().decompose() 3-qubit circuit with 3 instructions: ├── CX @ q[2], q[1] ├── C₂X @ q[0,1], q[2] └── CX @ q[2], q[1]
- class mimiqcircuits.GateCSX[source]#
Bases:
Control
Two qubit Controled-SX gate.
By convention, the first qubit is the control and second one is the targets.
Matrix representation:
\[\begin{split}\operatorname{CSX} =\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \frac{1+i}{2} & \frac{1-i}{2} \\ 0 & 0 & \frac{1-i}{2} & \frac{1+i}{2} \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCSX(), GateCSX().num_controls, GateCSX().num_targets, GateCSX().num_qubits (CSX, 1, 1, 2) >>> GateCSX().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 0.5 + 0.5*I, 0.5 - 0.5*I] [0, 0, 0.5 - 0.5*I, 0.5 + 0.5*I] >>> c = Circuit().push(GateCSX(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CSX @ q[0], q[1] >>> GateCSX().power(2), GateCSX().inverse() (CX, CSX†) >>> GateCSX().decompose() 2-qubit circuit with 3 instructions: ├── H @ q[1] ├── CU1((1/2)*pi) @ q[0], q[1] └── H @ q[1]
- class mimiqcircuits.GateCSXDG[source]#
Bases:
Control
Two qubit \({CSX}^\dagger\) gate.
Matrix representation:
\[\begin{split}\operatorname{CSX}^{\dagger} =\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \frac{1-i}{2} & \frac{1+i}{2} \\ 0 & 0 & \frac{1+i}{2} & \frac{1-i}{2} \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCSXDG(), GateCSXDG().num_controls, GateCSXDG().num_targets, GateCSXDG().num_qubits (CSX†, 1, 1, 2) >>> GateCSXDG().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 0.5 - 0.5*I, 0.5 + 0.5*I] [0, 0, 0.5 + 0.5*I, 0.5 - 0.5*I] >>> c = Circuit().push(GateCSXDG(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CSX† @ q[0], q[1] >>> GateCSXDG().power(2), GateCSXDG().inverse() (C(SX†**2), CSX) >>> GateCSXDG().decompose() 2-qubit circuit with 3 instructions: ├── H @ q[1] ├── CU1((-1/2)*pi) @ q[0], q[1] └── H @ q[1]
- class mimiqcircuits.GateCU(*args, **kwargs)[source]#
Bases:
Control
Two qubit controlled unitary gate.
Matrix representation:
\[\begin{split}\operatorname{CU}(\theta, \phi, \lambda, \gamma) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & e^{i\gamma} \cos\left(\frac{\theta}{2}\right) & -e^{i\gamma} e^{i\lambda}\sin\left(\frac{\theta}{2}\right) \\ 0 & 0 & e^{i\gamma} \mathrm{e}^{i\phi}\sin\left(\frac{\theta}{2}\right) & e^{i\gamma} \mathrm{e}^{i(\phi+\lambda)}\cos\left(\frac{\theta}{2}\right) \end{pmatrix}\end{split}\]- Parameters:
theta (float) – Euler angle 1 in radians.
phi (float) – Euler angle 2 in radians.
lmbda (float) – Euler angle 3 in radians.
gamma (float) – Global phase of the CU gate.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta, phi, lmbda, gamma = symbols('theta phi lambda gamma') >>> GateCU(theta, phi, lmbda, gamma), GateCU(theta, phi, lmbda, gamma).num_controls, GateCU(theta, phi, lmbda, gamma).num_targets, GateCU(theta, phi, lmbda, gamma).num_qubits (CU(theta, phi, lambda, gamma), 1, 1, 2) >>> GateCU(theta, phi, lmbda, gamma).matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, exp(I*gamma)*cos((1/2)*theta), -exp(I*(gamma + lambda))*sin((1/2)*theta)] [0, 0, exp(I*(gamma + phi))*sin((1/2)*theta), exp(I*(gamma + lambda + phi))*cos((1/2)*theta)] >>> c = Circuit().push(GateCU(theta, phi, lmbda, gamma), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CU(theta, phi, lambda, gamma) @ q[0], q[1] >>> GateCU(theta, phi, lmbda, gamma).power(2), GateCU(theta, phi, lmbda, gamma).inverse() (C(U(theta, phi, lambda, gamma)**2), CU(-theta, -lambda, -phi, -gamma)) >>> GateCU(theta, phi, lmbda, gamma).decompose() 2-qubit circuit with 7 instructions: ├── P(gamma) @ q[0] ├── P((1/2)*(lambda + phi)) @ q[0] ├── P((1/2)*(lambda - phi)) @ q[1] ├── CX @ q[0], q[1] ├── U((-1/2)*theta, 0, (-1/2)*(lambda + phi), 0.0) @ q[1] ├── CX @ q[0], q[1] └── U((1/2)*theta, phi, 0, 0.0) @ q[1]
- class mimiqcircuits.GateCX[source]#
Bases:
Control
Two qubit Controlled-X gate (or CNOT).
By convention, the first qubit is the control and the second is the target
Matrix representation:
\[\begin{split}\operatorname{CX} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCX(), GateCX().num_controls, GateCX().num_targets (CX, 1, 1) >>> GateCX().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 0, 1.0] [0, 0, 1.0, 0] >>> c = Circuit().push(GateCX(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CX @ q[0], q[1] >>> GateCX().power(2), GateCX().inverse() (CID, CX) >>> GateCX().decompose() 2-qubit circuit with 1 instructions: └── CX @ q[0], q[1]
- class mimiqcircuits.GateCY[source]#
Bases:
Control
Two qubit Controlled-Y gate.
By convention, the first qubit is the control and the second is the target
Matrix representation:
\[\begin{split}\operatorname{CY} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & -i \\ 0 & 0 & i & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCY(), GateCY().num_controls, GateCY().num_targets (CY, 1, 1) >>> GateCY().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 0, -0.0 - 1.0*I] [0, 0, 0.0 + 1.0*I, 0] >>> c = Circuit().push(GateCY(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CY @ q[0], q[1] >>> GateCY().power(2), GateCY().inverse() (CID, CY) >>> GateCY().decompose() 2-qubit circuit with 3 instructions: ├── S† @ q[1] ├── CX @ q[0], q[1] └── S @ q[1]
- class mimiqcircuits.GateCZ[source]#
Bases:
Control
Two qubit Controlled-Z gate.
By convention, the first qubit is the control and the second is the target
Matrix representation:
\[\begin{split}\operatorname{CZ} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & -1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateCZ(), GateCZ().num_controls, GateCZ().num_targets (CZ, 1, 1) >>> GateCZ().matrix() [1.0, 0, 0, 0] [0, 1.0, 0, 0] [0, 0, 1.0, 0] [0, 0, 0, -1.0] >>> c = Circuit().push(GateCZ(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── CZ @ q[0], q[1] >>> GateCZ().power(2), GateCZ().inverse() (CID, CZ) >>> GateCZ().decompose() 2-qubit circuit with 3 instructions: ├── H @ q[1] ├── CX @ q[0], q[1] └── H @ q[1]
- class mimiqcircuits.GateCall(decl: GateDecl, args: Tuple[float, ...])[source]#
Bases:
Gate
- evaluate(d)[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)
- class mimiqcircuits.GateCustom(matrix)[source]#
Bases:
Gate
One or Two qubit Custom gates.
Examples
>>> from mimiqcircuits import Circuit, GateCustom >>> import numpy as np >>> matrix = np.array([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 0, -1j],[0, 0, 1j, 0]]) >>> c = Circuit() >>> c.push(GateCustom(matrix), 0, 1) 2-qubit circuit with 1 instructions: └── Custom([1.0 + 0.0*I, 0.0 + 0.0*I, 0.0 + 0.0*I, 0.0 + 0.0*I]...[0.0 + 0.0*I, 0.0 + 0.0*I, 0.0 + 1.0*I, 0.0 + 0.0*I]) @ q[0,1]
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- property num_qubits#
- class mimiqcircuits.GateDCX[source]#
Bases:
Gate
Two qubit double-CNOT gate.
A two qubit Clifford gate consisting of two back-to-back CNOTs with alternate controls.
Matrix representation:
\[\begin{split}\operatorname{DCX} =\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 1 & 0 & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateDCX() DCX >>> GateDCX().matrix() [1.0, 0, 0, 0] [0, 0, 1.0, 0] [0, 0, 0, 1.0] [0, 1.0, 0, 0] >>> c = Circuit().push(GateDCX(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── DCX @ q[0,1] >>> GateDCX().power(2), GateDCX().inverse() (DCX†, DCX†) >>> GateDCX().decompose() 2-qubit circuit with 2 instructions: ├── CX @ q[0], q[1] └── CX @ q[1], q[0]
- class mimiqcircuits.GateDecl(name: str, arguments: Tuple[str, ...], circuit: Circuit)[source]#
Bases:
object
Simple declaration of gates using the @gatedecl decorator.
Examples
First way
>>> from symengine import symbols >>> from mimiqcircuits import *
Define symbols for the gate arguments
>>> x, y = symbols('x y')
Declare a gate using the @gatedecl decorator
>>> @gatedecl("ansatz") ... def ansatz(x): ... c = Circuit() ... c.push(GateX(), 0) ... c.push(GateRX(x), 1) ... return c
Create a GateDecl object using the decorator
>>> ansatz(x) ansatz(x)
>>> ansatz(y) ansatz(y)
Decompose
>>> ansatz(x).decompose() 2-qubit circuit with 2 instructions: ├── X @ q[0] └── RX(x) @ q[1]
>>> ansatz(2).decompose() 2-qubit circuit with 2 instructions: ├── X @ q[0] └── RX(2) @ q[1]
Second Way
>>> from symengine import * >>> from mimiqcircuits import *
Define symbols for the gate arguments
>>> x, y = symbols('x y')
From a circuit, create a GateDecl object directly
>>> c = Circuit() >>> c.push(GateXXplusYY(x,y), 0,1) 2-qubit circuit with 1 instructions: └── XXplusYY(x, y) @ q[0,1] >>> c.push(GateRX(x), 1) 2-qubit circuit with 2 instructions: ├── XXplusYY(x, y) @ q[0,1] └── RX(x) @ q[1] >>> gate_decl = GateDecl("ansatz", ('x','y'), c) >>> gate_decl gate ansatz(x, y) = ├── XXplusYY(x, y) @ q[0,1] └── RX(x) @ q[1] >>> GateCall(gate_decl, (2,4)) ansatz(2, 4)
Decompose the GateCall into a quantum circuit
>>> GateCall(gate_decl, (2,4)).decompose() 2-qubit circuit with 2 instructions: ├── XXplusYY(2, 4) @ q[0,1] └── RX(2) @ q[1]
Add to Circuit
>>> g = GateCall(gate_decl, (2,4)) >>> c = Circuit() >>> c.push(g,10,22) 23-qubit circuit with 1 instructions: └── ansatz(2, 4) @ q[10,22]
- property num_bits#
- property num_qubits#
- property num_zvars#
- class mimiqcircuits.GateECR[source]#
Bases:
Gate
Two qubit ECR (echo) gate.
Matrix representation:
\[\begin{split}\operatorname{ECR} =\begin{pmatrix} 0 & \frac{1}{\sqrt{2}} & 0 & \frac{i}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & 0 & \frac{-i}{\sqrt{2}} & 0 \\ 0 & \frac{i}{\sqrt{2}} & 0 & \frac{1}{\sqrt{2}} \\ \frac{-i}{\sqrt{2}} & 0 & \frac{1}{\sqrt{2}} & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateECR() ECR >>> GateECR().matrix() [0, 0, 0.707106781186548, 0.0 + 0.707106781186548*I] [0, 0, 0.0 + 0.707106781186548*I, 0.707106781186548] [0.707106781186548, -0.0 - 0.707106781186548*I, 0, 0] [-0.0 - 0.707106781186548*I, 0.707106781186548, 0, 0] >>> c = Circuit().push(GateECR(), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── ECR @ q[0,1] >>> GateECR().power(2), GateECR().inverse() (⨷ ² ID, ECR) >>> GateECR().decompose() 2-qubit circuit with 3 instructions: ├── RZX((1/4)*pi) @ q[0,1] ├── X @ q[0] └── RZX((-1/4)*pi) @ q[0,1]
- class mimiqcircuits.GateH[source]#
Bases:
Gate
Single qubit Hadamard gate.
Matrix representation:
\[\begin{split}\operatorname{H} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateH() H >>> GateH().matrix() [0.707106781186548, 0.707106781186548] [0.707106781186548, -0.707106781186548] >>> c = Circuit().push(GateH(), 0) >>> c 1-qubit circuit with 1 instructions: └── H @ q[0] >>> GateH().power(2), GateH().inverse() (ID, H) >>> GateH().decompose() 1-qubit circuit with 1 instructions: └── U((1/2)*pi, 0, pi, 0.0) @ q[0]
- class mimiqcircuits.GateHXY[source]#
Bases:
Gate
Single qubit HXY gate.
Matrix representation:
\[\begin{split}\operatorname{HXY} = \frac{1}{\sqrt{2}} \begin{pmatrix} 0 & 1 - i \\ 1 + i & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateHXY() HXY >>> GateHXY().matrix() [0, 0.707106781186548 - 0.707106781186548*I] [0.707106781186548 + 0.707106781186548*I, 0] >>> c = Circuit().push(GateHXY(), 0) >>> c 1-qubit circuit with 1 instructions: └── HXY @ q[0] >>> GateHXY().power(2), GateHXY().inverse() (HXY**2, HXY) >>> GateHXY().decompose() 1-qubit circuit with 5 instructions: ├── H @ q[0] ├── Z @ q[0] ├── H @ q[0] ├── S @ q[0] └── U(0, 0, 0, (-1/4)*pi) @ q[0]
- class mimiqcircuits.GateHXZ[source]#
Bases:
Gate
Single qubit HXZ gate (alias for
GateH
).Matrix representation:
\[\begin{split}\operatorname{H} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}\end{split}\]Examples
The HXZ gate behaves exactly like the Hadamard gate:
>>> from mimiqcircuits import * >>> GateHXZ() H >>> GateHXZ().matrix() [0.707106781186548, 0.707106781186548] [0.707106781186548, -0.707106781186548]
Adding GateHXZ to a circuit:
>>> c = Circuit().push(GateHXZ(), 0)
Power and inverse of the gate:
>>> GateHXZ().power(2), GateHXZ().inverse() (ID, H)
Decomposition of the gate:
>>> GateHXZ().decompose() 1-qubit circuit with 1 instructions: └── U((1/2)*pi, 0, pi, 0.0) @ q[0]
- class mimiqcircuits.GateHYZ[source]#
Bases:
Gate
Single qubit HYZ gate.
Matrix representation:
\[\begin{split}\operatorname{HYZ} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & -i \\ i & -1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateHYZ() HYZ >>> GateHYZ().matrix() [0.707106781186548, -0.0 - 0.707106781186548*I] [0.0 + 0.707106781186548*I, -0.707106781186548] >>> c = Circuit().push(GateHYZ(), 0) >>> c 1-qubit circuit with 1 instructions: └── HYZ @ q[0] >>> GateHYZ().power(2), GateHYZ().inverse() (HYZ**2, HYZ) >>> GateHYZ().decompose() 1-qubit circuit with 5 instructions: ├── H @ q[0] ├── S @ q[0] ├── H @ q[0] ├── Z @ q[0] └── U(0, 0, 0, (-1/4)*pi) @ q[0]
- class mimiqcircuits.GateID[source]#
Bases:
Gate
Single qubit Identity gate.
Matrix representation:
\[\begin{split}\operatorname{ID} = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateID() ID >>> GateID().matrix() [1.0, 0] [0, 1.0] >>> c = Circuit().push(GateID(), 0) >>> c 1-qubit circuit with 1 instructions: └── ID @ q[0] >>> GateID().power(2), GateID().inverse() (ID, ID) >>> GateID().decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, 0, 0.0) @ q[0]
- class mimiqcircuits.GateISWAP[source]#
Bases:
Gate
Two qubit ISWAP gate.
See Also
GateISWAPDG()
andGateSWAP()
Matrix representation:
\[\begin{split}\operatorname{ISWAP} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & i & 0 \\ 0 & i & 0 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateISWAP() ISWAP >>> GateISWAP().matrix() [1.0, 0, 0, 0] [0, 0, 0.0 + 1.0*I, 0] [0, 0.0 + 1.0*I, 0, 0] [0, 0, 0, 1.0] >>> c = Circuit().push(GateISWAP(), 0, 1) >>> GateISWAP().power(2), GateISWAP().inverse() (ISWAP**2, ISWAP†) >>> GateISWAP().decompose() 2-qubit circuit with 6 instructions: ├── S @ q[0] ├── S @ q[1] ├── H @ q[0] ├── CX @ q[0], q[1] ├── CX @ q[1], q[0] └── H @ q[1]
- class mimiqcircuits.GateP(lmbda)[source]#
Bases:
Gate
Single qubit Phase gate.
Matrix representation:
\[\begin{split}\operatorname{P}(\lambda) = \operatorname{U}(0,0,\lambda) = \begin{pmatrix} 1 & 0 \\ 0 & \mathrm{e}^{i\lambda} \end{pmatrix}\end{split}\]- Parameters:
lambda – Phase angle
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> lmbda = Symbol('lambda') >>> GateP(lmbda) P(lambda) >>> GateP(lmbda).matrix() [1.0, 0] [0, exp(I*lambda)] >>> c = Circuit().push(GateP(lmbda), 0) >>> c 1-qubit circuit with 1 instructions: └── P(lambda) @ q[0] >>> GateP(lmbda).power(2), GateP(lmbda).inverse() (P(2*lambda), P(-lambda)) >>> GateP(lmbda).decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, lambda, 0.0) @ q[0]
- class mimiqcircuits.GateR(theta, phi)[source]#
Bases:
Gate
Single qubit Rotation gate around the axis \(\cos(\phi)\hat{x} + \sin(\phi)\hat{y}\).
Matrix representation:
\[\begin{split}\operatorname R(\theta,\phi) = \begin{pmatrix} \cos \frac{\theta}{2} & -i e^{-i\phi} \sin \frac{\theta}{2} \\ -i e^{i \phi} \sin \frac{\theta}{2} & \cos \frac{\theta}{2} \end{pmatrix}\end{split}\]- Parameters:
theta (float) – The rotation angle in radians.
phi (float) – The axis of rotation in radians.
Example
>>> from mimiqcircuits import * >>> from symengine import * >>> theta, phi = symbols('theta phi') >>> GateR(theta, phi) R(theta, phi) >>> GateR(theta, phi).matrix() [cos((1/2)*theta), -I*exp(-I*phi)*sin((1/2)*theta)] [-I*exp(I*phi)*sin((1/2)*theta), cos((1/2)*theta)] >>> c = Circuit().push(GateR(theta, phi), 0) >>> GateR(theta, phi).power(2), GateR(theta, phi).inverse() (R(2*theta, phi), R(-theta, phi)) >>> GateR(theta, phi).decompose() 1-qubit circuit with 1 instructions: └── U3(theta, phi + (-1/2)*pi, -phi + (1/2)*pi) @ q[0]
- class mimiqcircuits.GateRX(theta)[source]#
Bases:
Gate
Single qubit Rotation gate around the axis \(\hat{x}\)
Matrix representation:
\[\begin{split}\operatorname{RX}(\theta) = \begin{pmatrix} \cos\frac{\theta}{2} & -i\sin\frac{\theta}{2} \\ -i\sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{pmatrix}\end{split}\]- Parameters:
theta – Rotation angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRX(theta) RX(theta) >>> GateRX(theta).matrix() [cos((1/2)*theta), -I*sin((1/2)*theta)] [-I*sin((1/2)*theta), cos((1/2)*theta)] >>> c = Circuit().push(GateRX(theta), 0) >>> c 1-qubit circuit with 1 instructions: └── RX(theta) @ q[0] >>> GateRX(theta).power(2), GateRX(theta).inverse() (RX(2*theta), RX(-theta)) >>> GateRX(theta).decompose() 1-qubit circuit with 1 instructions: └── U(theta, (-1/2)*pi, (1/2)*pi, 0.0) @ q[0]
- class mimiqcircuits.GateRXX(theta)[source]#
Bases:
Gate
Two qubit RXX gate (rotation about XX).
This gate is symmetric, and is maximally entangling at \((\theta = \frac{\pi}{2})\)
Matrix representation:
\[\begin{split}\operatorname{RXX}(\theta) =\begin{pmatrix} \cos(\frac{\theta}{2}) & 0 & 0 & -i\sin(\frac{\theta}{2}) \\ 0 & \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) & 0 \\ 0 & -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) & 0 \\ -i\sin(\frac{\theta}{2}) & 0 & 0 & \cos(\frac{\theta}{2}) \end{pmatrix}\end{split}\]- Parameters:
theta – The angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRXX(theta) RXX(theta) >>> c = Circuit() >>> c.push(GateRXX(theta), 0, 1) 2-qubit circuit with 1 instructions: └── RXX(theta) @ q[0,1] >>> GateRXX(theta).power(2), GateRXX(theta).inverse() (RXX(theta)**2, RXX(-theta)) >>> GateRXX(theta).matrix() [cos((1/2)*theta), 0, 0, -I*sin((1/2)*theta)] [0, cos((1/2)*theta), -I*sin((1/2)*theta), 0] [0, -I*sin((1/2)*theta), cos((1/2)*theta), 0] [-I*sin((1/2)*theta), 0, 0, cos((1/2)*theta)] >>> GateRXX(theta).decompose() 2-qubit circuit with 7 instructions: ├── H @ q[0] ├── H @ q[1] ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] ├── CX @ q[0], q[1] ├── H @ q[1] └── H @ q[0]
- class mimiqcircuits.GateRY(theta)[source]#
Bases:
Gate
Single qubit Rotation gate around the axis \(\hat{y}\)
Matrix representation:
\[\begin{split}\operatorname{RY}(\theta) = \begin{pmatrix} \cos\frac{\theta}{2} & -\sin\frac{\theta}{2} \\ \sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{pmatrix}\end{split}\]- Parameters:
theta (float) – Rotation angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRY(theta) RY(theta) >>> GateRY(theta).matrix() [cos((1/2)*theta), -sin((1/2)*theta)] [sin((1/2)*theta), cos((1/2)*theta)] >>> c = Circuit().push(GateRY(theta), 0) >>> c 1-qubit circuit with 1 instructions: └── RY(theta) @ q[0] >>> GateRY(theta).power(2), GateRY(theta).inverse() (RY(2*theta), RY(-theta)) >>> GateRY(theta).decompose() 1-qubit circuit with 1 instructions: └── U(theta, 0, 0, 0.0) @ q[0]
- class mimiqcircuits.GateRYY(theta)[source]#
Bases:
Gate
Two qubit RYY gate (rotation about YY).
This gate is symmetric, and is maximally entangling at \((\theta = \frac{\pi}{2})\)
Matrix representation:
\[\begin{split}\operatorname{RYY}(\theta) =\begin{pmatrix} \cos(\frac{\theta}{2}) & 0 & 0 & i\sin(\frac{\theta}{2}) \\ 0 & \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) & 0 \\ 0 & -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) & 0 \\ i\sin(\frac{\theta}{2}) & 0 & 0 & \cos(\frac{\theta}{2}) \end{pmatrix}\end{split}\]- Parameters:
theta (float) – The angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRYY(theta) RYY(theta) >>> GateRYY(theta).matrix() [cos((1/2)*theta), 0, 0, I*sin((1/2)*theta)] [0, cos((1/2)*theta), -I*sin((1/2)*theta), 0] [0, -I*sin((1/2)*theta), cos((1/2)*theta), 0] [I*sin((1/2)*theta), 0, 0, cos((1/2)*theta)] >>> c = Circuit().push(GateRYY(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── RYY(theta) @ q[0,1] >>> GateRYY(theta).power(2), GateRYY(theta).inverse() (RYY(theta)**2, RYY(-theta)) >>> GateRYY(theta).decompose() 2-qubit circuit with 7 instructions: ├── RX((1/2)*pi) @ q[0] ├── RX((1/2)*pi) @ q[1] ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] ├── CX @ q[0], q[1] ├── RX((-1/2)*pi) @ q[0] └── RX((-1/2)*pi) @ q[1]
- class mimiqcircuits.GateRZ(lmbda)[source]#
Bases:
Gate
Single qubit Rotation gate around the axis \(\hat{z}\)
Matrix representation:
\[\begin{split}\operatorname{RZ}(\lambda) = \begin{pmatrix} e^{-i\frac{\lambda}{2}} & 0 \\ 0 & e^{i\frac{\lambda}{2}} \end{pmatrix}\end{split}\]- Parameters:
lambda – Rotation angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> lmbda = Symbol('lambda') >>> GateRZ(lmbda) RZ(lambda) >>> GateRZ(lmbda).matrix() [exp(-1/2*I*lambda), 0] [0, exp(1/2*I*lambda)] >>> c = Circuit().push(GateRZ(lmbda), 0) >>> c 1-qubit circuit with 1 instructions: └── RZ(lambda) @ q[0] >>> GateRZ(lmbda).power(2), GateRZ(lmbda).inverse() (RZ(2*lambda), RZ(-lambda)) >>> GateRZ(lmbda).decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, lambda, (-1/2)*lambda) @ q[0]
- class mimiqcircuits.GateRZX(theta)[source]#
Bases:
Gate
Two qubit RZX gate.
This gate is maximally entangling at \((\theta = \frac{\pi}{2})\)
Matrix representation:
\[\begin{split}\operatorname{RZX}(\theta) =\begin{pmatrix} \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) & 0 & 0 \\ -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) & 0 & 0 \\ 0 & 0 & \cos(\frac{\theta}{2}) & i\sin(\frac{\theta}{2}) \\ 0 & 0 & i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) \end{pmatrix}\end{split}\]- Parameters:
theta (float) – The angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRZX(theta) RZX(theta) >>> GateRZX(theta).matrix() [cos((1/2)*theta), -I*sin((1/2)*theta), 0, 0] [-I*sin((1/2)*theta), cos((1/2)*theta), 0, 0] [0, 0, cos((1/2)*theta), I*sin((1/2)*theta)] [0, 0, I*sin((1/2)*theta), cos((1/2)*theta)] >>> c = Circuit().push(GateRZX(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── RZX(theta) @ q[0,1] >>> GateRZX(theta).power(2), GateRZX(theta).inverse() (RZX(theta)**2, RZX(-theta)) >>> GateRZX(theta).decompose() 2-qubit circuit with 5 instructions: ├── H @ q[1] ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] ├── CX @ q[0], q[1] └── H @ q[1]
- class mimiqcircuits.GateRZZ(theta)[source]#
Bases:
Gate
Two qubit RZZ gate (rotation about ZZ)..
This gate is symmetric, and is maximally entangling at \((\theta = \frac{\pi}{2})\)
Matrix representation:
\[\begin{split}\operatorname{RZZ}(\theta) = \begin{pmatrix} e^{-i\frac{\theta}{2}} & 0 & 0 & 0 \\ 0 & e^{i\frac{\theta}{2}} & 0 & 0 \\ 0 & 0 & e^{i\frac{\theta}{2}} & 0 \\ 0 & 0 & 0 & e^{-i\frac{\theta}{2}} \end{pmatrix}\end{split}\]- Parameters:
theta (float) – The angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRZZ(theta) RZZ(theta) >>> GateRZZ(theta).matrix() [exp(-1/2*I*theta), 0, 0, 0] [0, exp(1/2*I*theta), 0, 0] [0, 0, exp(1/2*I*theta), 0] [0, 0, 0, exp(-1/2*I*theta)] >>> c = Circuit().push(GateRZZ(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── RZZ(theta) @ q[0,1] >>> GateRZZ(theta).power(2), GateRZZ(theta).inverse() (RZZ(theta)**2, RZZ(-theta)) >>> GateRZZ(theta).decompose() 2-qubit circuit with 3 instructions: ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] └── CX @ q[0], q[1]
- class mimiqcircuits.GateS[source]#
Bases:
Power
Single qubit gate S.
It induces a \(\frac{\pi}{2}\) phase gate.
Matrix representation:
\[\begin{split}\operatorname{S} = \begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateS() S >>> GateS().matrix() [1.0, 0] [0, 0.0 + 1.0*I] >>> c = Circuit().push(GateS(), 0) >>> c 1-qubit circuit with 1 instructions: └── S @ q[0] >>> GateS().power(2), GateS().inverse() (Z, S†) >>> GateS().decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, (1/2)*pi, 0.0) @ q[0]
- class mimiqcircuits.GateSDG[source]#
Bases:
Inverse
Single qubit S-dagger gate (conjugate transpose of the S gate).
Matrix representation:
\[\begin{split}\operatorname{S}^\dagger = \begin{pmatrix} 1 & 0 \\ 0 & -i \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateSDG() S† >>> GateSDG().matrix() [1.0, 0] [0, 6.12323399573677e-17 - 1.0*I] >>> c = Circuit().push(GateSDG(), 0) >>> c 1-qubit circuit with 1 instructions: └── S† @ q[0] >>> GateSDG().power(2), GateSDG().inverse() (S†**2, S) >>> GateSDG().decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, (-1/2)*pi, 0.0) @ q[0]
- class mimiqcircuits.GateSWAP[source]#
Bases:
Gate
Two qubit SWAP gate.
See Also
GateISWAP()
Matrix representation:
\[\begin{split}\operatorname{SWAP} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateSWAP() SWAP >>> GateSWAP().matrix() [1.0, 0, 0, 0] [0, 0, 1.0, 0] [0, 1.0, 0, 0] [0, 0, 0, 1.0] >>> c = Circuit().push(GateSWAP(), 0, 1) >>> GateSWAP().power(2), GateSWAP().inverse() (⨷ ² ID, SWAP) >>> GateSWAP().decompose() 2-qubit circuit with 3 instructions: ├── CX @ q[0], q[1] ├── CX @ q[1], q[0] └── CX @ q[0], q[1]
- class mimiqcircuits.GateSX[source]#
Bases:
Power
Single qubit \(\sqrt{X}\) gate.
Matrix representation:
\[\begin{split}\sqrt{\operatorname{X}} = \frac{1}{2} \begin{pmatrix} 1+i & 1-i \\ 1-i & 1+i\\ \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateSX() SX >>> GateSX().matrix() [0.5 + 0.5*I, 0.5 - 0.5*I] [0.5 - 0.5*I, 0.5 + 0.5*I] >>> c = Circuit().push(GateSX(), 0) >>> c 1-qubit circuit with 1 instructions: └── SX @ q[0] >>> GateSX().power(2), GateSX().inverse() (X, SX†) >>> GateSX().decompose() 1-qubit circuit with 4 instructions: ├── S† @ q[0] ├── H @ q[0] ├── S† @ q[0] └── U(0, 0, 0, (1/4)*pi) @ q[0]
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- name = 'SX'#
- class mimiqcircuits.GateSXDG[source]#
Bases:
Inverse
Single qubit \(\sqrt{X}^\dagger\) gate (conjugate transpose of the \(\sqrt{X}\) gate).
Matrix representation:
\[\begin{split}\sqrt{\operatorname{X}}^\dagger = \frac{1}{2} \begin{pmatrix} 1-i & 1+i \\ 1+i & 1-i\\ \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateSXDG() SX† >>> GateSXDG().matrix() [0.5 - 0.5*I, 0.5 + 0.5*I] [0.5 + 0.5*I, 0.5 - 0.5*I] >>> c = Circuit().push(GateSXDG(), 0) >>> c 1-qubit circuit with 1 instructions: └── SX† @ q[0] >>> GateSXDG().power(2), GateSXDG().inverse() (SX†**2, SX) >>> GateSXDG().decompose() 1-qubit circuit with 4 instructions: ├── S @ q[0] ├── H @ q[0] ├── S @ q[0] └── U(0, 0, 0, (-1/4)*pi) @ q[0]
- class mimiqcircuits.GateSY[source]#
Bases:
Power
Single qubit \(\sqrt{Y}\) gate.
Matrix Representation
\[\begin{split}\operatorname{SY} = \sqrt{\operatorname{Y}} = \frac{1}{2} \begin{pmatrix} 1+i & -1-i \\ 1+i & 1+i \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateSY() SY
>>> GateSY().matrix() [0.5 + 0.5*I, -0.5 - 0.5*I] [0.5 + 0.5*I, 0.5 + 0.5*I]
>>> c = Circuit() >>> c.push(GateSY(), 1) 2-qubit circuit with 1 instructions: └── SY @ q[1]
>>> c.push(GateSY(), 2) 3-qubit circuit with 2 instructions: ├── SY @ q[1] └── SY @ q[2]
>>> power(GateSY(), 2) Y**1.0
Decomposition
>>> GateSY().decompose() 1-qubit circuit with 4 instructions: ├── S @ q[0] ├── S @ q[0] ├── H @ q[0] └── U(0, 0, 0, (1/4)*pi) @ q[0]
- class mimiqcircuits.GateSYDG[source]#
Bases:
Inverse
Single qubit \(\sqrt{Y}^\dagger\) gate (conjugate transpose of the \(\sqrt{Y}\) gate).
Matrix Representation
\[\begin{split}\operatorname{SYDG} = \sqrt{\operatorname{Y}}^\dagger = \frac{1}{2} \begin{pmatrix} 1-i & 1-i \\ -1+i & 1-i \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateSYDG() SY†
>>> GateSYDG().matrix() [0.5 - 0.5*I, 0.5 - 0.5*I] [-0.5 + 0.5*I, 0.5 - 0.5*I]
>>> c = Circuit() >>> c.push(GateSYDG(), 1) 2-qubit circuit with 1 instructions: └── SY† @ q[1]
>>> c.push(GateSYDG(), 2) 3-qubit circuit with 2 instructions: ├── SY† @ q[1] └── SY† @ q[2]
>>> power(GateSYDG(), 2) SY†**2
>>> inverse(GateSYDG()) SY
- class mimiqcircuits.GateT[source]#
Bases:
Power
Single qubit T gate.
Matrix representation:
\[\begin{split}\operatorname{T} = \begin{pmatrix} 1 & 0 \\ 0 & \exp\left(\frac{i\pi}{4}\right) \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateT() T >>> GateT().matrix() [1.0, 0] [0, 0.707106781186548 + 0.707106781186548*I] >>> c = Circuit().push(GateT(), 0) >>> c 1-qubit circuit with 1 instructions: └── T @ q[0] >>> GateT().power(2), GateT().inverse() (S, T†) >>> GateT().decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, (1/4)*pi, 0.0) @ q[0]
- class mimiqcircuits.GateTDG[source]#
Bases:
Inverse
Single qubit T-dagger gate (conjugate transpose of the T gate).
Matrix representation:
\[\begin{split}\operatorname{T}^\dagger = \begin{pmatrix} 1 & 0 \\ 0 & \exp\left(\frac{-i\pi}{4}\right) \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateTDG() T† >>> GateTDG().matrix() [1.0, 0] [0, 0.707106781186547 - 0.707106781186547*I] >>> c = Circuit().push(GateTDG(), 0) >>> c 1-qubit circuit with 1 instructions: └── T† @ q[0] >>> GateTDG().power(2), GateTDG().inverse() (T†**2, T) >>> GateTDG().decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, (-1/4)*pi, 0.0) @ q[0]
- class mimiqcircuits.GateU(theta, phi, lmbda, gamma=0.0)[source]#
Bases:
Gate
Single qubit generic unitary phase gate.
Matrix representation:
\[\begin{split}\operatorname{U}(\theta, \phi, \lambda, \gamma) = \mathrm{e}^{i\gamma} \begin{pmatrix} \cos\left(\frac{\theta}{2}\right) & -\mathrm{e}^{i\lambda}\sin\left(\frac{\theta}{2}\right)\\ \mathrm{e}^{i\phi}\sin\left(\frac{\theta}{2}\right) & \mathrm{e}^{i(\phi+\lambda)}\cos\left (\frac{\theta}{2}\right) \end{pmatrix}\end{split}\]- Parameters:
theta (float) – Euler angle 1 in radians.
phi (float) – Euler angle 2 in radians.
lambda (float) – Euler angle 3 in radians.
gamma (float, optional) – Euler angle 4 in radians (default is 0).
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta, phi, lmbda, gamma = symbols('theta phi lambda gamma') >>> GateU(theta, phi, lmbda, gamma) U(theta, phi, lambda, gamma) >>> GateU(theta, phi, lmbda, gamma).matrix() [exp(I*gamma)*cos((1/2)*theta), -exp(I*(gamma + lambda))*sin((1/2)*theta)] [exp(I*(gamma + phi))*sin((1/2)*theta), exp(I*(gamma + lambda + phi))*cos((1/2)*theta)] >>> c = Circuit().push(GateU(theta, phi, lmbda, gamma), 0) >>> c 1-qubit circuit with 1 instructions: └── U(theta, phi, lambda, gamma) @ q[0] >>> GateU(theta, phi, lmbda, gamma).power(2), GateU(theta, phi, lmbda, gamma).inverse() (U(theta, phi, lambda, gamma)**2, U(-theta, -lambda, -phi, -gamma)) >>> GateU(theta, phi, lmbda, gamma).decompose() 1-qubit circuit with 1 instructions: └── U(theta, phi, lambda, gamma) @ q[0] >>> c = Circuit().push(GateU(theta, phi, lmbda, gamma), 0) >>> c 1-qubit circuit with 1 instructions: └── U(theta, phi, lambda, gamma) @ q[0] >>> GateU(theta, phi, lmbda, gamma).power(2), GateU(theta, phi, lmbda, gamma).inverse() (U(theta, phi, lambda, gamma)**2, U(-theta, -lambda, -phi, -gamma)) >>> GateU(theta, phi, lmbda, gamma).decompose() 1-qubit circuit with 1 instructions: └── U(theta, phi, lambda, gamma) @ q[0]
- class mimiqcircuits.GateU1(lmbda)[source]#
Bases:
Gate
Single qubit generic unitary gate \({U_1}\).
Equivalent to
GateP()
Matrix representation:
\[\begin{split}\operatorname{U1}(\lambda) = \begin{pmatrix} 1 & 0 \\ 0 & e^{i\lambda} \end{pmatrix}\end{split}\]- Parameters:
lambda (float) – Euler angle 3 in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> lmbda = Symbol('lambda') >>> GateU1(lmbda) U1(lambda) >>> GateU1(lmbda).matrix() [1.0, 0] [0, exp(I*lambda)] >>> c = Circuit().push(GateU1(lmbda), 0) >>> c 1-qubit circuit with 1 instructions: └── U1(lambda) @ q[0] >>> GateU1(lmbda).power(2), GateU1(lmbda).inverse() (U1(2*lambda), U1(-lambda)) >>> GateU1(lmbda).decompose() 1-qubit circuit with 1 instructions: └── U(0, 0, lambda, 0.0) @ q[0]
- class mimiqcircuits.GateU2(phi, lmbda)[source]#
Bases:
Gate
Single qubit generic unitary gate \({U_2}\).
Matrix representation:
\[\begin{split}\operatorname{U2}(\phi,\lambda) = \frac{1}{\sqrt{2}}e^{-(\phi+\lambda)/2}\begin{pmatrix} 1 & -e^{i\lambda} \\ e^{i\phi} & e^{i(\phi+\lambda)} \end{pmatrix}\end{split}\]- Parameters:
phi – Euler angle in radians.
lambda – Euler angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> phi, lmbda = symbols('phi lambda') >>> GateU2(phi, lmbda) U2(phi, lambda) >>> GateU2(phi, lmbda).matrix() [0.707106781186548, -0.707106781186548*exp(I*lambda)] [0.707106781186548*exp(I*phi), 0.707106781186548*exp(I*(lambda + phi))] >>> c = Circuit().push(GateU2(phi, lmbda), 0) >>> c 1-qubit circuit with 1 instructions: └── U2(phi, lambda) @ q[0] >>> GateU2(phi, lmbda).power(2), GateU2(phi, lmbda).inverse() (U2(phi, lambda)**2, U2(-lambda - pi, -phi + pi)) >>> GateU2(phi, lmbda).decompose() 1-qubit circuit with 1 instructions: └── U((1/2)*pi, phi, lambda, 0.0) @ q[0]
- class mimiqcircuits.GateU3(theta, phi, lmbda)[source]#
Bases:
Gate
Single qubit generic unitary gate \({U_3}\).
This gate is equivalent to
GateU()
up to a global phase, \(\operatorname{U3}(\theta,\phi,\lambda) = e^{-i(\phi + \lambda + \theta)/2} \operatorname{U}(\theta,\phi,\lambda)\)Matrix representation:
\[\begin{split}\operatorname{U3}(\theta,\phi,\lambda) = \frac{1}{2}e^{-i(\phi + \lambda + \theta)/2} \begin{pmatrix} 1 + e^{i\theta} & -i e^{i\lambda}(1 - e^{i\theta}) \\ i e^{i\phi}(1 - e^{i\theta}) & e^{i(\phi + \lambda)}(1 + e^{i\theta}) \end{pmatrix}\end{split}\]- Parameters:
theta – Euler angle 1 in radians.
phi – Euler angle 2 in radians.
lambda – Euler angle 3 in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta, phi, lmbda = symbols('theta phi lambda') >>> GateU3(theta, phi, lmbda) U3(theta, phi, lambda) >>> GateU3(theta, phi, lmbda).matrix() [1.0*cos((1/2)*theta), -exp(I*lambda)*sin((1/2)*theta)] [exp(I*phi)*sin((1/2)*theta), exp(I*(lambda + phi))*cos((1/2)*theta)] >>> c = Circuit().push(GateU3(theta, phi, lmbda), 0) >>> GateU3(theta, phi, lmbda).power(2), GateU3(theta, phi, lmbda).inverse() (U3(theta, phi, lambda)**2, U3(-theta, -lambda, -phi)) >>> GateU3(theta, phi, lmbda).decompose() 1-qubit circuit with 1 instructions: └── U(theta, phi, lambda, 0.0) @ q[0]
- class mimiqcircuits.GateX[source]#
Bases:
Gate
Single qubit Pauli-X gate.
Matrix representation:
\[\begin{split}\operatorname{X} = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateX() X >>> GateX().matrix() [0, 1.0] [1.0, 0] >>> c = Circuit().push(GateX(), 0) >>> c 1-qubit circuit with 1 instructions: └── X @ q[0] >>> GateX().power(2), GateX().inverse() (ID, X) >>> GateX().decompose() 1-qubit circuit with 1 instructions: └── U(pi, 0, pi, 0.0) @ q[0]
- class mimiqcircuits.GateXXminusYY(theta, beta)[source]#
Bases:
Gate
Two qubit parametric GateXXminusYY gate.
Its action is to induce a coherent rotation by some angle between \(\ket{00}\) and \(\ket{11}\)
Matrix representation:
\[\begin{split}\operatorname{(XX-YY)}(\theta, \beta)=\begin{pmatrix} \cos(\frac{\theta}{2}) & 0 & 0 & -i\sin(\frac{\theta}{2})e^{-i\beta} \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ -i\sin(\frac{\theta}{2})e^{i\beta} & 0 & 0 & \cos(\frac{\theta}{2}) \end{pmatrix}\end{split}\]- Parameters:
theta (float) – The angle in radians.
beta (float) – The angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta, beta = symbols('theta beta') >>> GateXXminusYY(theta, beta) XXminusYY(theta, beta) >>> GateXXminusYY(theta, beta).matrix() [cos((1/2)*theta), 0, 0, I*(I*sin(beta) - cos(beta))*sin((1/2)*theta)] [0, 1.0, 0, 0] [0, 0, 1.0, 0] [(sin(beta) - I*cos(beta))*sin((1/2)*theta), 0, 0, cos((1/2)*theta)] >>> c = Circuit().push(GateXXminusYY(theta, beta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── XXminusYY(theta, beta) @ q[0,1] >>> GateXXminusYY(theta, beta).power(2), GateXXminusYY(theta, beta).inverse() (XXminusYY(theta, beta)**2, XXminusYY(-theta, beta)) >>> GateXXminusYY(theta, beta).decompose() 2-qubit circuit with 14 instructions: ├── RZ(-beta) @ q[1] ├── RZ((-1/2)*pi) @ q[0] ├── SX @ q[0] ├── RZ((1/2)*pi) @ q[0] ├── S @ q[1] ├── CX @ q[0], q[1] ├── RY((1/2)*theta) @ q[0] ├── RY((-1/2)*theta) @ q[1] ├── CX @ q[0], q[1] ├── S† @ q[1] ├── RZ((-1/2)*pi) @ q[0] ├── SX† @ q[0] ├── RZ((1/2)*pi) @ q[0] └── RZ(beta) @ q[1]
- class mimiqcircuits.GateXXplusYY(theta, beta)[source]#
Bases:
Gate
Two qubit parametric XXplusYY gate.
Also known as an XY gate. Its action is to induce a coherent rotation by some angle between \(\ket{10}\) and \(\ket{01}\).
Matrix representation:
\[\begin{split}\operatorname{(XX+YY)}(\theta, \beta)= \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2})e^{i\beta} & 0\\ 0 & -i\sin(\frac{\theta}{2})e^{-i\beta} & \cos(\frac{\theta}{2}) & 0\\ 0 & 0 & 0 & 1 \end{pmatrix}\end{split}\]- Parameters:
theta – The angle in radians.
beta – The phase angle in radians.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> theta, beta = symbols('theta beta') >>> GateXXplusYY(theta, beta) XXplusYY(theta, beta) >>> GateXXplusYY(theta, beta).matrix() [1.0, 0, 0, 0] [0, cos((1/2)*theta), (sin(beta) - I*cos(beta))*sin((1/2)*theta), 0] [0, I*(I*sin(beta) - cos(beta))*sin((1/2)*theta), cos((1/2)*theta), 0] [0, 0, 0, 1.0] >>> c = Circuit().push(GateXXplusYY(theta, beta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── XXplusYY(theta, beta) @ q[0,1] >>> GateXXplusYY(theta, beta).power(2), GateXXplusYY(theta, beta).inverse() (XXplusYY(theta, beta)**2, XXplusYY(-theta, beta)) >>> GateXXplusYY(theta, beta).decompose() 2-qubit circuit with 14 instructions: ├── RZ(beta) @ q[0] ├── RZ((-1/2)*pi) @ q[1] ├── SX @ q[1] ├── RZ((1/2)*pi) @ q[1] ├── S @ q[0] ├── CX @ q[1], q[0] ├── RY((-1/2)*theta) @ q[1] ├── RY((-1/2)*theta) @ q[0] ├── CX @ q[1], q[0] ├── S† @ q[0] ├── RZ((-1/2)*pi) @ q[1] ├── SX† @ q[1] ├── RZ((1/2)*pi) @ q[1] └── RZ(-beta) @ q[0]
- class mimiqcircuits.GateY[source]#
Bases:
Gate
Single qubit Pauli-Y gate.
Matrix representation:
\[\begin{split}\operatorname{Y} = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateY() Y >>> GateY().matrix() [0, -0.0 - 1.0*I] [0.0 + 1.0*I, 0] >>> c = Circuit().push(GateY(), 0) >>> GateY().power(2), GateY().inverse() (ID, Y) >>> GateY().decompose() 1-qubit circuit with 1 instructions: └── U(pi, (1/2)*pi, (1/2)*pi, 0.0) @ q[0]
- class mimiqcircuits.GateZ[source]#
Bases:
Gate
Single qubit Pauli-Z gate.
Matrix representation:
\[\begin{split}\operatorname{Z} = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}\end{split}\]Examples
>>> from mimiqcircuits import * >>> GateZ() Z >>> GateZ().matrix() [1.0, 0] [0, -1.0] >>> c = Circuit().push(GateZ(), 0) >>> GateZ().power(2), GateZ().inverse() (ID, Z) >>> GateZ().decompose() 1-qubit circuit with 1 instructions: └── P(pi) @ q[0]
- class mimiqcircuits.GeneralizedAmplitudeDamping(p, gamma)[source]#
Bases:
krauschannel
One-qubit generalized amplitude damping noise channel.
The amplitude generalized damping channel is defined by the Kraus operators.
See also
Kraus Matrices representation:
\[\begin{split}\operatorname E_1 = \sqrt{p} \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1-\gamma} \end{pmatrix} ,\quad \operatorname E_2 = \sqrt{p} \begin{pmatrix} 0 & \sqrt{\gamma} \\ 0 & 0 \end{pmatrix} ,\quad \operatorname E_3 = \sqrt{1-p} \begin{pmatrix} \sqrt{1-\gamma} & 0 \\ 0 & 1 \end{pmatrix} ,\quad \operatorname E_4 = \sqrt{1-p} \begin{pmatrix} 0 & 0 \\ \sqrt{\gamma} & 0 \end{pmatrix},\end{split}\]- Parameters:
gamma –
gamma in [0,1]
.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(GeneralizedAmplitudeDamping(0.1,1), 0) 1-qubit circuit with 1 instructions: └── GeneralizedAmplitudeDamping((0.1, 1)) @ q[0]
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- property num_qubits#
- property parnames#
- class mimiqcircuits.IfStatement(operation, bitstring: BitString)[source]#
Bases:
Operation
Conditional operation
This operation applies a specific operation if a given classical bit condition is met.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(IfStatement(GateX(), BitString('1')), 0, 0) 1-qubit circuit with 1 instructions: └── IF (c==1) X @ q[0], c[0]
- property bitstring#
- property op#
- class mimiqcircuits.Instruction(operation, qubits=None, bits=None, zvars=None)[source]#
Bases:
object
Initializes an instruction of a quantum circuit.
- Parameters:
operation (Operation) – The operation applied by the instruction.
qubits (tuple of int) – The qubits to apply the quantum operation to.
bits (tuple of int) – The classical bits to apply the quantum operation to.
- Raises:
TypeError – If operation is not a subclass of Gate or qubits is not a tuple.
ValueError – If qubits contains less than 1 or more than 2 elements.
Examples
>>> from mimiqcircuits import * >>> Instruction(GateX(),(0,),()) X @ q[0] >>> Instruction(Barrier(4),(0,1,2,3),()) Barrier @ q[0,1,2,3]
- property bits#
- property operation#
- property qubits#
- property zvars#
- class mimiqcircuits.Inverse(operation, *args, **kwargs)[source]#
Bases:
Gate
Inverse of the wrapped quantum operation.
The inversion is not performed right away, but only when the circuit is cached or executed.
Warning
Users should not use Inverse directly but rather the inverse method, which performs all the necessary simplifications (e.g., op.inverse().inverse() == op)
Examples
>>> from mimiqcircuits import * >>> Inverse(GateP(1)).matrix() [1.0, 0] [0, 0.54030230586814 - 0.841470984807897*I] >>> c = Circuit() >>> c.push(Inverse(GateP(1)), 1) 2-qubit circuit with 1 instructions: └── P(1)† @ q[1]
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- 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
- power(*args)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- class mimiqcircuits.Kraus(E: List[MutableDenseMatrix | ndarray | MutableDenseMatrix | AbstractOperator], rtol=1e-12)[source]#
Bases:
krauschannel
Kraus(kmatrices).
Custom N-qubit Kraus channel specified by a list of 2^N x 2^N Kraus matrices.
A Kraus channel is defined by:
\[\mathcal{E}(\rho) = \sum_k E_k \rho E_k^\dagger,\]where \(E_k\) are Kraus matrices that need to fulfill \(\sum_k E_k^\dagger E_k = I\).
If the Kraus matrices are all proportional to unitaries, use
MixedUnitary()
instead.The Kraus matrices are defined in the computational basis in the usual textbook order (the first qubit corresponds to the left-most qubit). For 1 qubit, we have \(|0\rangle\), \(|1\rangle\). For 2 qubits, we have \(|00\rangle\), \(|01\rangle\), \(|10\rangle\), \(|11\rangle\).
Note: Currently, only 1 and 2-qubit custom Kraus channels are supported.
See also
- Parameters:
kmatrices (list) – List of \(2^N \times 2^N\) complex matrices. The number of qubits is equal to \(N\).
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> c = Circuit() >>> c.push(Kraus([Matrix([[1, 0], [0, sqrt(0.9)]]), Matrix([[0, sqrt(0.1)], [0, 0]])]), 0) 1-qubit circuit with 1 instructions: └── Kraus(Operator([[1, 0], [0, 0.948683298050514]]), Operator([[0, 0.316227766016838], [0, 0]])) @ q[0]
Kraus Matrices
>>> g=Kraus([Matrix([[1, 0], [0, sqrt(0.9)]]), Matrix([[0, sqrt(0.1)], [0, 0]])]) >>> g.krausmatrices() [[1.0, 0] [0, 0.948683298050514] , [0, 0.316227766016838] [0, 0] ]
# Example 2: Kraus with Projector0 and Projector1
>>> c = Circuit() >>> c.push(Kraus([Projector0(), Projector1()]), 0) 1-qubit circuit with 1 instructions: └── Kraus(P₀(1), P₁(1)) @ q[0]
# Example 3: Kraus with a matrix and Projector1
>>> c = Circuit() >>> c.push(Kraus([Matrix([[1, 0], [0, 0]]), Projector1()]), 0) 1-qubit circuit with 1 instructions: └── Kraus(Operator([[1, 0], [0, 0]]), P₁(1)) @ q[0]
- evaluate(values: dict)[source]#
Evaluates symbolic parameters in Kraus matrices using a dictionary of values.
- Parameters:
values (dict) – A dictionary where keys are symbolic variables and values are the corresponding numerical values.
- Returns:
A new Kraus instance with evaluated matrices.
- Return type:
- class mimiqcircuits.Measure[source]#
Bases:
AbstractMeasurement
Measure operation.
This operation performs a measurement in the computational basis (Z-basis) and stores the result in a classical register.
The measurement projects the quantum state onto either the \(|0⟩\) or \(|1⟩\) state, corresponding to the classical bit values of 0 and 1, respectively.
Warning
Measure is non-reversible.
Examples
Adding Measure operation to the Circuit (The qubits (first arg) and the bits (second arg) can be: range, list, tuple, set or int)
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Measure(),0,0) 1-qubit circuit with 1 instructions: └── M @ q[0], c[0]
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Measure(), range(0,3), range(0,3)) 3-qubit circuit with 3 instructions: ├── M @ q[0], c[0] ├── M @ q[1], c[1] └── M @ q[2], c[2]
- class mimiqcircuits.MeasureReset[source]#
Bases:
AbstractMeasurement
MeasureReset operation.
This operation measures a qubit q, stores the value in a classical bit c, then applies a X operation to the qubit if the measured value is 1, effectively resetting the qubit to the \(\ket{0}\) state.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(MeasureReset(), 1, 0) 2-qubit circuit with 1 instructions: └── MR @ q[1], c[0] >>> c.decompose() 2-qubit circuit with 2 instructions: ├── M @ q[1], c[0] └── IF (c==1) X @ q[1], c[0]
- class mimiqcircuits.MeasureResetX[source]#
Bases:
AbstractMeasurement
MeasureResetX operation.
The MeasureResetX operation first applies a Hadamard gate (H) to the qubit, performs a measurement and reset operation similar to the MeasureReset operation, and then applies another Hadamard gate. This sequence effectively measures the qubit in the X-basis and resets it to the \(|+>\) state.
See also
MeasureReset
: The standard measurement and reset operation in the Z-basis.MeasureResetY
: Similar operation that measures and resets the qubit in the Y-basis.Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(MeasureResetX(), 1, 0) 2-qubit circuit with 1 instructions: └── MRX @ q[1], c[0] >>> c.decompose() 2-qubit circuit with 3 instructions: ├── H @ q[1] ├── MR @ q[1], c[0] └── H @ q[1]
- class mimiqcircuits.MeasureResetY[source]#
Bases:
AbstractMeasurement
MeasureResetY operation.
The MeasureResetY operation applies (HYZ) gate to the qubit, performs a MeasureReset operation, and then applies another HYZ gate. This sequence effectively measures the qubit in the Y-basis.
See also
MeasureReset
: The standard measurement and reset operation in the Z-basis.MeasureResetX
: Similar operation that measures and resets the qubit in the X-basis.Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(MeasureResetY(), 1, 0) 2-qubit circuit with 1 instructions: └── MRY @ q[1], c[0] >>> c.decompose() 2-qubit circuit with 3 instructions: ├── HYZ @ q[1] ├── MR @ q[1], c[0] └── HYZ @ q[1]
- class mimiqcircuits.MeasureResetZ[source]#
Bases:
AbstractMeasurement
This class acting as an alias for
MeasureReset
.
- class mimiqcircuits.MeasureX[source]#
Bases:
AbstractMeasurement
Single qubit measurement operation in the X-basis.
This operation projects the quantum state onto the X-basis and stores the result of such measurement in a classical register. The measurement is performed by first applying a Hadamard gate to rotate the qubit’s state into the computational basis, performing a standard Z-basis measurement, and then applying another Hadamard gate to return the qubit to its original basis.
Warning
MeasureX is non-reversible.
Examples
>>> from mimiqcircuits import * >>> MeasureX() MX
>>> c = Circuit() >>> c.push(MeasureX(), 2, 1) 3-qubit circuit with 1 instructions: └── MX @ q[2], c[1]
>>> c.push(MeasureX(), 3, 4) 4-qubit circuit with 2 instructions: ├── MX @ q[2], c[1] └── MX @ q[3], c[4]
- class mimiqcircuits.MeasureXX[source]#
Bases:
Operation
MeasureXX operation.
The MeasureXX operation measures the joint parity of two qubits in the X-basis, determining whether the qubits are in the same or different states within this basis. The operation begins by applying a controlled-X (CX) gate between the two qubits to entangle them. Following this, a Hadamard (H) gate is applied to the first qubit, rotating it into the X-basis. The second qubit, designated as the target, is then measured to extract the parity information. After the measurement, the Hadamard gate is applied again to the first qubit to reverse the rotation, and a second controlled-X (CX) gate is applied to disentangle the qubits, restoring the system to its original state. Through this sequence, the MeasureXX operation efficiently captures the parity relationship of the qubits in the X-basis.
A result of 0 indicates that the qubits are in the same state, while a result of 1 indicates that they are in different states.
See also
MeasureZZ
: Measure the joint parity of two qubits in the Z-basis.MeasureYY
: Measure the joint parity of two qubits in the Y-basis.Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(MeasureXX(), 0, 1, 0) 2-qubit circuit with 1 instructions: └── MXX @ q[0,1], c[0] >>> c.decompose() 2-qubit circuit with 5 instructions: ├── CX @ q[0], q[1] ├── H @ q[0] ├── M @ q[1], c[0] ├── H @ q[0] └── CX @ q[0], q[1]
- class mimiqcircuits.MeasureY[source]#
Bases:
AbstractMeasurement
Single qubit measurement operation in the Y-basis.
This operation projects the quantum state onto the Y-basis and stores the result of such measurement in a classical register. The measurement is performed by first applying a \(R_y(\pi/2)\) rotation gate to rotate the qubit’s state into the computational basis, performing a standard Z-basis measurement, and then applying another \(R_y(-\pi/2)\) rotation to return the qubit to its original basis.
Warning
MeasureY is non-reversible.
Examples
>>> from mimiqcircuits import * >>> MeasureY() MY
>>> c = Circuit() >>> c.push(MeasureY(), 2, 1) 3-qubit circuit with 1 instructions: └── MY @ q[2], c[1]
>>> c.push(MeasureY(), 3, 4) 4-qubit circuit with 2 instructions: ├── MY @ q[2], c[1] └── MY @ q[3], c[4]
- class mimiqcircuits.MeasureYY[source]#
Bases:
Operation
MeasureYY operation.
The MeasureYY operation measures the joint parity of two qubits in the Y-basis, determining whether they are in the same or different states in this basis. This is achieved by first applying an S gate (a π/2 phase shift) to both qubits, followed by a controlled-X (CX) gate. A Hadamard gate (H) is then applied to the first qubit, and the second qubit is measured. To restore the system, a Z gate is applied to the first qubit, followed by another Hadamard gate, another CX gate, and finally another S gate to both qubits. The measurement result reflects whether the qubits are in the same or different states in the Y-basis.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(MeasureYY(), 0, 1, 0) 2-qubit circuit with 1 instructions: └── MYY @ q[0,1], c[0] >>> c.decompose() 2-qubit circuit with 10 instructions: ├── S @ q[0] ├── S @ q[1] ├── CX @ q[0], q[1] ├── H @ q[0] ├── M @ q[0], c[0] ├── Z @ q[0] ├── H @ q[0] ├── CX @ q[0], q[1] ├── S @ q[0] └── S @ q[1]
- class mimiqcircuits.MeasureZ[source]#
Bases:
AbstractMeasurement
Single qubit measurement operation in the Z-basis.
This class returns an instance of the
Measure
operation, effectively acting as an alias for Z-basis measurement.Warning
MeasureZ is non-reversible.
Examples
>>> from mimiqcircuits import * >>> MeasureZ() M
>>> c = Circuit() >>> c.push(MeasureZ(), 0, 0) 1-qubit circuit with 1 instructions: └── M @ q[0], c[0]
>>> c.push(MeasureZ(), 1, 2) 2-qubit circuit with 2 instructions: ├── M @ q[0], c[0] └── M @ q[1], c[2]
- class mimiqcircuits.MeasureZZ[source]#
Bases:
Operation
MeasureZZ operation.
The MeasureZZ operation measures the joint parity of two qubits in the Z-basis. This is achieved by applying a controlled-X (CX) gate, measuring the target qubit, and then applying another CX gate to undo the entanglement. The measurement result indicates whether the qubits are in the same or different states in the Z-basis.
See also
MeasureXX
: Measure the joint parity of two qubits in the X-basis.MeasureYY
: Measure the joint parity of two qubits in the Y-basis.Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(MeasureZZ(), 0, 1, 0) 2-qubit circuit with 1 instructions: └── MZZ @ q[0,1], c[0] >>> c.decompose() 2-qubit circuit with 3 instructions: ├── CX @ q[0], q[1] ├── M @ q[1], c[0] └── CX @ q[0], q[1]
- class mimiqcircuits.MimiqConnection(url=None)[source]#
Bases:
MimiqConnection
Represents a connection to the Mimiq Server.
Inherits from: mimiqlink.MimiqConnection python.
- execute(circuits, label='pyapi_v0.15.3', algorithm='auto', nsamples=1000, bitstrings=None, timelimit=None, bonddim=None, entdim=None, seed=None, qasmincludes=None, force=False, **kwargs)[source]#
Execute a circuit or a list of quantum circuits on the Mimiq server.
- Parameters:
circuits (Circuit or list of Circuits or str) – A single Circuit object, a list of Circuit objects, or QASM file paths representing the circuits to be executed.
label (str) – A label for the execution. Defaults to “pyapi_v” + __version__.
algorithm (str) – The algorithm to use. Defaults to “auto”.
nsamples (int) – The number of samples to collect. Defaults to DEFAULT_SAMPLES.
bitstrings (list of str, optional) – Specific bitstrings to measure. Defaults to None.
timelimit (int, optional) – The maximum execution time in minutes. Defaults to None.
bonddim (int, optional) – The bond dimension to use. Defaults to None.
entdim (int, optional) – The entanglement dimension to use. Defaults to None.
seed (int, optional) – A seed for random number generation. Defaults to None.
qasmincludes (list of str, optional) – Additional QASM includes. Defaults to None.
**kwargs – Additional keyword arguments.
- Returns:
A handle to the execution, typically used to retrieve results.
- Return type:
object
- Raises:
ValueError – If nsamples exceeds MAX_SAMPLES, bond/entanglement dimensions are out of bounds, or if a circuit contains unevaluated symbolic parameters.
FileNotFoundError – If a QASM file is not found.
TypeError – If the circuits argument is not a Circuit object or a valid file path.
Note
You can also pass a single QASM file path as a string or a list of QASM file paths instead of Circuit objects. This allows for executing circuits defined in the OpenQASM format directly.
Examples
…
Connecting to server
>>> from mimiqcircuits import * >>> import os >>> conn = MimiqConnection(os.getenv("MIMIQCLOUD2")) >>> conn.connect(os.getenv("MIMIQUSER"), os.getenv("MIMIQPASS")) Connection: ├── url: https://mimiqfast.qperfect.io/api ├── Computing time: 597/10000 minutes ├── Executions: 452/10000 ├── Max time limit per request: 180 minutes └── status: open >>> c = Circuit() >>> c.push(GateH(), range(10)) 10-qubit circuit with 10 instructions: ├── H @ q[0] ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── H @ q[4] ├── H @ q[5] ├── H @ q[6] ├── H @ q[7] ├── H @ q[8] └── H @ q[9] >>> job = conn.execute(c, algorithm="auto") >>> res = conn.get_results(job) >>> res [QCSResults: ├── simulator: MIMIQ-StateVector 0.18.0 ├── timings: │ ├── parse time: 7.3677e-05s │ ├── apply time: 2.4677e-05s │ ├── total time: 0.000306075s │ ├── compression time: 8.103e-06s │ └── sample time: 0.000141276s ├── fidelity estimate: 1 ├── average multi-qubit gate error estimate: 0 ├── most sampled: │ ├── bs"1100000001" => 7 │ ├── bs"1010110100" => 5 │ ├── bs"0010110110" => 4 │ ├── bs"1001010110" => 4 │ └── bs"1001100111" => 4 ├── 1 executions ├── 0 amplitudes └── 1000 samples]
Prepare List of Circuits for execution (Batch-Mode)
>>> c1 = Circuit() >>> c1.push(Control(2, GateH()), 0, 1, 3) 4-qubit circuit with 1 instructions: └── C₂H @ q[0,1], q[3] >>> job = conn.execute([c,c1], algorithm="auto")
List of Results for all Circuits
>>> res = conn.get_results(job) >>> res [QCSResults: ├── simulator: MIMIQ-StateVector 0.18.0 ├── timings: │ ├── parse time: 0.00011103s │ ├── apply time: 2.7497e-05s │ ├── total time: 0.000326494s │ ├── compression time: 8.657e-06s │ └── sample time: 0.000110076s ├── fidelity estimate: 1 ├── average multi-qubit gate error estimate: 0 ├── most sampled: │ ├── bs"1011011100" => 6 │ ├── bs"0110001101" => 4 │ ├── bs"0001011001" => 4 │ ├── bs"1011010010" => 4 │ └── bs"1000000001" => 4 ├── 1 executions ├── 0 amplitudes └── 1000 samples, QCSResults: ├── simulator: MIMIQ-StateVector 0.18.0 ├── timings: │ ├── parse time: 0.081798891s │ ├── apply time: 0.277081657s │ ├── total time: 0.43127283099999997s │ ├── amplitudes time: 1.08e-07s │ ├── compression time: 0.072055493s │ └── sample time: 5.2623e-05s ├── fidelity estimate: 1 ├── average multi-qubit gate error estimate: 0 ├── most sampled: │ └── bs"0000" => 1000 ├── 1 executions ├── 0 amplitudes └── 1000 samples]
Result of the first circuit
>>> res = conn.get_result(job) Warning: Multiple results found. Returning the first one. >>> res QCSResults: ├── simulator: MIMIQ-StateVector 0.18.0 ├── timings: │ ├── parse time: 0.00011103s │ ├── apply time: 2.7497e-05s │ ├── total time: 0.000326494s │ ├── compression time: 8.657e-06s │ └── sample time: 0.000110076s ├── fidelity estimate: 1 ├── average multi-qubit gate error estimate: 0 ├── most sampled: │ ├── bs"1011011100" => 6 │ ├── bs"0110001101" => 4 │ ├── bs"0001011001" => 4 │ ├── bs"1011010010" => 4 │ └── bs"1000000001" => 4 ├── 1 executions ├── 0 amplitudes └── 1000 samples
Input parameters and List of the input Circuits
>>> circs, parameters = conn.get_inputs(job) Downloaded files: ['circuit1.pb', 'circuit2.pb', 'circuits.json', 'request.json'] >>> circs [10-qubit circuit with 10 instructions: ├── H @ q[0] ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── H @ q[4] ├── H @ q[5] ├── H @ q[6] ├── H @ q[7] ├── H @ q[8] └── H @ q[9] , 4-qubit circuit with 1 instructions: └── C₂H @ q[0,1], q[3] ] >>> parameters {'algorithm': 'auto', 'bitstrings': [], 'samples': 1000, 'seed': 1550300089630762344, 'circuits': [{'file': 'circuit1.pb', 'type': 'proto'}, {'file': 'circuit2.pb', 'type': 'proto'}], 'bondDimension': 256, 'entDimension': 16}
Input parameters and first input Circuit
>>> circ, parameters = conn.get_input(job) Downloaded files: ['circuit1.pb', 'circuit2.pb', 'circuits.json', 'request.json'] Warning: Multiple results found. Returning the first one. >>> circ 10-qubit circuit with 10 instructions: ├── H @ q[0] ├── H @ q[1] ├── H @ q[2] ├── H @ q[3] ├── H @ q[4] ├── H @ q[5] ├── H @ q[6] ├── H @ q[7] ├── H @ q[8] └── H @ q[9] >>> parameters {'algorithm': 'auto', 'bitstrings': [], 'samples': 1000, 'seed': 1550300089630762344, 'circuits': [{'file': 'circuit1.pb', 'type': 'proto'}, {'file': 'circuit2.pb', 'type': 'proto'}], 'bondDimension': 256, 'entDimension': 16}
Connecting Using Credentials#
conn = MimiqConnection(url="https://mimiq.qperfect.io/api") conn.connect("Email_address", "Password")
Saving and Loading Tokens#
conn.savetoken("qperfect.json") conn.loadtoken("qperfect.json")
Closing a Connection and Checking Connection Status#
conn.close() conn.isOpen()
- get_input(execution, **kwargs)[source]#
Retrieve the first circuit and parameters of the execution.
- Parameters:
execution (str) – The execution identifier.
- Returns:
A tuple containing the first Circuit object and parameters (dict).
- Return type:
tuple
- Raises:
RuntimeError – If required files are not found in the inputs.
- get_inputs(execution)[source]#
Retrieve the inputs (circuits and parameters) of the execution.
- Parameters:
execution (str) – The execution identifier.
- Returns:
A tuple containing a list of Circuit objects and parameters (dict).
- Return type:
tuple
- Raises:
RuntimeError – If required files are not found in the inputs.
- get_result(execution, **kwargs)[source]#
Retrieve the first result if multiple are found.
- Parameters:
execution (str) – The execution identifier.
**kwargs – Additional keyword arguments for result retrieval.
- Returns:
The first result found.
- Return type:
- Raises:
RuntimeWarning – If multiple results are found.
- get_results(execution, interval=1)[source]#
Retrieve the results of a completed execution.
- Parameters:
execution (str) – The execution identifier.
interval (int) – The interval (in seconds) for checking job status (default: 1).
- Returns:
A list of QCSResults instances.
- Return type:
List[QCSResults]
- Raises:
RuntimeError – If the remote job encounters an error.
- class mimiqcircuits.MixedUnitary(*args)[source]#
Bases:
krauschannel
MixedUnitary(p,umatrices).
Custom N-qubit mixed unitary channel specified by a list of \(2^N \times 2^N\) unitary matrices and a list of probabilities that add up to 1.
A mixed unitary noise channel is defined by:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(0 \leq p_k \leq 1\) and \(U_k\) are unitary matrices. The probabilities must fulfill \(\sum_k p_k = 1\).
If your Kraus matrices are not all proportional to unitaries, use
KrausChannel()
instead.The unitary matrices are defined in the computational basis in the usual textbook order (the first qubit corresponds to the left-most qubit). For 1 qubit, we have \(|0\rangle\), \(|1\rangle\). For 2 qubits, we have \(|00\rangle\), \(|01\rangle\), \(|10\rangle\), \(|11\rangle\).
Note: Currently, only 1 and 2-qubit custom MixedUnitary channels are supported.
See also
- Parameters:
p (list) – List of probabilities, must be positive real numbers and add up to 1.
umatrices (list) – List of complex-valued \(2^N \times 2^N\) matrices. The number of qubits is equal to \(N\).
The length of the lists p and umatrices must be equal.
Examples
>>> from mimiqcircuits import * >>> from symengine import * >>> c = Circuit() >>> c.push(MixedUnitary([0.9, 0.1], [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [1, 0]])]), 0) 1-qubit circuit with 1 instructions: └── MixedUnitary((0.9, "Custom([1 0; 0 1])"),(0.1, "Custom([0 1; 1 0])")) @ q[0]
>>> c.push(MixedUnitary([0.8, 0.2], [Matrix(GateID().matrix()), Matrix(GateRX(0.2).matrix())]), 1) 2-qubit circuit with 2 instructions: ├── MixedUnitary((0.9, "Custom([1 0; 0 1])"),(0.1, "Custom([0 1; 1 0])")) @ q[0] └── MixedUnitary((0.8, "Custom([1.0 0; 0 1.0])"),(0.2, "Custom([0.995004165278026 -0.0 - 0.0998334166468282*I; -0.0 - 0.0998334166468282*I 0.995004165278026])")) @ q[1]
RescaleGate
>>> p1= 0.2 >>> p2 = 0.8 >>> U1 = Matrix([[1, 0], [0, 1]]) # Identity matrix >>> U2 = Matrix([[0, 1], [1, 0]]) # Pauli-X matrix >>> gate1 = GateCustom(U1) >>> gate2 = GateCustom(U2) >>> rescaled_gate1 = RescaledGate(gate1, sqrt(p1)) >>> rescaled_gate2 = RescaledGate(gate2, sqrt(p2)) >>> op = MixedUnitary([rescaled_gate1, rescaled_gate2]) >>> op MixedUnitary((0.2, "Custom([1 0; 0 1])"), (0.8, "Custom([0 1; 1 0])")) >>> c.push(op,1) 2-qubit circuit with 3 instructions: ├── MixedUnitary((0.9, "Custom([1 0; 0 1])"),(0.1, "Custom([0 1; 1 0])")) @ q[0] ├── MixedUnitary((0.8, "Custom([1.0 0; 0 1.0])"),(0.2, "Custom([0.995004165278026 -0.0 - 0.0998334166468282*I; -0.0 - 0.0998334166468282*I 0.995004165278026])")) @ q[1] └── MixedUnitary((0.2, "Custom([1 0; 0 1])"),(0.8, "Custom([0 1; 1 0])")) @ q[1]
- evaluate(values: dict)[source]#
Evaluates symbolic parameters in the MixedUnitary using a dictionary of values.
- Parameters:
values (dict) – A dictionary where keys are symbolic variables and values are the corresponding numerical values.
- Returns:
A new MixedUnitary instance with evaluated parameters.
- Return type:
- classmethod ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- unwrappedkrausmatrices()[source]#
Returns the unitary Kraus matrices associated to the mixed unitary Kraus channel without symbolic wrapper.
See also
Example
>>> from mimiqcircuits import * >>> op = PauliX(0.2) >>> op.unwrappedkrausmatrices() [[0.894427190999916, 0] [0, 0.894427190999916] , [0, 0.447213595499958] [0.447213595499958, 0] ]
- class mimiqcircuits.Not[source]#
Bases:
Operation
Not operation.
Represents a NOT operation that can be added to quantum circuits. This operation inverts a classical bit.
Examples
>>> from mimiqcircuits import * >>> not_op = Not() >>> not_op.name '!' >>> c = Circuit() >>> c.push(Not(), 1) 0-qubit circuit with 1 instructions: └── ! @ c[1]
- class mimiqcircuits.ObservableInclude(*args)[source]#
Bases:
AbstractAnnotation
ObservableInclude operation for including observable index.
An annotation class for adding measurement records to a specified logical observable within a quantum circuit. Observables are sets of measurements expected to produce a deterministic result, used to track specific logical qubit states across operations.
The ObservableInclude class tags a group of measurement records as a logical observable, representing a consistent, predictable result under noiseless conditions. This grouping allows for tracking the state of logical qubits across circuit operations, which is crucial for error correction. Logical observables monitor encoded qubit states by combining multiple measurements, providing robustness against noise and helping to identify any deviations that indicate potential errors.
See also
Examples
Adding ObservableInclude to a circuit:
>>> from mimiqcircuits import * >>> ObservableInclude(2) ObservableInclude() >>> c= Circuit() >>> c.push(ObservableInclude(1), 0) 0-qubit circuit with 1 instructions: └── ObservableInclude() @ c[0]
- class mimiqcircuits.Operation[source]#
Bases:
ABC
Abstract base class for quantum operations.
- property cregsizes#
- property name#
- property num_bits#
- property num_cregs#
- property num_qregs#
- property num_qubits#
- property num_zvars#
- property parnames#
- property qregsizes#
- property zregsizes#
- class mimiqcircuits.Operator(mat)[source]#
Bases:
AbstractOperator
N-qubit operator specified by a \(2^N \times 2^N\) matrix.
Note
Only one and two qubit operators are supported.
This operator does not have to be unitary.
See also
AbstractOperator
,ExpectationValue
,KrausChannel
- Parameters:
matrix (list or np.ndarray) – The \(2^N \times 2^N\) matrix representing the operator.
Examples
>>> from mimiqcircuits import * >>> from symengine import Matrix >>> op = Operator(Matrix([[1, 2], [3, 4]])) >>> op 1-qubit Operator: ├── 1 2 └── 3 4 >>> op = Operator(Matrix([[1, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 1]])) >>> op 2-qubit Operator: ├── 1 0 0 1 ├── 0 0 0 0 ├── 0 0 0 0 └── 1 0 0 1
Operators can be used for expectation values:
>>> c = Circuit() >>> c.push(ExpectationValue(Operator(Matrix([[0, 1], [0, 0]]))), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨Operator([[0, 1], [0, 0]])⟩ @ q[1], z[1]
- property parnames#
Return the parameter names.
- class mimiqcircuits.Parallel(num_repeats, op: Gate)[source]#
Bases:
Gate
Parallel operation
This is a composite operation that applies multiple gates in parallel to the circuit at once.
Examples
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Parallel(3,GateX()),1,2,3) 4-qubit circuit with 1 instructions: └── ⨷ ³ X @ q[1], q[2], q[3]
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- 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 num_repeats#
- property op#
- power(*args)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- class mimiqcircuits.PauliNoise(p: List[float | int], paulistr: List[str])[source]#
Bases:
krauschannel
N-qubit Pauli noise channel specified by a list of probabilities and Pauli gates.
A Pauli channel is defined by:
\[\mathcal{E}(\rho) = \sum_k p_k P_k \rho P_k,\]where \(0 \leq p_k \leq 1\) and \(P_k\) are Pauli string operators, defined as tensor products of one-qubit Pauli operators. The probabilities must fulfill \(\sum_k p_k = 1\).
This channel is a mixed unitary channel (see
ismixedunitary()
).See also
Depolarizing
,PauliX
,PauliY
,PauliZ
, which are special cases of PauliNoise.- Parameters:
p (list) – List of probabilities that must add up to 1.
paulistrings (list) – List of strings, each of length \(N\), with each character being either “I”, “X”, “Y”, or “Z”. The number of qubits is equal to \(N\).
The lengths of p and paulistrings must be the same.
Examples
PauliNoise channels can be defined for any number of qubits, and for any number of Pauli strings:
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(PauliNoise([0.8, 0.1, 0.1], ["I", "X", "Y"]), 1) 2-qubit circuit with 1 instructions: └── PauliNoise((0.8, pauli"I"), (0.1, pauli"X"), (0.1, pauli"Y")) @ q[1]
>>> c.push(PauliNoise([0.9, 0.1], ["XY", "II"]), 1, 2) 3-qubit circuit with 2 instructions: ├── PauliNoise((0.8, pauli"I"), (0.1, pauli"X"), (0.1, pauli"Y")) @ q[1] └── PauliNoise((0.9, pauli"XY"), (0.1, pauli"II")) @ q[1]
>>> c.push(PauliNoise([0.5, 0.2, 0.2, 0.1], ["IXIX", "XYXY", "ZZZZ", "IXYZ"]), 1, 2, 3, 4) 5-qubit circuit with 3 instructions: ├── PauliNoise((0.8, pauli"I"), (0.1, pauli"X"), (0.1, pauli"Y")) @ q[1] ├── PauliNoise((0.9, pauli"XY"), (0.1, pauli"II")) @ q[1] └── PauliNoise((0.5, pauli"IXIX"), (0.2, pauli"XYXY"), (0.2, pauli"ZZZZ"), (0.1, pauli"IXYZ")) @ q[1]
- classmethod ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- property num_qubits#
- property parnames#
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- unwrappedkrausmatrices()[source]#
Returns the unitary Kraus matrices associated to the mixed unitary Kraus channel without symbolic wrapper.
See also
Example
>>> from mimiqcircuits import * >>> op = PauliX(0.2) >>> op.unwrappedkrausmatrices() [[0.894427190999916, 0] [0, 0.894427190999916] , [0, 0.447213595499958] [0.447213595499958, 0] ]
- class mimiqcircuits.PauliString(pauli: str | chr)[source]#
Bases:
Gate
PauliString.
N-qubit tensor product of Pauli operators.
The PauliString gate can represent any N-qubit tensor product of operators of the form P_1 ⊗ P_2 ⊗ P_3 ⊗ … ⊗ P_N, where each P_i ∈ { I, X, Y, Z } is a Pauli operator, including the identity.
This gate can be initialized by passing as argument a string of length N where each element is either ‘I’, ‘X’, ‘Y’, or ‘Z’. For example, PauliString(“IXXYZ”)
Examples
>>> from mimiqcircuits import * >>> g= PauliString("XYZ") >>> g.matrix() [0, 0, 0, 0, 0, 0, -0.0 - 1.0*I, 0] [0, 0, 0, 0, 0, 0, 0, 0.0 + 1.0*I] [0, 0, 0, 0, 0.0 + 1.0*I, 0, 0, 0] [0, 0, 0, 0, 0, -0.0 - 1.0*I, 0, 0] [0, 0, -0.0 - 1.0*I, 0, 0, 0, 0, 0] [0, 0, 0, 0.0 + 1.0*I, 0, 0, 0, 0] [0.0 + 1.0*I, 0, 0, 0, 0, 0, 0, 0] [0, -0.0 - 1.0*I, 0, 0, 0, 0, 0, 0] >>> c= Circuit() >>> c.push(PauliString("XYZ"),0,1,2) 3-qubit circuit with 1 instructions: └── XYZ @ q[0,1,2] >>> c.decompose() 3-qubit circuit with 3 instructions: ├── X @ q[0] ├── Y @ q[1] └── Z @ q[2]
- evaluate(d)[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)
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- property num_qubits#
- property parnames#
- class mimiqcircuits.PauliX(p: float | int)[source]#
Bases:
krauschannel
One-qubit Pauli X noise channel (bit flip error).
This channel is defined by the Kraus operators:
\[E_1 = \sqrt{1-p}\,I, \quad E_2 = \sqrt{p}\,X,\]where \(0 \leq p \leq 1\).
This channel is a mixed unitary channel (see
ismixedunitary()
), and is a special case ofPauliNoise
.PauliX(p) is equivalent to PauliNoise([1-p, p], [“I”, “X”]).
- Parameters:
p (float) – Probability of a bit flip error, must be in the range [0, 1].
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(PauliX(0.1), 1) 2-qubit circuit with 1 instructions: └── PauliX(0.1) @ q[1]
- static ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- class mimiqcircuits.PauliY(p: float | int)[source]#
Bases:
krauschannel
One-qubit Pauli Y noise channel (bit-phase flip error).
This channel is determined by the Kraus operators:
\[E_1 = \sqrt{1-p}\,I, \quad E_2 = \sqrt{p}\,Y,\]where \(0 \leq p \leq 1\).
This channel is a mixed unitary channel (see
ismixedunitary()
), and is a special case ofPauliNoise
.PauliY(p) is equivalent to PauliNoise([1-p, p], [“I”, “Y”]).
- Parameters:
p (float) – Probability of a bit-phase flip error, must be in the range [0, 1].
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(PauliY(0.1), 1) 2-qubit circuit with 1 instructions: └── PauliY(0.1) @ q[1]
- static ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- class mimiqcircuits.PauliZ(p: float | int)[source]#
Bases:
krauschannel
One-qubit Pauli Z noise channel (phase flip error).
This channel is determined by the Kraus operators:
\[E_1 = \sqrt{1-p}\,I, \quad E_2 = \sqrt{p}\,Z,\]where \(0 \leq p \leq 1\).
This channel is a mixed unitary channel (see
ismixedunitary()
), and is a special case ofPauliNoise
.PauliZ(p) is equivalent to PauliNoise([1-p, p], [“I”, “Z”]).
- Parameters:
p (float) – Probability of a phase flip error, must be in the range [0, 1].
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(PauliZ(0.1), 1) 2-qubit circuit with 1 instructions: └── PauliZ(0.1) @ q[1]
- static ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- class mimiqcircuits.PhaseAmplitudeDamping(p: float | int, gamma: float | int, beta: float | int)[source]#
Bases:
krauschannel
One-qubit phase amplitude damping noise channel.
This channel is defined by:
\[\begin{split}\mathcal{E}(\rho) = \begin{pmatrix} (1-\gamma)\rho_{00} + \gamma p & (1-2\beta)\sqrt{1-\gamma}\rho_{01} \\ (1-2\beta)\sqrt{1-\gamma}\rho_{10} & (1-\gamma)\rho_{11} + (1-p)\gamma \end{pmatrix}\end{split}\]Here, \(p, \gamma, \beta \in [0,1]\).
This channel is equivalent to a GeneralizedAmplitudeDamping(p, gamma) channel (see
GeneralizedAmplitudeDamping
), followed by a PauliZ(beta) channel (seePauliZ
).Use
krausmatrices()
to see a Kraus matrix representation of the channel.See also
AmplitudeDamping
,GeneralizedAmplitudeDamping
,ThermalNoise
.- Parameters:
p (float) – Probability parameter, must be in the range [0, 1].
γ (float) – Damping parameter, must be in the range [0, 1].
β (float) – Phase flip parameter, must be in the range [0, 1].
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(PhaseAmplitudeDamping(0.1, 0.2, 0.3), 1) 2-qubit circuit with 1 instructions: └── PhaseAmplitudeDamping(0.1, 0.2, 0.3) @ q[1]
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- property parnames#
- class mimiqcircuits.PhaseGradient(*args)[source]#
Bases:
Gate
Phase Gradient gate
A phase gradient gate applies a phase shift to a quantum register of n qubits, where each computational basis state |k⟩ experiences a phase proportional to its integer value k
- Parameters:
n (int) – The number of qubits in the quantum register.
- Returns:
The PhaseGradient gate.
- Return type:
- name#
The name of the operation.
- Type:
str
- num_qubits#
The number of qubits in the quantum register.
- Type:
int
- qregsizes#
The sizes of the quantum registers.
- Type:
list of int
Examples
>>> from mimiqcircuits import * >>> c=Circuit() >>> c.push(PhaseGradient(2),9,8) 10-qubit circuit with 1 instructions: └── PhaseGradient @ q[9,8]
- class mimiqcircuits.PolynomialOracle(*args)[source]#
Bases:
Gate
Polynomial Oracle.
- Parameters:
a (Num) – Coefficient a in the polynomial.
b (Num) – Coefficient b in the polynomial.
c (Num) – Coefficient c in the polynomial.
d (Num) – Coefficient d in the polynomial.
- Raises:
ValueError – If the input parameters do not satisfy the required conditions.
- Returns:
The Polynomial Oracle.
- Return type:
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(PolynomialOracle(5,5,1, 2, 3, 4), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 11-qubit circuit with 1 instructions: └── PolynomialOracle(1, 2, 3, 4) @ q[1,2,3,4,5], q[6,7,8,9,10]
- class mimiqcircuits.Power(operation, exponent, *args, **kwargs)[source]#
Bases:
Gate
Power operation.
Represents a Power operation raised to a specified exponent.
Examples
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Power(GateX(),1/2),1) 2-qubit circuit with 1 instructions: └── SX @ q[1] >>> c.push(Power(GateX(),5),1) 2-qubit circuit with 2 instructions: ├── SX @ q[1] └── X**5 @ q[1] >>> c.decompose() 2-qubit circuit with 6 instructions: ├── U(1.5707963267948966, -1.570796326794897, 1.5707963267948961, 0.7853981633974482) @ q[1] ├── X @ q[1] ├── X @ q[1] ├── X @ q[1] ├── X @ q[1] └── X @ q[1]
- evaluate(d)[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)
- property exponent#
- inverse()[source]#
Raise an error, as non-unitary operators cannot be inverted.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Raises:
NotImplementedError – If the method is called.
- 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 op#
- power(*args)[source]#
Raise an error, as powers of non-unitary operators are not supported.
This method is not implemented for non-unitary operators and will raise a NotImplementedError if called.
- Parameters:
n (int) – The exponent to which the operator would be raised.
- Raises:
NotImplementedError – If the method is called.
- class mimiqcircuits.ProjectiveNoise(basis)[source]#
Bases:
krauschannel
Single qubit projection noise onto a Pauli basis.
This channel is defined by the Kraus operators:
\[E_1 = |\alpha\rangle \langle\alpha|, \quad E_2 = |\beta\rangle \langle\beta|,\]where the states \(|\alpha\rangle\) and \(|\beta\rangle\) are the +1 and -1 eigenstates of a Pauli operator. Specifically, they correspond to \(\{ |0\rangle, |1\rangle \}\) (Z basis), \(\{ |+\rangle, |-\rangle \}\) (X basis), or \(\{ |y+\rangle, |y-\rangle \}\) (Y basis).
This operation is similar to measuring in the corresponding basis (X, Y, or Z), except that the outcome of the measurement is not stored, i.e., there is a loss of information.
- Parameters:
basis (str) – String or character that selects the Pauli basis, “X”, “Y”, or “Z”.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(ProjectiveNoise("Z"), 1) 2-qubit circuit with 1 instructions: └── ProjectiveNoiseZ @ q[1]
The Kraus matrices are given by:
>>> ProjectiveNoise("X").krausmatrices() [[0.5, 0.5] [0.5, 0.5] , [0.5, -0.5] [-0.5, 0.5] ]
>>> ProjectiveNoise("Y").krausmatrices() [[0.5, -0.0 - 0.5*I] [0.0 + 0.5*I, 0.5] , [0.5, 0.0 + 0.5*I] [-0.0 - 0.5*I, 0.5] ]
>>> ProjectiveNoise("Z").krausmatrices() [[1.0, 0] [0, 0] , [0, 0] [0, 1.0] ]
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- class mimiqcircuits.ProjectiveNoiseX[source]#
Bases:
krauschannel
Single qubit projection noise onto an X Pauli basis.
This channel is defined by the Kraus operators:
\[E_1 = |-\rangle \langle-|, \quad E_2 = |+\rangle \langle+|,\]where \(\ket{+}\) and \(\ket{-}\) are the eigenstates of Pauli X.
- class mimiqcircuits.ProjectiveNoiseY[source]#
Bases:
krauschannel
Single qubit projection noise onto a Y Pauli basis.
This channel is defined by the Kraus operators:
\[E_1 = |Y0\rangle \langle Y0|, \quad E_2 = |Y1\rangle \langle Y1|,\]where \(\ket{Y0}\) and \(\ket{Y1}\) are the eigenstates of Pauli Y.
- class mimiqcircuits.ProjectiveNoiseZ[source]#
Bases:
krauschannel
Single qubit projection noise onto a Z Pauli basis.
This channel is defined by the Kraus operators:
\[E_1 = |0\rangle \langle Z0|, \quad E_2 = |1\rangle \langle Z1|,\]where \(\ket{0}\) and \(\ket{1}\) are the eigenstates of Pauli Z.
- class mimiqcircuits.Projector0(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to a projection onto \(|0\rangle\).
Matrix Representation
\[\begin{split}\begin{pmatrix} a & 0 \\ 0 & 0 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling. Equivalent to
DiagonalOp(a, 0)
.The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – The top-left entry of the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> Projector0() P₀(1)
>>> Projector0(0.5) P₀(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(Projector0()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨P₀(1)⟩ @ q[1], z[1]
- property parnames#
- class mimiqcircuits.Projector00(a=1)[source]#
Bases:
AbstractOperator
Two-qubit operator corresponding to a projection onto \(|00\rangle\).
Matrix Representation
\[\begin{split}\begin{pmatrix} a & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> Projector00() P₀₀(1)
>>> Projector00(0.5) P₀₀(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(Projector00()), 1, 2, 1) 3-qubit circuit with 1 instructions: └── ⟨P₀₀(1)⟩ @ q[1,2], z[1]
- property parnames#
- class mimiqcircuits.Projector01(a=1)[source]#
Bases:
AbstractOperator
Two-qubit operator corresponding to a projection onto \(|01\rangle\).
Matrix Representation
\[\begin{split}\begin{pmatrix} 0 & 0 & 0 & 0\\ 0 & a & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> Projector01() P₀₁(1)
>>> Projector01(0.5) P₀₁(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(Projector01()), 1, 2, 1) 3-qubit circuit with 1 instructions: └── ⟨P₀₁(1)⟩ @ q[1,2], z[1]
- property parnames#
- class mimiqcircuits.Projector1(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to a projection onto \(|1\rangle\).
Matrix Representation
\[\begin{split}\begin{pmatrix} 0 & 0 \\ 0 & a \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling. Equivalent to
DiagonalOp(0, a)
.The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – The bottom-right entry of the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> Projector1() P₁(1)
>>> Projector1(0.5) P₁(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(Projector1()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨P₁(1)⟩ @ q[1], z[1]
- property parnames#
- class mimiqcircuits.Projector10(a=1)[source]#
Bases:
AbstractOperator
Two-qubit operator corresponding to a projection onto \(|10\rangle\).
Matrix Representation
\[\begin{split}\begin{pmatrix} 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & a & 0\\ 0 & 0 & 0 & 0 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> Projector10() P₁₀(1)
>>> Projector10(0.5) P₁₀(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(Projector10()), 1, 2, 1) 3-qubit circuit with 1 instructions: └── ⟨P₁₀(1)⟩ @ q[1,2], z[1]
- property parnames#
- class mimiqcircuits.Projector11(a=1)[source]#
Bases:
AbstractOperator
Two-qubit operator corresponding to a projection onto \(|11\rangle\).
Matrix Representation
\[\begin{split}\begin{pmatrix} 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & a \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> Projector11() P₁₁(1)
>>> Projector11(0.5) P₁₁(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(Projector11()), 1, 2, 1) 3-qubit circuit with 1 instructions: └── ⟨P₁₁(1)⟩ @ q[1,2], z[1]
- property parnames#
- class mimiqcircuits.ProjectorX0(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to a projection onto \(|+\rangle\).
Matrix Representation
\[\begin{split}\frac{a}{2} \begin{pmatrix} 1 & 1 \\ 1 & 1 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> ProjectorX0() PX₀(1)
>>> ProjectorX0(0.5) PX₀(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(ProjectorX0()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨PX₀(1)⟩ @ q[1], z[1]
- property parnames#
- class mimiqcircuits.ProjectorX1(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to a projection onto \(|-\rangle\).
Matrix Representation
\[\begin{split}\frac{a}{2} \begin{pmatrix} 1 & -1 \\ -1 & 1 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> ProjectorX1() PX₁(1)
>>> ProjectorX1(0.5) PX₁(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(ProjectorX1()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨PX₁(1)⟩ @ q[1], z[1]
- property parnames#
- class mimiqcircuits.ProjectorY0(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to a projection onto \(|y+\rangle\).
Matrix Representation
\[\begin{split}\frac{a}{2} \begin{pmatrix} 1 & -i \\ i & 1 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> ProjectorY0() PY₀(1)
>>> ProjectorY0(0.5) PY₀(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(ProjectorY0()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨PY₀(1)⟩ @ q[1], z[1]
- property parnames#
- class mimiqcircuits.ProjectorY1(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to a projection onto \(|y-\rangle\).
Matrix Representation
\[\begin{split}\frac{a}{2} \begin{pmatrix} 1 & i \\ -i & 1 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> ProjectorY1() PY₁(1)
>>> ProjectorY1(0.5) PY₁(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(ProjectorY1()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨PY₁(1)⟩ @ q[1], z[1]
- property parnames#
- class mimiqcircuits.ProjectorZ0[source]#
Bases:
AbstractOperator
Alias for
Projector0
- class mimiqcircuits.ProjectorZ1[source]#
Bases:
AbstractOperator
Alias for
Projector1
- class mimiqcircuits.QCSResults(simulator=None, version=None, fidelities=None, avggateerrors=None, cstates=None, zstates=None, amplitudes=None, timings=None)[source]#
Bases:
object
Represents the results of quantum computations obtained from quantum cloud services (QCS).
- Parameters:
simulator (str) – The name of the quantum simulator.
version (str) – The version of the quantum simulator.
fidelities (list) – List of fidelity estimates from different executions.
avggateerrors (list) – List of average multi-qubit gate errors from different executions.
cstates (list) – List of classical states obtained from executions.
zstates (list) – Not used in the current implementation.
amplitudes (dict) – Dictionary of statevector amplitudes for different quantum states.
timings (dict) – Dictionary of timing information for different phases of the computation.
- histogram()[source]#
Histogram of the obtained classical states’ occurrences.
- Returns:
A dictionary of classical states (bitarray) and their occurrences (float).
- Raises:
TypeError – If a non QCSResults object is passed.
- static loadproto(file)[source]#
Load QCSResults object from a Protocol Buffers file.
The
loadproto()
method is a static method and should be called on the class, not on an instance of the class.Note
Look for example in
QCSResults.saveproto()
- saveproto(file)[source]#
Save QCSResults object to a Protocol Buffers file.
Examples
>>> from mimiqcircuits import * >>> import os >>> from symengine import * >>> import tempfile >>> x, y = symbols("x y") >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instructions: └── H @ q[0] >>> conn = MimiqConnection(os.getenv("MIMIQCLOUD2")) >>> conn.connect(os.getenv("MIMIQUSER"), os.getenv("MIMIQPASS")) Connection: ├── url: https://mimiqfast.qperfect.io/api ├── Computing time: 597/10000 minutes ├── Executions: 451/10000 ├── Max time limit per request: 180 minutes └── status: open >>> job = conn.execute(c) >>> res = conn.get_result(job) >>> res QCSResults: ├── simulator: MIMIQ-StateVector 0.18.0 ├── timings: │ ├── parse time: 5.9552e-05s │ ├── apply time: 1.6682e-05s │ ├── total time: 0.00019081399999999998s │ ├── compression time: 4.575e-06s │ └── sample time: 5.299e-05s ├── fidelity estimate: 1 ├── average multi-qubit gate error estimate: 0 ├── most sampled: │ ├── bs"1" => 513 │ └── bs"0" => 487 ├── 1 executions ├── 0 amplitudes └── 1000 samples
>>> tmpfile = tempfile.NamedTemporaryFile(suffix=".pb", delete=True) >>> res.saveproto(tmpfile.name) 7169 >>> res.loadproto(tmpfile.name) QCSResults: ├── simulator: MIMIQ-StateVector 0.18.0 ├── timings: │ ├── parse time: 5.9552e-05s │ ├── apply time: 1.6682e-05s │ ├── total time: 0.00019081399999999998s │ ├── compression time: 4.575e-06s │ └── sample time: 5.299e-05s ├── fidelity estimate: 1 ├── average multi-qubit gate error estimate: 0 ├── most sampled: │ ├── bs"1" => 513 │ └── bs"0" => 487 ├── 1 executions ├── 0 amplitudes └── 1000 samples
- Note:
This example uses a temporary file to demonstrate the save and load functionality. You can save your file with any name at any location using:
res.saveproto("example.pb") res.loadproto("example.pb")
- class mimiqcircuits.QFT(*args)[source]#
Bases:
Gate
Quantum Fourier transform.
Performs the quantum Fourier transform on a register of n qubits.
- Parameters:
n (int) – The number of qubits in the quantum register.
- Raises:
ValueError – If the number of qubits is less than 1.
- Returns:
The Quantum Fourier Transform operation.
- Return type:
- name#
The name of the operation.
- Type:
str
- num_qubits#
The number of qubits in the quantum register.
- Type:
int
- qregsizes#
The sizes of the quantum registers.
- Type:
list of int
Examples
>>> from mimiqcircuits import * >>> c=Circuit() >>> c.push(QFT(2),1,2) 3-qubit circuit with 1 instructions: └── QFT @ q[1,2]
- class mimiqcircuits.QubitCoordinates(*args)[source]#
Bases:
AbstractAnnotation
QubitCoordinates operation for specifying qubit positions.
An annotation class used to specify the spatial location of a qubit in a quantum circuit. Coordinates do not affect simulation results but are useful for visualizing and organizing qubit layouts within the circuit.
See also
Examples
Adding QubitCoordinates to a circuit:
>>> from mimiqcircuits import * >>> QubitCoordinates([0.5, 0.75, 1.0]) QubitCoordinates(0.5, 0.75, 1.0) >>> op = QubitCoordinates([0.5, 0.75, 1.0]) >>> op.get_notes() [0.5, 0.75, 1.0] >>> c= Circuit() >>> c.push(QubitCoordinates([0.2, 0.3]), 0) 1-qubit circuit with 1 instructions: └── QubitCoordinates(0.2, 0.3) @ q[0]
- class mimiqcircuits.RescaledGate(gate: T, p)[source]#
Bases:
AbstractOperator
,Generic
[T
]RescaledGate operation.
The RescaledGate represents an operation where a quantum gate is rescaled by a factor p, typically between 0 and 1. This rescaling modifies the action of the gate, multiplying its matrix representation by p. The gate to be rescaled must be an instance of the Gate class, and p must be a valid scalar (real or symbolic) in the range [0, 1].
- Parameters:
gate (-) – The quantum gate to be rescaled.
p (-) – The rescaling factor, must be between 0 and 1.
- Raises:
- TypeError – If the provided gate is not an instance of Gate.
- ValueError – If the rescaling factor p is not between 0 and 1.
- - get_operation()
Returns the underlying gate.
- - get_param(name)
Retrieves the value of a parameter (such as p).
- - _matrix(*args)
Returns the matrix representation of the rescaled gate.
- - get_scale()
Returns the scaling factor p.
- - rescale(p)
Returns a new RescaledGate with a different scaling factor.
- - rescale_in_place(p)
Rescales the gate in place by multiplying the current p with the new value.
- - evaluate(d)
Substitutes values in the parameters (useful when symbolic values are used).
Examples
Creating and rescaling a gate:
>>> from mimiqcircuits import * >>> g = GateH() >>> rg = RescaledGate(g, 0.5)
>>> rg.get_scale() 0.5
>>> rg.rescale(0.8) 0.4*H
- evaluate(d)[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)
- class mimiqcircuits.Reset[source]#
Bases:
krauschannel
Reset operation.
Quantum operation that resets the status of one qubit to the \(\ket{0}\) state.
Warning
This operation is non-reversible.
Examples
Adding Reset operation to the Circuit (The args can be: range, list, tuple, set or int)
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Reset(), 0) 1-qubit circuit with 1 instructions: └── Reset @ q[0] >>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(Reset(),(0,1,2)) 3-qubit circuit with 3 instructions: ├── Reset @ q[0] ├── Reset @ q[1] └── Reset @ q[2]
- class mimiqcircuits.ResetX[source]#
Bases:
krauschannel
ResetX operation.
This operation is performed by applying a Hadamard gate (H) to the qubit, which transforms the qubit from the computational basis (\(\ket{0}\) or \(\ket{1}\)) to the superposition basis (\(\ket{+}\) or \(\ket{-}\)). After applying the Hadamard gate, a standard Reset operation is performed, resetting the qubit to the \(\ket{0}\) state. Finally, another Hadamard gate is applied to convert the \(\ket{0}\) state back into the \(\ket{+}\) state.
Warning
This operation is non-reversible.
Examples
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(ResetX(), 0) 1-qubit circuit with 1 instructions: └── ResetX @ q[0] >>> c.decompose() 1-qubit circuit with 3 instructions: ├── H @ q[0] ├── Reset @ q[0] └── H @ q[0]
- class mimiqcircuits.ResetY[source]#
Bases:
krauschannel
ResetY operation.
The ResetY operation works by first rotating the qubit’s state so that the Y-axis aligns with the Z-axis, applying a standard reset (which resets the qubit to the \(\ket{0}\) state), and then rotating the qubit back to its original basis.
Warning
This operation is non-reversible.
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(ResetY(), 0) 1-qubit circuit with 1 instructions: └── ResetY @ q[0] >>> c.decompose() 1-qubit circuit with 3 instructions: ├── HYZ @ q[0] ├── Reset @ q[0] └── HYZ @ q[0]
- class mimiqcircuits.ResetZ[source]#
Bases:
krauschannel
ResetZ operation.
Quantum operation that resets the status of one qubit to the \(\ket{0}\) state along the Z-axis. This operation is an alias of the
Reset
operation.Warning
This operation is non-reversible.
Examples
>>> from mimiqcircuits import * >>> c= Circuit() >>> c.push(ResetZ(), 0) 1-qubit circuit with 1 instructions: └── Reset @ q[0] >>> c.decompose() 1-qubit circuit with 1 instructions: └── Reset @ q[0]
- class mimiqcircuits.SchmidtRank[source]#
Bases:
Operation
Operation to get the Schmidt rank of a bipartition and store it in a z-register.
A Schmidt decomposition for a bipartition into subsystems \(A\) and \(B\) is defined for a pure state as:
Schmidt Decomposition
\[|\psi\rangle = \sum_{i=1}^{r} s_i |\alpha_i\rangle \otimes |\beta_i\rangle,\]where \(|\alpha_i\rangle\) (\(|\beta_i\rangle\)) are orthonormal states acting on \(A\) (\(B\)). The Schmidt rank is the number of terms \(r\) in the sum. A product state gives \(r=1\), and \(r>1\) signals entanglement.
We only consider bipartitions where \(A=\{1,\ldots,k-1\}\) and \(B=\{k,\ldots,N\}\), for some \(k\) and where \(N\) is the total number of qubits.
In MPS (Matrix Product States), when the state is optimally compressed, the Schmidt rank should be equal to the bond dimension (see
BondDim
).See also
Examples
When pushing to a circuit, the qubit index k takes the role of the above bipartition into A and B. For k=1, A is empty and the Schmidt rank will always return 1.
>>> from mimiqcircuits import * >>> k = 5 >>> c = Circuit() >>> c.push(SchmidtRank(), k, 1) 6-qubit circuit with 1 instructions: └── SchmidtRank @ q[5], z[1]
- property num_qubits#
- property parnames#
- class mimiqcircuits.ShiftCoordinates(*args)[source]#
Bases:
AbstractAnnotation
ShiftCoordinates operation for shifting the coordinates of qubits.
An annotation class used to apply a shift to the spatial coordinates of subsequent qubit or detector annotations in a quantum circuit. ShiftCoordinates accumulates offsets that adjust the position of related circuit components, aiding in visualization without affecting the simulation.
See also
Examples
Adding ShiftCoordinates to represent spatial shifts in a circuit:
>>> from mimiqcircuits import * >>> ShiftCoordinates(0.1, 0.2, 0.3) ShiftCoordinates(0.1, 0.2, 0.3) >>> ShiftCoordinates([0.4, 0.5]) ShiftCoordinates(0.4, 0.5) >>> ShiftCoordinates(0.4, 0.5) ShiftCoordinates(0.4, 0.5) >>> op = ShiftCoordinates(0.1, 0.9) >>> op.get_notes() [0.1, 0.9] >>> c = Circuit() >>> c.push(ShiftCoordinates(0.4, 0.2)) 0-qubit circuit with 1 instructions: └── ShiftCoordinates(0.4, 0.2)
- class mimiqcircuits.SigmaMinus(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to \(|0 \rangle\langle 1|\).
Matrix Representation
\[\begin{split}\begin{pmatrix} 0 & a\\ 0 & 0 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> SigmaMinus() SigmaMinus(1)
>>> SigmaMinus(0.5) SigmaMinus(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(SigmaMinus()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨SigmaMinus(1)⟩ @ q[1], z[1]
- property num_qubits#
- property parnames#
- class mimiqcircuits.SigmaPlus(a=1)[source]#
Bases:
AbstractOperator
One-qubit operator corresponding to \(|1 \rangle\langle 0|\).
Matrix Representation
\[\begin{split}\begin{pmatrix} 0 & 0\\ a & 0 \end{pmatrix}\end{split}\]This matrix is parametrized by a to allow for phases/rescaling.
The parameter a is optional and is set to 1 by default.
See also
- Parameters:
a (complex, optional) – Scaling factor for the matrix. Defaults to 1.
Examples
>>> from mimiqcircuits import * >>> SigmaPlus() SigmaPlus(1)
>>> SigmaPlus(0.5) SigmaPlus(0.5)
>>> c = Circuit() >>> c.push(ExpectationValue(SigmaPlus()), 1, 1) 2-qubit circuit with 1 instructions: └── ⟨SigmaPlus(1)⟩ @ q[1], z[1]
- property num_qubits#
- property parnames#
- class mimiqcircuits.ThermalNoise(T1: float | int, T2: float | int, time: float | int, ne: float | int)[source]#
Bases:
krauschannel
One-qubit thermal noise channel.
The thermal noise channel is equivalent to the
PhaseAmplitudeDamping
channel, but it is parametrized instead as:\[\begin{split}\mathcal{E}(\rho) = \begin{pmatrix} e^{-\Gamma_1 t}\rho_{00} + (1-n_e)(1-e^{-\Gamma_1 t}) & e^{-\Gamma_2 t}\rho_{01} \\ e^{-\Gamma_2 t}\rho_{10} & e^{-\Gamma_1 t}\rho_{11} + n_e(1-e^{-\Gamma_1 t}) \end{pmatrix}\end{split}\]where \(\Gamma_1 = 1/T_1\) and \(\Gamma_2 = 1/T_2\), and the parameters must fulfill \(T_1 \geq 0\), \(T_2 \leq 2 T_1\), \(t \geq 0\), and \(0 \leq n_e \leq 1\).
These parameters can be related to the ones used to define the
PhaseAmplitudeDamping
channel through \(p = 1-n_e\), \(\gamma = 1-e^{-\Gamma_1 t}\), and \(\beta = \frac{1}{2}(1-e^{-(\Gamma_2-\Gamma_1/2)t})\).- Parameters:
T₁ (float) – Longitudinal relaxation rate, must be greater than or equal to 0.
T₂ (float) – Transversal relaxation rate, must be less than or equal to 2 * T₁.
t (float) – Time duration of the gate, must be greater than or equal to 0.
nₑ (float) – Excitation fraction when in thermal equilibrium with the environment, must be in the range [0, 1].
Examples
>>> from mimiqcircuits import * >>> c = Circuit() >>> c.push(ThermalNoise(0.5, 0.6, 1.2, 0.3), 1) 2-qubit circuit with 1 instructions: └── ThermalNoise(0.5, 0.6, 1.2, 0.3) @ q[1]
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- property parnames#
- class mimiqcircuits.Tick[source]#
Bases:
AbstractAnnotation
An annotation class representing a timing marker or layer boundary in a quantum circuit. Tick does not affect simulation but provides structure by separating operations into distinct time steps, which is useful for visualization and analysis.
Examples
>>> from mimiqcircuits import * >>> tick = Tick() >>> print(tick) Tick
>>> c = Circuit() >>> c.push(tick) 0-qubit circuit with 1 instructions: └── Tick
- class mimiqcircuits.VonNeumannEntropy[source]#
Bases:
Operation
Operation to get the bipartite Von Neumann entanglement entropy and store it in a z-register.
The entanglement entropy for a bipartition into subsystems \(A\) and \(B\) is defined for a pure state \(\rho = | \psi \rangle\langle \psi |\) as:
Entanglement Entropy
\[\mathcal{S}(\rho_A) = - \mathrm{Tr}(\rho_A \log_2 \rho_A) = - \mathrm{Tr}(\rho_B \log_2 \rho_B) = \mathcal{S}(\rho_A)\]where \(\rho_A = \mathrm{Tr}_B(\rho)\) is the reduced density matrix. A product state has \(\mathcal{S}(\rho_A)=0\) and a maximally entangled state between \(A\) and \(B\) gives \(\mathcal{S}(\rho_A)=1\).
We only consider bipartitions where \(A=\{1,\ldots,k-1\}\) and \(B=\{k,\ldots,N\}\), for some \(k\) and where \(N\) is the total number of qubits.
When the system is open (i.e., with noise) and we are using quantum trajectories, the entanglement entropy of each trajectory is returned during execution.
See also
Examples
When pushing to a circuit, the qubit index k takes the role of the above bipartition into A and B. For k=1, A is empty and the entanglement entropy will always return 0.
>>> from mimiqcircuits import * >>> k = 5 >>> c = Circuit() >>> c.push(VonNeumannEntropy(), k, 1) 6-qubit circuit with 1 instructions: └── VonNeumannEntropy @ q[5], z[1]
- property num_qubits#
- property parnames#
- class mimiqcircuits.krauschannel[source]#
Bases:
Operation
Supertype for all N-qubit Kraus channels.
A Kraus channel is a quantum operation on a density matrix \(\\rho\) of the form:
\[\mathcal{E}(\rho) = \sum_k E_k \rho E_k^\dagger,\]where \(E_k\) are Kraus operators that need to fulfill \(\sum_k E_k^\dagger E_k \leq I\).
Special Properties:
isCPTP()
: A Kraus channel is a completely positive and trace-preserving (CPTP) operation when \(\\sum_k E_k^\dagger E_k = I\). Currently, all noise channels are CPTP.ismixedunitary()
: A Kraus channel is called a mixed unitary channel when the Kraus operators \(E_k\) are each proportional to a unitary matrix \(U_k\), i.e., when \(\\mathcal{E}(\\rho) = \\sum_k p_k U_k \\rho U_k^\dagger\) with some probabilities \(0 \leq p_k \leq 1\) that add up to 1 and \(U_k^\dagger U_k = I\).
- cumprobabilities()[source]#
Returns the cumulative sum of probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
Cumulative probabilities for the Kraus operators.
- Return type:
list
Examples
>>> from mimiqcircuits import * >>> Depolarizing1(0.1).cumprobabilities() [0.9, 0.933333333333333, 0.966666666666667, 1.0]
- classmethod isCPTP()[source]#
Determine whether the Kraus channel is Completely Positive and Trace Preserving (CPTP).
A quantum operation is CPTP if the Kraus operators fulfill the condition:
\[\sum_k E_k^\dagger E_k = I\]If the condition is:
\[\sum_k E_k^\dagger E_k < I\]then the operation is not CPTP.
Note
Currently, all noise channels are considered CPTP.
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is CPTP, False otherwise.
- Return type:
bool
- classmethod ismixedunitary()[source]#
Determine whether the quantum operation is a mixed unitary channel.
A channel is considered mixed unitary if all the Kraus operators \(E_k\) are proportional to a unitary matrix \(U_k\), i.e.,
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]with some probabilities \(0 \leq p_k \leq 1\) that add up to 1, and \(U_k^\dagger U_k = I\).
- Parameters:
krauschannel – The Kraus channel to check.
- Returns:
True if the channel is a mixed unitary channel, False otherwise.
- Return type:
bool
Examples
>>> from mimiqcircuits import * >>> PauliX(0.1).ismixedunitary() True
>>> AmplitudeDamping(0.1).ismixedunitary() False
- krausmatrices()[source]#
Returns the Kraus matrices associated with the given Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices returned by this function.
If the Kraus channel is parametric, the matrix elements are wrapped in a symengine or sympy object.
- Returns:
A list of symengine matrices representing the Kraus operators.
- Return type:
list
- krausoperators()[source]#
Returns the Kraus operators associated with the given Kraus channel.
This should be implemented for each specific channel.
- Returns:
A list of matrices representing the Kraus operators.
- Return type:
list
- probabilities()[source]#
Returns the probabilities for each Kraus operator in a mixed unitary channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(p_k\) are the probabilities.
This method is valid only for mixed unitary channels.
- Returns:
A list of probabilities for each Kraus operator.
- Return type:
list
- squaredkrausoperators()[source]#
Returns the square of the Kraus operators (\(E_k^\dagger E_k\)). This computes the Hermitian conjugate (dagger) of each Kraus operator and multiplies it by the operator itself.
- Returns:
A list of squared Kraus operators.
- Return type:
list
- unitarygates()[source]#
Returns the unitary gates associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary operators.
This method is valid only for mixed unitary channels.
- unitarymatrices()[source]#
Unitary matrices associated with the given mixed unitary Kraus channel.
A mixed unitary channel is written as:
\[\mathcal{E}(\rho) = \sum_k p_k U_k \rho U_k^\dagger,\]where \(U_k\) are the unitary matrices.
An error is raised if the channel is not mixed unitary (i.e., ismixedunitary(self)==False).
Note
If the Kraus channel is parametric, the matrix elements are wrapped in a symbolic object (e.g., from sympy or symengine). To manipulate expressions, use the appropriate symbolic manipulation libraries.
Examples
>>> from mimiqcircuits import * >>> PauliX(0.2).unitarymatrices() [[1.0, 0] [0, 1.0] , [0, 1.0] [1.0, 0] ]
- unwrappedcumprobabilities()[source]#
Returns the cumulative sum of probabilities for the mixed unitary channel without symbolic wrapping.
See also
- Returns:
A list of cumulative probabilities as float values.
- Return type:
list
- unwrappedkrausmatrices()[source]#
Returns the unitary Kraus matrices associated to the mixed unitary Kraus channel without symbolic wrapper.
See also
Example
>>> from mimiqcircuits import * >>> op = PauliX(0.2) >>> op.unwrappedkrausmatrices() [[0.894427190999916, 0] [0, 0.894427190999916] , [0, 0.447213595499958] [0.447213595499958, 0] ]