Constrained Quantum Optimizer - Uma Qiskit Function da Aqarios
Consulte a referência da API
Qiskit Functions são um recurso experimental disponível apenas para usuários dos planos Premium, Flex e On-Prem (via IBM Quantum Platform API) do IBM Quantum®. Elas estão em status de lançamento prévio (preview) e sujeitas a alterações.
Visão geral
Com o Constrained Quantum Optimizer da Aqarios, você pode resolver problemas de otimização binária restrita em hardware quântico IBM® sem reformulação manual e mapeamento de circuito. Basta fornecer um problema como um arquivo LP, um arquivo MPS ou um Luna Model. A função lida automaticamente com a reformulação, a síntese de circuito, a transpilação e a execução em hardware. O solucionador utiliza o warm-start iterativo [1] do algoritmo FlexQAOA, uma extensão nativa de restrições do Quantum Approximate Optimization Algorithm (QAOA).
O otimizador tem como alvo problemas binários com restrições. Em particular, restrições one-hot e restrições de set-packing podem ser impostas de forma nativa usando mixers XY. Outros tipos de restrição são automaticamente reformulados como termos de penalidade.
A função resolve apenas problemas discretos. Toda variável de decisão deve ser binária, ou inteira com limites inferior e superior explícitos, para que possa ser codificada em qubits. Variáveis contínuas (de valor real) não são compatíveis: um modelo que as contenha é rejeitado com o código de erro 4710.
Descrição
O desempenho pode depender tanto da instância do problema quanto das etapas de processamento subsequentes. Em alguns casos, amostras clássicas e amostras geradas quanticamente podem atingir qualidade final de solução semelhante após pós-processamento equivalente. A avaliação deve, portanto, considerar o fluxo de trabalho completo de otimização.
O Constrained Quantum Optimizer implementa o Iterative warm-start XY-mixer QAOA (IWS-QAOA) [1]. O algoritmo executa circuitos QAOA de ângulo fixo em hardware quântico e atualiza as probabilidades iniciais de warm-start de cada circuito usando os resultados de medição da iteração anterior. Não é necessário treinamento de parâmetros variacionais; em vez disso, é escolhida uma parametrização de rampa linear fixa.
Ao usar mixers XY para impor restrições one-hot, você pode melhorar drasticamente a qualidade da solução para problemas restritos, porque o espaço de busca é praticamente reduzido a um subespaço viável menor — e nenhuma complexidade adicional, devido a termos de penalidade, é introduzida no cenário de otimização.
Fluxo de trabalho
O fluxo de trabalho da função é descrito abaixo:
-
Pré-processamento: Antes da síntese do circuito, o otimizador analisa a estrutura de restrições do problema de entrada:
-
Pré-processamento de grafo: Quando aplicável ao problema, ele é analisado como um grafo, em que as arestas determinam a relação entre variáveis. Essa análise de grafo permite duas melhorias no pré-processamento do problema. Primeiro, restrições individuais podem ser agregadas em uma única restrição maior por meio da fusão de cliques (clique merging), de modo que sejam representadas por um único mixer XY. Segundo, variáveis com apenas um único vizinho podem ser fixadas deterministicamente, reduzindo o tamanho e a complexidade do problema.
-
Resolução de restrições: O pré-processador lida com cada restrição separadamente: se a restrição for uma restrição one-hot, ela pode ser imposta por meio de mixers XY. Se for uma restrição de set-packing, ela será primeiro transformada em uma restrição one-hot. Restrições de igualdade são tratadas por meio de penalidades quadráticas, e restrições de desigualdade por meio de penalização desbalanceada.
-
Derivação de penalidade: Restrições que não podem ser expressas como restrições de igualdade one-hot são convertidas em termos de penalidade. O otimizador deriva automaticamente a intensidade da penalidade a partir da estrutura do problema.
-
-
Warm-start iterativo: O otimizador executa múltiplas cadeias paralelas de warm-start. Cada cadeia mantém uma distribuição de probabilidade sobre atribuições de variáveis, que é usada como a probabilidade inicial do circuito QAOA (estado de warm-start). A cada iteração, uma cadeia amostra do circuito quântico, aplica pós-processamento clássico e atualiza sua distribuição com base na ocorrência das amostras. Ao longo das iterações, isso concentra a busca em soluções de alta qualidade sem um loop de otimização variacional.
O número de cadeias (num_parallel), o orçamento total de shots por cadeia (total_shots) e o número de repetições do QAOA (reps) são os principais controles para equilibrar a qualidade da solução em relação ao tempo de execução.
Benchmarks
Os benchmarks abaixo mostram que a Qiskit Function Constrained Quantum Optimizer é capaz de encontrar soluções viáveis e de alta qualidade para problemas de otimização restrita com bem mais de 100 variáveis binárias. A acurácia é a razão entre o valor objetivo encontrado e o ótimo conhecido. O tempo de execução é o tempo de relógio (wall-clock) desde a invocação da função até a entrega do resultado. O uso de QPU é o tempo faturável de Quantum Compute.
Dois problemas foram examinados: o problema Maximum Independent Set (MIS) e o Max--Cut, que é uma extensão do conhecido problema MaxCut para mais de duas categorias. O Max--Cut também é o problema de otimização equivalente ao problema de decisão de coloração de grafos (quando todas as arestas são cortadas, o grafo é -colorível).
| Problema | Variáveis | Restrições | Qubits | Acurácia | Viabilidade | Tempo total de execução (s) | Uso de QPU (s) | Total de shots |
|---|---|---|---|---|---|---|---|---|
| MIS es60fst02 | 186 | 280 | 124 | 100.0% | Verdadeiro | 940.2 | 147.0 | 25.0k |
| MIS sloane_2dc_128 | 128 | 5173 | 74 | 100.0% | Verdadeiro | 347.6 | 106.0 | 12.5k |
| Max-3-Cut Karate Club | 99 | 33 | 99 | 98.7% | Verdadeiro | 279.5 | 166.0 | 25.0k |
| Max-4-Cut Karate Club | 132 | 33 | 132 | 100.0% | Verdadeiro | 258.3 | 200.0 | 25.0k |
Notas sobre os benchmarks
-
Os resultados acima foram obtidos no processador Heron r2
ibm_marrakeshcom opções padrão euse_sessionhabilitado. Para a instânciasloane_2dc_128, foi usadototal_shots=12500. -
A contagem reduzida de qubits para as instâncias de MIS (74 e 124 em comparação com 128 e 186 variáveis) reflete a fixação de variáveis no pré-processamento.
-
As instâncias do problema para o MIS são retiradas da Quantum Optimization Benchmarking Library. - A instância do problema Max--Cut é o grafo Zachary Karate Club, que tem número cromático 5.
Primeiros passos
Este guia demonstra o uso básico do Constrained Quantum Optimizer, mostrando como carregar a função e executar problemas simples. Para um tutorial mais aprofundado, consulte Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer.
Autentique-se com sua chave de API do IBM Quantum e o CRN da instância e, em seguida, carregue a função a partir do catálogo.
O código a seguir pressupõe que você já salvou suas credenciais. Para configurá-las, siga as instruções em Save your IBM Cloud account credentials.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"luna_model": "luna-model", "networkx": "networkx", "qiskit_addon_opt_mapper": "qiskit-addon-opt-mapper", "qiskit_ibm_catalog": "qiskit-ibm-catalog"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
# Verify that you have access to the function
catalog.list()
[QiskitFunction(aqarios/constrained-quantum-optimizer)]
# Load the function
optimizer = catalog.load("aqarios/constrained-quantum-optimizer")
# Check the list of backends you have access to
catalog.backends()
[<IBMBackend('ibm_pittsburgh')>,
<IBMBackend('ibm_boston')>,
<IBMBackend('ibm_phoenix')>,
<IBMBackend('ibm_fez')>,
<IBMBackend('ibm_miami')>,
<IBMBackend('ibm_marrakesh')>,
<IBMBackend('ibm_kingston')>]
# Select the backend you want to use
backend = catalog.backend("ibm_phoenix")
Exemplo 1: Um problema restrito simples
O primeiro exemplo mostra como usar a função com arquivos LP, uma especificação comum de problema de otimização usada em pesquisa operacional. Você formulará o seguinte problema de otimização arbitrário com cinco variáveis binárias sujeito a duas restrições:
1. Formule o problema
Declare diretamente a expressão matemática no seguinte formato de string LP:
lp_str = """\\Problem name: Example
Minimize
obj: [ 2 x_1 x_2 + 4 x_2 x_3 - 2 x_3 x_4 - 4 x_4 x_5 - 4 x_1 x_3 - 8 x_2 x_5 ] / 2
Subject To
c1: x_1 + x_2 + x_3 <= 1
c2: x_3 - x_4 + x_5 = 0
Binaries
x_1 x_2 x_3 x_4 x_5
End
"""
Observe que [ ... ] / 2 é uma notação exigida para objetivos quadráticos pelo padrão LP.
2. Execute o otimizador
Resolva o problema com o otimizador.
# Set up low-resource options for the simple problem
options = {"total_shots": 2000, "num_parallel": 5, "use_session": True}
# Dispatch the job
job_1 = optimizer.run(
problem=lp_str, backend_name=backend.name, options=options
)
print(f"Job ID: {job_1.job_id}")
Job ID: 2e06a3a8-7c29-4c76-94d7-194293363f4a
# Monitor the job status
job_1.status()
'RUNNING: WAITING_FOR_QPU'
3. Recupere o resultado
A solução, mapeando os nomes das variáveis para as atribuições associadas, é fornecida pelo resultado.
result = job_1.result()
result
{'solutions': [{'x_1': 0, 'x_2': 1, 'x_3': 0, 'x_4': 1, 'x_5': 1}],
'solution_bitstrings': ['01011'],
'raw_energy': -6.0,
'objective_value': -6.0,
'feasible': True,
'metadata': {'resource_usage': {'RUNNING: MAPPING': {'CPU': 5.405},
'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU': 9.902},
'RUNNING: WAITING_FOR_QPU': {'CPU': 25.456},
'RUNNING: EXECUTING_QPU': {'CPU': 25.202},
'RUNNING: POST_PROCESSING': {'CPU': 6.481}},
'circuit_metrics': {'before_transpilation': {'num_qubits': 6,
'gate_count': 42,
'depth': 15,
'two_qubit_gate_count': 12,
'two_qubit_gate_depth': 7,
'operations': {'rz': 12,
'p': 8,
'ry': 7,
'rzz': 4,
'cx': 3,
'xx_plus_yy': 3,
'global_phase': 2,
'cry': 2,
'x': 1}},
'after_transpilation': {'num_qubits': 6,
'gate_count': 254,
'depth': 100,
'two_qubit_gate_count': 48,
'two_qubit_gate_depth': 33,
'operations': {'rz': 78, 'sx': 122, 'cz': 48, 'measure': 6, 'x': 0}}},
'solver_info': {'variable_mapping': {'x_1': 0,
'x_2': 1,
'x_3': 2,
'x_4': 3,
'x_5': 4}}}}
O campo solutions no dicionário retornado contém todas as melhores soluções degeneradas encontradas, como dicionários que mapeiam cada nome de variável para sua atribuição. As mesmas soluções também são retornadas como bitstrings em solution_bitstrings; metadata.solver_info.variable_mapping informa qual posição de caractere de uma bitstring pertence a qual variável. Junto com os dados da solução, são fornecidos o objective_value, um indicador feasible e metadata adicionais.
Exemplo 2: Maximum Independent Set
O problema Maximum Independent Set (MIS) busca o maior subconjunto de vértices em um grafo tal que nenhum par de vértices do subconjunto compartilhe uma aresta. Este exemplo resolve o MIS em um grafo regular de 12 nós. Para mais informações sobre o problema e um exemplo maior, consulte o tutorial.
O problema é construído com qiskit-addon-opt-mapper. Instale os pacotes necessários, se preciso:
# %pip install networkx qiskit-addon-opt-mapper
Etapa 1: Defina o problema
Construa um grafo 3-regular aleatório e crie o problema de otimização MIS. Cada nó do grafo se torna uma variável binária, e cada aresta introduz uma restrição garantindo que no máximo um dos extremos seja selecionado.
import networkx as nx
from qiskit_addon_opt_mapper.applications import IndependentSet
from qiskit_addon_opt_mapper.translators import to_docplex_mp
# 12-node random 3-regular graph
G = nx.random_regular_graph(3, 12, seed=7)
# Build MIS problem and export as LP string
mis = IndependentSet(G)
mis_problem = mis.to_optimization_problem()
lp_str = to_docplex_mp(mis_problem).export_as_lp_string()
print(lp_str)
\ This file has been generated by DOcplex
\ ENCODING=ISO-8859-1
\Problem name: Independent set
Maximize
obj: x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9 + x_10 + x_11
Subject To
c0: x_0 + x_4 <= 1
c1: x_0 + x_9 <= 1
c2: x_0 + x_8 <= 1
c3: x_1 + x_2 <= 1
c4: x_1 + x_7 <= 1
c5: x_1 + x_3 <= 1
c6: x_2 + x_4 <= 1
c7: x_2 + x_11 <= 1
c8: x_3 + x_10 <= 1
c9: x_3 + x_11 <= 1
c10: x_4 + x_5 <= 1
c11: x_5 + x_10 <= 1
c12: x_5 + x_6 <= 1
c13: x_6 + x_8 <= 1
c14: x_6 + x_7 <= 1
c15: x_7 + x_9 <= 1
c16: x_8 + x_11 <= 1
c17: x_9 + x_10 <= 1
Bounds
0 <= x_0 <= 1
0 <= x_1 <= 1
0 <= x_2 <= 1
0 <= x_3 <= 1
0 <= x_4 <= 1
0 <= x_5 <= 1
0 <= x_6 <= 1
0 <= x_7 <= 1
0 <= x_8 <= 1
0 <= x_9 <= 1
0 <= x_10 <= 1
0 <= x_11 <= 1
Binaries
x_0 x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 x_11
End
Etapa 2: Execute o otimizador
Resolva o problema com o otimizador.
options = {"total_shots": 2000, "use_session": True}
# Dispatch the job
job_2 = optimizer.run(
problem=lp_str, backend_name=backend.name, options=options
)
print(f"Job ID: {job_2.job_id}")
Job ID: f041431c-b42e-4627-afe5-522fea61faf6
# Monitor the job status
job_2.status()
'QUEUED'
Etapa 3: Recupere e interprete os resultados
Por fim, recuperamos a solução e verificamos sua correção.
result = job_2.result()
print(f"Feasible: {result['feasible']}")
print(f"Independent set size: {int(result['objective_value'])}")
# Extract the selected nodes
solution = result["solutions"][0]
independent_set = [
int(k.split("_")[1]) for k, v in solution.items() if v == 1
]
print(f"Selected nodes: {sorted(independent_set)}")
# Verify no two selected nodes share an edge
conflicts = [
(u, v)
for u, v in G.edges()
if u in independent_set and v in independent_set
]
print(f"Edge conflicts: {conflicts}")
Feasible: True
Independent set size: 5
Selected nodes: [1, 4, 6, 9, 11]
Edge conflicts: []
Exemplo 3: Coloração de grafo com 3 cores (Max-3-Cut)
O problema Max--Cut particiona os vértices de um grafo em grupos para maximizar o número de arestas cujos extremos pertencem a grupos diferentes. Para , isso equivale a encontrar uma 3-coloração que maximize as arestas entre cores diferentes.
Formalmente, atribua cada nó a um dos grupos com variáveis binárias para a cor . A restrição one-hot para cada nó impõe uma atribuição única. O objetivo maximiza as arestas entre grupos diferentes:
As restrições one-hot são ideais para mixers XY, que o otimizador trata de forma nativa.
Este exemplo usa o grafo Zachary Karate Club (34 nós, 78 arestas) e constrói o modelo com o Luna Model. Instale os pacotes necessários, se preciso:
# %pip install networkx matplotlib luna-model
Etapa 1: Defina o problema
Primeiro, gere as variáveis binárias com o pacote luna-model. Em seguida, defina o objetivo e adicione as restrições ao modelo.
import networkx as nx
from luna_model import Model, quicksum
k = 3
G = nx.karate_club_graph()
# Instantiate the Model object
model = Model(name="Max-3-Cut")
# Add binary variables
x = model.add_variables("x", shape=(G.number_of_nodes(), k))
# Add the objective by using the numpy dot abstraction
model.objective = quicksum(x[i].dot(x[j]) for i, j in G.edges)
# Bulk-add the one-hot constraints
model.add_constraints(x.sum(axis=1) == 1)
# Encode the model to send via API
model_enc = model.encode_b64()
Etapa 2: Execute o otimizador
Resolva o problema com o otimizador.
options = {"use_session": True}
# Dispatch the job
job_3 = optimizer.run(
problem=model_enc, backend_name=backend.name, options=options
)
print(f"Job ID: {job_3.job_id}")
Job ID: df911d83-9df7-44a1-bfad-5d66e08676c3
# Monitor the job status
job_3.status()
'RUNNING: WAITING_FOR_QPU'
Etapa 3: Recupere e visualize os resultados
Recupere e visualize os resultados.
result = job_3.result()
solution = result["solutions"][0]
# Map each node to its assigned color group
node_group = {}
for i in G.nodes:
for c in range(k):
if solution[f"x{i},{c}"] == 1:
node_group[i] = c
print(f"Feasible: {result['feasible']}")
print(f"Violations: {int(result['objective_value'])}")
# Visualize the partition
colors = ["tab:blue", "tab:orange", "tab:green"]
node_colors = [colors[node_group[i]] for i in G.nodes()]
nx.draw(G, nx.kamada_kawai_layout(G), node_color=node_colors, node_size=200)
Feasible: True
Violations: 4

Registro de alterações
[0.4.0] - 2026-09-22
Alterações incompatíveis
- O parâmetro de entrada
modelfoi renomeado paraproblem. - O campo de saída
obj_valuefoi renomeado paraobjective_value. - A opção
postprocessingfoi substituída porpostprocessing_level, que recebe um inteiro no intervalo[0, 3]em vez de uma string. Os valores anteriores são mapeados como"off"->0,"weak"->1,"medium"->2e"strong"->3, e o padrão continua sendo3. metadata.circuit_metricsfoi reestruturado. Agora ele informanum_qubits,gate_count,depth,two_qubit_gate_count,two_qubit_gate_deptheoperationsseparadamente parabefore_transpilationeafter_transpilation, em vez de um único dicionário plano com contagens médias de portas. O campo éNonequando o problema foi resolvido durante o pré-processamento e nenhum circuito foi executado (código de erro4712).
Recursos
- Adicionada a opção
seed_transpilerpara tornar a síntese e o roteamento de circuitos reproduzíveis entre execuções. - Adicionada a opção
job_tagspara anexar suas próprias tags a cada job do Qiskit Runtime que a função envia. - Adicionado o campo de saída
solution_bitstrings, que retorna as mesmas soluções desolutionsem formato de bitstring. - Adicionado
metadata.solver_info.variable_mapping, que mapeia cada nome de variável para sua posição de caractere nas entradas desolution_bitstrings.
Documentação
- Documentado que variáveis contínuas (de valor real) não são compatíveis e que variáveis inteiras exigem limites explícitos. Esses modelos falham com o código de erro
4710.
Obtenha suporte
Para dúvidas ou problemas, entre em contato com support@aqarios.com informando o ID do seu job.
Próximos passos
- Solicite acesso ao Constrained Quantum Optimizer da Aqarios.
- Visite a referência da API para a documentação completa de parâmetros e saídas.
- Experimente o tutorial Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer para um aprofundamento em uma instância real de benchmark do QOBLIB.
- Leia a publicação Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers.
Referências
- Bucher et al. (2026), Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers 10.1088/1367-2630/ae8ea2