{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "title",
      "metadata": {},
      "source": [
        "---\n",
        "title: Solve the Market Split problem with Kipu Quantum's Iskay Quantum Optimizer\n",
        "description: Learn how to solve the Market Split problem using the Iskay Quantum Optimizer with the bf-DCQO algorithm on IBM Quantum hardware\n",
        "---\n",
        "\n",
        "# Solve the Market Split problem with Kipu Quantum's Iskay Quantum Optimizer\n",
        "\n",
        "{/* cspell:ignore adiabaticity, HUBO, bitflip, metaheuristic, fontweight, fontsize, QOBLIB, Zuse, Kochenberger, Tramontani, Weninger, edgecolor, nonumber */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "note",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\" title=\"Note\">\n",
        "  Qiskit Functions are an experimental feature available only to IBM Quantum® Premium Plan, Flex Plan, and On-Prem (via IBM Quantum Platform API) Plan users. They are in preview release status and subject to change.\n",
        "</Admonition>\n",
        "\n",
        "*Usage estimate: 20 seconds on a Heron r2 processor. (NOTE: This is an estimate only. Your runtime might vary.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "background",
      "metadata": {},
      "source": [
        "## Background\n",
        "\n",
        "This tutorial demonstrates how to solve the Market Split problem using [Kipu Quantum's Iskay quantum optimizer](/docs/guides/kipu-optimization) [\\[1\\]](#references). The Market Split problem represents a real-world resource allocation challenge where markets must be partitioned into balanced sales regions to meet exact demand targets.\n",
        "\n",
        "### The Market Split challenge\n",
        "\n",
        "The Market Split problem presents a deceptively simple yet computationally formidable challenge in resource allocation. Consider a company with $m$ products being sold across $n$ different markets, where each market purchases a specific bundle of products (represented by the columns of matrix $A$). The business objective is to partition these markets into two balanced sales regions such that each region receives exactly half the total demand for every product.\n",
        "\n",
        "**Mathematical formulation:**\n",
        "\n",
        "We seek a binary assignment vector $x$, where:\n",
        "\n",
        "* $x_j = 1$ assigns market $j$ to Region A\n",
        "* $x_j = 0$ assigns market $j$ to Region B\n",
        "* The constraint $Ax = b$ must be satisfied, where $b$ represents the target sales (typically half the total demand per product)\n",
        "\n",
        "**Cost function:**\n",
        "\n",
        "To solve this problem, we minimize the squared constraint violation:\n",
        "\n",
        "$C(x) = ||Ax - b||^2 = \\sum_{i=1}^{m} \\left(\\sum_{j=1}^{n} A_{ij}x_j - b_i\\right)^2$\n",
        "\n",
        "where:\n",
        "\n",
        "* $A_{ij}$ represents the sales of product $i$ in market $j$\n",
        "* $x_j \\in \\{0,1\\}$ is the binary assignment of market $j$\n",
        "* $b_i$ is the target sales for product $i$ in each region\n",
        "* The cost equals zero precisely when all constraints are satisfied\n",
        "\n",
        "Each term in the sum represents the squared deviation from the target sales for a particular product. When we expand this cost function, we get:\n",
        "\n",
        "$C(x) = x^T A^T A x - 2b^T A x + b^T b$\n",
        "\n",
        "Since $b^T b$ is a constant, minimizing $C(x)$ is equivalent to minimizing the quadratic function $x^T A^T A x - 2b^T A x$, which is exactly a QUBO (Quadratic Unconstrained Binary Optimization) problem.\n",
        "\n",
        "**Computational complexity:**\n",
        "\n",
        "Despite its straightforward business interpretation, this problem exhibits remarkable computational intractability:\n",
        "\n",
        "* **Small-scale failure**: Conventional Mixed Integer Programming solvers fail on instances with as few as seven products under a timeout of one hour [\\[4\\]](#references)\n",
        "* **Exponential growth**: The solution space grows exponentially ($2^n$ possible assignments), making brute force approaches infeasible\n",
        "\n",
        "This severe computational barrier, combined with its practical relevance to territory planning and resource allocation, makes the Market Split problem an ideal benchmark for quantum optimization algorithms [\\[4\\]](#references).\n",
        "\n",
        "### What makes Iskay's approach unique?\n",
        "\n",
        "The Iskay optimizer uses the **bf-DCQO (bias-field digitized counterdiabatic quantum optimization)** algorithm [\\[1\\]](#references), which represents a significant advancement in quantum optimization:\n",
        "\n",
        "**Circuit efficiency**: The bf-DCQO algorithm achieves remarkable gate reduction [\\[1\\]](#references):\n",
        "\n",
        "* Up to **10 times fewer entangling gates** than Digital Quantum Annealing (DQA)\n",
        "* Significantly shallower circuits enable:\n",
        "  * Less error accumulation during quantum execution\n",
        "  * Ability to tackle larger problems on current quantum hardware\n",
        "  * No need for error mitigation techniques\n",
        "\n",
        "**Non-variational design**: Unlike variational algorithms requiring approximately 100 iterations, bf-DCQO typically needs only **approximately 10 iterations** [\\[1\\]](#references). This is achieved through:\n",
        "\n",
        "* Intelligent bias-field calculations from measured state distributions\n",
        "* Starting each iteration from an energy state near the previous solution\n",
        "* Integrated classical post-processing with local search\n",
        "\n",
        "**Counterdiabatic protocols**: The algorithm incorporates counterdiabatic terms that suppress unwanted quantum excitations during short evolution times, enabling the system to remain near the ground state even with rapid transitions [\\[1\\]](#references).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "requirements",
      "metadata": {},
      "source": [
        "## Requirements\n",
        "\n",
        "Before starting this tutorial, ensure that you have the following installed:\n",
        "\n",
        "* Qiskit IBM Runtime (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Functions (`pip install qiskit-ibm-catalog`)\n",
        "* NumPy (`pip install numpy`)\n",
        "* Requests (`pip install requests`)\n",
        "* Opt Mapper Qiskit addon (`pip install qiskit-addon-opt-mapper`)\n",
        "\n",
        "You will also need to get access to the [Iskay Quantum Optimizer function](/functions?id=kipu-quantum-iskay-quantum-optimizer) from the Qiskit Functions Catalog.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "setup",
      "metadata": {},
      "source": [
        "## Setup\n",
        "\n",
        "First, import all required packages for this tutorial.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "imports",
      "metadata": {},
      "outputs": [],
      "source": [
        "import os\n",
        "import tempfile\n",
        "import time\n",
        "from typing import Tuple, Optional\n",
        "\n",
        "import numpy as np\n",
        "import requests\n",
        "\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "from qiskit_addon_opt_mapper import OptimizationProblem\n",
        "from qiskit_addon_opt_mapper.converters import OptimizationProblemToQubo\n",
        "\n",
        "print(\"All required libraries imported successfully\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "credentials",
      "metadata": {},
      "source": [
        "### Configure IBM Quantum credentials\n",
        "\n",
        "Define your [IBM Quantum® Platform](/) credentials. You will need:\n",
        "\n",
        "* **API Token**: Your 44-character API key from IBM Quantum Platform\n",
        "* **Instance CRN**: Your IBM Cloud® instance identifier\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "creds",
      "metadata": {},
      "outputs": [],
      "source": [
        "token = \"<YOUR_API_KEY>\"\n",
        "instance = \"<YOUR_INSTANCE_CRN>\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step1",
      "metadata": {},
      "source": [
        "## Step 1: Map classical inputs to a quantum problem\n",
        "\n",
        "We begin by mapping our classical problem to a quantum-compatible representation. This step involves:\n",
        "\n",
        "1. Connecting to the Iskay Quantum Optimizer\n",
        "2. Loading and formulating the Market Split problem\n",
        "3. Understanding the bf-DCQO algorithm that will solve it\n",
        "\n",
        "### Connect to Iskay Quantum Optimizer\n",
        "\n",
        "We begin by establishing a connection to the Qiskit Functions Catalog and loading the Iskay Quantum Optimizer. The Iskay Optimizer is a quantum function provided by Kipu Quantum that implements the bf-DCQO algorithm for solving optimization problems on quantum hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "load_solver",
      "metadata": {},
      "outputs": [],
      "source": [
        "catalog = QiskitFunctionsCatalog(token=token, instance=instance)\n",
        "iskay_solver = catalog.load(\"kipu-quantum/iskay-quantum-optimizer\")\n",
        "\n",
        "print(\"Iskay optimizer loaded successfully\")\n",
        "print(\"Ready to solve optimization problems using bf-DCQO algorithm\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step2",
      "metadata": {},
      "source": [
        "### Load and formulate the problem\n",
        "\n",
        "#### Understand the problem data format\n",
        "\n",
        "Problem instances from QOBLIB (Quantum Optimization Benchmarking Library) [\\[2\\]](#references) are stored in a simple text format. Let's examine the actual content of our target instance `ms_03_200_177.dat`:\n",
        "\n",
        "```text\n",
        "3 20\n",
        "60   92  161   53   97    2   75   81    6  139  132   45  108  112  181   93  152  200  164   51 1002\n",
        "176  196   41  143    2   88    0   79   10   71   75  148   82  135   34  187   33  155   58   46  879\n",
        "68   68  179  173  127  163   48   49   99   78   44   52  173  131   73  198   84  109  180   95 1040\n",
        "```\n",
        "\n",
        "**Format structure:**\n",
        "\n",
        "* **First line:** `3 20`\n",
        "  * `3` = number of products (constraints/rows in matrix $A$)\n",
        "  * `20` = number of markets (variables/columns in matrix $A$)\n",
        "\n",
        "* **Next 3 lines:** Coefficient matrix $A$ and target vector $b$\n",
        "  * Each line has 21 numbers: first 20 are row coefficients, last is the target\n",
        "  * Line 2: `60 92 161 ... 51 | 1002`\n",
        "    * First 20 numbers: How much of Product 1 each of the 20 markets sells\n",
        "    * Last number (1002): Target sales for Product 1 in one region\n",
        "  * Line 3: `176 196 41 ... 46 | 879`\n",
        "    * Product 2 sales per market and target (879)\n",
        "  * Line 4: `68 68 179 ... 95 | 1040`\n",
        "    * Product 3 sales per market and target (1040)\n",
        "\n",
        "**Business interpretation:**\n",
        "\n",
        "* Market 0 sells: 60 units of Product 1, 176 units of Product 2, 68 units of Product 3\n",
        "* Market 1 sells: 92 units of Product 1, 196 units of Product 2, 68 units of Product 3\n",
        "* And so on for all 20 markets...\n",
        "* **Goal**: Split these 20 markets into two regions where each region gets exactly 1002 units of Product 1, 879 units of Product 2, and 1040 units of Product 3\n",
        "\n",
        "#### QUBO transformation\n",
        "\n",
        "## From constraints to QUBO: the mathematical transformation\n",
        "\n",
        "The power of quantum optimization lies in transforming constrained problems into unconstrained quadratic forms [\\[4\\]](#references). For the Market Split problem, we convert the equality constraints\n",
        "\n",
        "$Ax = b$\n",
        "\n",
        "where $x ∈ \\{0,1\\}^n$, into a QUBO by penalizing constraint violations.\n",
        "\n",
        "**The penalty method:**\n",
        "Since we need $Ax = b$ to hold exactly, we minimize the squared violation:\n",
        "$f(x) = ||Ax - b||^2$\n",
        "\n",
        "This equals zero precisely when all constraints are satisfied. Expanding algebraically:\n",
        "$f(x) = (Ax - b)^T(Ax - b) = x^T A^T A x - 2b^T A x + b^T b$\n",
        "\n",
        "**QUBO objective:**\n",
        "Since $b^T b$ is constant, our optimization becomes:\n",
        "$\\text{minimize} \\quad Q(x) = x^T(A^T A)x - 2(A^T b)^T x$\n",
        "\n",
        "**Key insight:** This transformation is exact, not approximate. Equality constraints naturally square into quadratic form without requiring auxiliary variables or penalty parameters - making this formulation mathematically elegant and computationally efficient for quantum solvers [\\[4\\]](#references). We'll use the `OptimizationProblem` class to define our constrained problem, then convert it to QUBO format using `OptimizationProblemToQubo`, both from the **qiskit\\_addon\\_opt\\_mapper** package. This automatically handles the penalty-based transformation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "functions_intro",
      "metadata": {},
      "source": [
        "### Implement data loading and QUBO conversion functions\n",
        "\n",
        "We now define three utility functions:\n",
        "\n",
        "1. `parse_marketsplit_dat()` - Parses the `.dat` file format and extracts matrices $A$ and $b$\n",
        "2. `fetch_marketsplit_data()` - Downloads problem instances directly from the QOBLIB repository\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "functions",
      "metadata": {},
      "outputs": [],
      "source": [
        "def parse_marketsplit_dat(filename: str) -> Tuple[np.ndarray, np.ndarray]:\n",
        "    \"\"\"\n",
        "    Parse a market split problem from a .dat file format.\n",
        "\n",
        "    Parameters\n",
        "    ----------\n",
        "    filename : str\n",
        "        Path to the .dat file containing the market split problem data.\n",
        "\n",
        "    Returns\n",
        "    -------\n",
        "    A : np.ndarray\n",
        "        Coefficient matrix of shape (m, n) where m is the number of products\n",
        "        and n is the number of markets.\n",
        "    b : np.ndarray\n",
        "        Target vector of shape (m,) containing the target sales per product.\n",
        "    \"\"\"\n",
        "    with open(filename, \"r\", encoding=\"utf-8\") as f:\n",
        "        lines = [\n",
        "            line.strip()\n",
        "            for line in f\n",
        "            if line.strip() and not line.startswith(\"#\")\n",
        "        ]\n",
        "\n",
        "    if not lines:\n",
        "        raise ValueError(\"Empty or invalid .dat file\")\n",
        "\n",
        "    # First line: m n (number of products and markets)\n",
        "    m, n = map(int, lines[0].split())\n",
        "\n",
        "    # Next m lines: each row of A followed by corresponding element of b\n",
        "    A, b = [], []\n",
        "    for i in range(1, m + 1):\n",
        "        values = list(map(int, lines[i].split()))\n",
        "        A.append(values[:-1])  # First n values: product sales per market\n",
        "        b.append(values[-1])  # Last value: target sales for this product\n",
        "\n",
        "    return np.array(A, dtype=np.int32), np.array(b, dtype=np.int32)\n",
        "\n",
        "\n",
        "def fetch_marketsplit_data(\n",
        "    instance_name: str = \"ms_03_200_177.dat\",\n",
        ") -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]:\n",
        "    \"\"\"\n",
        "    Fetch market split data directly from the QOBLIB repository.\n",
        "\n",
        "    Parameters\n",
        "    ----------\n",
        "    instance_name : str\n",
        "        Name of the .dat file to fetch (default: \"ms_03_200_177.dat\").\n",
        "\n",
        "    Returns\n",
        "    -------\n",
        "    A : np.ndarray or None\n",
        "        Coefficient matrix if successful, None if failed.\n",
        "    b : np.ndarray or None\n",
        "        Target vector if successful, None if failed.\n",
        "    \"\"\"\n",
        "    url = f\"https://git.zib.de/qopt/qoblib-quantum-optimization-benchmarking-library/-/raw/main/01-marketsplit/instances/{instance_name}\"\n",
        "\n",
        "    try:\n",
        "        response = requests.get(url, timeout=30)\n",
        "        response.raise_for_status()\n",
        "\n",
        "        with tempfile.NamedTemporaryFile(\n",
        "            mode=\"w\", suffix=\".dat\", delete=False, encoding=\"utf-8\"\n",
        "        ) as f:\n",
        "            f.write(response.text)\n",
        "            temp_path = f.name\n",
        "\n",
        "        try:\n",
        "            return parse_marketsplit_dat(temp_path)\n",
        "        finally:\n",
        "            os.unlink(temp_path)\n",
        "    except Exception as e:\n",
        "        print(f\"Error: {e}\")\n",
        "        return None, None"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "load_intro",
      "metadata": {},
      "source": [
        "### Load the problem instance\n",
        "\n",
        "Now we load the specific problem instance `ms_03_200_177.dat` from QOBLIB \\[2]. This instance has:\n",
        "\n",
        "* 3 products (constraints)\n",
        "* 20 markets (binary decision variables)\n",
        "* Over 1 million possible market assignments to explore ($2^{20} = 1,048,576$)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "load",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the problem instance\n",
        "instance_name = \"ms_03_200_177.dat\"\n",
        "A, b = fetch_marketsplit_data(instance_name=instance_name)\n",
        "\n",
        "if A is not None:\n",
        "    print(\"Successfully loaded problem instance from QOBLIB\")\n",
        "    print(\"\\nProblem Instance Analysis:\")\n",
        "    print(\"=\" * 50)\n",
        "    print(f\"Coefficient Matrix A: {A.shape[0]} × {A.shape[1]}\")\n",
        "    print(f\"   → {A.shape[0]} products (constraints)\")\n",
        "    print(f\"   → {A.shape[1]} markets (decision variables)\")\n",
        "    print(f\"Target Vector b: {b}\")\n",
        "    print(\"   → Target sales per product for each region\")\n",
        "    print(\n",
        "        f\"Solution Space: \"\n",
        "        f\"2^{A.shape[1]} = {2**A.shape[1]:,} possible assignments\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "convert_intro",
      "metadata": {},
      "source": [
        "### Convert to QUBO format\n",
        "\n",
        "We now transform the constrained optimization problem into QUBO format:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "convert",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Create optimization problem\n",
        "ms = OptimizationProblem(instance_name.replace(\".dat\", \"\"))\n",
        "\n",
        "# Add binary variables (one for each market)\n",
        "ms.binary_var_list(A.shape[1])\n",
        "\n",
        "# Add equality constraints (one for each product)\n",
        "for idx, rhs in enumerate(b):\n",
        "    ms.linear_constraint(A[idx, :], sense=\"==\", rhs=rhs)\n",
        "\n",
        "# Convert to QUBO with penalty parameter\n",
        "qubo = OptimizationProblemToQubo(penalty=1).convert(ms)\n",
        "\n",
        "print(\"QUBO Conversion Complete:\")\n",
        "print(\"=\" * 50)\n",
        "print(f\"Number of variables: {qubo.get_num_vars()}\")\n",
        "print(f\"Constant term: {qubo.objective.constant}\")\n",
        "print(f\"Linear terms: {len(qubo.objective.linear.to_dict())}\")\n",
        "print(f\"Quadratic terms: {len(qubo.objective.quadratic.to_dict())}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1d307072",
      "metadata": {},
      "source": [
        "### Convert QUBO to Iskay format\n",
        "\n",
        "Now we need to convert the QUBO object into the dictionary format required by Kipu Quantum's Iskay Optimizer.\n",
        "\n",
        "The `problem` and `problem_type` arguments encode an optimization problem of the form\n",
        "\n",
        "$$\n",
        "\\begin{align}\n",
        "\\min_{(x_1, x_2, \\ldots, x_n) \\in D} C(x_1, x_2, \\ldots, x_n) \\nonumber\n",
        "\\end{align}\n",
        "$$\n",
        "\n",
        "where\n",
        "\n",
        "$$\n",
        "C(x_1, ... , x_n) = a + \\sum_{i} b_i x_i + \\sum_{i, j} c_{i, j} x_i x_j + ... + \\sum_{k_1, ..., k_m} g_{k_1, ..., k_m} x_{k_1} ... x_{k_m}\n",
        "$$\n",
        "\n",
        "* By choosing `problem_type = \"binary\"`, you specify that the cost function is in `binary` format, which means that $D = \\{0,  1\\}^{n}$, as in, the cost function is written in QUBO/HUBO formulation.\n",
        "* On the other hand, by choosing `problem_type = \"spin\"`, the cost function is written in Ising formulation, where $D = \\{-1, 1\\}^{n}$.\n",
        "\n",
        "The coefficients of the problem should be encoded in a dictionary as follows:\n",
        "\n",
        "$$\n",
        "\\begin{align} \\nonumber\n",
        "&\\texttt{\\{} \\\\ \\nonumber\n",
        "&\\texttt{\"()\"}&: \\quad &a, \\\\ \\nonumber\n",
        "&\\texttt{\"(i,)\"}&: \\quad &b_i, \\\\ \\nonumber\n",
        "&\\texttt{\"(i, j)\"}&: \\quad &c_{i, j}, \\quad (i \\neq j) \\\\ \\nonumber\n",
        "&\\quad  \\vdots \\\\ \\nonumber\n",
        "&\\texttt{\"(} k_1, ..., k_m  \\texttt{)\"}&: \\quad &g_{k_1, ..., k_m}, \\quad (k_1 \\neq k_2 \\neq \\dots \\neq k_m) \\\\ \\nonumber\n",
        "&\\texttt{\\}}\n",
        "\\end{align}\n",
        "$$\n",
        "\n",
        "Note that the keys of the dictionary must be strings containing a valid tuple of non-repeating integers. For binary problems, we know that:\n",
        "\n",
        "$$\n",
        "x_i^2 = x_i\n",
        "$$\n",
        "\n",
        "for $i=j$ (since $x_i \\in \\{0,1\\}$ means $x_i \\cdot x_i = x_i$). So, in your QUBO formulation, if you have both linear contributions $b_i x_i$ and diagonal quadratic contributions $c_{i,i} x_i^2$, these terms must be combined into a single linear coefficient:\n",
        "\n",
        "**Total linear coefficient for variable $x_i$:** $b_i + c_{i,i}$\n",
        "\n",
        "This means:\n",
        "\n",
        "* Linear terms like `\"(i, )\"` contain: original linear coefficient + diagonal quadratic coefficient\n",
        "* Diagonal quadratic terms like `\"(i, i)\"` should **NOT** appear in the final dictionary\n",
        "* Only off-diagonal quadratic terms like `\"(i, j)\"` where $i \\neq j$ should be included as separate entries\n",
        "\n",
        "**Example:** If your QUBO has $3x_1 + 2x_1^2 + 4x_1 x_2$, the Iskay dictionary should contain:\n",
        "\n",
        "* `\"(0, )\"`: `5.0` (combining $3 + 2 = 5$)\n",
        "* `\"(0, 1)\"`: `4.0` (off-diagonal term)\n",
        "\n",
        "**NOT** separate entries for `\"(0, )\"`: `3.0` and `\"(0, 0)\"`: `2.0`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "57eda6fd",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Convert QUBO to Iskay dictionary format:\n",
        "\n",
        "# Create empty Iskay input dictionary\n",
        "iskay_input_problem = {}\n",
        "\n",
        "# Convert QUBO to Iskay dictionary format\n",
        "iskay_input_problem = {\"()\": qubo.objective.constant}\n",
        "\n",
        "for i in range(qubo.get_num_vars()):\n",
        "    for j in range(i, qubo.get_num_vars()):\n",
        "        if i == j:\n",
        "            # Add linear term (including diagonal quadratic contribution)\n",
        "            iskay_input_problem[f\"({i}, )\"] = float(\n",
        "                qubo.objective.linear.to_dict().get(i)\n",
        "            ) + float(qubo.objective.quadratic.to_dict().get((i, i)))\n",
        "        else:\n",
        "            # Add off-diagonal quadratic term\n",
        "            iskay_input_problem[f\"({i}, {j})\"] = float(\n",
        "                qubo.objective.quadratic.to_dict().get((i, j))\n",
        "            )\n",
        "\n",
        "# Display Iskay dictionary summary\n",
        "print(\"Iskay Dictionary Format:\")\n",
        "print(\"=\" * 50)\n",
        "print(f\"Total coefficients: {len(iskay_input_problem)}\")\n",
        "print(f\"  • Constant term: {iskay_input_problem['()']}\")\n",
        "print(\n",
        "    f\"  • Linear terms: \"\n",
        "    f\"{sum(1 for k in iskay_input_problem.keys() if k != '()' and ', )' in k)}\"\n",
        ")\n",
        "print(\n",
        "    f\"  • Quadratic terms: \"\n",
        "    f\"{sum(1 for k in iskay_input_problem.keys() if k != '()' and ', )' not in k)}\"\n",
        ")\n",
        "print(\"\\nSample coefficients:\")\n",
        "\n",
        "# Get first 10 and last 5 items properly\n",
        "items = list(iskay_input_problem.items())\n",
        "first_10 = list(enumerate(items[:10]))\n",
        "last_5 = list(enumerate(items[-5:], start=len(items) - 5))\n",
        "\n",
        "for i, (key, value) in first_10 + last_5:\n",
        "    coeff_type = (\n",
        "        \"constant\"\n",
        "        if key == \"()\"\n",
        "        else \"linear\"\n",
        "        if \", )\" in key\n",
        "        else \"quadratic\"\n",
        "    )\n",
        "    print(f\"  {key}: {value} ({coeff_type})\")\n",
        "print(\"  ...\")\n",
        "print(\"\\n✓ Problem ready for Iskay optimizer!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step3",
      "metadata": {},
      "source": [
        "### Understand the bf-DCQO algorithm\n",
        "\n",
        "Before we run the optimization, let's understand the sophisticated quantum algorithm that powers Iskay: **bf-DCQO (bias-field digitized counterdiabatic quantum optimization)** [\\[1\\]](#references).\n",
        "\n",
        "#### What is bf-DCQO?\n",
        "\n",
        "bf-DCQO is based on the time evolution of a quantum system where the problem solution is encoded in the **ground state** (lowest energy state) of the final quantum Hamiltonian [\\[1\\]](#references). The algorithm addresses a fundamental challenge in quantum optimization:\n",
        "\n",
        "**The challenge**: Traditional adiabatic quantum computing requires very slow evolution to maintain ground state conditions according to the adiabatic theorem. This demands increasingly deep quantum circuits as problem complexity grows, leading to more gate operations and accumulated errors.\n",
        "\n",
        "**The solution**: bf-DCQO uses counterdiabatic protocols to enable rapid evolution while maintaining ground state fidelity, dramatically reducing circuit depth.\n",
        "\n",
        "#### Mathematical framework\n",
        "\n",
        "The algorithm minimizes a cost function of the form:\n",
        "\n",
        "$\\min_{(x_1,x_2,...,x_n) \\in D} C(x_1,x_2,...,x_n)$\n",
        "\n",
        "where $D = \\{0,1\\}^n$ for binary variables and:\n",
        "\n",
        "$C(x) = a + \\sum_i b_i x_i + \\sum_{i,j} c_{ij} x_i x_j + ... + \\sum g_{k_1,...,k_m} x_{k_1}...x_{k_m}$\n",
        "\n",
        "For our Market Split problem, the cost function is:\n",
        "\n",
        "$C(x) = ||Ax - b||^2 = x^T A^T A x - 2 b^T A x + b^T b$\n",
        "\n",
        "#### The role of counterdiabatic terms\n",
        "\n",
        "**Counterdiabatic terms** are additional terms introduced into the time-dependent Hamiltonian that suppress unwanted excitations during the quantum evolution. Here's why they're crucial:\n",
        "\n",
        "In adiabatic quantum optimization, we evolve the system according to a time-dependent Hamiltonian:\n",
        "\n",
        "$H(t) = \\left(1 - \\frac{t}{T}\\right) H_{\\text{initial}} + \\frac{t}{T} H_{\\text{problem}}$\n",
        "\n",
        "where $H_{\\text{problem}}$ encodes our optimization problem. To maintain the ground state during rapid evolution, we add counterdiabatic terms:\n",
        "\n",
        "$H_{\\text{CD}}(t) = H(t) + H_{\\text{counter}}(t)$\n",
        "\n",
        "These counterdiabatic terms do the following:\n",
        "\n",
        "1. **Suppress unwanted transitions**: Prevent the quantum state from jumping to excited states during fast evolution\n",
        "2. **Enable shorter evolution times**: Allow us to reach the final state much faster without violating adiabaticity\n",
        "3. **Reduce circuit depth**: Shorter evolution leads to fewer gates and less error\n",
        "\n",
        "The practical impact is dramatic: bf-DCQO uses up to **10 times fewer entangling gates** than Digital Quantum Annealing [\\[1\\]](#references), making it practical for today's noisy quantum hardware.\n",
        "\n",
        "#### Bias-field iterative optimization\n",
        "\n",
        "Unlike variational algorithms that optimize circuit parameters through many iterations, bf-DCQO uses a **bias-field guided approach** that converges in approximately 10 iterations \\[1]:\n",
        "\n",
        "**Iteration process:**\n",
        "\n",
        "1. **Initial quantum evolution**: Start with a quantum circuit implementing the counterdiabatic evolution protocol\n",
        "\n",
        "2. **Measurement**: Measure the quantum state to obtain a probability distribution over bitstrings\n",
        "\n",
        "3. **Bias-field calculation**: Analyze the measurement statistics and calculate an optimal bias-field $h_i$ for each qubit:\n",
        "   $h_i = \\text{f}(\\text{measurement statistics}, \\text{previous solutions})$\n",
        "\n",
        "4. **Next iteration**: The bias-field modifies the Hamiltonian for the next iteration:\n",
        "   $H_{\\text{next}} = H_{\\text{problem}} + \\sum_i h_i \\sigma_i^z$\n",
        "\n",
        "   This allows starting near the previously found good solution, effectively performing a form of \"quantum local search\"\n",
        "\n",
        "5. **Convergence**: Repeat until the solution quality stabilizes or a maximum number of iterations is reached\n",
        "\n",
        "**Key advantage**: Each iteration provides meaningful progress toward the optimal solution by incorporating information from previous measurements, unlike variational methods that must explore the parameter space blindly.\n",
        "\n",
        "#### Integrated classical post-processing\n",
        "\n",
        "After the quantum optimization converges, Iskay performs classical **local search** post-processing:\n",
        "\n",
        "* **Bit-flip exploration**: Systematically or randomly flip bits in the best measured solution\n",
        "* **Energy evaluation**: Calculate $C(x)$ for each modified solution\n",
        "* **Greedy selection**: Accept improvements that lower the cost function\n",
        "* **Multiple passes**: Perform several passes (controlled by `postprocessing_level`)\n",
        "\n",
        "This hybrid approach compensates for bit-flip errors from hardware imperfections and readout errors, ensuring high-quality solutions even on noisy quantum devices.\n",
        "\n",
        "#### Why bf-DCQO excels on current hardware\n",
        "\n",
        "The bf-DCQO algorithm is specifically designed to excel on today's noisy intermediate-scale quantum (NISQ) devices [\\[1\\]](#references):\n",
        "\n",
        "1. **Error resilience**: Fewer gates (10 times reduction) means dramatically less error accumulation\n",
        "2. **No error mitigation required**: The algorithm's inherent efficiency eliminates the need for expensive error mitigation techniques [\\[1\\]](#references)\n",
        "3. **Scalability**: Can handle problems with up to 156 qubits (156 binary variables) with direct qubit-mapping [\\[1\\]](#references)\n",
        "4. **Proven performance**: Achieves 100% approximation ratios on benchmark MaxCut and HUBO instances [\\[1\\]](#references)\n",
        "\n",
        "Now let's see this powerful algorithm in action on our Market Split problem!\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step4",
      "metadata": {},
      "source": [
        "## Step 2: Optimize problem for quantum hardware execution\n",
        "\n",
        "The bf-DCQO algorithm automatically handles circuit optimization, creating shallow quantum circuits with counterdiabatic terms specifically designed for the target backend.\n",
        "\n",
        "### Configure the optimization\n",
        "\n",
        "The Iskay Optimizer requires several key parameters to effectively solve your optimization problem. Let's examine each parameter and its role in the quantum optimization process:\n",
        "\n",
        "#### Required parameters\n",
        "\n",
        "| Parameter         | Type               | Description                                                     | Example                                     |\n",
        "| ----------------- | ------------------ | --------------------------------------------------------------- | ------------------------------------------- |\n",
        "| **problem**       | `Dict[str, float]` | QUBO coefficients in string-key format                          | `{\"()\": -21.0, \"(0,4)\": 0.5, \"(0,1)\": 0.5}` |\n",
        "| **problem\\_type** | `str`              | Format specification: `\"binary\"` for QUBO or `\"spin\"` for Ising | `\"binary\"`                                  |\n",
        "| **backend\\_name** | `str`              | Target quantum device                                           | `\"ibm_fez\"`                                 |\n",
        "\n",
        "#### Essential concepts\n",
        "\n",
        "* **Problem format**: We use `\"binary\"` since our variables are binary (0/1), representing market assignments.\n",
        "* **Backend selection**: Choose between the available QPUs (for example, `\"ibm_fez\"`) based on your needs and compute resource instance.\n",
        "* **QUBO structure**: Our problem dictionary contains the exact coefficients from the mathematical transformation.\n",
        "\n",
        "#### Advanced options (optional)\n",
        "\n",
        "Iskay provides fine-tuning capabilities through optional parameters. While the defaults work well for most problems, you can customize the behavior for specific requirements:\n",
        "\n",
        "| Parameter                  | Type        | Default | Description                                                         |\n",
        "| -------------------------- | ----------- | ------- | ------------------------------------------------------------------- |\n",
        "| **shots**                  | `int`       | 10000   | Quantum measurements per iteration (higher = more accurate)         |\n",
        "| **num\\_iterations**        | `int`       | 10      | Algorithm iterations (more iterations can improve solution quality) |\n",
        "| **use\\_session**           | `bool`      | True    | Use IBM sessions for reduced queue times                            |\n",
        "| **seed\\_transpiler**       | `int`       | None    | Set for reproducible quantum circuit compilation                    |\n",
        "| **direct\\_qubit\\_mapping** | `bool`      | False   | Map virtual qubits directly to physical qubits                      |\n",
        "| **job\\_tags**              | `List[str]` | None    | Custom tags for job tracking                                        |\n",
        "| **preprocessing\\_level**   | `int`       | 0       | Problem preprocessing intensity (0-3) - see details below           |\n",
        "| **postprocessing\\_level**  | `int`       | 2       | Solution refinement level (0-2) - see details below                 |\n",
        "| **transpilation\\_level**   | `int`       | 0       | Transpiler optimization trials (0-5) - see details below            |\n",
        "| **transpile\\_only**        | `bool`      | False   | Analyze circuit optimization without running full execution         |\n",
        "\n",
        "**Preprocessing Levels (0-3)**: Specially important for larger problems that cannot currently fit on the coherence times of the hardware. Higher preprocessing levels achieve shallower circuit depths by approximations in the problem transpilation:\n",
        "\n",
        "* **Level 0**: Exact, longer circuits\n",
        "* **Level 1**: Good balance between accuracy and approximation, cutting out only the gates with angles in the lowest 10 percentile\n",
        "* **Level 2**: Slightly higher approximation, cutting out the gates with angles in the lowest 20 percentile and using `approximation_degree=0.95` in the transpilation\n",
        "* **Level 3**: Maximum approximation level, cutting out the gates in the lowest 30 percentile and using `approximation_degree=0.90` in the transpilation\n",
        "\n",
        "**Transpilation Levels (0-5)**: Control the advanced transpiler optimization trials for quantum circuit compilation. This can lead to an increase in classical overhead, and for some cases it might not change the circuit depth. The default value `2` in general leads to the smallest circuit and is relatively fast.\n",
        "\n",
        "* **Level 0**: Optimization of the decomposed DCQO circuit (layout, routing, scheduling)\n",
        "* **Level 1**: Optimization of `PauliEvolutionGate` and then the decomposed DCQO circuit (max\\_trials=10)\n",
        "* **Level 2**: Optimization of `PauliEvolutionGate` and then the decomposed DCQO circuit (max\\_trials=15)\n",
        "* **Level 3**: Optimization of `PauliEvolutionGate` and then the decomposed DCQO circuit (max\\_trials=20)\n",
        "* **Level 4**: Optimization of `PauliEvolutionGate` and then the decomposed DCQO circuit (max\\_trials=25)\n",
        "* **Level 5**: Optimization of `PauliEvolutionGate` and then the decomposed DCQO circuit (max\\_trials=50)\n",
        "\n",
        "**Postprocessing Levels (0-2)**: Control how much classical optimization, compensating for bit-flip errors with different number of greedy passes of a local search:\n",
        "\n",
        "* **Level 0**: 1 pass\n",
        "* **Level 1**: 2 passes\n",
        "* **Level 2**: 3 passes\n",
        "\n",
        "**Transpile-only mode**: Now available for users who want to analyze circuit optimization without running the full quantum algorithm execution.\n",
        "\n",
        "#### Custom configuration example\n",
        "\n",
        "Here's how you might configure Iskay with different settings:\n",
        "\n",
        "```python\n",
        "custom_options = {\n",
        "    # Higher shot count for better statistics\n",
        "    \"shots\": 15_000,\n",
        "\n",
        "    # More iterations for solution refinement\n",
        "    \"num_iterations\": 12,\n",
        "\n",
        "    # Light preprocessing for problem simplification\n",
        "    \"preprocessing_level\": 1,\n",
        "\n",
        "    # Maximum postprocessing for solution quality\n",
        "    \"postprocessing_level\": 2,\n",
        "\n",
        "    # Using higher transpilation level for circuit optimization\n",
        "    \"transpilation_level\": 3,\n",
        "\n",
        "    # Fixed seed for reproducible results\n",
        "    \"seed_transpiler\": 42,\n",
        "\n",
        "    # Custom tracking tags\n",
        "    \"job_tags\": [\"market_split\"]\n",
        "}\n",
        "```\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "86e2b10d",
      "metadata": {},
      "source": [
        "For this tutorial, we will keep most of the default parameters and will only change the number of bias-field iterations:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "config",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify the target backend\n",
        "backend_name = \"ibm_fez\"\n",
        "\n",
        "# Set the number of bias-field iterations and set a tag to identify the jobs\n",
        "options = {\n",
        "    \"num_iterations\": 3,  # Change number of bias-field iterations\n",
        "    \"job_tags\": [\"market_split_example\"],  # Tag to identify jobs\n",
        "}\n",
        "\n",
        "# Configure Iskay optimizer\n",
        "iskay_input = {\n",
        "    \"problem\": iskay_input_problem,\n",
        "    \"problem_type\": \"binary\",\n",
        "    \"backend_name\": backend_name,\n",
        "    \"options\": options,\n",
        "}\n",
        "\n",
        "print(\"Iskay Optimizer Configuration:\")\n",
        "print(\"=\" * 40)\n",
        "print(f\"  Backend: {backend_name}\")\n",
        "print(f\"  Problem: {len(iskay_input['problem'])} terms\")\n",
        "print(\"  Algorithm: bf-DCQO\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "submit_intro",
      "metadata": {},
      "source": [
        "## Step 3: Execute using Qiskit primitives\n",
        "\n",
        "We now submit our problem to run on IBM Quantum hardware. The bf-DCQO algorithm will:\n",
        "\n",
        "1. Construct shallow quantum circuits with counterdiabatic terms\n",
        "2. Execute approximately 10 iterations with bias-field optimization\n",
        "3. Perform classical post-processing with local search\n",
        "4. Return the optimal market assignment\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "run",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Submit the optimization job\n",
        "print(\"Submitting optimization job to Kipu Quantum...\")\n",
        "print(\n",
        "    f\"Problem size: {A.shape[1]} variables, {len(iskay_input['problem'])} terms\"\n",
        ")\n",
        "print(\n",
        "    \"Algorithm: bf-DCQO (bias-field digitized counterdiabatic quantum optimization)\"\n",
        ")\n",
        "\n",
        "job = iskay_solver.run(**iskay_input)\n",
        "\n",
        "print(\"\\nJob successfully submitted!\")\n",
        "print(f\"Job ID: {job.job_id}\")\n",
        "print(\"Optimization in progress...\")\n",
        "print(\n",
        "    f\"The bf-DCQO algorithm will efficiently explore \"\n",
        "    f\"{2**A.shape[1]:,} possible assignments\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "status_intro",
      "metadata": {},
      "source": [
        "### Monitor job status\n",
        "\n",
        "You can check the current status of your optimization job. The possible statuses are:\n",
        "\n",
        "* `QUEUED`: Job is waiting in the queue\n",
        "* `RUNNING`: Job is currently executing on quantum hardware\n",
        "* `DONE`: Job completed successfully\n",
        "* `CANCELED`: Job was canceled\n",
        "* `ERROR`: Job encountered an error\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "status",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Check job status\n",
        "print(f\"Job status: {job.status()}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "wait_intro",
      "metadata": {},
      "source": [
        "### Wait for completion\n",
        "\n",
        "This cell will block until the job completes. The optimization process includes:\n",
        "\n",
        "* Queue time (waiting for quantum hardware access)\n",
        "* Execution time (running the bf-DCQO algorithm with approximately 10 iterations)\n",
        "* Post-processing time (classical local search)\n",
        "\n",
        "Typical completion times range from a few minutes to tens of minutes depending on queue conditions.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "wait",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Wait for job completion\n",
        "while True:\n",
        "    status = job.status()\n",
        "    print(\n",
        "        f\"Waiting for job {job.job_id} to complete... (status: {status})\",\n",
        "        end=\"\\r\",\n",
        "        flush=True,\n",
        "    )\n",
        "    if status in [\"DONE\", \"CANCELED\", \"ERROR\"]:\n",
        "        print(\n",
        "            f\"\\nJob {job.job_id} completed with status: {status}\" + \" \" * 20\n",
        "        )\n",
        "        break\n",
        "    time.sleep(30)\n",
        "\n",
        "# Retrieve the optimization results\n",
        "result = job.result()\n",
        "print(\"\\nOptimization complete!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "step5",
      "metadata": {},
      "source": [
        "## Step 4: Post-process and return result in desired classical format\n",
        "\n",
        "We now post-process the quantum execution results. This includes:\n",
        "\n",
        "* Analyzing the solution structure\n",
        "* Validating constraint satisfaction\n",
        "* Benchmarking against classical approaches\n",
        "\n",
        "### Analyze results\n",
        "\n",
        "#### Understand the result structure\n",
        "\n",
        "Iskay returns a comprehensive result dictionary containing:\n",
        "\n",
        "* **`solution`**: A dictionary mapping variable indices to their optimal values (0 or 1)\n",
        "* **`solution_info`**: Detailed information including:\n",
        "  * `bitstring`: The optimal assignment as a binary string\n",
        "  * `cost`: The objective function value (should be 0 for perfect constraint satisfaction)\n",
        "  * `mapping`: How bitstring positions map to problem variables\n",
        "  * `seed_transpiler`: Seed used for reproducibility\n",
        "* **`prob_type`**: Whether the solution is in binary or spin format\n",
        "\n",
        "Let's examine the solution returned by the quantum optimizer.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "results",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Display the optimization results\n",
        "print(\"Optimization Results\")\n",
        "print(\"=\" * 50)\n",
        "print(f\"Problem Type: {result['prob_type']}\")\n",
        "print(\"\\nSolution Info:\")\n",
        "print(f\"  Bitstring: {result['solution_info']['bitstring']}\")\n",
        "print(f\"  Cost: {result['solution_info']['cost']}\")\n",
        "print(\"\\nSolution (first 10 variables):\")\n",
        "for i, (var, val) in enumerate(list(result[\"solution\"].items())[:10]):\n",
        "    print(f\"  {var}: {val}\")\n",
        "print(\"  ...\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "validation_intro",
      "metadata": {},
      "source": [
        "#### Solution validation\n",
        "\n",
        "Now we validate whether the quantum solution satisfies the Market Split constraints. The validation process checks:\n",
        "\n",
        "**What is a constraint violation?**\n",
        "\n",
        "* For each product $i$, we calculate the actual sales in Region A: $(Ax)_i$\n",
        "* We compare this to the target sales $b_i$\n",
        "* The **violation** is the absolute difference: $|(Ax)_i - b_i|$\n",
        "* A **feasible solution** has zero violations for all products\n",
        "\n",
        "**What we expect:**\n",
        "\n",
        "* **Ideal case**: Total violation = 0 (all constraints perfectly satisfied)\n",
        "  * Region A gets exactly 1002 units of Product 1, 879 units of Product 2, and 1040 units of Product 3\n",
        "  * Region B gets the remaining units (also 1002, 879, and 1040 respectively)\n",
        "* **Good case**: Total violation is small (near-optimal solution)\n",
        "* **Poor case**: Large violations indicate the solution doesn't satisfy the business requirements\n",
        "\n",
        "The validation function will compute:\n",
        "\n",
        "1. Actual sales per product in each region\n",
        "2. Constraint violations for each product\n",
        "3. Market distribution between regions\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "validate",
      "metadata": {},
      "outputs": [],
      "source": [
        "def validate_solution(A, b, solution):\n",
        "    \"\"\"Validate market split solution.\"\"\"\n",
        "    x = np.array(solution)\n",
        "    region_a = A @ x\n",
        "    region_b = A @ (1 - x)\n",
        "    violations = np.abs(region_a - b)\n",
        "\n",
        "    return {\n",
        "        \"target\": b,\n",
        "        \"region_a\": region_a,\n",
        "        \"region_b\": region_b,\n",
        "        \"violations\": violations,\n",
        "        \"total_violation\": np.sum(violations),\n",
        "        \"is_feasible\": np.sum(violations) == 0,\n",
        "        \"region_a_markets\": int(np.sum(x)),\n",
        "        \"region_b_markets\": len(x) - int(np.sum(x)),\n",
        "    }\n",
        "\n",
        "\n",
        "# Convert bitstring to list of integers and validate\n",
        "optimal_assignment = [\n",
        "    int(bit) for bit in result[\"solution_info\"][\"bitstring\"]\n",
        "]\n",
        "validation = validate_solution(A, b, optimal_assignment)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "validation_results_intro",
      "metadata": {},
      "source": [
        "#### Interpret the validation results\n",
        "\n",
        "The validation results show whether the Quantum Optimizer found a feasible solution. Let's examine the following:\n",
        "\n",
        "**Feasibility check:**\n",
        "\n",
        "* **`is_feasible = True`** means the solution perfectly satisfies all constraints (total violation = 0)\n",
        "* **`is_feasible = False`** means some constraints are violated\n",
        "\n",
        "**Sales analysis:**\n",
        "\n",
        "* Compare Target versus Actual sales for each product\n",
        "* For a perfect solution: Actual = Target for all products in both regions\n",
        "* The difference indicates how close we are to the desired market split\n",
        "\n",
        "**Market distribution:**\n",
        "\n",
        "* Shows how many markets are assigned to each region\n",
        "* There's no requirement for equal numbers of markets, only that sales targets are met\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "display_validation",
      "metadata": {},
      "outputs": [],
      "source": [
        "print(\"Solution Validation\")\n",
        "print(\"=\" * 50)\n",
        "print(f\"Feasible solution: {validation['is_feasible']}\")\n",
        "print(f\"Total constraint violation: {validation['total_violation']}\")\n",
        "\n",
        "print(\"\\nSales Analysis (Target vs Actual):\")\n",
        "for i, (target, actual_a, actual_b) in enumerate(\n",
        "    zip(validation[\"target\"], validation[\"region_a\"], validation[\"region_b\"])\n",
        "):\n",
        "    violation_a = abs(actual_a - target)\n",
        "    violation_b = abs(actual_b - target)\n",
        "    print(f\"  Product {i+1}:\")\n",
        "    print(f\"    Target: {target}\")\n",
        "    print(f\"    Region A: {actual_a} (violation: {violation_a})\")\n",
        "    print(f\"    Region B: {actual_b} (violation: {violation_b})\")\n",
        "\n",
        "print(\"\\nMarket Distribution:\")\n",
        "print(f\"  Region A: {validation['region_a_markets']} markets\")\n",
        "print(f\"  Region B: {validation['region_b_markets']} markets\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "interpretation",
      "metadata": {},
      "source": [
        "#### Solution quality assessment\n",
        "\n",
        "Based on the validation results above, we can assess the quality of the quantum solution:\n",
        "\n",
        "**If `is_feasible = True` (Total violation = 0):**\n",
        "\n",
        "* The Quantum Optimizer successfully found an optimal solution\n",
        "* All business constraints are perfectly satisfied\n",
        "* This demonstrates quantum advantage on a problem where classical solvers struggle [\\[4\\]](#references)\n",
        "\n",
        "**If `is_feasible = False` (Total violation > 0):**\n",
        "\n",
        "* The solution is near-optimal but not perfect\n",
        "* Small violations may be acceptable in practice\n",
        "* Consider adjusting optimizer parameters:\n",
        "  * Increase `num_iterations` for more optimization passes\n",
        "  * Increase `postprocessing_level` for more classical refinement\n",
        "  * Increase `shots` for better measurement statistics\n",
        "\n",
        "**Cost function interpretation:**\n",
        "\n",
        "* The `cost` value from `solution_info` equals $||Ax - b||^2$\n",
        "* Cost = 0 indicates perfect constraint satisfaction\n",
        "* Higher cost values indicate larger constraint violations\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "conclusion",
      "metadata": {},
      "source": [
        "## Conclusion\n",
        "\n",
        "### What we accomplished\n",
        "\n",
        "In this tutorial, we successfully:\n",
        "\n",
        "1. **Loaded a real optimization problem**: Obtained a challenging Market Split instance from the QOBLIB benchmark library \\[2]\n",
        "2. **Transformed to QUBO format**: Converted the constrained problem into an unconstrained quadratic formulation \\[3]\n",
        "3. **Leveraged advanced quantum algorithms**: Used Kipu Quantum's bf-DCQO algorithm with counterdiabatic terms \\[1]\n",
        "4. **Obtained optimal solutions**: Found feasible solutions satisfying all constraints\n",
        "\n",
        "### Key takeaways\n",
        "\n",
        "**Algorithm innovation**: The bf-DCQO algorithm represents a significant advancement [\\[1\\]](#references):\n",
        "\n",
        "* **10 times fewer gates** than digital quantum annealing\n",
        "* **Approximately 10 iterations** instead of approximately 100 for variational methods\n",
        "* **Built-in error resilience** through circuit efficiency\n",
        "\n",
        "**Counterdiabatic terms**: Enable rapid quantum evolution while maintaining ground state fidelity, making quantum optimization practical on today's noisy hardware [\\[1\\]](#references).\n",
        "\n",
        "**Bias-field guidance**: The iterative bias-field approach allows each iteration to start near previously found good solutions, providing a form of quantum-enhanced local search [\\[1\\]](#references).\n",
        "\n",
        "### Next steps\n",
        "\n",
        "To deepen your understanding and explore further:\n",
        "\n",
        "1. **Try different instances**: Experiment with other QOBLIB instances of varying sizes\n",
        "2. **Tune parameters**: Adjust `num_iterations`, `preprocessing_level`, `postprocessing_level`\n",
        "3. **Compare with classical**: Benchmark against classical optimization solvers\n",
        "4. **Try different strategies**: Try to find a better encoding for the problem or formulate it as HUBO (if possible)\n",
        "5. **Apply to your domain**: Adapt the QUBO/HUBO formulation techniques to your own optimization problems\n",
        "\n",
        "### References\n",
        "\n",
        "\\[1] IBM Quantum. \"[Kipu Quantum Optimization](/docs/guides/kipu-optimization).\" *IBM Quantum Documentation*.\n",
        "\n",
        "\\[2] QOBLIB - Quantum Optimization Benchmarking Library. Zuse Institute Berlin (ZIB). [https://git.zib.de/qopt/qoblib-quantum-optimization-benchmarking-library](https://git.zib.de/qopt/qoblib-quantum-optimization-benchmarking-library)\n",
        "\n",
        "\\[3] Glover, F., Kochenberger, G., & Du, Y. (2019). \"Quantum bridge analytics I: a tutorial on formulating and using QUBO models.\" *4OR: A Quarterly Journal of Operations Research*, 17(4), 335-371.\n",
        "\n",
        "\\[4] Lodi, A., Tramontani, A., & Weninger, K. (2023). \"The Intractable Decathlon: Benchmarking Hard Combinatorial Problems.\" *INFORMS Journal on Computing*.\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
}