{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "dde95705",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Constrained Quantum Optimizer – Eine Qiskit-Funktion von Aqarios\"\n",
        "description: \"Lösen Sie binäre Optimierungsprobleme mit Nebenbedingungen auf der „ IBM Quantum “-Hardware mithilfe des iterativen Warm-Start-QAOA-Verfahrens mit XY-Mixern von Aqarios.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore Aqarios QOBLIB Bucher docplex forall Zachary quicksum */}\n",
        "\n",
        "<span id=\"constrained-quantum-optimizer---a-qiskit-function-by-aqarios\" />\n",
        "\n",
        "# Constrained Quantum Optimizer – Eine Qiskit-Funktion von Aqarios\n",
        "\n",
        "*Siehe [API-Referenz](/docs/api/functions/aqarios-constrained-quantum-optimizer)*\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Qiskit Functions sind eine experimentelle Funktion, die ausschließlich Nutzern der Tarife „ IBM Quantum® Premium Plan “, „Flex Plan“ und „ On-Prem “ (über die „ IBM Quantum Platform “-API) zur Verfügung steht. Sie befinden sich im Preview-Status und können sich noch ändern.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "## Übersicht\n",
        "\n",
        "Mit dem „Constrained Quantum Optimizer“ von Aqarios können Sie binäre Optimierungsprobleme mit Nebenbedingungen auf der „ IBM® “-Quantenhardware lösen, ohne dass eine manuelle Neuformulierung und Schaltkreismappung erforderlich ist. Liefern Sie das Problem einfach als LP-Datei, MPS-Datei oder [Luna-Modell](https://docs.aqarios.com/luna-model). Die Funktion übernimmt automatisch die Umformulierung, die Schaltungssynthese, die Transpilation und die Hardware-Ausführung. Der Solver nutzt den iterativen Warm-Start [\\[1\\]](#references) des „ [FlexQAOA](https://docs.aqarios.com/luna-solve/algorithms/quantum-gate/flexqaoa/) “-Algorithmus, einer für Beschränkungen optimierten Erweiterung des Quantum Approximate Optimization Algorithm (QAOA).\n",
        "\n",
        "Der Optimierer ist auf binäre Probleme mit Nebenbedingungen ausgerichtet. Insbesondere können One-Hot-Beschränkungen und Set-Packing-Beschränkungen mithilfe von XY-Mixern nativ durchgesetzt werden. Andere Arten von Nebenbedingungen werden automatisch als Strafterme umformuliert.\n",
        "\n",
        "<Admonition type=\"note\" title=\"Unterstützte Variablentypen\">\n",
        "  Die Funktion löst ausschließlich diskrete Probleme. Jede Entscheidungsvariable muss binär sein oder eine Ganzzahl mit einer expliziten Unter- und Obergrenze, damit sie in Qubits kodiert werden kann. Kontinuierliche (reellwertige) Variablen werden nicht unterstützt: Ein Modell, das solche Variablen enthält, wird mit dem Fehlercode abgelehnt `4710`.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9f4110b",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8bcd63ea",
      "metadata": {},
      "source": [
        "<span id=\"description\" />\n",
        "\n",
        "## Beschreibung\n",
        "\n",
        "<Admonition type=\"caution\" title=\"Haftungsausschluss\">\n",
        "  Die Leistung kann sowohl von der konkreten Problemstellung als auch von den nachfolgenden Verarbeitungsschritten abhängen. In manchen Fällen können klassische Stichproben und quantengenerierte Stichproben nach einer gleichwertigen Nachbearbeitung eine ähnliche Qualität der Endlösung erzielen. Bei der Bewertung sollte daher der gesamte Optimierungsablauf berücksichtigt werden.\n",
        "</Admonition>\n",
        "\n",
        "Der „Constrained Quantum Optimizer“ implementiert den iterativen Warm-Start-XY-Mixer-QAOA (IWS-QAOA) [\\[1\\]](#references). Der Algorithmus führt QAOA-Schaltungen mit festem Winkel auf Quantenhardware aus und aktualisiert die anfänglichen Warm-Start-Wahrscheinlichkeiten jeder Schaltung anhand der Messergebnisse aus der vorherigen Iteration. Es ist kein Training mit Variationsparametern erforderlich; stattdessen wird eine feste lineare Rampenparametrisierung gewählt.\n",
        "\n",
        "Durch den Einsatz von XY-Mixern zur Durchsetzung von One-Hot-Beschränkungen lässt sich die Lösungsqualität bei beschränkten Problemen drastisch verbessern, da der Suchraum praktisch auf einen kleineren zulässigen Unterraum reduziert wird – und dabei keine zusätzliche Komplexität durch Strafterme in die Optimierungslandschaft eingeführt wird.\n",
        "\n",
        "<span id=\"workflow\" />\n",
        "\n",
        "### Arbeitsablauf\n",
        "\n",
        "Der Ablauf der Funktion wird im Folgenden beschrieben:\n",
        "\n",
        "1. **Vorverarbeitung** : Vor der Schaltungssynthese analysiert der Optimierer die Nebenbedingungsstruktur des Eingabeproblems:\n",
        "   * *Vorverarbeitung als Graph:* Sofern dies für das Problem relevant ist, wird es als Graph analysiert, wobei Kanten die Beziehungen zwischen den Variablen bestimmen. Diese Graphenanalyse ermöglicht zwei Verbesserungen bei der Vorverarbeitung. Zunächst können einzelne Nebenbedingungen mithilfe der Clique-Zusammenführung zu einer großen Nebenbedingung zusammengefasst werden, sodass sie durch einen einzigen XY-Mixer dargestellt werden. Zweitens können Variablen mit nur einem Nachbarn deterministisch festgelegt werden, wodurch sich der Umfang und die Komplexität des Problems verringern.\n",
        "   * *Auflösung von Nebenbedingungen:* Der Präprozessor behandelt jede Nebenbedingung separat: Handelt es sich um eine „One-Hot“-Nebenbedingung, kann diese mithilfe von XY-Mixern durchgesetzt werden. Handelt es sich um eine Set-Packing-Beschränkung, wird diese zunächst in eine One-Hot-Beschränkung umgewandelt. Gleichheitsbedingungen werden durch quadratische Straffunktionen berücksichtigt, Ungleichheitsbedingungen durch [eine asymmetrische Straffunktion](https://doi.org/10.1088/2058-9565/ad35e4).\n",
        "   * *Ableitung der Strafterme:* Einschränkungen, die nicht als One-Hot-Gleichheitsbedingungen ausgedrückt werden können, werden in Strafterme umgewandelt. Der Optimierer leitet die Stärke der Straffunktion automatisch aus der Problemstruktur ab.\n",
        "2. **Iterativer Warmstart** : Der Optimierer führt mehrere *parallele Warmstart-Ketten* aus. Jede Kette enthält eine Wahrscheinlichkeitsverteilung über Variablenzuordnungen, die als Startwahrscheinlichkeit der QAOA-Schaltung dient (Warm-Start-Zustand). Bei jeder Iteration entnimmt eine Kette Stichproben aus dem Quantenschaltkreis, führt eine klassische Nachbearbeitung durch und aktualisiert ihre Verteilung auf der Grundlage des Auftretens der Stichproben. Über mehrere Iterationen hinweg konzentriert dies die Suche auf hochwertige Lösungen, ohne dass eine Variationsoptimierungsschleife erforderlich ist.\n",
        "\n",
        "Die Anzahl der Ketten (`num_parallel`), das gesamte Schussbudget pro Kette (`total_shots`) und die Anzahl der QAOA-Wiederholungen (`reps`) sind die wichtigsten Steuergrößen für den Kompromiss zwischen Lösungsqualität und Laufzeit.\n",
        "\n",
        "![Ablaufdiagramm des Constrained Quantum Optimizer](https://quantum.cloud.ibm.com/docs/images/guides/aqarios-constrained-quantum-optimizer/cqo-diagram.svg)\n",
        "\n",
        "<span id=\"benchmarks\" />\n",
        "\n",
        "## Benchmarks\n",
        "\n",
        "Die folgenden Benchmark-Ergebnisse zeigen, dass die Qiskit-Funktion „Constrained Quantum Optimizer“ in der Lage ist, qualitativ hochwertige, realisierbare Lösungen für Optimierungsprobleme mit Nebenbedingungen und weit über 100 binären Variablen zu finden. Die Genauigkeit ist das Verhältnis des ermittelten objektiven Werts zum bekannten Optimum. Die Laufzeit ist die tatsächliche Zeit vom Aufruf der Funktion bis zur Ausgabe des Ergebnisses. Die QPU-Nutzung entspricht der abrechnungsfähigen Quantum-Compute-Zeit.\n",
        "\n",
        "Es wurden zwei Probleme untersucht: das Problem [der maximalen unabhängigen Menge](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer) (MIS) und das „Max- $k$ -Cut“-Problem, bei dem es sich um eine Erweiterung des bekannten Problems der maximalen unabhängigen Menge ( MaxCut ) auf mehr als zwei Kategorien handelt. Max- $k$ -Cut ist zudem das Optimierungsproblem, das dem Entscheidungsproblem der Graphenfärbung entspricht (wenn alle Kanten durchtrennt werden, ist der Graph „ $k$ -färbbar“).\n",
        "\n",
        "| Fehler                | Variablen | Einschränkungen | Qubits | Genauigkeit | Durchführbarkeit | Gesamtlaufzeit (s) | CPU-Auslastung (s) | Gesamtzahl der Schüsse |\n",
        "| --------------------- | --------- | --------------- | ------ | ----------- | ---------------- | ------------------ | ------------------ | ---------------------- |\n",
        "| MIS- es60fst02        | 186       | 280             | 124    | 100.0%      | Ja               | 940.2              | 147.0              | 25.0k                  |\n",
        "| MIS- sloane\\_2dc\\_128 | 128       | 5173            | 74     | 100.0%      | Ja               | 347.6              | 106.0              | 12.5k                  |\n",
        "| Max-3-Cut Karate-Club | 99        | 33              | 99     | 98.7%       | Ja               | 279.5              | 166.0              | 25.0k                  |\n",
        "| Max-4-Cut Karate-Club | 132       | 33              | 132    | 100.0%      | Ja               | 258.3              | 200.0              | 25.0k                  |\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f761442",
      "metadata": {},
      "source": [
        "<span id=\"benchmark-notes\" />\n",
        "\n",
        "### Benchmark-Hinweise\n",
        "\n",
        "* Die oben genannten Ergebnisse wurden auf dem `ibm_marrakesh` Heron- r2 -Prozessor mit den Standardoptionen und `use_session` aktivierter Funktion erzielt. In diesem `sloane_2dc_128` Fall `total_shots=12500` wurde … verwendet.\n",
        "* Die geringere Anzahl an Qubits bei MIS-Instanzen (74 und 124 gegenüber 128 und 186 Variablen) spiegelt die Festlegung von Variablen in der Vorverarbeitung wider.\n",
        "* Die Beispielinstanzen für MIS stammen aus der „[Quantum Optimization Benchmarking Library](https://doi.org/10.1038/s43588-026-00991-1) “. – Die Instanz für das Max- $k$ -Cut-Problem ist der [„Zachary Karate Club“-Graph](https://en.wikipedia.org/wiki/Zachary%27s_karate_club), der eine chromatische Zahl von 5 aufweist.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "73390a19",
      "metadata": {},
      "source": [
        "<span id=\"get-started\" />\n",
        "\n",
        "## Erste Schritte\n",
        "\n",
        "Diese Anleitung veranschaulicht die grundlegende Verwendung des „Constrained Quantum Optimizer“, indem sie zeigt, wie man die Funktion lädt und einfache Aufgaben ausführt. Eine ausführlichere Anleitung finden Sie unter „[Ermitteln der maximalen unabhängigen Menge mit dem Aqarios Constrained Quantum Optimizer](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer) “.\n",
        "\n",
        "Melden Sie sich mit Ihrem API-Schlüssel für die „ IBM Quantum “ und der Instanz- CRN an und laden Sie anschließend die Funktion aus dem Katalog.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Der folgende Code setzt voraus, dass Sie Ihre Anmeldedaten gespeichert haben. Befolgen Sie zur Einrichtung die Anweisungen unter „[Speichern Sie Ihre Anmeldedaten für das IBM Cloud -Konto](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) “.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "95a715d2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[QiskitFunction(aqarios/constrained-quantum-optimizer)]"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n",
        "\n",
        "# Verify that you have access to the function\n",
        "catalog.list()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "fe865158",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the function\n",
        "optimizer = catalog.load(\"aqarios/constrained-quantum-optimizer\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "d976e101",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[<IBMBackend('ibm_pittsburgh')>,\n",
              " <IBMBackend('ibm_boston')>,\n",
              " <IBMBackend('ibm_phoenix')>,\n",
              " <IBMBackend('ibm_fez')>,\n",
              " <IBMBackend('ibm_miami')>,\n",
              " <IBMBackend('ibm_marrakesh')>,\n",
              " <IBMBackend('ibm_kingston')>]"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Check the list of backends you have access to\n",
        "catalog.backends()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "6b0f5c79",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Select the backend you want to use\n",
        "backend = catalog.backend(\"ibm_phoenix\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e4445979",
      "metadata": {},
      "source": [
        "<span id=\"example-1-a-simple-constrained-problem\" />\n",
        "\n",
        "## Beispiel 1: Ein einfaches Problem mit Nebenbedingungen\n",
        "\n",
        "Das erste Beispiel zeigt, wie die Funktion mit [LP-Dateien](https://www.ibm.com/docs/icos/22.1.1?topic=cplex-lp-file-format-algebraic-representation) verwendet wird, einer gängigen Spezifikation für Optimierungsprobleme in der Operationsforschung. Sie formulieren das folgende beliebige Optimierungsproblem mit fünf binären Variablen $x_i \\in \\{0,1\\}$, das zwei Nebenbedingungen unterliegt:\n",
        "\n",
        "$$\n",
        "    \\min x_1 x_2 + 2 x_2 x_3 - x_3 x_4 - 2 x_4 x_5 - 2 x_1 x_3 - 4 x_2 x_5 \\\\\n",
        "    \\text{s.t.}\\quad x_1 + x_2 + x_3 \\leq 1 \\\\\n",
        "    \\quad x_3 - x_4 + x_5 = 0\n",
        "$$\n",
        "\n",
        "<span id=\"1-formulate-the-problem\" />\n",
        "\n",
        "### 1. Formulieren Sie das Problem\n",
        "\n",
        "Geben Sie den mathematischen Ausdruck direkt im folgenden LP-String-Format an:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7c3af25d",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "outputs": [],
      "source": [
        "lp_str = \"\"\"\\\\Problem name: Example\n",
        "Minimize\n",
        "  obj: [ 2 x_1 x_2 + 4 x_2 x_3 - 2 x_3 x_4 - 4 x_4 x_5 - 4 x_1 x_3 - 8 x_2 x_5 ] / 2\n",
        "Subject To\n",
        "  c1: x_1 + x_2 + x_3 <= 1\n",
        "  c2: x_3 - x_4 + x_5 = 0\n",
        "Binaries\n",
        "  x_1 x_2 x_3 x_4 x_5\n",
        "End\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6c75f9d",
      "metadata": {},
      "source": [
        "Beachten Sie, dass eine gemäß dem LP-Standard vorgeschriebene Notation für quadratische Zielfunktionen `[...] / 2` ist.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "003a933c",
      "metadata": {},
      "source": [
        "<span id=\"2-run-the-optimizer\" />\n",
        "\n",
        "### 2. Den Optimierer ausführen\n",
        "\n",
        "Lösen Sie das Problem mit dem Optimierer.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "242f1f89",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 2e06a3a8-7c29-4c76-94d7-194293363f4a\n"
          ]
        }
      ],
      "source": [
        "# Set up low-resource options for the simple problem\n",
        "options = {\"total_shots\": 2000, \"num_parallel\": 5, \"use_session\": True}\n",
        "\n",
        "# Dispatch the job\n",
        "job_1 = optimizer.run(\n",
        "    problem=lp_str, backend_name=backend.name, options=options\n",
        ")\n",
        "\n",
        "print(f\"Job ID: {job_1.job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "4bd4790a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'RUNNING: WAITING_FOR_QPU'"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job_1.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "acff0671",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"3-retrieve-the-result\" />\n",
        "\n",
        "### 3. Das Ergebnis abrufen\n",
        "\n",
        "Die Lösung, bei der die Variablennamen den zugehörigen Zuweisungen zugeordnet werden, ergibt sich aus dem Ergebnis.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6a121188",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'solutions': [{'x_1': 0, 'x_2': 1, 'x_3': 0, 'x_4': 1, 'x_5': 1}],\n",
              " 'solution_bitstrings': ['01011'],\n",
              " 'raw_energy': -6.0,\n",
              " 'objective_value': -6.0,\n",
              " 'feasible': True,\n",
              " 'metadata': {'resource_usage': {'RUNNING: MAPPING': {'CPU': 5.405},\n",
              "   'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU': 9.902},\n",
              "   'RUNNING: WAITING_FOR_QPU': {'CPU': 25.456},\n",
              "   'RUNNING: EXECUTING_QPU': {'CPU': 25.202},\n",
              "   'RUNNING: POST_PROCESSING': {'CPU': 6.481}},\n",
              "  'circuit_metrics': {'before_transpilation': {'num_qubits': 6,\n",
              "    'gate_count': 42,\n",
              "    'depth': 15,\n",
              "    'two_qubit_gate_count': 12,\n",
              "    'two_qubit_gate_depth': 7,\n",
              "    'operations': {'rz': 12,\n",
              "     'p': 8,\n",
              "     'ry': 7,\n",
              "     'rzz': 4,\n",
              "     'cx': 3,\n",
              "     'xx_plus_yy': 3,\n",
              "     'global_phase': 2,\n",
              "     'cry': 2,\n",
              "     'x': 1}},\n",
              "   'after_transpilation': {'num_qubits': 6,\n",
              "    'gate_count': 254,\n",
              "    'depth': 100,\n",
              "    'two_qubit_gate_count': 48,\n",
              "    'two_qubit_gate_depth': 33,\n",
              "    'operations': {'rz': 78, 'sx': 122, 'cz': 48, 'measure': 6, 'x': 0}}},\n",
              "  'solver_info': {'variable_mapping': {'x_1': 0,\n",
              "    'x_2': 1,\n",
              "    'x_3': 2,\n",
              "    'x_4': 3,\n",
              "    'x_5': 4}}}}"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result = job_1.result()\n",
        "\n",
        "result"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e8837f5f",
      "metadata": {},
      "source": [
        "Das `solutions` Feld im Rückgabewörterbuch enthält alle gefundenen degenerierten Bestlösungen in Form von Wörterbüchern, die jeden Variablennamen seiner Zuweisung zuordnen. Die gleichen Lösungen werden auch als Bitstrings zurückgegeben `solution_bitstrings`; `metadata.solver_info.variable_mapping` gibt an, welche Zeichenposition eines Bitstrings zu welcher Variablen gehört. Neben den Lösungsdaten `metadata` werden das `objective_value`, ein Flag `feasible` und weitere bereitgestellt.\n",
        "\n",
        "<span id=\"example-2-maximum-independent-set\" />\n",
        "\n",
        "## Beispiel 2: Maximale unabhängige Menge\n",
        "\n",
        "Beim Problem der maximalen unabhängigen Menge (MIS) soll die größte Teilmenge von Knoten in einem Graphen ermittelt werden, bei der sich keine zwei Knoten dieser Teilmenge eine Kante teilen. In diesem Beispiel wird das MIS-Problem auf einem regulären Graphen mit 12 Knoten gelöst. Weitere Informationen zu diesem Problem sowie ein ausführlicheres Beispiel finden Sie im [Tutorial](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer).\n",
        "\n",
        "Das Problem wurde mit [„qiskit-addon-opt-mapper“](https://github.com/qiskit/qiskit-addon-opt-mapper) erstellt.\n",
        "Installieren Sie gegebenenfalls die erforderlichen Pakete:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "a1e2f301",
      "metadata": {},
      "outputs": [],
      "source": [
        "# %pip install networkx qiskit-addon-opt-mapper"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d56e1440",
      "metadata": {},
      "source": [
        "<span id=\"step-1-define-the-problem\" />\n",
        "\n",
        "### Schritt 1: Das Problem definieren\n",
        "\n",
        "Erstellen Sie einen zufälligen 3-regulären Graphen und definieren Sie das MIS-Optimierungsproblem. Jeder Knoten des Graphen wird zu einer binären Variablen, und jede Kante führt eine Nebenbedingung ein, die sicherstellt, dass höchstens ein Endpunkt ausgewählt wird.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "03998691",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\\ This file has been generated by DOcplex\n",
            "\\ ENCODING=ISO-8859-1\n",
            "\\Problem name: Independent set\n",
            "\n",
            "Maximize\n",
            " obj: x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9 + x_10 + x_11\n",
            "Subject To\n",
            " c0: x_0 + x_4 <= 1\n",
            " c1: x_0 + x_9 <= 1\n",
            " c2: x_0 + x_8 <= 1\n",
            " c3: x_1 + x_2 <= 1\n",
            " c4: x_1 + x_7 <= 1\n",
            " c5: x_1 + x_3 <= 1\n",
            " c6: x_2 + x_4 <= 1\n",
            " c7: x_2 + x_11 <= 1\n",
            " c8: x_3 + x_10 <= 1\n",
            " c9: x_3 + x_11 <= 1\n",
            " c10: x_4 + x_5 <= 1\n",
            " c11: x_5 + x_10 <= 1\n",
            " c12: x_5 + x_6 <= 1\n",
            " c13: x_6 + x_8 <= 1\n",
            " c14: x_6 + x_7 <= 1\n",
            " c15: x_7 + x_9 <= 1\n",
            " c16: x_8 + x_11 <= 1\n",
            " c17: x_9 + x_10 <= 1\n",
            "\n",
            "Bounds\n",
            " 0 <= x_0 <= 1\n",
            " 0 <= x_1 <= 1\n",
            " 0 <= x_2 <= 1\n",
            " 0 <= x_3 <= 1\n",
            " 0 <= x_4 <= 1\n",
            " 0 <= x_5 <= 1\n",
            " 0 <= x_6 <= 1\n",
            " 0 <= x_7 <= 1\n",
            " 0 <= x_8 <= 1\n",
            " 0 <= x_9 <= 1\n",
            " 0 <= x_10 <= 1\n",
            " 0 <= x_11 <= 1\n",
            "\n",
            "Binaries\n",
            " x_0 x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 x_11\n",
            "End\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import networkx as nx\n",
        "from qiskit_addon_opt_mapper.applications import IndependentSet\n",
        "from qiskit_addon_opt_mapper.translators import to_docplex_mp\n",
        "\n",
        "# 12-node random 3-regular graph\n",
        "G = nx.random_regular_graph(3, 12, seed=7)\n",
        "\n",
        "# Build MIS problem and export as LP string\n",
        "mis = IndependentSet(G)\n",
        "mis_problem = mis.to_optimization_problem()\n",
        "lp_str = to_docplex_mp(mis_problem).export_as_lp_string()\n",
        "\n",
        "print(lp_str)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e6f7a8b9",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"step-2-run-the-optimizer\" />\n",
        "\n",
        "### Schritt 2: Den Optimierer ausführen\n",
        "\n",
        "Lösen Sie das Problem mit dem Optimierer.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "04236c83",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: f041431c-b42e-4627-afe5-522fea61faf6\n"
          ]
        }
      ],
      "source": [
        "options = {\"total_shots\": 2000, \"use_session\": True}\n",
        "\n",
        "# Dispatch the job\n",
        "job_2 = optimizer.run(\n",
        "    problem=lp_str, backend_name=backend.name, options=options\n",
        ")\n",
        "\n",
        "print(f\"Job ID: {job_2.job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "079ebc2f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'QUEUED'"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job_2.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "90c6de7c",
      "metadata": {},
      "source": [
        "<span id=\"step-3-retrieve-and-interpret-results\" />\n",
        "\n",
        "### Schritt 3: Ergebnisse abrufen und auswerten\n",
        "\n",
        "Schließlich rufen wir die Lösung ab und überprüfen sie auf ihre Richtigkeit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "f1a2b3c4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Feasible: True\n",
            "Independent set size: 5\n",
            "Selected nodes: [1, 4, 6, 9, 11]\n",
            "Edge conflicts: []\n"
          ]
        }
      ],
      "source": [
        "result = job_2.result()\n",
        "\n",
        "print(f\"Feasible: {result['feasible']}\")\n",
        "print(f\"Independent set size: {int(result['objective_value'])}\")\n",
        "\n",
        "# Extract the selected nodes\n",
        "solution = result[\"solutions\"][0]\n",
        "independent_set = [\n",
        "    int(k.split(\"_\")[1]) for k, v in solution.items() if v == 1\n",
        "]\n",
        "print(f\"Selected nodes: {sorted(independent_set)}\")\n",
        "\n",
        "# Verify no two selected nodes share an edge\n",
        "conflicts = [\n",
        "    (u, v)\n",
        "    for u, v in G.edges()\n",
        "    if u in independent_set and v in independent_set\n",
        "]\n",
        "print(f\"Edge conflicts: {conflicts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a2b3c4d5",
      "metadata": {},
      "source": [
        "<span id=\"example-3-graph-3-coloring-max-3-cut\" />\n",
        "\n",
        "## Beispiel 3: 3-Färbung von Graphen ( Max-3-Cut )\n",
        "\n",
        "Beim „Max- $k$ -Cut“-Problem werden die Knoten eines Graphen in „ $k$ “-Gruppen unterteilt, um die Anzahl der Kanten zu maximieren, deren Endpunkte zu unterschiedlichen Gruppen gehören. Für „ $k = 3$ “ entspricht dies der Suche nach einer 3-Färbung, die die Anzahl der Kanten mit unterschiedlichen Farben maximiert.\n",
        "\n",
        "Formell wird jedem Knoten $i \\in V$ eine der Gruppen $k$ mit den binären Variablen $x_{i,c}$ für die Farbe $c \\in \\{1, \\ldots, k\\}$ zugeordnet. Die One-Hot-Einschränkung $\\sum_c x_{i,c} = 1$ für jeden Knoten gewährleistet eine eindeutige Zuordnung. Das Ziel maximiert die Kanten zwischen den Gruppen:\n",
        "\n",
        "$$\n",
        "\\min \\sum_{(u,v) \\in E} \\sum_c x_{u,c} \\, x_{v,c}\\\\\n",
        "\\text{s.t.} \\sum_{c} x_{i,c} = 1 \\quad \\forall i \\in  V\n",
        "$$\n",
        "\n",
        "Die One-Hot-Beschränkungen eignen sich ideal für XY-Mischer, die vom Optimierer nativ verarbeitet werden.\n",
        "\n",
        "In diesem Beispiel wird der [Graph des](https://en.wikipedia.org/wiki/Zachary%27s_karate_club) Zachary Karate Club (34 Knoten, 78 Kanten) verwendet und das Modell mit dem [Luna-Modell](https://docs.aqarios.com/luna-model/) erstellt.\n",
        "Installieren Sie gegebenenfalls die erforderlichen Pakete:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "b3c4d5e6",
      "metadata": {},
      "outputs": [],
      "source": [
        "# %pip install networkx matplotlib luna-model"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4d5e6f7",
      "metadata": {},
      "source": [
        "<span id=\"step-1-define-the-problem\" />\n",
        "\n",
        "### Schritt 1: Das Problem definieren\n",
        "\n",
        "Erstellen Sie zunächst die binären Variablen mit dem Paket `luna-model` . Definieren Sie anschließend das Ziel und fügen Sie die Nebenbedingungen zum Modell hinzu.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "d5e6f7a8",
      "metadata": {},
      "outputs": [],
      "source": [
        "import networkx as nx\n",
        "from luna_model import Model, quicksum\n",
        "\n",
        "k = 3\n",
        "G = nx.karate_club_graph()\n",
        "\n",
        "# Instantiate the Model object\n",
        "model = Model(name=\"Max-3-Cut\")\n",
        "\n",
        "# Add binary variables\n",
        "x = model.add_variables(\"x\", shape=(G.number_of_nodes(), k))\n",
        "\n",
        "# Add the objective by using the numpy dot abstraction\n",
        "model.objective = quicksum(x[i].dot(x[j]) for i, j in G.edges)\n",
        "\n",
        "# Bulk-add the one-hot constraints\n",
        "model.add_constraints(x.sum(axis=1) == 1)\n",
        "\n",
        "# Encode the model to send via API\n",
        "model_enc = model.encode_b64()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "263ccb5d",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"step-2-run-the-optimizer\" />\n",
        "\n",
        "### Schritt 2: Den Optimierer ausführen\n",
        "\n",
        "Lösen Sie das Problem mit dem Optimierer.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f7a8b9c0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: df911d83-9df7-44a1-bfad-5d66e08676c3\n"
          ]
        }
      ],
      "source": [
        "options = {\"use_session\": True}\n",
        "\n",
        "# Dispatch the job\n",
        "job_3 = optimizer.run(\n",
        "    problem=model_enc, backend_name=backend.name, options=options\n",
        ")\n",
        "\n",
        "print(f\"Job ID: {job_3.job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "e2ff9b51",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'RUNNING: WAITING_FOR_QPU'"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job_3.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a8b9c0d1",
      "metadata": {},
      "source": [
        "<span id=\"step-3-retrieve-and-visualize-results\" />\n",
        "\n",
        "### Schritt 3: Ergebnisse abrufen und visualisieren\n",
        "\n",
        "Die Ergebnisse abrufen und visualisieren.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "b9c0d1e2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Feasible: True\n",
            "Violations: 4\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/aqarios-constrained-quantum-optimizer/extracted-outputs/b9c0d1e2-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "result = job_3.result()\n",
        "solution = result[\"solutions\"][0]\n",
        "\n",
        "# Map each node to its assigned color group\n",
        "node_group = {}\n",
        "for i in G.nodes:\n",
        "    for c in range(k):\n",
        "        if solution[f\"x{i},{c}\"] == 1:\n",
        "            node_group[i] = c\n",
        "\n",
        "print(f\"Feasible: {result['feasible']}\")\n",
        "print(f\"Violations: {int(result['objective_value'])}\")\n",
        "\n",
        "# Visualize the partition\n",
        "colors = [\"tab:blue\", \"tab:orange\", \"tab:green\"]\n",
        "node_colors = [colors[node_group[i]] for i in G.nodes()]\n",
        "nx.draw(G, nx.kamada_kawai_layout(G), node_color=node_colors, node_size=200)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f1a7c02",
      "metadata": {},
      "source": [
        "<span id=\"changelog\" />\n",
        "\n",
        "## Änderungsprotokoll\n",
        "\n",
        "<span id=\"[040]---2026-09-22\" />\n",
        "\n",
        "### \\[0.4.0] - 22.09.2026\n",
        "\n",
        "**Schwerwiegende Änderungen**\n",
        "\n",
        "* Der Eingabeparameter wurde `model` in umbenannt `problem`.\n",
        "* Das Ausgabefeld wurde `obj_value` in umbenannt `objective_value`.\n",
        "* Die Option `postprocessing` wurde durch ersetzt `postprocessing_level`, die `[0, 3]` anstelle einer Zeichenkette eine Ganzzahl im Bereich akzeptiert. Die bisherigen Werte entsprechen `\"off\"` -> `0`, `\"weak\"` -> `1`, `\"medium\"` -> und `\"strong\"` -> `2``3`, und der Standardwert bleibt unverändert bei `3`.\n",
        "* Umstrukturiert `metadata.circuit_metrics`. Es meldet nun `num_qubits`, `gate_count`, `depth`, `two_qubit_gate_count`, `two_qubit_gate_depth`, und separat `operations` für `before_transpilation` und `after_transpilation`, anstatt eines einzigen pauschalen Verzeichnisses mit gemittelten Gate-Zahlen. Das Feld ist, wenn `None` das Problem während der Vorverarbeitung gelöst wurde und kein Schaltkreis durchlaufen wurde (Fehlercode `4712`).\n",
        "\n",
        "**Funktionen**\n",
        "\n",
        "* Es wurde die Option `seed_transpiler` hinzugefügt, mit der die Schaltungssynthese und das Routing über mehrere Durchläufe hinweg reproduzierbar gemacht werden können.\n",
        "* Es wurde die Option `job_tags` hinzugefügt, jedem von der Funktion übermittelten „ Qiskit Runtime “-Auftrag eigene Tags hinzuzufügen.\n",
        "* Das Ausgabefeld wurde hinzugefügt `solution_bitstrings`, das dieselben Lösungen wie `solutions` in Form einer Bitfolge zurückgibt.\n",
        "* Es wurde hinzugefügt `metadata.solver_info.variable_mapping`, wodurch jeder Variablenname seiner Zeichenposition in den Einträgen von zugeordnet wird `solution_bitstrings`.\n",
        "\n",
        "**Dokumentation**\n",
        "\n",
        "* Es wurde dokumentiert, dass kontinuierliche (reellwertige) Variablen nicht unterstützt werden und dass ganzzahlige Variablen explizite Grenzwerte erfordern. Solche Modelle schlagen mit dem Fehlercode … fehl `4710`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9ec2e67",
      "metadata": {},
      "source": [
        "<span id=\"get-support\" />\n",
        "\n",
        "## Unterstützung anfordern\n",
        "\n",
        "Bei Fragen oder Problemen wenden Sie sich bitte unter Angabe Ihrer Auftrags-ID an [support@aqarios.com](mailto:support@aqarios.com).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a6a25c8",
      "metadata": {
        "jp-MarkdownHeadingCollapsed": true
      },
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  * [Beantragen Sie Zugriff auf den „Constrained Quantum Optimizer“ von Aqarios](https://aqarios.com/qiskit-function-access/).\n",
        "  * Die vollständige Dokumentation zu den Parametern und Ausgaben finden Sie in der [API-Referenz](/docs/api/functions/aqarios-constrained-quantum-optimizer).\n",
        "  * Probieren Sie das Tutorial [„Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer“](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer) aus, um einen detaillierten Einblick in eine echte QOBLIB-Benchmark-Instanz zu erhalten.\n",
        "  * Lesen Sie den Artikel „[Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers](https://doi.org/10.1088/1367-2630/ae8ea2) “.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c0a20cb",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Referenzen\n",
        "\n",
        "1. Bucher et al. (2026), *„Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers“* [10.1088/1367-2630/ae8ea2](https://doi.org/10.1088/1367-2630/ae8ea2)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}