Portuguese, Brazilian
Idiomas
English
Japanese
German
Korean
Portuguese, Brazilian
French
Shortcuts

Nota

Esta página foi gerada, a partir do tutorials/simulators/3_building_noise_models.ipynb.

Execute interativamente no IBM Quantum lab.

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.providers.aer import AerSimulator
from qiskit.tools.visualization import plot_histogram

# Import from Qiskit Aer noise module
from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.aer.noise import QuantumError, ReadoutError
from qiskit.providers.aer.noise import pauli_error
from qiskit.providers.aer.noise import depolarizing_error
from qiskit.providers.aer.noise import 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:

  1. A classe NoiseModel que armazena um modelo de ruído usado para simulação ruidosa.

  2. 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.

  3. 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

kraus_error

um canal de erro CPTP de n qubits geral dado como uma lista de matrizes de Kraus \([K_0, ...]\).

mixed_unitary_error

um erro unitário misto de n qubits dado como uma lista de matrizes unitárias e probabilidades \([(U_0, p_0),...]\).

coherent_unitary_error

um erro unitário coerente de n qubits dado como uma única matriz unitária \(U\).

pauli_error

um canal de erro Pauli de n qubits (unitária mista) dado como uma lista de Pauli’s e probabilidades \([(P_0, p_0),...]\)

depolarizing_error

um canal de erro de despolarização de n qubits parametrizado por uma probabilidade de despolarização \(p\).

reset_error

a single-qubit reset error parameterized by a probabilities \(p_0, p_1\) of resetting to the \(|0\rangle\), \(|1\rangle\) state.

thermal_relaxation_error

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\).

phase_amplitude_damping_error

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\).

amplitude_damping_error

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\).

phase_damping_error

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, QasmQobjInstructions = [[{'name': 'x', 'qubits': [0]}]
  P(1) = 0.95, QasmQobjInstructions = [[{'name': 'id', 'qubits': [0]}]
QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.05, QasmQobjInstructions = [[{'name': 'z', 'qubits': [0]}]
  P(1) = 0.95, QasmQobjInstructions = [[{'name': 'id', 'qubits': [0]}]
[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, QasmQobjInstructions = [[{'name': 'x', 'qubits': [0]}, {'name': 'z', 'qubits': [0]}]
  P(1) = 0.0475, QasmQobjInstructions = [[{'name': 'x', 'qubits': [0]}]
  P(2) = 0.0475, QasmQobjInstructions = [[{'name': 'z', 'qubits': [0]}]
  P(3) = 0.9025, QasmQobjInstructions = [[{'name': 'id', 'qubits': [0]}]
[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, QasmQobjInstructions = [[{'name': 'x', 'qubits': [0]}, {'name': 'z', 'qubits': [1]}]
  P(1) = 0.0475, QasmQobjInstructions = [[{'name': 'z', 'qubits': [1]}]
  P(2) = 0.0475, QasmQobjInstructions = [[{'name': 'x', 'qubits': [0]}]
  P(3) = 0.9025, QasmQobjInstructions = [[{'name': 'id', 'qubits': [1]}]

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],
        [ 0.00000000e+00+0.j,  9.74679434e-01+0.j]],

       [[ 0.00000000e+00+0.j,  2.23606798e-01+0.j],
        [ 2.23606798e-01+0.j, -4.96506831e-17+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) = 0.04999999999999995, QasmQobjInstructions = [[{'name': 'x', 'qubits': [0]}]
  P(1) = 0.9500000000000002, QasmQobjInstructions = [[{'name': 'id', 'qubits': [0]}]
[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

Ao adicionar um erro quântico, a um modelo de ruído, devemos especificar o tipo de instrução que ele atua sobre, e em quais qubits aplicá-lo. Há três casos para erros quânticos:

  1. Erro quântico em todos qubits

  2. Erro quântico de qubit específico

  3. Erro quântico não local

Erro quântico em todos qubits

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', 'u1', 'u2', 'u3']
  Instructions with noise: ['u3', 'u2', 'u1']
  All-qubits errors: ['u1', 'u2', 'u3']

Erro quântico de qubit específico

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', 'u1', 'u2', 'u3']
  Instructions with noise: ['u3', 'u2', 'u1']
  Qubits with noise: [0]
  Specific qubit errors: [('u1', [0]), ('u2', [0]), ('u3', [0])]

Erro quântico de qubit não local

Isto aplica um erro a um conjunto específico de qubits de ruído, após qualquer ocorrência de uma instrução, agindo sobre um conjunto específico de qubits de porta.

It is added as noise_model.add_nonlocal_quantum_error(error, instructions, instr_qubits, error_qubits):

[11]:
# Create an empty noise model
noise_model = NoiseModel()

# Add depolarizing error on qubit 2 forall single qubit u1, u2, u3 gates on qubit 0
error = depolarizing_error(0.05, 1)
noise_model.add_nonlocal_quantum_error(error, ['u1', 'u2', 'u3'], [0], [2])

# Print noise model info
print(noise_model)
NoiseModel:
  Basis gates: ['cx', 'id', 'u1', 'u2', 'u3']
  Instructions with noise: ['u3', 'u2', 'u1']
  Qubits with noise: [0, 2]
  Non-local specific qubit errors: [('u1', [0], [2]), ('u2', [0], [2]), ('u3', [0], [2])]

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:

[12]:
# 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

[13]:
# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))
[13]:
../../_images/tutorials_simulators_3_building_noise_models_26_0.png

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.

[14]:
# 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', 'u1', 'u2', 'u3']
  Instructions with noise: ['reset', 'u3', 'cx', 'u2', 'u1', 'measure']
  All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']

Executando a simulação de ruído

[15]:
# 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)
[15]:
../../_images/tutorials_simulators_3_building_noise_models_30_0.png

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.

[16]:
# 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', 'u2', 'u3']
  Instructions with noise: ['reset', 'cx', 'u3', 'u2', 'measure']
  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

[17]:
# 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)
[17]:
../../_images/tutorials_simulators_3_building_noise_models_34_0.png
[18]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.25.0
Terra0.17.0
Aer0.8.0
Ignis0.6.0
Aqua0.9.0
IBM Q Provider0.12.2
System information
Python3.7.7 (default, May 6 2020, 04:59:01) [Clang 4.0.1 (tags/RELEASE_401/final)]
OSDarwin
CPUs6
Memory (Gb)32.0
Fri Apr 02 12:05:34 2021 EDT

This code is a part of Qiskit

© Copyright IBM 2017, 2021.

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.

[ ]: