Costruire circuiti
Il codice di questa pagina è stato sviluppato in base ai seguenti requisiti. Si consiglia di utilizzare queste versioni o versioni più recenti.
qiskit[all]~=2.5.1
Questa pagina analizza più da vicino la classe QuantumCircuit nell'SDK Qiskit, compresi alcuni metodi più avanzati che si possono utilizzare 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 tali qubit. A titolo dimostrativo, la cella seguente crea un nuovo circuito con due nuovi qubit, quindi visualizza l'attributo qubits del circuito, che è un elenco di Qubits in ordine dal bit meno significativo al bit più significativo .
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubitsOutput:
[<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 possono anche essere nominati.
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>]
È possibile trovare l'indice e il registro di un qubit utilizzando il metodo del circuito e i suoi attributi find_bit 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)Output:
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
L'aggiunta di un'istruzione al circuito aggiunge l'istruzione all'attributo del circuito data del circuito. L'output della cella seguente mostra che data è un elenco di oggetti CircuitInstruction oggetti, ognuno dei quali ha un attributo operation e un attributo 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=())]
Il modo più semplice per visualizzare queste informazioni è tramite il draw metodo, che restituisce una rappresentazione grafica del circuito. Vedi la sezione "Visualizzazione dei circuiti" per scoprire diversi modi di rappresentare i circuiti quantistici.
qc.draw("mpl")Output:
Gli oggetti istruzione possono contenere circuiti di "definizione" che descrivono l'istruzione in termini di istruzioni più fondamentali. Ad esempio, la porta X è definita come un caso specifico della U3-gate, una porta a singolo qubit più generale.
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")Output:
Istruzioni e circuiti sono simili in quanto 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 su molte righe di codice e i metodi
QuantumCircuitspesso i metodi modificano l'oggetto esistente.
Che cos'è la profondità del circuito?
La profondità() di un circuito quantistico è una misura del numero di "strati" di porte quantistiche, eseguite in parallelo, necessarie per completare la computazione definita dal circuito. Poiché le porte quantistiche richiedono tempo per essere implementate, la profondità di un circuito corrisponde approssimativamente alla quantità di tempo che il computer quantistico impiega per eseguire il circuito. Pertanto, la profondità di un circuito è una grandezza importante utilizzata per misurare 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 più in generale, utilizzare il metodo append metodo. Questo prende un'istruzione e un elenco di qubit a cui applicare l'istruzione. Per un elenco delle istruzioni supportate, consultare la documentazione dell'API della libreria Circuit.
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")Output:
Per combinare due circuiti, utilizzare il metodo compose metodo. 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")Output:
Si potrebbe anche decidere di raggruppare i circuiti in istruzioni per tenerli organizzati. È possibile convertire un circuito in un'istruzione utilizzando il metodo to_instruction e poi aggiungerlo a un altro circuito come si farebbe 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")Output:
Se il circuito è unitario, è possibile convertirlo in un circuito Gate utilizzando il metodo to_gate metodo. Gate gli oggetti sono tipi specifici di istruzioni che hanno alcune caratteristiche in più, 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")Output:
Per vedere cosa succede, si può usare il metodo decompose per espandere ogni istruzione nella sua definizione.
Il metodo decompose restituisce un nuovo circuito e non modifica il circuito su cui agisce.
qc_a.decompose().draw("mpl")Output:
Misurare i qubit
Le misurazioni vengono utilizzate per rilevare lo stato dei singoli qubit e trasferire i risultati a un registro classico. Si noti che, se si inviano circuiti a una primitiva Sampler, è necessario specificare le misure. Tuttavia, i circuiti inviati a una primitiva Estimator non devono contenere misure.
I qubit possono essere misurati utilizzando tre metodi: measure, measure_all e measure_active. Per sapere come visualizzare i risultati delle misurazioni, consulta la pagina Visualizza risultati.
-
QuantumCircuit.measure: misura ogni qubit del primo argomento sul bit classico dato come secondo argomento. Questo metodo consente di controllare completamente la posizione in cui viene memorizzato il risultato della misurazione. -
QuantumCircuit.measure_all: non richiede argomenti e può essere utilizzato per circuiti quantistici senza bit classici predefiniti. Crea fili classici e memorizza i risultati delle misure in ordine. Ad esempio, la misura 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)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:
Circuiti parametrizzati
Molti algoritmi quantistici a breve termine prevedono l'esecuzione di molte varianti di un circuito quantistico. Poiché la costruzione e l'ottimizzazione di circuiti di grandi dimensioni può essere computazionalmente costosa, Qiskit supporta circuiti parametrizzati. Questi circuiti hanno parametri indefiniti, i cui valori devono essere definiti solo poco prima dell'esecuzione del circuito. Ciò consente di spostare la costruzione e l'ottimizzazione dei circuiti 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")Output:
La cella seguente crea molte varianti di questo circuito e mostra una delle varianti.
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")Output:
L'elenco dei parametri non definiti di un circuito si trova nell'attributo parameters .
qc.parametersOutput:
ParameterView([Parameter(angle)])
Modifica il nome di un parametro
Per impostazione predefinita, i nomi dei parametri per un circuito parametrizzato sono preceduti dal prefisso x-, x[0] ad esempio. È possibile modificare i nomi dopo averli 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 conoscere gli algoritmi quantistici a breve termine, seguite il corso di progettazione di algoritmi variazionali.
- Un esempio di circuiti utilizzati nel tutorial sull' algoritmo di Grover.
- Lavorare con semplici circuiti utilizzando IBM Quantum Composer.