Other Operations
Custom gates
MimiqCircuitsBase.GateCustom
— Typestruct GateCustom{N,T} <: AbstractGate{N}
N
qubit gate specified by a $2^N \times 2^N$ matrix with elements of type T
.
Use this to construct your own gates based on unitary matrices.
Only one and two qubits gates are supported.
MIMIQ uses textbook convention for specifying gates.
One qubit gate matrices are defined in the basis $|0\rangle$, $|1\rangle$ e.g.,
\[\operatorname{Z} = \begin{pmatrix} 1&0\\ 0&-1 \end{pmatrix}\]
Two qubit gate matrices are defined in the basis $|00\rangle$, $|01\rangle$>, $|10\rangle$, $|11\rangle$ where the left-most qubit is the first to appear in the target list e.g.,
\[\operatorname{CNOT} = \begin{pmatrix} 1&0&0&0\\ 0&1&0&0\\ 0&0&0&1\\ 0&0&1&0 \end{pmatrix}\]
julia> CNOT = [1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0]
4×4 Matrix{Int64}:
1 0 0 0
0 1 0 0
0 0 0 1
0 0 1 0
julia> # CNOT gate with control on q1 and target on q2
julia> Instruction(GateCustom(CNOT), 1, 2)
GateCustom([1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0]) @ q1, q2
# Examples
jldoctest julia> g = GateCustom([1 0; 0 1]) Custom([1.0 0.0; 0.0 1.0])
julia> push!(Circuit(), g, 1) 1-qubit circuit with 1 instructions: └── Custom([1.0 0.0; 0.0 1.0]) @ q1 ```
MimiqCircuitsBase.Operator
— TypeOperator(matrix)
N
qubit operator specified by an $2^N \times 2^N$ matrix.
Only one and two qubits operators are supported.
This operator doesn't have to be unitary.
See also AbstractOperator
, ExpectationValue
, and Kraus
.
Examples
julia> Operator([1 2; 3 4])
1-qubit Operator:
├── 1.0 2.0
└── 3.0 4.0
julia> Operator([1 0 0 1; 0 0 0 0; 0 0 0 0; 1 0 0 1])
2-qubit Operator:
├── 1.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 1.0
Operators can be used for expectation values:
julia> push!(Circuit(), ExpectationValue(Operator([0 1; 0 0])), 1, 1)
1-qubit circuit with 1 instructions:
└── ⟨Operator([0.0 1.0; 0.0 0.0])⟩ @ q[1], z[1]
MimiqCircuitsBase.AbstractOperator
— TypeAbstractOperator{N} <: Operation{N,0,0}
Supertype for all the N
-qubit operators.
Note that objects of type AbstractOperator do not need to be unitary.
Operators can be used to define Kraus channels (noise) AbstractKrausChannel
, or to compute expectation values ExpectationValue
. However, they will return an error if we attempt to directly apply them to states.
MimiqCircuitsBase.matrix
— Functionmatrix(operator)
Matrix associated to the given operator.
if the operator is parametric, the matrix elements are wrapped in a Symbolics.Num
object. To manipulate expressions use the Symbolics
package.
Examples
julia> matrix(GateH())
2×2 Matrix{Float64}:
0.707107 0.707107
0.707107 -0.707107
julia> matrix(GateRX(π/2))
2×2 Matrix{ComplexF64}:
0.707107+0.0im 0.0-0.707107im
0.0-0.707107im 0.707107+0.0im
MimiqCircuitsBase.opsquared
— Methodopsquared(op)
Compute $A^\dagger A$ for an operator $A$.
MimiqCircuitsBase.rescale
— Methodoprescale(op, a)
Compute $a * A$ for an operator $A$ and rescaling factor $a$.
MimiqCircuitsBase.unwrappedmatrix
— Methodunwrappedmatrix(operator)
Returns the matrix associated to the specified quantum operator without the Symbolics.Num
wrapper.
If any of the gate's parameters is symbolic, an error is thrown.
See also matrix
.
Examples
julia> unwrappedmatrix(GateRX(π/2))
2×2 Matrix{ComplexF64}:
0.707107+0.0im 0.0-0.707107im
0.0-0.707107im 0.707107+0.0im
julia> unwrappedmatrix(GateH())
2×2 Matrix{Float64}:
0.707107 0.707107
0.707107 -0.707107
Gate definitions
MimiqCircuitsBase.GateCall
— TypeGateCall(decl, args...)
Gate corresponding to a call to a GateDecl
definition.
It is created by calling a GateDecl
with the proper number of arguments.
Examples
julia> @gatedecl ansatz(θ) = begin
c = Circuit()
push!(c, GateX(), 1)
push!(c, GateRX(θ), 2)
return c
end
gate ansatz(θ) =
├── X @ q[1]
└── RX(θ) @ q[2]
julia> @variables λ;
julia> ansatz(λ)
ansatz(λ)
See also
MimiqCircuitsBase.GateDecl
— TypeGateDecl(name, args, circuit)
Define a new gate of given name, arguments and circuit.
Examples
A simple gate declaration, via the @gatedecl
macro:
julia> @gatedecl ansatz(θ) = begin
c = Circuit()
push!(c, GateX(), 1)
push!(c, GateRX(θ), 2)
return c
end
gate ansatz(θ) =
├── X @ q[1]
└── RX(θ) @ q[2]
julia> @variables λ;
julia> decompose(ansatz(λ))
2-qubit circuit with 2 instructions:
├── X @ q[1]
└── RX(λ) @ q[2]
See also
Non-unitary operations
MimiqCircuitsBase.MeasureReset
— TypeMeasureReset()
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 :math:\\ket{0}
state.
See also MeasureResetX
, MeasureResetY
, IfStatement
, GateH
.
Examples
julia> MeasureReset()
MR
julia> decompose(MeasureReset())
1-qubit circuit with 2 instructions:
├── M @ q[1], c[1]
└── IF(c==1) X @ q[1], c[1]
julia> c = push!(Circuit(), MeasureReset(), 1, 1)
1-qubit circuit with 1 instructions:
└── MR @ q[1], c[1]
julia> push!(c, MeasureReset(), 3, 4)
3-qubit circuit with 2 instructions:
├── MR @ q[1], c[1]
└── MR @ q[3], c[4]
MimiqCircuitsBase.MeasureResetX
— TypeMeasureResetX()
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
, MeasureResetY
, IfStatement
, GateH
.
Examples
julia> MeasureResetX()
MRX
julia> decompose(MeasureResetX())
1-qubit circuit with 3 instructions:
├── H @ q[1]
├── MR @ q[1], c[1]
└── H @ q[1]
julia> c = push!(Circuit(), MeasureResetX(), 1, 1)
1-qubit circuit with 1 instructions:
└── MRX @ q[1], c[1]
julia> push!(c, MeasureResetX(), 3, 4)
3-qubit circuit with 2 instructions:
├── MRX @ q[1], c[1]
└── MRX @ q[3], c[4]
MimiqCircuitsBase.MeasureResetY
— TypeMeasureResetY()
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 aclso MeasureResetX
, MeasureReset
, IfStatement
, GateHYZ
.
Examples
julia> MeasureResetY()
MRY
julia> decompose(MeasureResetY())
1-qubit circuit with 3 instructions:
├── HYZ @ q[1]
├── MR @ q[1], c[1]
└── HYZ @ q[1]
julia> c = push!(Circuit(), MeasureResetY(), 1, 1)
1-qubit circuit with 1 instructions:
└── MRY @ q[1], c[1]
julia> push!(c, MeasureResetY(), 3, 4)
3-qubit circuit with 2 instructions:
├── MRY @ q[1], c[1]
└── MRY @ q[3], c[4]
MimiqCircuitsBase.MeasureResetZ
— TypeMeasureResetZ()
This operation is an alias for MeasureReset
Operation.
MimiqCircuitsBase.Reset
— TypeReset()
Quantum operation that resets the status of one qubit to the $\ket{0}$ state.
Examples
julia> Reset()
Reset
julia> c = push!(Circuit(), Reset, 1)
1-qubit circuit with 1 instructions:
└── Reset @ q[1]
julia> push!(c, Reset(), 3)
3-qubit circuit with 2 instructions:
├── Reset @ q[1]
└── Reset @ q[3]
MimiqCircuitsBase.ResetX
— TypeResetX
Quantum operation that resets the status of one qubit to $\ket{+} = (\ket{0}+\ket{1})/\sqrt{2}$, the +1 eigenstate of the X gate.
This operation is equivalent to the sequence Reset
, GateH
.
See also Reset
, Operation
, Measure
.
Examples
julia> ResetX()
ResetX
julia> decompose(ResetX())
1-qubit circuit with 3 instructions:
├── H @ q[1]
├── Reset @ q[1]
└── H @ q[1]
julia> c = push!(Circuit(), ResetX, 1)
1-qubit circuit with 1 instructions:
└── ResetX @ q[1]
julia> push!(c, ResetX(), 3)
3-qubit circuit with 2 instructions:
├── ResetX @ q[1]
└── ResetX @ q[3]
MimiqCircuitsBase.ResetY
— TypeResetY
Quantum operation that resets the status of one qubit to $\ket{y+} = (\ket{0}+i\ket{1})/\sqrt{2}$, the +1 eigenstate of the Y gate.
This operation is equivalent to the sequence Reset
, GateH
, GateS
.
See also Reset
, Operation
, Measure
.
Examples
julia> ResetY()
ResetY
julia> decompose(ResetY())
1-qubit circuit with 3 instructions:
├── HYZ @ q[1]
├── Reset @ q[1]
└── HYZ @ q[1]
julia> c = push!(Circuit(), ResetY, 1)
1-qubit circuit with 1 instructions:
└── ResetY @ q[1]
julia> push!(c, ResetY(), 3)
3-qubit circuit with 2 instructions:
├── ResetY @ q[1]
└── ResetY @ q[3]
MimiqCircuitsBase.ResetZ
— TypeResetZ()
See Reset
.
No-ops
MimiqCircuitsBase.Barrier
— TypeBarrier(numqubits)
No-op operation that does not affect the quantum state or the execution of a circuit, but prevents compression or optimization across it.
Examples
julia> Barrier(1)
Barrier
julia> Barrier(2)
Barrier
julia> c = push!(Circuit(), Barrier(1), 1)
1-qubit circuit with 1 instructions:
└── Barrier @ q[1]
julia> push!(c, Barrier(1), 1:3)
3-qubit circuit with 4 instructions:
├── Barrier @ q[1]
├── Barrier @ q[1]
├── Barrier @ q[2]
└── Barrier @ q[3]
julia> push!(c, Barrier(3), 1,2,3)
3-qubit circuit with 5 instructions:
├── Barrier @ q[1]
├── Barrier @ q[1]
├── Barrier @ q[2]
├── Barrier @ q[3]
└── Barrier @ q[1:3]
Others
MimiqCircuitsBase.AbstractAnnotation
— TypeAbstractAnnotation{N, M, L} <: Operation{N, M, L}
An abstract type representing a general annotation operation for use in quantum circuits. This type supports annotations that are not strictly quantum operations but may carry metadata or extra circuit information.
MimiqCircuitsBase.Detector
— TypeDetector{N}(N::Integer, notes::AbstractVector)
An annotation class representing a detector in a quantum circuit. The Detector
checks the parity of measurement results over N
classical bits, where the parity should be deterministic under noiseless execution.
Detector monitors the results of a specific set of measurements and verifies that their combined parity (even or odd) remains consistent. This consistency is expected under ideal, noiseless conditions. If noise or errors disrupt the circuit, the Detector can identify this because the parity will change unexpectedly, signaling a potential error in the measurement outcomes. This helps in error detection by revealing inconsistencies that arise due to unintended disturbances.
See Also QubitCoordinates
, ShiftCoordinates
, or Tick
Arguments
N::Integer
: The number of classical bits.notes::AbstractVector
: A vector of floating-point values that contain measurement notes.
Throws
ArgumentError
: IfN
is zero or negative.
Examples
julia> detector = Detector(2, [1.0, 0.5])
Detector(1.0, 0.5)
julia> c = Circuit()
empty circuit
julia> push!(c,detector,1,2)
0-qubit circuit with 1 instructions:
└── Detector(1.0,0.5) @ c[1:2]
MimiqCircuitsBase.ObservableInclude
— TypeObservableInclude{N}(N::Integer, notes::AbstractVector)
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 QubitCoordinates
, Detector
, or Tick
Arguments
N::Integer
: The number of classical bits observed in this logical observable.notes::AbstractVector
: A vector of integers identifying measurement records.
Throws
ArgumentError
: IfN
is zero or negative.
Examples
julia> obs_include = ObservableInclude(2, [1, 2])
ObservableInclude(1, 2)
julia> c = Circuit()
empty circuit
julia> push!(c, obs_include,1,2)
0-qubit circuit with 1 instructions:
└── ObservableInclude(1,2) @ c[1:2]
MimiqCircuitsBase.QubitCoordinates
— TypeQubitCoordinates(coordinates...)
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 Detector
, ShiftCoordinates
, or Tick
Arguments
coordinates
: A variable number of floating-point values representing the coordinates of the qubit.
Examples
julia> coords = QubitCoordinates(0.0, 1.0)
QubitCoordinates(0.0, 1.0)
julia> c = Circuit()
empty circuit
julia> push!(c,coords,1)
1-qubit circuit with 1 instructions:
└── QubitCoordinates(0.0,1.0) @ q[1]
MimiqCircuitsBase.ShiftCoordinates
— TypeShiftCoordinates(coordinates...)
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 QubitCoordinates
, ShiftCoordinates
, or Tick
Arguments
coordinates
: A variable number of floating-point values representing the shift offsets for each coordinate.
Examples
julia> shift = ShiftCoordinates(1.0, 2.0)
ShiftCoordinates(1.0, 2.0)
julia> c = Circuit()
empty circuit
julia> push!(c, shift)
0-qubit circuit with 1 instructions:
└── ShiftCoordinates(1.0,2.0)
MimiqCircuitsBase.Tick
— TypeTick()
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.
See Also QubitCoordinates
, ShiftCoordinates
, or Detector
Examples
julia> tick = Tick()
Tick()
julia> c = Circuit()
empty circuit
julia> push!(c, tick)
0-qubit circuit with 1 instructions:
└── Tick()