Skip to main content
IBM Quantum Platform

Solucionador de otimização: uma função Qiskit da Q-CTRL Fire Opal

Consulte a referência da API

Note

As funções do Qiskit 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.

  • O código desta página foi desenvolvido com base nos seguintes requisitos. Recomendamos o uso dessas versões ou versões mais recentes.

    qiskit-ibm-runtime~=0.47.0
    sympy~=1.14.0
    

Visão geral

Com o Fire Opal Optimization Solver, você pode resolver problemas de otimização em escala de serviços públicos em hardware quântico sem precisar de conhecimento quântico. Basta inserir a definição do problema de alto nível, e o Solver se encarrega do resto. Todo o fluxo de trabalho é sensível a ruídos e aproveita o Fire Opal's Performance Management. O Solver fornece de forma consistente soluções precisas para problemas classicamente desafiadores, mesmo em escala de dispositivo completo nas maiores QPUs IBM®.

O Solver é flexível e pode ser utilizado para resolver problemas de otimização combinatória definidos como funções-objetivo ou grafos arbitrários. Os problemas não precisam ser mapeados para a topologia do dispositivo. Tanto os problemas sem restrições quanto os com restrições são solucionáveis, desde que as restrições possam ser formuladas como termos de penalidade. Os exemplos incluídos neste guia demonstram como resolver um problema de otimização em escala de utilidade, com e sem restrições, utilizando diferentes tipos de entrada do Solver. O primeiro exemplo trata de um problema de corte máximo definido em um grafo regular de grau 3 com 156 vértices, enquanto o segundo exemplo aborda um problema de cobertura mínima de vértices com 50 vértices, definido por uma função de custo.

Para obter acesso ao Optimization Solver, entre em contato com a Q-CTRL.


Descrição da função

O Solver otimiza e automatiza totalmente o algoritmo inteiro, desde a supressão de erros no nível do hardware até o mapeamento eficiente do problema e a otimização clássica de loop fechado. Nos bastidores, o pipeline do Solver reduz os erros em todos os estágios, possibilitando o desempenho aprimorado necessário para um dimensionamento significativo. O fluxo de trabalho subjacente é inspirado no Algoritmo de Otimização Aproximada Quântica (QAOA), que é um algoritmo híbrido quântico-clássico. Para obter um resumo detalhado do fluxo de trabalho completo do Optimization Solver, consulte o manuscrito publicado.

Visualização do fluxo de trabalho do Optimization Solver

Para resolver um problema genérico com o Optimization Solver:

  1. Defina seu problema como uma função objetiva, um gráfico ou uma cadeia de spin SparsePauliOp .
  2. Conecte-se à função por meio do Qiskit Functions Catalog.
  3. Execute o problema com o Solver e recupere os resultados.

Formatos de problemas aceitos

  • Representação de expressão polinomial de uma função objetiva. Idealmente criado em Python com um objeto SymPy Poly existente e formatado em uma string usando sympy.srepr.
  • Representação gráfica de um tipo específico de problema. O gráfico deve ser criado usando a biblioteca networkx em Python. Em seguida, ele deve ser convertido em uma string usando a função networkx [nx.readwrite.json_graph.adjacency_data](http://nx.readwrite.json_graph.adjacency_data.).
  • Representação da cadeia de spin de um problema específico. A cadeia de spin deve ser representada como um objeto SparsePauliOp ; consulte a documentação para obter mais detalhes.
Esta função é compatível com todos os back-ends do ` IBM `?

Se você quiser usar um backend que esta função ainda não suporta, entre em contato com a Q-CTRL para solicitar a adição desse suporte.


Referências

Os resultados de benchmarking publicados mostram que o Solver resolve com sucesso problemas com mais de 120 qubits, superando até mesmo os resultados publicados anteriormente sobre recozimento quântico e dispositivos de íons presos. As métricas de referência a seguir fornecem uma indicação aproximada da precisão e do dimensionamento dos tipos de problemas com base em alguns exemplos. As métricas reais podem diferir com base em vários recursos do problema, como o número de termos na função objetiva (densidade) e sua localidade, número de variáveis e ordem polinomial.

O "Número de qubits" indicado não é uma limitação rígida, mas representa limites aproximados em que você pode esperar uma precisão de solução extremamente consistente. Problemas de tamanhos maiores foram resolvidos com sucesso, e os testes além desses limites são incentivados.

A conectividade arbitrária de qubit é suportada em todos os tipos de problemas.

Tipo de problema
Número de qubits
Exemplo
Precisão
Tempo Total (s)
Uso do tempo de execução (s)
Número de iterações
Problemas quadráticos com conexões esparsas1563-corte máximo regular100%176429316
Otimização binária de ordem superior156Modelo de vidro de spin de Ising100%146127216
Problemas quadráticos densamente conectados50Corte máximo com conexão total100%175826812
Problema restrito com termos de penalidade50Cobertura mínima ponderada de vértices com 8% de densidade de bordas100%107421522

Introdução

Primeiro, autentique-se usando sua chave de API IBM Quantum. Em seguida, selecione a função do Qiskit da seguinte maneira. (Este trecho pressupõe que você já tenha salvo sua conta no seu ambiente local.)

from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Verify that you have access to the function
catalog.list()

Output:

[QiskitFunction(qunova/hivqe-chemistry),
 QiskitFunction(global-data-quantum/quantum-portfolio-optimizer),
 QiskitFunction(algorithmiq/tem),
 QiskitFunction(qedma/qesem),
 QiskitFunction(multiverse/singularity),
 QiskitFunction(ibm/circuit-function),
 QiskitFunction(q-ctrl/optimization-solver),
 QiskitFunction(colibritd/quick-pde),
 QiskitFunction(q-ctrl/performance-management),
 QiskitFunction(kipu-quantum/iskay-quantum-optimizer)]
# Access Function
solver = catalog.load("q-ctrl/optimization-solver")

Exemplo: Otimização sem restrições

Resolva o problema do corte máximo (max-cut). O exemplo a seguir demonstra as capacidades do Solver em um problema de corte máximo em um grafo não ponderado de 156 nós e 3 arcos regulares, mas também é possível resolver problemas em grafos ponderados.

Além do qiskit-ibm-catalog, você também usará os seguintes pacotes para executar este exemplo: networkx e numpy. Você pode instalar esses pacotes descomentando a célula a seguir se estiver executando este exemplo em um notebook usando o kernel IPython.

# %pip install networkx numpy

1. Defina o problema

Você pode resolver um problema de corte máximo definindo um problema de grafos e especificando problem_type='maxcut'.

import networkx as nx
import numpy as np

# Generate a random graph with 156 nodes
maxcut_graph = nx.random_regular_graph(d=3, n=156, seed=8)
# Optionally, visualize the graph
nx.draw_networkx(
    maxcut_graph, nx.kamada_kawai_layout(maxcut_graph), node_size=100
)

Output:

Output of the previous code cell

O Solver aceita uma string como entrada de definição do problema.

# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)

2. Execute o problema

Ao usar o método de entrada baseado em gráficos, especifique o tipo de problema.

# Solve the problem
maxcut_job = solver.run(
    problem=problem_as_str,
    problem_type="maxcut",
    backend_name=backend_name,  # E.g. "ibm_fez"
)

Verifique o status da sua carga de trabalho do Qiskit Function ou obtenha os resultados da seguinte maneira:

# Print the ID so you can use it later, if necessary
print(maxcut_job.job_id)

# Get job status
print(maxcut_job.status())

Output:

34b53970-d95a-4e24-8763-fc6f3d112843
QUEUED

3. Recuperar o resultado

Recupere o valor de corte ideal do dicionário de resultados.

Note

O mapeamento das variáveis para a cadeia de bits pode ter mudado. O dicionário de saída contém um variables_to_bitstring_index_map subdicionário, que ajuda a verificar a ordem.

# Poll for results
maxcut_result = maxcut_job.result()

# Take the absolute value of the solution since the cost function is minimized
qctrl_maxcut = abs(maxcut_result["solution_bitstring_cost"])

# Print the optimal cut value found by the Optimization Solver
print(f"Optimal cut value: {qctrl_maxcut}")

Output:

Optimal cut value: 210.0

Você pode verificar a precisão do resultado resolvendo o problema de forma clássica com solucionadores de código aberto, como PuLP se o gráfico não for densamente conectado. Problemas de alta densidade podem exigir solucionadores clássicos avançados para validar a solução.


Exemplo: Otimização restrita

O exemplo anterior de max-cut é um problema comum de otimização binária quadrática sem restrições. O Solucionador de Otimização do Q-CTRL pode ser utilizado para diversos tipos de problemas, incluindo otimização com restrições. É possível resolver tipos arbitrários de problemas inserindo a definição do problema representada como um polinômio, no qual as restrições são modeladas como termos de penalidade.

O exemplo a seguir demonstra como construir uma função de custo para um problema de otimização restrito, cobertura mínima de vértices (MVC).

Além dos pacotes qiskit-ibm-catalog e qiskit , você também usará os seguintes pacotes para executar este exemplo: numpy, networkx, e sympy. Você pode instalar esses pacotes descomentando a célula a seguir se estiver executando este exemplo em um notebook usando o kernel IPython.

# %pip install numpy networkx sympy

1. Defina o problema

Defina um problema de MVC aleatório gerando um gráfico com nós ponderados aleatoriamente.

import networkx as nx
from sympy import symbols, Poly, srepr

# To change the weights, change the seed to any integer.
rng_seed = 18
_rng = np.random.default_rng(rng_seed)
node_count = 50
edge_probability = 0.08
mvc_graph = nx.erdos_renyi_graph(
    node_count, edge_probability, seed=rng_seed, directed=False
)

# add node weights
for i in mvc_graph.nodes:
    mvc_graph.add_node(i, weight=_rng.random())

# Optionally, visualize the graph
nx.draw_networkx(mvc_graph, nx.kamada_kawai_layout(mvc_graph), node_size=200)

Output:

Output of the previous code cell

Um modelo de otimização padrão para MVC ponderado pode ser formulado da seguinte forma. Primeiro, uma penalidade deve ser adicionada para qualquer caso em que uma borda não esteja conectada a um vértice no subconjunto. Portanto, deixe ni=1n_i = 1 se o vértice ii estiver na cobertura (ou seja, no subconjunto) e ni=0n_i = 0 caso contrário. Em segundo lugar, o objetivo é minimizar o número total de vértices no subconjunto, que pode ser representado pela seguinte função:

Minimizey=iVωini\textbf{Minimize}\qquad y = \sum_{i\in V} \omega_i n_i

# Construct the cost function.
variables = symbols([f"n[{i}]" for i in range(node_count)])
cost_function = Poly(0, variables)

for i in mvc_graph.nodes():
    weight = mvc_graph.nodes[i].get("weight", 0)
    cost_function += variables[i] * weight

Agora, cada borda do gráfico deve incluir pelo menos um ponto final da cobertura, o que pode ser expresso como a desigualdade:

ni+nj1 for all (i,j)En_i + n_j \ge 1 \texttt{ for all } (i,j)\in E

Qualquer caso em que uma borda não esteja conectada ao vértice de cobertura deve ser penalizado. Isso pode ser representado na função de custo adicionando uma penalidade no formato P(1ninj+ninj)P(1-n_i-n_j+n_i n_j), em que PP é uma constante de penalidade positiva. Portanto, uma alternativa sem restrições para a desigualdade com restrições para o MVC ponderado é:

Minimizey=iVωini+P((i,j)E(1ninj+ninj))\textbf{Minimize}\qquad y = \sum_{i\in V}\omega_i n_i + P(\sum_{(i,j)\in E}(1 - n_i - n_j + n_i n_j))

# Add penalty term.
penalty_constant = 2
for i, j in mvc_graph.edges():
    cost_function += penalty_constant * (
        1 - variables[i] - variables[j] + variables[i] * variables[j]
    )

2. Execute o problema

# Solve the problem
mvc_job = solver.run(
    problem=srepr(cost_function),
    backend_name=backend_name,  # E.g. "ibm_fez"
)

Verifique o status da sua carga de trabalho do Qiskit Function ou obtenha os resultados da seguinte maneira:

print(mvc_job.status())

Output:

QUEUED

3. Obtenha o resultado

Recupere a solução e analise os resultados. Como esse problema tem nós ponderados, a solução não é simplesmente o número mínimo de nós cobertos. Em vez disso, o custo da solução representa a soma dos pesos dos vértices que estão incluídos na cobertura do vértice. Ele representa o "custo" ou "peso" total de cobrir todas as bordas do gráfico usando os vértices selecionados.

mvc_result = mvc_job.result()
qctrl_cost = mvc_result["solution_bitstring_cost"]

# Print results
print(f"Solution cost: {qctrl_cost}")

Output:

Solution cost: 10.248198273708624

Obtenha suporte

Em caso de dúvidas ou problemas, entre em contato com a Q-CTRL.


Log de mudanças

  • 11/02/2026: Agora oferecemos suporte para ibm_miami

Próximas etapas

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