Qiskit SDK 2.1 notes de mise à jour
2.1.2
Prélude
Qiskit 2.1.2 est un petit patch qui corrige plusieurs bugs trouvés dans la série 2.1.
Corrections des erreurs
-
Dans Qiskit 2.1.0, la passe de transpiler a été ajoutée à l'étape du gestionnaire de passes prédéfinies lorsque
VF2PostLayouttranspiler a été ajouté à l'étapeoptimizationdu gestionnaire de passes prédéfinies lorsqueoptimization_level=3. Cependant, la sortie du passeur n'a jamais été appliquée au circuit. Cette version supprime le laissez-passer de l'étapeoptimizationdu gestionnaire de laissez-passer prédéfini afin de réduire les coûts d'exécution. Dans Qiskit 2.2.0, la passe fera partie de l'étapeoptimizationet la sortie sera appliquée si la passe trouve une meilleure disposition. -
Correction d'un problème dans la passe
VF2Layoutoù, même avec un jeu de graines fixe, la sortie de la passe était potentiellement non déterministe, en particulier si le circuit d'entrée avait des qubits actifs qui ne contenaient que des opérations sur un seul qubit. Corrigé #14729 -
Correction d'un bogue dans
PassManager.run()où la fonctioncallbackn'était pas invoquée en cas d'utilisation de plusieurs circuits. Le rappel est désormais correctement déclenché pour chaque passe sur chaque circuit, y compris en cas d'exécution parallèle. -
Les passes de transposition intégrées qui définissent la propriété
final_layoutgèrent désormais correctement la mise à jour de ce champ s'il a déjà été défini. On peut observer que la méthodeTranspileLayout.routing_permutationrenvoie maintenant une permutation correcte après avoir exécuté plus d'une passe qui fixefinal_layout.Cela n'a pas eu d'incidence sur les appels normaux à
transpile()ougenerate_preset_pass_manager()utilisant les plugins intégrés de Qiskit; aucun pipeline construit sous cette forme ne tenterait de définirfinal_layoutplus d'une fois. -
Correction d'un bug dans
Target.instruction_supported()où la vérification de l'ordre des qubits de l'instruction était ignorée lorsque la méthode était appelée avec les argumentsoperation_nameetparametersqui correspondaient à une instruction existante. -
Correction d'un problème de correction lors de l'exportation de circuits avec des instructions de retard utilisant les unités
psvers QASM3. -
Correction d'un cas de figure dans l'affichage du
QFTcircuit. Auparavant, lorsque l'on appelaitQFT.inverse()était appelé et que les attributs du circuit QFT étaient modifiés, le nom du QFT était affiché sous la forme"IQFT_dg". Ce n'était pas le cas, et il s'agit maintenant de"IQFT". Correction #14758. -
Correction d'une fuite de mémoire dans la coordination de l'utilisation de
qk_circuit_get_instructionetqk_circuit_instruction_clear. -
Clarification du message d'erreur pour les versions spécifiées non valides en
qpy.dump()afin qu'il soit plus facile d'agir. -
Correction d'un problème avec la fonction
generate_preset_pass_manager()qui ignorait à tort les données relatives aux contraintes de temps contenues dans un objetTargetfourni lorsque l'argumentbackendn'était pas défini. Corrigé #14329 -
Correction d'un bug dans
SparsePauliOp.simplify()où la méthode supprimait les termes de Pauli sur la base de la magnitude de leurs coefficients avant de combiner les doublons. Cela a entraîné un comportement incorrect dans deux cas de figure importants :- Lorsque plusieurs termes de Pauli identiques avaient de petits coefficients qui étaient individuellement inférieurs au seuil de simplification mais dont la somme dépassait le seuil, ces termes ont été supprimés à tort.
- Lorsque plusieurs termes de Pauli identiques avaient des coefficients supérieurs au seuil mais dont la somme était proche de zéro, ils étaient incorrectement conservés.
Voir #14194 pour plus de détails.
2.1.1
Prélude
Qiskit 2.1.1 est un petit patch qui corrige plusieurs bugs trouvés dans la série 2.1.
Corrections des erreurs
-
Correction d'un bug dans la vérification de l'égalité
DAGOpNodeoù la comparaison de deux objetsDAGOpNodecontenant une instructionBoxOpinstruction. Auparavant, l'attributBoxOp.unitn'était pas pris en compte dans le cadre de la vérification de l'égalité, ce qui pouvait conduire à ce que deux nœuds inégaux soient considérés comme égaux. -
Correction de l'avertissement de dépréciation pour Python 3.9 afin qu'il soit correctement identifié comme étant causé par du code utilisateur lors de l'importation de Qiskit. Auparavant, il n'était pas identifié comme étant causé par le code de l'utilisateur, ce qui signifiait que les filtres d'avertissement par défaut de Python n'affichaient pas l'avertissement à l'utilisateur.
-
Correction du comportement de l'argument
max_trialspourVF2Layoutlorsqu'il est défini àNoneou à un nombre négatif. La passe a été documentée comme limitant la recherche à la taille du circuit ou de la cible si l'option est définie surNone, et comme acceptant des valeurs négatives pour spécifier une recherche non limitée. Cependant, dans 2.1.0, ce comportement a été modifié de manière incorrecte, de sorte queNoneeffectue une recherche non bornée et que l'utilisation d'un nombre négatif entraîne une erreur. Ces oublis ont été corrigés de manière à ce que la passe se comporte comme prévu et soit cohérente avec les versions précédentes. -
Correction d'un problème dans les plugins de synthèse de haut niveau
MCXSynthesis1DirtyKG24etMCXSynthesis2DirtyKG24pourMCXGateoù les plugins ne considéraient pas les qubits auxiliaires propres disponibles comme des qubits auxiliaires sales disponibles. En particulier, le pluginMCXSynthesis2DirtyKG24ne s'applique pas lorsqu'un qubit auxiliaire propre et un qubit auxiliaire sale sont disponibles. -
Correction d'une régression de performance lors de la construction incrémentale de
ParameterExpressionen combinant un grand nombre de sous-expressions. Corrigé #14653
2.1.0
Prélude
La version de Qiskit v2.1 introduit plusieurs améliorations importantes dans des domaines clés tels que l'API C, les capacités du transpilateur et la facilité d'utilisation des circuits quantiques. En outre, elle comprend de nombreuses améliorations générales et corrections de bogues. Les principaux faits marquants sont les suivants :
- Extensions de l'API C : S'appuyant sur le travail commencé dans la version précédente, Qiskit v2.1 ajoute le support pour la création et l'interaction avec des circuits quantiques via des fonctions API C, supportant l'ajout de portes standard, d'instructions standard et de portes unitaires. Cette version comprend également un ensemble de fonctions C permettant de construire et de manipuler un objet
Targeten préparation de la prise en charge d'un flux de travail de transpilation complet basé sur l'API C dans la prochaine version. De plus,QkComplex64est désormais défini comme une structure, ce qui permet de représenter les nombres complexes sans tenir compte du compilateur lorsque l'on travaille avec l'API C de Qiskit. Le fichier d'en-tête de l'API C a également été mis à jour afin qu'il soit généralement compatible avec une utilisation native en C++.- Prise en charge de l'ensemble de base Clifford+T : Le transpiling des circuits pour une cible avec des portes Clifford+T est maintenant pris en charge dès le départ. Sous le capot, si l'ensemble de base est constitué uniquement de portes Clifford+T, Qiskit s'assure que les passes appropriées pour traiter ces portes sont ajoutées aux gestionnaires de passes prédéfinis. Il s'agit d'une première étape vers la prise en charge de la transpilation pour les backends tolérants aux pannes.
- Améliorations apportées à
BoxOp: Cette version ajoute la possibilité d'attacher des annotations personnalisées aux instructionsBoxOpcette version ajoute la possibilité d'attacher des annotations personnalisées aux instructions, ce qui renforce le concept des déclarations en boîte de OpenQASM 3 dans Qiskit. Cela comprend également la sérialisation des annotations dans les formats QASM et QPY. En outre, la possibilité d'utiliser des durées d'étirement dans les boîtes a été ajoutée.- Python 3.9 dépréciation : Python 3.9 est déprécié à partir de Qiskit v2.1 et ne sera plus pris en charge dans Qiskit v2.3.
Pour plus de détails sur ce qui précède et bien d'autres choses encore, veuillez consulter les notes de version ci-dessous et visiter la documentation mise à jour.
Fonctionnalités de l'API C
-
L' API C de Qiskit ( qiskit.h ) permet désormais de construire et d'interagir avec les circuits quantiques. L'API C des circuits est centrée sur le type opaque
QkCircuitqui représente le circuit. Le typeQkCircuitpermet de construire un circuit avec n'importe quel élément de circuit défini nativement dans le modèle de données interne de Qiskit, Rust, pourQuantumCircuit. Il s'agit actuellement des portes standard,Measure,Delay,Reset,BarrieretUnitaryGate. Les capacités de l'API C des circuits seront étendues dans les prochaines versions, à mesure que le modèle de données Qiskit sera ajouté de manière native au modèle de données interne de Rust, ce qui permettra de l'utiliser dans l'API C.Par exemple, vous pouvez utiliser l'API C pour construire un état GHZ de 1000 qubits :
#include <qiskit.h> int main() { // Create an empty circuit with 1000 qubits and 1000 clbits QkCircuit *qc = qk_circuit_new(1000, 1000); // Add a Hadamard Gate on Qubit 0 uint32_t one_qubit[1] = {0,}; qk_circuit_gate(qc, QkGate_H, one_qubit, NULL); // The NULL pointer is for the parameter array. // Since Hadamard doesn't have parameters it // is never accessed. // Add the CX Gates: uint32_t qubits[2] = {0, 0}; uint32_t num_qubits = qk_circuit_num_qubits(qc); for (int i = 1; i<num_qubits; i++) { qubits[1] = i; qk_circuit_gate(qc, QkGate_CX, qubits, NULL); } // Add the measurements: uint32_t num_clbits = qk_circuit_num_clbits(qc); for (uint32_t i = 0; i<num_clbits; i++) { qk_circuit_measure(qc, i, i); } qk_circuit_free(qc); return 0; } -
L' API C de Qiskit ( qiskit.h ) prend désormais en charge la construction d'un fichier
Targetpour représenter une cible de transpilation. Par exemple :#include <qiskit.h> #include <math.h> int main() { // Create a Target with 3 qubits QkTarget *target = qk_target_new(3); // Create a Target Entry for a CX Gate QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX); // Define properties for CX between qubits (0, 1) with a duration of 1.93e-9 sec and error rate 3.17e-10. uint32_t qargs[2] = {0, 1}; qk_target_entry_add_property(cx_entry, qargs, 2, 1.93e-9, 3.17e-10); // Define properties for cx between qubits (1, 0) with a duration of 1.27e-9 sec and no error. uint32_t rev_qargs[2] = {1, 2}; qk_target_entry_add_property(cx_entry, rev_qargs, 2, 1.27e-9, NAN); // Add the cx entry to the target. QkExitCode result_cx = qk_target_add_instruction(target, cx_entry); // Add global ideal Y gate entry to the target QkExitCode result_y = qk_target_add_instruction(target, qk_target_entry_new(QkGate_Y)); // Create a Target entry for a Measurement with increasing duration and error as the qubit indices increase QkTargetEntry *measure = qk_target_entry_new_measure(); for (uint32_t i = 0; i< qk_target_num_qubits(target); i++) { uint32_t q[1] = {i}; qk_target_entry_add_property(measure, q, 1, 1e-6 * (i + 1), 1e-3 * (i + 1)); } QkExitCode result_measure = qk_target_add_instruction(target, measure); return 0; } -
Ajout d'un support pour l'interrogation des informations de version de Qiskit à partir de l'API C en utilisant les macros suivantes :
QISKIT_VERSION_MAJORnuméro de la version majeure : Contient le numéro de la version majeure.QISKIT_VERSION_MINORnuméro de la version mineure : Contient le numéro de la version mineure.QISKIT_VERSION_PATCHnuméro de version du correctif : Contient le numéro de version du correctif.QISKIT_VERSION: Contient une représentation numérique des informations relatives à la version, qui peut être utilisée pour des comparaisons.QISKIT_VERSION_NUMERIC(M,m,p): Une macro de type fonction qui renvoie la version " M.m.p " sous la forme d'une valeur numérique, qui peut être utilisée pour des comparaisons.
Par exemple, pour vérifier si la version actuelle est au moins 2.1.0, vous pouvez utiliser :
if (QISKIT_VERSION >= QISKIT_VERSION_NUMERIC(2, 1, 0)) { // Code for version 2.1.0 or later } -
Activation de la compatibilité C++ pour l'API C. L'en-tête généré permet désormais d'appeler directement des objets et des fonctions à partir de C++. Par exemple, une observable de 100 qubits avec le terme XYZ sur les 3 premiers qubits peut être construite comme suit
#include <iostream> #include <complex> #include <vector> #include <qiskit.h> int main() { uint32_t num_qubits = 100; // Use smart pointer with custom deleter to manage QkObs memory QkObs *obs = qk_obs_zero(num_qubits); // Construct the observable term std::complex<double> coeff_complex = 2.0; QkComplex64 coeff = qk_complex64_from_native(coeff_complex); std::vector<QkBitTerm> bit_terms = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z}; std::vector<uint32_t> indices = {0, 1, 2}; QkObsTerm term { .coeff = coeff, .len = bit_terms.size(), .bit_terms = bit_terms.data(), .indices = indices.data(), .num_qubits = num_qubits }; qk_obs_add_term(obs.get(), &term); // Print observable properties std::cout << "num_qubits: " << qk_obs_num_qubits(obs) << "\n"; std::cout << "num_terms: " << qk_obs_num_terms(obs) << "\n"; qk_obs_free(obs); return 0; }
Caractéristiques des circuits
-
Ajout d'une fonction
random_circuit_from_graph()qui génère un circuit aléatoire induisant le même graphe d'interaction que celui spécifié par interaction_graph.La probabilité de tirer au hasard une arête du graphe d'interaction en tant que porte à deux qubits peut être définie par l'utilisateur dans l'attribut de poids d'une arête dans le graphe d'interaction d'entrée. Si l'utilisateur ne définit pas de probabilité, chaque arête est dessinée uniformément. En d'autres termes, chaque porte à deux qubits représentée par une arête dans le graphe d'interaction a la même probabilité d'être ajoutée au circuit aléatoire. Si seul un sous-ensemble de probabilités d'arêtes est défini,
ValueErrorsera affiché.Dans cet exemple,
cp_mapest une liste d'arêtes avec des poids arbitraires.from qiskit.circuit.random.utils import random_circuit_from_graph import rustworkx as rx pydi_graph = rx.PyDiGraph() n_q = 5 cp_map = [(0, 1, 0.18), (1, 2, 0.15), (2, 3, 0.15), (3, 4, 0.22)] pydi_graph.extend_from_weighted_edge_list(cp_map) # cp_map can be passed in directly as interaction_graph qc = random_circuit_from_graph(interaction_graph = pydi_graph, min_2q_gate_per_edge = 1, max_operands = 2, measure = True, conditional = True, reset = True, seed = 0, insert_1q_oper = True, prob_conditional = 0.21, prob_reset = 0.1) qc.draw(output='mpl')
-
Ajout d'une nouvelle
QuantumCircuitméthode :QuantumCircuit.has_control_flow_op()pour vérifier si un objetQuantumCircuitcontient des opérations de flux de contrôle. -
Un nouveau module
qiskit.circuit.annotationet un objet de principeAnnotationont été ajoutés.Les annotations sont un moyen d'étiqueter les instructions (pour l'instant seulement
BoxOp) avec des données locales, personnalisées par l'utilisateur. Ces données sont destinées à être consommées par des passes de transposition personnalisées. Les annotations permettent d'attacher des données à des instructions spécifiques, plutôt que d'utiliser l'objet global-contextePropertySetlors de la compilation.Tous les objets
Annotationtous les objets ont un champnamespace. Cette clé sous forme de chaîne est utilisée pour les recherches, afin que les consommateurs puissent savoir s'ils gèrent une annotation particulière ou non. Il n'existe actuellement aucune méthode permettant d'interroger la sémantique abstraite d'une sous-classeAnnotationmais ces méthodes devraient être développées à l'avenir.Pour une analyse complète des capacités et des cas d'utilisation, voir
qiskit.circuit.annotationpour une discussion complète sur les capacités et les cas d'utilisation. -
BoxOp(créées parQuantumCircuit.box()) peuvent désormais être annotées avec des instancesAnnotationpersonnalisées. L'égalité de deux boîtes dépend de l'égalité des annotations.Généralement, cela se fait en passant une liste d'annotations comme seul argument positionnel lors de l'utilisation de
QuantumCircuit.box()sous la forme d'un gestionnaire de contexte :from qiskit.circuit import annotation, QuantumCircuit class MyAnnotation(annotation.Annotation): namespace = "my.annotation" def __eq__(self, other): return isinstance(other, MyAnnotation) qc = QuantumCircuit() with qc.box([MyAnnotation()]): pass -
La méthode
UnitaryGate.control()utilise désormais en interneqs_decomposition()au lieu deIsometrypour la décomposition utilisée pour définir l'élément contrôléUnitaryGate. Cette modification réduit le nombre deCXGateutilisés dans ledefinitionpour l'élément retournéControlledGated'environ 2x. -
Amélioration de la synthèse d'une commande multiple
U1Gateafin qu'elle ne croisse pas de manière exponentielle avec le nombre de contrôles. -
L'attribut
BoxOp.durationpeut désormais être unexpr.Exprde typeDurationtout commeDelay.duration. Il s'agit également de soutenirStretchpour la durée d'unBoxOp.
Fonctionnalités primitives
-
Les PUBs de l'estimateur utilisés comme entrée de
BaseEstimatorV2.run()peuvent désormais être définies à l'aide d'objetsSparseObservablepour la composante observable de PUB. Cela s'ajoute aux types déjà pris en charge, à savoir :str,Pauli,SparsePauliOpet une correspondance entre les valeurs destrouPauliaux valeurs defloat. Cependant, si leSparseObservablecontient des projecteurs, la prise en charge de ces derniers dépend de l'implémentation de la primitive. À partir de cette version, les implémentations dans Qiskit (StatevectorEstimatoretBackendEstimatorV2),qiskit-ibm-runtime(qiskit_ibm_runtime.EstimatorV2), et les implémentations primitives de Qiskit Aer (qiskit_aer.primitives.EstimatorV2) ne supportent pas encore les observables projectives. Les observables projectives sont celles qui contiennent les termes :0,1,+,-,r, oul. -
Ajouter un support à la classe
DataBinpour la rendre sérialisable avecpickle. Cela permet de rendre lesPrimitiveJobetPrimitiveResultsérialisable avecpickleégalement.
OpenQASM Caractéristiques
-
qasm3.dump()etqasm3.dumps()ont un nouvel argumentannotation_handlers, qui est utilisé pour fournir des instances deannotation.OpenQASM3Serializerau processus d'exportation OpenQASM 3, qui peut sérialiser les objets personnalisésAnnotationvers OpenQASM 3. -
Lorsque
qiskit_qasm3_import>=0.6.0est installé,qasm3.load()etqasm3.loads()ont un nouvel argumentannotation_handlers, qui est utilisé pour fournir des instances deannotation.OpenQASM3Serializerau processus d'importation de OpenQASM 3, qui peut désérialiser les objets personnalisésAnnotationà partir de OpenQASM 3. Ce support est actuellement limité aux déclarationsbox, car c'est le seul endroit où Qiskit peut représenter les annotations dans son modèle de données.
Caractéristiques du QPY
-
Ajout d'un nouveau format QPY, version 15, qui prend en charge les nouveaux objets
Annotationavec la prise en charge des sérialiseurs et désérialiseurs externes. Le format permet à ces sérialiseurs d'avoir un état, et des emplacements sûrs dans le format binaire sont alloués pour les objets d'état personnalisés et les représentations d'annotations personnalisées. -
qpy.dump()etqpy.load()ont maintenant un argument optionnelannotation_factories, qui est utilisé pour fournir des fonctions de construction d'objets de typeannotation.QPYSerializerpour gérer lesAnnotationsous-classes. Ceux-ci doivent être fournis par l'utilisateur, de la même manière que pourmetadata_serializer, car en général, Qiskit ne peut pas connaître tous les objets possibles définis de l'extérieurAnnotationdéfinis à l'extérieur. -
Ajout d'une nouvelle fonction
get_qpy_version()au moduleqpymodule. Cette fonction inspecte un fichier QPY et récupère la version du format QPY utilisée dans la charge utile. La version est renvoyée sous la forme d'un entier, qui peut être utilisé à des fins de journalisation ou de débogage. voir #14201.
Caractéristiques de l'information quantique
-
Une nouvelle classe,
PauliLindbladMapest ajoutée. Il s'agit d'une paramétrisation basée sur Pauli d'un sous-ensemble de cartes linéaires d'opérateurs multi-qubits, utilisée dans des applications d'apprentissage du bruit. Cette classe devrait constituer l'épine dorsale d'algorithmes améliorés d'apprentissage du bruit et permettre un contrôle meilleur et plus efficace des modèles de bruit dans les futures versions de Qiskit. -
Introduit le
QubitSparsePaulietQubitSparsePauliListqui représentent les mêmes concepts que les classesPaulietPauliListrespectivement, mais qui ne stockent que les termes non identiques, d'une manière analogue à la classeSparseObservable. Ces classes sont principalement destinées à être utilisées avec le nouveauPauliLindbladMap.
Caractéristiques de la synthèse
-
Ajout d'un nouvel algorithme de synthèse pour
HalfAdderGatequi ne nécessite pas de qubits auxiliaires et qui a un meilleur nombre de CX par rapport àadder_qft_d00(): -
Ajout de nouvelles décompositions pour
MCXGatel'utilisation d'ancillae propres, ce qui améliore la profondeur et l'efficacité des circuits :synth_mcx_1_clean_kg24()en utilisant 1 qubit ancilla propre supplémentairesynth_mcx_1_dirty_kg24()en utilisant 1 qubit ancilla sale supplémentairesynth_mcx_2_clean_kg24()en utilisant 2 qubits auxiliaires propres supplémentairessynth_mcx_2_dirty_kg24()en utilisant 2 qubits auxiliaires sales supplémentaires
Exemple d'utilisation :
from qiskit.synthesis.multi_controlled import synth_mcx_1_clean_kg24 n_ctrls = 10 qc = synth_mcx_1_clean_kg24(n_ctrls) qc.draw() -
La synthèse des portes multi-contrôlées a été améliorée pour réduire le nombre de portes synthétisées
CZGatea été améliorée afin de réduire le nombre de portes synthétisées. Dans certains cas, la réduction peut atteindre 99 %. Pour ce faire, on s'est appuyé sur la synthèse améliorée autour duMCXGateavec une synthèseCZGatede la synthèse contrôlée. -
Amélioration du plugin par défaut pour la synthèse d'objets
AnnotatedOperationobjets. Cette amélioration est particulièrement utile lors de la création et de la transposition de circuits contrôlés comportant des portes contrôlées. Par exemple :from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import CXGate from qiskit.compiler import transpile inner = QuantumCircuit(5) inner.append(CXGate().control(3, annotated=True), [0, 1, 2, 3, 4]) controlled_inner_gate = inner.to_gate().control(2, annotated=True) qc = QuantumCircuit(15) qc.append(controlled_inner_gate, [0, 1, 2, 3, 4, 5, 6]) qct = transpile(qc, basis_gates=["cx", "u"])Ce code crée un circuit quantique
qcqui contient un circuit quantique à 2 contrôles avec une porte CX à 3 contrôles. Grâce à cette amélioration, le nombre de portes CX dans le circuit transpilé est réduit de378à30. Il convient de noter qu'en spécifiantannotated=Truelors de la définition de la logique de contrôle, les portes contrôlées sont créées en tant qu'opérations annotées. Cela évite une synthèse trop rapide, permet au transpondeur de détecter quecontrolled_inner_gateest équivalent à une porte X à 6 contrôles, et de choisir la meilleure méthode de synthèse disponible pour les portes X à plusieurs contrôles, en particulier en utilisant les qubits ancilla disponibles. -
La fonction
adder_qft_d00()utilisée pour synthétiserModularAdderGateetHalfAdderGateaccepte désormais un paramètre supplémentaireannotated. SiTrue, la porte QFT inverse dans les additionneurs est mise en œuvre en tant qu'opérations annotées, ce qui permet au transpondeur d'appliquer des optimisations supplémentaires. -
La décomposition quantique de Shannon (
qs_decomposition()) comprend désormais une optimisation qui réduit le nombre deCXGatedans le cas où l'unité d'entrée est une unité contrôlée. -
La fonction de synthèse
synth_mcx_1_clean_b95()produit maintenant un circuit avec moins de portes CX. -
La classe
SolovayKitaevDecompositiondispose désormais d'arguments supplémentaires dans l'initialisateur, ce qui lui permet d'être directement construite à partir d'un ensemble debasis_gateset d'undepthpour les approximations de base. -
Ajouté
SolovayKitaevDecomposition.save_basic_approximations()pour enregistrer l'ensemble des approximations de base utilisées par la classe dans un format binaire. Cette modification, combinée aux nouveaux arguments de l'initialisateur, permet aux utilisateurs d'éviter l'utilisation explicite degenerate_basic_approximations()et de s'appuyer uniquement surSolovayKitaevDecomposition.
Fonctionnalités du transpilateur
-
La fonction
generate_preset_pass_manager()génère maintenant un gestionnaire de passe spécial lorsque l'ensemble de base est constitué uniquement de portes Clifford+T. Formellement, un ensemble de bases Clifford+T doit contenir uniquement des portes Clifford, ainsi que soitTGate,TdgGateou les deux. La liste complète des portes de Clifford prises en charge peut être obtenue en utilisant la commandeget_clifford_gate_names().Par exemple :
from qiskit.circuit import QuantumCircuit from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.quantum_info import get_clifford_gate_names basis_gates = get_clifford_gate_names() + ["t", "tdg"] pm = generate_preset_pass_manager(basis_gates=basis_gates) qc = QuantumCircuit(1) qc.rx(0.8, 0) qct = pm.run(qc) print(qct.count_ops())Il en résulterait avec :
OrderedDict([('h', 10210), ('t', 4508), ('tdg', 4503), ('sdg', 943), ('s', 941)])Auparavant, le gestionnaire de passes généré ne pouvait pas traiter l'exemple ci-dessus car il ne pouvait pas décomposer les portes de rotation à un qubit en portes de Clifford+T
UGateen portes de Clifford+T. Cependant, le nouveau gestionnaire de passe utilise la décomposition de Solovay-Kitaev pour approximer les portes de rotation à un qubit en utilisant les portesH,TetTdg, et appelle la passe de transposition pour traduire les portes dans l'ensemble de base cibleBasisTranslatorpour traduire les portes dans l'ensemble de base cible. Le nouveau gestionnaire de passes comporte également d'autres modifications permettant une traduction plus efficace en portes Clifford+T.Il est important de noter que l'ensemble de portes de la base Clifford+T spécifiée doit être universel, sinon la transpilation risque d'échouer. Bien que l'ensemble de portes
["h", "t", "tdg"]ou même["h", "t"]soit suffisant pour assurer l'universalité, il est recommandé d'ajouter d'autres portes de Clifford à l'ensemble si possible, faute de quoi la traduction risque d'être moins efficace. Par exemple, si la porte S n'est pas incluse, les portes S peuvent être décomposées en paires de portes T (c'est-à-dire que les portes de Clifford peuvent être décomposées en portes non-Clifford, ce qui n'est pas forcément le comportement souhaité).Voici un exemple un peu plus grand :
from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import QFTGate from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager qc = QuantumCircuit(4) qc.append(QFTGate(4), [0, 1, 2, 3]) basis_gates = ["cx", "s", "sdg", "h", "t", "tdg"] pm = generate_preset_pass_manager(basis_gates=basis_gates, optimization_level=2) qc = QuantumCircuit(4) qc.append(QFTGate(4), [0, 1, 2, 3]) qct = pm.run(qc) print(qct.count_ops())Il en résulterait avec :
OrderedDict([('h', 96510), ('tdg', 42396), ('t', 42389), ('s', 8240), ('sdg', 8235), ('cx', 12)]) -
Ajout d'un nouveau plugin de synthèse de haut niveau
HalfAdderSynthesisR25pour synthétiser unHalfAdderGate. Le nouveau plugin est basé suradder_ripple_r25().L'article
HalfAdderSynthesisDefaulta également été mis à jour pour suivre la séquence suivante de synthétiseurs de demi-addition :"HalfAdder.ripple_r25"lorsqu'il y a qubits,"HalfAdder.ripple_c04"lorsqu'un qubit auxiliaire est disponible, et"HalfAdder.ripple_r25"dans tous les autres cas. -
Ajout de plusieurs plugins de synthèse de haut niveau permettant de synthétiser des objets en forme d'étoile
MCXGate:MCXSynthesis1CleanKG24, sur la base desynth_mcx_1_clean_kg24().MCXSynthesis1DirtyKG24, sur la base desynth_mcx_1_dirty_kg24().MCXSynthesis2CleanKG24, sur la base desynth_mcx_2_clean_kg24().MCXSynthesis2DirtyKG24, sur la base desynth_mcx_2_dirty_kg24().
La classe
MCXSynthesisDefaulta également été mise à jour pour exécuter la séquence suivante de méthodes de synthèse MCX jusqu'à ce que la première réussisse : :"mcx.2_clean_kg24","mcx.1_clean_kg24","mcx.n_clean_m15","mcx.n_dirty_i15"`, ``"mcx.2_dirty_kg24","mcx.1_dirty_kg24","mcx.1_clean_b95","mcx.noaux_v24". Les méthodes sont ordonnées de manière à ce que les méthodes de meilleure qualité soient appliquées en premier. -
VF2PostLayouta été ajouté à la fin de l'étape d'optimisation par défaut lors de l'utilisation du niveau d'optimisation 3. -
Ajout d'une nouvelle passe d'optimisation
OptimizeCliffordTqui fusionne les paires de portes T consécutives en portes S et les paires de portes Tdg consécutives en portes Sdg. Cette optimisation est particulièrement efficace pour réduire le nombre de T après la décomposition de Solovay-Kitaev, qui produit plusieurs portes T ou Tdg consécutives. Par exemple :from qiskit.circuit import QuantumCircuit from qiskit.transpiler.passes import SolovayKitaev, OptimizeCliffordT qc = QuantumCircuit(1) qc.rx(0.8, 0) # Run Solovay-Kitaev pass on qc transpiled = SolovayKitaev()(qc) print(transpiled.count_ops().get("t", 0) + transpiled.count_ops().get("tdg", 0)) # Should print 12779 # Run Clifford+T optimization optimized = OptimizeCliffordT()(transpiled) print(optimized.count_ops().get("t", 0) + optimized.count_ops().get("tdg", 0)) # Should print 9011 -
Ajout de la passe
ContextAwareDynamicalDecouplingqui met en œuvre un découplage dynamique tenant compte du contexte, basé sur des séquences de Walsh-Hadamard. Les séquences de retard insérées seront mutuellement orthogonales aux séquences sur les qubits voisins et tiendront compte des spectateurs de contrôle/cible des portes CX et ECR. Pour plus d'informations, voir arXiv:2403.06852 pour plus d'informations.Exemple :
from qiskit.circuit.library import QFT from qiskit.transpiler import PassManager, CouplingMap from qiskit.transpiler.passes import ALAPScheduleAnalysis, ContextAwareDynamicalDecoupling from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.providers.fake_provider import GenericBackendV2 num_qubits = 10 circuit = QFT(num_qubits) circuit.measure_all() target = GenericBackendV2( 100, basis_gates=["id", "rz", "sx", "x", "ecr"], coupling_map=CouplingMap.from_grid(10, 10) ).target pm = generate_preset_pass_manager(optimization_level=2, target=target) dd = PassManager([ ALAPScheduleAnalysis(target=target), ContextAwareDynamicalDecoupling(target=target), ]) transpiled = pm.run(circuit) with_dd = dd.run(transpiled) with_dd.draw("mpl", idle_wires=False)
-
Ajout des attributs suivants à la classe
DAGCircuitpour permettre d'interroger le nombre de variables d'étirement :num_stretches,num_captured_stretchesetnum_declared_stretches. -
Ajout d'un nouveau plugin de synthèse unitaire
CliffordUnitarySynthesisqui tente de synthétiser une porte unitaire donnée en vérifiant si elle peut être représentée par un Clifford, auquel cas il renvoie un circuit qui implémente cette porte unitaire et n'est constitué que de portes de Clifford.Le plugin est invoqué par la passe
UnitarySynthesistranspiler pass lorsque le paramètremethodest fixé à"clifford".En outre, le paramètre
plugin_configdeUnitarySynthesispeut être utilisé pour transmettre les paramètres suivants spécifiques au plugin :- min_qubits : le nombre minimum de qubits à considérer (la valeur par défaut est 1).
- max_qubits : le nombre maximum de qubits à considérer (la valeur par défaut est 3).
Par exemple :
import math from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import UnitaryGate from qiskit.quantum_info import Operator from qiskit.transpiler.passes import UnitarySynthesis # clifford unitary over 2 qubits c2 = QuantumCircuit(2) c2.h(0) c2.rz(math.pi / 4, 1) c2.rz(math.pi / 4, 1) c2.sdg(1) uc2 = UnitaryGate(Operator(c2).data) # non-clifford unitary over 2 qubits n2 = QuantumCircuit(2) n2.h(0) n2.rz(math.pi / 4, 1) n2.sdg(1) un2 = UnitaryGate(Operator(n2).data) # quantum circuit with two unitary gates qc = QuantumCircuit(3) qc.append(uc2, [2, 1]) qc.append(un2, [0, 2]) transpiled = UnitarySynthesis(method="clifford")(qc) transpiled.draw("mpl")
L'exécution du code ci-dessus resynthétise la première porte unitaire en portes de Clifford, tandis que la deuxième porte reste inchangée.
Si nous modifions l'exemple ci-dessus comme suit :
config = {"min_qubits": 3} transpiled = UnitarySynthesis(method="clifford", plugin_config=config)(qc)les deux portes unitaires restent inchangées.
Fonctionnalités de visualisation
-
Introduction de styles personnalisés pour la fonction
dag_drawer()fonction. Cela vous permet de passer un dictionnaire au paramètrestyleavec des attributs personnalisés qui modifient le style du DAG que la fonction renvoie. Par exemple :from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.converters import circuit_to_dag from qiskit.visualization import dag_drawer q = QuantumRegister(3, 'q') c = ClassicalRegister(3, 'c') circ = QuantumCircuit(q, c) circ.h(q[0]) circ.cx(q[0], q[1]) circ.measure(q[0], c[0]) circ.rz(0.5, q[1]).c_if(c, 2) dag = circuit_to_dag(circ) style = { "inputnodecolor": "pink", "outputnodecolor": "lightblue", "opnodecolor": "red", } dag_drawer(dag, style=style)
Mise à niveau
-
La bibliothèque
python-dateutiln'est plus une dépendance de Qiskit. Depuis que Qiskit v2.0, plus rien dans la bibliothèque n'utilisait le sitepython-dateutilet Qiskit ne dépendait plus de la bibliothèque. Cette version le supprime de la liste des dépendances, de sorte qu'il n'est pas automatiquement installé comme condition préalable à l'utilisation de Qiskit. Si vous comptiez sur Qiskit pour installer dateutil pour vous en tant que dépendance, vous devrez maintenant vous assurer que vous l'installez manuellement (ce qui est la meilleure pratique pour les dépendances directes). -
sympyn'est plus nécessaire pour installer Qiskit. Après la migration vers un moteur symbolique basé sur Rust pour la classeParameterExpressionles utilisations de SymPy sont isolées à quelques utilitaires de visualisation, la passe deTemplateOptimizationtranspiler pass,ParameterExpression.sympify()(qui est explicitement pour l'interopérabilité SymPy ) etSparsePauliOp.simplify()en cas d'utilisation de coefficients paramétrés. Cette fonctionnalité n'étant pas la plus utilisée, SymPy est désormais traité comme une dépendance optionnelle et ces fonctions lèveront uneMissingOptionalLibraryErrorsi elles sont utilisées et que SymPy n'est pas installé. -
La dépendance à l'égard de
symengine, qui était utilisée pour la construction d'objets, a été suppriméeParameterExpressiona été supprimée. Il a été remplacé par un moteur symbolique interne et n'est plus nécessaire pour les fonctionnalités de base de Qiskit. La seule exception est que symengine a été incorporé dans les formats QPY 10, 11 et 12, il est donc toujours nécessaire si vous désérialisez ces formats. La dépendance à l'égard de symengine pourqpy.load()a été rendue explicitement optionnelle dans 2.0.0, mais si vous comptiez auparavant sur l'installation par défaut de symengine pour cette fonctionnalité, vous devrez désormais l'installer manuellement pour charger la charge utile. Si vous utilisiezParameterExpression.sympify()pour obtenir un objet expression symengine à partir d'un objetParameterExpressionvous obtiendrez désormais une expressionsympy. Si vous avez besoin de l'utiliser avec symengine, vous pouvez utilisersymengine.sympifypour convertir l'expressionsympyen une expression symengine.
Notes sur la mise à niveau des circuits
-
L'attribut
definitionde l'élémentHalfAdderGatea été modifié pour utiliser en interneadder_ripple_r25()pour générer la définition de la porte pour un circuit plus efficace sans qubits auxiliaires. Si l'ancienne définition est souhaitée pour une raison quelconque, vous pouvez utiliser directement la fonctionadder_qft_d00()qui générera un circuit équivalent à celui que l'on obtenait dans les versions précédentesdefinitiondans les versions précédentes. -
Le circuit renvoyé par la fonction
excitation_preserving()et la classeExcitationPreservingsont maintenant construits à l'aide d'un seulXXPlusYYGate. Il s'agit d'un changement par rapport aux versions précédentes qui utilisaient unRXXGatesuivi d'unRYYGate. Cette nouvelle construction de circuit est équivalente mais utilise moins de portes qui préservent toutes l'excitation, ce qui est par définition plus simple. -
Les
definitionde plusieurs portes standard ont été mis à jour selon les principes suivants :- Lorsqu'elle est disponible, une définition utilisant des portes de Clifford est préférée aux définitions qui incluent des portes non-Clifford.
- Lorsqu'elle est disponible, une définition utilisant des portes Clifford+T est préférée à une définition utilisant une porte
UGate. - L'utilisation de
PhaseGateest préférée àU1Gate. - L'utilisation de
UGateest préférée à`U2Gateet`U3Gate.
L'invariant suivant reste valable : en développant récursivement les définitions des portes, toute porte peut être exprimée en fin de compte en utilisant uniquement la base
["cx", "u"]. Les définitions de toutes les portes standard sont toutes équivalentes, de sorte que la sémantique des portes ne change pas, mais la construction exacte du circuit retourné pour certaines portes n'est plus exactement la même. Cette modification était nécessaire pour prendre en charge la transpilation Clifford+T. -
Qiskit utilise désormais sa propre bibliothèque d'expressions symboliques, basée sur Rust, pour implémenter les fonctions internes de
ParameterExpressionetParameter. Comme il s'agit d'une nouvelle implémentation du moteur de mathématiques symboliques de base utilisé pourParameterExpressionil peut y avoir des différences mineures dans le comportement exact de certaines fonctionnalités. Il devrait toujours produire des résultats équivalents pour l'API documentée. Veuillez ouvrir un dossier si vous constatez des problèmes d'exactitude.
Notes de mise à niveau de l'API C
-
La façon dont les nombres complexes sont exposés dans l'API C de Qiskit a changé. Auparavant,
QkComplex64était un type dépendant du compilateur qui permettait de transmettre des types complexes natifs par pointeur à l'API de Qiskit (par exemple sous la formedouble complex*). Bien que pratique, cette approche repose implicitement sur des hypothèses d'agencement de la mémoire qui ne sont pas strictement garanties.Qiskit v2.1 expose désormais
QkComplex64 { double re; double im; }en tant que structure, pour s'assurer que l'agencement de la mémoire est toujours compatible et pour un support plus large du compilateur. Pour des raisons de commodité, les convertisseursqk_complex64_from_nativeetqk_complex64_to_native, qui dépendent du compilateur, sont fournis, ce qui permet de convertir la structure en un nombre complexe natif. Notez qu'ils ne fonctionnent que sur les plates-formes supportantdouble complexou pour les compilateurs MSVC utilisant_Dcomplex.Par exemple :
#include <qiskit.h> #include <math.h> #include <stdio.h> #include <complex.h> int main(int argc, char *argv[]) { // platform-independent constructions: QkComplex64 coeff = {5.0, 3.0}; // ... or using converter // double complex native = 5.0 + I * 3; // uses C11 standard, does not work on MSVC // QkComplex64 coeff = qk_complex64_from_native(&native); // convert from native uint32_t num_qubits = 100; QkObs *obs = qk_obs_zero(num_qubits); QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z}; uint32_t indices[3] = {0, 1, 2}; QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits}; qk_obs_add_term(obs, &term); printf("num_qubits: %u\n", qk_obs_num_qubits(obs)); printf("num_terms: %lu\n", qk_obs_num_terms(obs)); qk_obs_free(obs); return 0; }
Notes de mise à niveau QPY
- La version QPY par défaut émise par
qpy.dump()a été remplacée par la dernière version 15 de QPY. Si vous avez besoin de générer une version plus ancienne pour une raison quelconque, vous pouvez utiliser le mot-cléversiondans la commandeqpy.dump()pour spécifier une version plus ancienne à générer.
Notes de mise à niveau de Synthesis
-
Le format de sérialisation des approximations de base dans les algorithmes Solovay-Kitaev est passé de
.npyà un autre format binaire, basé sur Rustserdeetbincode. Toutes les routines qui chargent des approximations de base (telles quegenerate_basic_approximations(),SolovayKitaevDecomposition.load_basic_approximations()ou l'initialisateur deSolovayKitaev) supportent toujours le chargement du format hérité. Cependant, tout nouveau fichier sera stocké dans le nouveau format. Si vous utilisez l'ancien format, rétrogradez Qiskit vers < 2.2 et stockez les fichiers nécessaires. -
Les valeurs par défaut de
SolovayKitaev(et les classes apparentées) sont passées àdepth=12etreps=5. Ceci est dû au fait que l'implémentation sous-jacente est maintenant en Rust, ce qui nous permet d'augmenter la précision par défaut, tout en restant significativement plus rapide que la version précédente Python.
Notes de mise à niveau du transpilateur
-
Les plugins de mise en page intégrés pour les gestionnaires de passage actuels ne contiendront plus leur composante principale (par exemple, une instance de "sabre") si aucune contrainte de couplage n'est fournie
SabreLayoutpour la scène "sabre" ) si aucune contrainte de couplage n'est fournie. Auparavant, les plugins construisaient des instances invalides de leurs passes de mise en page, en supposant qu'une logique distincte empêcherait les passes de s'exécuter et de soulever des exceptions.Cela ne devrait pas avoir d'effet significatif sur l'utilisation des gestionnaires de passes prédéfinis ou des plugins, puisqu'il n'était déjà jamais valable d'appeler les passes dans un état invalide.
Remarques concernant la dépréciation
-
La prise en charge de l'exécution de Qiskit avec Python 3.9 est obsolète et sera supprimée dans la version de Qiskit v2.3. La version 2.3.0 est la première version après que Python 3.9 soit en fin de vie et ne soit plus supporté [1]. Cela signifie qu'à partir de la version 2.3.0, vous devrez mettre à jour la version Python que vous utilisez vers Python 3.9 ou une version supérieure.
Circuits obsolètes
-
La bibliothèque de circuits a fait l'objet d'une refonte dans la version de Qiskit v1.3, dans laquelle des alternatives pour les objets de type
QuantumCircuitont été fournies, qui sont soit une fonctionInstructionou une fonction Python pour la construction. Ce remaniement permet au compilateur de raisonner sur les instructions de haut niveau et de réduire les frais généraux pour les circuits qui ne nécessitent pas d'optimisations de haut niveau.Toutes les
QuantumCircuitsont maintenant obsolètes en faveur de leurs alternatives introduites dans Qiskit v1.3. Dans ce cadre, la classe de baseBlueprintCircuitest également obsolète. Tous ont une période de dépréciation prolongée et ne seront supprimés que dans Qiskit v3.0.La classe
BlueprintCircuitn'a pas de remplaçant directQuantumCircuitdirectement ou une fonction qui génère des circuits. Pour plus de détails, voirqiskit.circuit.librarypour plus de détails, mais voici quelques circuits courants et leurs remplacements :QFT→QFTGateTwoLocal→n_local()(ce n'est pas une faute de frappe, cette fonction couvre les fonctionsNLocaletTwoLocal)EfficientSU2→efficient_su2()RealAmplitudes→real_amplitudes()ZZFeatureMap→zz_feature_map()QuantumVolume→quantum_volume()EvolvedOperatorAnsatz→evolved_operator_ansatz()MCXGrayCode→synth_mcx_gray_code()MCXRecursive→synth_mcx_n_dirty_i15()MCXVChain→synth_mcx_n_clean_m15()
Corrections des erreurs
-
Correction d'un bug dans la fonction
dag_drawer()et la méthodeDAGCircuit.draw()où la définition de l'argument du mot-cléstyle=plainn'affichait pas les étiquettes de circuit pour les nœuds du DAG dans la visualisation. -
Correction d'un bogue dans la méthode
QuantumCircuit.assign_parameters()où les paramètres qui n'étaient pas utilisés dans le circuit et qui étaient passés sous forme de chaînes n'étaient pas ignorés lorsque l'argumentstrict=Falseétait défini. Se référer au problème #13933 pour plus de détails. -
Correction de cas limites dans la configuration de
Makefilepour Windows, où la variable d'environnement prédéfinieOSne correspondait pas à la sortie de la commandeuname -s. -
Fixe l'attribut
namede l'attributOrGatequi était incorrectement défini à la chaîne"and"au lieu de la valeur attendue"or"qui est maintenant renvoyée. Cette valeur incorrecte"and"était en conflit avec leAndGate.nameet aurait pu conduire à plusieurs problèmes liés à l'utilisation deOrgateet à sa différenciation d'unAndGate. -
Correction d'un bug dans la fonction
qpy.load()qui ne parvenait pas à désérialiser les circuits dont les paramètres avaient été réaffectés à des paramètres portant le même nom. Correction de #13720, #13720, et #13720. -
Correction de l'article
GenericBackendV2pour inclure désormaisBoxOpcomme un type d'instruction pris en charge dans l'instruction généréeGenericBackendV2.targetgénéré lorsque le mot-clé argumentcontrol_flow=Trueest défini dans le constructeur. -
Lors de la synthèse d'une porte
MCXGateavec 3 commandes, la fonction de synthèsesynth_mcx_n_dirty_i15()nécessitait un qubit auxiliaire, produisant un circuit avec 5 qubits (3 de contrôle, 1 de cible et 1 auxiliaire). Cependant, l'algorithme de synthèse actuel n'utilise pas ce qubit auxiliaire. Ce comportement est maintenant corrigé : le circuit synthétisé est sur 4 qubits (3 de contrôle et 1 de cible), ce qui permet à la fonction de synthèse d'être appliquée dans un nombre légèrement plus important de cas. -
Les
QuantumCircuit.draw()etcircuit_drawer()rendra maintenant les instructionsBoxOpdans uneQuantumCircuitdans la même tranche verticale si les portées verticales ne se chevauchent pas sont désormais rendues dans la même tranche verticale, dans la mesure du possible. -
Correction de la méthode
QuantumCircuit.draw()et la fonctioncircuit_drawer()en mode"mpl"afin d'insérer moins d'espaces inutiles à l'intérieur du bord gauche lorsque l'on dessine des instances dans une fenêtreBoxOpdans unQuantumCircuit.
Autres remarques
-
Ajout d'une nouvelle cible de dépendance optionnelle
qpy-compat. Cette cible doit être utilisée si vous envisagez de charger des fichiers utilisant des formats QPY plus anciensqpydes fichiers utilisant les anciens formats QPY. La cible installe des exigences supplémentaires utilisées pour le chargement de fichiers QPY utilisant des versions de format < 13. If you are only using newer QPY format versions you do no need to install this. Theqpy.dump()only generates QPY > =13. Ceci n'est nécessaire que pour le chargement de fichiers générés avec des versions plus anciennes (antérieures à 2.0.0 ) de Qiskit. Vous pouvez installer cette nouvelle variante optionnelle avecpip install qiskit[qpy-compat]. -
Les poids relatifs des composantes "basic" et "lookahead" des
SabreSwapetSabreLayoutont été modifiés lorsque le suivi des ensembles étendus est actif (comme c'est toujours le cas enSabreLayoutet l'est par défaut dansSabreSwap). La composante heuristique relative à la distance entre les qubits dans une porte individuelle de la couche frontale ne s'affaiblit plus proportionnellement au nombre de portes dans la couche frontale; ce comportement était un choix historique, mais pour les circuits de grande taille, il a pour effet accidentel de faire en sorte que la couche frontale soit presque ignorée, ce qui est désastreux pour l'efficacité.Les améliorations de routage qui en résultent devraient être les plus perceptibles pour les circuits qui peuvent fréquemment être stratifiés en couches de plus de 20 portes parallèles à deux qubits.