[PYTHON] Suivez le flux de QAOA (VQE) au niveau du code source de Blueqat

QAOA et VQE

QAOA (Quantum Approximate Optimization Algorithm) est un algorithme qui optimise le modèle de ging à l'aide d'un ordinateur quantique de type porte quantique. De plus, VQE (Variational Quantum Eigensolver) est un algorithme qui trouve les valeurs propres d'une matrice à l'aide d'un ordinateur quantique de type porte quantique, et est souvent utilisé pour les calculs de chimie quantique.

Ces dernières années, le développement de QAOA et VQE a été activement encouragé car il fonctionne raisonnablement bien même sur un ordinateur quantique sans correction d'erreur.

Au niveau des bibliothèques informatiques quantiques, QAOA est souvent traité comme un type de VQE, et Blueqat traite également QAOA comme un type de VQE.

Le problème que vous souhaitez résoudre avec VQE / QAOA

Étant donné une matrice $ \ hat H $ appelée hamiltonien. Pour cette matrice, $ \ boldsymbol {X, qui est un vecteur de norme 1 et a le plus petit $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ (où $ \ cdot $ est le produit intérieur) VQE / QAOA peut résoudre le problème de la valeur de $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ lors de la recherche de} $. Selon la forme de l'hamiltonien et le but de la résolution du problème, on l'appelle QAOA ou VQE.

De plus, $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ est également appelé "énergie". En effet, en mécanique quantique, cela correspond en fait à l'équation de l'énergie.

Si cela peut être résolu efficacement

Il existe des applications telles que.

Écoulement approximatif de VQE

Les ordinateurs quantiques sont bons pour créer d'énormes matrices, les multiplier par des vecteurs appelés bits quantiques et échantillonner des chaînes de bits en fonction de la distribution de probabilité résultante.

Un ordinateur quantique est à peu près un appareil qui exploite un «circuit quantique» réalisé en combinant des portes quantiques. Si vous passez un circuit quantique, il échantillonnera la chaîne de bits.

Puisque $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ peut être obtenu à partir du résultat d'échantillonnage de la chaîne de bits, passez le circuit quantique à l'ordinateur quantique en changeant petit à petit le circuit quantique, puis $ \ Trouvez un circuit quantique qui minimise boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $.

Si vous le voulez

-Valeur minimale de $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ -Distribution de probabilité du résultat de la mesure (chaîne de bits) de $ \ boldsymbol {X} $ telle que $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ est minimisée

Peut être obtenu.

Tout en changeant petit à petit le circuit quantique?

Certaines portes quantiques correspondent à l'opération "rotation des bits quantiques". En ayant l'angle de rotation comme paramètre, il est possible de créer un circuit quantique en fonction du paramètre.

Puisque l'angle n'est qu'une valeur à virgule flottante, Paramètres (type à virgule flottante) → Circuit quantique → Résultat d'échantillonnage de chaîne de bits → Énergie (type à virgule flottante) Vous pouvez le considérer comme une "fonction qui renvoie un type à virgule flottante si vous lui donnez un type à virgule flottante".

En minimisant cette fonction, vous obtiendrez le résultat souhaité. Souvent, «scipy.optimize.minimize» est utilisé pour ces optimisations. Dans certains cas, l'optimisation bayésienne, etc. peut être utilisée.

Circonstances propres au simulateur informatique quantique

Dans la machine réelle de l'ordinateur quantique, la chaîne de bits a été obtenue par échantillonnage (en calculant le même circuit quantique plusieurs fois et en prenant le résultat plusieurs fois). En effet, l'état interne de l'ordinateur quantique (parfois appelé vecteur d'état, fonction d'onde, etc.) ne peut pas être extrait tel quel.

D'autre part, dans le cas du simulateur, puisque l'état interne est stocké sous forme de tableau, il peut être extrait tel quel, et la distribution de probabilité de la chaîne de bits peut être obtenue plus efficacement que de calculer le même circuit quantique plusieurs fois.

Lors de la lecture des articles VQE et QAOA, il est très important de se demander s'il s'agit d'un simulateur ou d'une machine réelle, car cela affecte non seulement la vitesse de calcul, mais également la précision du calcul.

Essayez de faire une image

En d'autres termes, c'est ce que c'est. vqe.svg.png

Ecrire avec Blueqat

Dans QAOA, l'hamiltonien est décrit en utilisant uniquement ce que l'on appelle l'interaction Z-ZZ, similaire au modèle d'Ising résolu par recuit quantique.

Considérons q (0) ―― 2 * q (1) ―― 3 * q (0) * q (1) comme un simple QUBO. Soit «q (0)» et «q (1)» les bits quantiques, et lorsqu'une des valeurs 0 et 1 est prise, quelle combinaison est utilisée pour minimiser cette équation. S'il s'agit de 2 variables, vous pouvez le frapper à la main,

q(0) q(1) q(0) - 2 * q(1) - 3 * q(0) * q(1)
0 0 0 - 20 - 30*0 = 0
1 0 1 - 20 - 31*0 = 1
0 1 0 - 21 - 30*1 = -2
1 1 1 - 21 - 31*1 = -4

Par conséquent, la valeur minimale est prise à (1, 1). Pour demander ça

from blueqat.pauli import qubo_bit as q
from blueqat.vqe import Vqe, QaoaAnsatz

h = q(0) - 2 * q(1) - 3 * q(0) * q(1)

ansatz = QaoaAnsatz(h, 4) #Le deuxième argument est de combien augmenter les paramètres et les circuits. Plus vous en avez, plus la probabilité de résolution est élevée, mais la résolution prend du temps
runner = Vqe(ansatz)
result = runner.run()
print(result.most_common())

Et le résultat est

(((1, 1), 0.944590105656669),)

Et (1, 1) a été obtenu avec une probabilité de 94% ou plus.

Lire la source

qubo_bit Omettez la docstring. qubo_bit est exactement comme ça.

def qubo_bit(n):
    return 0.5 - 0.5*Z[n]

Il s'agit d'une réécriture de ce qui a été écrit dans les bits de QUBO ($ q_i \ in \ {0, 1 \} ) dans le modèle ascendant ( \ sigma_i \ in \ {\ pm 1 \} $). Je suis juste là. Il est calculé de telle sorte que $ \ sigma_i = 1 $ lorsque $ q_i = 0 $ et $ \ sigma_i = -1 $ lorsque $ q_i = 1 $.

Z est défini comme désordonné dans blueqat.pauli, mais lors de son utilisation pour VQE ou QAOA,

--Le «Z [i]» est utilisé tel quel, ou il est multiplié par un coefficient ou autre «Z [i]» pour en faire un type «Term».

Sera utilisé. Aussi,

C'est devenu une relation.

L'évolution du temps est un calcul très important dans VQE et QAOA. En fait, je serais heureux si je pouvais écrire l'évolution temporelle de l'hamiltonien $ \ hat H $, donc j'aimerais développer le type ʻExpr` au fil du temps, mais il est généralement difficile de l'écrire avec une combinaison de portes, et il s'agit généralement d'un calcul approximatif par l'expansion de Suzuki Trotter, etc. Sera fait. D'autre part, le type "Term", qui consiste uniquement en une multiplication, peut être facilement développé dans le temps en combinant des portes.

QaoaAnsatz.__init__

Ansatz est un mot allemand qui semble être traduit par «temporaire» en japonais, mais il est candidat pour $ \ boldsymbol {X} $ dans $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $. Dans VQE, il est tout à fait possible d'appeler un circuit quantique candidat pour $ \ boldsymbol {X} $ de cette manière. Comme nous le verrons plus tard, la méthode la plus importante de QaoaAnsatz est get_circuit (), qui est responsable de la création de circuits quantiques à partir de paramètres.

class QaoaAnsatz(AnsatzBase):
    def __init__(self, hamiltonian, step=1, init_circuit=None):
        super().__init__(hamiltonian, step * 2)
        self.hamiltonian = hamiltonian.to_expr().simplify()
        if not self.check_hamiltonian():
            raise ValueError("Hamiltonian terms are not commutable")

        self.step = step
        self.n_qubits = self.hamiltonian.max_n() + 1
        if init_circuit:
            self.init_circuit = init_circuit
            if init_circuit.n_qubits > self.n_qubits:
                self.n_qubits = init_circuit.n_qubits
        else:
            self.init_circuit = Circuit(self.n_qubits).h[:]
        self.init_circuit.make_cache()
        self.time_evolutions = [term.get_time_evolution() for term in self.hamiltonian]

#De la classe parente__init__Cliquez ici
class AnsatzBase:
    def __init__(self, hamiltonian, n_params):
        self.hamiltonian = hamiltonian
        self.n_params = n_params
        self.n_qubits = self.hamiltonian.max_n() + 1

Ce qu'il faut passer à la classe parente __init__ est hamiltonian ($ \ hat H $), le nombre de paramètres et le nombre de bits quantiques. Le nombre de paramètres est passé deux fois le nombre d'étapes.

De plus, hamiltonian est forcé de faire correspondre le type avec hamiltonian.to_expr (). Simplify (), et` simplify () ʻest utilisé pour supprimer ou combiner des termes supplémentaires.

check_hamiltonian vérifie s'il s'agit d'un hamiltonien approprié pour QAOA.

En tant que circuit initial, sauf indication contraire, tous les bits quantiques multipliés par «H» sont transmis. Cela équivaut à commencer le recuit à partir de l'état où un champ magnétique latéral est appliqué pour la première fois, comme on l'appelle dans le recuit quantique.

Si vous appelez make_cache (), certains simulateurs effectueront des calculs quantiques jusqu'à ce stade et enregistreront les résultats. À partir de maintenant, je déplacerai le circuit initial avec une porte ajoutée plusieurs fois, de sorte qu'en faisant cela, les calculs inutiles peuvent être réduits. self.time_evolutions = [term.get_time_evolution () for term in self.hamiltonian] extrait le type Term term du type Expr`` hamiltonian pour obtenir une fonction d'évolution temporelle. Je vais.

Vqe.__init__

class Vqe:
    def __init__(self, ansatz, minimizer=None, sampler=None):
        self.ansatz = ansatz
        self.minimizer = minimizer or get_scipy_minimizer(
            method="Powell",
            options={"ftol": 5.0e-2, "xtol": 5.0e-2, "maxiter": 1000}
        )
        self.sampler = sampler or non_sampling_sampler
        self._result = None

Prend trois objets: ʻansatz, minimizer, sampler. Si vous omettez minimizer et sampler, les valeurs par défaut seront utilisées. minimizer est une fonction de minimisation, et par défaut, c'est un wrapping de scipy.optimize.minimize. sampler` est une fonction pour exécuter la machine ou le simulateur réel et obtenir le résultat de l'échantillonnage, et le simulateur est utilisé par défaut.

Si vous les mettez dans la figure précédente, ce sera comme suit. Je l'ai omis car la figure devient compliquée, mais ansatz calcule également l'énergie à partir du résultat de l'échantillonnage. (Parce que nous avons besoin de hamiltonien pour le calcul de l'énergie, nous laissons l'objet qui a hamiltonien le faire)

vqe_mod.svg.png

Vqe.run()

    def run(self, verbose=False):
        objective = self.ansatz.get_objective(self.sampler)
        if verbose:
            def verbose_objective(objective):
                def f(params):
                    val = objective(params)
                    print("params:", params, "val:", val)
                    return val
                return f
            objective = verbose_objective(objective)
        params = self.minimizer(objective, self.ansatz.n_params)
        c = self.ansatz.get_circuit(params)
        return VqeResult(self, params, c)

Si verbeux: Ce qui suit est juste un désordre pour ceux qui veulent voir les paramètres et les changements d'énergie, alors ne vous inquiétez pas trop, si vous l'ignorez

C'est un processus simple.

get_objective

    def get_objective(self, sampler):
        """Get an objective function to be optimized."""
        def objective(params):
            circuit = self.get_circuit(params)
            circuit.make_cache()
            return self.get_energy(circuit, sampler)
        return objective

La fonction objectif est exactement comme sur la figure

--Recevoir le paramètre params et créer un circuit quantique

C'est devenu un flux.

Pour la fonction objectif obtenue de cette manière, les paramètres sont optimisés par minimizer, il s'avère donc que le comportement est vraiment comme indiqué sur la figure.

Résumé

VQE et QAOA ne sont pas des algorithmes compliqués tant que vous pouvez comprendre le flux. Cette fois, j'ai essayé d'écrire dans la figure en lisant la source comment cela fonctionne réellement.

Bonus: problèmes avec le module Blueqat VQE actuel

J'ai fait le module pour déléguer l'autorité à la classe enfant autant que possible afin qu'elle soit aussi faiblement couplée que possible. Cependant, la clé de VQE est "comment optimiser les paramètres", et en particulier dans les calculs chimiques, vous pouvez utiliser les paramètres obtenus à partir de la structure moléculaire comme valeurs initiales, et optimiser en utilisant tout ce que vous pouvez utiliser. Je veux faire.

C'est une idée très incompatible avec la structure actuelle des modules VQE.

Actuellement, «minimizer» ne reçoit aucune information sur la fonction à optimiser, autre que la fonction elle-même et le nombre de paramètres. Le contenu de la fonction est optimisé comme une boîte noire.

Comment puis-je remonter le module pour une meilleure optimisation? (Pour l'instant, au lieu de passer le minimiseur de l'extérieur, je pense hériter de l'objet Vqe et l'utiliser comme méthode.)

Il y a aussi un problème avec l'interaction avec "sampler". Dans l'échantillonneur actuel, on supposait que chaque circuit fonctionnerait, mais en fait, avec IBM Q, plusieurs circuits peuvent être emballés et jetés vers un ordinateur quantique sur le cloud. Dans IBM Q, il est normal que le temps d'attente soit plus long que le temps de calcul, et pouvoir emballer et exécuter plusieurs circuits permet de gagner beaucoup de temps. Alors, comment pouvons-nous faire en sorte que plusieurs circuits puissent être emballés ensemble? (Je viens d'obtenir une liste de circuits, je les lance tous ensemble et je renvoie une liste de résultats, etc.)

Blueqat a beaucoup de soucis concernant le développement logiciel, plutôt que des soucis concernant le calcul quantique merdique. C'est un logiciel open source, donc je recherche quelqu'un pour aider au développement. Si vous avez confiance en vos compétences, veuillez nous en informer.

Recommended Posts

Suivez le flux de QAOA (VQE) au niveau du code source de Blueqat
[Python] Lire le code source de Bottle Part 2
[Python] Lire le code source de Bottle Part 1
Suivez le flux de communication de la connexion de pont de Docker avec nftables
Expliquez le code de Tensorflow_in_ROS
[Python] Lire le code source de Flask
Compter les lignes de code source (SLOC)