Quantencomputing für Data Science: ein Praxistest

Seite 2: Anwendungsfall 1: Quantum Sampling

Inhaltsverzeichnis

Beginnen wir mit einem naheliegenden Einsatzzweck eines Quantencomputers: dem Generieren von Zufallszahlen. Das sogenannte Sampling zieht Zahlen aus einer bestimmten Wahrscheinlichkeitsverteilung. Die Technik ist ein wichtiges Werkzeug für Data Scientists, die sie unter anderem für die Modellierung von Markov-Ketten und zum Training neuronaler Netze einsetzen. Als spezieller stochastischer Prozess dienen Markow-Ketten dazu, Wahrscheinlichkeiten für das Eintreten zukünftiger Ereignisse anzugeben. Auf beide Anwendungsfälle geht der Artikel detaillierter ein.

Qiskit lässt sich zum Beispiel zum Ziehen von Zufallszahlen auf einem Quantencomputer nutzen. Es ist in Python geschrieben und bietet den Vorteil, dass der Code kostenlos auf einem echten Quantencomputer ausführbar ist. Da die Maschinen bei IBM Quantum (IBMQ) in der Regel stark ausgelastet sind, müssen Entwicklerinnen und Entwickler lediglich etwas Zeit mitbringen. Verglichen mit dem Quantencomputing bei anderen kommerziellen Anbietern wie Google, Amazon oder Microsoft ist IBMQ eine günstige Alternative. Für das weiter unten folgende Beispiel mit 8000 Messungen fielen auf einer D-Wave-Maschine beispielsweise nach der aktuell gültigen Preisliste von AWS circa 1,82 US-Dollar an (ein Task mit 8000 Shots). Bei IonQ- und Rigetti-Systemen wären die Kosten höher.

Die folgenden wichtigen Codefragmente dienen dem Verständnis des ersten Beispiels. Der vollständige Sourcecode liegt in einem Jupyter Notebook auf GitHub parat.

Zunächst importiert das Notebook einige Bibliotheken:

from datetime import datetime
import pandas as pd
import qiskit as qml
from qiskit.providers.ibmq import least_busy
import matplotlib.pyplot as plt

Neben Qiskit umfasst der Import Data-Science-Libraries wie pandas. Der nächste Codeblock definiert einige globale Variablen zur Steuerung des Notebooks:

LOCAL_SIMULATION = False
SHOTS = 8000
BINOMIAL_N = 20
RANDOM_WALK_DAYS = 200

Die Variable LOCAL_SIMULATION konfiguriert, ob der Code lokal in einem Simulator oder remote auf einem echten Quantencomputer läuft. Im nächsten Schritt meldet sich das Notebook mit einem Account bei IBMQ an:

if not qml.IBMQ.active_account():
    qml.IBMQ.load_account()

Als Vorbereitung zum Ausführen des Codes ist eine Registrierung bei IBMQ notwendig. Eine Anleitung dazu findet sich in der Dokumentation. Nach der Anmeldung wählt der Code ein für den Anwendungsfall geeignetes Backend aus:

provider = qml.IBMQ.get_provider(hub='ibm-q')

if LOCAL_SIMULATION:
    backend = qml.Aer.get_backend('aer_simulator')
else:
    backend = least_busy(provider.backends(simulator=False, operational=True))

Falls die Variable LOCAL_SIMULATION gesetzt ist, kommt ein Simulator zum Einsatz, anderenfalls der am wenigsten frequentierte Quantencomputer bei IBMQ. Da das Beispiel mit nur einem Qubit ausführbar ist, kommen grundsätzlich alle verfügbaren Rechner unabhängig von ihrer Größe infrage. Dadurch verkürzt sich die Wartezeit. Da Quantencomputer immer noch eine Rarität sind, verbringen Entwicklerinnen und Entwickler gemeinsam mit anderen Anfragenden viel Zeit in Warteschleifen. Je mehr Qubits ein Rechner hat, desto gefragter ist er.

Nun folgt der Kernschritt des ersten Beispiels, die Definition eines Quantenschaltkreises:

circuit = qml.QuantumCircuit(1)
circuit.h(0)
circuit.measure_all()
compiled_circuit = qml.transpile(circuit, backend)

Ähnlich wie bei einem klassischen Rechner bilden Schaltkreise bei Quantencomputern ein grundlegendes Programmierelement. Der vorangehende Codeblock definiert einen Schaltkreis, der auf einem Qubit operiert, das sich zunächst im Ausgangszustand befindet. Mit einem Hadamard-Gatter werden die Werte 0 und 1 in der zweiten Zeile in einen überlagerten Zustand überführt. Die Wahrscheinlichkeit für eine Messung der Zahlen 0 und 1 liegt danach bei jeweils 50 Prozent. Eine Messung wird in der Quantenwelt auch als Shot bezeichnet. Das Beispiel sieht 8000 Messungen im Backend vor und liefert im Ergebnis ebenso viele Zufallszahlen:

result = backend.run(compiled_circuit, memory=True, shots=SHOTS).result()
random_numbers = result.get_memory()

Die erzeugten Zahlen folgen einer Bernoulli-Verteilung. Sie beschreibt Zufallsereignisse mit nur zwei möglichen Ausgängen ("Misserfolg" / "Erfolg" oder 0 / 1). Im Beispiel entsprechen die Werte mit gleicher Wahrscheinlichkeit 0 oder 1 (p=0,5). Im Unterschied zur Mehrheit klassischer Verfahren handelt es sich bei den erzeugten Daten nicht um Pseudozufallszahlen, sondern um tatsächlich zufällige Werte. Die Visualisierung der Verteilung in Abbildung 1 liefert folgendes Bild:

Bernoulli-Verteilung der Zufallszahlen für 8000 Messungen (Abb. 1)

Die Verteilung der Zufallszahlen weist wie erwartet etwa 4000 Ausprägungen der Werte 0 und 1 auf. Auch andere Verteilungen können Data Scientists mit Hilfe von Quantendaten erzeugen. Der nachfolgende Code-Block transformiert beispielsweise die im Quantencomputer erzeugte Bernoulli-Verteilung durch eine simple Operation in eine Binomialverteilung:

binomial_frame = bernoulli_frame.groupby(
    bernoulli_frame.index // BINOMIAL_N).sum().reset_index(drop=True)

Quantum Sampling ist der erste Bereich in dem Wissenschaftler Quantenüberlegenheit zeigen konnten. Ein Quantencomputer erfüllt dabei eine Aufgabe, die sich auf einem klassischen Rechner nicht in akzeptabler Zeit – beispielsweise in Sekunden oder allenfalls Tagen – bearbeiten lässt. In Zukunft dürften weitere Bereiche hinzukommen, darunter beispielsweise Simulationen.

Im nächsten Abschnitt dienen die erzeugten Zufallszahlen dazu, den Kursverlauf einer Aktie mithilfe einer Markov-Kette darzustellen.