L'équivalent de «Hello World» dans le monde D-Wave est l'exemple de damier 2D. Dans cet exemple, vous obtenez le graphique carré suivant à 4 nœuds:
Définissons que nous colorions le sommet noir si et le blanc si . Le but est de créer un motif en damier avec les quatre sommets du graphique. Il existe différentes manières de définir
et pour obtenir ce résultat. Tout d'abord, il existe deux solutions possibles à ce problème:σiσi=−1σi=+1hJ
Le recuit quantique D-Wave minimise l'hamiltonien d'Ising que nous définissons et il est important de comprendre l'effet des différents réglages du coupleur. Considérons par exemple le coupleur :J0,1
Si nous le sur , l'hamiltonien est minimisé si les deux qubits prennent la même valeur. Nous disons que les coupleurs négatifs sont corrélés . Alors que si nous le à , l'hamiltonien est minimisé si les deux qubits prennent des valeurs opposées. Ainsi, les coupleurs positifs sont anti-corrélés .J0,1=−1J0,1=+1
Dans l'exemple en damier, nous voulons anti-corréler chaque paire de qubits voisins ce qui donne le hamiltonien suivant:
H=σ0σ1+σ0σ2+σ1σ3+σ2σ3
Par souci de démonstration, nous ajoutons également un terme de biais sur le ème qubit de sorte que nous n'obtenions que la solution # 1. Cette solution nécessite et nous définissons donc son biais . Le hamiltonien final est maintenant:0σ0=−1h0=1
H=σ0+σ0σ1+σ0σ2+σ1σ3+σ2σ3
Alors codons-le!
REMARQUE: vous AVEZ BESOIN d'un accès au service cloud de D-Wave pour que tout fonctionne.
Tout d'abord, assurez-vous que le package Python dwave_sapi2
( https://cloud.dwavesys.com/qubist/downloads/ ) est installé. Tout va être Python 2.7 puisque D-Wave ne prend actuellement en charge aucune version Python supérieure. Cela étant dit, importons l'essentiel:
from dwave_sapi2.core import solve_ising
from dwave_sapi2.embedding import find_embedding, embed_problem, unembed_answer
from dwave_sapi2.util import get_hardware_adjacency
from dwave_sapi2.remote import RemoteConnection
Pour vous connecter à l'API D-Wave Solver, vous aurez besoin d'un jeton d'API valide pour leur solveur SAPI, de l'URL SAPI et vous devez décider quel processeur quantique vous souhaitez utiliser:
DWAVE_SAPI_URL = 'https://cloud.dwavesys.com/sapi'
DWAVE_TOKEN = [your D-Wave API token]
DWAVE_SOLVER = 'DW_2000Q_VFYC_1'
Je recommande d'utiliser la chimère D-Wave 2000Q Virtual Full Yield Chimera (VFYC) qui est une puce entièrement fonctionnelle sans aucun qubits morts! Voici la disposition des puces Chimera:
À ce stade, je divise le didacticiel en deux parties distinctes. Dans la première section, nous intégrons manuellement le problème dans le graphique matériel Chimera et dans la deuxième section, nous utilisons l'heuristique d'intégration de D-Wave pour trouver une intégration matérielle.
Incorporation manuelle
La cellule unitaire dans le coin supérieur gauche de la disposition des puces D-Wave 2000Q ci-dessus ressemble à ceci:
Notez que tous les coupleurs ne sont pas visualisés sur cette image. Comme vous pouvez le voir, il n'y a pas de coupleur entre qubit et qubit dont nous aurions besoin pour implémenter directement notre graphique carré ci-dessus. C'est pourquoi nous redéfinissons maintenant , , et . Nous continuons ensuite et définissons comme une liste et comme un dictionnaire:010→01→42→73→3hJ
J = {(0,4): 1, (4,3): 1, (3,7): 1, (7,0): 1}
h = [-1,0,0,0,0,0,0,0,0]
h a 8 entrées depuis que nous utilisons les qubits 0 à 7. Nous établissons maintenant la connexion à l'API Solver et demandons le solveur D-Wave 2000Q VFYC:
connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN)
solver = connection.get_solver(DWAVE_SOLVER)
Maintenant, nous pouvons définir le nombre de lectures et choisir answer_mode
d'être "histogramme" qui trie déjà les résultats par le nombre d'occurrences pour nous. Nous sommes maintenant prêts à résoudre l'instance d'Ising avec le recuit quantique D-Wave:
params = {"answer_mode": 'histogram', "num_reads": 10000}
results = solve_ising(solver, h, J, **params)
print results
Vous devriez obtenir le résultat suivant:
{
'timing': {
'total_real_time': 1655206,
'anneal_time_per_run': 20,
'post_processing_overhead_time': 13588,
'qpu_sampling_time': 1640000,
'readout_time_per_run': 123,
'qpu_delay_time_per_sample': 21,
'qpu_anneal_time_per_sample': 20,
'total_post_processing_time': 97081,
'qpu_programming_time': 8748,
'run_time_chip': 1640000,
'qpu_access_time': 1655206,
'qpu_readout_time_per_sample': 123
},
'energies': [-5.0],
'num_occurrences': [10000],
'solutions': [
[1, 3, 3, 1, -1, 3, 3, -1, {
lots of 3 's that I am omitting}]]}
Comme vous pouvez le voir, nous avons obtenu la bonne énergie d'état fondamental ( energies
) de . La chaîne de solution est pleine de , ce qui est le résultat par défaut pour les qubits inutilisés / non mesurés et si nous appliquons les transformations inverses - , , et - nous obtenons la chaîne de solution correcte . Terminé!−5.030→04→17→23→3[1,−1,−1,1]
Incorporation heuristique
Si vous commencez à créer des instances Ising de plus en plus grandes, vous ne pourrez pas effectuer d'incorporation manuelle. Supposons donc que nous ne pouvons pas incorporer manuellement notre exemple de damier 2D. et restent alors inchangés par rapport à nos définitions initiales:Jh
J = {(0,1): 1, (0,2): 1, (1,3): 1, (2,3): 1}
h = [-1,0,0,0]
Nous établissons à nouveau la connexion à distance et obtenons l'instance de solveur D-Wave 2000Q VFYC:
connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN)
solver = connection.get_solver(DWAVE_SOLVER)
Afin de trouver une intégration de notre problème, nous devons d'abord obtenir la matrice d'adjacence du graphe matériel actuel:
adjacency = get_hardware_adjacency(solver)
Essayons maintenant de trouver une intégration de notre problème:
embedding = find_embedding(J.keys(), adjacency)
Si vous avez affaire à de grandes instances Ising, vous pouvez rechercher des incorporations dans plusieurs threads (parallélisées sur plusieurs processeurs), puis sélectionner l'incorporation avec la plus petite longueur de chaîne! Une chaîne, c'est lorsque plusieurs qubits sont forcés d'agir comme un seul qubit afin d'augmenter le degré de connectivité. Cependant, plus la chaîne est longue, plus elle risque de se casser. Et les chaînes cassées donnent de mauvais résultats!
Nous sommes maintenant prêts à intégrer notre problème dans le graphique:
[h, j0, jc, embeddings] = embed_problem(h, J, embedding, adjacency)
j0
contient les couplages d'origine que nous avons définis et jc
contient les couplages qui renforcent l'intégrité des chaînes (ils corrèlent les qubits au sein des chaînes). Ainsi, nous devons les combiner à nouveau dans un grand dictionnaire :J
J = j0.copy()
J.update(jc)
Maintenant, nous sommes prêts à résoudre le problème intégré:
params = {"answer_mode": 'histogram', "num_reads": 10000}
raw_results = solve_ising(solver, h, J, **params)
print 'Lowest energy found: {}'.format(raw_results['energies'])
print 'Number of occurences: {}'.format(raw_results['num_occurrences'])
Le raw_results
ne sera pas de sens pour nous à moins que nous le problème annuler l' incorporation. Dans le cas où certaines chaînes se sont rompues, nous les réparons par un vote majoritaire tel que défini par l'argument facultatif broken_chains
:
unembedded_results = unembed_answer(raw_results['solutions'],
embedding, broken_chains='vote')
print 'Solution string: {}'.format(unembedded_results)
Si vous exécutez ceci, vous devriez obtenir le résultat correct dans toutes les lectures:
Lowest energy found: [-5.0]
Number of occurences: [10000]
Solution string: [[1, -1, -1, 1]]
J'espère que cela a répondu à votre question et je vous recommande fortement de vérifier tous les paramètres supplémentaires que vous pouvez passer à la solve_ising
fonction pour améliorer la qualité de vos solutions telles que num_spin_reversal_transforms
ou postprocess
.