Costruire circuiti
Versioni dei pacchetti
Il codice in questa pagina è stato sviluppato utilizzando i seguenti requisiti. Raccomandiamo di usare queste versioni o versioni più recenti.
qiskit[all]~=2.3.0
Questa pagina approfondisce la classe QuantumCircuit nell'SDK di Qiskit, inclusi alcuni metodi più avanzati che puoi usare per creare circuiti quantistici.
Che cos'è un circuito quantistico?​
Un semplice circuito quantistico è un insieme di qubit e un elenco di istruzioni che agiscono su quei qubit. Per illustrarlo, la cella seguente crea un nuovo circuito con due nuovi qubit, quindi visualizza l'attributo qubits del circuito, che è un elenco di Qubit in ordine dal bit meno significativo al bit più significativo .
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubits
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]
È possibile combinare più oggetti QuantumRegister e ClassicalRegister per creare un circuito. Ogni QuantumRegister e ClassicalRegister può anche essere denominato.
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.qubits
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
Puoi trovare l'indice e il registro di un qubit usando il metodo find_bit del circuito e i suoi attributi.
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)
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
Aggiungere un'istruzione al circuito fa sì che l'istruzione venga accodata all'attributo data del circuito. L'output della cella seguente mostra che data è un elenco di oggetti CircuitInstruction, ognuno dei quali ha un attributo operation e un attributo qubits.
qc.x(0) # Add X-gate to qubit 0
qc.data
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
Il modo più semplice per visualizzare queste informazioni è tramite il metodo draw, che restituisce una rappresentazione grafica di un circuito. Consulta la pagina Visualizzare i circuiti per i diversi modi di visualizzare i circuiti quantistici.
qc.draw("mpl")
Gli oggetti istruzione del circuito possono contenere circuiti di "definizione" che descrivono l'istruzione in termini di istruzioni più fondamentali. Ad esempio, la X-gate è definita come un caso particolare della U3-gate, un gate a singolo qubit più generale.
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")
Istruzioni e circuiti si somigliano nel senso che entrambi descrivono operazioni su bit e qubit, ma hanno scopi diversi:
- Le istruzioni sono trattate come fisse, e i loro metodi di solito restituiscono nuove istruzioni (senza mutare l'oggetto originale).
- I circuiti sono progettati per essere costruiti in molte righe di codice, e i metodi di
QuantumCircuitspesso mutano l'oggetto esistente.
Che cos'è la profondità di un circuito?​
La profondità (depth()) di un circuito quantistico è una misura del numero di "strati" di gate quantistici, eseguiti in parallelo, necessari per completare il calcolo definito dal circuito. Poiché i gate quantistici richiedono tempo per essere implementati, la profondità di un circuito corrisponde approssimativamente al tempo che impiega il computer quantistico per eseguirlo. La profondità è quindi una delle quantità importanti usate per valutare se un circuito quantistico può essere eseguito su un dispositivo.
Il resto di questa pagina illustra come manipolare i circuiti quantistici.
Costruire circuiti​
Metodi come QuantumCircuit.h e QuantumCircuit.cx aggiungono istruzioni specifiche ai circuiti. Per aggiungere istruzioni a un circuito in modo più generale, usa il metodo append. Questo metodo accetta un'istruzione e un elenco di qubit a cui applicarla. Consulta la documentazione API della Circuit Library per un elenco delle istruzioni supportate.
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")
Per combinare due circuiti, usa il metodo compose. Questo accetta un altro QuantumCircuit e un elenco opzionale di mappature di qubit.
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")
Potresti anche voler compilare i circuiti in istruzioni per mantenere i tuoi circuiti organizzati. Puoi convertire un circuito in un'istruzione usando il metodo to_instruction, quindi aggiungerla a un altro circuito come faresti con qualsiasi altra istruzione. Il circuito disegnato nella cella seguente è funzionalmente equivalente al circuito disegnato nella cella precedente.
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")
Se il tuo circuito è unitario, puoi convertirlo in un Gate usando il metodo to_gate. Gli oggetti Gate sono tipi specifici di istruzioni che hanno alcune funzionalità aggiuntive, come il metodo control, che aggiunge un controllo quantistico.
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")
Per capire cosa sta succedendo, puoi usare il metodo decompose per espandere ogni istruzione nella sua definizione.
Il metodo decompose restituisce un nuovo circuito e non muta il circuito su cui agisce.
qc_a.decompose().draw("mpl")
Misurare i qubit​
Le misurazioni vengono usate per campionare gli stati dei singoli qubit e trasferire i risultati in un registro classico. Tieni presente che se stai inviando circuiti a una primitiva Sampler, le misurazioni sono obbligatorie. Invece, i circuiti inviati a una primitiva Estimator non devono contenere misurazioni.
I qubit possono essere misurati usando tre metodi: measure, measure_all e measure_active. Per scoprire come visualizzare i risultati delle misurazioni, consulta la pagina Visualizzare i risultati.
-
QuantumCircuit.measure: misura ogni qubit nel primo argomento sul bit classico fornito come secondo argomento. Questo metodo consente il pieno controllo su dove viene memorizzato il risultato della misurazione. -
QuantumCircuit.measure_all: non richiede argomenti e può essere usato per circuiti quantistici senza bit classici predefiniti. Crea i fili classici e memorizza i risultati delle misurazioni in ordine. Ad esempio, la misurazione del qubit viene memorizzata nel cbit ). Aggiunge anche una barriera prima della misurazione. -
QuantumCircuit.measure_active: simile ameasure_all, ma misura solo i qubit che hanno operazioni.
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)
Circuiti parametrizzati​
Molti algoritmi quantistici a breve termine prevedono l'esecuzione di numerose varianti di un circuito quantistico. Poiché la costruzione e l'ottimizzazione di circuiti di grandi dimensioni possono essere costose dal punto di vista computazionale, Qiskit supporta i circuiti parametrizzati. Questi circuiti hanno parametri non definiti, i cui valori non devono essere specificati fino a poco prima dell'esecuzione del circuito. Questo ti permette di spostare la costruzione e l'ottimizzazione del circuito fuori dal ciclo principale del programma. La cella seguente crea e visualizza un circuito parametrizzato.
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")
La cella seguente crea molte varianti di questo circuito e ne visualizza una.
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")
Puoi trovare l'elenco dei parametri non definiti di un circuito nel suo attributo parameters.
qc.parameters
ParameterView([Parameter(angle)])
Modificare il nome di un parametro​
Per impostazione predefinita, i nomi dei parametri per un circuito parametrizzato sono preceduti dal prefisso x— ad esempio, x[0]. Puoi modificare i nomi dopo che sono stati definiti, come mostrato nell'esempio seguente.
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)
Passi successivi​
- Per scoprire gli algoritmi quantistici a breve termine, segui il corso Variational algorithm design.
- Consulta un esempio di utilizzo dei circuiti nel tutorial Algoritmo di Grover.
- Lavora con circuiti semplici usando IBM Quantum Composer.