Blog

Sortir des sentiers battus en matière de préparations d'État - Utilisation de Classiq pour générer des circuits de distribution log-normaux de profondeur 1 

28
Juillet
,
2022

Cette note illustre comment utiliser la plateforme Classiq pour résoudre le problème de préparation d'état log-normal de notre récent concours de codage. Nous examinons deux méthodes pour générer cette préparation d'état ainsi que l'astuce nécessaire pour générer une préparation d'état avec une profondeur de circuit de 1. 

Étape 1 pour tous les algorithmes quantiques

Les préparations d'état font partie intégrante de l'informatique quantique, presque toutes les applications quantiques commençant par la préparation d'un état dans un registre quantique. En finance, par exemple, l'état peut représenter la distribution des prix de certains actifs dans le cadre d'un algorithme d'optimisation de portefeuille. En chimie, il peut s'agir d'une estimation initiale de l'état fondamental d'une molécule, et dans l'apprentissage automatique quantique, il s'agit du vecteur de caractéristiques à analyser.

La préparation de l'état est l'initialisation des qubits avec des portes quantiques de sorte que leur sortie mesurée corresponde à une distribution de probabilité souhaitée. Cet état initialisé peut ensuite être utilisé par des circuits quantiques ultérieurs pour effectuer des calculs. La préparation de l'état log-normal dont nous allons parler est un état initialisé couramment utilisé dans de nombreux calculs financiers. 

Le problème de la préparation de l'état log-normal

Lors de notre récent concours de codage, les concurrents devaient concevoir un circuit générant une distribution log-normale avec une moyenne (µ) de 0 et un écart-type (σ) de 0,1 en utilisant au maximum 10 qubits. Le circuit doit approximer une distribution log-normale avec une erreur ne dépassant pas 0,01 et ne peut contenir que des portes "u" et "CX". Le gagnant sera le circuit ayant la plus faible profondeur tout en satisfaisant à tous les critères susmentionnés.

Ce problème était à la fois le plus difficile à résoudre et le circuit quantique le plus simple à calculer parmi les quatre problèmes du concours que nous avons conçus. Afin de donner à nos concurrents un indice sur la manière d'aborder ce problème, nous leur avons demandé de soumettre à la fois le circuit quantique et la méthode de discrétisation qu'ils ont employée.

Résoudre les préparations d'état avec Classiq

Pour générer une préparation d'état avec Classiq, nous invoquons la fonction "StatePreparation" et spécifions les probabilités du circuit, le nombre de qubits et la limite supérieure d'erreur. Nous savons que le nombre maximum de qubits est de 10, que nous devons introduire une distribution log-normale et que l'erreur totale du circuit (l'erreur mathématique dans l'approximation d'une distribution log-normale plus l'erreur dans sa traduction en circuit quantique) ne doit pas dépasser 0,01. Une fois ces quelques paramètres définis, la plateforme Classiq implémentera le circuit quantique. C'est aussi simple que cela ; vous trouverez ci-dessous le code pour générer ce circuit en utilisant le SDK Python de Classiq, bien qu'un circuit équivalent puisse être généré avec l'extension Classiq dans Visual Studio Code. 


import classiq
from classiq import ModelDesigner
from classiq.builtin_functions import StatePreparation

# Given variables
TARGET_ERR = 1e-2
SIGMA = 0.1
N_QUBITS = 10

# Calculated probability distribution and error bound
# Set flag to False for unequal partition of the 'x' axis
lognorm_probabilities, _, l2_error_upper_bound, _ = partition(n_qubits=N_QUBITS, flag=True) 

# State preparation parameters
sp_params = StatePreparation(probabilities=lognorm_probabilities, 
                             num_qubits=N_QUBITS, 
                             error_metric={"L2": {"upper_bound": l2_error_upper_bound}})

# Circuit Synthesis
model_designer = ModelDesigner()
model_designer.StatePreparation(params=sp_params)
circuit = model_designer.synthesize()

La clé de la résolution de ce problème réside dans l'approche adoptée pour mettre en œuvre cette distribution. La solution simple et directe à ce problème consiste à sélectionner un sous-ensemble du domaine centré sur la moyenne de la distribution, à répartir uniformément notre discrétisation sur les cases disponibles dans cette zone (avec 10 qubits, nous disposons de210 cases) et à ne pas tenir compte du reste du domaine. Les probabilités dans ces210 cases de notre sous-ensemble de domaine peuvent alors être modifiées pour correspondre à une distribution log-normale. Pour définir notre circuit, il suffit de charger cette fonction de masse de probabilité dans la plate-forme Classiq et de sélectionner notre seuil d'erreur. En suivant cette méthode, la plateforme Classiq (utilisant la version 0.15) a implémenté pour nous un circuit 242-depth. Le circuit interactif ci-dessous peut être trouvé ici.

visualisation interactive

Logo Classiq

Il y a eu une erreur avec le script

L'astuce

Il existe cependant une autre approche. Deux paramètres peuvent être définis lors de la préparation d'un état : les probabilités à charger et la méthode de discrétisation utilisée pour calculer les résultats. La discrétisation de la méthode précédente utilisait un espacement linéaire standard pour sa discrétisation. Pour ce faire, nous avons dû charger des probabilités correspondant à la distribution log-normale souhaitée. 

Que se passerait-il donc si l'on choisissait un espacement de discrétisation non linéaire ? En choisissant intelligemment l'espacement de nos210 cases, nous pouvons mettre en place un circuit dans lequel toutes les probabilités chargées sont identiques. Cela peut rendre difficiles les calculs ultérieurs pour ce circuit quantique, mais cela rendrait la préparation de l'état triviale. Nous pouvons maintenant choisir librement la base de mesure pour nos qubits et les préparer tous avec la même probabilité dans cette base. Si nous choisissons la base $|+\rangle$, par exemple, nous pouvons préparer tous nos qubits avec des portes de Hadamard, ce qui donne un circuit avec une profondeur de 1, vu ci-dessous et disponible ici.

visualisation interactive

Logo Classiq

Nous avons été heureux de constater que les gagnants de ce problème de concours ont été capables d'identifier cette astuce, chacun employant sa propre méthode de sélection de la discrétisation. Ce problème existe pour démontrer qu'il faut plus que des connaissances techniques pour générer des circuits quantiques efficaces ; il faut aussi de la créativité pour générer des circuits quantiques efficaces. Pour générer notre discrétisation, nous définissons deux fonctions : l'une pour calculer l'erreur L2 et l'autre pour générer la discrétisation en tenant compte de l'erreur L2. Notre code est ajouté ci-dessous.


from scipy.stats import lognorm
from scipy.interpolate import interp1d
import numpy as np

# Calcul de l'erreur L2
def l2_error(pmf : np.array, x_grid : np.array, sigma=0.1) :
    pmf = np.array(pmf)
    x_grid = np.array(x_grid)
    assert all(pmf >= 0)
    assert np.isclose(sum(pmf), 1)
    assert all(x_grid >= 0)
    assert all(np.diff(x_grid) > 0)
    assert len(pmf) + 1 == len(x_grid)

    n_point = 2 ** 22
    tail_value = (TARGET_ERR / 100) ** 2
    min_x = lognorm.ppf(tail_value, sigma)
    max_x = lognorm.ppf(1 - tail_value, sigma)
    x_middle = np.linspace(min_x, max_x, n_point)
    x_lower_tail = np.linspace(0, min_x, n_point // 1000)
    x_upper_tail = np.linspace(max_x, x_grid[-1], n_point // 1000) if x_grid[-1] > max_x else np.array([])

    x_approx = np.diff(x_grid) / 2 + x_grid[:-1]
    x_approx = np.concatenate(([x_approx[0]], x_approx, [x_approx[-1]]))
    pdf_approx = pmf / np.diff(x_grid)
    pdf_approx = np.concatenate(([pdf_approx[0]], pdf_approx, [pdf_approx[-1]]))

    fy = interp1d(x_approx, pdf_approx, kind='nearest', assume_sorted=True, fill_value=(0, 0), bounds_error=False)
    x_full = np.concatenate((x_lower_tail[:-1], x_middle, x_upper_tail[1 :]))
    approx_pdf = fy(x_full)

    full_pdf = lognorm.pdf(x_full, sigma)
    dx = np.diff(x_full)
    dx = np.append(dx, 0)

    upper_tail_err_2_approx = lognorm.sf(x_full[-1], sigma)
    main_err_2 = sum((full_pdf - approx_pdf) ** 2 * dx)
    err = (upper_tail_err_2_approx + main_err_2) ** 0.5
    Retourner err

# Calcul de la distribution de probabilité en fonction de la méthode de discrétisation choisie
def partition(n_qubits=10, flag=True) :
    bins = 2 ** n_qubits
    tail_value = (TARGET_ERR / 10) ** 2
    if flag :
        x_discrete = np.linspace(lognorm.ppf(tail_value, SIGMA),
                               lognorm.ppf(1 - tail_value, SIGMA), bins + 1)
    else :
        x_discrete = lognorm.ppf(np.linspace(tail_value, 1 - tail_value, bins + 1), SIGMA)
    pmf = np.diff(lognorm.cdf(x_discrete, SIGMA))
    pmf = pmf / sum(pmf)
    ERR = l2_error(pmf, x_discrete, sigma=SIGMA)
    margin = TARGET_ERR - ERR
    assert margin > 0
    return tuple(pmf), x_discrete, margin, ERR

Pour comparer avec les solutions proposées par les concurrents, voir ici.

Au-delà des distributions log-normales

Classiq rend la création d'une préparation d'état simple. Définissez les probabilités dans lesquelles vous voulez que votre circuit soit initié, et la plateforme s'occupera du reste. Classiq permet une définition flexible des probabilités comme une fonction de masse de probabilité ou un mélange gaussien et fournit de multiples méthodes pour définir l'erreur autorisée pour le circuit, comme KL, L1, L2, la probabilité maximale et la perte de fidélité. Voici un exemple de Classiq utilisé pour implémenter une préparation d'état utilisant des moments gaussiens, et voici un exemple d'algorithme d'analyse de risque de crédit utilisant un moment gaussien pour sa préparation d'état. 

La préparation d'état de Classiq est flexible, facile à programmer et génère automatiquement le circuit désiré, que vous reproduisiez les résultats d'un article académique ou que vous créiez de nouveaux algorithmes quantiques. Comme nous le disons chez Classiq, "définir ce que vous voulez est facile, mais le mettre en œuvre est difficile". Laissez donc la plateforme Classiq mettre en œuvre les circuits que vous avez définis. Les clients de Classiq travaillent à un niveau supérieur. Spécifiez la fonctionnalité souhaitée du circuit ainsi que les contraintes applicables, et la plateforme Classiq trouve automatiquement la bonne implémentation parmi des milliards d'options d'espace de conception.

Planifiez une démonstration en direct de la plateforme Classiq pour la voir en action, ou contactez-nous pour savoir comment vous pouvez créer des circuits quantiques à la pointe de l'industrie en quelques minutes.

Cette note illustre comment utiliser la plateforme Classiq pour résoudre le problème de préparation d'état log-normal de notre récent concours de codage. Nous examinons deux méthodes pour générer cette préparation d'état ainsi que l'astuce nécessaire pour générer une préparation d'état avec une profondeur de circuit de 1. 

Étape 1 pour tous les algorithmes quantiques

Les préparations d'état font partie intégrante de l'informatique quantique, presque toutes les applications quantiques commençant par la préparation d'un état dans un registre quantique. En finance, par exemple, l'état peut représenter la distribution des prix de certains actifs dans le cadre d'un algorithme d'optimisation de portefeuille. En chimie, il peut s'agir d'une estimation initiale de l'état fondamental d'une molécule, et dans l'apprentissage automatique quantique, il s'agit du vecteur de caractéristiques à analyser.

La préparation de l'état est l'initialisation des qubits avec des portes quantiques de sorte que leur sortie mesurée corresponde à une distribution de probabilité souhaitée. Cet état initialisé peut ensuite être utilisé par des circuits quantiques ultérieurs pour effectuer des calculs. La préparation de l'état log-normal dont nous allons parler est un état initialisé couramment utilisé dans de nombreux calculs financiers. 

Le problème de la préparation de l'état log-normal

Lors de notre récent concours de codage, les concurrents devaient concevoir un circuit générant une distribution log-normale avec une moyenne (µ) de 0 et un écart-type (σ) de 0,1 en utilisant au maximum 10 qubits. Le circuit doit approximer une distribution log-normale avec une erreur ne dépassant pas 0,01 et ne peut contenir que des portes "u" et "CX". Le gagnant sera le circuit ayant la plus faible profondeur tout en satisfaisant à tous les critères susmentionnés.

Ce problème était à la fois le plus difficile à résoudre et le circuit quantique le plus simple à calculer parmi les quatre problèmes du concours que nous avons conçus. Afin de donner à nos concurrents un indice sur la manière d'aborder ce problème, nous leur avons demandé de soumettre à la fois le circuit quantique et la méthode de discrétisation qu'ils ont employée.

Résoudre les préparations d'état avec Classiq

Pour générer une préparation d'état avec Classiq, nous invoquons la fonction "StatePreparation" et spécifions les probabilités du circuit, le nombre de qubits et la limite supérieure d'erreur. Nous savons que le nombre maximum de qubits est de 10, que nous devons introduire une distribution log-normale et que l'erreur totale du circuit (l'erreur mathématique dans l'approximation d'une distribution log-normale plus l'erreur dans sa traduction en circuit quantique) ne doit pas dépasser 0,01. Une fois ces quelques paramètres définis, la plateforme Classiq implémentera le circuit quantique. C'est aussi simple que cela ; vous trouverez ci-dessous le code pour générer ce circuit en utilisant le SDK Python de Classiq, bien qu'un circuit équivalent puisse être généré avec l'extension Classiq dans Visual Studio Code. 


import classiq
from classiq import ModelDesigner
from classiq.builtin_functions import StatePreparation

# Given variables
TARGET_ERR = 1e-2
SIGMA = 0.1
N_QUBITS = 10

# Calculated probability distribution and error bound
# Set flag to False for unequal partition of the 'x' axis
lognorm_probabilities, _, l2_error_upper_bound, _ = partition(n_qubits=N_QUBITS, flag=True) 

# State preparation parameters
sp_params = StatePreparation(probabilities=lognorm_probabilities, 
                             num_qubits=N_QUBITS, 
                             error_metric={"L2": {"upper_bound": l2_error_upper_bound}})

# Circuit Synthesis
model_designer = ModelDesigner()
model_designer.StatePreparation(params=sp_params)
circuit = model_designer.synthesize()

La clé de la résolution de ce problème réside dans l'approche adoptée pour mettre en œuvre cette distribution. La solution simple et directe à ce problème consiste à sélectionner un sous-ensemble du domaine centré sur la moyenne de la distribution, à répartir uniformément notre discrétisation sur les cases disponibles dans cette zone (avec 10 qubits, nous disposons de210 cases) et à ne pas tenir compte du reste du domaine. Les probabilités dans ces210 cases de notre sous-ensemble de domaine peuvent alors être modifiées pour correspondre à une distribution log-normale. Pour définir notre circuit, il suffit de charger cette fonction de masse de probabilité dans la plate-forme Classiq et de sélectionner notre seuil d'erreur. En suivant cette méthode, la plateforme Classiq (utilisant la version 0.15) a implémenté pour nous un circuit 242-depth. Le circuit interactif ci-dessous peut être trouvé ici.

visualisation interactive

Logo Classiq

Il y a eu une erreur avec le script

L'astuce

Il existe cependant une autre approche. Deux paramètres peuvent être définis lors de la préparation d'un état : les probabilités à charger et la méthode de discrétisation utilisée pour calculer les résultats. La discrétisation de la méthode précédente utilisait un espacement linéaire standard pour sa discrétisation. Pour ce faire, nous avons dû charger des probabilités correspondant à la distribution log-normale souhaitée. 

Que se passerait-il donc si l'on choisissait un espacement de discrétisation non linéaire ? En choisissant intelligemment l'espacement de nos210 cases, nous pouvons mettre en place un circuit dans lequel toutes les probabilités chargées sont identiques. Cela peut rendre difficiles les calculs ultérieurs pour ce circuit quantique, mais cela rendrait la préparation de l'état triviale. Nous pouvons maintenant choisir librement la base de mesure pour nos qubits et les préparer tous avec la même probabilité dans cette base. Si nous choisissons la base $|+\rangle$, par exemple, nous pouvons préparer tous nos qubits avec des portes de Hadamard, ce qui donne un circuit avec une profondeur de 1, vu ci-dessous et disponible ici.

visualisation interactive

Logo Classiq

Nous avons été heureux de constater que les gagnants de ce problème de concours ont été capables d'identifier cette astuce, chacun employant sa propre méthode de sélection de la discrétisation. Ce problème existe pour démontrer qu'il faut plus que des connaissances techniques pour générer des circuits quantiques efficaces ; il faut aussi de la créativité pour générer des circuits quantiques efficaces. Pour générer notre discrétisation, nous définissons deux fonctions : l'une pour calculer l'erreur L2 et l'autre pour générer la discrétisation en tenant compte de l'erreur L2. Notre code est ajouté ci-dessous.


from scipy.stats import lognorm
from scipy.interpolate import interp1d
import numpy as np

# Calcul de l'erreur L2
def l2_error(pmf : np.array, x_grid : np.array, sigma=0.1) :
    pmf = np.array(pmf)
    x_grid = np.array(x_grid)
    assert all(pmf >= 0)
    assert np.isclose(sum(pmf), 1)
    assert all(x_grid >= 0)
    assert all(np.diff(x_grid) > 0)
    assert len(pmf) + 1 == len(x_grid)

    n_point = 2 ** 22
    tail_value = (TARGET_ERR / 100) ** 2
    min_x = lognorm.ppf(tail_value, sigma)
    max_x = lognorm.ppf(1 - tail_value, sigma)
    x_middle = np.linspace(min_x, max_x, n_point)
    x_lower_tail = np.linspace(0, min_x, n_point // 1000)
    x_upper_tail = np.linspace(max_x, x_grid[-1], n_point // 1000) if x_grid[-1] > max_x else np.array([])

    x_approx = np.diff(x_grid) / 2 + x_grid[:-1]
    x_approx = np.concatenate(([x_approx[0]], x_approx, [x_approx[-1]]))
    pdf_approx = pmf / np.diff(x_grid)
    pdf_approx = np.concatenate(([pdf_approx[0]], pdf_approx, [pdf_approx[-1]]))

    fy = interp1d(x_approx, pdf_approx, kind='nearest', assume_sorted=True, fill_value=(0, 0), bounds_error=False)
    x_full = np.concatenate((x_lower_tail[:-1], x_middle, x_upper_tail[1 :]))
    approx_pdf = fy(x_full)

    full_pdf = lognorm.pdf(x_full, sigma)
    dx = np.diff(x_full)
    dx = np.append(dx, 0)

    upper_tail_err_2_approx = lognorm.sf(x_full[-1], sigma)
    main_err_2 = sum((full_pdf - approx_pdf) ** 2 * dx)
    err = (upper_tail_err_2_approx + main_err_2) ** 0.5
    Retourner err

# Calcul de la distribution de probabilité en fonction de la méthode de discrétisation choisie
def partition(n_qubits=10, flag=True) :
    bins = 2 ** n_qubits
    tail_value = (TARGET_ERR / 10) ** 2
    if flag :
        x_discrete = np.linspace(lognorm.ppf(tail_value, SIGMA),
                               lognorm.ppf(1 - tail_value, SIGMA), bins + 1)
    else :
        x_discrete = lognorm.ppf(np.linspace(tail_value, 1 - tail_value, bins + 1), SIGMA)
    pmf = np.diff(lognorm.cdf(x_discrete, SIGMA))
    pmf = pmf / sum(pmf)
    ERR = l2_error(pmf, x_discrete, sigma=SIGMA)
    margin = TARGET_ERR - ERR
    assert margin > 0
    return tuple(pmf), x_discrete, margin, ERR

Pour comparer avec les solutions proposées par les concurrents, voir ici.

Au-delà des distributions log-normales

Classiq rend la création d'une préparation d'état simple. Définissez les probabilités dans lesquelles vous voulez que votre circuit soit initié, et la plateforme s'occupera du reste. Classiq permet une définition flexible des probabilités comme une fonction de masse de probabilité ou un mélange gaussien et fournit de multiples méthodes pour définir l'erreur autorisée pour le circuit, comme KL, L1, L2, la probabilité maximale et la perte de fidélité. Voici un exemple de Classiq utilisé pour implémenter une préparation d'état utilisant des moments gaussiens, et voici un exemple d'algorithme d'analyse de risque de crédit utilisant un moment gaussien pour sa préparation d'état. 

La préparation d'état de Classiq est flexible, facile à programmer et génère automatiquement le circuit désiré, que vous reproduisiez les résultats d'un article académique ou que vous créiez de nouveaux algorithmes quantiques. Comme nous le disons chez Classiq, "définir ce que vous voulez est facile, mais le mettre en œuvre est difficile". Laissez donc la plateforme Classiq mettre en œuvre les circuits que vous avez définis. Les clients de Classiq travaillent à un niveau supérieur. Spécifiez la fonctionnalité souhaitée du circuit ainsi que les contraintes applicables, et la plateforme Classiq trouve automatiquement la bonne implémentation parmi des milliards d'options d'espace de conception.

Planifiez une démonstration en direct de la plateforme Classiq pour la voir en action, ou contactez-nous pour savoir comment vous pouvez créer des circuits quantiques à la pointe de l'industrie en quelques minutes.

A propos de "The Qubit Guy's Podcast" (Le podcast du gars de Qubit)

Animé par The Qubit Guy (Yuval Boger, notre directeur marketing), le podcast accueille des leaders d'opinion de l'informatique quantique pour discuter de questions commerciales et techniques qui ont un impact sur l'écosystème de l'informatique quantique. Nos invités fournissent des informations intéressantes sur les logiciels et algorithmes d'ordinateurs quantiques, le matériel informatique quantique, les applications clés de l'informatique quantique, les études de marché de l'industrie quantique et bien plus encore.

Si vous souhaitez proposer un invité pour le podcast, veuillez nous contacter.

Créez des logiciels quantiques sans contraintes

contactez-nous