Skip to main content
IBM Quantum Platform

Diagonalisation quantique de Krylov

Dans cette leçon sur la diagonalisation quantique de Krylov (KQD), nous répondrons aux questions suivantes :

  • Qu'est-ce que la méthode de Krylov, en général?
  • Pourquoi la méthode de Krylov fonctionne-t-elle et dans quelles conditions?
  • Quel est le rôle de l'informatique quantique?

La partie quantique des calculs est basée en grande partie sur les travaux de Ref [1].

La vidéo ci-dessous donne un aperçu des méthodes de Krylov dans l'informatique classique, motive leur utilisation et explique comment l'informatique quantique peut jouer un rôle dans ce domaine. Le texte suivant offre plus de détails et met en œuvre une méthode de Krylov à la fois de manière classique et en utilisant un ordinateur quantique.


1. Introduction aux méthodes de Krylov

Une méthode de sous-espace de Krylov peut se référer à n'importe laquelle des méthodes construites autour de ce qu'on appelle le sous-espace de Krylov. Un examen complet de ces derniers dépasse le cadre de cette leçon, mais les références [2-4] peuvent toutes fournir des informations plus détaillées. Nous nous concentrerons ici sur ce qu'est un sous-espace de Krylov, comment et pourquoi il est utile pour résoudre les problèmes de valeurs propres, et enfin comment il peut être mis en œuvre sur un ordinateur quantique.

Définition : Étant donné une matrice symétrique semi-définie positive N×NN\times N AA, l'espace de Krylov Kr\mathcal{K}^r d'ordre rr est l'espace couvert par les vecteurs obtenus en multipliant les puissances supérieures d'une matrice AA, jusqu'à r−1≤Nr-1\leq N, avec un vecteur de référence ∣v⟩\vert v \rangle.

Kr=span{∣v⟩,A∣v⟩,A2∣v⟩,...,Ar−1∣v⟩}\mathcal{K}^r = \text{span}\left\{ \vert v \rangle, A \vert v \rangle, A^2 \vert v \rangle, ..., A^{r-1} \vert v \rangle \right\}

Bien que les vecteurs ci-dessus couvrent ce que nous appelons un sous-espace de Krylov, il n'y a aucune raison de penser qu'ils seront orthogonaux. On utilise souvent un processus d'orthonormalisation itératif similaire à l' orthogonalisation de Gram-Schmidt. Ici, le processus est légèrement différent puisque chaque nouveau vecteur est rendu orthogonal aux autres au fur et à mesure qu'il est généré. Dans ce contexte, on parle d' itération d'Arnoldi. A partir du vecteur initial ∣v⟩|v\rangle, on génère le vecteur suivant A∣v⟩A|v\rangle, puis on s'assure que ce second vecteur est orthogonal au premier en soustrayant sa projection sur ∣v⟩|v\rangle. C'est-à-dire

∣v0⟩=∣v⟩∣∣∣v⟩∣∣∣v1⟩=A∣v⟩−⟨v0∣A∣v⟩∣v0⟩∣∣A∣v⟩−⟨v0∣A∣v⟩∣v0⟩∣∣\begin{aligned} |v_0\rangle &=\frac{|v\rangle}{\left|\left| |v\rangle \right|\right|}\\ |v_1\rangle &=\frac{A|v\rangle-\langle v_0|A|v\rangle |v_0\rangle}{\left|\left|A|v\rangle-\langle v_0|A|v\rangle |v_0\rangle \right|\right|} \end{aligned}

On voit aisément que ∣v0⟩⊥∣v1⟩|v_0\rangle \perp |v_1\rangle, puisque

⟨v0∣v1⟩=⟨v0∣A∣v⟩−⟨v0∣A∣v⟩⟨v0∣v0⟩∣∣A∣v⟩−⟨A∣v⟩∣v0⟩∣v0⟩∣∣=0\langle v_0 | v_1\rangle=\frac{\langle v_0 | A|v\rangle-\langle v_0 |A|v\rangle\langle v_0|v_0\rangle}{\left|\left| A|v\rangle-\langle A|v\rangle|v_0\rangle |v_0\rangle \right|\right|}=0

Nous procédons de la même manière pour le vecteur suivant, en nous assurant qu'il est orthogonal aux deux vecteurs précédents :

∣v2⟩=A∣v1⟩−⟨v0∣A∣v1⟩∣v0⟩−⟨v1∣A∣v1⟩∣v1⟩∣∣A∣v1⟩−⟨v0∣A∣v1⟩∣v0⟩−⟨v1∣A∣v1⟩∣v1⟩∣∣|v_2\rangle=\frac{A |v_1\rangle-\langle v_0|A |v_1\rangle |v_0\rangle-\langle v_1|A |v_1\rangle |v_1\rangle}{\left|\left| A |v_1\rangle-\langle v_0|A |v_1\rangle |v_0\rangle-\langle v_1|A |v_1\rangle |v_1\rangle\right|\right|}

Si nous répétons ce processus pour tous les vecteurs rr, nous obtenons une base orthonormée complète pour un espace de Krylov. Notez que le processus d'orthogonalisation ici produira zéro une fois r>mr>m, puisque mm vecteur orthogonal couvre nécessairement tout l'espace. Le processus aboutira également à zéro si un vecteur est un vecteur propre de AA puisque tous les vecteurs suivants seront des multiples de ce vecteur.

1.1 Un exemple simple : Krylov à la main

Passons en revue la génération d'un sous-espace de Krylov sur une matrice trivialement petite, afin de voir le processus. Nous commençons par une matrice initiale AA qui nous intéresse :

A=(4−10−14−10−14)A=\begin{pmatrix}4&-1&0\\-1&4&-1\\0&-1&4\end{pmatrix}

Pour ce petit exemple, nous pouvons déterminer les vecteurs propres et les valeurs propres facilement, même à la main. Nous présentons ici la solution numérique.

# One might use linalg.eigh here, but later matrices may not be Hermitian. So we use
# linalg.eig in this lesson.

import numpy as np

A = np.array([[4, -1, 0], [-1, 4, -1], [0, -1, 4]])
eigenvalues, eigenvectors = np.linalg.eig(A)
print("The eigenvalues are ", eigenvalues)
print("The eigenvectors are ", eigenvectors)

Output:

The eigenvalues are  [2.58578644 4.         5.41421356]
The eigenvectors are  [[ 5.00000000e-01 -7.07106781e-01  5.00000000e-01]
 [ 7.07106781e-01  1.37464400e-16 -7.07106781e-01]
 [ 5.00000000e-01  7.07106781e-01  5.00000000e-01]]

Nous les enregistrons ici pour une comparaison ultérieure :

a0=2.59,∣0⟩=(1/2−2/21/2)a1=4,∣1⟩=(2/20−2/2)a2=5.41,∣2⟩=(1/22/21/2)\begin{aligned} a_0&=2.59,&|0\rangle&=&\begin{pmatrix}1/2\\-\sqrt{2}/2\\1/2\end{pmatrix}\\ \\ a_1&=4,&|1\rangle&=&\begin{pmatrix}\sqrt{2}/2\\0\\-\sqrt{2}/2\end{pmatrix}\\ \\ a_2&=5.41,&|2\rangle&=&\begin{pmatrix}1/2\\\sqrt{2}/2\\1/2\end{pmatrix} \end{aligned}

Nous aimerions étudier comment ce processus fonctionne (ou échoue) lorsque nous augmentons la dimension de notre sous-espace de Krylov, rr. À cette fin, nous allons appliquer ce processus :

  • Générer un sous-espace de l'espace vectoriel complet à partir d'un vecteur choisi aléatoirement ∣v⟩|v\rangle (l'appeler ∣v0⟩|v_0\rangle s'il est déjà normalisé, comme ci-dessus).
  • Projetez la matrice complète AA sur ce sous-espace et trouvez les valeurs propres de cette matrice projetée A~\tilde{A}.
  • Augmenter la taille du sous-espace en générant davantage de vecteurs, en veillant à ce qu'ils soient orthonormés, à l'aide d'un processus similaire à l'orthogonalisation de Gram-Schmidt.
  • Projetez AA sur le sous-espace le plus grand et trouvez les valeurs propres de la matrice résultante, A~\tilde{A}.
  • Répétez cette opération jusqu'à ce que les valeurs propres convergent (ou, dans le cas présent, jusqu'à ce que vous ayez généré des vecteurs couvrant tout l'espace vectoriel de la matrice originale AA ).

Une mise en œuvre normale de la méthode de Krylov n'aurait pas besoin de résoudre le problème des valeurs propres de la matrice projetée sur chaque sous-espace de Krylov au fur et à mesure de sa construction. Vous pouvez construire le sous-espace de la dimension souhaitée, projeter la matrice sur ce sous-espace et diagonaliser la matrice projetée. La projection et la diagonalisation à chaque dimension du sous-espace ne sont effectuées que pour vérifier la convergence.

r=1r=1 des dimensions :

Nous choisissons un vecteur aléatoire, disons

∣v0⟩=(100)|v_0\rangle=\begin{pmatrix}1\\0\\0\end{pmatrix}

S'il n'est pas déjà normalisé, normalisez-le.

Nous projetons maintenant notre matrice AA sur le sous-espace de ce seul vecteur :

A~0=⟨v0∣A∣v0⟩=(100)(4−10−14−10−14)(100)=(4)\tilde{A}_0=\langle v_0| A|v_0\rangle=\begin{pmatrix}1&0&0\end{pmatrix}\begin{pmatrix}4&-1&0\\-1&4&-1\\0&-1&4\end{pmatrix}\begin{pmatrix}1\\0\\0\end{pmatrix}=(4)

Il s'agit de la projection de la matrice sur notre sous-espace de Krylov lorsqu'il ne contient qu'un seul vecteur, ∣v0⟩|v_0\rangle. La valeur propre de cette matrice est trivialement 4. Nous pouvons considérer cela comme notre estimation d'ordre zéro des valeurs propres (dans ce cas, une seule) de AA. Bien qu'il s'agisse d'une estimation médiocre, c'est l'ordre de grandeur correct.

r=2r=2 des dimensions :

Nous générons maintenant le vecteur suivant dans notre sous-espace en opérant avec AA sur le vecteur précédent :

A∣v0⟩=(4−10−14−10−14)(100)=(4−10)A|v_0\rangle=\begin{pmatrix}4&-1&0\\-1&4&-1\\0&-1&4\end{pmatrix}\begin{pmatrix}1\\0\\0\end{pmatrix}=\begin{pmatrix}4\\-1\\0\end{pmatrix}

Nous soustrayons maintenant la projection de ce vecteur sur notre vecteur précédent afin de garantir l'orthogonalité.

∣v1⟩=A∣v0⟩−⟨v0∣A∣v0⟩∣v0⟩|v_1\rangle=A|v_0\rangle-\langle v_0 |A|v_0\rangle|v_0\rangle ∣v1⟩=(4−10)−(100)(4−10)(100)=(0−10)|v_1\rangle=\begin{pmatrix}4\\-1\\0\end{pmatrix}-\begin{pmatrix}1& 0& 0\end{pmatrix}\begin{pmatrix}4\\-1\\0\end{pmatrix}\begin{pmatrix}1\\0\\0\end{pmatrix}=\begin{pmatrix}0\\-1\\0\end{pmatrix}

S'il n'est pas déjà normalisé, normalisez-le. Dans ce cas, le vecteur était déjà normalisé, donc

∣v1⟩=(0−10)|v_1\rangle=\begin{pmatrix}0\\-1\\0\end{pmatrix}

Nous projetons maintenant notre matrice A sur le sous-espace de ces deux vecteurs :

A~1=(1000−10)(4−10−14−10−14)(100−100)=(1000−10)(41−1−401)=(4114)\tilde{A}_1= \begin{pmatrix} 1&0&0\\0&-1&0 \end{pmatrix} \begin{pmatrix}4&-1&0\\-1&4&-1\\0&-1&4\end{pmatrix}\begin{pmatrix}1&0\\0&-1\\0&0\end{pmatrix}=\begin{pmatrix}1&0&0\\0&-1&0\end{pmatrix}\begin{pmatrix}4&1\\-1&-4\\0&1\end{pmatrix}=\begin{pmatrix}4&1\\1&4\end{pmatrix}

Il nous reste à déterminer les valeurs propres de cette matrice. Mais cette matrice est légèrement plus petite que la matrice complète. Dans les problèmes impliquant de très grandes matrices, il peut être très avantageux de travailler avec ce sous-espace plus petit.

det⁡(A1~−λI)=0\det(\tilde{A_1}-\lambda I)=0 ∣4−λ114−λ∣=(4−λ)2−1=0\begin{vmatrix} 4-\lambda&1\\1&4-\lambda\end{vmatrix} =(4-\lambda)^2-1=0 4−λ=±1→λ=3,54-\lambda=±1→\lambda=3,5

Bien qu'il ne s'agisse pas encore d'une bonne estimation, elle est meilleure que l'estimation de second ordre. Nous procéderons à une nouvelle itération pour nous assurer que le processus est clair. Cependant, cela réduit l'intérêt de la méthode, puisque nous finirons par diagonaliser une matrice 3x3 lors de l'itération suivante, ce qui signifie que nous n'avons pas gagné de temps ni de puissance de calcul.

r=3r=3 des dimensions :

Nous générons maintenant le vecteur suivant dans notre sous-espace en opérant avec A sur le vecteur précédent :

A∣v1⟩=(4−10−14−10−14)(0−10)=(1−41)A|v_1\rangle=\begin{pmatrix}4&-1&0\\-1&4&-1\\0&-1&4\end{pmatrix}\begin{pmatrix}0\\-1\\0\end{pmatrix}=\begin{pmatrix}1\\-4\\1\end{pmatrix}

Nous soustrayons maintenant la projection de ce vecteur sur nos deux vecteurs précédents afin de garantir l'orthogonalité.

∣v2⟩=A∣v1⟩−⟨v0∣A∣v1⟩∣v0⟩−⟨v1∣A∣v1⟩∣v1⟩∣v2⟩=(1−41)−(100)(1−41)(100)−(0−10)(1−41)(0−10)=(001)\begin{aligned} |v_2\rangle&=A|v_1\rangle-\langle v_0 |A|v_1\rangle|v_0\rangle-\langle v_1 |A|v_1\rangle|v_1\rangle\\ |v_2\rangle&=\begin{pmatrix}1\\-4\\1\end{pmatrix}-\begin{pmatrix}1& 0& 0 \end{pmatrix}\begin{pmatrix}1\\-4\\1\end{pmatrix}\begin{pmatrix}1\\0\\0\end{pmatrix}-\begin{pmatrix}0&-1& 0\end{pmatrix}\begin{pmatrix}1\\-4\\1\end{pmatrix}\begin{pmatrix}0\\-1\\0\end{pmatrix}=\begin{pmatrix}0\\0\\1\end{pmatrix} \end{aligned}

S'il n'est pas déjà normalisé, normalisez-le. Dans ce cas, le vecteur était déjà normalisé, donc

∣v2⟩=(001)|v_2 \rangle=\begin{pmatrix}0\\0\\1\end{pmatrix}

Nous projetons maintenant notre matrice AA sur le sous-espace de ces vecteurs :

A~2=(1000−10001)(4−10−14−10−14)(1000−10001)=(4−101−410−14)(1000−10001)=(410141014)\tilde{A}_2=\begin{pmatrix}1&0&0\\0&-1&0\\0&0&1\end{pmatrix}\begin{pmatrix}4&-1&0\\-1&4&-1\\0&-1&4\end{pmatrix}\begin{pmatrix}1&0&0\\0&-1&0\\0&0&1\end{pmatrix}=\begin{pmatrix}4&-1&0\\1&-4&1\\0&-1&4\end{pmatrix}\begin{pmatrix}1&0&0\\0&-1&0\\0&0&1\end{pmatrix}=\begin{pmatrix}4&1&0\\1&4&1\\0&1&4\end{pmatrix}

Nous déterminons maintenant les valeurs propres :

det⁡(A~2−λI)=0\det(\tilde{A}_2-\lambda I)=0 ∣4−λ1014−λ1014−λ∣=(4−λ)((4−λ)2−1)−(4−λ)=0\begin{vmatrix}4-\lambda&1&0\\1&4-\lambda&1\\0&1&4-\lambda\end{vmatrix} = (4-\lambda)((4-\lambda)^2-1)-(4-\lambda)=0\\ 4−λ=0,4−λ=±21/2→λ=4−21/2,4,4+21/2≈2.59,4,5.414-\lambda=0,4-\lambda=±2^{1/2}→\lambda=4-2^{1/2},4,4+2^{1/2}≈2.59,4,5.41

Ces valeurs propres sont exactement les valeurs propres de la matrice originale AA. Cela doit être le cas, puisque nous avons étendu notre sous-espace de Krylov à l'ensemble de l'espace vectoriel de la matrice originale AA.

Dans cet exemple, la méthode de Krylov ne semble pas particulièrement plus facile que la diagonalisation directe. En effet, comme nous le verrons dans les sections suivantes, la méthode de Krylov n'est avantageuse qu'à partir d'une certaine dimension de la matrice; ceci a pour but de nous aider à résoudre les problèmes de valeurs propres/vecteurs propres de matrices extrêmement grandes.

Image montrant une très grande matrice projetée sur un sous-espace de Krylov, c'est-à-dire des lignes de vecteurs de Krylov formant une matrice à gauche, un hamiltonien, puis des colonnes de vecteurs de Krylov à droite.

C'est le seul exemple que nous montrerons "à la main", mais la section 2 ci-dessous présente des exemples de calcul.

Clarification des termes

Une idée fausse très répandue est qu'il n'existe qu'un seul sous-espace de Krylov pour un problème donné. Mais bien sûr, comme il existe de nombreux vecteurs initiaux auxquels notre matrice peut être appliquée, il existe de nombreux sous-espaces de Krylov possibles. Nous n'utiliserons l'expression "le sous-espace de Krylov" que pour faire référence à un sous-espace de Krylov spécifique déjà défini pour un exemple particulier. Pour les approches générales de résolution de problèmes, nous nous référerons à "a Krylov subspace " (sous-espace de Krylov). Une dernière précision : il est possible de se référer à un " espace de Krylov". Il est souvent appelé " sous-espace de Krylov" en raison de son utilisation dans le contexte de la projection de matrices d'un espace initial dans un sous-espace. Dans ce contexte, nous l'appellerons le plus souvent sous-espace.

Vérifiez votre compréhension

Expliquez pourquoi il n'est pas (a) utile et (b) possible d'étendre la dimension du sous-espace de Krylov rr au-delà de la dimension NN de la matrice concernée.

  • (a) Étant donné que nous orthonormalisons les vecteurs au fur et à mesure que nous les générons, un ensemble d’ NN s de ces vecteurs formera une base complète, ce qui signifie qu’une combinaison linéaire de ceux-ci permet de créer n’importe quel vecteur de l’espace.

    (b) Le processus d'orthogonalisation consiste à soustraire la projection d'un nouveau vecteur sur tous les vecteurs précédents. Si tous les vecteurs précédents génèrent l'espace vectoriel entier, alors la soustraction des projections sur le sous-espace entier nous donnera toujours un vecteur nul.

Imaginons qu'un collègue chercheur fasse une démonstration de la méthode de Krylov appliquée à une petite matrice fictive. Y a-t-il un problème avec leur choix de matrice AA et de vecteur initial ∣ψ⟩|\psi\rangle?

A=(213123335)A=\begin{pmatrix}2&1&3\\1&2&3\\3&3&5\end{pmatrix}

et

∣ψ⟩=12(1−10).|\psi\rangle=\frac{1}{\sqrt{2}}\begin{pmatrix}1\\-1\\0\end{pmatrix}.
  • Votre collègue a accidentellement choisi un vecteur propre pour son vecteur initial. Agir avec la matrice sur le vecteur initial renverra simplement le même vecteur, mis à l'échelle par la valeur propre. Cela ne génère pas de sous-espace de dimension croissante. Conseillez à votre collègue de choisir un vecteur initial différent, en vous assurant qu'il ne s'agit pas d'un vecteur propre.

Appliquez la méthode de Krylov à la matrice donnée, en choisissant un nouveau vecteur initial approprié. Notez les estimations de la valeur propre minimale aux ordres 0 et 1 de votre sous-espace de Krylov.

A=(110111011)A=\begin{pmatrix}1&1&0\\1&1&1\\0&1&1\end{pmatrix}
  • De nombreuses réponses sont possibles en fonction du choix du vecteur initial. Nous choisirons :

    ∣v0⟩=13(111).|v_0\rangle=\frac{1}{\sqrt{3}}\begin{pmatrix}1\\1\\1\end{pmatrix}.

    Pour obtenir ∣v1⟩|v_1\rangle, on applique une fois AA à ∣v0⟩|v_0\rangle, puis on rend ∣v1⟩|v_1\rangle orthogonal à ∣v0⟩|v_0\rangle.

    A∣v0⟩=(110111011)13(111)=13(232)A|v_0\rangle=\begin{pmatrix}1&1&0\\1&1&1\\0&1&1\end{pmatrix}\frac{1}{\sqrt{3}}\begin{pmatrix}1\\1\\1\end{pmatrix} = \frac{1}{\sqrt{3}}\begin{pmatrix}2\\3\\2\end{pmatrix}A∣v0⟩−⟨v0∣A∣v0⟩∣v0⟩=13(232)−13(111)13(232)13(111)=13(232)−7313(111)=32(−1/32/3−1/3)A|v_0\rangle - \langle v_0|A|v_0\rangle |v_0\rangle=\frac{1}{\sqrt{3}}\begin{pmatrix}2\\3\\2\end{pmatrix} - \frac{1}{\sqrt{3}}\begin{pmatrix}1&1&1\end{pmatrix}\frac{1}{\sqrt{3}}\begin{pmatrix}2\\3\\2\end{pmatrix}\frac{1}{\sqrt{3}}\begin{pmatrix}1\\1\\1\end{pmatrix} = \frac{1}{\sqrt{3}}\begin{pmatrix}2\\3\\2\end{pmatrix}-\frac{7}{3}\frac{1}{\sqrt{3}}\begin{pmatrix}1\\1\\1\end{pmatrix}=\sqrt{\frac{3}{2}}\begin{pmatrix}-1/3\\2/3\\-1/3\end{pmatrix}

    Au 0ème ordre, la projection sur notre sous-espace de Krylov est la suivante

    ⟨v0∣A∣v0⟩=13(111)(110111011)13(111)=73\langle v_0|A|v_0\rangle=\frac{1}{\sqrt{3}}\begin{pmatrix}1&1&1\end{pmatrix} \begin{pmatrix}1&1&0\\1&1&1\\0&1&1\end{pmatrix} \frac{1}{\sqrt{3}}\begin{pmatrix}1\\1\\1\end{pmatrix} = \frac{7}{3}

    Au premier ordre, la projection sur ce sous-espace de Krylov est la suivante

    ⟨V1∣A∣V1⟩=(131313−1623−16)(110111011)(13−16132313−16)\langle V^1|A|V^1\rangle=\begin{pmatrix}\frac{1}{\sqrt{3}}&\frac{1}{\sqrt{3}}&\frac{1}{\sqrt{3}}\\-\sqrt{\frac{1}{6}}&\sqrt{\frac{2}{3}}&-\sqrt{\frac{1}{6}}\end{pmatrix} \begin{pmatrix}1&1&0\\1&1&1\\0&1&1\end{pmatrix} \begin{pmatrix}\frac{1}{\sqrt{3}}&-\sqrt{\frac{1}{6}}\\\frac{1}{\sqrt{3}}& \sqrt{\frac{2}{3}} \\ \frac{1}{\sqrt{3}}&-\sqrt{\frac{1}{6}}\end{pmatrix}

    Cette opération peut être effectuée à la main, mais elle est plus facile à réaliser avec numpy :

    import numpy as np
    vstar = np.array([[1/np.sqrt(3),1/np.sqrt(3),1/np.sqrt(3)],[-1/np.sqrt(6),np.sqrt(2/3),-1/np.sqrt(6)]]
    )
    A = np.array([[1, 1, 0],
                  [1, 1, 1],
                  [0, 1, 1]])
    v = np.array([[1/np.sqrt(3),-1/np.sqrt(6)],[1/np.sqrt(3),np.sqrt(2/3)],[1/np.sqrt(3),-1/np.sqrt(6)]])
    proj = vstar@A@v
    print(proj)
    eigenvalues, eigenvectors = np.linalg.eig(proj)
    print("The eigenvalues are ", eigenvalues)
    print("The eigenvectors are ", eigenvectors)

    outputs:

    [[ 2.33333333  0.47140452]
     [ 0.47140452 -0.33333333]]
    The eigenvalues are  [ 2.41421356 -0.41421356]
    The eigenvectors are  [[ 0.98559856 -0.16910198]
     [ 0.16910198  0.98559856]]

    L'estimation de la valeur propre minimale est -0.414.

1.2 Types de méthodes de Krylov

les "méthodes du sous-espace de Krylov" peuvent faire référence à plusieurs techniques itératives utilisées pour résoudre les grands systèmes linéaires et les problèmes de valeurs propres. Toutes ces méthodes ont en commun de construire une solution approximative à partir d'un sous-espace de Krylov

Kr(A,∣v⟩)=span{∣v⟩,A∣v⟩,A2∣v⟩,...,Ar−1∣v⟩},\mathcal{K}^r(A,|v\rangle ) = \text{span}\{|v\rangle, A|v\rangle, A^2|v\rangle, ..., A^{r-1}|v\rangle\},

où ∣v⟩|v\rangle est l'estimation initiale (voir Ref [5]). Elles diffèrent par la manière dont elles choisissent la meilleure approximation à partir de ce sous-espace, en équilibrant des facteurs tels que le taux de convergence, l'utilisation de la mémoire et le coût de calcul global. L'objectif de cette leçon est d'exploiter l'informatique quantique dans le contexte des méthodes du sous-espace de Krylov; une discussion exhaustive de ces méthodes dépasse le cadre de cette leçon. Les brèves définitions ci-dessous ne sont données qu'à titre indicatif et comprennent quelques références permettant d'approfondir ces méthodes.

La méthode du gradient conjugué (CG) : Cette méthode est utilisée pour résoudre les systèmes linéaires symétriques et définis positifs [6]. Il minimise la norme A de l'erreur à chaque itération, ce qui le rend particulièrement efficace pour les systèmes issus d'EDP elliptiques discrétisées [7]. Nous utiliserons cette approche dans la section suivante pour expliquer pourquoi un sous-espace de Krylov serait un sous-espace efficace pour rechercher des solutions améliorées aux systèmes linéaires.

La méthode du résidu minimal généralisé (GMRES) : Cette méthode est conçue pour résoudre des systèmes linéaires généraux non symétriques. Il minimise la norme résiduelle sur un espace de Krylov à chaque itération, ce qui le rend robuste mais potentiellement gourmand en mémoire pour les grands systèmes [7].

La méthode du résidu minimal (MINRES) : Cette méthode est utilisée pour résoudre les systèmes linéaires indéfinis symétriques. Il est similaire au GMRES mais tire parti de la symétrie de la matrice pour réduire les coûts de calcul [8].

Parmi les autres approches intéressantes, on peut citer la méthode d'orthogonalisation complète (FOM), qui est étroitement liée à la méthode d'Arnoldi pour les problèmes de valeurs propres, la méthode du gradient bi-conjugué ( BiCG ) et la méthode de réduction de la dimension induite (IDR).

1.3 Pourquoi la méthode du sous-espace de Krylov fonctionne-t-elle?

Nous expliquerons ici que la méthode du sous-espace de Krylov devrait être un moyen efficace d'approximer les valeurs propres des matrices par un raffinement itératif des approximations des vecteurs propres, à travers la lentille de la descente la plus abrupte. Nous démontrerons qu'étant donné une supposition initiale d'un état fondamental, l'espace des corrections successives de cette supposition initiale qui produit la convergence la plus rapide est un sous-espace de Krylov. Nous n'apportons pas de preuve rigoureuse du comportement de convergence.

Supposons que notre matrice d'intérêt AA soit symétrique et définie positive. C'est ce qui rend notre argument le plus pertinent pour la méthode CG ci-dessus. Nous ne faisons ici aucune hypothèse sur l'éparpillement; nous ne prétendons pas non plus que AA doit être un hermitien (ce qu'il doit être s'il s'agit d'un hamiltonien).

Nous souhaitons généralement résoudre un problème de la forme suivante

A∣x⟩=∣b⟩.A|x\rangle=|b\rangle.

On peut imaginer que ∣b⟩=c∣x⟩|b\rangle=c|x\rangle où cc est une constante, comme dans un problème de valeurs propres. Mais l'énoncé de notre problème reste plus général pour l'instant.

Nous partons d'un vecteur ∣x0⟩|x_0\rangle qui constitue une solution approximative. Bien qu'il existe des similitudes entre cette hypothèse ∣x0⟩|x_0\rangle et ∣v0⟩|v_0\rangle dans la section 1.1, nous ne nous en servons pas ici. Nous pensons que l' ∣x0⟩|x_0\rangle contient une erreur, que nous appelons « ∣e0⟩|e_0\rangle » :

∣e0⟩:=∣x⟩−∣x0⟩.|e_0\rangle:=|x\rangle−|x_0\rangle.

Nous définissons également l' R0R_0 résiduelle :

∣R0⟩=∣b⟩−A∣x0⟩.|R_0\rangle=|b\rangle−A|x_0\rangle.

Nous utilisons ici la majuscule RR pour distinguer le résidu de la dimension de notre sous-espace de Krylov rr.

Un véritable vecteur propre noté x, une estimation notée x₀ et une représentation graphique de l'erreur entre ces deux valeurs.

Nous voulons maintenant procéder à une correction de la forme suivante

∣x1⟩=∣x0⟩+∣p0⟩,|x_1\rangle=|x_0\rangle+|p_0\rangle,

ce qui, nous l'espérons, améliorera notre approximation. Ici, ∣p0⟩|p_0\rangle est un vecteur qui reste à déterminer. Soit ∣e1⟩|e_1\rangle l'erreur après la correction. Ensuite

∣e1⟩=∣x⟩−∣x1⟩=∣x⟩−(∣x0⟩+∣p0⟩)=∣e0⟩−∣p0⟩.|e_1\rangle=|x\rangle−|x_1\rangle=|x\rangle−(|x_0\rangle+|p_0\rangle)=|e_0\rangle−|p_0\rangle. Un vecteur propre valide et une mise à jour de la valeur initiale. L'estimation mise à jour est plus proche du vecteur propre réel.

Nous nous intéressons à la manière dont notre erreur se comporte lorsqu'elle est transformée par notre matrice. Calculons donc la norme AA de l'erreur. C'est-à-dire

∥∣e0⟩−∣p0⟩∥A2=(⟨e0∣A−⟨p0∣A)(∣e0⟩−∣p0⟩)=⟨e0∣A∣e0⟩−⟨e0∣A∣p0⟩−⟨p0∣A∣e0⟩+⟨p0∣A∣p0⟩=⟨e0∣A∣e0⟩−2⟨e0∣A∣p0⟩+⟨p0∣A∣p0⟩=d−2⟨R0∣p0⟩+⟨p0∣A∣p0⟩,\begin{aligned} ∥|e_0\rangle−|p_0\rangle∥_A^2&=\left(\langle e_0|A−\langle p_0|A\right)\left(|e_0\rangle−|p_0\rangle\right)\\ & = \langle e_0|A|e_0 \rangle − \langle e_0|A|p_0\rangle − \langle p_0|A|e_0\rangle+\langle p_0|A|p_0\rangle\\ & = \langle e_0|A|e_0\rangle−2\langle e_0|A|p_0\rangle+\langle p_0|A|p_0\rangle\\ & = d−2\langle R_0|p_0\rangle +\langle p_0|A|p_0\rangle, \end{aligned}

où nous avons utilisé la symétrie de AA ainsi que le fait que A∣e0⟩=∣R0⟩A |e_0\rangle = |R_0\rangle. Ici, dd est une constante indépendante de ∣p0⟩|p_0\rangle. Comme mentionné dans la section 1.2, la norme AA de l'erreur n'est pas la seule grandeur que l'on pourrait choisir de minimiser, mais c'est un bon choix. Nous souhaitons observer comment cette grandeur varie en fonction du choix des vecteurs de correction ∣p0⟩|p_0\rangle. Nous définissons donc la fonction ff en posant

f(∣p0⟩)=⟨p0∣A∣p0⟩−2⟨R0∣p0⟩+d.f(|p_0\rangle)=\langle p_0|A|p_0\rangle−2\langle R_0|p_0\rangle+d.

ff est simplement l'erreur ∣e1⟩|e_1\rangle en fonction de la correction ∣p0⟩|p_0\rangle mesurée dans la norme AA. Nous voulons donc choisir ∣p0⟩|p_0\rangle de telle sorte que f(∣p0⟩)f(|p_0\rangle) soit aussi petit que possible. Pour ce faire, nous calculons le gradient de ff. En utilisant la symétrie de AA, nous avons

∇f(∣p0⟩)=2(A∣p0⟩−∣R0⟩).\nabla f(|p_0\rangle) = 2(A|p_0\rangle−|R_0\rangle).

Le gradient indique la direction de la pente la plus raide, ce qui signifie que sa direction opposée correspond à la direction dans laquelle la fonction diminue le plus : la direction de la pente la plus raide en sens inverse. À partir de notre hypothèse initiale ∣x0⟩|x_0\rangle, où ∣p0⟩=0|p_0\rangle=0, on a que ∇f(0)=−2∣R0⟩\nabla f(0) = -2|R_0\rangle. Ainsi, la fonction ff diminue le plus fortement dans la direction du résidu ∣R0⟩|R_0\rangle. Notre choix initial serait donc le plus favorisé par l'ajout du vecteur ∣p0⟩=α0∣R0⟩|p_0\rangle=\alpha_0 |R_0\rangle pour un certain scalaire α0\alpha_0.

Dans l'étape suivante, nous choisissons à nouveau un vecteur ∣p1⟩|p_1\rangle et ajoutons sa valeur à l'approximation actuelle. En utilisant le même argument que précédemment, nous choisissons ∣p1⟩=α1∣R1⟩|p_1\rangle = \alpha_1 |R_1\rangle pour un certain scalaire α1\alpha_1. Nous continuons ainsi, de sorte que l'itération kthk^\text{th} de notre vecteur est

∣xk+1⟩=∣x0⟩+α0∣R0⟩+α1∣R1⟩+⋯+αk∣Rk⟩.|x_{k+1}\rangle=|x_0\rangle+\alpha_0 |R_0\rangle+\alpha_1 |R_1\rangle+⋯+\alpha_k |R_k\rangle.

De manière équivalente, nous voulons construire l'espace dans lequel nous choisissons nos estimations améliorées en ajoutant ∣R0⟩|R_0\rangle, ∣R1⟩|R_1\rangle, et ainsi de suite, dans l'ordre. Le vecteur estimé kthk^\text{th} se situe dans

∣xk+1⟩∈∣x0⟩+span{∣R0⟩,∣R1⟩,…,∣Rk⟩}.|x_{k+1}\rangle\in |x_0\rangle+\text{span}\{|R_0\rangle,|R_1\rangle,…,|R_k\rangle \}.

Maintenant, en utilisant la relation que

∣Rk+1⟩=∣b⟩−A∣xk+1⟩=∣b⟩−A(∣xk⟩+αk∣Rk⟩)=∣Rk⟩−αkA∣Rk⟩,|R_{k+1}\rangle=|b\rangle−A |x_{k+1}\rangle=|b\rangle−A(|x_k\rangle+\alpha_k |R_k\rangle)=|R_k\rangle−\alpha_k A |R_k\rangle,

nous constatons que

span{∣R0⟩,∣R1⟩,…,∣Rk⟩}=span{∣R0⟩,A∣R0⟩,…,Ak∣R0⟩}.\text{span} \{|R_0\rangle,|R_1\rangle,…,|R_k\rangle \}=\text{span} \{|R_0\rangle,A|R_0\rangle,…,A^{k}|R_0\rangle \}.

Autrement dit, l'espace que nous construisons et qui se rapproche le plus efficacement de la solution correcte ∣x⟩|x\rangle est précisément l'espace obtenu par l'application successive de la matrice AA sur ∣R0⟩|R_0\rangle. Un sous-espace de Krylov est l'espace engendré par les vecteurs représentant les directions successives de la descente la plus raide.

Enfin, nous rappelons que nous n'avons fait aucune déclaration numérique sur la mise à l'échelle de cette approche et que nous n'avons pas non plus discuté de l'avantage comparatif pour les matrices éparses. Il s'agit uniquement de motiver l'utilisation des méthodes du sous-espace de Krylov et de leur donner un sens intuitif. Nous allons maintenant explorer le comportement de ces méthodes numériquement.

Vérifiez votre compréhension

Dans le processus ci-dessus, nous avons proposé de minimiser la norme AA de l'erreur. Quelles autres quantités pourrait-on envisager de minimiser dans la recherche de l'état fondamental et de sa valeur propre?

  • On pourrait imaginer d'utiliser le vecteur résiduel au lieu de la norme AA de l'erreur. Dans certains cas, il peut être utile de considérer le vecteur d'erreur lui-même.


2. Méthodes de Krylov dans le calcul classique

Dans cette section, nous mettons en œuvre les itérations d'Arnoldi de manière informatique afin de pouvoir exploiter un sous-espace de Krylov pour résoudre les problèmes de valeurs propres. Nous l'appliquerons d'abord à un exemple à petite échelle, puis nous examinerons comment le temps de calcul s'adapte à l'augmentation de la taille de la matrice concernée. Une idée clé ici est que la génération des vecteurs couvrant l'espace de Krylov contribuera largement au temps de calcul total requis. La mémoire nécessaire varie selon les méthodes de Krylov. Mais les contraintes de mémoire peuvent limiter l'utilisation des méthodes traditionnelles de Krylov.

2.1 Exemple simple à petite échelle

Lors de la création d'un sous-espace de Krylov, nous devons orthonormer les vecteurs de notre sous-espace. Définissons une fonction qui prend un vecteur établi dans notre sous-espace vknown (non supposé être normalisé) et un vecteur candidat à ajouter à notre sous-espace vnext et qui rend vnext orthogonal à vknown et normalisé. Définissons également une fonction qui suit ce processus pour tous les vecteurs établis dans notre sous-espace de Krylov afin de garantir un ensemble totalement orthonormé.

# vknown is some established vector in our subspace. vnext is one we wish to add,
# which must be orthogonal to vknown.


def orthog_pair(vknown, vnext):
    vknown = vknown / np.sqrt(vknown.T @ vknown)
    diffvec = vknown.T @ vnext * vknown
    vnext = vnext - diffvec
    return vnext


# v is the candidate vector to be added to our subspace. s is the existing subspace.


def orthoset(v, s):
    v = v / np.sqrt(v.T @ v)
    temp = v
    for i in range(len(s)):
        temp = orthog_pair(s[i], temp)
    v = temp / np.sqrt(temp.T @ temp)
    return v

Définissons maintenant une fonction qui construit un sous-espace de Krylov de plus en plus grand, jusqu'à ce que l'espace des vecteurs de Krylov couvre l'espace complet de la matrice originale. Cela nous permettra de voir dans quelle mesure les valeurs propres obtenues à l'aide de notre méthode de sous-espace de Krylov correspondent aux valeurs exactes, en fonction de la dimension du sous-espace de Krylov. Il est important de noter que notre fonction krylov_full_build renvoie les vecteurs de Krylov, les hamiltoniens projetés, les valeurs propres et le temps nécessaire.

# Necessary imports and definitions to track time in microseconds
import time


def time_mus():
    return int(time.time() * 1000000)


# This function constructs a Krylov subspace that spans the whole space of the original matrix.
#     Input:
#       v0          : initial vector
#       matrix      : original matrix to be diagonalized
#     Output:
#       ks          : Krylov vectors
#       Hs          : projected Hamiltonians
#       eigs        : eigenvalues
#       k_tot_times : time required for the operation


def krylov_full_build(v0, matrix):
    t0 = time_mus()
    b = v0 / np.sqrt(v0 @ v0.T)
    A = matrix
    ks = []
    ks.append(b)
    Hs = []
    eigs = []
    Hs.append(b.T @ A @ b)
    eigs.append(np.array([b.T @ A @ b]))
    k_tot_times = []

    for j in range(len(A) - 1):
        vec = A @ ks[j].T
        ortho = orthoset(vec, ks)
        ks.append(ortho)
        ksarray = np.array(ks)
        Hs.append(ksarray @ A @ ksarray.T)
        eigs.append(np.linalg.eig(Hs[j + 1]).eigenvalues)
        k_tot_times.append(time_mus() - t0)

    # Return the Krylov vectors, the projected Hamiltonians, the eigenvalues,
    # and the total time required.
    return (ks, Hs, eigs, k_tot_times)

Nous allons tester cette méthode sur une matrice qui est encore assez petite, mais plus grande que ce que nous pourrions vouloir faire à la main.

# Define our small test matrix
test_matrix = np.array(
    [
        [4, -1, 0, 1, 0],
        [-1, 4, -1, 2, 1],
        [0, -1, 4, 3, 3],
        [1, 2, 3, 4, 0],
        [0, 1, 3, 0, 4],
    ]
)

# Give the test matrix and an initial guess as arguments in the function defined above.
# Calculate outputs.
test_ks, test_Hs, test_eigs, text_k_tot_times = krylov_full_build(
    np.array([0.5, 0.5, 0, 0.5, 0.5]), test_matrix
)

Nous pouvons vérifier nos fonctions en nous assurant qu'à la dernière étape (lorsque l'espace de Krylov est l'espace vectoriel complet de la matrice originale), les valeurs propres de la méthode de Krylov correspondent exactement à celles de la diagonalisation numérique exacte :

print(np.linalg.eig(test_matrix).eigenvalues)
print(test_eigs[len(test_matrix) - 1])

Output:

[-1.36956923  8.43756009  2.9040308   5.34436028  4.68361806]
[-1.36956923  8.43756009  2.9040308   4.68361806  5.34436028]

C'est un succès. Bien entendu, ce qui compte vraiment, c'est la qualité de notre approximation en fonction de la dimension de notre sous-espace de Krylov. Étant donné que nous sommes souvent préoccupés par la recherche d'états fondamentaux et d'autres valeurs propres minimales (et pour d'autres raisons plus algébriques expliquées ci-dessous), examinons notre estimation de la valeur propre la plus faible en fonction de la dimension du sous-espace de Krylov. C'est-à-dire

def errors(matrix, krylov_eigs):
    targ_min = min(np.linalg.eig(matrix).eigenvalues)
    err = []
    for i in range(len(matrix)):
        err.append(min(krylov_eigs[i]) - targ_min)
    return err
import matplotlib.pyplot as plt

krylov_error = errors(test_matrix, test_eigs)

plt.plot(krylov_error)
plt.axhline(y=0, color="red", linestyle="--")  # Add dashed red line at y=0
plt.xlabel("Order of Krylov subspace")  # Add x-axis label
plt.ylabel("Error in minimum eigenvalue")  # Add y-axis label
plt.show()

Output:

Output of the previous code cell

On constate que la valeur propre minimale est atteinte avec une assez grande précision dès que le sous-espace de Krylov a atteint la taille K2\mathcal{K}^2, et qu’elle est parfaite selon K3\mathcal{K}^3.

2.2 Échelle de temps avec dimension matricielle

Convainquons-nous que la méthode de Krylov peut être avantageuse par rapport aux résolveurs numériques exacts de la manière suivante :

  • Construire des matrices aléatoires (pas très clairsemées, pas l'application idéale pour la KQD)
  • Déterminer les valeurs propres à l'aide de deux méthodes : directement en utilisant NumPy et en utilisant un sous-espace de Krylov.
  • Nous choisissons un seuil de précision pour nos valeurs propres, avant d'accepter les estimations de Krylov.
  • Comparez le temps nécessaire pour résoudre le problème de ces deux manières.

Mises en garde : Comme nous le verrons en détail ci-dessous, la diagonalisation quantique de Krylov s'applique mieux aux opérateurs dont les représentations matricielles sont peu nombreuses et/ou peuvent être écrites à l'aide d'un petit nombre de groupes d'opérateurs de Pauli commutatifs. Les matrices aléatoires que nous utilisons ici ne correspondent pas à cette description. Celles-ci ne sont utiles que pour sonder l'échelle à laquelle les méthodes de Krylov classiques pourraient être utiles. Deuxièmement, en utilisant la méthode de Krylov, nous calculerons les valeurs propres en utilisant de nombreux sous-espaces de Krylov de tailles différentes. Nous indiquerons le temps nécessaire pour obtenir le sous-espace de Krylov de dimension minimale qui permet d'obtenir la précision requise pour la valeur propre de l'état fondamental. Là encore, il s'agit d'une situation un peu différente de la résolution d'un problème insoluble pour les résolveurs exacts, puisque nous utilisons la solution exacte pour évaluer la dimension nécessaire.

Nous commençons par générer notre ensemble de matrices aléatoires.

import numpy as np

# Set the random seed
np.random.seed(42)

# how many random matrices will we make
num_matrix = 200

matrices = []
for m in range(1, num_matrix):
    matrices.append(np.random.rand(m, m))

Nous allons maintenant diagonaliser chaque matrice directement, en utilisant numpy. Nous calculons le temps nécessaire à la diagonalisation pour une comparaison ultérieure.

matrix_numpy_times = []
matrix_numpy_eigs = []
for mm in range(num_matrix - 1):
    t0 = time_mus()
    matrix_numpy_eigs.append(min(np.linalg.eig(matrices[mm]).eigenvalues))
    matrix_numpy_times.append(time_mus() - t0)

plt.plot(matrix_numpy_times)
plt.xlabel("Dimension of matrix")  # Add x-axis label
plt.ylabel("Time to diagonalize (microsec)")  # Add y-axis label
plt.show()

Output:

Output of the previous code cell

Notez que dans l'image ci-dessus, le temps anormalement élevé autour d'une dimension de 125 peut être dû à la nature aléatoire des matrices ou à l'implémentation sur le processeur classique utilisé, mais il n'est pas reproductible. Une nouvelle exécution du code produira un profil différent avec des pics anormaux différents.

Pour chaque matrice, nous allons maintenant construire un sous-espace de Krylov et calculer les valeurs propres par étapes. À chaque étape, nous vérifions si la valeur propre la plus basse a été obtenue avec l'erreur absolue spécifiée. Le sous-espace qui nous donne en premier des valeurs propres dans les limites de l'erreur spécifiée est le sous-espace pour lequel nous enregistrerons les temps de calcul. L'exécution de cette cellule peut prendre plusieurs minutes, en fonction de la vitesse du processeur. N'hésitez pas à sauter l'évaluation ou à réduire la dimension maximale des matrices diagonalisées. Il suffit de regarder les résultats précalculés.

# Choose the absolute error you can tolerate, and make a list for tracking the Krylov subspace size
# at which that error is achieved.
abserr = 0.05
accept_subspace_size = []

# Lists to store total time spent on the Krylov method, and the subset of that time spent on
# diagonalizing the projected matrix.
matrix_krylov_tot_times = []
matrix_krylov_dim = []

# Step through all our random matrices
for mm in range(0, num_matrix - 1):
    test_ks, test_Hs, test_eigs, test_k_tot_times = krylov_full_build(
        np.ones(len(matrices[mm])), matrices[mm]
    )
    # We have not yet found a Krylov subspace that produces our minimum eigenvalue to
    # within the required error.
    found = 0
    for j in range(0, len(matrices[mm]) - 1):
        # If we still haven't found the desired subspace...
        if found == 0:
            # ...but if this one satisfies the requirement, then record everything
            if (
                abs((min(test_eigs[j]) - matrix_numpy_eigs[mm]) / matrix_numpy_eigs[mm])
                < abserr
            ):
                accept_subspace_size.append(j)
                matrix_krylov_tot_times.append(test_k_tot_times[j])
                matrix_krylov_dim.append(mm)
                found = 1

Traçons les temps que nous avons obtenus pour ces deux méthodes à titre de comparaison :

plt.plot(matrix_numpy_times, color="blue")
plt.plot(matrix_krylov_dim, matrix_krylov_tot_times, color="green")
plt.xlabel("Dimension of matrix")  # Add x-axis label
plt.ylabel("Time to diagonalize (microsec)")  # Add y-axis label
plt.show()

Output:

Output of the previous code cell

Il s'agit des temps réels nécessaires, mais pour les besoins de la discussion, nous allons lisser ces courbes en faisant la moyenne sur quelques points adjacents / dimensions de la matrice. C'est ce qui est fait ci-dessous :

smooth_numpy_times = []
smooth_krylov_times = []

# Choose the number of adjacent points over which to average forward;
# the same will be used backward.
smooth_steps = 10

# We will do this smoothing for all points/matrix dimensions
for i in range(len(matrix_krylov_tot_times)):
    # Ensure we don't exceed the boundaries of our lists
    start = max(0, i - smooth_steps)
    end = min(len(matrix_krylov_tot_times) - 1, i + smooth_steps)

    # Dummy variables for accumulating an average over adjacent points. This is done for both Krylov
    # and the NumPy calculations.
    smooth_count = 0
    smooth_numpy_sum = 0
    smooth_krylov_sum = 0

    for j in range(start, end):
        smooth_numpy_sum = smooth_numpy_sum + matrix_numpy_times[j]
        smooth_krylov_sum = smooth_krylov_sum + matrix_krylov_tot_times[j]
        smooth_count = smooth_count + 1

    # Appending the averaged adjacent values to our new smooth lists
    smooth_numpy_times.append(smooth_numpy_sum / smooth_count)
    smooth_krylov_times.append(smooth_krylov_sum / smooth_count)
plt.plot(smooth_numpy_times, color="blue")
plt.plot(smooth_krylov_times, color="green")
plt.xlabel("Dimension of matrix")  # Add x-axis label
plt.ylabel("Time to diagonalize (smoothed, microsec)")  # Add y-axis label
plt.show()

Output:

Output of the previous code cell

Notez que le temps nécessaire à la construction d'un sous-espace de Krylov dépasse initialement le temps nécessaire à la diagonalisation complète de numpy. Mais lorsque la taille de la matrice augmente, la méthode de Krylov devient avantageuse. Cela est vrai même si nous abaissons notre erreur acceptable, mais l'avantage apparaît lorsque la taille de la matrice est plus grande. Cela vaut la peine d'être décortiqué.

La complexité temporelle de la diagonalisation numérique est de O(n3)O(n^3) (avec quelques variations d'un algorithme à l'autre). La complexité temporelle de la génération d'une base orthonormée de vecteurs nn est également de O(n3)O(n^3). L'avantage de la méthode de Krylov ne réside donc pas dans l'utilisation d'une base orthonormée some\it{some}, mais dans l'utilisation d'une base orthonormée particulière qui sélectionne efficacement les valeurs propres d'intérêt. Nous l'avons déjà vu dans l'esquisse d'une preuve dans la première section de cette leçon, et cela est essentiel pour les garanties de convergence dans les méthodes de Krylov.

Passons en revue les progrès réalisés jusqu'à présent :

  • Pour les très grandes matrices, la méthode du sous-espace de Krylov peut donner des valeurs propres approximatives dans les tolérances requises plus rapidement que les algorithmes de diagonalisation traditionnels.
  • Pour des matrices aussi grandes, la génération d'un sous-espace de Krylov est la partie la plus longue de la méthode du sous-espace de Krylov.
  • Il serait donc très utile de disposer d'un moyen efficace de générer un sous-espace de Krylov. C'est enfin là que l'ordinateur quantique entre en scène.

Vérifiez votre compréhension

Reportez-vous au graphique lissé ci-dessus représentant les temps de diagonalisation en fonction de la dimension de la matrice.

(a) D'après ce graphique, à partir de quelle dimension approximative de la matrice la méthode de Krylov est-elle devenue plus rapide?

(b) Quels aspects du calcul pourraient modifier la dimension à partir de laquelle la méthode de Krylov devient plus rapide?

  • (a) Les résultats peuvent varier si vous relancez le calcul, mais la méthode de Krylov devient plus rapide à partir d'une dimension d'environ 80 à 85.

    (b) Il existe de nombreuses réponses possibles. Parmi les facteurs importants, on peut citer la précision requise et la稀疏性 des matrices à diagonaliser.


3. Krylov via l'évolution temporelle

Tout ce que nous avons décrit jusqu'à présent peut être réalisé de manière classique. Comment et quand utiliserions-nous un ordinateur quantique? Pour les très grandes matrices, la méthode de Krylov peut nécessiter de longs temps de calcul et de grandes quantités de mémoire. Le temps nécessaire à l'opération matricielle de HH sur ∣v⟩|v\rangle est équivalent à celui de O(N2)O(N^2) dans le pire des cas. Même la multiplication de matrices éparses sur un vecteur (le cas typique des solveurs classiques de type Krylov) a une échelle de complexité temporelle de l'ordre de O(N)O(N). Ceci est fait pour chaque vecteur que nous voulons dans notre sous-espace. La dimension du sous-espace rr n'est généralement pas une fraction significative de NN, et s'échelonne souvent comme log⁡(N)\log(N). Par conséquent, la génération de tous les vecteurs est comparable à O(N2log⁡(N))O(N^2 \log(N)) dans le pire des cas. Bien qu'il y ait d'autres étapes, comme l'orthogonalisation, c'est l'échelle dominante qu'il faut garder à l'esprit.

L'informatique quantique nous permet de modifier les attributs du problème qui déterminent l'échelle du temps et des ressources nécessaires. Au lieu de dépendre de la taille de la matrice NN, nous verrons des éléments tels que le nombre de tirs et le nombre de termes de Pauli non commutatifs qui composent l'hamiltonien. Voyons comment cela fonctionne.

3.1 Évolution dans le temps

Rappelons que l'opérateur qui fait évoluer dans le temps un état quantique est e−iHt/ℏe^{-iHt/\hbar} (et il est très courant, en particulier en informatique quantique, de supprimer le ℏ\hbar de la notation). Une façon de comprendre et même de réaliser une telle fonction exponentielle d'un opérateur est d'examiner son expansion en série de Taylor. Notez que cette opération agissant sur un vecteur initial ∣v⟩|v\rangle produit une somme de termes avec des puissances croissantes de HH appliquées à l'état initial. Il semble que nous puissions créer notre sous-espace de Krylov en faisant évoluer dans le temps l'état de notre supposition initiale!

e−iHt/ℏ→e−iHt≈1−iHt−(H2t2)2+⋯e−iHt∣v⟩≈∣v⟩−iHt∣v⟩−(H2t2)2∣v⟩+⋯\begin{aligned} e^{-iHt/\hbar}→e^{-iHt}&≈1-iHt-\frac{(H^2 t^2)}{2}+⋯\\ e^{-iHt} |v\rangle &≈ |v\rangle-iHt|v\rangle-\frac{(H^2 t^2)}{2}|v\rangle+⋯ \end{aligned}

La mise en garde concerne la réalisation de l'évolution temporelle sur un véritable ordinateur quantique. De nombreux termes de l'hamiltonien ne commuteront pas entre eux. Ainsi, si certains opérateurs exponentiels simples comme e−iZe^{-iZ} correspondent à des circuits simples, ce n'est pas le cas des hamiltoniens généraux. Et comme ils contiennent des termes non commutatifs, nous ne pouvons pas simplement décomposer l'exponentielle en un produit de termes simples, comme nous pouvons le faire avec les nombres.

e−iHt=e−i(H1+H2+⋯+Hn)t≠e−iH1te−iH2t...e−iHnte^{-iHt}=e^{-i(H_1+H_2+⋯+H_n)t}\neq e^{-iH_1 t} e^{-iH_2 t}... e^{-iH_n t}

Ce n'est donc pas trivial, mais c'est un processus bien étudié dans l'informatique quantique. Nous réalisons l'évolution temporelle sur les ordinateurs quantiques à l'aide d'un processus appelé trotterisation, qui est en soi un sujet très riche [10]. Mais à un niveau très élevé, en divisant l'évolution temporelle en très petites étapes, par exemple mm étapes de taille dtdt, nous limitons les effets de la non-commutativité des termes.

e−iHt=e−i(H1+H2+⋯+Hn)t=(e−i(H1+H2+⋯+Hn)t/m)m≈(e−iH1dte−iH2dt…e−iHndt)me^{-iHt}=e^{-i(H_1+H_2+⋯+H_n )t} = (e^{-i(H_1+H_2+⋯+H_n )t/m} )^m ≈(e^{-iH_1 dt} e^{-iH_2 dt} …e^{-iH_n dt} )^m

où dt=t/mdt = t/m.

Appelons "sous-espace de Krylov d'ordre r" un sous-espace de Krylov que nous avons généré dans le contexte classique en utilisant directement des puissances de H.

KPr(H,∣v⟩)=span{∣v⟩,H∣v⟩,H2∣v⟩…Hr−1∣v⟩}\mathcal{K}_P^r (H,|v\rangle)=\text{span}\{|v\rangle,H|v\rangle,H^2 |v\rangle… H^{r-1} |v\rangle\}

Nous générons maintenant un espace similaire en utilisant l'opérateur d'évolution temporelle unitaire U≡e−iHtU \equiv e^{-iHt}; nous l'appellerons "espace de Krylov unitaire" KUr\mathcal{K}_U^r. Le sous-espace de Krylov puissance KPr\mathcal{K}_P^r que nous utilisons classiquement ne peut pas être généré directement sur un ordinateur quantique car HH n'est pas un opérateur unitaire. On peut montrer que l'utilisation du sous-espace de Krylov unitaire donne des garanties de convergence similaires à celles du sous-espace de Krylov puissance, à savoir que l'erreur de l'état fondamental converge efficacement tant que l'état initial ∣v⟩|v\rangle a un chevauchement avec l'état fondamental réel qui ne s'évanouit pas exponentiellement, et tant qu'il y a un écart suffisant entre les valeurs propres. Voir la référence [1] pour une discussion plus précise sur la convergence.

Ici, les puissances de UU deviennent des pas de temps différents (la puissance kthk^\text{th} de UU avance d'un temps k×dtk \times dt ). Nous pouvons appeler ∣ψk⟩|\psi_k\rangle l'élément du sous-espace qui évolue dans le temps pour la durée totale kdtk dt.

U=e−iHdtUk=e−iH(kdt)KUr=span{∣ψ⟩,U∣ψ⟩,U2∣ψ⟩…Ur−1∣ψ⟩}\begin{aligned} U&=e^{-iHdt}\\ U^k&=e^{-iH(kdt)}\\ \mathcal{K}_U^r&=\text{span}\{|\psi\rangle,U|\psi\rangle,U^2 |\psi\rangle… U^{r-1} |\psi\rangle\} \end{aligned}

Nous pouvons projeter notre hamiltonien H sur le sous-espace de Krylov unitaire, KUr\mathcal{K}_U^r. En d'autres termes, nous calculons chaque élément de la matrice de HH dans la base KUr\mathcal{K}_U^r. Nous appellerons cette matrice projetée H~\tilde{H}.

3.2 Comment implémenter sur un ordinateur quantique

Les éléments de la matrice de H~\tilde{H} sont donnés par les valeurs d'espérance ⟨ψm∣H∣ψn⟩\langle \psi_m |H| \psi_n\rangle, qui peuvent être estimées à l'aide de l'ordinateur quantique. N'oubliez pas que HH peut être écrit comme une somme d'opérateurs de Pauli sur différents qubits, et que tous les opérateurs de Pauli ne peuvent pas être mesurés simultanément. Nous pouvons trier les termes de Pauli en groupes de termes commutatifs et les mesurer tous en même temps. Mais nous pourrions avoir besoin de plusieurs groupes de ce type pour couvrir tous les termes. Le nombre de groupes distincts de navetteurs dans lesquels les termes peuvent être répartis ( NGCPN_\text{GCP} ) devient donc important.

H=∑α=1NGCPcαPαH=\sum_{\alpha=1}^{N_\text{GCP}} c_\alpha P_\alpha

Ici, PαP_\alpha désigne une chaîne de Pauli de la forme Pα∼IZIXII...YZXIXP_\alpha \sim IZIXII...YZXIX ou un ensemble de telles chaînes de Pauli qui commutent entre elles. Étant donné que l'on peut écrire HH sous la forme d'une somme d'opérateurs mesurables, les expressions suivantes pour les éléments de matrice de H~\tilde{H} peuvent être mises en œuvre à l'aide de l'estimateur primitif IBM Quantum.

H~mn=⟨ψm∣H∣ψn⟩=⟨ψeiHtm∣H∣ψe−iHtn⟩=⟨ψeiHmdt∣H∣ψe−iHndt⟩\begin{aligned} \tilde{H}_{mn}&=\langle \psi_m |H| \psi_n\rangle\\ &=\langle \psi e^{iHt_m} |H| \psi e^{-iHt_n}\rangle\\ &=\langle \psi e^{iHmdt} |H|\psi e^{-iHndt}\rangle \end{aligned}

Où ∣ψn⟩=e−iHtn∣ψ⟩\vert \psi_n \rangle = e^{-i H t_n} \vert \psi \rangle sont les vecteurs de l'espace de Krylov unitaire et tn=ndtt_n = n dt sont les multiples du pas de temps dtdt choisi. Sur un ordinateur quantique, le calcul de chaque élément de matrice peut être effectué à l'aide de n'importe quel algorithme permettant d'obtenir un chevauchement entre les états quantiques. Dans cette leçon, nous allons nous intéresser au test de Hadamard. Étant donné que l’ KU\mathcal{K}_U e a pour dimension rr, l’hamiltonien projeté dans le sous-espace aura pour dimension r×rr \times r. Si rr est suffisamment petit (en général, r<<100r<<100 suffit pour garantir la convergence des estimations des valeurs propres), on peut alors facilement diagonaliser l’hamiltonien projeté H~\tilde{H}, de manière classique. Cependant, nous ne pouvons pas diagonaliser directement H~\tilde{H} en raison de la non-orthogonalité des vecteurs de l'espace de Krylov. Il va falloir mesurer leurs chevauchements et construire une matrice S~\tilde{S}

S~mn=⟨ψm∣ψn⟩\tilde{S}_{mn} = \langle \psi_m \vert \psi_n \rangle

Cela nous permet de résoudre le problème des valeurs propres dans un espace non orthogonal (également appelé problème généralisé des valeurs propres)

H~ c⃗=E S~ c⃗\tilde{H} \ \vec{c} = E \ \tilde{S} \ \vec{c}

On peut alors obtenir des estimations des valeurs propres et des états propres de HH en examinant les solutions de ce problème généralisé des valeurs propres. Par exemple, l'estimation de l'énergie de l'état fondamental est obtenue en prenant la plus petite valeur propre EE et l'état fondamental à partir du vecteur propre correspondant c⃗\vec{c}. Les coefficients dans c⃗\vec{c} déterminent la contribution des différents vecteurs qui couvrent KU\mathcal{K}_U.

Problème général des valeurs propres

Pourquoi ne pouvons-nous pas simplement diagonaliser H~\tilde{H}? Étant donné que S~\tilde{S} contient des informations sur la géométrie de la base de Krylov (qui n'est pas orthogonale sauf dans des cas très particuliers), H~\tilde{H} ne décrit pas à lui seul une projection de l'hamiltonien complet, de sorte que ses valeurs propres n'ont aucune relation particulière avec celles de l'hamiltonien complet - elles pourraient être n'importe quelles valeurs aléatoires. La résolution du problème des valeurs propres généralisées est nécessaire pour obtenir les valeurs propres et les vecteurs propres approximatifs correspondant à la projection de l'hamiltonien complet dans l'espace de Krylov...

Un schéma de circuit avec de nombreuses couches indiquant que le circuit doit être utilisé plusieurs fois avec différents états pour effectuer le test de Hadamard modifié.

La figure montre une représentation du circuit du test de Hadamard modifié, une méthode utilisée pour calculer le chevauchement entre différents états quantiques. Pour chaque élément de la matrice H~i,j\tilde{H}_{i,j}, un test de Hadamard entre les états ∣ψi⟩\vert \psi_i \rangle, ∣ψj⟩\vert \psi_j \rangle est effectué. Ceci est mis en évidence dans la figure par le schéma de couleurs pour les éléments de la matrice et les opérations Prep  ψi\text{Prep} \; \psi_i, Prep  ψj\text{Prep} \; \psi_j correspondantes. Ainsi, un ensemble de tests de Hadamard pour toutes les combinaisons possibles de vecteurs de l'espace de Krylov est nécessaire pour calculer tous les éléments de la matrice de l'hamiltonien projeté H~\tilde{H}. Le fil supérieur du circuit de test de Hadamard est un qubit d'ancilla qui est mesuré soit dans la base X, soit dans la base Y. Sa valeur d'espérance détermine la valeur du chevauchement entre les états. Le fil du bas représente tous les qubits de l'hamiltonien du système. L'opération Prep  ψi\text{Prep} \; \psi_i prépare le qubit du système dans l'état ∣ψi⟩\vert \psi_i \rangle contrôlé par l'état du qubit ancillaire (de même pour Prep  ψj\text{Prep} \; \psi_j ) et l'opération PP représente la décomposition de Pauli de l'hamiltonien du système H=∑iPiH = \sum_i P_i. La mise en œuvre de cette opération sur un ordinateur quantique est présentée plus en détail ci-dessous.


4. Diagonalisation quantique de Krylov sur un ordinateur quantique

Nous allons maintenant mettre en œuvre la diagonalisation quantique de Krylov sur un véritable ordinateur quantique. Commençons par importer quelques paquets utiles.

import numpy as np
import scipy as sp
import matplotlib.pylab as plt
from typing import Union, List
import warnings

from qiskit.quantum_info import SparsePauliOp, Pauli
from qiskit.circuit import Parameter
from qiskit import QuantumCircuit, QuantumRegister
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.synthesis import LieTrotter

# from qiskit.providers.fake_provider import Fake20QV1
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator, Batch

import itertools as it

warnings.filterwarnings("ignore")

Nous définissons la fonction ci-dessous pour résoudre le problème des valeurs propres généralisées que nous venons d'expliquer.

def solve_regularized_gen_eig(
    h: np.ndarray,
    s: np.ndarray,
    threshold: float,
    k: int = 1,
    return_dimn: bool = False,
) -> Union[float, List[float]]:
    """
    Method for solving the generalized eigenvalue problem with regularization

    Args:
        h (numpy.ndarray):
            The effective representation of the matrix in our Krylov subspace
        s (numpy.ndarray):
            The matrix of overlaps between vectors of our Krylov subspace
        threshold (float):
            Cut-off value for the eigenvalue of s
        k (int):
            Number of eigenvalues to return
        return_dimn (bool):
            Whether to return the size of the regularized subspace

    Returns:
        lowest k-eigenvalue(s) that are the solution of the regularized generalized eigenvalue problem


    """
    s_vals, s_vecs = sp.linalg.eigh(s)
    s_vecs = s_vecs.T
    good_vecs = np.array([vec for val, vec in zip(s_vals, s_vecs) if val > threshold])
    h_reg = good_vecs.conj() @ h @ good_vecs.T
    s_reg = good_vecs.conj() @ s @ good_vecs.T
    if k == 1:
        if return_dimn:
            return sp.linalg.eigh(h_reg, s_reg)[0][0], len(good_vecs)
        else:
            return sp.linalg.eigh(h_reg, s_reg)[0][0]
    else:
        if return_dimn:
            return sp.linalg.eigh(h_reg, s_reg)[0][:k], len(good_vecs)
        else:
            return sp.linalg.eigh(h_reg, s_reg)[0][:k]

Au moins dans le cadre d'une analyse comparative initiale, il est utile de connaître une solution classique exacte pour vérifier le comportement de la convergence. La fonction ci-dessous calcule l'énergie de l'état fondamental d'un hamiltonien, en utilisant le hamiltonien et le nombre de qubits comme arguments.

def single_particle_gs(H_op, n_qubits):
    """
    Find the ground state of the single particle(excitation) sector
    """
    H_x = []
    for p, coeff in H_op.to_list():
        H_x.append(set([i for i, v in enumerate(Pauli(p).x) if v]))

    H_z = []
    for p, coeff in H_op.to_list():
        H_z.append(set([i for i, v in enumerate(Pauli(p).z) if v]))

    H_c = H_op.coeffs

    print("n_sys_qubits", n_qubits)

    n_exc = 1
    sub_dimn = int(sp.special.comb(n_qubits + 1, n_exc))
    print("n_exc", n_exc, ", subspace dimension", sub_dimn)

    few_particle_H = np.zeros((sub_dimn, sub_dimn), dtype=complex)

    sparse_vecs = [
        set(vec) for vec in it.combinations(range(n_qubits + 1), r=n_exc)
    ]  # list all of the possible sets of n_exc indices of 1s in n_exc-particle states

    m = 0
    for i, i_set in enumerate(sparse_vecs):
        for j, j_set in enumerate(sparse_vecs):
            m += 1

            if len(i_set.symmetric_difference(j_set)) <= 2:
                for p_x, p_z, coeff in zip(H_x, H_z, H_c):
                    if i_set.symmetric_difference(j_set) == p_x:
                        sgn = ((-1j) ** len(p_x.intersection(p_z))) * (
                            (-1) ** len(i_set.intersection(p_z))
                        )
                    else:
                        sgn = 0

                    few_particle_H[i, j] += sgn * coeff

    gs_en = min(np.linalg.eigvalsh(few_particle_H))
    print("single particle ground state energy: ", gs_en)
    return gs_en

4.1 Étape 1 : Mettre en correspondance le problème avec les circuits quantiques et les opérateurs

Nous allons maintenant définir un hamiltonien. Cette fonction se distingue de la fonction ci-dessus en ce sens qu'elle prend un hamiltonien comme argument et ne renvoie que l'état fondamental, et ce de manière classique. L'hamiltonien que nous définissons ici détermine les niveaux d'énergie de tous les états propres énergétiques, et cet hamiltonien peut être construit à l'aide d'opérateurs de Pauli et mis en œuvre sur un ordinateur quantique.

Nous choisissons un hamiltonien correspondant à une chaîne de spins qui peut avoir n'importe quelle orientation dans l'espace, appelée "chaîne de Heisenberg". Nous supposons que le spin ithi^\text{th} peut être influencé par ses voisins les plus proches (les spins (i−1)th(i-1)^\text{th} et (i+1)th(i+1)^\text{th} ) mais pas par des voisins plus éloignés. Nous tenons également compte de la possibilité que l'interaction entre les spins soit différente lorsque les spins pointent le long d'axes différents. Cette asymétrie est parfois due, par exemple, à la structure du réseau cristallin dans lequel les spins sont intégrés.

# Define problem Hamiltonian.
n_qubits = 10
# coupling strength for XX, YY, and ZZ interactions
JX = 1
JY = 3
JZ = 2

# Define the Hamiltonian:
H_int = [["I"] * n_qubits for _ in range(3 * (n_qubits - 1))]
for i in range(n_qubits - 1):
    H_int[i][i] = "Z"
    H_int[i][i + 1] = "Z"
for i in range(n_qubits - 1):
    H_int[n_qubits - 1 + i][i] = "X"
    H_int[n_qubits - 1 + i][i + 1] = "X"
for i in range(n_qubits - 1):
    H_int[2 * (n_qubits - 1) + i][i] = "Y"
    H_int[2 * (n_qubits - 1) + i][i + 1] = "Y"
H_int = ["".join(term) for term in H_int]
H_tot = [
    (term, JZ)
    if term.count("Z") == 2
    else (term, JY)
    if term.count("Y") == 2
    else (term, JX)
    for term in H_int
]

# Get operator
H_op = SparsePauliOp.from_list(H_tot)
print(H_tot)

Output:

[('ZZIIIIIIII', 2), ('IZZIIIIIII', 2), ('IIZZIIIIII', 2), ('IIIZZIIIII', 2), ('IIIIZZIIII', 2), ('IIIIIZZIII', 2), ('IIIIIIZZII', 2), ('IIIIIIIZZI', 2), ('IIIIIIIIZZ', 2), ('XXIIIIIIII', 1), ('IXXIIIIIII', 1), ('IIXXIIIIII', 1), ('IIIXXIIIII', 1), ('IIIIXXIIII', 1), ('IIIIIXXIII', 1), ('IIIIIIXXII', 1), ('IIIIIIIXXI', 1), ('IIIIIIIIXX', 1), ('YYIIIIIIII', 3), ('IYYIIIIIII', 3), ('IIYYIIIIII', 3), ('IIIYYIIIII', 3), ('IIIIYYIIII', 3), ('IIIIIYYIII', 3), ('IIIIIIYYII', 3), ('IIIIIIIYYI', 3), ('IIIIIIIIYY', 3)]

Le code ci-dessous restreint l'hamiltonien à des états à une seule particule et utilise la norme spectrale pour définir une bonne taille pour notre pas de temps dtdt. Nous choisissons de manière heuristique une valeur pour le pas de temps dt (basée sur les limites supérieures de la norme de l'hamiltonien). Ref [9] a montré qu'un pas de temps suffisamment petit est π/∣∣H∣∣\pi/\vert \vert H \vert \vert, et qu'il est préférable jusqu'à un certain point de sous-estimer cette valeur plutôt que de la surestimer, car une surestimation peut permettre aux contributions des états à haute énergie de corrompre même l'état optimal dans l'espace de Krylov. D'autre part, le choix d'une valeur trop faible pour dtdt entraîne un mauvais conditionnement du sous-espace de Krylov, puisque les vecteurs de base de Krylov diffèrent moins d'un pas de temps à l'autre.

# Get Hamiltonian restricted to single-particle states
single_particle_H = np.zeros((n_qubits, n_qubits))
for i in range(n_qubits):
    for j in range(i + 1):
        for p, coeff in H_op.to_list():
            p_x = Pauli(p).x
            p_z = Pauli(p).z
            if all(p_x[k] == ((i == k) + (j == k)) % 2 for k in range(n_qubits)):
                sgn = ((-1j) ** sum(p_z[k] and p_x[k] for k in range(n_qubits))) * (
                    (-1) ** p_z[i]
                )
            else:
                sgn = 0
            single_particle_H[i, j] += sgn * coeff
for i in range(n_qubits):
    for j in range(i + 1, n_qubits):
        single_particle_H[i, j] = np.conj(single_particle_H[j, i])

# Set dt according to spectral norm
dt = np.pi / np.linalg.norm(single_particle_H, ord=2)
dt

Output:

np.float64(0.17453292519943295)

Nous spécifions le nombre d'étapes de Trotter à utiliser dans l'évolution temporelle. Nous spécifions également une dimension maximale de Krylov de 4. Cette dimension de Krylov n'est pas assez grande pour des applications réalistes. Mais cela suffit pour cet exemple. De plus, nous vérifierons la convergence à des dimensions encore plus petites. Nous explorerons dans les leçons suivantes des méthodes qui nous permettront de mettre à l'échelle et de projeter nos hamiltoniens sur des sous-espaces plus grands.

# Set parameters for quantum Krylov algorithm
krylov_dim = 4  # size of krylov subspace
num_trotter_steps = 4
dt_circ = dt / num_trotter_steps

Préparation de l'État

Choisissez un état de référence ∣ψ⟩\vert \psi \rangle qui présente un certain chevauchement avec l'état fondamental. Pour cet hamiltonien, nous utilisons l'état a avec une excitation dans le qubit du milieu ∣00..010...00⟩\vert 00..010...00 \rangle comme état de référence.

qc_state_prep = QuantumCircuit(n_qubits)
qc_state_prep.x(int(n_qubits / 2) + 1)
qc_state_prep.draw("mpl", scale=0.5)

Output:

Output of the previous code cell

Évolution dans le temps

Nous pouvons réaliser l'opérateur d'évolution temporelle généré par un hamiltonien donné : U=e−iHtU=e^{-iHt} via l' approximation de Lie-Trotter. Par souci de simplicité, nous utilisons le site PauliEvolutionGate intégré dans le circuit d'évolution temporelle. La syntaxe générale est la suivante.

t = Parameter("t")

## Create the time-evo op circuit
evol_gate = PauliEvolutionGate(
    H_op, time=t, synthesis=LieTrotter(reps=num_trotter_steps)
)

qr = QuantumRegister(n_qubits)
qc_evol = QuantumCircuit(qr)
qc_evol.append(evol_gate, qargs=qr)

Output:

<qiskit.circuit.instructionset.InstructionSet at 0x7ccaa4664250>

Nous utiliserons une version de cette méthode ci-dessous dans le test de Hadamard, mais en avançant pour les temps dtdt.

test de Hadamard

Rappelons que nous souhaitons calculer les éléments de matrice de la matrice d' H~\tilde{H} ainsi que de la matrice de Gram S~\tilde{S} à l'aide du test de Hadamard. Voyons comment cela fonctionne dans ce contexte, en nous concentrant d'abord sur la construction de H~\tilde{H}. Le processus global est illustré ci-dessous. Les couches de blocs de préparation d'états colorés Prep∣ψi⟩\text{Prep}|\psi_i\rangle rappellent que ce processus est effectué pour toutes les combinaisons de ∣ψi⟩|\psi_i\rangle et ∣ψj⟩|\psi_j\rangle dans notre sous-espace.

Image d'un schéma de circuit quantique avec de nombreuses couches indiquant que le circuit doit être évalué pour de nombreux états différents afin de réaliser le test de Hadamard.

Les états du système aux étapes indiquées sont les suivants :

Step 0:∣Ψ⟩=∣0⟩∣0⟩NStep 1:∣Ψ⟩=12(∣0⟩+∣1⟩)∣0⟩NStep 2:∣Ψ⟩=12(∣0⟩∣0⟩N+∣1⟩∣ψi⟩)Step 3:∣Ψ⟩=12(∣0⟩∣0⟩N+∣1⟩P∣ψi⟩)Step 4:∣Ψ⟩=12(∣0⟩∣ψj⟩+∣1⟩P∣ψi⟩)\begin{aligned} \text{Step 0:}\qquad|\Psi\rangle & = |0\rangle|0\rangle^N \\ \text{Step 1:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\Big(|0\rangle + |1\rangle \Big)|0\rangle^N \\ \text{Step 2:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\Big(|0\rangle|0\rangle^N+|1\rangle |\psi_i\rangle\Big)\\ \text{Step 3:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\Big(|0\rangle |0\rangle^N+|1\rangle P |\psi_i\rangle\Big) \\ \text{Step 4:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\Big(|0\rangle |\psi_j\rangle+|1\rangle P|\psi_i\rangle\Big) \end{aligned}

Ici, PP est un terme de Pauli dans la décomposition de l'hamiltonien (notez qu'il ne peut pas s'agir d'une combinaison linéaire de plusieurs termes de Pauli commutés, car cela ne serait pas unitaire - le regroupement est possible en utilisant une construction différente que nous montrerons plus tard). Prep  ψi\text{Prep} \; \psi_i, Prep  ψj\text{Prep} \; \psi_j sont des opérations contrôlées qui préparent ∣ψi⟩|\psi_i\rangle, ∣ψj⟩|\psi_j\rangle des vecteurs de l'espace de Krylov unitaire, avec ∣ψk⟩=e−iHkdt∣ψ⟩=e−iHkdtUψ∣0⟩N|\psi_k\rangle = e^{-i H k dt } \vert \psi \rangle = e^{-i H k dt } U_{\psi} \vert 0 \rangle^N. L'application des mesures de XX et YY à ce circuit permet de calculer les parties réelles et imaginaires, respectivement, des éléments de la matrice dont nous avons besoin.

En partant de l'étape 4 ci-dessus, appliquer la porte de Hadamard HH au qubit zeroth.

∣Ψ⟩⟶12∣0⟩(∣ψj⟩+P∣ψi⟩)+12∣1⟩(∣ψj⟩−P∣ψi⟩)\begin{equation*} |\Psi\rangle \longrightarrow\quad\frac{1}{2}|0\rangle\Big( |\psi_j\rangle + P|\psi_i\rangle\Big) + \frac{1}{2}|1\rangle\Big(|\psi_j\rangle - P|\psi_i\rangle\Big) \end{equation*}

Mesurez ensuite XX ou YY.

⇒⟨X⟩=14(∥∣ψj⟩+P∣ψi⟩∥2−∥∣ψj⟩−P∣ψi⟩∥2)=Re[⟨ψj∣P∣ψi⟩].\begin{equation*} \begin{split} \Rightarrow\quad\langle X\rangle &= \frac{1}{4}\Bigg(\Big\|| \psi_j\rangle + P|\psi_i\rangle \Big\|^2-\Big\||\psi_j\rangle - P|\psi_i\rangle\Big\|^2\Bigg) \\ &= \text{Re}\Big[\langle\psi_j| P|\psi_i\rangle\Big]. \end{split} \end{equation*}

D'après l'identité ∣a+b∥2=⟨a+b∣a+b⟩=∥a∥2+∥b∥2+2Re⟨a∣b⟩|a + b\|^2 = \langle a + b | a + b \rangle = \|a\|^2 + \|b\|^2 + 2\text{Re}\langle a | b \rangle. De même, en mesurant YY, on obtient

⟨Y⟩=Im[⟨ψj∣P∣ψi⟩].\begin{equation*} \langle Y\rangle = \text{Im}\Big[\langle\psi_j| P|\psi_i\rangle\Big]. \end{equation*}

En ajoutant ces étapes à l'évolution temporelle que nous avons établie précédemment, nous écrivons ce qui suit.

## Create the time-evo op circuit
evol_gate = PauliEvolutionGate(
    H_op, time=dt, synthesis=LieTrotter(reps=num_trotter_steps)
)

## Create the time-evo op dagger circuit
evol_gate_d = PauliEvolutionGate(
    H_op, time=dt, synthesis=LieTrotter(reps=num_trotter_steps)
)
evol_gate_d = evol_gate_d.inverse()

# Put pieces together
qc_reg = QuantumRegister(n_qubits)
qc_temp = QuantumCircuit(qc_reg)
qc_temp.compose(qc_state_prep, inplace=True)
for _ in range(num_trotter_steps):
    qc_temp.append(evol_gate, qargs=qc_reg)
for _ in range(num_trotter_steps):
    qc_temp.append(evol_gate_d, qargs=qc_reg)
qc_temp.compose(qc_state_prep.inverse(), inplace=True)

# Create controlled version of the circuit
controlled_U = qc_temp.to_gate().control(1)

# Create hadamard test circuit for real part
qr = QuantumRegister(n_qubits + 1)
qc_real = QuantumCircuit(qr)
qc_real.h(0)
qc_real.append(controlled_U, list(range(n_qubits + 1)))
qc_real.h(0)

print("Circuit for calculating the real part of the overlap in S via Hadamard test")
qc_real.draw("mpl", fold=-1, scale=0.5)

Output:

Circuit for calculating the real part of the overlap in S via Hadamard test
Output of the previous code cell

Nous avons déjà mis en garde contre la profondeur des circuits de Trotter. L'exécution du test de Hadamard dans ces conditions peut donner lieu à un circuit encore plus profond, en particulier une fois que nous avons décomposé en portes natives. Ce chiffre augmente encore si l'on tient compte de la topologie de l'appareil. Ainsi, avant d'utiliser le moindre temps sur l'ordinateur quantique, il est bon de vérifier la profondeur de 2 qubits de notre circuit.

print(
    "Number of layers of 2Q operations",
    qc_real.decompose(reps=2).depth(lambda x: x[0].num_qubits == 2),
)

Output:

Number of layers of 2Q operations 14401

Un circuit de cette complexité ne peut pas fournir de résultats exploitables sur les ordinateurs quantiques modernes. Si nous voulons créer les sites H~\tilde{H} et S~\tilde{S}, il nous faut trouver une meilleure solution. C'est ce qui justifie l'efficacité du test de Hadamard présenté ci-dessous.

4. Étape 2. Optimiser les circuits et les opérateurs pour le matériel cible

Test de Hadamard efficace

Nous pouvons optimiser les circuits profonds pour le test de Hadamard que nous avons obtenu en introduisant certaines approximations et en nous appuyant sur certaines hypothèses concernant l'hamiltonien du modèle. Par exemple, considérons le circuit suivant pour le test de Hadamard :

Image d'un schéma de circuit quantique avec de nombreuses couches indiquant que le circuit doit être évalué pour de nombreux opérateurs unitaires différents afin d'effectuer le test de Hadamard modifié et efficace.

Supposons que nous puissions calculer classiquement E0E_0, la valeur propre de ∣0⟩N|0\rangle^N sous l'hamiltonien HH. Cette condition est remplie lorsque l'hamiltonien préserve la symétrie U(1). Bien que cette hypothèse puisse sembler forte, il existe de nombreux cas où l'on peut supposer qu'il existe un état de vide (dans ce cas, il s'agit de l'état ∣0⟩N|0\rangle^N ) qui n'est pas affecté par l'action de l'hamiltonien. C'est le cas, par exemple, des hamiltoniens de chimie qui décrivent une molécule stable (où le nombre d'électrons est conservé). Étant donné que la porte Prep  ψ0\text{Prep} \; \psi_0, prépare l'état de référence souhaité ∣ψ0⟩=Prep  ψ0∣0⟩=e−iH0dtUψ0∣0⟩\ket{\psi_0} = \text{Prep} \; \psi_0 \ket{0} = e^{-i H 0 dt} U_{\psi_0} \ket{0}, par exemple, préparer l'état HF pour la chimie Prep  ψ0\text{Prep} \; \psi_0 serait un produit de NOT à un seul qubit, de sorte que controlled- Prep  ψ0\text{Prep} \; \psi_0 est simplement un produit de CNOT. Le circuit ci-dessus met alors en œuvre l'état suivant avant la mesure :

Step 0:∣Ψ⟩=∣0⟩∣0⟩NStep 1:∣Ψ⟩=12(∣0⟩∣0⟩N+∣1⟩∣0⟩N)Step 2:∣Ψ⟩=12(∣0⟩∣0⟩N+∣1⟩∣ψ0⟩)Step 3:∣Ψ⟩=12(eiϕ∣0⟩∣0⟩N+∣1⟩U∣ψ0⟩)Step 4:∣Ψ⟩=12(eiϕ∣0⟩∣ψ0⟩+∣1⟩U∣ψ0⟩)=12(∣+⟩(eiϕ∣ψ0⟩+U∣ψ0⟩)+∣−⟩(eiϕ∣ψ0⟩−U∣ψ0⟩))=12(∣+i⟩(eiϕ∣ψ0⟩−iU∣ψ0⟩)+∣−i⟩(eiϕ∣ψ0⟩+iU∣ψ0⟩))\begin{aligned} \text{Step 0:}\qquad|\Psi\rangle & = \ket{0} \ket{0}^{N}\\ \text{Step 1:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\left(\ket{0}\ket{0}^N+ \ket{1} \ket{0}^N\right)\\ \text{Step 2:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\left(|0\rangle|0\rangle^N+|1\rangle|\psi_0\rangle\right)\\ \text{Step 3:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\left(e^{i\phi}\ket{0}\ket{0}^N+\ket{1} U\ket{\psi_0}\right)\\ \text{Step 4:}\qquad|\Psi\rangle & = \frac{1}{\sqrt{2}}\left(e^{i\phi}\ket{0} \ket{\psi_0}+\ket{1} U\ket{\psi_0}\right)\\ & = \frac{1}{2}\left(\ket{+}\left(e^{i\phi}\ket{\psi_0}+U\ket{\psi_0}\right)+\ket{-}\left(e^{i\phi}\ket{\psi_0}-U\ket{\psi_0}\right)\right)\\ & = \frac{1}{2}\left(\ket{+i}\left(e^{i\phi}\ket{\psi_0}-iU\ket{\psi_0}\right)+\ket{-i}\left(e^{i\phi}\ket{\psi_0}+iU\ket{\psi_0}\right)\right) \end{aligned}

où nous avons utilisé le déphasage simulable classique U∣0⟩N=eiϕ∣0⟩N U\ket{0}^N = e^{i\phi}\ket{0}^N de l'étape 2 à 3. Les valeurs attendues sont donc les suivantes

⟨X⊗P⟩=14((e−iϕ⟨ψ0∣+⟨ψ0∣U†)P(eiϕ∣ψ0⟩+U∣ψ0⟩)−(e−iϕ⟨ψ0∣−⟨ψ0∣U†)P(eiϕ∣ψ0⟩−U∣ψ0⟩))=Re[e−iϕ⟨ψ0∣PU∣ψ0⟩],\begin{aligned} \langle X\otimes P\rangle&=\frac{1}{4} \Big( \left(e^{-i\phi}\bra{\psi_0}+\bra{\psi_0}U^\dagger\right)P\left(e^{i\phi}\ket{\psi_0}+U\ket{\psi_0}\right) \\ &\qquad-\left(e^{-i\phi}\bra{\psi_0}-\bra{\psi_0}U^\dagger\right)P\left(e^{i\phi}\ket{\psi_0}-U\ket{\psi_0}\right) \Big)\\ &=\text{Re}\left[e^{-i\phi}\bra{\psi_0}PU\ket{\psi_0}\right], \end{aligned} ⟨Y⊗P⟩=14((e−iϕ⟨ψ0∣+i⟨ψ0∣U†)P(eiϕ0∣ψ0⟩−iU∣ψ0⟩)−(e−iϕ⟨ψ0∣−i⟨ψ0∣U†)P(eiϕ∣ψ0⟩+iU∣ψ0⟩))=Im[e−iϕ⟨ψ0∣PU∣ψ0⟩]. \begin{aligned} \langle Y\otimes P\rangle&=\frac{1}{4} \Big( \left(e^{-i\phi}\bra{\psi_0}+i\bra{\psi_0}U^\dagger\right)P\left(e^{i\phi_0}\ket{\psi_0}-iU\ket{\psi_0}\right) \\ &\qquad-\left(e^{-i\phi}\bra{\psi_0}-i\bra{\psi_0}U^\dagger\right)P\left(e^{i\phi}\ket{\psi_0}+iU\ket{\psi_0}\right) \Big)\\ &=\text{Im}\left[e^{-i\phi}\bra{\psi_0}PU\ket{\psi_0}\right]. \end{aligned}

En utilisant ces hypothèses, nous avons pu écrire les valeurs attendues des opérateurs d'intérêt avec moins d'opérations contrôlées. En fait, nous ne devons mettre en œuvre que la préparation contrôlée de l'état Prep  ψ0\text{Prep} \; \psi_0 et non les évolutions temporelles contrôlées. En reformulant notre calcul comme indiqué ci-dessus, nous pourrons réduire considérablement la profondeur des circuits résultants.

Notez qu'en prime, puisque l'opérateur de Pauli apparaît maintenant comme une mesure à la fin du circuit plutôt que comme une porte contrôlée au milieu, il peut être mesuré avec d'autres opérateurs de Pauli commutés comme dans la décomposition H=∑α=1NGCPcαPαH=\sum_{\alpha = 1}^{N_\text{GCP}}c_\alpha P_\alpha donnée ci-dessus.

Décomposer l'opérateur d'évolution temporelle avec la décomposition de Trotter

Au lieu de mettre en œuvre l'opérateur d'évolution temporelle de manière exacte, nous pouvons utiliser la décomposition de Trotter pour en réaliser une approximation. En répétant plusieurs fois une certaine décomposition de Trotter, on parvient à réduire davantage l'erreur introduite par l'approximation. Dans ce qui suit, nous construisons directement l'implémentation de Trotter de la manière la plus efficace pour le graphe d'interaction de l'hamiltonien que nous considérons (interactions entre voisins les plus proches uniquement). En pratique, nous insérons des rotations de Pauli RxxR_{xx}, RyyR_{yy}, RzzR_{zz} avec des intensités de couplage JxJ_x, JyJ_y et JzJ_z ainsi qu’un angle paramétré tt, qui correspondent à la mise en œuvre approximative de e−i(JxXX+JyYY+JzZZ)te^{-i (J_x XX + J_y YY + J_z ZZ) t}. Compte tenu de la différence de définition entre les rotations de Pauli et l’évolution temporelle que nous cherchons à mettre en œuvre, nous devrons utiliser le paramètre 2∗dt2*dt pour obtenir une évolution temporelle de dtdt. De plus, nous inversons l’ordre des opérations pour les nombres impairs de répétitions des étapes de Trotter, ce qui est fonctionnellement équivalent mais permet de synthétiser des opérations adjacentes en un seul opérateur unitair SU(2)SU(2). On obtient ainsi un circuit beaucoup moins profond que celui obtenu à l'aide de la fonctionnalité PauliEvolutionGate() générique.

t = Parameter("t")

# Create instruction for rotation about XX+YY-ZZ:
Rxyz_circ = QuantumCircuit(2)
Rxyz_circ.rxx(2 * JX * t, 0, 1)
Rxyz_circ.ryy(2 * JY * t, 0, 1)
Rxyz_circ.rzz(2 * JZ * t, 0, 1)
Rxyz_instr = Rxyz_circ.to_instruction(label="R J_x XX + J_y YY + J_z ZZ")

interaction_list = [
    [[i, i + 1] for i in range(0, n_qubits - 1, 2)],
    [[i, i + 1] for i in range(1, n_qubits - 1, 2)],
]  # linear chain

qr = QuantumRegister(n_qubits)
trotter_step_circ = QuantumCircuit(qr)
for i, color in enumerate(interaction_list):
    for interaction in color:
        trotter_step_circ.append(Rxyz_instr, interaction)
    if i < len(interaction_list) - 1:
        trotter_step_circ.barrier()
reverse_trotter_step_circ = trotter_step_circ.reverse_ops()

qc_evol = QuantumCircuit(qr)
for step in range(num_trotter_steps):
    if step % 2 == 0:
        qc_evol = qc_evol.compose(trotter_step_circ)
    else:
        qc_evol = qc_evol.compose(reverse_trotter_step_circ)

qc_evol.decompose().draw("mpl", fold=-1, scale=0.5)

Output:

Output of the previous code cell

Nous préparons à nouveau un état initial pour ce test de Hadamard efficace.

control = 0
excitation = int(n_qubits / 2) + 1
controlled_state_prep = QuantumCircuit(n_qubits + 1)
controlled_state_prep.cx(control, excitation)
controlled_state_prep.draw("mpl", fold=-1, scale=0.5)

Output:

Output of the previous code cell

Circuits modèles pour calculer les éléments matriciels de S~\tilde{S} et H~\tilde{H} via le test de Hadamard

La seule différence entre les circuits utilisés dans le test de Hadamard sera la phase de l'opérateur d'évolution temporelle et les observables mesurés. Nous pouvons donc préparer un circuit modèle qui représente le circuit générique pour le test de Hadamard, avec des espaces réservés pour les portes qui dépendent de l'opérateur d'évolution temporelle.

# Parameters for the template circuits
parameters = []
for idx in range(1, krylov_dim):
    parameters.append(dt_circ * (idx))
# Create modified hadamard test circuit
qr = QuantumRegister(n_qubits + 1)
qc = QuantumCircuit(qr)
qc.h(0)
qc.compose(controlled_state_prep, list(range(n_qubits + 1)), inplace=True)
qc.barrier()
qc.compose(qc_evol, list(range(1, n_qubits + 1)), inplace=True)
qc.barrier()
qc.x(0)
qc.compose(controlled_state_prep.inverse(), list(range(n_qubits + 1)), inplace=True)
qc.x(0)

qc.decompose().draw("mpl", fold=-1)

Output:

Output of the previous code cell
print(
    "The optimized circuit has 2Q gates depth: ",
    qc.decompose().decompose().depth(lambda x: x[0].num_qubits == 2),
)

Output:

The optimized circuit has 2Q gates depth:  50

Cette profondeur est considérablement réduite par rapport au test de Hadamard original. Cette profondeur est gérable par les ordinateurs quantiques modernes, bien qu'elle soit encore assez élevée. Nous devrons utiliser des techniques de pointe pour atténuer les erreurs afin d'obtenir des résultats utiles.

Sélectionner un backend sur lequel exécuter notre calcul de Krylov quantique, de sorte que nous puissions transpiler notre circuit pour l'exécuter sur cet ordinateur quantique.

# Use the least-busy backend or specify a quantum computer using the syntax commented out below.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Or you may choose a specify backend and channel if necessary for your workflow.
# service = QiskitRuntimeService(channel="ibm_quantum_platform")
# backend = service.backend("ibm_fez")

Nous transposons maintenant nos circuits et nos opérateurs.

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
basis_gates = list(target.operation_names)
pm = generate_preset_pass_manager(
    optimization_level=3, backend=backend, basis_gates=basis_gates
)

qc_trans = pm.run(qc)
print(qc_trans.depth(lambda x: x[0].num_qubits == 2))
print(qc_trans.count_ops())
qc_trans.draw("mpl", fold=-1, idle_wires=False, scale=0.5)

Output:

36
OrderedDict([('rz', 410), ('sx', 361), ('cz', 156), ('x', 18), ('barrier', 6)])
Output of the previous code cell

Après optimisation, notre profondeur de deux qubits transposée est encore réduite.

4.3 Étape 3. Exécuter à l'aide d'une primitive « IBM Quantum »

Nous créons maintenant des PUBs pour l'exécution avec l'Estimator.

# Define observables to measure for S
observable_S_real = "I" * (n_qubits) + "X"
observable_S_imag = "I" * (n_qubits) + "Y"

observable_op_real = SparsePauliOp(
    observable_S_real
)  # define a sparse pauli operator for the observable
observable_op_imag = SparsePauliOp(observable_S_imag)

layout = qc_trans.layout  # get layout of transpiled circuit
observable_op_real = observable_op_real.apply_layout(
    layout
)  # apply physical layout to the observable
observable_op_imag = observable_op_imag.apply_layout(layout)
observable_S_real = (
    observable_op_real.paulis.to_labels()
)  # get the label of the physical observable
observable_S_imag = observable_op_imag.paulis.to_labels()

observables_S = [[observable_S_real], [observable_S_imag]]


# Define observables to measure for H
# Hamiltonian terms to measure
observable_list = []
for pauli, coeff in zip(H_op.paulis, H_op.coeffs):
    # print(pauli)
    observable_H_real = pauli[::-1].to_label() + "X"
    observable_H_imag = pauli[::-1].to_label() + "Y"
    observable_list.append([observable_H_real])
    observable_list.append([observable_H_imag])

layout = qc_trans.layout

observable_trans_list = []
for observable in observable_list:
    observable_op = SparsePauliOp(observable)
    observable_op = observable_op.apply_layout(layout)
    observable_trans_list.append([observable_op.paulis.to_labels()])

observables_H = observable_trans_list


# Define a sweep over parameter values
params = np.vstack(parameters).T


# Estimate the expectation value for all combinations of
# observables and parameter values, where the pub result will have
# shape (# observables, # parameter values).
pub = (qc_trans, observables_S + observables_H, params)

Les circuits pour t=0t=0 sont calculables de manière classique. Nous procédons ainsi avant de passer au cas t≠0t\neq 0 en utilisant un ordinateur quantique.

from qiskit.quantum_info import StabilizerState, Pauli


qc_cliff = qc.assign_parameters({t: 0})


# Get expectation values from experiment
S_expval_real = StabilizerState(qc_cliff).expectation_value(
    Pauli("I" * (n_qubits) + "X")
)
S_expval_imag = StabilizerState(qc_cliff).expectation_value(
    Pauli("I" * (n_qubits) + "Y")
)

# Get expectation values
S_expval = S_expval_real + 1j * S_expval_imag

H_expval = 0
for obs_idx, (pauli, coeff) in enumerate(zip(H_op.paulis, H_op.coeffs)):
    # Get expectation values from experiment
    expval_real = StabilizerState(qc_cliff).expectation_value(
        Pauli(pauli[::-1].to_label() + "X")
    )
    expval_imag = StabilizerState(qc_cliff).expectation_value(
        Pauli(pauli[::-1].to_label() + "Y")
    )
    expval = expval_real + 1j * expval_imag

    # Fill-in matrix elements
    H_expval += coeff * expval


print(H_expval)

Output:

(10+0j)

Bien que nous ayons pu réduire la profondeur de notre porte par des ordres de grandeur en utilisant le test de Hadamard efficace, la profondeur est encore suffisante pour nécessiter une atténuation des erreurs à la pointe de la technologie. Nous précisons ci-dessous les attributs de l'atténuation utilisée. Toutes les méthodes utilisées sont importantes, mais il convient d'attirer l'attention sur l' amplification probabiliste des erreurs (APE) en particulier. Cette technique puissante s'accompagne d'une importante surcharge quantique. Le calcul effectué ici peut prendre 20 minutes ou plus à exécuter sur un véritable ordinateur quantique. Vous pouvez jouer avec les paramètres ci-dessous pour augmenter ou diminuer la précision et, par conséquent, les frais généraux. Les paramètres par défaut ci-dessous permettent d'obtenir des résultats très fidèles.

# Experiment options
num_randomizations = 300
num_randomizations_learning = 20
max_batch_circuits = 20
shots_per_randomization = 100
learning_pair_depths = [0, 4, 24]
noise_factors = [1, 1.3, 1.6]

# Base option formatting
options = {
    # Builtin resilience settings for ZNE
    "resilience": {
        "measure_mitigation": True,
        "zne_mitigation": True,
        "zne": {"noise_factors": noise_factors},
        # TREX noise learning configuration
        "measure_noise_learning": {
            "num_randomizations": num_randomizations_learning,
            "shots_per_randomization": shots_per_randomization,
        },
        # PEA noise model configuration
        "layer_noise_learning": {
            "max_layers_to_learn": 10,
            "layer_pair_depths": learning_pair_depths,
            "shots_per_randomization": shots_per_randomization,
            "num_randomizations": num_randomizations_learning,
        },
    },
    # Randomization configuration
    "twirling": {
        "num_randomizations": num_randomizations,
        "shots_per_randomization": shots_per_randomization,
        "strategy": "all",
    },
    # Experimental settings for PEA method
    "experimental": {
        # # Just in case, disable any further qiskit transpilation not related to twirling / DD
        # "skip_transpilation": True,
        # Execution configuration
        "execution": {
            "max_pubs_per_batch_job": max_batch_circuits,
            "fast_parametric_update": True,
        },
        # Error Mitigation configuration
        "resilience": {
            # ZNE Configuration
            "zne": {
                "amplifier": "pea",
                "return_all_extrapolated": True,
                "return_unextrapolated": True,
                "extrapolated_noise_factors": [0] + noise_factors,
            }
        },
    },
}

Enfin, nous exécutons les circuits pour S~\tilde{S} et H~\tilde{H} avec Estimator.

# This job required 17 minutes of QPU time to run on a Heron r2 processor. This is only an estimate.
# Your execution time may vary.

with Batch(backend=backend) as batch:
    # Estimator
    estimator = Estimator(mode=batch, options=options)

    job = estimator.run([pub], precision=1)

4.4 Étape 4. Post-traitement et analyse des résultats

Ce que nous avons obtenu de l'ordinateur quantique, ce sont les éléments individuels de la matrice de S~\tilde{S} et les groupes de Pauli commutés qui composent les éléments de la matrice de H~\tilde{H}. Ces termes doivent être combinés pour récupérer nos matrices, afin que nous puissions résoudre le problème généralisé des valeurs propres.

# Store the outputs as 'results'.
results = job.result()[0]

Calculer les matrices hamiltoniennes et de chevauchement effectives

Calculer d'abord la phase accumulée par l'état ∣0⟩\vert 0 \rangle au cours de l'évolution temporelle incontrôlée

prefactors = [
    np.exp(-1j * sum([c for p, c in H_op.to_list() if "Z" in p]) * i * dt)
    for i in range(1, krylov_dim)
]

Une fois que nous avons les résultats de l'exécution des circuits, nous pouvons post-traiter les données pour calculer les éléments de la matrice de SS

# Assemble S, the overlap matrix of dimension D:
S_first_row = np.zeros(krylov_dim, dtype=complex)
S_first_row[0] = 1 + 0j

# Add in ancilla-only measurements:
for i in range(krylov_dim - 1):
    # Get expectation values from experiment
    expval_real = results.data.evs[0][0][i]  # automatic extrapolated evs if ZNE is used
    expval_imag = results.data.evs[1][0][i]  # automatic extrapolated evs if ZNE is used

    # Get expectation values
    expval = expval_real + 1j * expval_imag
    S_first_row[i + 1] += prefactors[i] * expval

S_first_row_list = S_first_row.tolist()  # for saving purposes


S_circ = np.zeros((krylov_dim, krylov_dim), dtype=complex)

# Distribute entries from first row across matrix:
for i, j in it.product(range(krylov_dim), repeat=2):
    if i >= j:
        S_circ[j, i] = S_first_row[i - j]
    else:
        S_circ[j, i] = np.conj(S_first_row[j - i])
from sympy import Matrix

Matrix(S_circ)

Output:

[1.00.149322296177984−0.283023058106896i0.185815978760175−0.0910521940394691i0.0940509850777074−0.094154537369141i0.149322296177984+0.283023058106896i1.00.149322296177984−0.283023058106896i0.185815978760175−0.0910521940394691i0.185815978760175+0.0910521940394691i0.149322296177984+0.283023058106896i1.00.149322296177984−0.283023058106896i0.0940509850777074+0.094154537369141i0.185815978760175+0.0910521940394691i0.149322296177984+0.283023058106896i1.0]\displaystyle \left[\begin{matrix}1.0 & 0.149322296177984 - 0.283023058106896 i & 0.185815978760175 - 0.0910521940394691 i & 0.0940509850777074 - 0.094154537369141 i\\0.149322296177984 + 0.283023058106896 i & 1.0 & 0.149322296177984 - 0.283023058106896 i & 0.185815978760175 - 0.0910521940394691 i\\0.185815978760175 + 0.0910521940394691 i & 0.149322296177984 + 0.283023058106896 i & 1.0 & 0.149322296177984 - 0.283023058106896 i\\0.0940509850777074 + 0.094154537369141 i & 0.185815978760175 + 0.0910521940394691 i & 0.149322296177984 + 0.283023058106896 i & 1.0\end{matrix}\right]

Et les éléments de la matrice de H~\tilde{H}

import itertools

# Assemble S, the overlap matrix of dimension D:
H_first_row = np.zeros(krylov_dim, dtype=complex)
H_first_row[0] = H_expval

for obs_idx, (pauli, coeff) in enumerate(zip(H_op.paulis, H_op.coeffs)):
    # Add in ancilla-only measurements:
    for i in range(krylov_dim - 1):
        # Get expectation values from experiment
        expval_real = results.data.evs[2 + 2 * obs_idx][0][
            i
        ]  # automatic extrapolated evs if ZNE is used
        expval_imag = results.data.evs[2 + 2 * obs_idx + 1][0][
            i
        ]  # automatic extrapolated evs if ZNE is used

        # Get expectation values
        expval = expval_real + 1j * expval_imag
        H_first_row[i + 1] += prefactors[i] * coeff * expval

H_first_row_list = H_first_row.tolist()

H_eff_circ = np.zeros((krylov_dim, krylov_dim), dtype=complex)

# Distribute entries from first row across matrix:
for i, j in itertools.product(range(krylov_dim), repeat=2):
    if i >= j:
        H_eff_circ[j, i] = H_first_row[i - j]
    else:
        H_eff_circ[j, i] = np.conj(H_first_row[j - i])
from sympy import Matrix

Matrix(H_eff_circ)

Output:

[10.0−3.02044405310714−2.80721615865252i0.496487054782717+0.188101957039621i1.0770511571923+0.104340737159455i−3.02044405310714+2.80721615865252i10.0−3.02044405310714−2.80721615865252i0.496487054782717+0.188101957039621i0.496487054782717−0.188101957039621i−3.02044405310714+2.80721615865252i10.0−3.02044405310714−2.80721615865252i1.0770511571923−0.104340737159455i0.496487054782717−0.188101957039621i−3.02044405310714+2.80721615865252i10.0]\displaystyle \left[\begin{matrix}10.0 & -3.02044405310714 - 2.80721615865252 i & 0.496487054782717 + 0.188101957039621 i & 1.0770511571923 + 0.104340737159455 i\\-3.02044405310714 + 2.80721615865252 i & 10.0 & -3.02044405310714 - 2.80721615865252 i & 0.496487054782717 + 0.188101957039621 i\\0.496487054782717 - 0.188101957039621 i & -3.02044405310714 + 2.80721615865252 i & 10.0 & -3.02044405310714 - 2.80721615865252 i\\1.0770511571923 - 0.104340737159455 i & 0.496487054782717 - 0.188101957039621 i & -3.02044405310714 + 2.80721615865252 i & 10.0\end{matrix}\right]

Enfin, nous pouvons résoudre le problème des valeurs propres généralisées pour H~\tilde{H} :

H~c⃗=cSc⃗\tilde{H} \vec{c} = c S \vec{c}

et obtenir une estimation de l'énergie de l'état fondamental cminc_{min}

gnd_en_circ_est_list = []
for d in range(1, krylov_dim + 1):
    # Solve generalized eigenvalue problem
    gnd_en_circ_est = solve_regularized_gen_eig(
        H_eff_circ[:d, :d], S_circ[:d, :d], threshold=1e-1
    )
    gnd_en_circ_est_list.append(gnd_en_circ_est)
    print("The estimated ground state energy is: ", gnd_en_circ_est)

Output:

The estimated ground state energy is:  10.0
The estimated ground state energy is:  5.933953916292923
The estimated ground state energy is:  4.4101773995740645
The estimated ground state energy is:  3.921288588521255

Pour un secteur à une seule particule, nous pouvons calculer efficacement l'état fondamental de ce secteur de l'hamiltonien de manière classique

gs_en = single_particle_gs(H_op, n_qubits)

Output:

n_sys_qubits 10
n_exc 1 , subspace dimension 11
single particle ground state energy:  2.391547869638771
len(H_op)

Output:

27
plt.plot(
    range(1, krylov_dim + 1),
    gnd_en_circ_est_list,
    color="blue",
    linestyle="-.",
    label="KQD estimate",
)
plt.plot(
    range(1, krylov_dim + 1),
    [gs_en] * krylov_dim,
    color="red",
    linestyle="-",
    label="exact",
)
plt.xticks(range(1, krylov_dim + 1), range(1, krylov_dim + 1))
plt.legend()
plt.xlabel("Krylov space dimension")
plt.ylabel("Energy")
plt.title("Estimating Ground state energy with Krylov Quantum Diagonalization")
plt.show()

Output:

Output of the previous code cell

5. Discussion et prolongement

Pour récapituler, nous partons d'un état de référence, puis nous le faisons évoluer pendant différentes périodes de temps pour générer le sous-espace de Krylov unitaire. Nous projetons notre hamiltonien sur ce sous-espace. Nous estimons également les chevauchements des vecteurs du sous-espace. Enfin, nous résolvons classiquement le problème des valeurs propres généralisées de dimension inférieure.

Aperçu de l'organigramme de la QKD : commencer par un état de référence, faire évoluer l'état vers des vecteurs de Krylov approximatifs, projeter dans le sous-espace de Krylov, diagonaliser le sous-espace projeté de manière classique, et déterminer les propriétés de l'état fondamental.

Comparons ce qui détermine les coûts de calcul de l'utilisation de la technique de Krylov par la méthode classique et par la méthode de la mécanique quantique. Il n'existe pas d'analogie parfaite entre les approches classiques et quantiques pour toutes les étapes. Ce tableau présente une graduation des différentes étapes à prendre en considération.

Un tableau décrivant la mise à l'échelle de différents processus de manière classique et dans l'approche quantique des méthodes de Krylov. Certaines étapes quantiques n'ont pas d'analogue. Les échelles sont les mêmes que celles indiquées dans le texte.

Rappelons que les hamiltoniens comportent généralement des termes qui ne peuvent pas être mesurés simultanément (car ils ne commutent pas entre eux). Nous classons les termes de l'hamiltonien en groupes d'opérateurs de Pauli commutatifs qui peuvent tous être mesurés simultanément, et il peut s'avérer nécessaire de recourir à de nombreux groupes de ce type pour rendre compte de tous les termes qui ne commutent pas entre eux. Pour générer une « H~\tilde{H} » sur un ordinateur quantique, il faut effectuer des mesures distinctes pour chaque groupe de chaînes de Pauli commutatives dans l'hamiltonien, et chacune de ces mesures nécessite de nombreux essais. Nous devons effectuer cette opération pour r2r^2 éléments de matrice différents, correspondant à r2r^2 combinaisons de facteurs d'évolution temporelle différents. Il existe parfois des moyens de réduire ce temps de calcul, mais dans cette approche approximative, le temps nécessaire évolue selon la loi Nshots×NGCP×r2N_\text{shots}\times N_\text{GCP} \times r^2. Les éléments de SS doivent être estimés, ce qui évolue selon la loi O(Nshots×r2)O(N_\text{shots}\times r^2). Enfin, la résolution du problème des valeurs propres généralisées dans l’espace projeté nécessite, de manière classique, un temps de calcul de l’ordre de O(r3)O(r^3).

Nous voyons que la diagonalisation de Krylov quantique peut être utile dans les cas où le nombre de groupes de Pauli commutés dans l'hamiltonien est relativement faible. Ces dépendances d'échelle suggèrent certaines applications pour lesquelles la méthode de Krylov peut être utile, et d'autres pour lesquelles elle ne le sera probablement pas. Certains hamiltoniens sont très complexes lorsqu'ils sont mis en correspondance avec des qubits, car ils impliquent de nombreuses chaînes de Pauli non commutatives qui ne peuvent pas être facilement divisées en quelques groupes commutatifs. C'est souvent le cas pour les problèmes de chimie quantique, par exemple. Cette complexité présente deux défis majeurs pour les ordinateurs quantiques à court terme :

  • L'estimation de chaque élément de H~\tilde{H} devient très coûteuse en raison du grand nombre de termes.
  • Les circuits de Trotter nécessaires deviennent d'une profondeur prohibitive.

Ces deux points seront moins problématiques lorsque les ordinateurs quantiques atteindront la tolérance aux pannes, mais ils doivent être pris en compte à court terme. Même les systèmes dont les mappings sont plus "simples" que ceux de la chimie quantique peuvent rencontrer les mêmes obstacles si les hamiltoniens comportent trop de termes non commutatifs. La méthode de Krylov est la plus utile lorsque l'hamiltonien peut être divisé en un nombre relativement restreint de groupes de Pauli commutés et lorsque HH est facile à mettre en œuvre dans les circuits de trotteur. Ces deux conditions sont remplies, par exemple, pour de nombreux modèles de treillis intéressants en physique. La KQD est particulièrement utile lorsque l'on sait très peu de choses sur l'état fondamental. Cela s'explique par les garanties de convergence inhérentes à cette méthode et par son applicabilité dans des scénarios où les autres méthodes ne sont pas viables en raison d'une connaissance insuffisante de l'état du sol.

Bien que la KQD soit un outil puissant, les aspects du protocole qui prennent du temps, en particulier l'estimation de chaque élément de l'hamiltonien projeté et le chevauchement des états de Krylov, représentent des possibilités d'amélioration. Une autre approche consiste à exploiter les méthodes de Krylov en conjonction avec les méthodes basées sur l'échantillonnage, qui font l'objet de la leçon suivante.


6. Annexes

Annexe I : Sous-espace de Krylov issu d'évolutions en temps réel

L'espace de Krylov unitaire est défini comme suit

KU(H,∣ψ⟩)=span{∣ψ⟩,e−iH dt∣ψ⟩,…,e−irH dt∣ψ⟩}\mathcal{K}_U(H, |\psi\rangle) = \text{span}\left\{ |\psi\rangle, e^{-iH\,dt} |\psi\rangle, \dots, e^{-irH\,dt} |\psi\rangle \right\}

pour un certain pas de temps dtdt que nous déterminerons plus tard. Supposons temporairement que rr est pair : définissons alors d=r/2d=r/2. Remarquez que lorsque nous projetons l'hamiltonien dans l'espace de Krylov ci-dessus, il est indiscernable de l'espace de Krylov

KU(H,∣ψ⟩)=span{ei d H dt∣ψ⟩,ei(d−1)H dt∣ψ⟩,…,e−i(d−1)H dt∣ψ⟩,e−i d H dt∣ψ⟩},\mathcal{K}_U(H, |\psi\rangle) = \text{span}\left\{ e^{i\,d\,H\,dt}|\psi\rangle, e^{i(d-1)H\,dt} |\psi\rangle, \dots, e^{-i(d-1)H\,dt} |\psi\rangle, e^{-i\,d\,H\,dt} |\psi\rangle \right\},

c'est-à-dire lorsque toutes les évolutions temporelles sont décalées vers l'arrière de dd pas de temps. La raison pour laquelle il n'est pas possible de les distinguer est que les éléments de la matrice

H~j,k=⟨ψ∣ei j H dtHe−i k H dt∣ψ⟩=⟨ψ∣Hei(j−k)H dt∣ψ⟩\tilde{H}_{j,k} = \langle\psi|e^{i\,j\,H\,dt}He^{-i\,k\,H\,dt}|\psi\rangle=\langle\psi|He^{i(j-k)H\,dt}|\psi\rangle

sont invariants en cas de décalage global du temps d'évolution, puisque les évolutions temporelles commutent avec l'hamiltonien. Pour les rr impairs, nous pouvons utiliser l'analyse pour les r−1r-1.

Nous voulons montrer que quelque part dans cet espace de Krylov, il est garanti qu'il existe un état de basse énergie. Nous le faisons au moyen du résultat suivant, qui est dérivé du théorème 3.1 dans [3] :

Affirmation 1 : il existe une fonction ff telle que pour les énergies EE dans le domaine spectral de l'hamiltonien (c'est-à-dire entre l'énergie de l'état fondamental et l'énergie maximale),...

  1. f(E0)=1f(E_0)=1
  2. ∣f(E)∣≤2(1+δ)−d|f(E)|\le2\left(1 + \delta\right)^{-d} pour toutes les valeurs de EE qui se situent à ≥δ\ge\delta de E0E_0, c'est-à-dire qu'elle est exponentiellement supprimée
  3. f(E)f(E) est une combinaison linéaire de eijE dte^{ijE\,dt} pour j=−d,−d+1,...,d−1,dj=-d,-d+1,...,d-1,d

Nous donnons une preuve ci-dessous, mais elle peut être ignorée sans risque, à moins que l'on ne veuille comprendre l'argument complet et rigoureux. Pour l'instant, nous nous concentrons sur les implications de l'affirmation ci-dessus. En vertu de la propriété 3 ci-dessus, nous pouvons voir que l'espace de Krylov décalé ci-dessus contient l'état f(H)∣ψ⟩f(H)|\psi\rangle. Il s'agit de notre état de basse énergie. Pour comprendre pourquoi, il faut écrire ∣ψ⟩|\psi\rangle dans la base propre de l'énergie :

∣ψ⟩=∑k=0Nγk∣Ek⟩,|\psi\rangle = \sum_{k=0}^{N}\gamma_k|E_k\rangle,

où ∣Ek⟩|E_k\rangle est le kème état propre énergétique et γk\gamma_k est son amplitude dans l'état initial ∣ψ⟩|\psi\rangle. Exprimé en termes de ceci, f(H)∣ψ⟩f(H)|\psi\rangle est donné par

f(H)∣ψ⟩=∑k=0Nγkf(Ek)∣Ek⟩,f(H)|\psi\rangle = \sum_{k=0}^{N}\gamma_kf(E_k)|E_k\rangle,

en utilisant le fait que l'on peut remplacer HH par EkE_k lorsqu'il agit sur l'état propre ∣Ek⟩|E_k\rangle. L'erreur énergétique de cet état est donc

energy error=⟨ψ∣f(H)(H−E0)f(H)∣ψ⟩⟨ψ∣f(H)2∣ψ⟩\text{energy error} = \frac{\langle\psi|f(H)(H-E_0)f(H)|\psi\rangle}{\langle\psi|f(H)^2|\psi\rangle} =∑k=0N∣γk∣2f(Ek)2(Ek−E0)∑k=0N∣γk∣2f(Ek)2.= \frac{\sum_{k=0}^{N}|\gamma_k|^2f(E_k)^2(E_k-E_0)}{\sum_{k=0}^{N}|\gamma_k|^2f(E_k)^2}.

Pour transformer ceci en une borne supérieure plus facile à comprendre, nous séparons d'abord la somme du numérateur en termes avec Ek−E0≤δE_k-E_0\le\delta et en termes avec Ek−E0>δE_k-E_0>\delta :

energy error=∑Ek≤E0+δ∣γk∣2f(Ek)2(Ek−E0)∑k=0N∣γk∣2f(Ek)2+∑Ek>E0+δ∣γk∣2f(Ek)2(Ek−E0)∑k=0N∣γk∣2f(Ek)2.\text{energy error} = \frac{\sum_{E_k\le E_0+\delta}|\gamma_k|^2f(E_k)^2(E_k-E_0)}{\sum_{k=0}^{N}|\gamma_k|^2f(E_k)^2} + \frac{\sum_{E_k> E_0+\delta}|\gamma_k|^2f(E_k)^2(E_k-E_0)}{\sum_{k=0}^{N}|\gamma_k|^2f(E_k)^2}.

Nous pouvons limiter le premier terme par δ\delta,

∑Ek≤E0+δ∣γk∣2f(Ek)2(Ek−E0)∑k=0N∣γk∣2f(Ek)2<δ∑Ek≤E0+δ∣γk∣2f(Ek)2∑k=0N∣γk∣2f(Ek)2≤δ,\frac{\sum_{E_k\le E_0+\delta}|\gamma_k|^2f(E_k)^2(E_k-E_0)}{\sum_{k=0}^{N}|\gamma_k|^2f(E_k)^2} < \frac{\delta\sum_{E_k\le E_0+\delta}|\gamma_k|^2f(E_k)^2}{\sum_{k=0}^{N}|\gamma_k|^2f(E_k)^2} \le \delta,

où la première étape suit parce que Ek−E0≤δE_k-E_0\le\delta pour chaque EkE_k dans la somme, et la deuxième étape suit parce que la somme dans le numérateur est un sous-ensemble de la somme dans le dénominateur. Pour le second terme, on commence par abaisser le dénominateur par ∣γ0∣2|\gamma_0|^2, puisque f(E0)2=1f(E_0)^2=1 : en additionnant le tout, on obtient

energy error≤δ+1∣γ0∣2∑Ek>E0+δ∣γk∣2f(Ek)2(Ek−E0).\text{energy error} \le \delta + \frac{1}{|\gamma_0|^2}\sum_{E_k>E_0+\delta}|\gamma_k|^2f(E_k)^2(E_k-E_0).

Pour simplifier ce qui reste, remarquez que pour tous ces EkE_k, par la définition de ff nous savons que f(Ek)2≤4(1+δ)−2df(E_k)^2 \le 4\left(1 + \delta\right)^{-2d}. De plus, la borne supérieure de Ek−E0<2∥H∥E_k-E_0<2\|H\| et la borne supérieure de ∑Ek>E0+δ∣γk∣2<1\sum_{E_k>E_0+\delta}|\gamma_k|^2<1 donnent

energy error≤δ+8∣γ0∣2∥H∥(1+δ)−2d.\text{energy error} \le \delta + \frac{8}{|\gamma_0|^2}\|H\|\left(1 + \delta\right)^{-2d}.

Ceci est valable pour n'importe quel δ>0\delta>0, donc si nous fixons δ\delta égal à notre erreur cible, alors la limite d'erreur ci-dessus converge vers celle-ci de manière exponentielle avec la dimension de Krylov 2d=r2d=r. Notez également que si δ<E1−E0\delta<E_1-E_0, le terme δ\delta disparaît entièrement dans la limite ci-dessus.

Pour compléter l'argument, nous notons tout d'abord que ce qui précède n'est que l'erreur énergétique de l'état particulier f(H)∣ψ⟩f(H)|\psi\rangle, plutôt que l'erreur énergétique de l'état de plus faible énergie dans l'espace de Krylov. Toutefois, en vertu du principe variationnel (Rayleigh-Ritz), l'erreur énergétique de l'état de plus faible énergie dans l'espace de Krylov est limitée par l'erreur énergétique de tout état dans l'espace de Krylov, de sorte que ce qui précède est également une limite supérieure de l'erreur énergétique de l'état de plus faible énergie, c'est-à-dire la sortie de l'algorithme de diagonalisation quantique de Krylov.

Il est possible d'effectuer une analyse similaire à la précédente en tenant compte du bruit et de la procédure de seuillage décrite dans le manuel. Voir [2] et [4] pour cette analyse.

Annexe II : preuve de la revendication 1

Ce qui suit est en grande partie dérivé de [3], Théorème 3.1: Soit 0<a<b0 < a < b et Πd∗\Pi^*_d l'espace des polynômes résiduels (polynômes dont la valeur en 0 est 1) de degré au plus dd. La solution de

β(a,b,d)=min⁡p∈Πd∗max⁡x∈[a,b]∣p(x)∣\beta(a, b, d) = \min_{p \in \Pi^*_d} \max_{x \in [a, b]} |p(x)| \quad

est

p∗(x)=Td(b+a−2xb−a)Td(b+ab−a),p^*(x) = \frac{T_d\left(\frac{b + a - 2x}{b - a}\right)}{T_d\left(\frac{b + a}{b - a}\right)}, \quad

et la valeur minimale correspondante est

β(a,b,d)=Td−1(b+ab−a).\beta(a, b, d) = T_d^{-1}\left(\frac{b + a}{b - a}\right).

Nous voulons convertir cette fonction en une fonction qui peut être exprimée naturellement en termes d'exponentielles complexes, car ce sont les évolutions temporelles réelles qui génèrent l'espace de Krylov quantique. Pour ce faire, il est commode d'introduire la transformation suivante des énergies dans le domaine spectral de l'hamiltonien en nombres dans l'intervalle [0,1][0,1] : définir

g(E)=1−cos⁡((E−E0)dt)2,g(E) = \frac{1-\cos\big((E-E_0)dt\big)}{2},

où dtdt est un pas de temps tel que −π<E0dt<Emaxdt<π-\pi < E_0dt < E_\text{max}dt < \pi. Remarquez que g(E0)=0g(E_0)=0 et g(E)g(E) croissent au fur et à mesure que EE s'éloigne de E0E_0.

En utilisant maintenant le polynôme p∗(x)p^*(x) avec les paramètres a, b, d fixés à a=g(E0+δ)a = g(E_0 + \delta), b=1b = 1, et d = int( r/2 ), nous définissons la fonction :

f(E)=p∗(g(E))=Td(1+2cos⁡((E−E0)dt)−cos⁡(δ dt)1+cos⁡(δ dt))Td(1+21−cos⁡(δ dt)1+cos⁡(δ dt))f(E) = p^* \left( g(E) \right) = \frac{T_d\left(1 + 2\frac{\cos\big((E-E_0)dt\big) - \cos\big(\delta\,dt\big)}{1 +\cos\big(\delta\,dt\big)}\right)}{T_d\left(1 + 2\frac{1-\cos\big(\delta\,dt\big)}{1 + \cos\big(\delta\,dt\big)}\right)}

où E0E_0 est l'énergie de l'état fondamental. Nous pouvons voir en insérant cos⁡(x)=eix+e−ix2\cos(x)=\frac{e^{ix}+e^{-ix}}{2} que f(E)f(E) est un polynôme trigonométrique de degré dd, c'est-à-dire une combinaison linéaire de eijE dte^{ijE\,dt} pour j=−d,−d+1,...,d−1,dj=-d,-d+1,...,d-1,d. De plus, d'après la définition de p∗(x)p^*(x) ci-dessus, nous avons que f(E0)=p(0)=1f(E_0)=p(0)=1 et pour tout EE dans le domaine spectral tel que ∣E−E0∣>δ\vert E-E_0 \vert > \delta nous avons

∣f(E)∣≤β(a,b,d)=Td−1(1+21−cos⁡(δ dt)1+cos⁡(δ dt))|f(E)| \le \beta(a, b, d) = T_d^{-1}\left(1 + 2\frac{1-\cos\big(\delta\,dt\big)}{1 + \cos\big(\delta\,dt\big)}\right) ≤2(1+δ)−d=2(1+δ)−⌊k/2⌋.\leq 2\left(1 + \delta\right)^{-d} = 2\left(1 + \delta\right)^{-\lfloor k/2\rfloor}.

Références :

[1] https://arxiv.org/abs/2407.14431

[2] https://arxiv.org/abs/1811.09025

[3] https://people.math.ethz.ch/~mhg/pub/biksm.pdf

[4] https://academic.oup.com/book/36426

[5] https://en.wikipedia.org/wiki/Krylov_sous-espace

[6] Méthodes du sous-espace de Krylov : Principes et analyse, Jörg Liesen, Zdenek Strakos https://academic.oup.com/book/36426

[7] Iterative Methods for Sparse Linear Systems" par Yousef Saad

[8] "MINRES-QLP : A Krylov Subspace Method for Indefinite or Singular Symmetric Systems" par Sou-Cheng Choi, Christopher Paige, et Michael Saunders ( https://epubs.siam.org/doi/10.1137/100787921 )

[9] Ethan N. Epperly, Lin Lin et Yuji Nakatsukasa. "Une théorie de la diagonalisation du sous-espace quantique". SIAM Journal on Matrix Analysis and Applications 43, 1263-1290 (2022).

[10] https://link.aps.org/doi/10.1103/PRXQuantum.4.030319

Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.