Saltar al contenido principal
Este proyecto está en fase beta. ¿Encontraste un error? Abre un issue en GitHub. ¿Tienes una pregunta o una idea? Pregunta en Discussions — ¡nos encantaría tu opinión!
¿Cómo es la calidad de la traducción en esta página?

SQOA Solver - una Qiskit Function de JIJ

Consulta la referencia de la API.

nota

Qiskit Functions es una función experimental disponible solo para los usuarios del Premium Plan, el Flex Plan y el On-Prem Plan (mediante la API de IBM Quantum Platform) de IBM Quantum®. Están en estado de versión preliminar y sujetas a cambios.

Descripción general​

Con SQOA Solver de JIJ, puedes resolver problemas grandes de optimización combinatoria en computadoras cuánticas de IBM®. El solver se basa en el Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) [1]. A diferencia de los algoritmos cuánticos que usan una correspondencia uno a uno entre variables de decisión clásicas y qubits, SQOA Solver puede manejar problemas de optimización con más variables que el número de qubits disponibles en los dispositivos cuánticos actuales. Además, su diseño basado en muestreo lo hace menos sensible al ruido físico del hardware cuántico actual. En conjunto, estas características hacen que SQOA Solver sea muy adecuado para problemas de optimización en esta etapa de la computación cuántica.

El solver maneja problemas de Quadratic Unconstrained Binary Optimization (QUBO) dados como una formulación matemática clásica, y asigna automáticamente la formulación clásica al entorno cuántico. También puedes convertir problemas con restricciones en problemas sin restricciones mediante el método de penalización.

Las siguientes secciones describen el workflow del solver, los resultados de benchmarks y ejemplos de extremo a extremo que modelan problemas con qiskit-addon-opt-mapper y, opcionalmente, Open Mathematical prograMming eXchange (OMMX). OMMX es un formato de datos abierto y un SDK que simplifica el intercambio de problemas de optimización entre herramientas de software.

Descripción​

SQOA Solver implementa el Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) y lo rodea con preprocesamiento y postprocesamiento clásicos. Esta sección explica el marco SQOA y en qué se diferencia del Quantum Approximate Optimization Algorithm (QAOA).

La siguiente figura muestra un esquema del workflow de SQOA Solver. Esquema del workflow de SQOA Solver, desde el preprocesamiento clásico pasando por el muestreo SQOA hasta el postprocesamiento y la búsqueda local

El marco SQOA​

SQOA es un marco basado en muestreo para la optimización combinatoria [1]. Combina dos técnicas: Quantum Random Access Optimization (QRAO) [2], que codifica el problema en una relajación cuántica, y la diagonalización cuántica basada en muestras (SQD) [3], también conocida como interacción de configuraciones seleccionada cuánticamente (QSCI) [4], que usa la computadora cuántica solo para muestrear cadenas de bits y encuentra el estado de baja energía en una computadora clásica. SQOA es un marco en el sentido de que fija esta combinación pero deja los detalles a cada implementación, como la forma de asignar las variables a los qubits y qué circuitos generan las muestras.

  • Relajación cuántica con QRAO. QAOA y otros enfoques basados en Ising representan cada variable binaria mediante el operador ZZ de su qubit. QRAO usa también los operadores XX e YY. Con un código de acceso aleatorio cuántico (QRAC) (3,1), hasta tres variables binarias comparten un qubit, y cada variable se representa con un operador de Pauli distinto.

    Entonces el QUBO se convierte en un hamiltoniano relajado que necesita menos qubits que el hamiltoniano de Ising. Las variables que interactúan en el QUBO deben colocarse en qubits distintos. Si compartieran un qubit, el producto de sus operadores de Pauli se reduciría a un solo operador sobre ese qubit (por ejemplo, XY=iZXY = iZ), y el hamiltoniano relajado ya no representaría su interacción.

    Por lo tanto, la asignación de variables a qubits determina tanto el número de qubits como la calidad de la relajación, y SQOA Solver diseña esta asignación en su preprocesamiento.

  • Diagonalización cuántica basada en muestras (SQD). Primero, la computadora cuántica prepara un estado cuántico que tiene solapamiento con los estados de baja energía del hamiltoniano relajado y luego muestrea cadenas de bits de él. Una computadora clásica proyecta el hamiltoniano relajado sobre el subespacio generado por las cadenas de bits muestreadas y lo diagonaliza para aproximar el estado fundamental.

    Como el hamiltoniano relajado no es diagonal, la diagonalización combina las cadenas de bits muestreadas en una superposición. Con un hamiltoniano de Ising diagonal, cada cadena de bits ya es un estado propio, y la diagonalización solo seleccionaría la mejor muestra. El mismo enfoque se ha aplicado a problemas a gran escala en química cuántica.

El estado fundamental aproximado obtenido por SQD no corresponde directamente a una solución clásica del problema original, por lo que la solución clásica debe decodificarse a partir de él. Dado que este estado se calcula en una computadora clásica, la decodificación, llamada redondeo, es un postprocesamiento clásico. SQOA Solver usa técnicas de decodificación diseñadas para obtener mejores soluciones clásicas de forma heurística.

La siguiente tabla compara SQOA con QAOA, un enfoque variacional común para la misma clase de problemas.

 QAOASQOA
Qubits para nn variables binariasnnUn qubit contiene hasta tres de las variables. El número exacto depende de la estructura del problema
Uso de la QPUEstima repetidamente la energía de circuitos parametrizados dentro de un bucle de optimización clásicoSolo muestrea cadenas de bits. No se entrena ningún parámetro de circuito en la QPU
De las muestras a una soluciónSelecciona la mejor cadena de bits medidaDiagonaliza el hamiltoniano relajado en el subespacio muestreado en una computadora clásica y redondea el estado resultante

Alrededor de SQOA-QR, SQOA Solver añade procesamiento clásico. Su preprocesamiento fija las variables cuyos valores óptimos se pueden determinar de antemano y diseña la asignación de variables a qubits. Su postprocesamiento refina la solución redondeada con una búsqueda local, que puedes desactivar con postprocessing_level=0.

Benchmarks​

Aviso legal

El rendimiento puede depender tanto de la instancia del problema como de los pasos de procesamiento posteriores. En algunos casos, las muestras clásicas y las muestras generadas cuánticamente pueden alcanzar una calidad de solución final similar tras un postprocesamiento equivalente. Por lo tanto, la evaluación debe considerar el workflow de optimización completo.

Las siguientes métricas de benchmark ofrecen una indicación general de la calidad de la solución, la compresión de qubits y el tiempo de ejecución para tamaños y estructuras de problema seleccionados. La tabla enumera una selección de instancias de Maximum Independent Set de la Quantum Optimization Benchmarking Library (QOBLIB) y dos instancias de MaxCut 3-regulares. Puedes cargar las instancias de QOBLIB como objetos ommx.v1.Instance, junto con sus soluciones óptimas, usando el paquete ommx-quantum-benchmarks.

Cada instancia se ejecutó 10 veces en un procesador IBM Heron r2. Number of qubits cuenta los qubits realmente usados en el hardware tras el preprocesamiento y la codificación QRAC. La razón de compresión depende de la instancia. Approximation ratio (AR) indica la calidad de la mejor solución encontrada en las 10 ejecuciones:

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

donde CbestC_{\textrm{best}} es el mejor valor objetivo encontrado y CoptC_{\textrm{opt}} es el valor objetivo óptimo conocido. Todas las instancias son problemas de maximización con un valor óptimo positivo, por lo que AR es como máximo 100%, y un 100% en la columna Approximation ratio indica que el solver encontró una solución óptima. Total time es el tiempo medio combinado de QPU y CPU por ejecución. QPU time es el uso medio de IBM Quantum Compute por ejecución.

InstanciaNúmero de variablesNúmero de qubitsRazón de aproximaciónTiempo total (segundos)Tiempo 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

Primeros pasos​

Encuentra la información de acceso a esta Qiskit Function en el Qiskit Functions Catalog.

Esta sección muestra cómo autenticarte y cargar la función, y cómo preparar un problema en el formato de diccionario que acepta SQOA Solver usando OptimizationProblem de qiskit-addon-opt-mapper. Los ejemplos siguientes ejecutan la función y leen el resultado.

Autenticarse y cargar la función​

Primero, autentícate con tu clave de API de IBM Quantum. (El siguiente código asume que ya guardaste tu cuenta en tu entorno local.) Luego, crea un cliente de catálogo de la siguiente manera:

# 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")

Preparar la entrada con qiskit-addon-opt-mapper​

Esta guía modela problemas con la clase OptimizationProblem de qiskit-addon-opt-mapper. SQOA Solver acepta un problema QUBO como un diccionario de coeficientes en el formato de tupla-cadena usado por las funciones de optimización de IBM, por lo que todos los ejemplos de esta guía siguen el mismo patrón de preparación en el lado del cliente:

  1. Escribe el modelo. Crea un OptimizationProblem, añade variables de decisión binarias y define el objetivo y las restricciones.

  2. Convierte a QUBO. Convierte el problema con OptimizationProblemToQubo, que añade las restricciones al objetivo como términos de penalización y devuelve un problema de minimización sin restricciones equivalente.

  3. Convierte a un diccionario. Pasa el QUBO a la función auxiliar to_problem_dict() definida en la siguiente sección y pasa el resultado a solver.run() como problem, junto con variable_type="binary".

SQOA Solver siempre minimiza un problema en formato de diccionario, lo cual coincide con el problema de minimización que devuelve OptimizationProblemToQubo. Para un problema de maximización, el objective_value devuelto es por lo tanto el negativo del objetivo original. Para leer el resultado en términos del problema original, evalúa la asignación devuelta con OptimizationProblem, como muestran los ejemplos. Para los detalles del formato de diccionario, consulta Accepted problem formats en la referencia de la API.

# %pip install qiskit-addon-opt-mapper

Define la siguiente función auxiliar una vez y reutilízala en cada ejemplo. Convierte el QUBO devuelto por OptimizationProblemToQubo al formato de diccionario. Las claves usan los índices de variable del QUBO, por lo que las claves de solución x_0, x_1, etc. del resultado corresponden a esos índices. Cada variable recibe una entrada lineal, incluso con coeficiente cero, para que la solución devuelta cubra todas las variables.

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()}

Ejemplo 1: MaxCut en un grafo 3-regular​

Muchos problemas de grafos, como MaxCut, son NP-difíciles y son candidatos naturales para la optimización cuántica. Instala networkx como dependencia adicional para ejecutar este ejemplo:

# %pip install networkx

1. Escribe el modelo​

Asigna una variable binaria xv∈{0,1}x_v \in \{0, 1\} a cada vértice de un grafo G=(V,E)G = (V, E) para indicar su lado del corte. Una arista se corta cuando sus extremos están en lados distintos, por lo que el tamaño del corte es:

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 ya es un QUBO sin restricciones, por lo que OptimizationProblemToQubo solo convierte la maximización en la minimización equivalente y mantiene las variables sin cambios. La clase de aplicación Maxcut en qiskit_addon_opt_mapper.applications construye el mismo modelo con 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. Ejecuta el solver​

Convierte el modelo a un QUBO y luego a un diccionario, y envíalo. problem y variable_type son obligatorios. backend_name es opcional. Cuando se omite o es None, la función selecciona la QPU operativa menos ocupada disponible para tu instancia.

El diccionario options acepta shots, seed, session, postprocessing_level y job_tags. Para ver las descripciones y los valores predeterminados, consulta la referencia de la 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. Recupera el resultado​

job.result() devuelve un diccionario con cuatro claves:

  • solution es la asignación completa de variables, con claves x_i, donde i es el índice de la variable (por ejemplo, x_3).

  • objective_value y feasible son el objetivo y la factibilidad de esa asignación, evaluados sobre el diccionario enviado.

  • metadata contiene solver_info y resource_usage.

Dado que el QUBO es la forma de minimización de MaxCut, objective_value es el negativo del tamaño del corte. Evalúa la asignación sobre el OptimizationProblem original para leer directamente el tamaño del corte.

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. Comprueba el uso de recursos​

result["metadata"]["resource_usage"] informa del tiempo empleado en cada fase de ejecución. Las fases distintas de RUNNING: EXECUTING_QPU informan de CPU_TIME, el tiempo real de la fase en segundos, cuando está disponible.

La fase RUNNING: EXECUTING_QPU informa de QPU_TIME, el uso de QPU de todos los trabajos de Quantum Compute de la ejecución, si el uso final está disponible para cada trabajo. Para más detalles, consulta la referencia de la 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

Ejemplo 2: Convertir un problema con restricciones a QUBO​

SQOA Solver acepta problemas sin restricciones. Este ejemplo muestra cómo convertir un problema con restricciones en un QUBO con OptimizationProblemToQubo y volver a asignar el resultado a las variables del 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 añade las restricciones al objetivo como términos de penalización y convierte el problema a minimización. El peso de penalización adecuado depende del problema.

Tras la ejecución, interpret() vuelve a asignar la asignación del QUBO a las variables del problema original.

Evalúa el objetivo y la factibilidad en el problema original. Para un problema en formato de diccionario, el campo feasible del resultado se refiere solo al dominio de las variables, porque el diccionario no tiene restricciones.

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.]

Ejemplo 3: Enviar una instancia de OMMX​

SQOA Solver también acepta un ommx.v1.Instance del SDK de OMMX, que mantiene juntos los nombres de variables, los subíndices y los metadatos de conversión con el problema. En comparación con un diccionario, una entrada OMMX tiene las siguientes ventajas:

  • El resultado también contiene el ommx.v1.Solution canónico en solver_info["ommx_solution"].

  • objective_value se evalúa en el sentido de la instancia, por lo que el objetivo de un problema de maximización no se niega.

  • Para una instancia convertida en el lugar con Instance.to_qubo(), feasible se evalúa respecto a las restricciones originales.

Este ejemplo construye el modelo MaxCut del Ejemplo 1 con JijModeling, un modelador de optimización matemática que compila modelos en instancias de OMMX. Instala JijModeling, que también instala el paquete ommx:

# %pip install "jijmodeling~=2.8.0"

SQOA Solver intercambia datos OMMX como cadenas Base64 estándar con relleno. Define las siguientes funciones auxiliares para esta conversión:

  • to_problem_payload() serializa un ommx.v1.Instance en la cadena que pasas como problem.

  • to_ommx_solution() decodifica el ommx.v1.Solution canónico del 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. Escribe el modelo con JijModeling​

La formulación de espín habitual de MaxCut en un grafo G=(V,E)G = (V, E) asigna sv∈{−1,+1}s_v \in \{-1, +1\} a cada vértice. Una arista se corta cuando susv=−1s_u s_v = -1, por lo que el tamaño del corte es:

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

JijModeling no proporciona una variable de decisión de espín nativa, y SQOA Solver acepta variables binarias de QUBO. Por lo tanto, declara bv∈{0,1}b_v \in \{0, 1\} y define la expresión con valores de espín sv=1−2bvs_v = 1 - 2b_v dentro del modelo. Con esta expresión, el objetivo se mantiene en la forma de espín estándar y la instancia compilada sigue siendo un QUBO binario.

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)

Si muestras maxcut_model en un notebook, aparece la siguiente formulación:

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. Compila la instancia y ejecuta el solver​

Enlaza el grafo del Ejemplo 1 para compilar un ommx.v1.Instance y envíalo con variable_type="binary". Una instancia de OMMX siempre se envía como un problema binario.

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. Recupera el resultado​

Para una entrada OMMX, objective_value es el tamaño del corte, y to_ommx_solution() decodifica la solución canónica para que puedas leer la asignación por nombre de variable.

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]

Obtener soporte​

Para obtener soporte, escribe un correo a info@j-ij.com.

Próximos pasos​

Recomendaciones

Referencias​

[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