Das 'Hello World'-Äquivalent in der D-Wave-Welt ist das 2D-Schachbrett-Beispiel. In diesem Beispiel erhalten Sie das folgende quadratische Diagramm mit 4 Knoten:
Definieren wir, dass wir den Vertex schwarz färben, wenn und weiß, wenn . Ziel ist es, ein Schachbrettmuster mit den vier Eckpunkten im Diagramm zu erstellen. Es gibt verschiedene Möglichkeiten, und zu definieren
, um dieses Ergebnis zu erzielen. Erstens gibt es zwei mögliche Lösungen für dieses Problem: σ i = - 1σichσich= - 1h Jσich= +1hJ
Der D-Wave-Quanten-Annealer minimiert den von uns definierten Ising-Hamilton-Operator, und es ist wichtig, den Effekt der verschiedenen Kopplereinstellungen zu verstehen. Betrachten Sie zum Beispiel den -Koppler:J0 , 1
Wenn wir es auf setzen , wird der Hamilton-Operator minimiert, wenn beide Qubits den gleichen Wert annehmen. Wir sagen, negative Koppler korrelieren . Wenn wir es auf , wird der Hamilton-Operator minimiert, wenn die beiden Qubits entgegengesetzte Werte annehmen. Somit korrelieren positive Kuppler nicht miteinander .J 0 , 1 = + 1J0 , 1= - 1J0 , 1= + 1
Im Schachbrett-Beispiel möchten wir jedes Paar benachbarter Qubits antikorrelieren, wodurch der folgende Hamilton-Operator entsteht:
H= σ0σ1+ σ0σ2+ σ1σ3+ σ2σ3
Zur Veranschaulichung fügen wir auch einen Bias-Term für das te Qubit hinzu, sodass wir nur die Lösung Nr. 1 erhalten. Diese Lösung benötigt und wir setzen daher die Vorspannung . Der letzte Hamiltonianer ist jetzt:σ 0 = - 1 h 0 = 10σ0= - 1h0= 1
H= σ0+ σ0σ1+ σ0σ2+ σ1σ3+ σ2σ3
Also lasst es uns programmieren!
HINWEIS: Sie MÜSSEN auf den Cloud-Service von D-Wave zugreifen, damit alles funktioniert.
Stellen Sie zunächst sicher, dass Sie das Python-Paket dwave_sapi2
( https://cloud.dwavesys.com/qubist/downloads/ ) installiert haben. Alles wird Python 2.7 sein, da D-Wave derzeit keine höhere Python-Version unterstützt. Vor diesem Hintergrund wollen wir das Wesentliche importieren:
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
Um eine Verbindung zur D-Wave Solver-API herzustellen, benötigen Sie ein gültiges API-Token für den SAPI-Solver, die SAPI-URL und müssen entscheiden, welchen Quantenprozessor Sie verwenden möchten:
DWAVE_SAPI_URL = 'https://cloud.dwavesys.com/sapi'
DWAVE_TOKEN = [your D-Wave API token]
DWAVE_SOLVER = 'DW_2000Q_VFYC_1'
Ich empfehle die Verwendung der D-Wave 2000Q VFYC (Virtual Full Yield Chimera), eines voll funktionsfähigen Chips ohne tote Qubits! Hier ist das Chimera-Chip-Layout:
An dieser Stelle teile ich das Tutorial in zwei Teile auf. Im ersten Abschnitt wird das Problem manuell in das Chimera-Hardware-Diagramm eingebettet, und im zweiten Abschnitt werden die Einbettungsheuristiken von D-Wave verwendet, um eine Hardware-Einbettung zu finden.
Manuelles Einbetten
Die Einheitszelle in der oberen linken Ecke des obigen D-Wave 2000Q-Chip-Layouts sieht folgendermaßen aus:
Beachten Sie, dass in diesem Bild nicht alle Koppler sichtbar sind. Wie Sie sehen, gibt es zwischen Qubit und Qubit keinen Koppler, den wir für die direkte Implementierung unseres obigen quadratischen Diagramms benötigen würden. Deshalb definieren wir jetzt , , und . Dann definieren wir als Liste und als Wörterbuch: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 hat 8 Einträge, da wir die Qubits 0 bis 7 verwenden. Wir stellen nun eine Verbindung zur Solver-API her und fordern den D-Wave 2000Q VFYC-Solver an:
connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN)
solver = connection.get_solver(DWAVE_SOLVER)
Jetzt können wir die Anzahl der Auslesungen definieren und answer_mode
als "Histogramm" auswählen , das die Ergebnisse bereits nach der Anzahl der Vorkommen sortiert. Wir sind jetzt bereit, die Ising-Instanz mit dem D-Wave-Quanten-Annealer zu lösen:
params = {"answer_mode": 'histogram', "num_reads": 10000}
results = solve_ising(solver, h, J, **params)
print results
Sie sollten das folgende Ergebnis erhalten:
{
'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}]]}
Wie Sie sehen, haben wir die richtige Grundzustandsenergie ( energies
) von . Die Lösung String ist voll von ‚s , die die Standard - Ergebnis für nicht verwendete / ungemessene Qubits ist und wenn wir anwenden , um die Reverse - Transformationen - , , und - wir die richtige Lösung String bekommen . Getan!- 5,030 → 04 → 17 → 23 → 3[ 1 , - 1 , - 1 , 1 ]
Heuristische Einbettung
Wenn Sie beginnen, immer größere Ising-Instanzen zu erstellen, können Sie keine manuelle Einbettung durchführen. Nehmen wir also an, wir können unser 2D-Schachbrettbeispiel nicht manuell einbetten. und bleiben dann unverändert von unseren ursprünglichen Definitionen:Jh
J = {(0,1): 1, (0,2): 1, (1,3): 1, (2,3): 1}
h = [-1,0,0,0]
Wir stellen erneut die Remote-Verbindung her und erhalten die D-Wave 2000Q VFYC-Solver-Instanz:
connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN)
solver = connection.get_solver(DWAVE_SOLVER)
Um eine Einbettung unseres Problems zu finden, müssen wir zuerst die Adjazenzmatrix des aktuellen Hardware-Graphen abrufen:
adjacency = get_hardware_adjacency(solver)
Versuchen wir nun, eine Einbettung unseres Problems zu finden:
embedding = find_embedding(J.keys(), adjacency)
Wenn Sie mit großen Ising-Instanzen arbeiten, möchten Sie möglicherweise nach Einbettungen in mehreren Threads (parallelisiert über mehrere CPUs) suchen und dann die Einbettung mit der geringsten Kettenlänge auswählen! Eine Kette ist, wenn mehrere Qubits gezwungen werden, als ein einziges Qubit zu fungieren, um den Konnektivitätsgrad zu erhöhen. Je länger die Kette ist, desto wahrscheinlicher ist es, dass sie bricht. Und gebrochene Ketten führen zu schlechten Ergebnissen!
Wir sind jetzt bereit, unser Problem in das Diagramm einzubetten:
[h, j0, jc, embeddings] = embed_problem(h, J, embedding, adjacency)
j0
enthält die von uns definierten ursprünglichen Kopplungen und jc
enthält die Kopplungen, die die Integrität der Ketten erzwingen (sie korrelieren die Qubits innerhalb der Ketten). Daher müssen wir sie erneut in einem großen Wörterbuch kombinieren :J
J = j0.copy()
J.update(jc)
Jetzt sind wir bereit, das eingebettete Problem zu lösen:
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'])
Das raw_results
ergibt für uns keinen Sinn, wenn wir das Problem nicht gelöst haben. Für den Fall, dass einige Ketten gerissen sind, korrigieren wir sie durch eine Mehrheitsabstimmung, wie im optionalen Argument definiert broken_chains
:
unembedded_results = unembed_answer(raw_results['solutions'],
embedding, broken_chains='vote')
print 'Solution string: {}'.format(unembedded_results)
Wenn Sie dies ausführen, sollten Sie in allen Anzeigen das richtige Ergebnis erhalten:
Lowest energy found: [-5.0]
Number of occurences: [10000]
Solution string: [[1, -1, -1, 1]]
Ich hoffe, dies hat Ihre Frage beantwortet, und ich empfehle dringend, alle zusätzlichen Parameter zu prüfen, die Sie an die solve_ising
Funktion übergeben können, um die Qualität Ihrer Lösungen wie num_spin_reversal_transforms
oder zu verbessern postprocess
.