Nota
Esta página foi gerada, a partir do tutorials/simulators/3_building_noise_models.ipynb.
Construindo Modelos de Ruído¶
Introdução¶
Este notebook apresenta como utilizar o módulo noise
do Qiskit Aer, para construir modelos de ruído personalizados para simulações ruidosas.
[1]:
import numpy as np
from qiskit import QuantumCircuit, transpile
from qiskit.quantum_info import Kraus, SuperOp
from qiskit_aer import AerSimulator
from qiskit.tools.visualization import plot_histogram
# Import from Qiskit Aer noise module
from qiskit_aer.noise import (NoiseModel, QuantumError, ReadoutError,
pauli_error, depolarizing_error, thermal_relaxation_error)
Módulo de Ruído do Qiskit Aer¶
O módulo noise
do Qiskit Aer contém classes Python para a construção de modelos de ruído personalizados para simulação. Há três classes principais:
A classe
NoiseModel
que armazena um modelo de ruído usado para simulação ruidosa.A classe
QuantumError
, que descreve os erros de porta CPTP. Esses podem ser aplicados:Depois de instruções gate ou reset
Antes de instruções measure.
A classe
ReadoutError
que descreve erros de leitura clássicos.
Erros Quânticos¶
Em vez de lidar com o objeto QuantumError
, diretamente, muitas funções auxiliares existem para gerar, automaticamente, um tipo específico de erro quântico parametrizado. Estes estão contidos no módulo noise
e incluem funções para muitos tipos de erros comuns utilizados na pesquisa de computação quântica. Os nomes das funções e o tipo de erro que elas retornam são:
Função de erro padrão |
Detalhes |
---|---|
|
um canal de erro CPTP de n qubits geral dado como uma lista de matrizes de Kraus \([K_0, ...]\). |
|
um erro unitário misto de n qubits dado como uma lista de matrizes unitárias e probabilidades \([(U_0, p_0),...]\). |
|
um erro unitário coerente de n qubits dado como uma única matriz unitária \(U\). |
|
an n-qubit Pauli error channel (mixed unitary) given as a list of Pauli’s and probabilities \([(P_0, p_0),...]\) |
|
um canal de erro de despolarização de n qubits parametrizado por uma probabilidade de despolarização \(p\). |
|
Erro de reset de um qubit-único (um estado) parametrizado por probabilidades \(p_0, p_1\) de resetar para o estado \(|0\rangle\), \(|1\rangle\). |
|
um canal de relaxação térmica de um único qubit parametrizado por constantes de tempo de relaxação \(T_1\), \(T_2\), tempo de porta \(t\), e população térmica do estado excitado \(p_1\). |
|
Um canal de erro de amortecimento de fase combinada e amplitude generalizada de um único qubit dado por um parâmetro de amortecimento de amplitude \(\lambda\), um parâmetro de amortecimento de fase \(\gamma\), e uma população térmica do estado excitado \(p_1\). |
|
Um canal de erro de amortecimento de amplitude generalizada de um único qubit dado por um parâmetro de amortecimento de amplitude \(\lambda\), e uma população térmica de estado excitado \(p_1\). |
|
Um canal de erro de amortecimento de fase de um único qubit, dado por um parâmetro de amortecimento de fase \(\gamma\) |
Combinando erros quânticos¶
As instâncias de QuantumError
podem ser combinadas usando a composição, o produto tensorial e a expansão tensorial (produto tensorial de ordem inversa) para produzir o novos QuantumErrors
como:
Composição: \(\cal{E}(\rho)=\cal{E_2}(\cal{E_1}(\rho))\) como
error = error1.compose(error2)
Produto tensorial: \(\cal{E}(\rho) =(\cal{E_1}\otimes\cal{E_2})(\rho)\) como
error error1.tensor(error2)
Produto de expansão: \(\cal{E}(\rho) =(\cal{E_2}\otimes\cal{E_1})(\rho)\) as
error error1.expand(error2)
Exemplo¶
Por exemplo para construir um erro de inversão de bit de um único qubit de 5%:
[2]:
# Construct a 1-qubit bit-flip and phase-flip errors
p_error = 0.05
bit_flip = pauli_error([('X', p_error), ('I', 1 - p_error)])
phase_flip = pauli_error([('Z', p_error), ('I', 1 - p_error)])
print(bit_flip)
print(phase_flip)
QuantumError on 1 qubits. Noise circuits:
P(0) = 0.05, Circuit =
┌───┐
q: ┤ X ├
└───┘
P(1) = 0.95, Circuit =
┌───┐
q: ┤ I ├
└───┘
QuantumError on 1 qubits. Noise circuits:
P(0) = 0.05, Circuit =
┌───┐
q: ┤ Z ├
└───┘
P(1) = 0.95, Circuit =
┌───┐
q: ┤ I ├
└───┘
[3]:
# Compose two bit-flip and phase-flip errors
bitphase_flip = bit_flip.compose(phase_flip)
print(bitphase_flip)
QuantumError on 1 qubits. Noise circuits:
P(0) = 0.0025000000000000005, Circuit =
┌───┐┌───┐
q: ┤ X ├┤ Z ├
└───┘└───┘
P(1) = 0.0475, Circuit =
┌───┐┌───┐
q: ┤ X ├┤ I ├
└───┘└───┘
P(2) = 0.0475, Circuit =
┌───┐┌───┐
q: ┤ I ├┤ Z ├
└───┘└───┘
P(3) = 0.9025, Circuit =
┌───┐┌───┐
q: ┤ I ├┤ I ├
└───┘└───┘
[4]:
# Tensor product two bit-flip and phase-flip errors with
# bit-flip on qubit-0, phase-flip on qubit-1
error2 = phase_flip.tensor(bit_flip)
print(error2)
QuantumError on 2 qubits. Noise circuits:
P(0) = 0.0025000000000000005, Circuit =
┌───┐
q_0: ┤ X ├
├───┤
q_1: ┤ Z ├
└───┘
P(1) = 0.0475, Circuit =
┌───┐
q_0: ┤ I ├
├───┤
q_1: ┤ Z ├
└───┘
P(2) = 0.0475, Circuit =
┌───┐
q_0: ┤ X ├
├───┤
q_1: ┤ I ├
└───┘
P(3) = 0.9025, Circuit =
┌───┐
q_0: ┤ I ├
├───┤
q_1: ┤ I ├
└───┘
Convertendo para e, a partir de operadores QuantumChannel¶
Podemos, também, converter em ambas as direções entre objetos QuantumError
no Qiskit Aer e objetos QuantumChannel
no Qiskit Terra.
[5]:
# Convert to Kraus operator
bit_flip_kraus = Kraus(bit_flip)
print(bit_flip_kraus)
Kraus([[[ 9.74679434e-01+0.j, 0.00000000e+00+0.j],
[-1.20234617e-16+0.j, 9.74679434e-01+0.j]],
[[ 2.62045272e-16+0.j, 2.23606798e-01+0.j],
[ 2.23606798e-01+0.j, -2.84112242e-16+0.j]]],
input_dims=(2,), output_dims=(2,))
[6]:
# Convert to Superoperator
phase_flip_sop = SuperOp(phase_flip)
print(phase_flip_sop)
SuperOp([[1. +0.j, 0. +0.j, 0. +0.j, 0. +0.j],
[0. +0.j, 0.9+0.j, 0. +0.j, 0. +0.j],
[0. +0.j, 0. +0.j, 0.9+0.j, 0. +0.j],
[0. +0.j, 0. +0.j, 0. +0.j, 1. +0.j]],
input_dims=(2,), output_dims=(2,))
[7]:
# Convert back to a quantum error
print(QuantumError(bit_flip_kraus))
# Check conversion is equivalent to original error
QuantumError(bit_flip_kraus) == bit_flip
QuantumError on 1 qubits. Noise circuits:
P(0) = 1.0, Circuit =
┌───────┐
q: ┤ kraus ├
└───────┘
[7]:
True
Erro de Leitura¶
Erros de leitura clássicos são especificados por uma lista de vetores de probabilidade de atribuição \(P(A|B)\):
\(A\) é o valor do bit clássico gravado
\(B\) é o valor verdadeiro do bit retornado da medição
Por exemplo, para 1 qubit: $ P(A|B) = [P(A|0), P(A|1)]$.
[8]:
# Measurement miss-assignement probabilities
p0given1 = 0.1
p1given0 = 0.05
ReadoutError([[1 - p1given0, p1given0], [p0given1, 1 - p0given1]])
[8]:
ReadoutError([[0.95 0.05]
[0.1 0.9 ]])
Erros de leitura também podem ser combinados usando: compose
, tensor
e expand
, como com os erros quânticos.
Adicionando erros a um modelo de ruído¶
When adding a quantum error to a noise model we must specify the type of instruction that it acts on, and what qubits to apply it to. There are two cases for Quantum Errors:
Erro quântico em todos qubits
Erro quântico de qubit específico
1. All-qubit quantum error¶
Isto aplica o mesmo erro, para qualquer ocorrência de uma instrução, independentemente, de quais qubits ele atua.
Ele é adicionado como noise_model.add_all_qubit_quantum_error(error, instructions)
:
[9]:
# Create an empty noise model
noise_model = NoiseModel()
# Add depolarizing error to all single qubit u1, u2, u3 gates
error = depolarizing_error(0.05, 1)
noise_model.add_all_qubit_quantum_error(error, ['u1', 'u2', 'u3'])
# Print noise model info
print(noise_model)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u3', 'u2', 'u1']
All-qubits errors: ['u1', 'u2', 'u3']
2. Specific qubit quantum error¶
Isto aplica o erro, a qualquer ocorrência de uma instrução atuando em uma lista especificada de qubits. Observe que a ordem dos qubits importa: Para uma porta de 2 qubits um erro aplicado aos qubits [0, 1] é diferente de um aplicado aos qubits [1 0] por exemplo.
É adicionado como noise_model.add_quantum_error(error, instructions, qubits)
:
[10]:
# Create an empty noise model
noise_model = NoiseModel()
# Add depolarizing error to all single qubit u1, u2, u3 gates on qubit 0 only
error = depolarizing_error(0.05, 1)
noise_model.add_quantum_error(error, ['u1', 'u2', 'u3'], [0])
# Print noise model info
print(noise_model)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['u3', 'u2', 'u1']
Qubits with noise: [0]
Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]
Note on non-local qubit quantum error¶
NoiseModel
does not support addition of non-local qubit quantum errors. They should be handled outside of NoiseModel
. That suggests you should write your own transpiler pass (TransformationPass
) and run the pass just before running the simulator if you need to insert your quantum errors into your circuit under your own conditions. See noise.passes.LocalNoisePass
for example of how to implement such a transpiler pass.
Executando uma simulação ruidosa com um modelo de ruído¶
The command AerSimulator(noise_model=noise_model)
returns a simulator configured to the given noise model. In addition to setting the simulator’s noise model, it also overrides the simulator’s basis gates, according to the gates of the noise model.
Exemplos de Modelo de Ruído¶
Vamos, agora, dar alguns exemplos de modelos de ruído. Para as nossas demonstrações, utilizaremos um circuito de teste simples, gerando um estado GHZ de n qubits:
[11]:
# System Specification
n_qubits = 4
circ = QuantumCircuit(n_qubits)
# Test Circuit
circ.h(0)
for qubit in range(n_qubits - 1):
circ.cx(qubit, qubit + 1)
circ.measure_all()
print(circ)
┌───┐ ░ ┌─┐
q_0: ┤ H ├──■─────────────░─┤M├─────────
└───┘┌─┴─┐ ░ └╥┘┌─┐
q_1: ─────┤ X ├──■────────░──╫─┤M├──────
└───┘┌─┴─┐ ░ ║ └╥┘┌─┐
q_2: ──────────┤ X ├──■───░──╫──╫─┤M├───
└───┘┌─┴─┐ ░ ║ ║ └╥┘┌─┐
q_3: ───────────────┤ X ├─░──╫──╫──╫─┤M├
└───┘ ░ ║ ║ ║ └╥┘
meas: 4/════════════════════════╩══╩══╩══╩═
0 1 2 3
Simulação Ideal¶
[12]:
# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))
[12]:

Exemplo de Ruído 1: Modelo básico de ruído de erro de inversão de bit¶
Vamos considerar um simples exemplo de modelo de ruído de brinquedo comum na pesquisa de teoria da informação quântica:
Ao aplicar uma porta de um único qubit, inverte o estado do qubit com probabilidade
p_gate1
.Ao aplicar uma porta de 2 qubits, aplica erros de um único qubit para cada qubit.
Ao resetar um qubit, faça-o para 1 em vez de 0 com probabilidade
p_reset
.Ao medir um qubit, inverte o estado do qubit com probabilidade
p_meas
.
[13]:
# Example error probabilities
p_reset = 0.03
p_meas = 0.1
p_gate1 = 0.05
# QuantumError objects
error_reset = pauli_error([('X', p_reset), ('I', 1 - p_reset)])
error_meas = pauli_error([('X',p_meas), ('I', 1 - p_meas)])
error_gate1 = pauli_error([('X',p_gate1), ('I', 1 - p_gate1)])
error_gate2 = error_gate1.tensor(error_gate1)
# Add errors to noise model
noise_bit_flip = NoiseModel()
noise_bit_flip.add_all_qubit_quantum_error(error_reset, "reset")
noise_bit_flip.add_all_qubit_quantum_error(error_meas, "measure")
noise_bit_flip.add_all_qubit_quantum_error(error_gate1, ["u1", "u2", "u3"])
noise_bit_flip.add_all_qubit_quantum_error(error_gate2, ["cx"])
print(noise_bit_flip)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
Instructions with noise: ['reset', 'measure', 'u3', 'u1', 'cx', 'u2']
All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']
Executando a simulação de ruído¶
[14]:
# Create noisy simulator backend
sim_noise = AerSimulator(noise_model=noise_bit_flip)
# Transpile circuit for noisy basis gates
circ_tnoise = transpile(circ, sim_noise)
# Run and get counts
result_bit_flip = sim_noise.run(circ_tnoise).result()
counts_bit_flip = result_bit_flip.get_counts(0)
# Plot noisy output
plot_histogram(counts_bit_flip)
[14]:

Exemplo 2: relaxamento térmico T1/T2¶
Agora, considere um modelo de erro mais realista, baseado na relaxação térmica com o ambiente do qubit: * Cada qubit é parametrizado por uma constante de tempo de relaxação térmica \(T_1\) e uma constante de tempo de desfasagem \(T_2\). * Observe que devemos ter \(T_2 \le 2 T_1\). * As taxas de erro nas instruções são determinadas pelos tempos de porta e pelos valores \(T_1\), \(T_2\) do qubit.
[15]:
# T1 and T2 values for qubits 0-3
T1s = np.random.normal(50e3, 10e3, 4) # Sampled from normal distribution mean 50 microsec
T2s = np.random.normal(70e3, 10e3, 4) # Sampled from normal distribution mean 50 microsec
# Truncate random T2s <= T1s
T2s = np.array([min(T2s[j], 2 * T1s[j]) for j in range(4)])
# Instruction times (in nanoseconds)
time_u1 = 0 # virtual gate
time_u2 = 50 # (single X90 pulse)
time_u3 = 100 # (two X90 pulses)
time_cx = 300
time_reset = 1000 # 1 microsecond
time_measure = 1000 # 1 microsecond
# QuantumError objects
errors_reset = [thermal_relaxation_error(t1, t2, time_reset)
for t1, t2 in zip(T1s, T2s)]
errors_measure = [thermal_relaxation_error(t1, t2, time_measure)
for t1, t2 in zip(T1s, T2s)]
errors_u1 = [thermal_relaxation_error(t1, t2, time_u1)
for t1, t2 in zip(T1s, T2s)]
errors_u2 = [thermal_relaxation_error(t1, t2, time_u2)
for t1, t2 in zip(T1s, T2s)]
errors_u3 = [thermal_relaxation_error(t1, t2, time_u3)
for t1, t2 in zip(T1s, T2s)]
errors_cx = [[thermal_relaxation_error(t1a, t2a, time_cx).expand(
thermal_relaxation_error(t1b, t2b, time_cx))
for t1a, t2a in zip(T1s, T2s)]
for t1b, t2b in zip(T1s, T2s)]
# Add errors to noise model
noise_thermal = NoiseModel()
for j in range(4):
noise_thermal.add_quantum_error(errors_reset[j], "reset", [j])
noise_thermal.add_quantum_error(errors_measure[j], "measure", [j])
noise_thermal.add_quantum_error(errors_u1[j], "u1", [j])
noise_thermal.add_quantum_error(errors_u2[j], "u2", [j])
noise_thermal.add_quantum_error(errors_u3[j], "u3", [j])
for k in range(4):
noise_thermal.add_quantum_error(errors_cx[j][k], "cx", [j, k])
print(noise_thermal)
NoiseModel:
Basis gates: ['cx', 'id', 'rz', 'sx', 'u2', 'u3']
Instructions with noise: ['reset', 'measure', 'u3', 'cx', 'u2']
Qubits with noise: [0, 1, 2, 3]
Specific qubit errors: [('reset', (0,)), ('reset', (1,)), ('reset', (2,)), ('reset', (3,)), ('measure', (0,)), ('measure', (1,)), ('measure', (2,)), ('measure', (3,)), ('u2', (0,)), ('u2', (1,)), ('u2', (2,)), ('u2', (3,)), ('u3', (0,)), ('u3', (1,)), ('u3', (2,)), ('u3', (3,)), ('cx', (0, 0)), ('cx', (0, 1)), ('cx', (0, 2)), ('cx', (0, 3)), ('cx', (1, 0)), ('cx', (1, 1)), ('cx', (1, 2)), ('cx', (1, 3)), ('cx', (2, 0)), ('cx', (2, 1)), ('cx', (2, 2)), ('cx', (2, 3)), ('cx', (3, 0)), ('cx', (3, 1)), ('cx', (3, 2)), ('cx', (3, 3))]
Executando a simulação de ruído¶
[16]:
# Run the noisy simulation
sim_thermal = AerSimulator(noise_model=noise_thermal)
# Transpile circuit for noisy basis gates
circ_tthermal = transpile(circ, sim_thermal)
# Run and get counts
result_thermal = sim_thermal.run(circ_tthermal).result()
counts_thermal = result_thermal.get_counts(0)
# Plot noisy output
plot_histogram(counts_thermal)
[16]:

[17]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.24.0.dev0+dba2eff |
qiskit-aer | 0.11.2 |
qiskit-ibmq-provider | 0.19.2 |
qiskit | 0.40.0 |
System information | |
Python version | 3.8.11 |
Python compiler | Clang 12.0.5 (clang-1205.0.22.11) |
Python build | default, Jul 27 2021 10:46:38 |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 64.0 |
Tue Feb 07 10:30:00 2023 JST |
This code is a part of Qiskit
© Copyright IBM 2017, 2023.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.