Zum Hauptinhalt springen
Dieses Projekt befindet sich in der Beta-Phase. Einen Fehler gefunden? GitHub Issue erstellen. Frage oder Idee? In Discussions fragen — wir freuen uns über dein Feedback!
Wie ist die Übersetzungsqualität auf dieser Seite?

SQOA Solver - eine Qiskit Function von JIJ

Siehe die API-Referenz.

hinweis

Qiskit Functions sind eine experimentelle Funktion, die nur für Nutzer des IBM Quantum® Premium Plans, Flex Plans und On-Prem-Plans (über die IBM Quantum Platform API) verfügbar ist. Sie befinden sich im Preview-Status und können sich ändern.

Überblick​

Mit SQOA Solver von JIJ kannst du große kombinatorische Optimierungsprobleme auf IBM® Quantencomputern lösen. Der Solver basiert auf dem Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) [1]. Anders als Quantenalgorithmen, die eine Eins-zu-eins-Abbildung zwischen klassischen Entscheidungsvariablen und Qubits verwenden, kann SQOA Solver Optimierungsprobleme mit mehr Variablen behandeln, als auf aktuellen Quantengeräten Qubits zur Verfügung stehen. Sein samplingbasiertes Design macht ihn außerdem weniger empfindlich gegenüber dem physikalischen Rauschen aktueller Quantenhardware. Zusammen machen diese Eigenschaften SQOA Solver gut geeignet für Optimierungsprobleme in der heutigen Phase des Quantencomputings.

Der Solver behandelt Probleme der Quadratic Unconstrained Binary Optimization (QUBO), die als klassische mathematische Formulierung vorliegen, und bildet die klassische Formulierung automatisch auf das Quantenmodell ab. Du kannst auch Probleme mit Nebenbedingungen mithilfe der Penalty-Methode in Probleme ohne Nebenbedingungen umwandeln.

Die folgenden Abschnitte beschreiben den Workflow des Solvers, Benchmark-Ergebnisse und End-to-End-Beispiele, die Probleme mit qiskit-addon-opt-mapper und optional mit Open Mathematical prograMming eXchange (OMMX) modellieren. OMMX ist ein offenes Datenformat und SDK, das den Austausch von Optimierungsproblemen zwischen Softwarewerkzeugen vereinfacht.

Beschreibung​

SQOA Solver implementiert den Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) und umgibt ihn mit klassischer Vor- und Nachverarbeitung. Dieser Abschnitt erklärt das SQOA-Framework und wie es sich vom Quantum Approximate Optimization Algorithm (QAOA) unterscheidet.

Die folgende Abbildung zeigt eine schematische Darstellung des SQOA-Solver-Workflows. Schematische Darstellung des SQOA-Solver-Workflows, von der klassischen Vorverarbeitung über das SQOA-Sampling bis zur Nachverarbeitung und lokalen Suche

Das SQOA-Framework​

SQOA ist ein samplingbasiertes Framework für kombinatorische Optimierung [1]. Es kombiniert zwei Techniken: Quantum Random Access Optimization (QRAO) [2], das das Problem in einer Quantenrelaxation kodiert, und Sample-based Quantum Diagonalization (SQD) [3], auch bekannt als Quantum-selected Configuration Interaction (QSCI) [4], das den Quantencomputer nur zum Sampeln von Bitstrings verwendet und den Zustand niedrigster Energie auf einem klassischen Computer findet. SQOA ist insofern ein Framework, als es diese Kombination festlegt, die Details aber der jeweiligen Implementierung überlässt, etwa wie die Variablen den Qubits zugewiesen werden und welche Circuits die Samples erzeugen.

  • Quantenrelaxation mit QRAO. QAOA und andere Ising-basierte Ansätze stellen jede binäre Variable durch den Operator ZZ ihres Qubits dar. QRAO verwendet zusätzlich die Operatoren XX und YY. Mit einem (3,1)-Quantum Random Access Code (QRAC) teilen sich bis zu drei binäre Variablen ein Qubit, und jede Variable wird durch einen anderen Pauli-Operator dargestellt.

    Das QUBO wird dadurch zu einem relaxierten Hamiltonian, der weniger Qubits benötigt als der Ising-Hamiltonian. Variablen, die im QUBO wechselwirken, müssen auf verschiedenen Qubits liegen. Würden sie sich ein Qubit teilen, würde sich das Produkt ihrer Pauli-Operatoren auf einen einzelnen Operator auf diesem Qubit reduzieren (zum Beispiel XY=iZXY = iZ), und der relaxierte Hamiltonian würde ihre Wechselwirkung nicht mehr abbilden.

    Die Zuweisung der Variablen zu Qubits bestimmt daher sowohl die Anzahl der Qubits als auch die Qualität der Relaxation, und SQOA Solver entwirft diese Zuweisung in seiner Vorverarbeitung.

  • Sample-based Quantum Diagonalization (SQD). Der Quantencomputer bereitet zunächst einen Quantenzustand vor, der mit Zuständen niedriger Energie des relaxierten Hamiltonians überlappt, und sampelt daraus Bitstrings. Ein klassischer Computer projiziert den relaxierten Hamiltonian auf den von den gesampelten Bitstrings aufgespannten Unterraum und diagonalisiert ihn, um den Grundzustand zu approximieren.

    Da der relaxierte Hamiltonian nicht diagonal ist, kombiniert die Diagonalisierung die gesampelten Bitstrings zu einer Superposition. Bei einem diagonalen Ising-Hamiltonian ist jeder Bitstring bereits ein Eigenzustand, und die Diagonalisierung würde nur das beste Sample auswählen. Derselbe Ansatz wurde auf große Probleme in der Quantenchemie angewendet.

Der durch SQD erhaltene approximative Grundzustand entspricht nicht direkt einer klassischen Lösung des ursprünglichen Problems, daher muss die klassische Lösung daraus dekodiert werden. Da dieser Zustand auf einem klassischen Computer berechnet wird, ist die Dekodierung, genannt Rounding, eine klassische Nachverarbeitung. SQOA Solver verwendet Dekodierungstechniken, die heuristisch bessere klassische Lösungen liefern sollen.

Die folgende Tabelle vergleicht SQOA mit QAOA, einem verbreiteten variationalen Ansatz für dieselbe Problemklasse.

 QAOASQOA
Qubits für nn binäre VariablennnEin Qubit hält bis zu drei der Variablen. Die genaue Anzahl hängt von der Problemstruktur ab
Nutzung der QPUSchätzt wiederholt die Energie parametrisierter Circuits innerhalb einer klassischen OptimierungsschleifeSampelt nur Bitstrings. Auf der QPU werden keine Circuit-Parameter trainiert
Von den Samples zur LösungWählt den besten gemessenen Bitstring ausDiagonalisiert den relaxierten Hamiltonian im gesampelten Unterraum auf einem klassischen Computer und rundet den resultierenden Zustand

Um SQOA-QR herum ergänzt SQOA Solver klassische Verarbeitung. Die Vorverarbeitung fixiert Variablen, deren optimale Werte sich vorab bestimmen lassen, und entwirft die Zuweisung der Variablen zu Qubits. Die Nachverarbeitung verfeinert die gerundete Lösung mit einer lokalen Suche, die du mit postprocessing_level=0 ausschalten kannst.

Benchmarks​

Haftungsausschluss

Die Leistung kann sowohl von der Probleminstanz als auch von den nachfolgenden Verarbeitungsschritten abhängen. In manchen Fällen können klassische Samples und quantengenerierte Samples nach gleichwertiger Nachverarbeitung eine ähnliche endgültige Lösungsqualität erreichen. Die Bewertung sollte daher den gesamten Optimierungs-Workflow berücksichtigen.

Die folgenden Benchmark-Metriken geben einen allgemeinen Hinweis auf Lösungsqualität, Qubit-Kompression und Ausführungszeit für ausgewählte Problemgrößen und -strukturen. Die Tabelle listet eine Auswahl von Maximum-Independent-Set-Instanzen aus der Quantum Optimization Benchmarking Library (QOBLIB) sowie zwei 3-reguläre MaxCut-Instanzen auf. Du kannst die QOBLIB-Instanzen zusammen mit ihren optimalen Lösungen mithilfe des Pakets ommx-quantum-benchmarks als ommx.v1.Instance-Objekte laden.

Jede Instanz wurde 10-mal auf einem IBM Heron r2-Prozessor ausgeführt. Number of qubits zählt die tatsächlich auf der Hardware verwendeten Qubits nach der Vorverarbeitung und der QRAC-Kodierung. Das Kompressionsverhältnis hängt von der Instanz ab. Approximation ratio (AR) gibt die Qualität der besten über die 10 Läufe gefundenen Lösung an:

AR=CbestCopt,\mathrm{AR} = \frac{C_{\textrm{best}}}{C_{\textrm{opt}}},

wobei CbestC_{\textrm{best}} der beste gefundene Zielfunktionswert und CoptC_{\textrm{opt}} der bekannte optimale Zielfunktionswert ist. Alle Instanzen sind Maximierungsprobleme mit positivem optimalem Wert, daher ist AR höchstens 100 %, und 100 % in der Spalte Approximation ratio bedeutet, dass der Solver eine optimale Lösung gefunden hat. Total time ist die durchschnittliche kombinierte QPU- und CPU-Zeit pro Lauf. QPU time ist die durchschnittliche IBM Quantum Compute-Nutzung pro Lauf.

InstanzAnzahl der VariablenAnzahl der QubitsApproximationsverhältnisGesamtzeit (Sekunden)QPU-Zeit (Sekunden)
maxcut_384_nodes38412998.5%62.112.0
gen200_p0-9_4420067100%38.012.0
es60fst0218642100%24.712.0
es60fst0416229100%17.912.0
maxcut_150_nodes15051100%23.112.0
sloane_1dc_1281283793.8%19.112.0
sloane_2dc_1281288100%12.311.5
C125-912543100%22.312.0
es60fst0112312100%13.612.0
es60fst0311326100%14.912.0
sloane_1dc_646416100%13.411.9
chesapeake3913100%13.112.0
football356100%12.512.0
karate342100%6.26.0
ibm323211100%12.912.0
farm174100%8.58.0

Erste Schritte​

Zugangsinformationen für diese Qiskit Function findest du im Qiskit Functions Catalog.

Dieser Abschnitt zeigt, wie du dich authentifizierst und die Function lädst und wie du ein Problem in dem Dictionary-Format vorbereitest, das SQOA Solver akzeptiert, indem du OptimizationProblem aus qiskit-addon-opt-mapper verwendest. Die folgenden Beispiele führen die Function aus und lesen das Ergebnis aus.

Authentifizieren und die Function laden​

Authentifiziere dich zunächst mit deinem IBM Quantum API-Schlüssel. (Der folgende Code setzt voraus, dass du dein Konto bereits in deiner lokalen Umgebung gespeichert hast.) Erstelle dann wie folgt einen Catalog-Client:

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"jijmodeling": "jijmodeling", "networkx": "networkx", "ommx": "ommx", "qiskit_addon_opt_mapper": "qiskit-addon-opt-mapper", "qiskit_ibm_catalog": "qiskit-ibm-catalog"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# verify that you have access to the function
catalog.list()
[QiskitFunction(jij/sqoa-solver)]
solver = catalog.load("jij/sqoa-solver")

Die Eingabe mit qiskit-addon-opt-mapper vorbereiten​

Dieser Leitfaden modelliert Probleme mit der Klasse OptimizationProblem aus qiskit-addon-opt-mapper. SQOA Solver akzeptiert ein QUBO-Problem als Koeffizienten-Dictionary im Tupel-String-Format, das von den IBM-Optimierungsfunktionen verwendet wird, daher folgt jedes Beispiel in diesem Leitfaden demselben clientseitigen Vorbereitungsmuster:

  1. Das Modell schreiben. Erstelle ein OptimizationProblem, füge binäre Entscheidungsvariablen hinzu und lege die Zielfunktion sowie eventuelle Nebenbedingungen fest.

  2. In QUBO umwandeln. Wandle das Problem mit OptimizationProblemToQubo um, das Nebenbedingungen als Penalty-Terme zur Zielfunktion hinzufügt und ein äquivalentes Minimierungsproblem ohne Nebenbedingungen zurückgibt.

  3. In ein Dictionary umwandeln. Übergib das QUBO an die im nächsten Abschnitt definierte Hilfsfunktion to_problem_dict() und übergib das Ergebnis zusammen mit variable_type="binary" als problem an solver.run().

SQOA Solver minimiert ein Dictionary-Problem immer, was dem Minimierungsproblem entspricht, das OptimizationProblemToQubo zurückgibt. Bei einem Maximierungsproblem ist der zurückgegebene objective_value daher das Negative der ursprünglichen Zielfunktion. Um das Ergebnis im Sinne des ursprünglichen Problems zu lesen, werte die zurückgegebene Zuweisung mit OptimizationProblem aus, wie es die Beispiele zeigen. Details zum Dictionary-Format findest du unter Akzeptierte Problemformate in der API-Referenz.

# %pip install qiskit-addon-opt-mapper

Definiere die folgende Hilfsfunktion einmal und verwende sie in jedem Beispiel wieder. Sie wandelt das von OptimizationProblemToQubo zurückgegebene QUBO in das Dictionary-Format um. Die Schlüssel verwenden die Variablenindizes des QUBO, daher entsprechen die Lösungsschlüssel x_0, x_1 und so weiter im Ergebnis diesen Indizes. Jede Variable erhält einen linearen Eintrag, auch mit Koeffizient null, damit die zurückgegebene Lösung alle Variablen abdeckt.

from qiskit_addon_opt_mapper import OptimizationProblem
from qiskit_addon_opt_mapper.converters import OptimizationProblemToQubo

def to_problem_dict(qubo: OptimizationProblem) -> dict[str, float]:
"""Convert a QUBO from OptimizationProblemToQubo to the SQOA Solver dictionary format."""
objective = qubo.objective
payload = {"()": objective.constant}
# Keep every variable in the problem, even with a zero linear coefficient.
payload.update({f"({i},)": 0.0 for i in range(qubo.get_num_vars())})
for i, coefficient in objective.linear.to_dict().items():
payload[f"({i},)"] += coefficient
for (i, j), coefficient in objective.quadratic.to_dict().items():
# Fold a binary diagonal term x_i * x_i = x_i into the linear term.
key = f"({i},)" if i == j else f"({i}, {j})"
payload[key] = payload.get(key, 0.0) + coefficient
return {key: float(value) for key, value in payload.items()}

Beispiel 1: MaxCut auf einem 3-regulären Graphen​

Viele Graphenprobleme, etwa MaxCut, sind NP-schwer und natürliche Kandidaten für Quantenoptimierung. Installiere networkx als zusätzliche Abhängigkeit, um dieses Beispiel auszuführen:

# %pip install networkx

1. Das Modell schreiben​

Weise jedem Knoten eines Graphen G=(V,E)G = (V, E) eine binäre Variable xv∈{0,1}x_v \in \{0, 1\} zu, die seine Seite des Schnitts angibt. Eine Kante wird geschnitten, wenn ihre Endpunkte auf verschiedenen Seiten liegen, daher ist die Schnittgröße:

Cut(x)=∑(u,v)∈E(xu+xv−2xuxv).\mathrm{Cut}(x) = \sum_{(u,v) \in E} \left(x_u + x_v - 2 x_u x_v\right).

Diese Zielfunktion ist bereits ein QUBO ohne Nebenbedingungen, daher macht OptimizationProblemToQubo lediglich aus der Maximierung die äquivalente Minimierung und lässt die Variablen unverändert. Die Anwendungsklasse Maxcut in qiskit_addon_opt_mapper.applications baut dasselbe Modell mit Maxcut(G).to_optimization_problem().

import networkx as nx

G = nx.random_regular_graph(3, 40, seed=42)

linear = {v: 0 for v in G.nodes}
quadratic = {}
for u, v in G.edges:
linear[u] += 1
linear[v] += 1
quadratic[(u, v)] = -2

maxcut = OptimizationProblem("MaxCut")
maxcut.binary_var_list(G.number_of_nodes(), name="x")
maxcut.maximize(linear=linear, quadratic=quadratic)

2. Den Solver ausführen​

Wandle das Modell in ein QUBO und dann in ein Dictionary um und sende es ab. problem und variable_type sind erforderlich. backend_name ist optional. Wird er weggelassen oder ist er None, wählt die Function die am wenigsten ausgelastete betriebsbereite QPU, die deiner Instanz zur Verfügung steht.

Das Dictionary options akzeptiert shots, seed, session, postprocessing_level und job_tags. Beschreibungen und Standardwerte findest du in der API-Referenz.

qubo = OptimizationProblemToQubo().convert(maxcut)

job = solver.run(
problem=to_problem_dict(qubo),
variable_type="binary",
backend_name="ibm_fez",
options={
"shots": 4096,
"seed": 42,
},
)

3. Das Ergebnis abrufen​

job.result() gibt ein Dictionary mit vier Schlüsseln zurück:

  • solution ist die vollständige Variablenzuweisung, mit x_i als Schlüssel, wobei i der Variablenindex ist (zum Beispiel x_3).

  • objective_value und feasible sind die Zielfunktion und die Zulässigkeit dieser Zuweisung, ausgewertet auf dem abgesendeten Dictionary.

  • metadata enthält solver_info und resource_usage.

Da das QUBO die Minimierungsform von MaxCut ist, ist objective_value das Negative der Schnittgröße. Werte die Zuweisung auf dem ursprünglichen OptimizationProblem aus, um die Schnittgröße direkt abzulesen.

result = job.result()

x = [result["solution"][f"x_{i}"] for i in range(maxcut.get_num_vars())]
print(f"Cut value: {maxcut.objective.evaluate(x)}")
print(f"Nodes on side 1: {[v for v, value in enumerate(x) if value > 0.5]}")
Cut value: 55.0
Nodes on side 1: [5, 7, 9, 11, 14, 16, 17, 19, 21, 23, 24, 26, 30, 31, 33, 34, 36, 37, 38]

4. Die Ressourcennutzung prüfen​

result["metadata"]["resource_usage"] gibt die in jeder Ausführungsphase verbrachte Zeit an. Andere Phasen als RUNNING: EXECUTING_QPU melden CPU_TIME, die Wanduhrzeit der Phase in Sekunden, sofern verfügbar.

Die Phase RUNNING: EXECUTING_QPU meldet QPU_TIME, die QPU-Nutzung aller Quantum Compute-Jobs des Laufs, sofern die endgültige Nutzung für jeden Job verfügbar ist. Details findest du in der API-Referenz.

for phase, metrics in result["metadata"]["resource_usage"].items():
line = f"{phase:36s}"
if "CPU_TIME" in metrics:
line += f" CPU {metrics['CPU_TIME']:8.1f} s"
if "QPU_TIME" in metrics:
line += f" QPU {metrics['QPU_TIME']:8.1f} s"
print(line)
RUNNING: MAPPING CPU 3.2 s
RUNNING: OPTIMIZING_FOR_HARDWARE CPU 5.0 s
RUNNING: WAITING_FOR_QPU CPU 1.1 s
RUNNING: EXECUTING_QPU QPU 3.0 s
RUNNING: POST_PROCESSING CPU 0.9 s

Beispiel 2: Ein Problem mit Nebenbedingungen in QUBO umwandeln​

SQOA Solver akzeptiert Probleme ohne Nebenbedingungen. Dieses Beispiel zeigt, wie du ein Problem mit Nebenbedingungen mit OptimizationProblemToQubo in ein QUBO umwandelst und das Ergebnis auf die Variablen des ursprünglichen Problems zurückabbildest.

selection = OptimizationProblem("ConstrainedExample")
selection.binary_var_list(2, name="x")
selection.maximize(linear={"x0": 1, "x1": 1})
selection.linear_constraint({"x0": 1, "x1": 1}, "<=", 1, name="at_most_one")

print(selection.prettyprint())
Problem name: ConstrainedExample

Maximize
x0 + x1

Subject to
Linear constraints (1)
x0 + x1 <= 1 'at_most_one'

Binary variables (2)
x0 x1

OptimizationProblemToQubo fügt die Nebenbedingungen als Penalty-Terme zur Zielfunktion hinzu und wandelt das Problem in eine Minimierung um. Das passende Penalty-Gewicht hängt vom Problem ab.

Nach dem Lauf bildet interpret() die QUBO-Zuweisung auf die Variablen des ursprünglichen Problems zurück ab.

Werte die Zielfunktion und die Zulässigkeit auf dem ursprünglichen Problem aus. Bei einem Dictionary-Problem bezieht sich das Feld feasible des Ergebnisses nur auf den Wertebereich der Variablen, da das Dictionary keine Nebenbedingungen enthält.

converter = OptimizationProblemToQubo(penalty=4.0)
qubo = converter.convert(selection)

job = solver.run(
problem=to_problem_dict(qubo),
variable_type="binary",
backend_name="ibm_fez",
)
result = job.result()

x_qubo = [result["solution"][f"x_{i}"] for i in range(qubo.get_num_vars())]
x = converter.interpret(x_qubo)
print("Objective:", selection.objective.evaluate(x))
print("Feasible:", selection.is_feasible(x))
print("x values:", x)
Objective: 1.0
Feasible: True
x values: [1. 0.]

Beispiel 3: Eine OMMX-Instanz absenden​

SQOA Solver akzeptiert auch eine ommx.v1.Instance aus dem OMMX-SDK, die Variablennamen, Indizes und Konvertierungsmetadaten zusammen mit dem Problem aufbewahrt. Im Vergleich zu einem Dictionary hat eine OMMX-Eingabe die folgenden Vorteile:

  • Das Ergebnis enthält außerdem die kanonische ommx.v1.Solution in solver_info["ommx_solution"].

  • objective_value wird im Sinne der Instanz ausgewertet, daher wird die Zielfunktion eines Maximierungsproblems nicht negiert.

  • Bei einer Instanz, die mit Instance.to_qubo() direkt umgewandelt wurde, wird feasible gegen die ursprünglichen Nebenbedingungen ausgewertet.

Dieses Beispiel baut das MaxCut-Modell aus Beispiel 1 mit JijModeling, einem Modellierer für mathematische Optimierung, der Modelle zu OMMX-Instanzen kompiliert. Installiere JijModeling, wodurch auch das Paket ommx installiert wird:

# %pip install "jijmodeling~=2.8.0"

SQOA Solver tauscht OMMX-Daten als standardmäßige Base64-Strings mit Padding aus. Definiere die folgenden Hilfsfunktionen für diese Konvertierung:

  • to_problem_payload() serialisiert eine ommx.v1.Instance in den String, den du als problem übergibst.

  • to_ommx_solution() dekodiert die kanonische ommx.v1.Solution aus dem Ergebnis.

import base64

from ommx.v1 import Instance, Solution

def to_problem_payload(instance: Instance) -> str:
"""Serialize an OMMX instance into the `problem` string for SQOA Solver."""
return base64.b64encode(instance.to_bytes()).decode()

def to_ommx_solution(result: dict) -> Solution:
"""Decode the canonical OMMX solution from a SQOA Solver result."""
payload = result["metadata"]["solver_info"]["ommx_solution"]
return Solution.from_bytes(base64.b64decode(payload, validate=True))

1. Das Modell mit JijModeling schreiben​

Die übliche Spin-Formulierung von MaxCut auf einem Graphen G=(V,E)G = (V, E) weist jedem Knoten sv∈{−1,+1}s_v \in \{-1, +1\} zu. Eine Kante wird geschnitten, wenn susv=−1s_u s_v = -1 gilt, daher ist die Schnittgröße:

Cut⁡(s)=∑(u,v)∈E1−susv2.\operatorname{Cut}(s) = \sum_{(u,v) \in E} \frac{1 - s_u s_v}{2}.

JijModeling bietet keine native Spin-Entscheidungsvariable, und SQOA Solver akzeptiert binäre QUBO- Variablen. Deklariere daher bv∈{0,1}b_v \in \{0, 1\} und definiere den spinwertigen Ausdruck sv=1−2bvs_v = 1 - 2b_v innerhalb des Modells. Mit diesem Ausdruck bleibt die Zielfunktion in der Standard-Spin-Form, und die kompilierte Instanz bleibt ein binäres QUBO.

import jijmodeling as jm

@jm.Problem.define("MaxCut", sense=jm.ProblemSense.MAXIMIZE)
def maxcut_model(problem: jm.DecoratedProblem):
V = problem.Natural() # number of nodes
E = problem.Graph(dtype=V) # edge list
b = problem.BinaryVar(shape=(V,))
s = 1 - 2 * b # spin-valued expression

problem += jm.sum((1 - s[u] * s[v]) / 2 for u, v in E)

Wenn du maxcut_model in einem Notebook anzeigst, zeigt es die folgende Formulierung:

Problem ⁣:MaxCutmax⁡∑⟨u,v⟩∈E1−(1−2⋅b)u⋅(1−2⋅b)v2whereDecision Variables:bi∈{0,1}a 1-dim array of binary decision variables∀i∈{0,…,V−1}Placeholders:Ei∈V×Va 1-dim array of placeholders with elements in V×V∀i∈{0,…,len_at(E,0)−1}V∈Na scalar placeholder in N\begin{array}{rl} \text{Problem}\colon &\text{MaxCut}\\ \displaystyle \max &\displaystyle \sum _{\left\langle u,v\right\rangle \in E}{\frac{1-{\left(1-2\cdot b\right)}_{u}\cdot {\left(1-2\cdot b\right)}_{v}}{2}}\\ &\\ \text{where}&\\ &\text{Decision Variables:}\\ &\qquad \begin{alignedat}{2}{b}_{i}&\in \left\{0,1\right\}&\qquad &\text{a }1\text{-dim array of }\text{binary}\text{ decision variables}\\ &\forall i\in \left\{0,\ldots ,V-1\right\}&&\\ \end{alignedat}\\ &\\ &\text{Placeholders:}\\ &\qquad \begin{alignedat}{2}{E}_{i}&\in V\times V&\qquad &\text{a }1\text{-dim array of placeholders with elements in }V\times V\\ &\forall i\in \left\{0,\ldots ,\mathop{\mathtt{len\_{}at}}\left(E,0\right)-1\right\}&&\\ &&&\\ V&\in \mathbb{N}&\qquad &\text{a scalar placeholder in }\mathbb{N}\\ \end{alignedat}\end{array}

2. Die Instanz kompilieren und den Solver ausführen​

Binde den Graphen aus Beispiel 1, um eine ommx.v1.Instance zu kompilieren, und sende sie mit variable_type="binary" ab. Eine OMMX-Instanz wird immer als binäres Problem abgesendet.

instance = maxcut_model.eval(
{"V": G.number_of_nodes(), "E": [list(edge) for edge in G.edges]}
)

job = solver.run(
problem=to_problem_payload(instance),
variable_type="binary",
backend_name="ibm_fez",
)

3. Das Ergebnis abrufen​

Bei einer OMMX-Eingabe ist objective_value die Schnittgröße, und to_ommx_solution() dekodiert die kanonische Lösung, sodass du die Zuweisung nach Variablennamen lesen kannst.

result = job.result()
print(f"Cut value: {result['objective_value']}")

solution = to_ommx_solution(result)
b_values = solution.extract_decision_variables("b")
print(
f"Nodes on side 1: {sorted(v for (v,), value in b_values.items() if value > 0.5)}"
)
Cut value: 55.0
Nodes on side 1: [5, 7, 9, 11, 14, 16, 17, 19, 21, 23, 24, 26, 30, 31, 33, 34, 36, 37, 38]

Support erhalten​

Für Support schreibe eine E-Mail an info@j-ij.com.

Nächste Schritte​

Empfehlungen
  • Fordere über dieses Formular eine kostenlose Testversion von SQOA Solver an.
  • Besuche die API-Referenz für diese Qiskit Function.
  • Probiere ein End-to-End-Beispiel im Tutorial zum Maximum-Independent-Set-Problem aus.
  • Lerne, wie du Optimierungsprobleme mit qiskit-addon-opt-mapper modellierst.
  • Lerne, wie du Optimierungsprobleme mit JijModeling und OMMX modellierst und austauschst.
  • Lies die SQOA-QR-Veröffentlichung [1], um mehr über das SQOA-Framework zu erfahren.

Referenzen​

[1] Matsuyama, H., & Yamashiro, Y. (2025). Sampling-based quantum optimization algorithm with quantum relaxation. 2025 IEEE International Conference on Quantum Computing and Engineering (QCE), 1, 2323–2333. DOI, arXiv:2504.12629

[2] Fuller, B., Hadfield, C., Glick, J. R., Imamichi, T., Itoko, T., Thompson, R. J., Jiao, Y., Kagele, M. M., Blom-Schieber, A. W., Raymond, R., et al. (2024). Approximate solutions of combinatorial problems via quantum relaxations. IEEE Transactions on Quantum Engineering, 5, 1–15. DOI, arXiv:2111.03167

[3] Robledo-Moreno, J., Motta, M., Haas, H., Javadi-Abhari, A., Jurcevic, P., Kirby, W., et al. (2025). Chemistry beyond the scale of exact diagonalization on a quantum-centric supercomputer. Science Advances, 11(25), eadu9991. DOI, arXiv:2405.05068

[4] Kanno, K., Kohda, M., Imai, R., Koh, S., Mitarai, K., Mizukami, W., & Nakagawa, Y. O. (2026). Quantum-selected configuration interaction: Classical diagonalization of Hamiltonians in subspaces selected by quantum computers. Physical Review Research, 8(2), 023268. DOI, arXiv:2302.11320