Unitary Gates¶
Unitary gates are fundamental components of quantum circuits. Here we explain how to work with unitary gates in MIMIQ.
Mathematical background¶
State vector and probability¶
In quantum mechanics, every transformation applied to a quantum state must be unitary (in a closed system). To understand why, we can expand the quantum state as
where \(\ket{\psi_i}\) are orthonormal basis states. For this state, the following condition must hold true:
Since \(|c_i|^2\) corresponds to the probability of measuring state \(\ket{\psi_i}\), this condition simply says that the probabilities must add up to one. Unitary gates preserve this normalization condition, see below.
Unitary transformation¶
An alternative way to compute the probability is through the inner product. Given two states in Hilbert space, \(\ket{\alpha}\) and \(\ket{\psi}\), the squared inner product \(|\braket{\alpha|\psi}|^2\) reflects the probability of measuring the system in state \(\ket{\alpha}\). Thus, the normalization condition can be written as \(|\braket{\psi|\psi}|^2 = 1\). In other words, the length of the state vector in complex space must be one.
When evolving the state \(\ket{\psi}\) using an operator U, the normalization condition becomes (omitting the square):
To fulfill this, the operator U must satisfy the condition:
An operator that fulfills this requirement is called a unitary operator and its matrix representation is unitary too.
Unitary gates in MIMIQ.¶
MIMIQ offers a large number of gates to build quantum circuits. For an overview, type the following line in your Python session:
help(GATES)
Similarly, to get more information about a specific gate, you can type the following command in your Python session using the gate of your choice:
help(GateID)
There are different categories of gates depending on the number of targets, parameters etc. We discuss how to implement them in the following.
Single-qubit gates¶
List of single-qubit gates: GateID, GateX, GateY, GateZ, GateH, GateS, GateSDG, GateT, GateTDG, GateSX, GateSXDG. GateSY, GateSYDG.
push() function.>>> circuit = Circuit()
>>> circuit.push(GateX(), 0)
1-qubit circuit with 1 instructions:
└── X @ q[0]
Single-qubit parametric gates¶
List of single-qubit parametric gates: GateU, GateP, GateRX, GateRY, GateRZ, GateR, GateU1, GateU2, GateU3, Delay().
`GateU(0.5, 0.5, 0.5)` or `GateU1(0.5)`), if you are unsure of the expected number of parameters use the help() function in your Python interactive session and give it the oject you are interested in (ex: help(GateU)).push() function and give the index of the target qubit.>>> circuit = Circuit()
>>> circuit.push(GateRX(math.pi/2), 0)
1-qubit circuit with 1 instructions:
└── RX(1.5707963267948966) @ q[0]
Two qubit gates¶
List of two qubits gates: GateCX, GateCY, GateCZ, GateCH, GateSWAP, GateISWAP, GateCS, GateCSDG, GateCSX, GateCSXDG, GateECR, GateDCX.
push() function to add it to the circuit.>>> circuit = Circuit()
>>> circuit.push(GateCH(), 0, 1)
2-qubit circuit with 1 instructions:
└── CH @ q[0], q[1]
Two-qubit parametric gates¶
List of two qubits parametric gates : GateCP, GateCU, GateCRX, GateCRY, GateCRZ, GateRXX, GateRYY, GateRZZ,
GateRZX, GateXXplusYY, GateXXminusYY.
GateCU(math.pi, math.pi, math.pi)).push() function. Again, check each gate’s documentation to understand the qubit ordering; for controlled gates the first qubit corresponds to the control qubit, the second to the target.>>> circuit = Circuit()
>>> circuit.push(GateRXX(math.pi/2), 0, 1)
2-qubit circuit with 1 instructions:
└── RXX(1.5707963267948966) @ q[0,1]
Multi-qubit gates¶
List of multi-qubit gates: GateCCX, GateC3X, GateCCP, GateCSWAP.
For the multi-qubit controlled gates you will need to give the index of each qubit to the push() function. As usual, first the control qubits, then the targets; check the specific documentation of each gate.
>>> circuit = Circuit()
>>> circuit.push(GateC3X(), 0, 1, 2, 3)
4-qubit circuit with 1 instructions:
└── C₃X @ q[0,1,2], q[3]
Generalized gates¶
Some common gate combinations are available as generalized gates: PauliString, QFT, PhaseGradient, Diffusion, PolynomialOracle.
Generalized gates can be applied to a variable number of qubits.
It is highly recommended to check their docstrings to understand their usage help(QFT).
Here is an example of use:
>>> circuit = Circuit()
>>> circuit.push(PhaseGradient(10), *range(0, 10))
10-qubit circuit with 1 instructions:
└── PhaseGradient @ q[0,1,2,3,4,5,6,7,8,9]
These gates target a variable number of gates, so you have to specify in the constructor how many target qubits will be used, and give to the push() function one index per target qubit.
More about generalized gates on special operations.
Custom Gates¶
If you need to use a specific unitary gate that is not provided by MIMIQ, you can use GateCustom` to create your own unitary gate.
Note
Only one qubit or two qubits gates can be created using MIMIQ’s GateCustom.
Note
Avoid using GateCustom if you can define the same gate using a pre-defined gate from MIMIQ’s library, as it could impact negatively peformance.
To create a custom unitary gate you first have to define the matrix of your gate in Python:
# define the matrix for a 2 qubits gate
>>> custom_matrix = np.array([[np.exp(1j*math.pi/3), 0, 0, 0], [0, np.exp(1j*math.pi/5), 0, 0 ], [0, 0, np.exp(1j*math.pi/7), 0], [0, 0, 0, np.exp(1j*math.pi/11)]])
Then you can create your unitary gate and use it like any other gate using push()
>>> circuit = Circuit()
>>> custom_gate = GateCustom(custom_matrix)
>>> circuit.push(custom_gate, 0, 1)
2-qubit circuit with 1 instructions:
└── Custom(...) @ q[0,1]
Composition: Control, Power, Inverse, Parallel¶
Gates in MIMIQ can be combined to create more complex gates using Control, Power, Inverse, Parallel.
Control¶
A controlled version of every gate can be built using the control() function.
For example, CX can be built with the following instruction:
>>> CX = control(1, GateX())
The first argument indicates the number of control qubits and is completely up to the user. For example a CCCCCX can be built with the following instruction:
>>> CCCCCX = control(5, GateX())
Details
A wrapper for GateCX is already provided by MIMIQ. Whenever possible, it is recommended to use the gates already provided by the framework instead of creating your own composite gate to prevent performances loss.
Be careful when adding the new control gate to your circuit. When using the push() function, the first expected indices should be the control qubits specified in Control and the last indices the target qubits of the gate, for instance:
>>> circuit = Circuit()
>>> circuit.push(CCCCCX, 0, 1, 2, 3, 4, 5)
6-qubit circuit with 1 instructions:
└── C₅X @ q[0,1,2,3,4], q[5]
Power¶
To raise the power of a gate you can use the power() function.
For example, \(\sqrt{\mathrm{GateS}} = \mathrm{GateT}\), therefore, the following instruction can be used to generate the GateS:
>>> power(GateS(), 1/2)
T
The power method will attempt to realize simplifications whenever it can, for example asking for the square of GateX will directly give you GateID.
Inverse¶
To get the inverse of an operator you can use the inverse() method.
Remember that the inverse of a unitary matrix is the same as the adjoint (conjugate transpose), so this is a simple way to get the adjoint of a gate.
For example here is how to get the inverse of a GateH
>>> inv_H = inverse(GateH())
Parallel¶
To create a composite gate applying a specific gate to multiple qubits at once you can use the parallel() method.
>>> circuit = Circuit()
>>> X_gate_4 = parallel(4, GateX())
>>> circuit.push(X_gate_4, 0, 1, 2, 3)
4-qubit circuit with 1 instructions:
└── ⨷ ⁴ X @ q[0], q[1], q[2], q[3]
>>> circuit.draw()
┌─┐
q[0]: ╶┤X├────────────────────────────────────────────────────────────────────╴
├─┤
q[1]: ╶┤X├────────────────────────────────────────────────────────────────────╴
├─┤
q[2]: ╶┤X├────────────────────────────────────────────────────────────────────╴
├─┤
q[3]: ╶┤X├────────────────────────────────────────────────────────────────────╴
└─┘
To check the number of repetition of your custom parallel gate you can use the num_repeats() method:
>>> X_gate_4.num_repeats
4
Be careful when using a multi-qubit gate with parallel() as the index of the targeted qubits in push() can become confusing.
for example see below the parallel applicatoin of a CX gate:
>>> circuit = Circuit()
>>> double_CX = Parallel(2, GateCX())
>>> circuit.push(double_CX, 0, 1, 2, 3)
4-qubit circuit with 1 instructions:
└── ⨷ ² CX @ q[0], q[1], q[2], q[3]
>>> circuit.draw()
┌────┐
q[0]: ╶┤0 ├─────────────────────────────────────────────────────────────────╴
│ CX│
q[1]: ╶┤1 ├─────────────────────────────────────────────────────────────────╴
├────┤
q[2]: ╶┤0 ├─────────────────────────────────────────────────────────────────╴
│ CX│
q[3]: ╶┤1 ├─────────────────────────────────────────────────────────────────╴
└────┘
Here the index 0 and 1 correspond to the control and target of the first CX gate and 2 and 3 correspond to the second CX gate.
Extract information of unitary gates¶
MIMIQ priovides a few methods to extract information about the unitary gates.
Matrix¶
To get the matrix of a unitary gate you can use the matrix():
>>> GateCX().matrix()
[1.0, 0, 0, 0]
[0, 1.0, 0, 0]
[0, 0, 0, 1.0]
[0, 0, 1.0, 0]
Number of targets¶
Another way to know how many qubits, bits or z-variables are targeted by one unitary gate you can use num_qubits(), num_bits() and num_zvars(), respectively.
>>> GateCX().num_qubits, GateCX().num_bits, GateCX().num_zvars
(2, 0, 0)
>>> Measure().num_qubits, Measure().num_bits, Measure().num_zvars
(1, 1, 0)
>>> Amplitude("01").num_qubits,Amplitude("01").num_bits, Amplitude("01").num_zvars
(0, 0, 1)
See non-unitary operations and statistical operations pages for more information on Measure and Amplitude.
Reference¶
- class mimiqcircuits.GateID[source]
Bases:
GateSingle 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 instruction: └── ID @ q[0] >>> GateID().power(2), GateID().inverse() (ID, ID) >>> GateID().decompose() 1-qubit circuit with 1 instruction: └── U(0, 0, 0, 0.0) @ 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.
- isidentity()[source]
- class mimiqcircuits.GateX[source]
Bases:
GateSingle 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 instruction: └── X @ q[0] >>> GateX().power(2), GateX().inverse() (ID, X) >>> GateX().decompose() 1-qubit circuit with 1 instruction: └── U(pi, 0, pi, 0.0) @ 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.
- class mimiqcircuits.GateY[source]
Bases:
GateSingle 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 instruction: └── U(pi, (1/2)*pi, (1/2)*pi, 0.0) @ 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.
- class mimiqcircuits.GateZ[source]
Bases:
GateSingle 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 instruction: └── P(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.
- class mimiqcircuits.GateH[source]
Bases:
GateSingle 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 instruction: └── H @ q[0] >>> GateH().power(2), GateH().inverse() (ID, H) >>> GateH().decompose() 1-qubit circuit with 1 instruction: └── U((1/2)*pi, 0, pi, 0.0) @ 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.
- class mimiqcircuits.GateCX(num_controls=None, operation=None, *args, **kwargs)[source]
Bases:
ControlTwo 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 instruction: └── CX @ q[0], q[1] >>> GateCX().power(2), GateCX().inverse() (CID, CX) >>> GateCX().decompose() 2-qubit circuit with 1 instruction: └── CX @ q[0], q[1]
- __init__(num_controls=1, operation=None)[source]
Initialize a CX gate.
- Parameters:
num_controls – Ignored, always 1 for CX.
operation – Ignored, always GateX() for CX.
- class mimiqcircuits.GateRX(theta)[source]
Bases:
GateSingle 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 instruction: └── RX(theta) @ q[0] >>> GateRX(theta).power(2), GateRX(theta).inverse() (RX(2*theta), RX(-theta)) >>> GateRX(theta).decompose() 1-qubit circuit with 1 instruction: └── U(theta, (-1/2)*pi, (1/2)*pi, 0.0) @ q[0]
- __init__(theta)[source]
- 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.
- isidentity()[source]
- class mimiqcircuits.GateRY(theta)[source]
Bases:
GateSingle 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 instruction: └── RY(theta) @ q[0] >>> GateRY(theta).power(2), GateRY(theta).inverse() (RY(2*theta), RY(-theta)) >>> GateRY(theta).decompose() 1-qubit circuit with 1 instruction: └── U(theta, 0, 0, 0.0) @ q[0]
- __init__(theta)[source]
- 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.
- isidentity()[source]
- class mimiqcircuits.GateRZ(lmbda)[source]
Bases:
GateSingle 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 instruction: └── RZ(lambda) @ q[0] >>> GateRZ(lmbda).power(2), GateRZ(lmbda).inverse() (RZ(2*lambda), RZ(-lambda)) >>> GateRZ(lmbda).decompose() 1-qubit circuit with 1 instruction: └── U(0, 0, lambda, (-1/2)*lambda) @ q[0]
- __init__(lmbda)[source]
- 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.
- isidentity()[source]
- class mimiqcircuits.GateU(theta, phi, lmbda, gamma=0.0)[source]
Bases:
GateSingle 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:
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 instruction: └── 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 instruction: └── U(theta, phi, lambda, gamma) @ q[0] >>> c = Circuit().push(GateU(theta, phi, lmbda, gamma), 0) >>> c 1-qubit circuit with 1 instruction: └── 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 instruction: └── U(theta, phi, lambda, gamma) @ q[0]
- __init__(theta, phi, lmbda, gamma=0.0)[source]
- 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.
- convert_to_numeric(matrix)[source]
Convert a symbolic matrix to a numeric numpy array.
- class mimiqcircuits.GateCustom(matrix)[source]
Bases:
GateOne 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 instruction: └── Custom(...) @ q[0:1]
- __init__(matrix)[source]
- matrix()[source]
Try to numerically evaluate entries when possible, otherwise keep symbolic.
- property num_qubits
- 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 is_unitary(matrix, tol=1e-08)[source]
- pretty_print()[source]
- 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)
- 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.
- mimiqcircuits.control(*args)[source]
Apply a control to a quantum operation or creating a lazy expression.
This function can be used in two ways: 1. To create a controlled version of a Gate or Operation. 2. To create a lazy expression that will apply a control to a future argument.
- Parameters:
*args –
Variable length argument list. - If one argument is provided:
If it’s an operation, returns a lazy expression control(?, op).
If it’s an integer (num_controls), returns a lazy expression control(n, ?).
If two arguments are provided (num_controls, gate): - Returns the controlled operation gate.control(num_controls).
- Returns:
The controlled operation or a lazy expression.
- Return type:
- Raises:
TypeError – If the arguments are of invalid types or count.
Examples
>>> from mimiqcircuits import * >>> op = control(2, GateX()) >>> op C₂X >>> lazy_ctrl = control(2) >>> lazy_ctrl(GateX()) C₂X
- mimiqcircuits.power(*args)[source]
Raise a quantum operation to a power or create a lazy expression.
- Parameters:
*args –
Variable length argument list. - If one argument is provided:
If it’s an operation, returns a lazy expression power(op, ?).
If it’s a number (exponent), returns a lazy expression power(?, exponent).
If two arguments are provided (gate, exponent): - Returns the powered operation gate.power(exponent).
- Returns:
The powered operation or a lazy expression.
- Return type:
- Raises:
TypeError – If the arguments are of invalid types or count.
Examples
>>> from mimiqcircuits import * >>> op = power(GateX(), 0.5) >>> op SX
- mimiqcircuits.inverse(op)[source]
Compute the inverse of a quantum operation.
- Parameters:
op (Operation) – The operation to invert.
- Returns:
The inverse of the operation.
- Return type:
Examples
>>> from mimiqcircuits import * >>> op = inverse(GateS()) >>> op S†
- mimiqcircuits.parallel(*args)[source]
Create a parallel execution of a quantum operation or a lazy expression.
This function can be used to apply an operation multiple times in parallel across different qubits.
- Parameters:
*args –
Variable length argument list. - If one argument is provided:
If it’s an operation, returns a lazy expression parallel(?, op).
If it’s an integer (num_repeats), returns a lazy expression parallel(n, ?).
- If two arguments are provided (num_repeats, gate):
Returns the parallel operation gate.parallel(num_repeats).
- Returns:
The parallel operation or a lazy expression.
- Return type:
- Raises:
TypeError – If the arguments are of invalid types or count.
Examples
>>> from mimiqcircuits import * >>> op = parallel(3, GateH()) >>> op ⨷ ³ H