Risoluzione dei tempi differita con l'uso di stretch
La specifica linguistica 3 dell' OpenQASM contiene un stretch tipo con cui è possibile specificare la temporizzazione relativa delle operazioni invece della temporizzazione assoluta. Il supporto per stretch come durate per Delay istruzioni è stato aggiunto in Qiskit v2.0.0. Il valore concreto di una durata di estensione viene risolto in fase di compilazione, dopo che è nota la durata esatta dei gate calibrati. Il compilatore cerca di ridurre al minimo la durata dell'estensione, tenendo conto dei vincoli temporali su uno o più qubit. È quindi possibile esprimere progetti di gate quali gate con spaziatura uniforme (ad esempio, per implementare una sequenza di disaccoppiamento dell'eco di ordine superiore), allineamento a sinistra di una sequenza di gate o applicazione di un gate per la durata di alcuni sottocircuiti, senza conoscere la temporizzazione esatta.
Esempi
Disaccoppiamento dinamico
Un caso d'uso comune di stretch è quello di applicare il disaccoppiamento dinamico a un qubit inattivo mentre un altro qubit è sottoposto a operazioni condizionali.
Ad esempio, possiamo utilizzare stretch per applicare una sequenza di disaccoppiamento dinamico XX al qubit 1, per la durata del blocco condizionale applicato al qubit 0, come illustrato dal diagramma seguente:
Il circuito corrispondente è il seguente. Si noti che è necessaria una coppia di barriere per definire i confini di questa temporizzazione relativa.
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr
qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits
# Add barriers to define the boundaries
circuit.barrier()
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q0)
with else_:
circuit.x(q0)
# Apply an XX DD sequence with stretch on qubit 1
s = circuit.add_stretch("s")
circuit.delay(s, q1)
circuit.x(q1)
circuit.delay(expr.mul(s, 2), q1)
circuit.x(q1)
circuit.delay(s, q1)
circuit.barrier()Allineamento della pianificazione
Questo esempio utilizza stretch per garantire che una sequenza di porte tra due barriere sia allineata a sinistra, indipendentemente dalla loro durata effettiva:
from qiskit import QuantumCircuit
from numpy import pi
qc = QuantumCircuit(5)
qc.barrier()
qc.cx(0, 1)
qc.u(pi/4, 0, pi/2, 2)
qc.cx(3, 4)
a = qc.add_stretch("a")
b = qc.add_stretch("b")
c = qc.add_stretch("c")
# Use the stretches as Delay duration.
qc.delay(a, [0, 1])
qc.delay(b, 2)
qc.delay(c, [3, 4])
qc.barrier()Quando si utilizza il servizio Compute di IBM Quantumstretch , eventuali frazioni risultanti da una risoluzione dello stretch vengono aggiunte al primo ritardo che utilizza lo stretch.
Esempio:
a = circuit.add_stretch("a")
circuit.barrier(q0, q1)
circuit.delay(100, q0)
circuit.delay(a, q1) # resolve to 26
circuit.x(q1) # duration: 8
circuit.delay(a, q1) # resolve to 25
circuit.x(q1) # duration: 8
circuit.delay(a, q1) # resolve to 25
circuit.x(q1) # duration: 8
circuit.barrier(q0, q1)Il codice di cui sopra risolve con un valore di 25 e un resto di 1. Al primo ritardo[a] verrà aggiunto il resto.
Equazione di risoluzione dello stiramento:
Visualizza i valori di estensione nel servizio di calcolo " IBM Quantum "
Il valore effettivo della durata di uno stretch viene determinato in fase di compilazione, dopo la pianificazione del circuito. Quando si esegue un processo Sampler in un servizio di elaborazion IBM Quantum, è possibile visualizzare i valori di estensione risolti nei metadati dei risultati del processo. Il supporto per stretch in Quantum Compute è attualmente in fase sperimentale, pertanto è necessario innanzitutto impostare un'opzione sperimentale per abilitarne il recupero, quindi accedere ai dati direttamente dai metadati come segue:
# Enable stretch value retrieval.
sampler.options.experimental = {
"execution": {
"stretch_values": True,
"scheduler_timing": True,
},
}
# Access the stretch values from the metadata.
job_result = job.result()
circuit_stretch_values = (
job_result[0].metadata["compilation"]["stretch_values"]
)
# Visualize the timing.
# Use the sliders at the bottom, the controls at the top, and the
# legend on the side of the output to customize the view.
draw_circuit_schedule_timing(ob.result()[0].metadata['compilation']
['scheduler_timing']['timing'])Sebbene il tempo totale di esecuzione del circuito sia riportato nei metadati "compilation", NON si tratta del tempo utilizzato ai fini della fatturazione (tempo QPU).
Comprendere l'output dei metadati
I stretch_values metadati restituiscono le seguenti informazioni:
- Nome: Il nome dell'estensione applicata.
- Valore: il valore dell'obiettivo richiesto.
- Resto: il resto risultante dalla risoluzione dell'allungamento, che viene aggiunto al primo ritardo che utilizza l'allungamento.
- Valori espansi: insiemi di valori che specificano l'inizio dell'allungamento e la sua durata.
Esempio
# Define the circuit
circuit = QuantumCircuit(4)
foo = circuit.add_stretch("foo")
bar = circuit.add_stretch("bar")
circuit.barrier()
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.delay(foo, 2)
circuit.x(2)
# 3*foo
circuit.delay(expr.mul(3, foo), 2)
circuit.x(2)
# 2*foo
circuit.delay(expr.mul(2, foo), 2)
circuit.delay(bar, 3)
circuit.x(3)
circuit.delay(bar, 3)
circuit.measure_all()Output dei metadati
[{'name': 'bar',
'value': 29,
'remainder': 1,
'expanded_values': [[1365, 30], [1404, 29]]},
{'name': 'foo',
'value': 8,
'remainder': 2,
'expanded_values': [[1365, 10], [1384, 24], [1417, 16]]}
]I valori restituiti per la durata dipendono dal valore dell'obiettivo e dal resto calcolato. Ad esempio, queste sono le durate restituite per foo:
foo value+remainder(8+2 = 10)foo value* 3 (8 x 3 = 24)foo value* 2 (8 x 2 = 16)
È possibile utilizzare una visualizzazione per comprendere e verificare la tempistica.
draw_circuit_schedule_timing(job.result()[0].metadata
['compilation']['scheduler_timing']['timing'])Nell'immagine seguente, basata sull'output di esempio, foo corrisponde agli allungamenti su Qubit 2. Il primo ritardo di allungamento che utilizza foo inizia alla fine del init_play (1365). La durata dell'estensione è 10, quindi il ritardo termina quando inizia il x gate (1365+10=1375). È possibile interpretare il secondo e il terzo tratto in modo simile.

Utilizza i cursori nella parte inferiore, i controlli nella parte superiore (passa con il mouse sull'immagine di output per visualizzarli) e la legenda sul lato dell'output per personalizzare la visualizzazione. Passa il mouse sull'immagine per visualizzare i dati esatti.
Per ulteriori dettagli, consultare la sezione "Visualizzazione dei tempi dei circuiti ".
Limiti del calcolo quantistico
Il supporto per in stretch Quantum Compute è attualmente in fase sperimentale e presenta i seguenti limiti:
-
Al massimo una variabile di tratto per ogni qubit impostato tra le barriere (implicite ed esplicite). Un insieme di qubit è uno o più qubit; questi insiemi devono essere mutuamente esclusivi.
a = circuit.add_stretch("a") b = circuit.add_stretch("b") circuit.delay(a, (q0, q1)) circuit.delay(b, q0) # Invalid because 2 stretches are applied on q0a = circuit.add_stretch("a") b = circuit.add_stretch("b") circuit.delay(a, (q0, q1)) circuit.delay(b, q2) -
L'area circondata da un insieme di barriere è chiamata regione barriera. Una variabile di tipo stretch non può essere utilizzata in più regioni barriera.
# Stretch a is used in two barrier regions a = circuit.add_stretch("a") circuit.barrier((q0, q1)) circuit.delay(a, q0) circuit.barrier((q0, q1)) circuit.delay(a, q0) circuit.barrier((q0, q1)): uso non corretto della funzione stretch nelle regioni di barriera # Stretch a is used inside a barrier region that is on q0 and q1 a = circuit.add_stretch("a") circuit.barrier((q0, q1)) circuit.delay(a, q0) circuit.barrier(q2) circuit.delay(a, q0) circuit.barrier((q0, q1))corretto della funzione stretch in una regione barriera -
Le espressioni stretch sono limitate a quelle della forma
X*stretch + YdoveXeYsono costanti in virgola mobile o interi.a = circuit.add_stretch("a") b = circuit.add_stretch("b") c = circuit.add_stretch("c") # (a / b) * c is not supported circuit.delay(expr.mul(expr.div(a, b), c), q1)from qiskit.circuit import Duration a = circuit.add_stretch("a") circuit.delay(expr.add(expr.mul(a, 2), Duration.dt(3)), 0) -
Le espressioni di stiramento possono includere una sola variabile di stiramento.
a = circuit.add_stretch("a") b = circuit.add_stretch("b") circuit.delay(expr.add(a, b), 0)a = circuit.add_stretch("a") circuit.delay(expr.add(a, a), 0) -
Le espressioni stretch non possono risolvere con valori di ritardo negativi. Il solutore attuale non deduce i vincoli di non negatività.
from qiskit.circuit import Duration circuit.barrier((q0, q1)) circuit.delay(20, q1) # The length of this barrier region is 20dt, meaning the # equation for solving stretch 'a' is a + 40dt = 20dt, giving a = -20dt. circuit.delay(expr.add(a, Duration.dt(40)), q0) circuit.barrier((q0, q1))circuit.barrier((q0, q1)) circuit.delay(20, q1) circuit.delay(a, q0) circuit.barrier((q0, q1))