Pular para o conteúdo principal
Este projeto está em fase beta. Encontrou um bug? Abra uma issue no GitHub. Tem uma pergunta ou ideia? Pergunte no Discussions — adoraríamos receber seu feedback!
Como está a qualidade da tradução nesta página?

SQOA Solver - uma Qiskit Function da JIJ

Veja a referência da API.

nota

As 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) Plan. Elas estão em status de versão preliminar (preview) e sujeitas a alterações.

Visão geral​

Com o SQOA Solver da JIJ, você pode resolver grandes problemas de otimização combinatória em computadores quânticos IBM®. O solver é baseado no Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) [1]. Diferentemente dos algoritmos quânticos que usam um mapeamento um-para-um entre variáveis de decisão clássicas e qubits, o SQOA Solver consegue lidar com problemas de otimização com mais variáveis do que o número de qubits disponíveis nos dispositivos quânticos atuais. Seu design baseado em amostragem também o torna menos sensível ao ruído físico do hardware quântico atual. Juntas, essas características tornam o SQOA Solver adequado para problemas de otimização nesta etapa da computação quântica.

O solver trata problemas de Quadratic Unconstrained Binary Optimization (QUBO) dados como uma formulação matemática clássica e mapeia automaticamente essa formulação clássica para o cenário quântico. Você também pode converter problemas com restrições em problemas sem restrições usando o método de penalidade.

As seções a seguir descrevem o workflow do solver, os resultados de benchmark e exemplos de ponta a ponta que modelam problemas com o qiskit-addon-opt-mapper e, opcionalmente, com o Open Mathematical prograMming eXchange (OMMX). O OMMX é um formato de dados aberto e um SDK que simplifica a troca de problemas de otimização entre ferramentas de software.

Descrição​

O SQOA Solver implementa o Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) e o envolve com pré-processamento e pós-processamento clássicos. Esta seção explica o framework SQOA e como ele difere do Quantum Approximate Optimization Algorithm (QAOA).

A figura a seguir mostra um esquema do workflow do SQOA Solver. Esquema do workflow do SQOA Solver, do pré-processamento clássico, passando pela amostragem SQOA, até o pós-processamento e a busca local

O framework SQOA​

O SQOA é um framework baseado em amostragem para otimização combinatória [1]. Ele combina duas técnicas: Quantum Random Access Optimization (QRAO) [2], que codifica o problema em um relaxamento quântico, e diagonalização quântica baseada em amostras (SQD) [3], também conhecida como quantum-selected configuration interaction (QSCI) [4], que usa o computador quântico apenas para amostrar bitstrings e encontra o estado de baixa energia em um computador clássico. O SQOA é um framework no sentido de que fixa essa combinação, mas deixa os detalhes para cada implementação, como a forma de atribuir as variáveis aos qubits e quais circuitos geram as amostras.

  • Relaxamento quântico com QRAO. O QAOA e outras abordagens baseadas em Ising representam cada variável binária pelo operador ZZ do seu qubit. O QRAO também usa os operadores XX e YY. Com um código de acesso aleatório quântico (QRAC) (3,1), até três variáveis binárias compartilham um qubit, e cada variável é representada por um operador de Pauli diferente.

    O QUBO então se torna um Hamiltoniano relaxado que precisa de menos qubits do que o Hamiltoniano de Ising. Variáveis que interagem no QUBO devem ser colocadas em qubits diferentes. Se compartilhassem um qubit, o produto de seus operadores de Pauli se reduziria a um único operador nesse qubit (por exemplo, XY=iZXY = iZ), e o Hamiltoniano relaxado deixaria de representar a interação entre elas.

    A atribuição de variáveis a qubits determina, portanto, tanto o número de qubits quanto a qualidade do relaxamento, e o SQOA Solver projeta essa atribuição em seu pré-processamento.

  • Diagonalização quântica baseada em amostras (SQD). O computador quântico primeiro prepara um estado quântico que tem sobreposição com estados de baixa energia do Hamiltoniano relaxado e depois amostra bitstrings dele. Um computador clássico projeta o Hamiltoniano relaxado no subespaço gerado pelos bitstrings amostrados e o diagonaliza para aproximar o estado fundamental.

    Como o Hamiltoniano relaxado não é diagonal, a diagonalização combina os bitstrings amostrados em uma superposição. Com um Hamiltoniano de Ising diagonal, todo bitstring já é um autoestado, e a diagonalização apenas selecionaria a melhor amostra. A mesma abordagem foi aplicada a problemas de grande escala em química quântica.

O estado fundamental aproximado obtido pelo SQD não corresponde diretamente a uma solução clássica do problema original, então a solução clássica precisa ser decodificada a partir dele. Como esse estado é calculado em um computador clássico, a decodificação, chamada de arredondamento, é um pós-processamento clássico. O SQOA Solver usa técnicas de decodificação projetadas para obter melhores soluções clássicas de forma heurística.

A tabela a seguir compara o SQOA com o QAOA, uma abordagem variacional comum para a mesma classe de problemas.

 QAOASQOA
Qubits para nn variáveis bináriasnnUm qubit comporta até três das variáveis. O número exato depende da estrutura do problema
Uso da QPUEstima repetidamente a energia de circuitos parametrizados dentro de um laço de otimização clássicoApenas amostra bitstrings. Nenhum parâmetro de circuito é treinado na QPU
Das amostras a uma soluçãoSeleciona o melhor bitstring medidoDiagonaliza o Hamiltoniano relaxado no subespaço amostrado em um computador clássico e arredonda o estado resultante

Em torno do SQOA-QR, o SQOA Solver adiciona processamento clássico. Seu pré-processamento fixa as variáveis cujos valores ótimos podem ser determinados antecipadamente e projeta a atribuição de variáveis a qubits. Seu pós-processamento refina a solução arredondada com uma busca local, que você pode desativar com postprocessing_level=0.

Benchmarks​

Aviso legal

O desempenho pode depender tanto da instância do problema quanto das etapas de processamento posteriores. Em alguns casos, amostras clássicas e amostras geradas quanticamente podem alcançar uma qualidade de solução final semelhante após um pós-processamento equivalente. Portanto, a avaliação deve considerar o workflow de otimização completo.

As métricas de benchmark a seguir dão uma indicação geral da qualidade da solução, da compressão de qubits e do tempo de execução em tamanhos e estruturas de problema selecionados. A tabela lista uma seleção de instâncias de Maximum Independent Set da Quantum Optimization Benchmarking Library (QOBLIB) e duas instâncias de MaxCut 3-regulares. Você pode carregar as instâncias da QOBLIB como objetos ommx.v1.Instance, junto com suas soluções ótimas, usando o pacote ommx-quantum-benchmarks.

Cada instância foi executada 10 vezes em um processador IBM Heron r2. Number of qubits conta os qubits realmente usados no hardware após o pré-processamento e a codificação QRAC. A taxa de compressão depende da instância. Approximation ratio (AR) informa a qualidade da melhor solução encontrada nas 10 execuções:

AR=CbestCopt,\mathrm{AR} = \frac{C_{\textrm{best}}}{C_{\textrm{opt}}},

em que CbestC_{\textrm{best}} é o melhor valor objetivo encontrado e CoptC_{\textrm{opt}} é o valor objetivo ótimo conhecido. Todas as instâncias são problemas de maximização com valor ótimo positivo, então o AR é no máximo 100%, e 100% na coluna Approximation ratio indica que o solver encontrou uma solução ótima. Total time é o tempo médio combinado de QPU e CPU por execução. QPU time é o uso médio do IBM Quantum Compute por execução.

InstânciaNúmero de variáveisNúmero de qubitsRazão de aproximaçãoTempo total (segundos)Tempo de QPU (segundos)
maxcut_384_nodes38412998.5%62.112.0
gen200_p0-9_4420067100%38.012.0
es60fst0218642100%24.712.0
es60fst0416229100%17.912.0
maxcut_150_nodes15051100%23.112.0
sloane_1dc_1281283793.8%19.112.0
sloane_2dc_1281288100%12.311.5
C125-912543100%22.312.0
es60fst0112312100%13.612.0
es60fst0311326100%14.912.0
sloane_1dc_646416100%13.411.9
chesapeake3913100%13.112.0
football356100%12.512.0
karate342100%6.26.0
ibm323211100%12.912.0
farm174100%8.58.0

Primeiros passos​

Encontre as informações de acesso a esta Qiskit Function no Qiskit Functions Catalog.

Esta seção mostra como autenticar e carregar a função, e como preparar um problema no formato de dicionário aceito pelo SQOA Solver usando OptimizationProblem do qiskit-addon-opt-mapper. Os exemplos seguintes executam a função e leem o resultado.

Autentique e carregue a função​

Primeiro, autentique-se com sua chave de API do IBM Quantum. (O código a seguir pressupõe que você já salvou sua conta no seu ambiente local.) Em seguida, crie um cliente de catálogo da seguinte forma:

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"jijmodeling": "jijmodeling", "networkx": "networkx", "ommx": "ommx", "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(jij/sqoa-solver)]
solver = catalog.load("jij/sqoa-solver")

Prepare a entrada com o qiskit-addon-opt-mapper​

Este guia modela problemas com a classe OptimizationProblem do qiskit-addon-opt-mapper. O SQOA Solver aceita um problema QUBO como um dicionário de coeficientes no formato de tupla-string usado pelas funções de otimização da IBM, então todos os exemplos deste guia seguem o mesmo padrão de preparação no lado do cliente:

  1. Escreva o modelo. Crie um OptimizationProblem, adicione variáveis de decisão binárias e defina o objetivo e quaisquer restrições.

  2. Converta para QUBO. Converta o problema com OptimizationProblemToQubo, que adiciona as restrições ao objetivo como termos de penalidade e retorna um problema de minimização equivalente sem restrições.

  3. Converta para um dicionário. Passe o QUBO para a função auxiliar to_problem_dict() definida na próxima seção e passe o resultado para solver.run() como problem, junto com variable_type="binary".

O SQOA Solver sempre minimiza um problema em formato de dicionário, o que corresponde ao problema de minimização que OptimizationProblemToQubo retorna. Para um problema de maximização, o objective_value retornado é, portanto, o negativo do objetivo original. Para ler o resultado em termos do problema original, avalie a atribuição retornada com OptimizationProblem, como mostram os exemplos. Para detalhes do formato de dicionário, consulte Accepted problem formats na referência da API.

# %pip install qiskit-addon-opt-mapper

Defina a seguinte função auxiliar uma vez e reutilize-a em todos os exemplos. Ela converte o QUBO retornado por OptimizationProblemToQubo para o formato de dicionário. As chaves usam os índices de variáveis do QUBO, de modo que as chaves de solução x_0, x_1 e assim por diante no resultado correspondem a esses índices. Toda variável recebe uma entrada linear, mesmo com coeficiente zero, para que a solução retornada cubra todas as variáveis.

from qiskit_addon_opt_mapper import OptimizationProblem
from qiskit_addon_opt_mapper.converters import OptimizationProblemToQubo

def to_problem_dict(qubo: OptimizationProblem) -> dict[str, float]:
"""Convert a QUBO from OptimizationProblemToQubo to the SQOA Solver dictionary format."""
objective = qubo.objective
payload = {"()": objective.constant}
# Keep every variable in the problem, even with a zero linear coefficient.
payload.update({f"({i},)": 0.0 for i in range(qubo.get_num_vars())})
for i, coefficient in objective.linear.to_dict().items():
payload[f"({i},)"] += coefficient
for (i, j), coefficient in objective.quadratic.to_dict().items():
# Fold a binary diagonal term x_i * x_i = x_i into the linear term.
key = f"({i},)" if i == j else f"({i}, {j})"
payload[key] = payload.get(key, 0.0) + coefficient
return {key: float(value) for key, value in payload.items()}

Exemplo 1: MaxCut em um grafo 3-regular​

Muitos problemas de grafos, como o MaxCut, são NP-difíceis e são candidatos naturais à otimização quântica. Instale o networkx como dependência adicional para executar este exemplo:

# %pip install networkx

1. Escreva o modelo​

Atribua uma variável binária xv∈{0,1}x_v \in \{0, 1\} a cada vértice de um grafo G=(V,E)G = (V, E) para indicar seu lado do corte. Uma aresta é cortada quando suas extremidades estão em lados diferentes, então o tamanho do corte é:

Cut(x)=∑(u,v)∈E(xu+xv−2xuxv).\mathrm{Cut}(x) = \sum_{(u,v) \in E} \left(x_u + x_v - 2 x_u x_v\right).

Este objetivo já é um QUBO sem restrições, então OptimizationProblemToQubo apenas transforma a maximização na minimização equivalente e mantém as variáveis inalteradas. A classe de aplicação Maxcut em qiskit_addon_opt_mapper.applications constrói o mesmo modelo com Maxcut(G).to_optimization_problem().

import networkx as nx

G = nx.random_regular_graph(3, 40, seed=42)

linear = {v: 0 for v in G.nodes}
quadratic = {}
for u, v in G.edges:
linear[u] += 1
linear[v] += 1
quadratic[(u, v)] = -2

maxcut = OptimizationProblem("MaxCut")
maxcut.binary_var_list(G.number_of_nodes(), name="x")
maxcut.maximize(linear=linear, quadratic=quadratic)

2. Execute o solver​

Converta o modelo para um QUBO e depois para um dicionário, e envie-o. problem e variable_type são obrigatórios. backend_name é opcional. Quando é omitido ou None, a função seleciona a QPU operacional menos ocupada disponível para a sua instância.

O dicionário options aceita shots, seed, session, postprocessing_level e job_tags. Para descrições e valores padrão, consulte a referência da API.

qubo = OptimizationProblemToQubo().convert(maxcut)

job = solver.run(
problem=to_problem_dict(qubo),
variable_type="binary",
backend_name="ibm_fez",
options={
"shots": 4096,
"seed": 42,
},
)

3. Obtenha o resultado​

job.result() retorna um dicionário com quatro chaves:

  • solution é a atribuição completa das variáveis, indexada por x_i, em que i é o índice da variável (por exemplo, x_3).

  • objective_value e feasible são o objetivo e a viabilidade dessa atribuição, avaliados no dicionário enviado.

  • metadata contém solver_info e resource_usage.

Como o QUBO é a forma de minimização do MaxCut, objective_value é o negativo do tamanho do corte. Avalie a atribuição no OptimizationProblem original para ler o tamanho do corte diretamente.

result = job.result()

x = [result["solution"][f"x_{i}"] for i in range(maxcut.get_num_vars())]
print(f"Cut value: {maxcut.objective.evaluate(x)}")
print(f"Nodes on side 1: {[v for v, value in enumerate(x) if value > 0.5]}")
Cut value: 55.0
Nodes on side 1: [5, 7, 9, 11, 14, 16, 17, 19, 21, 23, 24, 26, 30, 31, 33, 34, 36, 37, 38]

4. Verifique o uso de recursos​

result["metadata"]["resource_usage"] informa o tempo gasto em cada fase de execução. As fases diferentes de RUNNING: EXECUTING_QPU informam CPU_TIME, o tempo real (wall-clock) da fase em segundos, quando disponível.

A fase RUNNING: EXECUTING_QPU informa QPU_TIME, o uso de QPU de todos os jobs do Quantum Compute da execução, se o uso final estiver disponível para cada job. Para detalhes, consulte a referência da API.

for phase, metrics in result["metadata"]["resource_usage"].items():
line = f"{phase:36s}"
if "CPU_TIME" in metrics:
line += f" CPU {metrics['CPU_TIME']:8.1f} s"
if "QPU_TIME" in metrics:
line += f" QPU {metrics['QPU_TIME']:8.1f} s"
print(line)
RUNNING: MAPPING CPU 3.2 s
RUNNING: OPTIMIZING_FOR_HARDWARE CPU 5.0 s
RUNNING: WAITING_FOR_QPU CPU 1.1 s
RUNNING: EXECUTING_QPU QPU 3.0 s
RUNNING: POST_PROCESSING CPU 0.9 s

Exemplo 2: Converta um problema com restrições para QUBO​

O SQOA Solver aceita problemas sem restrições. Este exemplo mostra como converter um problema com restrições em um QUBO com OptimizationProblemToQubo e mapear o resultado de volta para as variáveis do problema original.

selection = OptimizationProblem("ConstrainedExample")
selection.binary_var_list(2, name="x")
selection.maximize(linear={"x0": 1, "x1": 1})
selection.linear_constraint({"x0": 1, "x1": 1}, "<=", 1, name="at_most_one")

print(selection.prettyprint())
Problem name: ConstrainedExample

Maximize
x0 + x1

Subject to
Linear constraints (1)
x0 + x1 <= 1 'at_most_one'

Binary variables (2)
x0 x1

OptimizationProblemToQubo adiciona as restrições ao objetivo como termos de penalidade e converte o problema para minimização. O peso de penalidade apropriado depende do problema.

Após a execução, interpret() mapeia a atribuição do QUBO de volta para as variáveis do problema original.

Avalie o objetivo e a viabilidade no problema original. Para um problema em formato de dicionário, o campo feasible do resultado se refere apenas ao domínio das variáveis, porque o dicionário não tem restrições.

converter = OptimizationProblemToQubo(penalty=4.0)
qubo = converter.convert(selection)

job = solver.run(
problem=to_problem_dict(qubo),
variable_type="binary",
backend_name="ibm_fez",
)
result = job.result()

x_qubo = [result["solution"][f"x_{i}"] for i in range(qubo.get_num_vars())]
x = converter.interpret(x_qubo)
print("Objective:", selection.objective.evaluate(x))
print("Feasible:", selection.is_feasible(x))
print("x values:", x)
Objective: 1.0
Feasible: True
x values: [1. 0.]

Exemplo 3: Envie uma instância OMMX​

O SQOA Solver também aceita um ommx.v1.Instance do SDK OMMX, que mantém juntos, com o problema, os nomes das variáveis, os subscritos e os metadados de conversão. Em comparação com um dicionário, uma entrada OMMX tem as seguintes vantagens:

  • O resultado também contém o ommx.v1.Solution canônico em solver_info["ommx_solution"].

  • objective_value é avaliado no sentido da instância, então o objetivo de um problema de maximização não é negado.

  • Para uma instância convertida no local com Instance.to_qubo(), feasible é avaliado em relação às restrições originais.

Este exemplo constrói o modelo MaxCut do Exemplo 1 com o JijModeling, um modelador de otimização matemática que compila modelos em instâncias OMMX. Instale o JijModeling, que também instala o pacote ommx:

# %pip install "jijmodeling~=2.8.0"

O SQOA Solver troca dados OMMX como strings Base64 padrão com preenchimento. Defina as seguintes funções auxiliares para essa conversão:

  • to_problem_payload() serializa um ommx.v1.Instance na string que você passa como problem.

  • to_ommx_solution() decodifica o ommx.v1.Solution canônico a partir do resultado.

import base64

from ommx.v1 import Instance, Solution

def to_problem_payload(instance: Instance) -> str:
"""Serialize an OMMX instance into the `problem` string for SQOA Solver."""
return base64.b64encode(instance.to_bytes()).decode()

def to_ommx_solution(result: dict) -> Solution:
"""Decode the canonical OMMX solution from a SQOA Solver result."""
payload = result["metadata"]["solver_info"]["ommx_solution"]
return Solution.from_bytes(base64.b64decode(payload, validate=True))

1. Escreva o modelo com o JijModeling​

A formulação de spin usual do MaxCut em um grafo G=(V,E)G = (V, E) atribui sv∈{−1,+1}s_v \in \{-1, +1\} a cada vértice. Uma aresta é cortada quando susv=−1s_u s_v = -1, então o tamanho do corte é:

Cut⁡(s)=∑(u,v)∈E1−susv2.\operatorname{Cut}(s) = \sum_{(u,v) \in E} \frac{1 - s_u s_v}{2}.

O JijModeling não oferece uma variável de decisão de spin nativa, e o SQOA Solver aceita variáveis QUBO binárias. Portanto, declare bv∈{0,1}b_v \in \{0, 1\} e defina a expressão com valor de spin sv=1−2bvs_v = 1 - 2b_v dentro do modelo. Com essa expressão, o objetivo permanece na forma de spin padrão, e a instância compilada continua sendo um QUBO binário.

import jijmodeling as jm

@jm.Problem.define("MaxCut", sense=jm.ProblemSense.MAXIMIZE)
def maxcut_model(problem: jm.DecoratedProblem):
V = problem.Natural() # number of nodes
E = problem.Graph(dtype=V) # edge list
b = problem.BinaryVar(shape=(V,))
s = 1 - 2 * b # spin-valued expression

problem += jm.sum((1 - s[u] * s[v]) / 2 for u, v in E)

Se você exibir maxcut_model em um notebook, ele mostrará a seguinte formulação:

Problem ⁣:MaxCutmax⁡∑⟨u,v⟩∈E1−(1−2⋅b)u⋅(1−2⋅b)v2whereDecision Variables:bi∈{0,1}a 1-dim array of binary decision variables∀i∈{0,…,V−1}Placeholders:Ei∈V×Va 1-dim array of placeholders with elements in V×V∀i∈{0,…,len_at(E,0)−1}V∈Na scalar placeholder in N\begin{array}{rl} \text{Problem}\colon &\text{MaxCut}\\ \displaystyle \max &\displaystyle \sum _{\left\langle u,v\right\rangle \in E}{\frac{1-{\left(1-2\cdot b\right)}_{u}\cdot {\left(1-2\cdot b\right)}_{v}}{2}}\\ &\\ \text{where}&\\ &\text{Decision Variables:}\\ &\qquad \begin{alignedat}{2}{b}_{i}&\in \left\{0,1\right\}&\qquad &\text{a }1\text{-dim array of }\text{binary}\text{ decision variables}\\ &\forall i\in \left\{0,\ldots ,V-1\right\}&&\\ \end{alignedat}\\ &\\ &\text{Placeholders:}\\ &\qquad \begin{alignedat}{2}{E}_{i}&\in V\times V&\qquad &\text{a }1\text{-dim array of placeholders with elements in }V\times V\\ &\forall i\in \left\{0,\ldots ,\mathop{\mathtt{len\_{}at}}\left(E,0\right)-1\right\}&&\\ &&&\\ V&\in \mathbb{N}&\qquad &\text{a scalar placeholder in }\mathbb{N}\\ \end{alignedat}\end{array}

2. Compile a instância e execute o solver​

Associe o grafo do Exemplo 1 para compilar um ommx.v1.Instance e envie-o com variable_type="binary". Uma instância OMMX é sempre enviada como um problema binário.

instance = maxcut_model.eval(
{"V": G.number_of_nodes(), "E": [list(edge) for edge in G.edges]}
)

job = solver.run(
problem=to_problem_payload(instance),
variable_type="binary",
backend_name="ibm_fez",
)

3. Obtenha o resultado​

Para uma entrada OMMX, objective_value é o tamanho do corte, e to_ommx_solution() decodifica a solução canônica para que você possa ler a atribuição pelo nome da variável.

result = job.result()
print(f"Cut value: {result['objective_value']}")

solution = to_ommx_solution(result)
b_values = solution.extract_decision_variables("b")
print(
f"Nodes on side 1: {sorted(v for (v,), value in b_values.items() if value > 0.5)}"
)
Cut value: 55.0
Nodes on side 1: [5, 7, 9, 11, 14, 16, 17, 19, 21, 23, 24, 26, 30, 31, 33, 34, 36, 37, 38]

Obtenha suporte​

Para suporte, envie um e-mail para info@j-ij.com.

Próximos passos​

Recomendações

Referências​

[1] Matsuyama, H., & Yamashiro, Y. (2025). Sampling-based quantum optimization algorithm with quantum relaxation. 2025 IEEE International Conference on Quantum Computing and Engineering (QCE), 1, 2323–2333. DOI, arXiv:2504.12629

[2] Fuller, B., Hadfield, C., Glick, J. R., Imamichi, T., Itoko, T., Thompson, R. J., Jiao, Y., Kagele, M. M., Blom-Schieber, A. W., Raymond, R., et al. (2024). Approximate solutions of combinatorial problems via quantum relaxations. IEEE Transactions on Quantum Engineering, 5, 1–15. DOI, arXiv:2111.03167

[3] Robledo-Moreno, J., Motta, M., Haas, H., Javadi-Abhari, A., Jurcevic, P., Kirby, W., et al. (2025). Chemistry beyond the scale of exact diagonalization on a quantum-centric supercomputer. Science Advances, 11(25), eadu9991. DOI, arXiv:2405.05068

[4] Kanno, K., Kohda, M., Imai, R., Koh, S., Mitarai, K., Mizukami, W., & Nakagawa, Y. O. (2026). Quantum-selected configuration interaction: Classical diagonalization of Hamiltonians in subspaces selected by quantum computers. Physical Review Research, 8(2), 023268. DOI, arXiv:2302.11320