QkDag
typedef struct QkDag QkDagLa QkDag structure expose une interface de bas niveau à la représentation sous forme de graphe acyclique dirigé (DAG) d'un circuit quantique par le transcompilateur Qiskit, destinée à être utilisée dans les passes du transcompilateur. Il n'expose que ce qui est défini dans le modèle de données interne de Qiskit. Il manque donc certaines fonctionnalités disponibles dans la classe de niveau DAGCircuit supérieur Python.
L'API C ne prend actuellement en charge que la création de DAG contenant des opérations définies dans le modèle de données Rust interne de Qiskit. En général, cela inclut uniquement les portes de la bibliothèque de portes standard, les opérations standard non unitaires (actuellement Barrier, Measure, Reset, et Delay) et UnitaryGate. Cette fonctionnalité sera étendue au fil du temps, à mesure que le modèle de données Rust sera développé pour prendre en charge nativement davantage de fonctionnalités.
Types de données
QkDagNodeType
enum QkDagNodeType
Le type de nœud dans un QkDag.
Les nœuds d'opération représentent une instruction appliquée. Les autres nœuds sont considérés comme des nœuds « filaires » et représentent les points finaux des chaînes de dépendance des données du DAG.
Valeurs :
énumérateur QkDagNodeType_Operation
Nœud opérationnel.
énumérateur QkDagNodeType_QubitIn
Nœud de départ du fil Qubit.
énumérateur QkDagNodeType_QubitOut
Nœud d'extrémité de fil Qubit.
énumérateur QkDagNodeType_ClbitIn
Nœud de départ du fil Clbit.
énumérateur QkDagNodeType_ClbitOut
Nœud d'extrémité de fil Clbit.
énumérateur QkDagNodeType_VarIn
Nœud classique à fil variable.
énumérateur QkDagNodeType_VarOut
Nœud d'extrémité de fil variable classique.
QkOperationKind
enum QkOperationKind
Le type d'opération.
Cette valeur est renvoyée lors de l'interrogation d'un nœud particulier du graphe avec qk_dag_op_node_kind, et est destinée à permettre à l'appelant de distribuer (par exemple via un « commutateur ») les appels spécifiques au type d'opération contenu.
Valeurs :
énumérateur QkOperationKind_Gate
énumérateur QkOperationKind_Barrier
énumérateur QkOperationKind_Delay
énumérateur QkOperationKind_Measure
énumérateur QkOperationKind_Reset
énumérateur QkOperationKind_Unitary
énumérateur QkOperationKind_PauliProductMeasurement
énumérateur QkOperationKind_ControlFlow
énumérateur QkOperationKind_Unknown
Cette variante est utilisée comme type opaque pour les opérations qui ne sont pas encore implémentées dans le modèle de données natif.
QkOperationKind_PauliProductRotation de recenseur
QkDagNeighbors
struct QkDagNeighbors
Une structure permettant de stocker les informations relatives aux successeurs et aux prédécesseurs récupérées respectivement à partir de qk_dag_successors et qk_dag_predecessors.
Cet objet est en lecture seule depuis C. Pour respecter les garanties de sécurité de qk_dag_neighbors_clear, vous ne devez pas écraser les données initialisées par qk_dag_successors ou qk_dag_predecessors, y compris les données pointées.
const uint32_t *voisins
Tableau de taille num_neighbors d'indices de nœuds.
taille_t nombre_de_voisins
La longueur du neighbors tableau.
Fonctions
qk_dag_new
QkDag *qk_dag_new(void)
Construisez un nouveau DAG vide.
Vous devez libérer le DAG renvoyé avec qk_dag_free lorsque vous avez terminé de l'utiliser.
Exemple
QkDag *empty = qk_dag_new();Retours
Un pointeur vers le DAG créé.
qk_dag_add_quantum_register
void qk_dag_add_quantum_register(QkDag *dag, const QkQuantumRegister *reg)
Ajouter un registre quantique au DAG.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1024, "my_register");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag et si reg n'est pas un pointeur valide et non nul vers un QkQuantumRegister.
Paramètres
- dag – Pointeur vers le DAG.
- reg – Pointeur vers le registre quantique.
qk_dag_add_classical_register
void qk_dag_add_classical_register(QkDag *dag, const QkClassicalRegister *reg)
Ajoutez un registre classique au DAG.
Exemple
QkDag *dag = qk_dag_new();
QkClassicalRegister *cr = qk_classical_register_new(24, "my_register");
qk_dag_add_classical_register(dag, cr);
qk_classical_register_free(cr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag et si reg n'est pas un pointeur valide et non nul vers un QkClassicalRegister.
Paramètres
- dag – Pointeur vers le DAG.
- reg – Pointeur vers le registre classique.
qk_dag_num_qubits
uint32_t qk_dag_num_qubits(const QkDag *dag)
Obtenir le nombre de qubits contenus dans le DAG.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(24, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t num_qubits = qk_dag_num_qubits(dag); // num_qubits==24
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
Retours
Le nombre de qubits sur lesquels le DAG est défini.
qk_dag_num_clbits
uint32_t qk_dag_num_clbits(const QkDag *dag)
Obtenir le nombre de clbits contenus dans le DAG.
Exemple
QkDag *dag = qk_dag_new();
QkClassicalRegister *cr = qk_classical_register_new(24, "my_register");
qk_dag_add_classical_register(dag, cr);
uint32_t num_clbits = qk_dag_num_clbits(dag); // num_clbits==24
qk_classical_register_free(cr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
Retours
Le nombre de clbits sur lesquels le DAG est défini.
qk_dag_num_op_nodes
size_t qk_dag_num_op_nodes(const QkDag *dag)
Renvoie le nombre total de nœuds d'opération dans le DAG.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
size_t num = qk_dag_num_op_nodes(dag); // 1
qk_dag_free(dag);
qk_quantum_register_free(qr);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
Retours
Nombre total d'instructions dans le DAG.
qk_dag_global_phase
QkParam *qk_dag_global_phase(const QkDag *dag)
Récupérer la phase globale du DAG.
Cette fonction renvoie une copie de la phase globale du DAG; cette valeur doit être libérée via :c:func:qk_param_free après utilisation.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(24, "my_register");
qk_dag_add_quantum_register(dag, qr);
QkParam *global_phase = qk_dag_global_phase(dag);
qk_param_free(global_phase);
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
Retours
La phase globale du DAG.
qk_dag_set_global_phase
QkExitCode qk_dag_set_global_phase(QkDag *dag, const QkParam *phase)
Définir la phase globale du DAG.
Cette fonction copie la nouvelle phase globale lors de sa définition; l'appelant conserve donc la propriété de cette QkParam phase, et la valeur de celle-ci doit être libérée via :c:func:qk_param_free après sa définition.
Exemple
QkDag *dag = qk_dag_new();
QkParam *new_global_phase = qk_param_from_double(1.23);
qk_dag_set_global_phase(dag, new_global_phase);
qk_param_free(new_global_phase);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag et si phase n'est pas un pointeur valide et non nul vers un QkParam.
Paramètres
- dag – Pointeur vers le DAG.
- phase – Un pointeur vers la phase globale à définir.
Retours
QkExitCode_Success une fois la phase globale correctement définie. En cas d'échec, QkExitCode_ParameterError cette section décrit les erreurs génériques pouvant survenir lors de la recherche des symboles de paramètres, telles que des valeurs de paramètres non valides. Dans le cas contraire, QkExitCode_DagError cela indique que la cause de la défaillance est spécifique au DAG.
qk_dag_node_type
QkDagNodeType qk_dag_node_type(const QkDag *dag, uint32_t node)
Obtenir le type du nœud spécifié.
Le résultat peut être utilisé dans une instruction switch pour envoyer le traitement approprié lors de l'itération sur des nœuds de type inconnu.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud dont on souhaite obtenir le type.
Retours
Type de noeud.
qk_dag_qubit_in_node
uint32_t qk_dag_qubit_in_node(const QkDag *dag, uint32_t qubit)
Récupère l'index du nœud d'entrée du fil correspondant au qubit donné.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- qubit – Le qubit dont vous souhaitez obtenir l'index du nœud d'entrée.
Retours
Le nœud d'entrée du fil qubit.
qk_dag_qubit_out_node
uint32_t qk_dag_qubit_out_node(const QkDag *dag, uint32_t qubit)
Récupérer l'index du nœud de sortie du fil correspondant au qubit donné.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- qubit – Le qubit dont vous souhaitez obtenir l'index du nœud de sortie.
Retours
Le nœud de sortie du fil qubit.
qk_dag_clbit_in_node
uint32_t qk_dag_clbit_in_node(const QkDag *dag, uint32_t clbit)
Récupère l'index du nœud d'entrée du fil correspondant au clbit donné.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- clbit – Le clbit permettant d'obtenir l'index du nœud d'entrée.
Retours
Le nœud d'entrée du fil clbit.
qk_dag_clbit_out_node
uint32_t qk_dag_clbit_out_node(const QkDag *dag, uint32_t clbit)
Récupère l'index du nœud de sortie du fil correspondant au clbit donné.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- clbit – Le clbit pour obtenir l'index du nœud de sortie.
Retours
Le nœud de sortie du fil clbit.
qk_dag_wire_node_value
uint32_t qk_dag_wire_node_value(const QkDag *dag, uint32_t node)
Récupérer la valeur d'un nœud terminal de connexion.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud terminal dont vous souhaitez obtenir la valeur du câble.
Retours
La valeur (par exemple, qubit, clbit ou var) dans le nœud terminal.
qk_dag_op_node_num_qubits
uint32_t qk_dag_op_node_num_qubits(const QkDag *dag, uint32_t node)
Obtient le nombre de qubits du nœud d'opération spécifié.
Panique si le nœud n'est pas une opération.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont on souhaite obtenir le nombre de qubits.
Retours
Le nombre de qubits de l'opération.
qk_dag_op_node_num_clbits
uint32_t qk_dag_op_node_num_clbits(const QkDag *dag, uint32_t node)
Obtient le nombre de bits de contrôle du nœud d'opération spécifié.
Panique si le nœud n'est pas une opération.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont on souhaite obtenir le nombre de clbits.
Retours
Le nombre de clbits de l'opération.
qk_dag_op_node_num_params
uint32_t qk_dag_op_node_num_params(const QkDag *dag, uint32_t node)
Obtient le nombre de paramètres du nœud d'opération spécifié.
Panique si le nœud n'est pas une opération.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont vous souhaitez obtenir le nombre de paramètres.
Retours
Le nombre de paramètres de l'opération.
qk_dag_op_node_qubits
const uint32_t *qk_dag_op_node_qubits(const QkDag *dag, uint32_t node)
Récupérer les qubits du nœud d'opération spécifié.
Panique si le nœud n'est pas une opération.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont on souhaite obtenir les qubits.
Retours
Un pointeur vers les qubits. Utilisez qk_dag_op_node_num_qubits pour déterminer le nombre d'éléments.
qk_dag_op_node_clbits
const uint32_t *qk_dag_op_node_clbits(const QkDag *dag, uint32_t node)
Récupère les bits clbits du nœud d'opération spécifié.
Panique si le nœud n'est pas une opération.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont vous souhaitez obtenir les clbits.
Retours
Un pointeur vers les bits clbits. Utilisez qk_dag_op_node_num_clbits pour déterminer le nombre d'éléments.
qk_dag_apply_gate
uint32_t qk_dag_apply_gate(QkDag *dag, QkGate gate, const uint32_t *qubits, const double *params, bool front)
Appliquez un QkGate au DAG.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
qk_dag_free(dag);
qk_quantum_register_free(qr);Sécurité
Les qubits``params types et doivent être des pointeurs vers un tableau de uint32_t et double respectivement, dont la longueur correspond aux attentes pour la porte standard. Si le tableau n'est pas suffisamment long, le comportement de cette fonction est indéfini, car elle lira en dehors des limites du tableau. Il peut s'agir d'un pointeur nul s'il n'y a pas de qubits ou de paramètres pour une porte donnée. Vous pouvez vérifier qk_gate_num_qubits et qk_gate_num_params pour déterminer combien de qubits et de paramètres sont nécessaires pour une porte donnée.
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG auquel appliquer la porte.
- gate – L' StandardGate à appliquer.
- qubits – Pointeur vers le tableau des indices
uint32_tde qubits auxquels ajouter la porte. Il peut s'agir d'un pointeur nul s'il n'y a pas de qubits pourgate(par exempleQkGate_GlobalPhase). - params – Pointeur vers le tableau de
doublevaleurs à utiliser pour les paramètres de la porte. Il peut s'agir d'un pointeur nul s'il n'y a pas de paramètres pourgate(par exempleQkGate_H). - avant – Si
true, la porte est appliquée comme première opération sur les qubits spécifiés, plutôt que comme dernière opération.
Retours
L'index du nœud d'opération nouvellement ajouté.
qk_dag_apply_measure
uint32_t qk_dag_apply_measure(QkDag *dag, uint32_t qubit, uint32_t clbit, bool front)
Appliquer une mesure à un DAG.
Exemple
Mesurez tous les qubits dans l'index clbit correspondant à la fin du circuit.
uint32_t num_qubits = qk_dag_num_qubits(dag);
for (uint32_t i = 0; i < num_qubits; i++) {
qk_dag_apply_measure(dag, i, i, false);
}Sécurité
Le comportement est indéfini si dag n'est pas un pointeur aligné et non nul vers un valide QkDag, ou si qubit ou clbit sont hors de plage.
Paramètres
- dag – Le circuit auquel s'appliquer.
- qubit – L'index qubit à mesurer.
- clbit – L'index clbit dans lequel stocker le résultat.
- avant – Indique s'il faut appliquer la mesure au début du circuit. En général
false.
Retours
L'index du nœud de l'instruction créée.
qk_dag_apply_reset
uint32_t qk_dag_apply_reset(QkDag *dag, uint32_t qubit, bool front)
Appliquez une réinitialisation au DAG.
Exemples
Appliquer les réinitialisations initiales à tous les qubits.
uint32_t num_qubits = qk_dag_num_qubits(dag);
for (uint32_t qubit = 0; qubit < num_qubits; qubit++) {
qk_dag_apply_reset(dag, qubit, true);
}Sécurité
Le comportement est indéfini si dag n'est pas un pointeur aligné et non nul vers un valide QkDag, ou si qubit est hors de la plage.
Paramètres
- dag – Le circuit auquel s'appliquer.
- qubit – L'index du qubit à réinitialiser.
- avant – Indique s'il faut appliquer la réinitialisation au début du circuit. En général
false.
Retours
L'index du nœud de l'instruction créée.
qk_dag_apply_barrier
uint32_t qk_dag_apply_barrier(QkDag *dag, const uint32_t *qubits, uint32_t num_qubits, bool front)
Appliquez une barrière sur le DAG.
Exemples
Appliquez une barrière finale sur tous les qubits :
qk_dag_apply_barrier(dag, NULL, qk_dag_num_qubits(dag), false);Appliquez une barrière au début d'un circuit sur les indices de qubits spécifiés :
uint32_t qubits[] = {0, 2, 4, 5};
uint32_t num_qubits = sizeof(qubits) / sizeof(qubits[0]);
qk_dag_apply_barrier(dag, qubits, num_qubits, true);Sécurité
Le comportement est indéfini si :
dagn'est pas un pointeur aligné et non nul vers un valideQkDag,qubitsn'est pas aligné ou n'est pas valide pournum_qubitsles lectures d'index initialisés, dans les limites et non dupliqués, sauf siqubitsest nul.
Paramètres
- dag – Le circuit auquel s'appliquer.
- qubits – Les indices de qubits auxquels appliquer la barrière. Cette valeur peut être nulle, auquel cas
num_qubitsn'est pas lu, et la barrière est appliquée à tous les qubits du DAG. - num_qubits – Nombre de qubits auxquels la barrière s'applique.
- avant – Si la barrière doit être appliquée au début du circuit. En général
false.
Retours
L'index du nœud de l'instruction créée.
qk_dag_apply_unitary
uint32_t qk_dag_apply_unitary(QkDag *dag, const QkComplex64 *matrix, const uint32_t *qubits, uint32_t num_qubits, bool front)
Appliquer une porte unitaire à un DAG.
Les valeurs dans matrix doivent former une matrice unitaire à priorité sur les lignes de taille correcte pour le nombre de qubits. Les données sont copiées à partir du pointeur et doivent uniquement être valides pour la lecture jusqu'à ce que cette fonction renvoie une valeur.
Voir : Conventions de circuit pour plus de détails sur les conventions d'étiquetage des bits et des matrices de Qiskit.
Sécurité
Le comportement est indéfini si l'une des conditions suivantes est remplie :
dagn'est pas un pointeur aligné et non nul vers un valideQkDag,matrixn'est pas un pointeur aligné vers des valeurs4**num_qubitsinitialisées,qubitsn'est pas un pointeur aligné vers des valeursnum_qubitsinitialisées.
Paramètres
- dag – Le circuit auquel s'appliquer.
- matrice – Une matrice unitaire initialisée de type row-major de taille totale
4**num_qubits. - qubits – Tableau d'indices
uint32_tdistincts des qubits. - num_qubits – Nombre de qubits auxquels la porte s'applique.
- avant – Indique s'il faut appliquer la porte au début du circuit. En général
false.
Retours
L'index du nœud de l'instruction créée.
qk_dag_op_node_gate_op
QkGate qk_dag_op_node_gate_op(const QkDag *dag, uint32_t node, double *out_params)
Récupérer la porte standard du nœud spécifié.
Panique si le nœud n'est pas une opération de porte standard.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {0};
uint32_t h_gate_idx = qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
QkGate gate = qk_dag_op_node_gate_op(dag, h_gate_idx, NULL);
qk_dag_free(dag);
qk_quantum_register_free(qr);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag. Si out_params n'est pas NULL, il doit pointer vers un tampon suffisamment grand pour contenir tous les paramètres de la porte, sinon le comportement est indéfini car cette fonction écrira au-delà de ses limites. Vous pouvez vérifier qk_dag_op_node_num_params pour déterminer combien de paramètres sont requis pour un nœud d'opération donné.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont vous souhaitez obtenir la porte standard.
- out_params – Un tampon à remplir avec les paramètres de la porte ou NULL s'ils ne sont pas souhaités.
Retours
La valeur du portail.
qk_dag_op_node_unitary
void qk_dag_op_node_unitary(const QkDag *dag, uint32_t node, QkComplex64 *out)
Copiez la matrice unitaire de l'indice de nœud correspondant.
Panique si le nœud n'est pas une porte unitaire.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur non nul vers un valide QkDag, si out n'est pas aligné ou si out n'est pas valide pour 4**num_qubits les écritures de QkComplex64.
Paramètres
- dag – Circuit à partir duquel lire.
- node – L'index du nœud de l'instruction de matrice unitaire.
- out – Mémoire allouée et alignée pour les valeurs
4**num_qubitscomplexes dans l'ordre des lignes, oùnum_qubitsest le nombre de qubits auxquels la porte s'applique.
qk_dag_op_node_kind
QkOperationKind qk_dag_op_node_kind(const QkDag *dag, uint32_t node)
Obtenir le « type » d'un nœud d'opération.
Le résultat peut être utilisé dans une instruction switch pour distribuer le traitement approprié lors de l'itération sur les nœuds d'opération.
Panique si node n'est pas un nœud d'opération.
Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud d'opération dont on veut obtenir le « type ».
Retours
Le « type » du nœud.
qk_dag_successors
QkDagNeighbors qk_dag_successors(const QkDag *dag, uint32_t node)
Récupérer les successeurs du nœud spécifié.
Le tableau des successeurs et sa longueur sont renvoyés sous forme de QkDagNeighbors struct, où chaque élément du tableau correspond à un index de nœud DAG. Vous devez appeler la qk_dag_neighbors_clear fonction une fois terminé afin de libérer la mémoire allouée à la structure.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
uint32_t node_cx = qk_dag_apply_gate(dag, QkGate_CX, (uint32_t[]){0, 1}, NULL, false);
QkDagNeighbors successors = qk_dag_successors(dag, node_cx);
qk_dag_neighbors_clear(&successors);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud dont on souhaite obtenir les successeurs.
Retours
Une instance de la QkDagNeighbors structure contenant les informations sur les successeurs.
qk_dag_predecessors
QkDagNeighbors qk_dag_predecessors(const QkDag *dag, uint32_t node)
Récupérer les prédécesseurs du nœud spécifié.
Le tableau des prédécesseurs et sa longueur sont renvoyés sous forme de QkDagNeighbors struct, où chaque élément du tableau correspond à un index de nœud DAG. Vous devez appeler la qk_dag_neighbors_clear fonction une fois terminé afin de libérer la mémoire allouée à la structure.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
uint32_t node_cx = qk_dag_apply_gate(dag, QkGate_CX, (uint32_t[]){0, 1}, NULL, false);
QkDagNeighbors predecessors = qk_dag_predecessors(dag, node_cx);
qk_dag_neighbors_clear(&predecessors);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – Le nœud dont on souhaite obtenir les prédécesseurs.
Retours
Une instance de la QkDagNeighbors structure contenant les informations sur les prédécesseurs.
qk_dag_neighbors_clear
void qk_dag_neighbors_clear(QkDagNeighbors *neighbors)
Effacez les champs de la structure QkDagNeighbors d'entrée.
La fonction désalloue la mémoire pointée par le neighbors champ et la définit sur NULL. Il définit également le num_neighbors champ sur 0.
Sécurité
Le comportement est indéfini si neighbors n'est pas un pointeur valide et non nul vers un QkDagNeighbors objet rempli avec ou qk_dag_successors qk_dag_predecessors.
Paramètres
- voisins – Pointeur vers un
QkDagNeighborsobjet.
qk_dag_get_instruction
void qk_dag_get_instruction(const QkDag *dag, uint32_t index, QkCircuitInstruction *instruction)
Renvoyer les détails d'une instruction dans le circuit.
Ceci est un miroir de qk_circuit_get_instruction. Vous pouvez également utiliser des méthodes individuelles telles que qk_dag_op_node_gate_op pour obtenir des propriétés individuelles.
Vous devez appeler qk_circuit_instruction_clear pour réinitialiser le QkCircuitInstruction avant de le réutiliser ou de le jeter.
Exemples
Parcourir un DAG pour trouver les qubits sur lesquels des mesures ont été effectuées :
bool *measured = calloc(qk_dag_num_qubits(dag), sizeof(*measured));
uint32_t num_ops = qk_dag_num_op_nodes(dag);
uint32_t *ops = malloc(num_ops * sizeof(*ops));
qk_dag_topological_op_nodes(dag, ops);
// Storage space for the instruction.
QkCircuitInstruction inst;
for (uint32_t i = 0; i < num_ops; i++) {
qk_dag_get_instruction(dag, ops[i], &inst);
if (!strcmp(inst.name, "measure"))
measured[inst.qubits[0]] = true;
qk_circuit_instruction_clear(&inst);
}
free(ops);
free(measured);Sécurité
Le comportement est indéfini si ou dag ne instruction sont pas des pointeurs valides, alignés et non nuls vers le type de données pertinent. Les champs instruction n'ont pas besoin d'être initialisés.
Paramètres
- dag – Circuit à partir duquel récupérer l'instruction.
- index – L'index du nœud. C'est une erreur de passer un index qui n'est pas un nœud op valide.
- instruction – Un point indiquant où écrire le
QkCircuitInstruction.
qk_dag_compose
QkExitCode qk_dag_compose(QkDag *dag, const QkDag *other, const uint32_t *qubits, const uint32_t *clbits)
Composez le other DAG sur dag l'instance avec l'option d'un sous-ensemble de fils d'entrée de other étant mappé sur un sous-ensemble de fils de sortie de dag.
other peut comprendre un nombre inférieur ou égal de fils pour chaque type.
Exemple
// Build the following dag
// rqr_0: ──■───────
// │ ┌───┐
// rqr_1: ──┼──┤ Y ├
// ┌─┴─┐└───┘
// rqr_2: ┤ X ├─────
// └───┘
QkDag *dag_right = qk_dag_new();
QkQuantumRegister *rqr = qk_quantum_register_new(3, "rqr");
qk_dag_add_quantum_register(dag_right, rqr);
qk_dag_add_classical_register(dag_right, rcr);
qk_dag_apply_gate(dag_right, QkGate_CX, (uint32_t[]){0, 2}, NULL, false);
qk_dag_apply_gate(dag_right, QkGate_Y, (uint32_t[]){1}, NULL, false);
// Build the following dag
// ┌───┐
// lqr_0: ──┤ H ├───
// ┌─┴───┴──┐
// lqr_1: ┤ P(0.1) ├
// └────────┘
QkDag *dag_left = qk_dag_new();
QkQuantumRegister *lqr = qk_quantum_register_new(2, "lqr");
qk_dag_add_quantum_register(dag_left, lqr);
qk_dag_add_classical_register(dag_left, lcr);
qk_dag_apply_gate(dag_left, QkGate_H, (uint32_t[]){0}, NULL, false);
qk_dag_apply_gate(dag_left, QkGate_Phase, (uint32_t[]){1}, (double[]){0.1}, false);
// Compose left circuit onto right circuit
// Should result in circuit
// ┌───┐
// rqr_0: ──■──┤ H ├──────────
// │ ├───┤┌────────┐
// rqr_1: ──┼──┤ Y ├┤ P(0.1) ├
// ┌─┴─┐└───┘└────────┘
// rqr_2: ┤ X ├───────────────
// └───┘
qk_dag_compose(dag_right, dag_left, NULL, NULL);
// Clean up after you're done
qk_dag_free(dag_left);
qk_dag_free(dag_right);
qk_quantum_register_free(lqr);
qk_quantum_register_free(rqr);Sécurité
Le comportement est indéfini si dag ou ne other sont pas des pointeurs valides et non nuls vers un QkDag. Si qubit ni clbit ne sont NULL, il doit contenir une quantité inférieure ou égale à celle que possède le circuit.
Paramètres
- dag – Pointeur vers le DAG à composer.
- autre – Un pointeur vers le DAG à composer avec
dag. - qubits – Une liste d'indices représentant les fils qubit à composer.
- clbits – Une liste d'indices représentant les fils clbit à composer.
Retours
QkExitCode_Success en cas de décomposition réussie, sinon un code d'erreur spécifique au DAG indiquant la cause de l'échec.
qk_dag_free
void qk_dag_free(QkDag *dag)
Libérez le DAG.
Exemple
QkDag *dag = qk_dag_new();
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est ni nul ni un pointeur valide vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG à libérer.
qk_dag_to_circuit
QkCircuit *qk_dag_to_circuit(const QkDag *dag)
Convertir un DAG donné en circuit.
Le nouveau circuit est copié à partir du DAG; la référence dag d'origine appartient toujours à l'appelant et doit toujours être libérée avec qk_dag_free. Vous devez libérer le circuit renvoyé avec qk_circuit_free lorsque vous avez terminé.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
QkCircuit *qc = qk_dag_to_circuit(dag);
qk_circuit_free(qc);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG à partir duquel créer le circuit.
Retours
Un pointeur vers le nouveau circuit.
qk_dag_topological_op_nodes
void qk_dag_topological_op_nodes(const QkDag *dag, uint32_t *out_order)
Renvoie les nœuds d'opération dans le DAG classés par ordre topologique.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
qk_dag_apply_gate(dag, QkGate_S, qubit, NULL, false);
// get the number of operation nodes
uint32_t num_ops = qk_dag_num_op_nodes(dag); // 2
uint32_t *out_order = malloc(sizeof(uint32_t) * num_ops);
// get operation nodes listed in topological order
qk_dag_topological_op_nodes(dag, out_order);
// do something with the ordered nodes
for (uint32_t i = 0; i < num_ops; i++) {
QkGate gate = qk_dag_op_node_gate_op(dag, out_order[i], NULL);
printf("The gate at location %u is %u.\n", i, gate);
}
// free the out_order array, register, and dag pointer when done
free(out_order);
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un QkDag ou si out_order n'est pas un pointeur valide et non nul vers une séquence de éléments qk_dag_num_op_nodes(dag) consécutifs de uint32_t.
Paramètres
- dag – Pointeur vers le DAG.
- out_order – Pointeur vers un tableau
qk_dag_num_op_nodes(dag)d'éléments de typeuint32_t, dans lequel cette fonction écrira la sortie.
qk_dag_substitute_node_with_dag
void qk_dag_substitute_node_with_dag(QkDag *dag, uint32_t node, const QkDag *replacement)
Remplacer un nœud dans un QkDag par un sous-circuit spécifié par un autre QkDag
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {0};
uint32_t node_to_replace = qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
qk_dag_apply_gate(dag, QkGate_S, qubit, NULL, false);
// Build replacement dag for H
QkDag *replacement = qk_dag_new();
QkQuantumRegister *replacement_qr = qk_quantum_register_new(1, "other");
qk_dag_add_quantum_register(replacement, replacement_qr);
double pi_param[1] = {3.14159};
qk_dag_apply_gate(replacement, QkGate_RZ, qubit, pi_param, false);
qk_dag_apply_gate(replacement, QkGate_SX, qubit, NULL, false);
qk_dag_apply_gate(replacement, QkGate_RZ, qubit, pi_param, false);
qk_dag_substitute_node_with_dag(dag, node_to_replace, replacement);
// Free the replacement dag, register, dag, and register
qk_quantum_register_free(replacement_qr);
qk_dag_free(replacement);
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si dag et ne replacement sont pas des pointeurs valides et non nuls vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG.
- node – L'index du nœud de l'opération à remplacer par l'autre
QkDag. Il doit s'agir de l'index d'un nœud d'opération dansdaget le nombre de qargs et de cargs doit correspondre au nombre de qubits et de clbits dansreplacement. - remplacement – L'autre
QkDagà remplacernodepar. Ce dag doit avoir le même nombre de qubits que l'opération pournode. L'ordre des bits du nœud sera traité dans l'ordre, doncqargs[0]pournodesera mappé àqubits[0]dansreplacement,qargs[1]àqubits[0], etc. Le même principe s'applique également aux bits classiques.
qk_dag_copy_empty_like
QkDag *qk_dag_copy_empty_like(const QkDag *dag, QkVarsMode vars_mode, QkBlocksMode blocks_mode)
Renvoie une copie de soi-même avec la même structure, mais vide.
Cette structure comprend :
- nom et autres métadonnées
- phase globale
- durée
- tous les qubits et clbits, y compris les registres.
Exemple
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
// As the DAG does not contain any control-flow instructions,
// vars_mode and blocks_mode do not have any effect.
QkDag *copied_dag = qk_dag_copy_empty_like(dag, QkVarsMode_Alike, QkBlocksMode_Drop);
uint32_t num_ops_in_copied_dag = qk_dag_num_op_nodes(copied_dag); // 0
// do something with copied_dag
qk_quantum_register_free(qr);
qk_dag_free(dag);
qk_dag_free(copied_dag);Sécurité
Le comportement est indéfini si dag n'est pas un pointeur valide vers un QkDag.
Paramètres
- dag – Pointeur vers le DAG à copier.
- vars_mode – Mode de gestion des variables classiques.
- blocks_mode – Mode de gestion des blocs.
Retours
Le pointeur vers le circuit DAG copié.
qk_dag_replace_block_with_unitary
uint32_t qk_dag_replace_block_with_unitary(QkDag *dag, uint32_t num_block_ids, const uint32_t *block_ids, const QkComplex64 *matrix, uint32_t num_qubits, const uint32_t *qubits, bool cycle_check)
Remplacer un bloc contigu non vide de nœuds dans un QkDag par une porte unitaire unique correspondant à la matrice unitaire spécifiée.
Lors du remplacement, les nœuds du bloc sont supprimés et remplacés par un nouveau nœud agissant sur les qubits concernés.
Exemple
// Create a DAG with H, T, S, T, H gates on the second qubit
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubit[1] = {1};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
uint32_t idx1 = qk_dag_apply_gate(dag, QkGate_T, qubit, NULL, false);
uint32_t idx2 = qk_dag_apply_gate(dag, QkGate_S, qubit, NULL, false);
uint32_t idx3 = qk_dag_apply_gate(dag, QkGate_T, qubit, NULL, false);
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
// Replace the inner T, S, T gates by a unitary gate (representing Z)
uint32_t replaced_ids[3] = {idx1, idx2, idx3};
static const QkComplex64 mat_z[4] = {{1, 0}, {0, 0}, {0, 0}, {-1, 0}};
uint32_t new_node_idx =
qk_dag_replace_block_with_unitary(dag, 3, replaced_ids, mat_z, 1, qubit, false);
// free the register and dag pointer when done
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si l'une des conditions suivantes est remplie :
dagn'est pas un pointeur aligné et non nul vers un valideQkDag,qubitsn'est pas un pointeur aligné vers des valeursnum_qubitsinitialisées.matrixn'est pas un pointeur aligné vers des valeurs4**num_qubitsinitialisées,block_idsn'est pas un pointeur aligné sur des valeursnum_block_idsinitialisées.
Paramètres
- dag – Pointeur vers le DAG.
- num_block_ids – Nombre d'entrées dans
block_ids. Ce nombre doit être différent de zéro. - block_ids – Pointeur vers un tableau non vide de nœuds à remplacer.
- matrice – Pointeur vers une matrice unitaire initialisée, de type « row-major », de taille
4**num_qubits. - num_qubits – Le nombre de qubits sur lesquels agit la porte unitaire obtenue.
- qubits – Pointeur vers un tableau d'indices de qubits
uint32_tdistincts. Chaque entrée spécifie l'indice du qubit DAG qui correspond à la position respective de l'argument dans la porte unitaire. - cycle_check – Si
true, la fonction vérifie si le remplacement du nœud fourniblock_idspar un seul nœud introduirait un cycle dans le DAG (ce qui rendrait le DAG invalide). Si un cycle est créé, le DAG reste inchangé etUINT32_MAXest renvoyé. Cette vérification entraîne une perte de performances. Si vous pouvez garantir que le bloc fourniblock_idsest contigu et qu'il ne créera pas de cycle lorsqu'il sera réduit à un seul nœud, cette valeur peut être définie surfalse.
Retours
L'index du nœud d'opération nouvellement ajouté, ou UINT32_MAX si cycle_check est true et que le remplacement entraînerait un cycle.
qk_dag_substitute_node_with_unitary
void qk_dag_substitute_node_with_unitary(QkDag *dag, uint32_t node, const QkComplex64 *matrix, uint32_t num_qubits)
Remplacer une opération dans un nœud d'un graphe QkDag par une porte unitaire correspondant à la matrice unitaire spécifiée.
La nouvelle opération doit correspondre à la forme de l'opération remplacée. Les qargs et les cargs du nœud resteront inchangés.
Exemple
// Create a DAG with a Z-gate
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
uint32_t idx_z = qk_dag_apply_gate(dag, QkGate_Z, (uint32_t[]){1}, NULL, false);
static const QkComplex64 mat[4] = {{1, 0}, {0, 0}, {0, 0}, {-1, 0}};
// Replace the Z-gate by a unitary matrix
qk_dag_substitute_node_with_unitary(dag, idx_z, mat, 1);
// free the register and dag pointer when done
qk_quantum_register_free(qr);
qk_dag_free(dag);Sécurité
Le comportement est indéfini si l'une des conditions suivantes est remplie :
dagn'est pas un pointeur aligné et non nul vers un valideQkDag,matrixn'est pas un pointeur aligné vers des valeurs4**num_qubitsinitialisées,
Paramètres
- dag – Pointeur vers le DAG.
- nœud – Le nœud dont l'opération est remplacée. Le nombre de qubits dans l'opération de substitution doit être égal à
num_qubitset le nombre de clbits doit être0. - matrice – Pointeur vers une matrice unitaire initialisée, de type « row-major », de taille
4**num_qubits. - num_qubits – Le nombre de qubits sur lesquels agit l'opérateur unitaire.
qk_dag_to_python
PyObject *qk_dag_to_python(QkDag *dag)
Transférez la propriété d'un QkDag objet à Python.
Il n'est pas sûr d'utiliser le QkDag pointeur après avoir appelé cette fonction. En particulier, vous ne devez pas essayer de le nettoyer ou de le dégager. L'appelant doit être le propriétaire de l'objet QkDag, et non pas détenir une référence empruntée (par exemple, un objet QkDag * récupéré à partir de qk_dag_borrow_from_python n'est pas considéré comme étant de sa propriété).
Sécurité
L'appelant doit être connecté à un interprète d' Python. Le comportement est indéfini si dag n'est pas un pointeur valide et non nul vers un objet initialisé et appartenant à l'utilisateur QkDag.
Paramètres
- dag – L'objet concerné.
Retours
Une référence de type « owned- Python » à l'objet.
qk_dag_borrow_from_python
QkDag *qk_dag_borrow_from_python(PyObject *ob)
Récupérer un QkDag pointeur à partir d'un objet Python.
Cette opération emprunte une référence à un objet de type Python et en extrait le QkDag pointeur, à condition que celui-ci soit du type approprié. Le pointeur renvoyé est emprunté au ob pointeur. Si le type PyObject n'est pas correct, la valeur de retour est NULL et l'état d'exception de l'interpréteur Python est activé.
Vous devez être connecté à un interpréteur Python pour pouvoir appeler cette fonction.
Vous pouvez également utiliser qk_dag_convert_from_python, qui est logiquement identique à cette fonction, mais qui peut être directement utilisé comme fonction de « conversion » pour la PyArg_Parse* famille de fonctions de conversion de l' Python.
Sécurité
L'appelant doit être connecté à un interprète d' Python. Le comportement est indéfini si ob n'est pas un pointeur valide et non nul vers un objet de type Python.
Paramètres
- ob – Un objet de type « Python » emprunté.
Retours
Un pointeur vers l'objet natif, ou NULL si l'objet de l' Python ation n'est pas du bon type.
qk_dag_convert_from_python
int qk_dag_convert_from_python(PyObject *object, void *address)
Récupérer un pointeur DAG à partir d'un objet Python.
Cette fonction emprunte une référence à Python et en extrait le QkDag pointeur vers address, si celui-ci est du type approprié. Le pointeur renvoyé est emprunté au object pointeur. Si PyObject n'est pas du type correct, la valeur de retour est 1, l'état d'exception de l'interpréteur Python est activé et address reste inchangé.
Vous devez être connecté à un interpréteur Python pour pouvoir appeler cette fonction.
Vous pouvez également utiliser qk_dag_borrow_from_python, qui est logiquement identique à ceci, mais qui présente une syntaxe plus naturelle pour une utilisation directe.
Sécurité
L'appelant doit être connecté à un interprète d' Python. Le comportement est indéfini si object n'est pas un pointeur valide et non nul vers un objet Python, ou si address n'est pas un pointeur vers des données modifiables du type approprié.
Paramètres
- objet – Un objet emprunté de type « Python ».
- adresse – Emplacement où enregistrer les données de sortie.
Retours
1 en cas de réussite, 0 en cas d'échec.