OpenQASM 2
qiskit.qasm2
Qiskit supporta l'interoperabilità con i programmi di OpenQASM 2.0, sia per l' analisi dei formati di Qiskit che per l' esportazione in OpenQASM 2.
OpenQASM 2 è un linguaggio semplice e non adatto alla serializzazione generale degli oggetti Qiskit. Se è questo che state cercando, vedete alcune discussioni sulle alternative qui di seguito.
Analisi dell'API
Questo modulo contiene due funzioni pubbliche, entrambe in grado di creare un file QuantumCircuit da un programma OpenQASM 2. load() accetta un nome di file, mentre loads() prende il programma stesso come stringa. I loro interni sono molto simili, quindi entrambi offrono quasi le stesse API.
load
qiskit.qasm2.load(filename, *, include_path=('.',), include_input_directory='append', custom_instructions=(), custom_classical=(), strict=False)
Analizzare un programma OpenQASM 2 da un file in un file QuantumCircuit. Il percorso indicato deve essere codificato ASCII o UTF-8 e contenere il programma OpenQASM 2.
Il parser interno per le espressioni classiche è ricorsivo e genera un'eccezione RecursionError se una qualsiasi espressione richiede una profondità eccessiva per essere valutata. Questa profondità massima può essere regolata utilizzando sys.setrecursionlimit(); il limite effettivo è pari a un decimo di questo valore.
Parametri
- filename (str |PathLike) – Il percorso del file « OpenQASM e 2».
- include_path (Iterable[str |PathLike]) – ordine delle directory da cercare durante l'esecuzione
includedelle istruzioni. - include_input_directory (Literal['append', 'prepend'] | None) – Se aggiungere la directory del file di input a
include_pathe, in tal caso, se aggiungerla alla ricerca per ultima o se anteporla alla ricerca per prima. PassareNoneper sopprimere completamente l'aggiunta di questa directory. - custom_instructions (Iterable[CustomInstruction]) – eventuali costruttori personalizzati da utilizzare per porte specifiche o istruzioni opache durante la progettazione del circuito. Per ulteriori informazioni, consulta la sezione "Specificare istruzioni personalizzate".
- custom_classical (Iterable[CustomClassical]) – eventuali funzioni classiche personalizzate che dovrebbero essere utilizzate durante l'analisi delle espressioni classiche. Per ulteriori informazioni, consultare la sezione "Specificazione di funzioni classiche personalizzate".
- strict (bool) – se eseguire in modalità rigorosa.
Risultati
Un oggetto circuito che rappresenta lo stesso programma OpenQASM 2.
Tipo di restituzione
loads
qiskit.qasm2.loads(string, *, include_path=('.',), custom_instructions=(), custom_classical=(), strict=False)
Analizzare un programma OpenQASM 2 da una stringa in un file QuantumCircuit.
Il parser interno per le espressioni classiche è ricorsivo e genera un'eccezione RecursionError se una qualsiasi espressione richiede una profondità eccessiva per essere valutata. Questa profondità massima può essere regolata utilizzando sys.setrecursionlimit(); il limite effettivo è pari a un decimo di questo valore.
Parametri
- string (str) – Il programma OpenQASM 2 in una stringa.
- include_path (Iterable[str |PathLike]) – ordine delle directory da cercare durante l'esecuzione
includedelle istruzioni. - custom_instructions (Iterable[CustomInstruction]) – eventuali costruttori personalizzati da utilizzare per porte specifiche o istruzioni opache durante la progettazione del circuito. Per ulteriori informazioni, consulta la sezione "Specificare istruzioni personalizzate".
- custom_classical (Iterable[CustomClassical]) – eventuali funzioni classiche personalizzate che dovrebbero essere utilizzate durante l'analisi delle espressioni classiche. Per ulteriori informazioni, consultare la sezione "Specificazione di funzioni classiche personalizzate".
- strict (bool) – se eseguire in modalità rigorosa.
Risultati
Un oggetto circuito che rappresenta lo stesso programma OpenQASM 2.
Tipo di restituzione
Entrambe le funzioni di caricamento accettano anche un argomento include_path, che è un'iterabile di nomi di directory da utilizzare per la ricerca di file nelle istruzioni include . Le directory vengono provate a partire dall'indice 0 e viene utilizzata la prima corrispondenza. L'importazione qelib1.inc viene trattata in modo speciale; viene sempre trovata prima di cercare nel percorso include e contiene esattamente il contenuto del documento che descrive il linguaggio OpenQASM 2. Le porte di questo file di inclusione sono mappate sugli oggetti porta della libreria dei circuiti definiti da Qiskit.
Specificare istruzioni personalizzate
È possibile estendere i componenti quantistici del linguaggio OpenQASM 2 passando come argomento custom_instructions un iterabile di informazioni sulle istruzioni personalizzate. Nei file che hanno definizioni compatibili per queste istruzioni, il dato constructor sarà utilizzato al posto di qualsiasi altra gestione qiskit.qasm2 sarebbe stato fatto. Queste istruzioni possono essere facoltativamente contrassegnate come builtin, il che fa sì che non richiedano una dichiarazione opaque o gate , ma ignoreranno silenziosamente una dichiarazione compatibile. In ogni caso, è un errore fornire un'istruzione personalizzata con un numero diverso di parametri o qubit come un'istruzione definita in un programma analizzato. Ogni elemento dell'argomento iterabile deve essere una particolare classe di dati:
CustomInstruction
class qiskit.qasm2.CustomInstruction(name, num_params, num_qubits, constructor, builtin=False)
Basi: object
Informazioni su un'istruzione personalizzata che deve essere definita durante l'analisi.
I campi name, num_params e num_qubits sono autoesplicativi. Il campo constructor deve essere un oggetto richiamabile con la firma *args -> Instruction, dove ogni num_params args è un valore in virgola mobile. La maggior parte delle classi di gate Qiskit incorporate hanno questa forma.
C'è un campo finale builtin . Questa opzione è facoltativa e, se impostata a true, fa sì che l'istruzione sia definita e disponibile all'interno del parsing, anche se non esiste una definizione in nessun file OpenQASM 2 incluso.
Esempi
Indicare all'importatore di utilizzare gli oggetti e RZXGate di ECRGate Qiskit per interpretare gate le istruzioni che si sa essere state create a partire da quegli stessi oggetti durante l'esportazione da OpenQASM 2:
from qiskit import qasm2
from qiskit.circuit import QuantumCircuit, library
qc = QuantumCircuit(2)
qc.ecr(0, 1)
qc.rzx(0.3, 0, 1)
qc.rzx(0.7, 1, 0)
qc.rzx(1.5, 0, 1)
qc.ecr(1, 0)
# This output string includes `gate ecr q0, q1 { ... }` and `gate rzx(p) q0, q1 { ... }`
# statements, since `ecr` and `rzx` are neither built-in gates nor in ``qelib1.inc``.
dumped = qasm2.dumps(qc)
# Tell the importer how to interpret the `gate` statements, which we know are safe
# because we controlled the input OpenQASM 2 source.
custom = [
qasm2.CustomInstruction("ecr", 0, 2, library.ECRGate),
qasm2.CustomInstruction("rzx", 1, 2, library.RZXGate),
]
loaded = qasm2.loads(dumped, custom_instructions=custom)Parametri
Ciò può essere particolarmente utile quando si cerca di risolvere le ambiguità nelle convenzioni della fase globale di un programma OpenQASM 2. Per maggiori dettagli, vedere OpenQASM 2 Convenzioni di fase.
Specificare funzioni classiche personalizzate
Analogamente alle estensioni quantistiche di cui sopra, è possibile estendere l'elaborazione delle espressioni classiche (argomenti dei gate) passando un iterabile all'argomento custom_classical a uno dei due caricatori. Questo ha bisogno del name (un identificatore valido OpenQASM 2), del numero num_params di parametri che accetta e di un Python callable che implementi la funzione. Il callable Python deve essere in grado di accettare num_params argomenti posizionali in virgola mobile e deve restituire un float o un intero (che sarà convertito in un float). Le funzioni integrate non possono essere sovrascritte.
CustomClassical
class qiskit.qasm2.CustomClassical(name, num_params, callable, /)
Basi: object
Informazioni su una funzione classica personalizzata che deve essere definita nelle espressioni matematiche.
Il callable dato deve essere una funzione Python che accetta num_params float e restituisce un float. Il nome è l'identificativo a cui ci si riferisce nel programma OpenQASM 2. Questo non può entrare in conflitto con nessun cancello definito.
Modalità ristretta
Entrambe le funzioni del caricatore hanno una modalità "strict" opzionale. Per impostazione predefinita, questo parser è un po' più rilassato rispetto alle specifiche ufficiali: consente l'inserimento di virgole negli elenchi di parametri, di punti e virgole non necessari (dichiarazioni vuote), di omettere la dichiarazione di versione OPENQASM 2.0; e un paio di altri miglioramenti della qualità della vita, senza emettere alcun errore. È possibile utilizzare la modalità lettera-specifica con strict=True.
Esportazione API
Come altri moduli di serializzazione in Python, questo modulo offre due funzioni pubbliche: dump() e dumps()che prendono un oggetto QuantumCircuit e scrivono un programma rappresentativo di OpenQASM 2 in un oggetto simile a un file o restituiscono una stringa, rispettivamente.
dump
qiskit.qasm2.dump(circuit, filename_or_stream, /)
Eseguire il dump di un circuito come programma OpenQASM 2 in un file o in un flusso.
Parametri
- circuit (QuantumCircuit) – il
QuantumCircuitda esportare. - filename_or_stream (PathLike |TextIOBase) – un oggetto simile a un percorso (probabilmente un
stropathlib.Path), oppure un flusso in modalità testo già aperto.
Aumenti
QASM2ExportError - se il circuito non può essere rappresentato da OpenQASM 2.
dumps
qiskit.qasm2.dumps(circuit, /)
Esportazione di un circuito in un programma OpenQASM 2 in una stringa.
Parametri
circuit (QuantumCircuit) – il QuantumCircuit da esportare.
Risultati
Una stringa OpenQASM 2 che rappresenta il circuito.
Aumenti
QASM2ExportError - se il circuito non può essere rappresentato da OpenQASM 2.
Tipo di restituzione
Errori
Questo modulo definisce un tipo di errore generico che deriva da QiskitError che può essere usato come cattura quando ci si preoccupa dei fallimenti emessi dal livello di interoperatività in modo specifico.
QASM2Error
exception qiskit.qasm2.QASM2Error(*message)
Basi: QiskitError
Un errore generale sollevato dal livello di interoperatività OpenQASM 2.
Impostare il messaggio di errore.
Nei casi in cui il lexer o il parser falliscano a causa di un file OpenQASM 2 non valido, le funzioni di conversione solleveranno un errore più specifico con un messaggio che spiega quale sia il fallimento e in quale punto del file si sia verificato.
QASM2ParseError
exception qiskit.qasm2.QASM2ParseError(*message)
Basi: QASM2Error
Errore generato da un errore di analisi di un file OpenQASM 2.
Impostare il messaggio di errore.
Quando gli esportatori non riescono a esportare un circuito, probabilmente perché ha una struttura che non può essere rappresentata da OpenQASM 2.0, emettono anche un errore personalizzato.
QASM2ExportError
exception qiskit.qasm2.QASM2ExportError(*message)
Basi: QASM2Error
È stato rilevato un errore a causa di una mancata conversione di un oggetto Qiskit in un modulo OpenQASM 2.
Impostare il messaggio di errore.
Esempi
Esempi di esportazione
Esportazione di un semplice QuantumCircuit in una stringa OpenQASM 2:
import qiskit.qasm2
from qiskit.circuit import QuantumCircuit
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
print(qiskit.qasm2.dumps(qc))OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];Scrivere lo stesso QuantumCircuit in un determinato nome di file:
qiskit.qasm2.dump(qc, "myfile.qasm")Allo stesso modo, si possono usare istanze generali os.PathLike come nome del file:
import pathlib
qiskit.qasm2.dump(qc, pathlib.Path.home() / "myfile.qasm")Si può anche scaricare il testo in un flusso già aperto:
import io
with io.StringIO() as stream:
qiskit.qasm2.dump(qc, stream)Esempi di analisi sintattica
Utilizzare loads() per importare un programma OpenQASM 2 in una stringa in un file QuantumCircuit:
import qiskit.qasm2
program = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0], q[1];
measure q -> c;
"""
circuit = qiskit.qasm2.loads(program)
circuit.draw() ┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1È possibile ottenere la stessa cosa se il programma è memorizzato in un file utilizzando load() passando il nome del file come argomento:
import qiskit.qasm2
circuit = qiskit.qasm2.load("myfile.qasm")OpenQASM 2 possono includere altri file di OpenQASM 2 tramite l'istruzione include . È possibile influenzare il percorso di ricerca utilizzato per trovare questi file con l'argomento include_path a entrambi i comandi load() e loads(). Per impostazione predefinita, viene ricercata solo la directory di lavoro corrente.
import qiskit.qasm2
program = """
include "other.qasm";
// ... and so on
"""
circuit = qiskit.qasm2.loads(program, include_path=("/path/to/a", "/path/to/b", "."))Solo per load() c'è un argomento aggiuntivo include_input_directory, che può essere usato per 'append', 'prepend' o per ignorare (None) la directory del file caricato nel percorso di inclusione. Per impostazione predefinita, questa directory viene aggiunta al percorso di ricerca, quindi viene provata per ultima, ma è possibile modificarla.
import qiskit.qasm2
filenames = ["./subdirectory/a.qasm", "/path/to/b.qasm", "~/my.qasm"]
# Search the directory of each file before other parts of the include path.
circuits = [
qiskit.qasm2.load(filename, include_input_directory="prepend") for filename in filenames
]
# Override the include path, and don't search the directory of each file unless it's in the
# absolute path list.
circuits = [
qiskit.qasm2.load(
filename,
include_path=("/usr/include/qasm", "~/qasm/include"),
include_input_directory=None,
)
for filename in filenames
]A volte potrebbe essere necessario modificare gli Gate oggetti generati dall’importatore per determinate istruzioni denominate. I gate definiti dall'istruzione include "qelib1.inc"; verranno automaticamente associati a un gate appropriato della libreria di circuiti di Qiskit, ma è possibile estendere questa funzionalità:
from qiskit.circuit import Gate
from qiskit.qasm2 import loads, CustomInstruction
class MyGate(Gate):
def __init__(self, theta):
super().__init__("my", 2, [theta])
class Builtin(Gate):
def __init__(self):
super().__init__("builtin", 1, [])
program = """
opaque my(theta) q1, q2;
qreg q[2];
my(0.5) q[0], q[1];
builtin q[0];
"""
customs = [
CustomInstruction(name="my", num_params=1, num_qubits=2, constructor=MyGate),
# Setting 'builtin=True' means the instruction doesn't require a declaration to be usable.
CustomInstruction("builtin", 0, 1, Builtin, builtin=True),
]
circuit = loads(program, custom_instructions=customs)Allo stesso modo, è possibile aggiungere nuove funzioni classiche utilizzate durante la descrizione degli argomenti delle porte, sia nel corpo principale del programma (che escono piegate in modo costante) sia all'interno dei corpi delle porte definite (che vengono calcolate su richiesta). Qui forniamo una versione Python di atan2(y, x), che matematicamente è ma gestisce correttamente i quadranti angolari e gli infiniti, e una funzione add_one personalizzata:
import math
from qiskit.qasm2 import loads, CustomClassical
program = """
include "qelib1.inc";
qreg q[2];
rx(atan2(pi, 3 + add_one(0.2))) q[0];
cx q[0], q[1];
"""
def add_one(x):
return x + 1
customs = [
# `atan2` takes two parameters, and `math.atan2` implements it.
CustomClassical("atan2", 2, math.atan2),
# Our `add_one` takes only one parameter.
CustomClassical("add_one", 1, add_one),
]
circuit = loads(program, custom_classical=customs)OpenQASM Convenzioni a 2 fasi
Come linguaggio, OpenQASM 2 non ha un modo per specificare la fase globale di un programma completo, né di particolari definizioni di porte. Ciò significa che i parser del linguaggio possono interpretare particolari porte con una fase globale diversa da quella che ci si potrebbe aspettare. Ad esempio, la libreria standard de facto di OpenQASM 2 qelib1.inc contiene le definizioni di u1 e rz come segue:
gate u1(lambda) q {
U(0, 0, lambda) q;
}
gate rz(phi) a {
u1(phi) a;
}In altre parole, rz sembra essere un alias diretto di u1. Tuttavia, l'interpretazione di u1 è specificata nell' equazione (3) del documento che descrive il linguaggio come
dove il simbolo denota l'equivalenza solo fino a una fase globale. Nel parsing di OpenQASM 2, dobbiamo scegliere come gestire una distinzione tra tali porte; u1 è definito nella prosa come diverso da una fase rispetto a rz, ma il linguaggio non è progettato per rappresentarlo.
U1GateL'impostazione predefinita di Qiskit è quella di interpretare l'uso della libreria standard rz tramite RZGate, mentre l'uso di u1 viene interpretato come l'uso di, con fasi distinte. Se desideri utilizzare le convenzioni di fase che derivano più direttamente da un'interpretazione letterale delle gate istruzioni contenute nel file di intestazione, puoi utilizzare CustomInstruction per sovrascrivere il modo in cui Qiskit costruisce il circuito.
Per lo standard qelib1.inc include un solo punto di differenza, e quindi l'override necessario per cambiare la convenzione di fase è:
from qiskit import qasm2
from qiskit.circuit.library import PhaseGate
from qiskit.quantum_info import Operator
program = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[1];
rz(pi / 2) q[0];
"""
custom = [
qasm2.CustomInstruction("rz", 1, 1, PhaseGate),
]U1GateIn questo modo si utilizzerà la classe di PhaseGate Qiskit per rappresentare l'istruzione rz , che è uguale (compresa la fase) a:
Operator(qasm2.loads(program, custom_instructions=custom))Operator([[1.000000e+00+0.j, 0.000000e+00+0.j],
[0.000000e+00+0.j, 6.123234e-17+1.j]],
input_dims=(2,), output_dims=(2,))Compatibilità con le versioni precedenti
QuantumCircuit.from_qasm_str() e from_qasm_file() utilizzato per apportare alcune aggiunte alle specifiche grezze. Qiskit ha originariamente cercato di utilizzare OpenQASM 2 come una sorta di formato di serializzazione, ampliando il suo comportamento man mano che Qiskit si espandeva. Il nuovo parser, con tutte le sue impostazioni predefinite, implementa le specifiche in modo più rigoroso.
In particolare, negli importatori legacy:
-
il percorso di inclusione è effettivamente:
<qiskit>/qasm/libs, dove<qiskit>è la radice del pacchettoqiskitinstallato;- la directory di lavoro corrente.
-
ci sono istruzioni aggiuntive definite in
qelib1.inc:csx a, bPorta controllata , corrispondente a
CSXGate.cu(theta, phi, lambda, gamma) c, tLa versione a quattro parametri di un modello “controlled- ”, corrispondente a
CUGate.rxx(theta) a, bRotazione di due qubit attorno all’asse , corrispondente a
RXXGate.rzz(theta) a, bRotazione di due qubit attorno all’asse , corrispondente a
RZZGate.rccx a, b, cLa porta di a doppio controllo, ma con differenze di fase relative rispetto alla porta di Toffoli standard.
RCCXGateQuesto dovrebbe corrispondere al gate di Qiskit, ma il convertitore legacy in realtà non genererebbe questo tipo.rc3x a, b, c, dIl gate “ ” a triplo controllo, ma con differenze di fase relative rispetto alla definizione standard. Corrisponde a
RC3XGate.c3x a, b, c, dIl gate “ ” a triplo controllo, corrispondente a
C3XGate.c3sqrtx a, b, c, dIl gate “ ” a triplo controllo, corrispondente a
C3SXGate.c4x a, b, c, d, eIl gate “ ” a quattro controlli., corrispondente a
C4XGate. -
se è stata data una definizione di
opaqueogateper il nomedelay, tentano di emettere un'istruzione ad ogni chiamataDelaya ogni chiamata. Per funzionare, ci si aspetta una definizione compatibile conopaque delay(t) q;, dove il tempotè dato in unità didt. L'importatore solleva errori di costruzione se non c'è esattamente un parametro e un qubit, o se il parametro non ha valore intero. -
sono disponibili le funzioni aggiuntive di calcolo scientifico
asin,acoseatan. -
la grammatica analizzata è effettivamente la stessa della modalità rigorosa dei nuovi importatori.
È possibile emulare questo comportamento in load() e loads() impostando include_path in modo appropriato (si provi a ispezionare la variabile qiskit.__file__ per trovare la posizione installata) e passando un elenco di istanze di CustomInstruction per ciascuno dei gate personalizzati di cui ci si occupa. Per semplificare le cose, mettiamo a disposizione tre tuple, ognuna delle quali contiene un componente di una configurazione equivalente al comportamento del convertitore legacy di Qiskit.
qiskit.qasm2.LEGACY_CUSTOM_INSTRUCTIONS
Una tupla contenente le istruzioni personalizzate extra che i convertitori integrati legacy di Qiskit utilizzano se qelib1.inc è incluso e c'è una qualsiasi definizione di istruzione delay . Le porte nella versione cartacea di qelib1.inc e delay richiedono tutte la presenza di una dichiarazione compatibile all'interno del programma OpenQASM 2, ma le aggiunte legacy di Qiskit sono tutte contrassegnate come builtin, poiché non sono effettivamente presenti in nessun file di inclusione visto da questo parser.
qiskit.qasm2.LEGACY_CUSTOM_CLASSICAL
Una tupla contenente le funzioni custom_classical extra che i convertitori integrati di Qiskit utilizzano oltre a quelle specificate dal documento. Si tratta delle tre funzioni trigonometriche inverse di base: , e .
qiskit.qasm2.LEGACY_INCLUDE_PATH
Una tupla contenente l'esatto percorso include_path usato dal convertitore Qiskit tradizionale.
Per tutti i gate definiti nella versione legacy di qelib1.inc e nell'istruzione delay di Qiskit, non importa come i gate siano effettivamente definiti e utilizzati, l'importatore legacy tenterà sempre di produrre i suoi oggetti personalizzati per essi. Questo può causare errori durante la costruzione del circuito, anche dopo un parsing riuscito. Non c'è modo di emulare questo comportamento difettoso con qiskit.qasm2; solo un'istruzione include "qelib1.inc"; o l'argomento custom_instructions possono far sì che vengano utilizzate le istruzioni integrate di Qiskit, le cui firme corrispondono l'una all'altra.
I circuiti importati con load() e loads() utilizzando le impostazioni di compatibilità con le versioni precedenti sopra indicate dovrebbero risultare identici a quelli creati dall'importatore legacy di Qiskit, a condizione che non siano definiti gate nonqelib1.inc utente. I gate definiti dall'utente vengono gestiti in modo leggermente diverso nel nuovo importatore e, sebbene a un'analisi più attenta dovrebbero presentare campi equivalenti definition , questo modulo utilizza una classe personalizzata per caricare la definizione in modo differito quando viene richiesta (come la maggior parte degli oggetti Qiskit), anziché crearla immediatamente durante l'analisi sintattica. Le regole di confronto di Qiskit per i gate considereranno questi due oggetti come disuguali, sebbene qualsiasi passaggio attraverso transpile() un determinato backend dovrebbe produrre gli stessi circuiti di uscita.
Alternative
I componenti del parser di questo modulo sono nati come un pacchetto separato PyPI : qiskit-qasm2. Questo pacchetto alla versione 0.5.3 è stato venduto in Qiskit Terra 0.24. Eventuali modifiche successive tra i due pacchetti potrebbero non essere necessariamente mantenute sincronizzate.
Esiste una versione più recente della specifica OpenQASM, la versione 3.0, che è descritta in https://openqasm.com. Questo include molte più strutture per la programmazione classica di alto livello. Qiskit ha già un supporto rudimentale per OpenQASM 3; vedere qiskit.qasm3 per questo.
OpenQASM 2 non è un linguaggio di serializzazione adatto a Qiskit QuantumCircuit. Questo modulo è fornito a scopo di interoperabilità, non come formato di serializzazione generale. Se questo è ciò di cui avete bisogno, prendete in considerazione l'uso di qiskit.qpy al suo posto.