French
Langues
English
Japanese
German
Korean
Portuguese, Brazilian
French
Shortcuts

Note

Cette page a été générée à partir de tutorials/noise/6_repetition_code.ipynb.

Exécuter en mode interactif dans le IBM Quantum lab.

Codes de répétition

Introduction

Dans la correction des erreurs quantiques, nous prenons beaucoup de qubits bruyants (que nous appelons physical qubits) et nous les utilisons pour stocker un nombre plus petit de logical qubits. La procédure de correction des erreurs est conçue pour détecter et corriger les effets du bruit. Cela rend les qubits logiques beaucoup moins bruyants et plus fiables que les qubits physiques à partir desquels ils sont construits.

Le code de répétition est un exemple simple de correction d’erreur quantique, dans lequel un bit logique est stocké plutôt qu’un qubit logique. Une instance donnée du code de répétition est définie par deux nombres, que nous appelons \(d\) et \(T\).

Le paramètre \(d\) détermine le nombre de qubits physiques utilisés. Les informations réelles sur le bit logique sont stockées dans les qubits \(d\) (que nous appellerons code qubits). L’encodage se fait de manière très simple : pour encoder un 0, tous les qubits sont définis dans l’état \(|0\rangle\), pour encoder un 1, ils sont définis à \(|1\rangle\). Pour lire la valeur, vous pouvez juste regarder n’importe quel qubit. Pour le lire d’une manière qui protège contre les erreurs de qubit-uniques, vous pouvez lire tous les qubits et prendre un vote à la majorité.

Ce n’est pas seulement à la lecture que nous pouvons extraire des informations utiles qui nous aideront à corriger les erreurs. Nous pouvons également extraire des informations alors que le bit logique est inactif, ou même lorsqu’il est impliqué dans le calcul.

Comme il s’agit d’un exercice de correction d’erreurs quantiques, nous le ferons d’une manière qui fonctionnerait également pour les qubits logiques. Plus précisément, notre méthode d’extraction d’informations sur les erreurs ne doit pas extraire d’informations concernant les informations logiques stockées. Dans le cas de quantique, cela est nécessaire pour que nous ne perturbions pas les états de superposition des qubits stockés.

Nous allons extraire des informations sur les \(T\) tours de syndrome measurements (mesures du syndrome). Pour le code de répétition, elles sont basées sur le fait que toutes les qubits de code doivent être dans le même état (tous \(|0\rangle\) ou tous \(|1\rangle\)). Toute dérogation est donc une signature d’erreur. Plus précisément, nous imaginons nos \(d\) code qubits assis le long d’une ligne. Nous procéderons alors à une mesure sur chaque paire de qubits de code voisins. Cela nous dira si elles sont identiques ou différentes, sans extraire aucune information sur leurs valeurs.

The implementation of these measurements requires \(d-1\) additional qubits, which we will call link qubits for the repetition code. By performing two CNOTs between the pair of code qubits and a corresponding link qubit, the required information (and only the required information) is placed on the link qubit and can then be measured.

[1]:
from qiskit import *
cq = QuantumRegister(2,'code_qubit')
lq = QuantumRegister(1,'link_qubit')
qc = QuantumCircuit(cq,lq)
qc.cx(cq[0],lq[0])
qc.cx(cq[1],lq[0])
print(qc)

code_qubit_0: |0>──■───────
                   │
code_qubit_1: |0>──┼────■──
                 ┌─┴─┐┌─┴─┐
link_qubit_0: |0>┤ X ├┤ X ├
                 └───┘└───┘

Ici, nous fournissons des outils pour créer et tester les codes de répétition. La première chose à faire est de les importer.

[2]:
from qiskit.ignis.verification.topological_codes import RepetitionCode
from qiskit.ignis.verification.topological_codes import GraphDecoder
from qiskit.ignis.verification.topological_codes import lookuptable_decoding, postselection_decoding

Création d’un code de répétition

La classe repetition_code crée un code pour les valeurs données de \(d\) et \(T\).

[3]:
d = 3
T = 2
code = RepetitionCode(d,T)

Avec cela, nous pouvons inspecter diverses propriétés du code, comme les noms des registres de qubit utilisés pour le code et les qubits de ancilla.

[4]:
code.qubit_registers
[4]:
{'code_qubit', 'link_qubit'}

Ces registres sont aussi des attributs de l’objet repetition_code.

[5]:
code.code_qubit
[5]:
QuantumRegister(3, 'code_qubit')

Vous pouvez également accéder aux circuits quantiques qui implémentent le code. Deux d’entre eux sont donnés: un pour chacune des deux valeurs possibles de bits logiques.

[6]:
for log in ['0','1']:
    print('\n========= logical',log,'=========\n')
    print( code.circuit[log] )

========= logical 0 =========

                      ┌───┐     ┌───┐     ┌─┐           ░ ┌───┐     ┌───┐     »
     link_qubit_0: |0>┤ X ├─────┤ X ├─────┤M├─|0>───────░─┤ X ├─────┤ X ├─────»
                      └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░ └─┬─┘┌───┐└─┬─┘┌───┐»
     link_qubit_1: |0>──┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░───┼──┤ X ├──┼──┤ X ├»
                        │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░   │  └─┬─┘  │  └─┬─┘»
     code_qubit_0: |0>──■────┼────┼────┼───╫───╫────────░───■────┼────┼────┼──»
                             │    │    │   ║   ║        ░        │    │    │  »
     code_qubit_1: |0>───────■────■────┼───╫───╫────────░────────■────■────┼──»
                                       │   ║   ║        ░                  │  »
     code_qubit_2: |0>─────────────────■───╫───╫────────░──────────────────■──»
                                           ║   ║        ░                     »
round_0_link_bit_0: 0 ═════════════════════╩═══╬══════════════════════════════»
                                               ║                              »
round_0_link_bit_1: 0 ═════════════════════════╩══════════════════════════════»
                                                                              »
round_1_link_bit_0: 0 ════════════════════════════════════════════════════════»
                                                                              »
round_1_link_bit_1: 0 ════════════════════════════════════════════════════════»
                                                                              »
        code_bit_0: 0 ════════════════════════════════════════════════════════»
                                                                              »
        code_bit_1: 0 ════════════════════════════════════════════════════════»
                                                                              »
        code_bit_2: 0 ════════════════════════════════════════════════════════»
                                                                              »
«                    ┌─┐           ░
«      link_qubit_0: ┤M├─|0>───────░──────────
«                    └╥┘ ┌─┐       ░
«      link_qubit_1: ─╫──┤M├──|0>──░──────────
«                     ║  └╥┘       ░ ┌─┐
«      code_qubit_0: ─╫───╫────────░─┤M├──────
«                     ║   ║        ░ └╥┘┌─┐
«      code_qubit_1: ─╫───╫────────░──╫─┤M├───
«                     ║   ║        ░  ║ └╥┘┌─┐
«      code_qubit_2: ─╫───╫────────░──╫──╫─┤M├
«                     ║   ║        ░  ║  ║ └╥┘
«round_0_link_bit_0: ═╬═══╬═══════════╬══╬══╬═
«                     ║   ║           ║  ║  ║
«round_0_link_bit_1: ═╬═══╬═══════════╬══╬══╬═
«                     ║   ║           ║  ║  ║
«round_1_link_bit_0: ═╩═══╬═══════════╬══╬══╬═
«                         ║           ║  ║  ║
«round_1_link_bit_1: ═════╩═══════════╬══╬══╬═
«                                     ║  ║  ║
«        code_bit_0: ═════════════════╩══╬══╬═
«                                        ║  ║
«        code_bit_1: ════════════════════╩══╬═
«                                           ║
«        code_bit_2: ═══════════════════════╩═
«

========= logical 1 =========

                            ░ ┌───┐     ┌───┐     ┌─┐           ░ ┌───┐     »
     link_qubit_0: |0>──────░─┤ X ├─────┤ X ├─────┤M├─|0>───────░─┤ X ├─────»
                            ░ └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░ └─┬─┘┌───┐»
     link_qubit_1: |0>──────░───┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░───┼──┤ X ├»
                      ┌───┐ ░   │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░   │  └─┬─┘»
     code_qubit_0: |0>┤ X ├─░───■────┼────┼────┼───╫───╫────────░───■────┼──»
                      ├───┤ ░        │    │    │   ║   ║        ░        │  »
     code_qubit_1: |0>┤ X ├─░────────■────■────┼───╫───╫────────░────────■──»
                      ├───┤ ░                  │   ║   ║        ░           »
     code_qubit_2: |0>┤ X ├─░──────────────────■───╫───╫────────░───────────»
                      └───┘ ░                      ║   ║        ░           »
round_0_link_bit_0: 0 ═════════════════════════════╩═══╬════════════════════»
                                                       ║                    »
round_0_link_bit_1: 0 ═════════════════════════════════╩════════════════════»
                                                                            »
round_1_link_bit_0: 0 ══════════════════════════════════════════════════════»
                                                                            »
round_1_link_bit_1: 0 ══════════════════════════════════════════════════════»
                                                                            »
        code_bit_0: 0 ══════════════════════════════════════════════════════»
                                                                            »
        code_bit_1: 0 ══════════════════════════════════════════════════════»
                                                                            »
        code_bit_2: 0 ══════════════════════════════════════════════════════»
                                                                            »
«                    ┌───┐     ┌─┐           ░
«      link_qubit_0: ┤ X ├─────┤M├─|0>───────░──────────
«                    └─┬─┘┌───┐└╥┘ ┌─┐       ░
«      link_qubit_1: ──┼──┤ X ├─╫──┤M├──|0>──░──────────
«                      │  └─┬─┘ ║  └╥┘       ░ ┌─┐
«      code_qubit_0: ──┼────┼───╫───╫────────░─┤M├──────
«                      │    │   ║   ║        ░ └╥┘┌─┐
«      code_qubit_1: ──■────┼───╫───╫────────░──╫─┤M├───
«                           │   ║   ║        ░  ║ └╥┘┌─┐
«      code_qubit_2: ───────■───╫───╫────────░──╫──╫─┤M├
«                               ║   ║        ░  ║  ║ └╥┘
«round_0_link_bit_0: ═══════════╬═══╬═══════════╬══╬══╬═
«                               ║   ║           ║  ║  ║
«round_0_link_bit_1: ═══════════╬═══╬═══════════╬══╬══╬═
«                               ║   ║           ║  ║  ║
«round_1_link_bit_0: ═══════════╩═══╬═══════════╬══╬══╬═
«                                   ║           ║  ║  ║
«round_1_link_bit_1: ═══════════════╩═══════════╬══╬══╬═
«                                               ║  ║  ║
«        code_bit_0: ═══════════════════════════╩══╬══╬═
«                                                  ║  ║
«        code_bit_1: ══════════════════════════════╩══╬═
«                                                     ║
«        code_bit_2: ═════════════════════════════════╩═
«

Génération d’un code de répétition personnalisé

Vous pouvez également implémenter des tours de mesure et des portes logiques X vous-même. Par exemple, mettons en place un code sans cycles de mesure du syndrome.

[7]:
empty_code = RepetitionCode(3,0)

Cela ne fait que mettre en place deux circuits pour les deux états codés logiquement. Il n’y a pas de cycle de mesure du syndrome et pas de lecture finale.

[8]:
def print_circuits(code):
    for log in ['0','1']:
        print('\n========= logical',log,'=========\n')
        print( code.circuit[log] )

print_circuits(empty_code)

========= logical 0 =========


link_qubit_0: |0>

link_qubit_1: |0>

code_qubit_0: |0>

code_qubit_1: |0>

code_qubit_2: |0>


========= logical 1 =========

                       ░
link_qubit_0: |0>──────░─
                       ░
link_qubit_1: |0>──────░─
                 ┌───┐ ░
code_qubit_0: |0>┤ X ├─░─
                 ├───┤ ░
code_qubit_1: |0>┤ X ├─░─
                 ├───┤ ░
code_qubit_2: |0>┤ X ├─░─
                 └───┘ ░

Nous pouvons ajouter un cycle en utilisant la méthode syndrome_measurement().

[9]:
empty_code.syndrome_measurement()
print_circuits(empty_code)

========= logical 0 =========

                      ┌───┐     ┌───┐     ┌─┐           ░
     link_qubit_0: |0>┤ X ├─────┤ X ├─────┤M├─|0>───────░─
                      └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░
     link_qubit_1: |0>──┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░─
                        │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░
     code_qubit_0: |0>──■────┼────┼────┼───╫───╫────────░─
                             │    │    │   ║   ║        ░
     code_qubit_1: |0>───────■────■────┼───╫───╫────────░─
                                       │   ║   ║        ░
     code_qubit_2: |0>─────────────────■───╫───╫────────░─
                                           ║   ║        ░
round_0_link_bit_0: 0 ═════════════════════╩═══╬══════════
                                               ║
round_0_link_bit_1: 0 ═════════════════════════╩══════════


========= logical 1 =========

                            ░ ┌───┐     ┌───┐     ┌─┐           ░
     link_qubit_0: |0>──────░─┤ X ├─────┤ X ├─────┤M├─|0>───────░─
                            ░ └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░
     link_qubit_1: |0>──────░───┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░─
                      ┌───┐ ░   │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░
     code_qubit_0: |0>┤ X ├─░───■────┼────┼────┼───╫───╫────────░─
                      ├───┤ ░        │    │    │   ║   ║        ░
     code_qubit_1: |0>┤ X ├─░────────■────■────┼───╫───╫────────░─
                      ├───┤ ░                  │   ║   ║        ░
     code_qubit_2: |0>┤ X ├─░──────────────────■───╫───╫────────░─
                      └───┘ ░                      ║   ║        ░
round_0_link_bit_0: 0 ═════════════════════════════╩═══╬══════════
                                                       ║
round_0_link_bit_1: 0 ═════════════════════════════════╩══════════

Une opération logique X peut être ajoutée en utilisant la méthode x().

[10]:
empty_code.x()
print_circuits(empty_code)

========= logical 0 =========

                      ┌───┐     ┌───┐     ┌─┐           ░       ░
     link_qubit_0: |0>┤ X ├─────┤ X ├─────┤M├─|0>───────░───────░─
                      └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░       ░
     link_qubit_1: |0>──┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░───────░─
                        │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░ ┌───┐ ░
     code_qubit_0: |0>──■────┼────┼────┼───╫───╫────────░─┤ X ├─░─
                             │    │    │   ║   ║        ░ ├───┤ ░
     code_qubit_1: |0>───────■────■────┼───╫───╫────────░─┤ X ├─░─
                                       │   ║   ║        ░ ├───┤ ░
     code_qubit_2: |0>─────────────────■───╫───╫────────░─┤ X ├─░─
                                           ║   ║        ░ └───┘ ░
round_0_link_bit_0: 0 ═════════════════════╩═══╬══════════════════
                                               ║
round_0_link_bit_1: 0 ═════════════════════════╩══════════════════


========= logical 1 =========

                            ░ ┌───┐     ┌───┐     ┌─┐           ░       ░
     link_qubit_0: |0>──────░─┤ X ├─────┤ X ├─────┤M├─|0>───────░───────░─
                            ░ └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░       ░
     link_qubit_1: |0>──────░───┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░───────░─
                      ┌───┐ ░   │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░ ┌───┐ ░
     code_qubit_0: |0>┤ X ├─░───■────┼────┼────┼───╫───╫────────░─┤ X ├─░─
                      ├───┤ ░        │    │    │   ║   ║        ░ ├───┤ ░
     code_qubit_1: |0>┤ X ├─░────────■────■────┼───╫───╫────────░─┤ X ├─░─
                      ├───┤ ░                  │   ║   ║        ░ ├───┤ ░
     code_qubit_2: |0>┤ X ├─░──────────────────■───╫───╫────────░─┤ X ├─░─
                      └───┘ ░                      ║   ║        ░ └───┘ ░
round_0_link_bit_0: 0 ═════════════════════════════╩═══╬══════════════════
                                                       ║
round_0_link_bit_1: 0 ═════════════════════════════════╩══════════════════

Ceci a également un kwarg (argument), logs, qui est une liste des circuits pour lesquels X est appliqué. C’est ['0','1'] par défaut.

La lecture finale est alors faite avec la méthode readout().

[11]:
empty_code.readout()
print_circuits(empty_code)

========= logical 0 =========

                      ┌───┐     ┌───┐     ┌─┐           ░       ░
     link_qubit_0: |0>┤ X ├─────┤ X ├─────┤M├─|0>───────░───────░──────────
                      └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░       ░
     link_qubit_1: |0>──┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░───────░──────────
                        │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░ ┌───┐ ░ ┌─┐
     code_qubit_0: |0>──■────┼────┼────┼───╫───╫────────░─┤ X ├─░─┤M├──────
                             │    │    │   ║   ║        ░ ├───┤ ░ └╥┘┌─┐
     code_qubit_1: |0>───────■────■────┼───╫───╫────────░─┤ X ├─░──╫─┤M├───
                                       │   ║   ║        ░ ├───┤ ░  ║ └╥┘┌─┐
     code_qubit_2: |0>─────────────────■───╫───╫────────░─┤ X ├─░──╫──╫─┤M├
                                           ║   ║        ░ └───┘ ░  ║  ║ └╥┘
round_0_link_bit_0: 0 ═════════════════════╩═══╬═══════════════════╬══╬══╬═
                                               ║                   ║  ║  ║
round_0_link_bit_1: 0 ═════════════════════════╩═══════════════════╬══╬══╬═
                                                                   ║  ║  ║
        code_bit_0: 0 ═════════════════════════════════════════════╩══╬══╬═
                                                                      ║  ║
        code_bit_1: 0 ════════════════════════════════════════════════╩══╬═
                                                                         ║
        code_bit_2: 0 ═══════════════════════════════════════════════════╩═


========= logical 1 =========

                            ░ ┌───┐     ┌───┐     ┌─┐           ░       ░    »
     link_qubit_0: |0>──────░─┤ X ├─────┤ X ├─────┤M├─|0>───────░───────░────»
                            ░ └─┬─┘┌───┐└─┬─┘┌───┐└╥┘ ┌─┐       ░       ░    »
     link_qubit_1: |0>──────░───┼──┤ X ├──┼──┤ X ├─╫──┤M├──|0>──░───────░────»
                      ┌───┐ ░   │  └─┬─┘  │  └─┬─┘ ║  └╥┘       ░ ┌───┐ ░ ┌─┐»
     code_qubit_0: |0>┤ X ├─░───■────┼────┼────┼───╫───╫────────░─┤ X ├─░─┤M├»
                      ├───┤ ░        │    │    │   ║   ║        ░ ├───┤ ░ └╥┘»
     code_qubit_1: |0>┤ X ├─░────────■────■────┼───╫───╫────────░─┤ X ├─░──╫─»
                      ├───┤ ░                  │   ║   ║        ░ ├───┤ ░  ║ »
     code_qubit_2: |0>┤ X ├─░──────────────────■───╫───╫────────░─┤ X ├─░──╫─»
                      └───┘ ░                      ║   ║        ░ └───┘ ░  ║ »
round_0_link_bit_0: 0 ═════════════════════════════╩═══╬═══════════════════╬═»
                                                       ║                   ║ »
round_0_link_bit_1: 0 ═════════════════════════════════╩═══════════════════╬═»
                                                                           ║ »
        code_bit_0: 0 ═════════════════════════════════════════════════════╩═»
                                                                             »
        code_bit_1: 0 ═══════════════════════════════════════════════════════»
                                                                             »
        code_bit_2: 0 ═══════════════════════════════════════════════════════»
                                                                             »
«
«      link_qubit_0: ──────
«
«      link_qubit_1: ──────
«
«      code_qubit_0: ──────
«                    ┌─┐
«      code_qubit_1: ┤M├───
«                    └╥┘┌─┐
«      code_qubit_2: ─╫─┤M├
«                     ║ └╥┘
«round_0_link_bit_0: ═╬══╬═
«                     ║  ║
«round_0_link_bit_1: ═╬══╬═
«                     ║  ║
«        code_bit_0: ═╬══╬═
«                     ║  ║
«        code_bit_1: ═╩══╬═
«                        ║
«        code_bit_2: ════╩═
«

Exécution d’un code de répétition

L’objet code produit les circuits requis pour le code. L’utilisateur peut ensuite les exécuter en utilisant n’importe quelle méthode qu’il préfère, en permettant un contrôle total de la compilation, des backends (plateformes quantiques), des modèles de bruit, etc.

Par exemple, ici nous les exécutons sans bruit sur le qasm_simulator.

[12]:
circuits = code.get_circuit_list()
job = execute( circuits, Aer.get_backend('qasm_simulator') )
raw_results = {}
for log in ['0','1']:
    raw_results[log] = job.result().get_counts(log)
    print('\n========= logical',log,'=========\n')
    print(raw_results[log])

========= logical 0 =========

{'000 00 00': 1024}

========= logical 1 =========

{'111 00 00': 1024}

Ici, les chaînes de droite à gauche représentent les sorties des cycles de mesure du syndrome, suivies de la mesure finale des qubits de code.

Ces résultats doivent être réécrits sous une forme différente pour être décodés. Pour cela, nous pouvons utiliser la méthode process_results de l’objet code.

[13]:
code.process_results( raw_results )
[13]:
{'0': {'0 0  00 00 00': 1024}, '1': {'1 1  00 00 00': 1024}}

Le résultat est un dictionnaire dont les clés sont des chaînes de bits qui représentent les sorties du circuit, et les valeurs représentent le nombre d’exécutions pour lesquelles cette sortie s’est produite.

Les chaînes de caractères ne sont pas la sortie directe des circuits. Ils ont été traités pour prendre la forme qui nous aide à corriger les erreurs. Voici une courte visite guidée.

  • Le 0 0 à l’extrême gauche pour le résultat logique 0 et le 1 1 à l’extrême gauche de la logique 1, sont les lectures logiques. N’importe quel qubit de code peut être utilisé pour cette lecture, car ils devraient tous être égaux (sans erreurs). Nous pourrions donc avoir un seul résultat ici, pour un qubit de code arbitrairement choisi. Ou nous pourrions en avoir \(d\), un pour chaque qubits. Au lieu de cela, nous en avons deux, à chaque extrémité de la ligne. C’est parce qu’il fonctionne mieux avec le décodeur (que nous utiliserons plus tard). En l’absence d’erreurs, ces deux valeurs seront toujours égales.

  • Le 0000 suivant est le résultat \(d-1\) des mesures du syndrome pour le premier cycle. 0 implique que la paire correspondante de qubits sont le même et 1 implique différent. Il y a \(d-1\) résultats parce que la ligne de \(d\) qubits de code a \(d-1\) paires voisines possibles. En l’absence d’erreurs, ils seront tous 0.

  • Le 0000 qui suit est le changement de syndrome entre le premier et le second cycle. C’est donc le OR au niveau du bit des résultats de la mesure du syndrome du deuxième cycle avec ceux du premier. En l’absence d’erreurs, ils seront tous 0.

  • Les blocs suivants suivent la même formule, bien que le dernier nécessite un commentaire. Ceci n’est pas mesuré à l’aide de la méthode standard (avec un qubit de lien). Au lieu de cela, il est calculé à partir de la mesure de lecture finale de tous les qubits de code. Encore une fois, il est présenté comme un changement de syndrome, et sera tout 0 en l’absence d’erreurs. Ceci est le \(T+1\)-ème bloc des mesures du syndrome puisqu’il n’est pas compté parmi les cycles de mesure du syndrome \(T\), car il n’est pas fait de la même manière que les autres.

Exemple 1: 0 0 0110 0000 0000 représenterait un code de répétition \(d=5\), \(T=2\) avec un code de répétition encodé 0. Le syndrome montre que (très probablement) le qubit de code au milieu a été retourné par une erreur avant le premier cycle de mesure. Cela le fait en désaccord avec les deux qubits de code voisins pour le reste du circuit. Ceci est montré par le syndrome dans le premier cycle, mais les blocs pour les cycles suivants ne le signalent pas car il ne représente plus un changement. D’autres séries d’erreurs auraient également pu causer ce syndrome, mais elles auraient besoin d’être plus complexes et donc probablement moins probables.

Exemple 2: 0 0 0010 0010 0000 représenterait un code de répétition \(d=5\), \(T=2\) avec un code de répétition encodé 0. Ici, une des mesures du syndrome a rapporté une différence entre deux qubits de code au premier cycle, conduisant à un 1. Le cycle suivant n’a pas vu le même effet, et a donc abouti à un 0. Cependant, étant donné que cela n’est pas en accord avec le résultat précédent pour la même mesure du syndrome, et que nous suivons les changements du syndrome, ce changement entraîne un autre 1. Les cycles suivants ne détectent rien non plus, mais cela ne représente plus un changement et donne donc un 0 dans la même position. Le résultat de mesure conduisant au premier 1 est probablement une erreur.

Exemple 3: 0 1 0000 0001 0000 représenterait un code de répétition \(d=5\), \(T=2\) avec un code de répétition encodé 1. Un qubit de code à la fin de la ligne est retourné avant le deuxième cycle de mesures du syndrome. Ceci est détecté par une seule mesure de syndrome, car il est à la fin de la ligne. Pour la même raison, il perturbe aussi une des lectures logiques.

Notez que dans tous ces exemples, une seule erreur entraîne exactement deux caractères dans la chaîne de caractères à changer de la valeur qu’elle aurait sans erreur. C’est en fait la raison pour laquelle la sortie logique se compose des deux extrémités. C’est une propriété qui sera utilisée par le décodeur.

Pour voir les effets du bruit, il faut spécifier un modèle de bruit. Par exemple, mettons en place un modèle de bruit simple avec des erreurs de porte et de mesure.

[14]:
from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.aer.noise.errors import pauli_error, depolarizing_error

def get_noise(p_meas,p_gate):

    error_meas = pauli_error([('X',p_meas), ('I', 1 - p_meas)])
    error_gate1 = depolarizing_error(p_gate, 1)
    error_gate2 = error_gate1.tensor(error_gate1)

    noise_model = NoiseModel()
    noise_model.add_all_qubit_quantum_error(error_meas, "measure")
    noise_model.add_all_qubit_quantum_error(error_gate1, ["u1", "u2", "u3"])
    noise_model.add_all_qubit_quantum_error(error_gate2, ["cx"])

    return noise_model
[15]:
noise_model = get_noise(0.04,0.04)

Cela peut alors être exécuté pour générer des résultats bruyants. Faisons une fonction rapide pour faire cela, puis exécutez-le.

[16]:
def get_syndrome(code,noise_model,shots=1014):

    circuits = code.get_circuit_list()

    job = execute( circuits, Aer.get_backend('qasm_simulator'),noise_model=noise_model, shots=shots )
    raw_results = {}
    for log in ['0','1']:
        raw_results[log] = job.result().get_counts(log)

    return code.process_results( raw_results )
[17]:
get_syndrome(code,noise_model)
[17]:
{'0': {'1 1  10 10 11': 1,
  '0 0  00 01 01': 36,
  '0 0  10 11 10': 1,
  '0 1  00 10 11': 2,
  '0 1  01 10 10': 1,
  '0 1  00 00 10': 3,
  '0 0  00 00 11': 32,
  '0 0  00 11 11': 6,
  '0 1  01 00 00': 1,
  '0 0  01 00 10': 2,
  '0 1  00 11 10': 1,
  '0 0  11 11 00': 2,
  '0 0  00 01 10': 20,
  '1 0  01 01 10': 7,
  '0 0  01 00 01': 2,
  '0 1  10 10 01': 2,
  '1 0  00 00 01': 4,
  '1 1  00 01 10': 1,
  '0 0  10 10 00': 60,
  '0 1  00 00 01': 37,
  '1 0  00 11 10': 2,
  '0 0  00 00 00': 554,
  '0 0  10 10 11': 3,
  '1 0  01 10 10': 2,
  '0 1  00 01 00': 11,
  '1 0  10 01 01': 1,
  '0 0  11 00 00': 3,
  '1 0  10 10 10': 4,
  '1 0  00 00 10': 47,
  '0 1  00 11 01': 1,
  '1 1  01 10 00': 1,
  '0 0  01 01 00': 48,
  '1 0  00 10 00': 19,
  '0 1  10 11 00': 2,
  '0 0  00 11 00': 12,
  '0 1  01 11 11': 1,
  '0 1  00 01 11': 1,
  '1 0  00 01 11': 2,
  '0 0  00 10 10': 41,
  '1 1  00 00 11': 4,
  '0 0  10 11 01': 4,
  '0 0  01 11 10': 2,
  '1 0  01 01 01': 2,
  '0 0  00 10 01': 5,
  '0 0  01 10 00': 12,
  '0 0  01 01 11': 2,
  '0 0  10 00 10': 3,
  '1 0  11 11 10': 2,
  '0 1  01 01 01': 2},
 '1': {'0 1  10 10 10': 2,
  '1 1  00 10 10': 57,
  '0 1  10 01 01': 1,
  '1 1  11 11 11': 2,
  '1 1  11 00 00': 2,
  '1 0  00 11 01': 2,
  '1 1  00 10 01': 7,
  '1 1  11 11 00': 3,
  '1 1  01 01 11': 5,
  '1 1  10 10 11': 4,
  '1 1  01 11 10': 3,
  '1 1  00 11 11': 1,
  '1 1  01 01 00': 39,
  '0 1  00 10 11': 1,
  '0 1  01 10 10': 1,
  '0 1  00 00 10': 45,
  '1 0  00 01 00': 15,
  '0 0  00 00 11': 2,
  '1 1  10 10 00': 52,
  '1 1  10 11 10': 1,
  '1 1  00 01 01': 37,
  '1 1  01 00 01': 4,
  '1 1  01 10 11': 1,
  '0 1  00 11 10': 1,
  '1 0  01 00 00': 2,
  '1 1  00 11 00': 12,
  '1 1  10 11 01': 4,
  '0 0  00 01 10': 1,
  '1 1  11 01 10': 1,
  '1 0  00 00 01': 33,
  '1 1  00 01 10': 12,
  '1 1  11 10 01': 1,
  '0 1  00 00 01': 1,
  '1 0  00 11 10': 1,
  '1 1  01 00 10': 1,
  '0 1  00 01 00': 4,
  '1 1  00 00 00': 553,
  '1 0  10 10 10': 1,
  '1 0  00 00 10': 2,
  '0 1  00 11 01': 2,
  '1 1  01 10 00': 16,
  '0 1  01 01 10': 3,
  '0 1  00 10 00': 17,
  '1 0  00 10 00': 1,
  '1 0  10 11 00': 1,
  '0 1  00 01 11': 4,
  '1 1  01 11 01': 2,
  '1 1  00 00 11': 36,
  '1 0  01 01 01': 3,
  '1 1  10 00 10': 5,
  '1 0  00 10 11': 4,
  '1 0  10 10 01': 3}}

Ici, les résultats non bruyants sont les plus probables. Le reste des échantillons est réparti entre autres possibilités avec des syndromes non triviaux.

Décodage d’un code de répétition

Les résultats bruyants peuvent changer la valeur logique lors de la lecture et donc affecter notre capacité à lire le qubit logique. Cela peut être atténué en regardant les valeurs du syndrome. Ils peuvent nous dire si oui ou non les valeurs logiques sont les plus susceptibles d’avoir changé, et donc nous permettre de corriger les erreurs. Le processus d’analyse du syndrome pour corriger les erreurs est appelé “decoding” (décodage). Nous le faisons en construisant un objet de décodage pour notre code.

[18]:
dec = GraphDecoder( RepetitionCode(4,2) )

Cela permet d’analyser le code en regardant comment différents types d’erreur modifient la sortie. Avec cette information, ainsi qu’un algorithme de décodage, nous pouvons déterminer quelle est la valeur logique la plus probable.

Par exemple, utilisons l’algorithme de “matching” (correspondance) pour décoder, qui est basé sur le poids minimum de la correspondance parfaite. Cela prend des chaînes de sortie spécifiques en entrée. Nous lui donnerons l’exemple d’une simple chaîne de caractères '1 0 001 100 100', pour un 1 logique qui a subi deux erreurs.

[19]:
dec.matching('1 0  001 100 100')
[19]:
'1 1'

La sortie est ce que la partie logique aurait dû être. Comme vous pouvez le voir, le décodeur a correctement déterminé que la lecture aurait dû être d’un 1 logique.

Lorsque nous prenons plusieurs échantillons, nous pouvons déterminer avec quelle probabilité le décodeur est incorrect. Cela devrait diminuer de façon exponentielle car la taille du code est augmentée, car les configurations de bruit qui trompent le décodeur deviennent moins probables. La probabilité d’une erreur logique est calculée en utilisant la méthode logical_prob(). Cela exécute la correspondance par défaut, mais d’autres algorithmes peuvent être spécifiés par l”algorithm kwarg (argument).

[20]:
for d in range(3,8):

    code = RepetitionCode(d,2)

    results = get_syndrome(code,noise_model=noise_model,shots=8192)

    dec = GraphDecoder(code)

    logical_prob_match = dec.get_logical_prob(results)
    logical_prob_lookup = lookuptable_decoding(results,results)
    logical_prob_post = postselection_decoding(results)

    for log in ['0','1']:
        print('d =',d,',log =',log)
        print('logical error probability for matching      =',logical_prob_match[log])
        print('logical error probability for lookup table  =',logical_prob_lookup[log])
        print('logical error probability for postselection =',logical_prob_post[log])
        print('')
    print('')
d = 3 ,log = 0
logical error probability for matching      = 0.0323486328125
logical error probability for lookup table  = 0.021484375
logical error probability for postselection = 0.0004528985507246377

d = 3 ,log = 1
logical error probability for matching      = 0.02880859375
logical error probability for lookup table  = 0.0169677734375
logical error probability for postselection = 0.0


d = 4 ,log = 0
logical error probability for matching      = 0.01806640625
logical error probability for lookup table  = 0.01171875
logical error probability for postselection = 0.0

d = 4 ,log = 1
logical error probability for matching      = 0.0206298828125
logical error probability for lookup table  = 0.0074462890625
logical error probability for postselection = 0.0


d = 5 ,log = 0
logical error probability for matching      = 0.0091552734375
logical error probability for lookup table  = 0.002197265625
logical error probability for postselection = 0.0

d = 5 ,log = 1
logical error probability for matching      = 0.0086669921875
logical error probability for lookup table  = 0.002197265625
logical error probability for postselection = 0.0


d = 6 ,log = 0
logical error probability for matching      = 0.005859375
logical error probability for lookup table  = 0.0
logical error probability for postselection = 0.0

d = 6 ,log = 1
logical error probability for matching      = 0.0050048828125
logical error probability for lookup table  = 0.0001220703125
logical error probability for postselection = 0.0


d = 7 ,log = 0
logical error probability for matching      = 0.0025634765625
logical error probability for lookup table  = 0.0
logical error probability for postselection = 0.0

d = 7 ,log = 1
logical error probability for matching      = 0.002197265625
logical error probability for lookup table  = 0.0
logical error probability for postselection = 0.0


[21]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.14.0
Terra0.11.0
Aer0.3.4
Ignis0.2.0
Aqua0.6.1
IBM Q Provider0.4.4
System information
Python3.7.5 (default, Oct 25 2019, 10:52:18) [Clang 4.0.1 (tags/RELEASE_401/final)]
OSDarwin
CPUs4
Memory (Gb)16.0
Tue Dec 10 17:06:25 2019 EST

This code is a part of Qiskit

© Copyright IBM 2017, 2019.

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.

[ ]: