Construire des circuits
Le code de cette page a été développé en tenant compte des exigences suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.5.1
Cette page examine de plus près la classe QuantumCircuit dans le SDK Qiskit, y compris certaines méthodes plus avancées que vous pouvez utiliser pour créer des circuits quantiques.
Qu'est-ce qu'un circuit quantique?
Un circuit quantique simple est une collection de qubits et une liste d'instructions qui agissent sur ces qubits. Pour le démontrer, la cellule suivante crée un nouveau circuit avec deux nouveaux qubits, puis affiche l'attribut qubits du circuit, qui est une liste de Qubits dans l'ordre du bit le moins significatif au bit le plus significatif .
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubitsOutput:
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]
Plusieurs objets QuantumRegister et ClassicalRegister peuvent être combinés pour créer un circuit. Chaque QuantumRegister et ClassicalRegister peuvent également être nommés.
from qiskit.circuit import QuantumRegister, ClassicalRegister
qr1 = QuantumRegister(2, "qreg1") # Create a QuantumRegister with 2 qubits
qr2 = QuantumRegister(1, "qreg2") # Create a QuantumRegister with 1 qubit
cr1 = ClassicalRegister(3, "creg1") # Create a ClassicalRegister with 3 cbits
combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # Create a quantum circuit with 2 QuantumRegisters and 1 ClassicalRegister
combined_circ.qubitsOutput:
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
Vous pouvez trouver l'index et le registre d'un qubit en utilisant la méthode et les attributs du circuit find_bit du circuit et de ses attributs.
desired_qubit = qr2[0] # Qubit 0 of register 'qreg2'
print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)Output:
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
L'ajout d'une instruction au circuit ajoute l'instruction à l'attribut du circuit data du circuit. La sortie de cellule suivante montre que data est une liste d'objets qui ont chacun un attribut et un attribut CircuitInstruction objets, dont chacun possède un attribut operation et un attribut qubits .
qc.x(0) # Add X-gate to qubit 0
qc.dataOutput:
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
La manière la plus simple de consulter ces informations consiste à utiliser la draw méthode, qui renvoie une représentation graphique du circuit. Consultez la section « Visualisation des circuits » pour découvrir différentes façons de représenter les circuits quantiques.
qc.draw("mpl")Output:
Les objets d'instruction de circuit peuvent contenir des circuits de "définition" qui décrivent l'instruction en termes d'instructions plus fondamentales. Par exemple, la porte X est définie comme un cas spécifique de la U3-gate, une porte à qubit unique plus générale.
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")Output:
Les instructions et les circuits sont similaires en ce sens qu'ils décrivent tous deux des opérations sur des bits et des qubits, mais ils ont des objectifs différents :
- Les instructions sont considérées comme fixes et leurs méthodes renvoient généralement de nouvelles instructions (sans modifier l'objet d'origine).
- Les circuits sont conçus pour être construits sur plusieurs lignes de code, et les méthodes mutent souvent l'objet existant
QuantumCircuitmutent souvent l'objet existant.
Qu'est-ce que la profondeur de circuit?
La profondeur() d'un circuit quantique est une mesure du nombre de "couches" de portes quantiques, exécutées en parallèle, nécessaires pour effectuer le calcul défini par le circuit. Comme la mise en œuvre des portes quantiques prend du temps, la profondeur d'un circuit correspond approximativement au temps qu'il faut à l'ordinateur quantique pour exécuter le circuit. Ainsi, la profondeur d'un circuit est une quantité importante utilisée pour mesurer si un circuit quantique peut être exécuté sur un appareil.
Le reste de cette page illustre comment manipuler les circuits quantiques.
Construire des circuits
Des méthodes telles que QuantumCircuit.h et QuantumCircuit.cx ajoutent des instructions spécifiques aux circuits. Pour ajouter des instructions à un circuit de manière plus générale, utilisez la méthode append méthode. Elle prend une instruction et une liste de qubits auxquels appliquer l'instruction. Voir la documentation de l'API de la bibliothèque de circuits pour une liste des instructions prises en charge.
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")Output:
Pour combiner deux circuits, utilisez la méthode compose méthode. Il accepte un autre QuantumCircuit et une liste optionnelle de mappages de qubits.
qc_a = QuantumCircuit(4)
qc_a.x(0)
qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)
# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")Output:
Vous pouvez également compiler les circuits en instructions afin de les organiser. Vous pouvez convertir un circuit en instruction en utilisant la méthode to_instruction puis l'ajouter à un autre circuit comme n'importe quelle autre instruction. Le circuit dessiné dans la cellule suivante est fonctionnellement équivalent au circuit dessiné dans la cellule précédente.
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")Output:
Si votre circuit est unitaire, vous pouvez le convertir en un circuit Gate en utilisant la méthode to_gate méthode. Gate les objets sont des types d'instructions spécifiques qui présentent des caractéristiques supplémentaires, telles que la méthode, qui ajoute un contrôle quantique control qui ajoute un contrôle quantique.
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")Output:
Pour voir ce qui se passe, vous pouvez utiliser la méthode decompose pour développer chaque instruction dans sa définition.
Le decompose la méthode renvoie un nouveau circuit et ne modifie pas le circuit sur lequel elle agit.
qc_a.decompose().draw("mpl")Output:
Mesurer les qubits
Les mesures permettent de déterminer l'état de chaque qubit et de transférer les résultats vers un registre classique. Notez que si vous soumettez des circuits à une primitive Sampler, des mesures sont obligatoires. Cependant, les circuits transmis à une primitive Estimator ne doivent pas contenir de mesures.
Il existe trois méthodes pour mesurer les qubits : measure, measure_all et measure_active. Pour savoir comment visualiser les résultats mesurés, consultez la page « Visualiser les résultats ».
-
QuantumCircuit.measure: mesure chaque qubit du premier argument sur le bit classique donné en second argument. Cette méthode permet de contrôler entièrement l'endroit où le résultat de la mesure est stocké. -
QuantumCircuit.measure_all: ne prend aucun argument et peut être utilisé pour les circuits quantiques sans bits classiques prédéfinis. Il crée des fils classiques et stocke les résultats des mesures dans l'ordre. Par exemple, la mesure du qubit est stockée dans le cbit ). Il ajoute également une barrière avant la mesure. -
QuantumCircuit.measure_active: similaire àmeasure_all, mais ne mesure que les qubits qui ont des opérations.
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)Output:
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)Output:
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)Output:
Circuits paramétrés
De nombreux algorithmes quantiques à court terme impliquent l'exécution de nombreuses variations d'un circuit quantique. Étant donné que la construction et l'optimisation de grands circuits peuvent être coûteuses en termes de calcul, Qiskit prend en charge les circuits paramétrés. Ces circuits ont des paramètres non définis et leurs valeurs ne doivent être définies que juste avant l'exécution du circuit. Cela vous permet de sortir la construction et l'optimisation du circuit de la boucle principale du programme. La cellule suivante crée et affiche un circuit paramétré.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter
angle = Parameter("angle") # undefined number
# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)
qc.draw("mpl")Output:
La cellule suivante crée plusieurs variantes de ce circuit et affiche l'une d'entre elles.
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")Output:
Vous trouverez la liste des paramètres non définis d'un circuit dans son attribut parameters .
qc.parametersOutput:
ParameterView([Parameter(angle)])
Modifier le nom d'un paramètre
Par défaut, les noms des paramètres d'un circuit paramétré sont préfixés par xun signe -, par exemple x[0]. Vous pouvez modifier les noms après les avoir définis, comme illustré dans l'exemple suivant.
from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector
# Define a parameterized circuit with default names
# For example, x[0]
circuit = z_feature_map(2)
# Set new parameter names
# They will now be prefixed by `hi` instead
# For example, hi[0]
training_params = ParameterVector("hi", 2)
# Assign parameter names to the quantum circuit
circuit = circuit.assign_parameters(parameters=training_params)Etapes suivantes
- Pour en savoir plus sur les algorithmes quantiques à court terme, suivez le cours sur la conception d'algorithmes variationnels.
- Voir un exemple d'utilisation des circuits dans le tutoriel sur l 'algorithme de Grover.
- Travaillez avec des circuits simples en utilisant IBM Quantum Composer.