Skip to main content
IBM Quantum Platform

Resolva o problema da divisão do mercado com o Iskay Quantum Optimizer da Kipu Quantum

Nota

Qiskit Functions são um recurso experimental disponível apenas para usuários dos planos IBM Quantum® Premium Plan, Flex Plan e On-Prem (via IBM Quantum Platform API). Eles estão no status de versão prévia e estão sujeitos a alterações.

Estimativa de uso: 20 segundos em um processador Heron r2. (OBSERVAÇÃO: essa é apenas uma estimativa. Seu tempo de execução pode variar)


Segundo plano

Este tutorial demonstra como resolver o problema de divisão de mercado usando o otimizador quântico Iskay do Kipu Quantum [1]. O problema de divisão de mercado representa um desafio de alocação de recursos do mundo real em que os mercados devem ser divididos em regiões de vendas equilibradas para atender às metas exatas de demanda.

O desafio da divisão do mercado

O problema de divisão de mercado apresenta um desafio aparentemente simples, mas computacionalmente formidável, na alocação de recursos. Considere uma empresa com mm produtos sendo vendidos em nn mercados diferentes, onde cada mercado compra um pacote específico de produtos (representado pelas colunas da matriz AA ). O objetivo comercial é dividir esses mercados em duas regiões de vendas equilibradas, de modo que cada região receba exatamente metade da demanda total de cada produto.

Formulação matemática:

Buscamos um vetor de atribuição binária xx, onde:

  • xj=1x_j = 1 atribui o mercado jj à região A
  • xj=0x_j = 0 atribui o mercado jj à Região B
  • A restrição Ax=bAx = b deve ser satisfeita, em que bb representa a meta de vendas (normalmente, metade da demanda total por produto)

Função de custo:

Para resolver esse problema, minimizamos a violação da restrição ao quadrado:

C(x)=Axb2=i=1m(j=1nAijxjbi)2C(x) = ||Ax - b||^2 = \sum_{i=1}^{m} \left(\sum_{j=1}^{n} A_{ij}x_j - b_i\right)^2

em que:

  • AijA_{ij} representa as vendas do produto ii no mercado jj
  • xj{0,1}x_j \in \{0,1\} é a atribuição binária de mercado jj
  • bib_i é a meta de vendas do produto ii em cada região
  • O custo é igual a zero exatamente quando todas as restrições são satisfeitas

Cada termo na soma representa o desvio quadrático da meta de vendas de um determinado produto. Quando expandimos essa função de custo, obtemos:

C(x)=xTATAx2bTAx+bTbC(x) = x^T A^T A x - 2b^T A x + b^T b

Como bTbb^T b é uma constante, minimizar C(x)C(x) é equivalente a minimizar a função quadrática xTATAx2bTAxx^T A^T A x - 2b^T A x, que é exatamente um problema QUBO (Quadratic Unconstrained Binary Optimization).

Complexidade computacional:

Apesar de sua interpretação comercial simples, esse problema apresenta uma notável intratabilidade computacional:

  • Falha em pequena escala : Os solucionadores convencionais de programação inteira mista falham em instâncias com apenas sete produtos em um tempo limite de uma hora [4]
  • Crescimento exponencial : O espaço de solução cresce exponencialmente ( 2n2^n atribuições possíveis), tornando inviáveis as abordagens de força bruta

Essa grave barreira computacional, combinada com sua relevância prática para o planejamento de territórios e a alocação de recursos, torna o problema de divisão de mercado uma referência ideal para algoritmos de otimização quântica [4].

O que torna a abordagem de Iskay única?

O otimizador Iskay usa o algoritmo bf-DCQO (bias-field digitized counterdiabatic quantum optimization) [1], que representa um avanço significativo na otimização quântica:

Eficiência do circuito : O algoritmo bf-DCQO alcança uma notável redução de portas [1] :

  • Até 10 vezes menos portas de emaranhamento do que o Digital Quantum Annealing (DQA)
  • Possibilita circuitos significativamente mais rasos:
    • Menor acúmulo de erros durante a execução quântica
    • Capacidade de lidar com problemas maiores no hardware quântico atual
    • Não há necessidade de técnicas de atenuação de erros

Projeto não variacional : Ao contrário dos algoritmos variacionais que exigem aproximadamente 100 iterações, o bf-DCQO normalmente precisa de apenas aproximadamente 10 iterações [1]. Isso é realizado por meio de:

  • Cálculos inteligentes de campo de polarização a partir de distribuições de estados medidos
  • Iniciar cada iteração a partir de um estado de energia próximo à solução anterior
  • Pós-processamento clássico integrado com pesquisa local

Protocolos contra-diabáticos : O algoritmo incorpora termos contra-diabáticos que suprimem excitações quânticas indesejadas durante curtos tempos de evolução, permitindo que o sistema permaneça próximo ao estado fundamental mesmo com transições rápidas [1].


Requisitos

Antes de iniciar este tutorial, verifique se você tem os seguintes itens instalados:

  • Qiskit IBM Runtime (pip install qiskit-ibm-runtime)
  • Qiskit Functions (pip install qiskit-ibm-catalog)
  • NumPy (pip install numpy)
  • Solicitações (pip install requests)
  • Addon do Opt Mapper Qiskit (pip install qiskit-addon-opt-mapper)

Você também precisará obter acesso à função Iskay Quantum Optimizer no site Qiskit Functions Catalog.


Instalação

Primeiro, importe todos os pacotes necessários para este tutorial.

import os
import tempfile
import time
from typing import Tuple, Optional

import numpy as np
import requests

from qiskit_ibm_catalog import QiskitFunctionsCatalog

from qiskit_addon_opt_mapper import OptimizationProblem
from qiskit_addon_opt_mapper.converters import OptimizationProblemToQubo

print("All required libraries imported successfully")

Configurar credenciais d IBM Quantum

Defina suas IBM Quantum® Platform credenciais. Você precisará de:

  • Token de API : Sua chave de API de 44 caracteres de IBM Quantum Platform
  • CRN da instância : Seu identificador de instância IBM Cloud®
token = "<YOUR_API_KEY>"
instance = "<YOUR_INSTANCE_CRN>"

Passo 1: Mapear entradas clássicas para um problema quântico

Começamos mapeando nosso problema clássico para uma representação compatível com o quantum. Essa etapa envolve:

  1. Conexão com o Iskay Quantum Optimizer
  2. Carregamento e formulação do problema de divisão de mercado
  3. Entendendo o algoritmo bf-DCQO que o resolverá

Conecte-se ao Iskay Quantum Optimizer

Começamos estabelecendo uma conexão com o site Qiskit Functions Catalog e carregando o Iskay Quantum Optimizer. O Iskay Optimizer é uma função quântica fornecida pela Kipu Quantum que implementa o algoritmo bf-DCQO para resolver problemas de otimização em hardware quântico.

catalog = QiskitFunctionsCatalog(token=token, instance=instance)
iskay_solver = catalog.load("kipu-quantum/iskay-quantum-optimizer")

print("Iskay optimizer loaded successfully")
print("Ready to solve optimization problems using bf-DCQO algorithm")

Carregue e formule o problema

Entenda o formato dos dados do problema

As instâncias de problemas da QOBLIB (Quantum Optimization Benchmarking Library) [2] são armazenadas em um formato de texto simples. Vamos examinar o conteúdo real de nossa instância de destino ms_03_200_177.dat:

3 20
60   92  161   53   97    2   75   81    6  139  132   45  108  112  181   93  152  200  164   51 1002
176  196   41  143    2   88    0   79   10   71   75  148   82  135   34  187   33  155   58   46  879
68   68  179  173  127  163   48   49   99   78   44   52  173  131   73  198   84  109  180   95 1040

Estrutura do formato:

  • Primeira linha: 3 20

    • 3 = número de produtos (restrições/linhas na matriz AA )
    • 20 = número de mercados (variáveis/colunas na matriz AA )
  • Próximas 3 linhas: Matriz de coeficiente AA e vetor de destino bb

    • Cada linha tem 21 números: os primeiros 20 são coeficientes de linha, o último é o alvo
    • Linha 2: 60 92 161 ... 51 | 1002
      • Primeiros 20 números: Quanto do Produto 1 cada um dos 20 mercados vende
      • Último número (1002): Meta de vendas para o Produto 1 em uma região
    • Linha 3: 176 196 41 ... 46 | 879
      • Vendas do produto 2 por mercado e meta (879)
    • Linha 4: 68 68 179 ... 95 | 1040
      • Vendas do produto 3 por mercado e meta (1040)

Interpretação de negócios:

  • O Mercado 0 vende: 60 unidades do Produto 1, 176 unidades do Produto 2, 68 unidades do Produto 3
  • O Mercado 1 vende: 92 unidades do Produto 1, 196 unidades do Produto 2, 68 unidades do Produto 3
  • E assim por diante para todos os 20 mercados...
  • Meta : Dividir esses 20 mercados em duas regiões em que cada região receba exatamente 1002 unidades do Produto 1, 879 unidades do Produto 2 e 1040 unidades do Produto 3

Transformação QUBO


Das restrições ao QUBO: a transformação matemática

O poder da otimização quântica está na transformação de problemas com restrições em formas quadráticas sem restrições [4]. Para o problema de Market Split, convertemos as restrições de igualdade

Ax=bAx = b

onde x{0,1}nx ∈ \{0,1\}^n, em um QUBO, penalizando as violações de restrições.

O método de penalidade: Como precisamos que Ax=bAx = b se mantenha exatamente, minimizamos a violação ao quadrado: f(x)=Axb2f(x) = ||Ax - b||^2

Isso é igual a zero exatamente quando todas as restrições são satisfeitas. Expandindo algebricamente: f(x)=(Axb)T(Axb)=xTATAx2bTAx+bTbf(x) = (Ax - b)^T(Ax - b) = x^T A^T A x - 2b^T A x + b^T b

Objetivo do QUBO: Como bTbb^T b é constante, nossa otimização se torna: minimizeQ(x)=xT(ATA)x2(ATb)Tx\text{minimize} \quad Q(x) = x^T(A^T A)x - 2(A^T b)^T x

Principais percepções: Essa transformação é exata, não aproximada. As restrições de igualdade se enquadram naturalmente na forma quadrática sem exigir variáveis auxiliares ou parâmetros de penalidade, o que torna essa formulação matematicamente elegante e computacionalmente eficiente para solucionadores quânticos [4]. Usaremos a classe OptimizationProblem para definir nosso problema restrito e, em seguida, convertê-lo para o formato QUBO usando OptimizationProblemToQubo, ambos do pacote qiskit_addon_opt_mapper. Isso lida automaticamente com a transformação baseada em penalidades.

Implementar funções de carregamento de dados e conversão QUBO

Agora definimos três funções de utilidade:

  1. parse_marketsplit_dat() - Analisa o formato de arquivo .dat e extrai as matrizes AA e bb
  2. fetch_marketsplit_data() - Faz o download de instâncias de problemas diretamente do repositório QOBLIB
def parse_marketsplit_dat(filename: str) -> Tuple[np.ndarray, np.ndarray]:
    """
    Parse a market split problem from a .dat file format.

    Parameters
    ----------
    filename : str
        Path to the .dat file containing the market split problem data.

    Returns
    -------
    A : np.ndarray
        Coefficient matrix of shape (m, n) where m is the number of products
        and n is the number of markets.
    b : np.ndarray
        Target vector of shape (m,) containing the target sales per product.
    """
    with open(filename, "r", encoding="utf-8") as f:
        lines = [
            line.strip()
            for line in f
            if line.strip() and not line.startswith("#")
        ]

    if not lines:
        raise ValueError("Empty or invalid .dat file")

    # First line: m n (number of products and markets)
    m, n = map(int, lines[0].split())

    # Next m lines: each row of A followed by corresponding element of b
    A, b = [], []
    for i in range(1, m + 1):
        values = list(map(int, lines[i].split()))
        A.append(values[:-1])  # First n values: product sales per market
        b.append(values[-1])  # Last value: target sales for this product

    return np.array(A, dtype=np.int32), np.array(b, dtype=np.int32)


def fetch_marketsplit_data(
    instance_name: str = "ms_03_200_177.dat",
) -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]:
    """
    Fetch market split data directly from the QOBLIB repository.

    Parameters
    ----------
    instance_name : str
        Name of the .dat file to fetch (default: "ms_03_200_177.dat").

    Returns
    -------
    A : np.ndarray or None
        Coefficient matrix if successful, None if failed.
    b : np.ndarray or None
        Target vector if successful, None if failed.
    """
    url = f"https://git.zib.de/qopt/qoblib-quantum-optimization-benchmarking-library/-/raw/main/01-marketsplit/instances/{instance_name}"

    try:
        response = requests.get(url, timeout=30)
        response.raise_for_status()

        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".dat", delete=False, encoding="utf-8"
        ) as f:
            f.write(response.text)
            temp_path = f.name

        try:
            return parse_marketsplit_dat(temp_path)
        finally:
            os.unlink(temp_path)
    except Exception as e:
        print(f"Error: {e}")
        return None, None

Carregar a instância do problema

Agora carregamos a instância específica do problema ms_03_200_177.dat do QOBLIB [2]. Essa instância tem:

  • 3 produtos (restrições)
  • 20 mercados (variáveis de decisão binárias)
  • Mais de 1 milhão de possíveis atribuições de mercado para explorar ( 220=1,048,5762^{20} = 1,048,576 )
# Load the problem instance
instance_name = "ms_03_200_177.dat"
A, b = fetch_marketsplit_data(instance_name=instance_name)

if A is not None:
    print("Successfully loaded problem instance from QOBLIB")
    print("\nProblem Instance Analysis:")
    print("=" * 50)
    print(f"Coefficient Matrix A: {A.shape[0]} × {A.shape[1]}")
    print(f"   → {A.shape[0]} products (constraints)")
    print(f"   → {A.shape[1]} markets (decision variables)")
    print(f"Target Vector b: {b}")
    print("   → Target sales per product for each region")
    print(
        f"Solution Space: "
        f"2^{A.shape[1]} = {2**A.shape[1]:,} possible assignments"
    )

Converter para o formato QUBO

Agora, transformamos o problema de otimização com restrições no formato QUBO:

# Create optimization problem
ms = OptimizationProblem(instance_name.replace(".dat", ""))

# Add binary variables (one for each market)
ms.binary_var_list(A.shape[1])

# Add equality constraints (one for each product)
for idx, rhs in enumerate(b):
    ms.linear_constraint(A[idx, :], sense="==", rhs=rhs)

# Convert to QUBO with penalty parameter
qubo = OptimizationProblemToQubo(penalty=1).convert(ms)

print("QUBO Conversion Complete:")
print("=" * 50)
print(f"Number of variables: {qubo.get_num_vars()}")
print(f"Constant term: {qubo.objective.constant}")
print(f"Linear terms: {len(qubo.objective.linear.to_dict())}")
print(f"Quadratic terms: {len(qubo.objective.quadratic.to_dict())}")

Converter QUBO para o formato Iskay

Agora precisamos converter o objeto QUBO no formato de dicionário exigido pelo Iskay Optimizer da Kipu Quantum.

Os argumentos problem e problem_type codificam um problema de otimização da forma

min(x1,x2,,xn)DC(x1,x2,,xn)\begin{align} \min_{(x_1, x_2, \ldots, x_n) \in D} C(x_1, x_2, \ldots, x_n) \nonumber \end{align}

em que

C(x1,...,xn)=a+ibixi+i,jci,jxixj+...+k1,...,kmgk1,...,kmxk1...xkmC(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}
  • Ao escolher problem_type = "binary", você especifica que a função de custo está no formato binary , o que significa que D={0,1}nD = \{0, 1\}^{n}, como em, a função de custo é escrita na formulação QUBO/HUBO.
  • Por outro lado, ao escolher problem_type = "spin", a função de custo é escrita na formulação de Ising, onde D={1,1}nD = \{-1, 1\}^{n}.

Os coeficientes do problema devem ser codificados em um dicionário da seguinte forma:

{"()":a,"(i,)":bi,"(i, j)":ci,j,(ij)"(k1,...,km)":gk1,...,km,(k1k2km)}\begin{align} \nonumber &\texttt{\{} \\ \nonumber &\texttt{"()"}&: \quad &a, \\ \nonumber &\texttt{"(i,)"}&: \quad &b_i, \\ \nonumber &\texttt{"(i, j)"}&: \quad &c_{i, j}, \quad (i \neq j) \\ \nonumber &\quad \vdots \\ \nonumber &\texttt{"(} k_1, ..., k_m \texttt{)"}&: \quad &g_{k_1, ..., k_m}, \quad (k_1 \neq k_2 \neq \dots \neq k_m) \\ \nonumber &\texttt{\}} \end{align}

Observe que as chaves do dicionário devem ser cadeias de caracteres que contenham uma tupla válida de números inteiros não repetidos. Para problemas binários, sabemos que:

xi2=xix_i^2 = x_i

para i=ji=j (já que xi{0,1}x_i \in \{0,1\} significa xixi=xix_i \cdot x_i = x_i ). Portanto, em sua formulação QUBO, se você tiver contribuições lineares bixib_i x_i e contribuições quadráticas diagonais ci,ixi2c_{i,i} x_i^2, esses termos deverão ser combinados em um único coeficiente linear:

Coeficiente linear total para a variável xix_i : bi+ci,ib_i + c_{i,i}

Ou seja:

  • Termos lineares como "(i, )" contêm: coeficiente linear original + coeficiente quadrático diagonal
  • Termos quadráticos diagonais como "(i, i)" NÃO devem aparecer no dicionário final
  • Somente os termos quadráticos fora da diagonal, como "(i, j)" onde iji \neq j, devem ser incluídos como entradas separadas

Exemplo: Se seu QUBO tiver 3x1+2x12+4x1x23x_1 + 2x_1^2 + 4x_1 x_2, o dicionário Iskay deverá conter:

  • "(0, )": 5.0 (combinando 3+2=53 + 2 = 5 )
  • "(0, 1)": 4.0 (termo fora da diagonal)

NÃO há entradas separadas para "(0, )": 3.0 e "(0, 0)": 2.0.

# Convert QUBO to Iskay dictionary format:

# Create empty Iskay input dictionary
iskay_input_problem = {}

# Convert QUBO to Iskay dictionary format
iskay_input_problem = {"()": qubo.objective.constant}

for i in range(qubo.get_num_vars()):
    for j in range(i, qubo.get_num_vars()):
        if i == j:
            # Add linear term (including diagonal quadratic contribution)
            iskay_input_problem[f"({i}, )"] = float(
                qubo.objective.linear.to_dict().get(i)
            ) + float(qubo.objective.quadratic.to_dict().get((i, i)))
        else:
            # Add off-diagonal quadratic term
            iskay_input_problem[f"({i}, {j})"] = float(
                qubo.objective.quadratic.to_dict().get((i, j))
            )

# Display Iskay dictionary summary
print("Iskay Dictionary Format:")
print("=" * 50)
print(f"Total coefficients: {len(iskay_input_problem)}")
print(f"  • Constant term: {iskay_input_problem['()']}")
print(
    f"  • Linear terms: "
    f"{sum(1 for k in iskay_input_problem.keys() if k != '()' and ', )' in k)}"
)
print(
    f"  • Quadratic terms: "
    f"{sum(1 for k in iskay_input_problem.keys() if k != '()' and ', )' not in k)}"
)
print("\nSample coefficients:")

# Get first 10 and last 5 items properly
items = list(iskay_input_problem.items())
first_10 = list(enumerate(items[:10]))
last_5 = list(enumerate(items[-5:], start=len(items) - 5))

for i, (key, value) in first_10 + last_5:
    coeff_type = (
        "constant"
        if key == "()"
        else "linear"
        if ", )" in key
        else "quadratic"
    )
    print(f"  {key}: {value} ({coeff_type})")
print("  ...")
print("\n✓ Problem ready for Iskay optimizer!")

Entenda o algoritmo bf-DCQO

Antes de executarmos a otimização, vamos entender o sofisticado algoritmo quântico que alimenta o Iskay: bf-DCQO (bias-field digitized counterdiabatic quantum optimization) [1].

O que é bf-DCQO?

o bf-DCQO é baseado na evolução temporal de um sistema quântico em que a solução do problema é codificada no estado fundamental (estado de energia mais baixa) do Hamiltoniano quântico final [1]. O algoritmo aborda um desafio fundamental na otimização quântica:

O desafio : a computação quântica adiabática tradicional exige uma evolução muito lenta para manter as condições do estado fundamental de acordo com o teorema adiabático. Isso exige circuitos quânticos cada vez mais profundos à medida que a complexidade do problema aumenta, levando a mais operações de porta e erros acumulados.

A solução : o bf-DCQO usa protocolos contra-diabáticos para permitir uma evolução rápida e, ao mesmo tempo, manter a fidelidade do estado fundamental, reduzindo drasticamente a profundidade do circuito.

Estrutura matemática

O algoritmo minimiza uma função de custo do tipo:

min(x1,x2,...,xn)DC(x1,x2,...,xn)\min_{(x_1,x_2,...,x_n) \in D} C(x_1,x_2,...,x_n)

em que D={0,1}nD = \{0,1\}^n para variáveis binárias e:

C(x)=a+ibixi+i,jcijxixj+...+gk1,...,kmxk1...xkmC(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}

Para nosso problema de divisão de mercado, a função de custo é:

C(x)=Axb2=xTATAx2bTAx+bTbC(x) = ||Ax - b||^2 = x^T A^T A x - 2 b^T A x + b^T b

O papel dos termos antidiabéticos

Os termos contra-diabáticos são termos adicionais introduzidos no Hamiltoniano dependente do tempo que suprimem as excitações indesejadas durante a evolução quântica. Veja por que eles são cruciais:

Na otimização quântica adiabática, evoluímos o sistema de acordo com um Hamiltoniano dependente do tempo:

H(t)=(1tT)Hinitial+tTHproblemH(t) = \left(1 - \frac{t}{T}\right) H_{\text{initial}} + \frac{t}{T} H_{\text{problem}}

em que HproblemH_{\text{problem}} codifica nosso problema de otimização. Para manter o estado fundamental durante a evolução rápida, adicionamos termos contra-diabáticos:

HCD(t)=H(t)+Hcounter(t)H_{\text{CD}}(t) = H(t) + H_{\text{counter}}(t)

Esses termos contra-diabáticos fazem o seguinte:

  1. Suprimir transições indesejadas : Impedir que o estado quântico salte para estados excitados durante a evolução rápida
  2. Permitir tempos de evolução mais curtos : Permite que alcancemos o estado final muito mais rapidamente sem violar a adiabaticidade
  3. Reduzir a profundidade do circuito : Uma evolução mais curta leva a menos portas e menos erros

O impacto prático é significativo: o bf-DCQO usa até 10 vezes menos portas de emaranhamento do que o Digital Quantum Annealing [1], o que o torna prático para o hardware quântico ruidoso atual.

Otimização iterativa do campo de viés

Diferentemente dos algoritmos variacionais que otimizam os parâmetros do circuito por meio de muitas iterações, o bf-DCQO usa uma abordagem guiada por campo de polarização que converge em aproximadamente 10 iterações [1] :

Processo de iteração:

  1. Evolução quântica inicial : Comece com um circuito quântico implementando o protocolo de evolução contra-diabática

  2. Medição : Medir o estado quântico para obter uma distribuição de probabilidade sobre cadeias de bits

  3. Cálculo do campo de polarização : Analise as estatísticas de medição e calcule um campo de polarização ideal hih_i para cada qubit: hi=f(measurement statistics,previous solutions)h_i = \text{f}(\text{measurement statistics}, \text{previous solutions})

  4. Próxima iteração : O campo de polarização modifica o Hamiltoniano para a próxima iteração: Hnext=Hproblem+ihiσizH_{\text{next}} = H_{\text{problem}} + \sum_i h_i \sigma_i^z

    Isso permite começar perto da boa solução encontrada anteriormente, realizando efetivamente uma forma de "pesquisa local quântica"

  5. Convergência : Repetir até que a qualidade da solução se estabilize ou até que um número máximo de iterações seja atingido

Principal vantagem : Cada iteração proporciona um progresso significativo em direção à solução ideal ao incorporar informações de medições anteriores, ao contrário dos métodos variacionais que precisam explorar o espaço de parâmetros às cegas.

Pós-processamento clássico integrado

Após a convergência da otimização quântica, o Iskay realiza o pós-processamento clássico de pesquisa local :

  • Exploração de inversão de bits : Inverter sistemática ou aleatoriamente os bits na melhor solução medida
  • Avaliação de energia : Calcular C(x)C(x) para cada solução modificada
  • Seleção inteligente : Aceitar melhorias que reduzam a função de custo
  • Múltiplas passagens : Executar várias passagens (controladas por postprocessing_level)

Essa abordagem híbrida compensa os erros de inversão de bits causados por imperfeições de hardware e erros de leitura, garantindo soluções de alta qualidade mesmo em dispositivos quânticos com ruído.

Por que o bf-DCQO se destaca no hardware atual

O algoritmo bf-DCQO foi projetado especificamente para se destacar nos dispositivos quânticos atuais de escala intermediária e ruidosa (NISQ) [1] :

  1. Resiliência a erros : Menos portas (redução de 10 vezes) significa muito menos acúmulo de erros
  2. Não é necessária a mitigação de erros : A eficiência inerente do algoritmo elimina a necessidade de técnicas caras de atenuação de erros [1]
  3. Escalabilidade : Pode lidar com problemas de até 156 qubits (156 variáveis binárias) com mapeamento direto de qubits [1]
  4. Desempenho comprovado : Atinge taxas de aproximação de 100% nas instâncias de referência MaxCut e HUBO [1]

Agora vamos ver esse poderoso algoritmo em ação em nosso problema de divisão de mercado!


Etapa 2: Otimizar o problema para execução em hardware quântico

O algoritmo bf-DCQO lida automaticamente com a otimização de circuitos, criando circuitos quânticos rasos com termos contra-diabáticos projetados especificamente para o backend de destino.

Configure a otimização

O Iskay Optimizer requer vários parâmetros-chave para resolver efetivamente seu problema de otimização. Vamos examinar cada parâmetro e sua função no processo de otimização quântica:

Parâmetros necessários

Parâmetro
Tipo
Descrição
Exemplo
problemaDict[str, float]Coeficientes QUBO em formato de chave de cadeia{"()": -21.0, "(0,4)": 0.5, "(0,1)": 0.5}
problema_tipostrEspecificação do formato: "binary" para QUBO ou "spin" para Ising"binary"
backend_namestrDispositivo quântico alvo"ibm_fez"

Conceitos essenciais

  • Formato do problema : Usamos o site "binary" , pois nossas variáveis são binárias (0/1), representando atribuições de mercado.
  • Seleção de back-end : Escolha entre as QPUs disponíveis (por exemplo, "ibm_fez") com base em suas necessidades e na instância do recurso de computação.
  • Estrutura QUBO : Nosso dicionário de problemas contém os coeficientes exatos da transformação matemática.

Opções avançadas (opcional)

O Iskay oferece recursos de ajuste fino por meio de parâmetros opcionais. Embora os padrões funcionem bem para a maioria dos problemas, você pode personalizar o comportamento para atender a requisitos específicos:

Parâmetro
Tipo
Padrão
Descrição
Tentativasint10000Medições quânticas por iteração (maior = mais preciso)
num_iteraçõesint22Iterações do algoritmo (mais iterações podem melhorar a qualidade da solução)
usar_sessãoboolSimUse sessões IBM para reduzir o tempo de fila
semente_transpiladorintNenhumConjunto para compilação reproduzível de circuitos quânticos
direct_qubit_mappingboolNãoMapear os qubits virtuais diretamente para os qubits físicos
trabalho_tagsList[str]NenhumTags personalizadas para rastreamento de trabalhos
pré-processamento\nívelint0Intensidade de pré-processamento do problema (0-3) - veja detalhes abaixo
pós-processamento\nívelint2Nível de refinamento da solução (0-2) - veja detalhes abaixo
transpilação_nívelint0Testes de otimização do transpilador (0-5) - veja detalhes abaixo
transpile_onlyboolNãoAnalise a otimização do circuito sem executar a execução completa

Níveis de pré-processamento (0-3) : Especialmente importante para problemas maiores que não cabem no momento nos tempos de coerência do hardware. Níveis mais altos de pré-processamento atingem profundidades de circuito mais rasas por meio de aproximações na transpilação do problema:

  • Nível 0 : Circuitos exatos e mais longos
  • Nível 1 : Bom equilíbrio entre precisão e aproximação, cortando apenas os portões com ângulos no percentil 10 mais baixo
  • Nível 2 : Aproximação um pouco maior, cortando os portões com ângulos no percentil 20 mais baixo e usando approximation_degree=0.95 na transpilação
  • Nível 3 : Nível máximo de aproximação, cortando os portões no percentil 30 mais baixo e usando approximation_degree=0.90 na transpilação

Níveis de transpilação (0-5) : Controle os testes avançados de otimização do transpilador para compilação de circuitos quânticos. Isso pode levar a um aumento na sobrecarga clássica e, em alguns casos, pode não alterar a profundidade do circuito. O valor padrão 2 em geral leva ao menor circuito e é relativamente rápido.

  • Nível 0 : otimização do circuito DCQO decomposto (layout, roteamento, programação)
  • Nível 1 : Otimização do site PauliEvolutionGate e, em seguida, do circuito DCQO decomposto ( max_trials=10 )
  • Nível 2 : otimização do site PauliEvolutionGate e, em seguida, do circuito DCQO decomposto ( max_trials=15 )
  • Nível 3 : otimização do site PauliEvolutionGate e, em seguida, do circuito DCQO decomposto ( max_trials=20 )
  • Nível 4 : otimização de PauliEvolutionGate e, em seguida, o circuito DCQO decomposto ( max_trials=25 )
  • Nível 5 : Otimização do site PauliEvolutionGate e, em seguida, do circuito DCQO decomposto ( max_trials=50 )

Níveis de pós-processamento (0-2) : Controle a quantidade de otimização clássica, compensando os erros de inversão de bits com um número diferente de passagens gananciosas de uma pesquisa local:

  • Nível 0 : 1 passe
  • Nível 1 : 2 passes
  • Nível 2 : 3 passes

Modo somente transpile : Agora disponível para usuários que desejam analisar a otimização do circuito sem executar o algoritmo quântico completo.

Exemplo de configuração personalizada

Veja como você pode configurar o Iskay com diferentes definições:

custom_options = {
    # Higher shot count for better statistics
    "shots": 15_000,

    # More iterations for solution refinement
    "num_iterations": 12,

    # Light preprocessing for problem simplification
    "preprocessing_level": 1,

    # Maximum postprocessing for solution quality
    "postprocessing_level": 2,

    # Using higher transpilation level for circuit optimization
    "transpilation_level": 3,

    # Fixed seed for reproducible results
    "seed_transpiler": 42,

    # Custom tracking tags
    "job_tags": ["market_split"]
}

Para este tutorial, manteremos a maioria dos parâmetros padrão e alteraremos apenas o número de iterações do campo de polarização:

# Specify the target backend
backend_name = "ibm_fez"

# Set the number of bias-field iterations and set a tag to identify the jobs
options = {
    "num_iterations": 3,  # Change number of bias-field iterations
    "job_tags": ["market_split_example"],  # Tag to identify jobs
}

# Configure Iskay optimizer
iskay_input = {
    "problem": iskay_input_problem,
    "problem_type": "binary",
    "backend_name": backend_name,
    "options": options,
}

print("Iskay Optimizer Configuration:")
print("=" * 40)
print(f"  Backend: {backend_name}")
print(f"  Problem: {len(iskay_input['problem'])} terms")
print("  Algorithm: bf-DCQO")

Passo 3: Execute usando Qiskit primitives

Agora enviamos nosso problema para ser executado no hardware IBM Quantum. O algoritmo bf-DCQO irá:

  1. Construir circuitos quânticos rasos com termos contra-diabáticos
  2. Execute aproximadamente 10 iterações com otimização de campo de polarização
  3. Realizar o pós-processamento clássico com pesquisa local
  4. Retornar a atribuição de mercado ideal
# Submit the optimization job
print("Submitting optimization job to Kipu Quantum...")
print(
    f"Problem size: {A.shape[1]} variables, {len(iskay_input['problem'])} terms"
)
print(
    "Algorithm: bf-DCQO (bias-field digitized counterdiabatic quantum optimization)"
)

job = iskay_solver.run(**iskay_input)

print("\nJob successfully submitted!")
print(f"Job ID: {job.job_id}")
print("Optimization in progress...")
print(
    f"The bf-DCQO algorithm will efficiently explore "
    f"{2**A.shape[1]:,} possible assignments"
)

Monitorar o status da tarefa

Você pode verificar o status atual do seu trabalho de otimização. Os status possíveis são:

  • QUEUED: O trabalho está aguardando na fila
  • RUNNING: O trabalho está sendo executado atualmente no hardware quântico
  • DONE: Trabalho concluído com êxito
  • CANCELED: O trabalho foi cancelado
  • ERROR: O trabalho encontrou um erro
# Check job status
print(f"Job status: {job.status()}")

Aguarde a conclusão

Essa célula será bloqueada até que o trabalho seja concluído. O processo de otimização inclui:

  • Tempo de fila (aguardando acesso ao hardware quântico)
  • Tempo de execução (executando o algoritmo bf-DCQO com aproximadamente 10 iterações)
  • Tempo de pós-processamento (pesquisa local clássica)

Os tempos de conclusão típicos variam de alguns minutos a dezenas de minutos, dependendo das condições da fila.

# Wait for job completion
while True:
    status = job.status()
    print(
        f"Waiting for job {job.job_id} to complete... (status: {status})",
        end="\r",
        flush=True,
    )
    if status in ["DONE", "CANCELED", "ERROR"]:
        print(
            f"\nJob {job.job_id} completed with status: {status}" + " " * 20
        )
        break
    time.sleep(30)

# Retrieve the optimization results
result = job.result()
print("\nOptimization complete!")

Etapa 4: Pós-processamento e retorno do resultado no formato clássico desejado

Agora, fazemos o pós-processamento dos resultados da execução quântica. Isso inclui:

  • Análise da estrutura da solução
  • Validação da satisfação das restrições
  • Avaliação comparativa com abordagens clássicas

Analisar resultados

Entenda a estrutura do resultado

O Iskay retorna um dicionário de resultados abrangente que contém:

  • solution: Um dicionário que mapeia os índices de variáveis para seus valores ideais (0 ou 1)
  • solution_info: Informações detalhadas, incluindo:
    • bitstring: A atribuição ideal como uma string binária
    • cost: O valor da função objetiva (deve ser 0 para satisfação perfeita das restrições)
    • mapping: Como as posições de bitstring são mapeadas para as variáveis do problema
    • seed_transpiler: Semente usada para reprodutibilidade
  • prob_type: Se a solução está em formato binário ou spin

Vamos examinar a solução retornada pelo otimizador quântico.

# Display the optimization results
print("Optimization Results")
print("=" * 50)
print(f"Problem Type: {result['prob_type']}")
print("\nSolution Info:")
print(f"  Bitstring: {result['solution_info']['bitstring']}")
print(f"  Cost: {result['solution_info']['cost']}")
print("\nSolution (first 10 variables):")
for i, (var, val) in enumerate(list(result["solution"].items())[:10]):
    print(f"  {var}: {val}")
print("  ...")

Validação de solução

Agora, validamos se a solução quântica satisfaz as restrições do Market Split. O processo de validação verifica:

O que é uma violação de restrição?

  • Para cada produto ii, calculamos as vendas reais na Região A: (Ax)i(Ax)_i
  • Comparamos isso com a meta de vendas bib_i
  • A violação é a diferença absoluta: (Ax)ibi|(Ax)_i - b_i|
  • Uma solução viável tem zero violações para todos os produtos

O que esperamos:

  • Caso ideal : Violação total = 0 (todas as restrições perfeitamente satisfeitas)
    • A região A recebe exatamente 1002 unidades do Produto 1, 879 unidades do Produto 2 e 1040 unidades do Produto 3
    • A região B recebe as unidades restantes (também 1002, 879 e 1040, respectivamente)
  • Bom caso : A violação total é pequena (solução quase ideal)
  • Caso ruim : Grandes violações indicam que a solução não atende aos requisitos comerciais

A função de validação será computada:

  1. Vendas reais por produto em cada região
  2. Violações de restrições para cada produto
  3. Distribuição do mercado entre as regiões
def validate_solution(A, b, solution):
    """Validate market split solution."""
    x = np.array(solution)
    region_a = A @ x
    region_b = A @ (1 - x)
    violations = np.abs(region_a - b)

    return {
        "target": b,
        "region_a": region_a,
        "region_b": region_b,
        "violations": violations,
        "total_violation": np.sum(violations),
        "is_feasible": np.sum(violations) == 0,
        "region_a_markets": int(np.sum(x)),
        "region_b_markets": len(x) - int(np.sum(x)),
    }


# Convert bitstring to list of integers and validate
optimal_assignment = [
    int(bit) for bit in result["solution_info"]["bitstring"]
]
validation = validate_solution(A, b, optimal_assignment)

Interprete os resultados da validação

Os resultados da validação mostram se o Quantum Optimizer encontrou uma solução viável. Vamos examinar o seguinte:

Verificação de viabilidade:

  • is_feasible = True significa que a solução satisfaz perfeitamente todas as restrições (violação total = 0)
  • is_feasible = False significa que algumas restrições foram violadas

Análise de vendas:

  • Comparar as vendas pretendidas com as vendas reais de cada produto
  • Para uma solução perfeita: Real = Meta para todos os produtos em ambas as regiões
  • A diferença indica o quanto estamos próximos da divisão de mercado desejada

Distribuição de mercado:

  • Mostra quantos mercados estão atribuídos a cada região
  • Não há exigência de um número igual de mercados, apenas que as metas de vendas sejam atingidas
print("Solution Validation")
print("=" * 50)
print(f"Feasible solution: {validation['is_feasible']}")
print(f"Total constraint violation: {validation['total_violation']}")

print("\nSales Analysis (Target vs Actual):")
for i, (target, actual_a, actual_b) in enumerate(
    zip(validation["target"], validation["region_a"], validation["region_b"])
):
    violation_a = abs(actual_a - target)
    violation_b = abs(actual_b - target)
    print(f"  Product {i+1}:")
    print(f"    Target: {target}")
    print(f"    Region A: {actual_a} (violation: {violation_a})")
    print(f"    Region B: {actual_b} (violation: {violation_b})")

print("\nMarket Distribution:")
print(f"  Region A: {validation['region_a_markets']} markets")
print(f"  Region B: {validation['region_b_markets']} markets")

Avaliação da qualidade da solução

Com base nos resultados de validação acima, podemos avaliar a qualidade da solução quântica:

Se is_feasible = True (violação total = 0):

  • O Quantum Optimizer encontrou com sucesso uma solução ideal
  • Todas as restrições comerciais são perfeitamente atendidas
  • Isso demonstra a vantagem quântica em um problema em que os solucionadores clássicos têm dificuldades [4]

Se is_feasible = False (Total violation > 0):

  • A solução é quase ideal, mas não perfeita
  • Pequenas violações podem ser aceitáveis na prática
  • Considere o ajuste dos parâmetros do otimizador:
    • Aumente o site num_iterations para obter mais passes de otimização
    • Aumente postprocessing_level para um refinamento mais clássico
    • Aumente o site shots para obter melhores estatísticas de medição

Interpretação da função de custo:

  • O valor cost de solution_info é igual a Axb2||Ax - b||^2
  • Custo = 0 indica satisfação perfeita das restrições
  • Valores de custo mais altos indicam maiores violações de restrições

Conclusão

O que conseguimos

Neste tutorial, teremos sucesso:

  1. Carregamento de um problema de otimização real : obteve uma instância desafiadora de Market Split da biblioteca de benchmark QOBLIB [2]
  2. Transformado para o formato QUBO : Converteu o problema restrito em uma formulação quadrática sem restrições [3]
  3. Aproveitamento de algoritmos quânticos avançados : Usou o algoritmo bf-DCQO da Kipu Quantum com termos contra-diabáticos [1]
  4. Obteve soluções ótimas : Encontrou soluções viáveis que satisfazem todas as restrições

Principais conclusões

Inovação do algoritmo : O algoritmo bf-DCQO representa um avanço significativo [1] :

  • 10 vezes menos portas do que o recozimento quântico digital
  • Aproximadamente 10 iterações em vez de aproximadamente 100 para métodos variacionais
  • Resiliência a erros incorporada por meio da eficiência do circuito

Termos contra-diabáticos : Permitem a rápida evolução quântica e, ao mesmo tempo, mantêm a fidelidade do estado fundamental, tornando a otimização quântica prática no hardware ruidoso atual [1].

Orientação de campo de polarização : A abordagem iterativa de campo de polarização permite que cada iteração comece perto de boas soluções encontradas anteriormente, proporcionando uma forma de pesquisa local aprimorada por quantum [1].

Próximas etapas

Para aprofundar seu entendimento e explorar mais:

  1. Experimente instâncias diferentes : Faça experiências com outras instâncias do QOBLIB de tamanhos variados
  2. Sintonizar parâmetros : Adjust num_iterations, preprocessing_level, postprocessing_level
  3. Comparação com o clássico : Benchmark em relação aos solucionadores de otimização clássicos
  4. Experimente estratégias diferentes : Tente encontrar uma codificação melhor para o problema ou formule-o como HUBO (se possível)
  5. Aplique em seu domínio : Adaptar as técnicas de formulação QUBO/HUBO a seus próprios problemas de otimização

Referências

[1] IBM Quantum. "Otimização quântica da Kipu " IBM Quantum Documentação.

[2] QOBLIB - Biblioteca de Benchmarking de Otimização Quântica. Instituto Zuse de Berlim (ZIB). https://git.zib.de/qopt/qoblib-quantum-optimization-benchmarking-library

[3] Glover, F., Kochenberger, G., & Du, Y. (2019). "Análise de ponte quântica I: um tutorial sobre a formulação e o uso de modelos QUBO" 4OR: A Quarterly Journal of Operations Research, 17(4), 335-371.

[4] Lodi, A., Tramontani, A., & Weninger, K. (2023). "O decatlo intratável: Benchmarking Hard Combinatorial Problems" INFORMS Journal on Computing.

Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.