Noise
MimiqCircuitsBase.add_noise!
— Methodadd_noise!(c, g, noise; before=false, parallel=false)
Add a noise operation noise
to every operation g
in the circuit c
.
The noise operation noise
can be a Kraus channel or a gate and will act on the same qubits as the operation g
it is being added to.
The operations g
and noise
have to act on the same number of qubits.
Arguments
c
: Circuit.g
: Operation to which noise will be added.noise
: Kraus channel or gate that will be added to each operationg
.before
: (optional) Bool, default=false
. Ifbefore
isfalse
then the noise is added right after the operation; if it'strue
it's added right before.parallel
: (optional) Bool, default=false
. Ifparallel
isfalse
then the noise is added immediately after/before the operation. If it'strue
the function identifies blocks of consecutive transversal operations of typeg
and adds after each such block a block of transversal noise operationsnoise
. The result of both should be equivalent, it's only the order of operations that changes.
Returns
The circuit c
with the noise added in place.
Examples
Parallel vs not parallel.
julia> c = push!(Circuit(), GateH(), 1:3);
julia> add_noise!(c, GateH(), AmplitudeDamping(0.2))
3-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]
julia> c = push!(Circuit(), GateH(), 1:3);
julia> add_noise!(c, GateH(), AmplitudeDamping(0.2); parallel=true)
3-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.
julia> c = push!(Circuit(), GateCZ(), 1, 2:4);
julia> add_noise!(c, GateCZ(), Depolarizing2(0.1); parallel=true)
4-qubit circuit with 6 instructions:
├── CZ @ q[1], q[2]
├── Depolarizing(2,0.1) @ q[1:2]
├── CZ @ q[1], q[3]
├── Depolarizing(2,0.1) @ q[1,3]
├── CZ @ q[1], q[4]
└── Depolarizing(2,0.1) @ q[1,4]
The before=true
option is mostly used for Measure
.
julia> c = push!(Circuit(), Measure(), 1:3, 1:3);
julia> add_noise!(c, Measure(), PauliX(0.1); before=true)
3-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]
Unitary gates are added in the same way.
julia> c = push!(Circuit(), GateH(), 1:3);
julia> add_noise!(c, GateH(), GateRX(0.01))
3-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]
MimiqCircuitsBase.add_noise
— Methodadd_noise(c, g, noise; before=false, parallel=false)
Add noise operation noise
to every operation g
in circuit c
.
A copy of c
is created and then noise is added to the copy.
See [add_noise!
] for more information.
MimiqCircuitsBase.sample_mixedunitaries
— Methodsample_mixedunitaries(c; rng, 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, but it can also be used to generate samples of circuits without running them.
See also ismixedunitary
, MixedUnitary
, probabilities
, and unitarygates
.
Arguments
c
: Circuit to be sampled.rng
: (optional) Random number generator.ids
: (optional) Boolean, default=false
. When the selected Kraus operator is an identity it has no effect on the circuit. The parameterids
decides whether to add it to the circuit (ids=true
) or not (
ids=false`; default). Usually, most of the Kraus operators selected will be identity gates.
Returns
A copy of circuit but with every mixed unitary Kraus channel replaced by one of the unitary gates of the channel (or nothing if identity and ids==false
).
Examples
Gates and non-mixed-unitary Kraus channels remain unchanged.
julia> using Random
julia> c = push!(Circuit(), GateH(), 1:3);
julia> push!(c, Depolarizing1(0.5), 1:3);
julia> push!(c, AmplitudeDamping(0.5), 1:3)
3-qubit circuit with 9 instructions:
├── H @ q[1]
├── H @ q[2]
├── H @ q[3]
├── Depolarizing(1,0.5) @ q[1]
├── Depolarizing(1,0.5) @ q[2]
├── Depolarizing(1,0.5) @ q[3]
├── AmplitudeDamping(0.5) @ q[1]
├── AmplitudeDamping(0.5) @ q[2]
└── AmplitudeDamping(0.5) @ q[3]
julia> rng = MersenneTwister(42);
julia> sample_mixedunitaries(c; rng=rng, ids=true)
3-qubit circuit with 9 instructions:
├── H @ q[1]
├── H @ q[2]
├── H @ q[3]
├── Y @ q[1]
├── ID @ q[2]
├── ID @ q[3]
├── AmplitudeDamping(0.5) @ q[1]
├── AmplitudeDamping(0.5) @ q[2]
└── AmplitudeDamping(0.5) @ q[3]
By default identities are not included.
julia> rng = MersenneTwister(42);
julia> sample_mixedunitaries(c; rng=rng)
3-qubit circuit with 7 instructions:
├── H @ q[1]
├── H @ q[2]
├── H @ q[3]
├── Y @ q[1]
├── AmplitudeDamping(0.5) @ q[1]
├── AmplitudeDamping(0.5) @ q[2]
└── AmplitudeDamping(0.5) @ q[3]
Different calls to the function generate different results.
julia> sample_mixedunitaries(c; rng=rng)
3-qubit circuit with 6 instructions:
├── H @ q[1]
├── H @ q[2]
├── H @ q[3]
├── AmplitudeDamping(0.5) @ q[1]
├── AmplitudeDamping(0.5) @ q[2]
└── AmplitudeDamping(0.5) @ q[3]
julia> sample_mixedunitaries(c; rng=rng)
3-qubit circuit with 6 instructions:
├── H @ q[1]
├── H @ q[2]
├── H @ q[3]
├── AmplitudeDamping(0.5) @ q[1]
├── AmplitudeDamping(0.5) @ q[2]
└── AmplitudeDamping(0.5) @ q[3]
MimiqCircuitsBase.ProjectiveNoiseX
— TypeProjectiveNoiseX()
Single qubit projection noise onto a 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
.
See also ProjectiveNoise
, ProjectiveNoiseY
, or ProjectiveNoiseZ
.
MimiqCircuitsBase.ProjectiveNoiseY
— TypeProjectiveNoiseY()
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
.
See also ProjectiveNoise
, ProjectiveNoiseX
, or ProjectiveNoiseZ
.
MimiqCircuitsBase.ProjectiveNoiseZ
— TypeProjectiveNoiseZ()
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
.
See also ProjectiveNoise
, ProjectiveNoiseX
, or ProjectiveNoiseY
.
MimiqCircuitsBase.ProjectiveNoise
— FunctionProjectiveNoise(basis)
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\langle, |1\langle \}$ ($Z$ basis), $\{ |+\langle, |-\langle \}$ ($X$ basis), or $\{ |y+\langle, |y-\langle \}$ (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's loss of information.
Arguments
basis
: Symbol, String or Char that selects the Pauli basis,"X"
,"Y"
, or"Z"
.
Examples
julia> push!(Circuit(), ProjectiveNoise("Z"), 1)
1-qubit circuit with 1 instructions:
└── ProjectiveNoiseZ @ q[1]
The Kraus matrices are given by:
julia> krausmatrices(ProjectiveNoise("X"))
2-element Vector{Matrix{Float64}}:
[0.5 0.5; 0.5 0.5]
[0.5 -0.5; -0.5 0.5]
julia> krausmatrices(ProjectiveNoise("Y"))
2-element Vector{Matrix{ComplexF64}}:
[0.5 + 0.0im 0.0 - 0.5im; 0.0 + 0.5im 0.5 + 0.0im]
[0.5 + 0.0im 0.0 + 0.5im; 0.0 - 0.5im 0.5 + 0.0im]
julia> krausmatrices(ProjectiveNoise("Z"))
2-element Vector{Matrix{Int64}}:
[1 0; 0 0]
[0 0; 0 1]
MimiqCircuitsBase.Kraus
— TypeKraus(E)
Custom $N$ qubit Kraus channel specified by a list of Kraus operators.
A Kraus channel is defined by
\[\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 = I$.
If the Kraus operators 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$. See also GateCustom
.
Currently only 1 and 2-qubit custom Kraus channels are supported.
See also MixedUnitary
, AbstractKrausChannel
.
Arguments
E
: Vector of $2^N \times 2^N$ complex matrices or $N$ qubit operators. Both can be mixed.
Examples
julia> push!(Circuit(), Kraus([[1 0; 0 sqrt(0.9)], [0 sqrt(0.1); 0 0]]), 1)
1-qubit circuit with 1 instructions:
└── Kraus(Operator([1.0 0.0; 0.0 0.948683]), Operator([0.0 0.316228; 0.0 0.0])) @ q[1]
julia> push!(Circuit(), Kraus([Projector0(), Projector1()]), 1)
1-qubit circuit with 1 instructions:
└── Kraus(Projector0(1), Projector1(1)) @ q[1]
julia> push!(Circuit(), Kraus([[1 0; 0 0], Projector1()]), 1)
1-qubit circuit with 1 instructions:
└── Kraus(Operator([1.0 0.0; 0.0 0.0]), Projector1(1)) @ q[1]
julia> @variables x
1-element Vector{Symbolics.Num}:
x
julia> g = Kraus([Projector0(), Projector1(x)])
Kraus(Projector0(1), Projector1(x))
julia> evaluate(g,Dict(x=>1))
Kraus(Projector0(1), Projector1(1))
julia> g = Kraus([[1 0; 0 sqrt(0.9)], [0 sqrt(0.1); 0 x]])
Kraus(Operator([1.0 0.0; 0.0 0.948683]), Operator([0 0.316228; 0 x]))
julia> evaluate(g,Dict(x=>0))
Kraus(Operator([1.0 0.0; 0.0 0.948683]), Operator([0 0.316228; 0 0]))
MimiqCircuitsBase.AbstractKrausChannel
— TypeAbstractKrausChannel{N} <: Operation{N,0,0}
Supertype for all the $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 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$.
See also krausmatrices
, unitarymatrices
, probabilities
.
MimiqCircuitsBase.cumprobabilities
— Methodcumprobabilities(mixedunitarychannel)
Cumulative sum of probabilities of a mixed unitary Kraus channel.
A mixed unitary channel is written as $\sum_k p_k U_k \rho U_k^\dagger$, where $p_k$ are the probabilities.
An error is returned for Kraus channels with ismixedunitary(krauschannel)==false
.
if the Kraus channel is parametric, the cumprobabilities are wrapped in a Symbolics.Num
object. To manipulate expressions use the Symbolics
package.
See also probabilities
, ismixedunitary
.
Examples
julia> cumprobabilities(Depolarizing1(0.1))
4-element Vector{Symbolics.Num}:
0.9
0.9333333333333333
0.9666666666666667
1.0
MimiqCircuitsBase.ismixedunitary
— Methodismixedunitary(krauschannel)
Whether the quantum operation is a mixed unitary channel.
This is the case when all the Kraus operators $E_k$ are proportional to a unitary $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$.
Examples
julia> ismixedunitary(PauliX(0.1))
true
julia> ismixedunitary(AmplitudeDamping(0.1))
false
MimiqCircuitsBase.krausmatrices
— Methodkrausmatrices(krauschannel)
Kraus matrices associated to the given 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 matrices returned by this function.
if the Kraus channel is parametric, the matrix elements are wrapped in a Symbolics.Num
object. To manipulate expressions use the Symbolics
package.
Examples
julia> krausmatrices(AmplitudeDamping(0.1))
2-element Vector{Matrix{Float64}}:
[1.0 0.0; 0.0 0.9486832980505138]
[0.0 0.31622776601683794; 0.0 0.0]
For mixed unitary channels the Kraus matrices are the unitary matrices times the square root of the probabilities.
julia> krausmatrices(PauliX(0.2))
2-element Vector{Matrix{Symbolics.Num}}:
[0.8944271909999159 -0.0; 0.0 0.8944271909999159]
[0.0 0.4472135954999579; 0.4472135954999579 0.0]
MimiqCircuitsBase.krausoperators
— Methodkrausoperators(kraus)
Kraus operators associated to the given Kraus channel.
See also krausmatrices
.
Examples
julia> krausoperators(PauliX(0.2))
2-element Vector{Operator{1}}:
Operator([0.8944271909999159 -0.0; 0.0 0.8944271909999159])
Operator([0.0 0.4472135954999579; 0.4472135954999579 0.0])
julia> krausoperators(AmplitudeDamping(0.1))
2-element Vector{AbstractOperator{1}}:
D(1, 0.9486832980505138)
SigmaMinus(0.31622776601683794)
MimiqCircuitsBase.probabilities
— Methodprobabilities(mixedunitarychannel)
Probabilities of each Kraus operator for mixed unitary Kraus channels.
A mixed unitary channel is written as $\sum_k p_k U_k \rho U_k^\dagger$, where $p_k$ are the probabilities.
An error is returned for Kraus channels with ismixedunitary(krauschannel)==false
.
if the Kraus channel is parametric, the probabilities are wrapped in a Symbolics.Num
object. To manipulate expressions use the Symbolics
package.
See also ismixedunitary
, unitarymatrices
, and krausmatrices
.
Examples
julia> probabilities(PauliX(0.1))
2-element Vector{Symbolics.Num}:
0.9
0.1
MimiqCircuitsBase.squaredkrausoperators
— Methodsquaredkrausoperators(kraus)
Square of of Kraus operators ($O^\dagger O$) associated to the given Kraus channel.
See also krausoperators
.
Examples
julia> squaredkrausoperators(AmplitudeDamping(0.1))
2-element Vector{AbstractOperator{1}}:
D(1, 0.8999999999999999)
P₁(0.1)
MimiqCircuitsBase.unitarygates
— Methodunitarygates(krauschannel)
Unitary gates associated to 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 returned by this function.
An error is returned for Kraus channels with ismixedunitary(krauschannel)==false
.
See also ismixedunitary
, unitarymatrices
, and krausmatrices
.
Examples
julia> unitarygates(PauliNoise([0.9,0.1],["II","XX"]))
2-element Vector{PauliString{2}}:
II
XX
MimiqCircuitsBase.unitarymatrices
— Methodunitarymatrices(mixedunitarychannel)
Unitary matrices associated to 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 matrices.
An error is returned for Kraus channels with ismixedunitary(krauschannel)==false
.
if the Kraus channel is parametric, the matrix elements are wrapped in a Symbolics.Num
object. To manipulate expressions use the Symbolics
package.
See also ismixedunitary
, probabilities
, and krausmatrices
.
Examples
julia> unitarymatrices(PauliX(0.2))
2-element Vector{Matrix}:
[1.0 -0.0; 0.0 1.0]
[0 1; 1 0]
MimiqCircuitsBase.unwrappedcumprobabilities
— Methodunwrappedcumprobabilities(mixedunitarychannel)
Cumulative sum of probabilities associated to the specified mixed unitary Kraus channel without the Symbolics.Num
wrapper.
If any of the noise channel's parameters is symbolic, an error is thrown.
See cumprobabilities
for more information.
julia> unwrappedcumprobabilities(Depolarizing1(0.1))
4-element Vector{Float64}:
0.9
0.9333333333333333
0.9666666666666667
1.0
MimiqCircuitsBase.unwrappedkrausmatrices
— Methodunwrappedkrausmatrices(krauschannel)
Returns the Kraus matrices associated to the specified Kraus channel without the Symbolics.Num
wrapper.
If any of the noise channel's parameters is symbolic, an error is thrown.
See krausmatrices
for more information.
Examples
julia> unwrappedkrausmatrices(AmplitudeDamping(0.1))
2-element Vector{Matrix{Float64}}:
[1.0 0.0; 0.0 0.9486832980505138]
[0.0 0.31622776601683794; 0.0 0.0]
MimiqCircuitsBase.unwrappedprobabilities
— Methodunwrappedprobabilities(mixedunitarychannel)
Probabilities associated to the specified mixed unitary Kraus channel without the Symbolics.Num
wrapper.
If any of the noise channel's parameters is symbolic, an error is thrown.
See probabilities
for more information.
julia> unwrappedprobabilities(PauliX(0.1))
2-element Vector{Float64}:
0.9
0.1
MimiqCircuitsBase.unwrappedunitarymatrices
— Methodunwrappedunitarymatrices(krauschannel)
Returns the unitary Kraus matrices associated to the mixed unitary Kraus channel without the Symbolics.Num
wrapper.
If any of the noise channel's parameters is symbolic, an error is thrown.
See unitarymatrices
for more information.
Examples
julia> unwrappedunitarymatrices(PauliX(0.2))
2-element Vector{Matrix}:
[1.0 -0.0; 0.0 1.0]
[0 1; 1 0]
MimiqCircuitsBase.Amplitude
— TypeAmplitude(bs::BitString)
Operation to get amplitude of a state vector element.
The operation gets the quantum state's amplitude (which is a complex number) corresponding to the state defined by the bitstring bs
in the computational basis and stores it in a z-register.
See BitString
.
Examples
When defining a circuit, only the z-register to store the result needs to be specified.
julia> Amplitude(BitString("001"))
Amplitude(bs"001")
julia> c = push!(Circuit(),Amplitude(BitString("001")), 1)
0-qubit circuit with 1 instructions:
└── Amplitude(bs"001") @ z[1]
MimiqCircuitsBase.DiagonalOp
— TypeDiagonalOp(a,b)
One-qubit diagonal operator.
The corresponding matrix
\[\begin{pmatrix} a & 0\\ 0 & b \end{pmatrix}\]
is parametrized by complex numbers a
and b
.
See also Operator
, Projector0
, Projector1
.
Examples
julia> DiagonalOp(1,0.5)
D(1, 0.5)
julia> push!(Circuit(), ExpectationValue(DiagonalOp(1,0.5)), 1, 2)
1-qubit circuit with 1 instructions:
└── ⟨D(1,0.5)⟩ @ q[1], z[2]
MimiqCircuitsBase.AmplitudeDamping
— TypeAmplitudeDamping(γ)
One-qubit amplitude damping noise channel.
This channel is defined by the Kraus operators
\[E_1 = \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1-\gamma} \end{pmatrix} ,\quad E_2 = \begin{pmatrix} 0 & \sqrt{\gamma} \\ 0 & 0 \end{pmatrix},\]
where $\gamma \in [0,1]$.
Physically, it corresponds to an energy gain/loss process, such as spontaneous emission.
Examples
julia> push!(Circuit(), AmplitudeDamping(0.1), 1)
1-qubit circuit with 1 instructions:
└── AmplitudeDamping(0.1) @ q[1]
MimiqCircuitsBase.GeneralizedAmplitudeDamping
— TypeGeneralizedAmplitudeDamping(p,γ)
One-qubit generalized amplitude damping noise channel.
This channel is defined by the Kraus operators
\[E_1 = \sqrt{p} \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1-\gamma} \end{pmatrix} ,\quad E_2 = \sqrt{p} \begin{pmatrix} 0 & \sqrt{\gamma} \\ 0 & 0 \end{pmatrix} ,\quad E_3 = \sqrt{1-p} \begin{pmatrix} \sqrt{1-\gamma} & 0 \\ 0 & 1 \end{pmatrix} ,\quad E_4 = \sqrt{1-p} \begin{pmatrix} 0 & 0 \\ \sqrt{\gamma} & 0 \end{pmatrix},\]
where $\gamma, p \in [0,1]$.
Physically, it corresponds to a combination of spontaneous emission and spontaneous absorption with probabilities $p$ and $1-p$, respectively.
Examples
julia> push!(Circuit(), GeneralizedAmplitudeDamping(0.1, 0.3), 1)
1-qubit circuit with 1 instructions:
└── GeneralizedAmplitudeDamping(0.1,0.3) @ q[1]
MimiqCircuitsBase.PhaseAmplitudeDamping
— TypePhaseAmplitudeDamping(p,γ,β)
One-qubit phase amplitude damping noise channel.
This channel is defined by:
\[\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}\]
Here, $p, \gamma, \beta \in [0,1]$.
This channel is equivalent to a GeneralizedAmplitudeDamping(p,γ)
channel (see GeneralizedAmplitudeDamping
), followed by a PauliZ(β)
channel (see PauliZ
).
Use krausmatrices
to see a Kraus matrix representation of the channel.
See also AmplitudeDamping
, GeneralizedAmplitudeDamping
, and ThermalNoise
.
Examples
julia> push!(Circuit(), PhaseAmplitudeDamping(0.1, 0.2, 0.3), 1)
1-qubit circuit with 1 instructions:
└── PhaseAmplitudeDamping(0.1,0.2,0.3) @ q[1]
MimiqCircuitsBase.ThermalNoise
— TypeThermalNoise(T₁, T₂, t, nₑ)
One-qubit thermal noise channel.
The thermal noise channel is equivalent to the PhaseAmplitudeDamping
channel, but it is parametrized instead as
\[\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}\]
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})$.
See also PhaseAmplitudeDamping
, AmplitudeDamping
, and GeneralizedAmplitudeDamping
.
Arguments
T₁
: Longitudinal relaxation rate.T₂
: Transversal relaxation rate.t
: Time duration of gate.nₑ
: Excitation fraction when in thermal equilibrium with the environment.
Examples
julia> push!(Circuit(), ThermalNoise(0.5, 0.6, 1.2, 0.3), 1)
1-qubit circuit with 1 instructions:
└── ThermalNoise(0.5,0.6,1.2,0.3) @ q[1]
MimiqCircuitsBase.Depolarizing
— TypeDepolarizing(N,p)
$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 (see [`Paulistring`](@ref)). There is exactly one Kraus operator$E{i>1}$for each distinct combination of Pauli operators$Pi$, except for the$N$-qubit identity$I_N = I\otimes I \otimes I \otimes...``
For example, for one qubit we have 3 operators $P_i \in \{X,Y,Z\}$, and 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 \}$. Use unitarygates
to see this.
This channel is a mixed unitary channel, see ismixedunitary
, and is a special case of PauliNoise
.
See also PauliString
and PauliNoise
.
Arguments
N
: Number of qubits.p
: Probability of error, i.e. of not applying identity.
Examples
Depolarizing channels can be defined for any $N$:
julia> push!(Circuit(), Depolarizing(1, 0.1), 1)
1-qubit circuit with 1 instructions:
└── Depolarizing(1,0.1) @ q[1]
julia> push!(Circuit(), Depolarizing(5, 0.1), 1, 2, 3, 4, 5)
5-qubit circuit with 1 instructions:
└── Depolarizing(5,0.1) @ q[1:5]
For one and two qubits you can use the shorthand notation:
julia> push!(Circuit(), Depolarizing1(0.1), 1)
1-qubit circuit with 1 instructions:
└── Depolarizing(1,0.1) @ q[1]
julia> push!(Circuit(), Depolarizing2(0.1), 1, 2)
2-qubit circuit with 1 instructions:
└── Depolarizing(2,0.1) @ q[1:2]
MimiqCircuitsBase.Depolarizing1
— TypeDepolarizing1(p) Doc TODO
MimiqCircuitsBase.Depolarizing2
— TypeDepolarizing2(p) Doc TODO
MimiqCircuitsBase.PauliNoise
— TypePauliNoise(p, paulistrings)
$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 (see PauliString
) 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.
Arguments
p
: Vector of probabilities that must add up to 1.paulistrings
: Vector of strings, each one of length $N$ and with each character being either"I"
,"X"
,"Y"
, or"Z"
. The number of qubits is equal to $N$.
The vectors p
and paulistrings
must have the same length.
Examples
PauliNoise channels can be defined for any number of qubits, and for any number of Pauli strings.
julia> push!(Circuit(), PauliNoise([0.8, 0.1, 0.1], ["I","X","Y"]), 1)
1-qubit circuit with 1 instructions:
└── PauliNoise((0.8,pauli"I"),(0.1,pauli"X"),(0.1,pauli"Y")) @ q[1]
julia> push!(Circuit(), PauliNoise([0.9, 0.1], ["XY","II"]), 1, 2)
2-qubit circuit with 1 instructions:
└── PauliNoise((0.9,pauli"XY"),(0.1,pauli"II")) @ q[1:2]
julia> push!(Circuit(), PauliNoise([0.5, 0.2, 0.2, 0.1], ["IXIX","XYXY","ZZZZ","IXYZ"]), 1, 2, 3, 4)
4-qubit circuit with 1 instructions:
└── PauliNoise((0.5,pauli"IXIX"),(0.2,pauli"XYXY"),(0.2,pauli"ZZZZ"),(0.1,pauli"IXYZ")) @ q[1:4]
MimiqCircuitsBase.PauliX
— TypePauliX(p)
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 of PauliNoise
.
PauliX(p)
is the same as PauliNoise([1-p,p],["I","X"])
.
Examples
julia> push!(Circuit(), PauliX(0.1), 1)
1-qubit circuit with 1 instructions:
└── PauliX(0.1) @ q[1]
MimiqCircuitsBase.PauliY
— TypePauliY(p)
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 of PauliNoise
.
PauliY(p)
is the same as PauliNoise([1-p,p],["I","Y"])
.
Examples
julia> push!(Circuit(), PauliY(0.1), 1)
1-qubit circuit with 1 instructions:
└── PauliY(0.1) @ q[1]
MimiqCircuitsBase.PauliZ
— TypePauliZ(p)
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 of PauliNoise
.
PauliZ(p)
is the same as PauliNoise([1-p,p],["I","Z"])
.
Examples
julia> push!(Circuit(), PauliZ(0.1), 1)
1-qubit circuit with 1 instructions:
└── PauliZ(0.1) @ q[1]
MimiqCircuitsBase.MixedUnitary
— TypeMixedUnitary(p,U)
Custom $N$ qubit mixed unitary channel specified by a list of unitary gates 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 Kraus
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$. See also GateCustom
.
Currently only 1 and 2-qubit custom MixedUnitary channels are supported.
See also Kraus
, ismixedunitary
, AbstractKrausChannel
, and RescaledGate
.
Arguments
p
: Vector of probabilities, must be positive real numbers and add up to 1.U
: Vector of either complex-valued $2^N \times 2^N$ matrices or unitary gates acting on $N$ qubits. Both can be mixed.
The length of the vectors p
and U
must be equal.
Examples
julia> push!(Circuit(), MixedUnitary([0.9, 0.1], [[1 0; 0 1], [0 1; 1 0]]), 1)
1-qubit circuit with 1 instructions:
└── MixedUnitary((0.9,Custom([1.0 0.0; 0.0 1.0])),(0.1,Custom([0.0 1.0; 1.0 0.0]))) @ q[1]
julia> push!(Circuit(), MixedUnitary([0.8, 0.2], [GateID(), GateRX(0.2)]), 1)
1-qubit circuit with 1 instructions:
└── MixedUnitary((0.8,ID),(0.2,RX(0.2))) @ q[1]
julia> push!(Circuit(), MixedUnitary([0.8, 0.2], [[1 0; 0 1], GateRX(0.2)]), 1)
1-qubit circuit with 1 instructions:
└── MixedUnitary((0.8,Custom([1.0 0.0; 0.0 1.0])),(0.2,RX(0.2))) @ q[1]
julia> @variables x
1-element Vector{Symbolics.Num}:
x
julia> g= MixedUnitary([0.9, x], [[1 0; 0 1], [0 1; 1 0]])
MixedUnitary((0.9, Custom([1.0 0.0; 0.0 1.0])), (x, Custom([0.0 1.0; 1.0 0.0])))
julia> evaluate(g,Dict(x=>.1))
MixedUnitary((0.9, Custom([1.0 0.0; 0.0 1.0])), (0.1, Custom([0.0 1.0; 1.0 0.0])))
julia> g= MixedUnitary([0.9, 0.1], [[1 0; 0 1], [0 1; 1 x]])
MixedUnitary((0.9, Custom([1 0; 0 1])), (0.1, Custom([0 1; 1 x])))
julia> evaluate(g,Dict(x=>0))
MixedUnitary((0.9, Custom([1 0; 0 1])), (0.1, Custom([0 1; 1 0])))
MimiqCircuitsBase.PauliString
— TypePauliString(paulistr)
$N$-qubit tensor product of Pauli operators.
The PauliString gate can represent any $N$-qubit tensor product of Pauli operators of the form
\[P_1 \otimes P_2 \otimes P_3 \otimes \ldots \otimes P_N,\]
where each $P_i \in \{ I, X, Y, Z \}$ is a Pauli operator, including the identity.
See also GateID
, GateX
, GateY
, GateZ
.
Arguments
paulistr
: string of length $N$ where each character is either"I"
,"X"
,"Y"
, or"Z"
. The number of qubits is equal to $N$.
Examples
PauliStrings of any length are supported.
julia> c = push!(Circuit(), PauliString("XX"), 1, 2)
2-qubit circuit with 1 instructions:
└── XX @ q[1:2]
julia> push!(c, PauliString("IXYZZYXI"), 1, 2, 3, 4, 5, 6, 7, 8)
8-qubit circuit with 2 instructions:
├── XX @ q[1:2]
└── IXYZZYXI @ q[1:8]
Decomposition
Decomposes into one-qubit Pauli gates.
julia> decompose(PauliString("XIYZZ"))
5-qubit circuit with 5 instructions:
├── X @ q[1]
├── ID @ q[2]
├── Y @ q[3]
├── Z @ q[4]
└── Z @ q[5]
MimiqCircuitsBase.@pauli_str
— Macromacro pauli_str(s)
pauli""
literal for creating a PauliString
gate.
Examples
julia> pauli"XYYXZ"
XYYXZ