SQOA Solver - une Qiskit Function de JIJ
Consulte la référence de l'API.
Les Qiskit Functions sont une fonctionnalité expérimentale disponible uniquement pour les utilisateurs des offres IBM Quantum® Premium Plan, Flex Plan et On-Prem (via l'API d'IBM Quantum Platform). Elles sont en préversion et susceptibles de changer.
Vue d'ensemble
Avec SQOA Solver de JIJ, tu peux résoudre de grands problèmes d'optimisation combinatoire sur les ordinateurs quantiques d'IBM®. Le solveur repose sur l'algorithme d'optimisation quantique par échantillonnage avec relaxation quantique (Sampling-based Quantum Optimization Algorithm with Quantum Relaxation, SQOA-QR) [1]. Contrairement aux algorithmes quantiques qui utilisent une correspondance biunivoque entre les variables de décision classiques et les qubits, SQOA Solver peut traiter des problèmes d'optimisation comportant plus de variables que le nombre de qubits disponibles sur les dispositifs quantiques actuels. Sa conception fondée sur l'échantillonnage le rend aussi moins sensible au bruit physique du matériel quantique actuel. Ensemble, ces caractéristiques rendent SQOA Solver bien adapté aux problèmes d'optimisation au stade actuel de l'informatique quantique.
Le solveur traite les problèmes d'optimisation binaire quadratique sans contrainte (Quadratic Unconstrained Binary Optimization, QUBO) donnés sous forme de formulation mathématique classique, et il convertit automatiquement cette formulation classique vers le cadre quantique. Tu peux aussi convertir des problèmes contraints en problèmes sans contrainte grâce à la méthode de pénalité.
Les sections suivantes décrivent le workflow du solveur, les résultats de benchmarks et des exemples de bout en bout qui modélisent des problèmes avec qiskit-addon-opt-mapper et, éventuellement, Open Mathematical prograMming eXchange (OMMX). OMMX est un format de données ouvert et un SDK qui simplifient l'échange de problèmes d'optimisation entre outils logiciels.
Description
SQOA Solver implémente l'algorithme d'optimisation quantique par échantillonnage avec relaxation quantique (SQOA-QR) et l'entoure d'un prétraitement et d'un post-traitement classiques. Cette section explique le cadre SQOA et en quoi il diffère de l'algorithme d'optimisation approximative quantique (Quantum Approximate Optimization Algorithm, QAOA).
La figure suivante montre un schéma du workflow de SQOA Solver.
Le cadre SQOA
SQOA est un cadre fondé sur l'échantillonnage pour l'optimisation combinatoire [1]. Il combine deux techniques : l'optimisation par accès aléatoire quantique (Quantum Random Access Optimization, QRAO) [2], qui encode le problème dans une relaxation quantique, et la diagonalisation quantique par échantillonnage (sample-based quantum diagonalization, SQD) [3], aussi connue sous le nom d'interaction de configurations sélectionnées quantiquement (quantum-selected configuration interaction, QSCI) [4], qui utilise l'ordinateur quantique uniquement pour échantillonner des chaînes de bits et trouve l'état de basse énergie sur un ordinateur classique. SQOA est un cadre au sens où il fixe cette combinaison mais laisse les détails à chaque implémentation, comme la manière d'affecter les variables aux qubits et les circuits qui génèrent les échantillons.
-
Relaxation quantique avec QRAO. QAOA et les autres approches fondées sur le modèle d'Ising représentent chaque variable binaire par l'opérateur de son qubit. QRAO utilise aussi les opérateurs et . Avec un code d'accès aléatoire quantique (QRAC) (3,1), jusqu'à trois variables binaires partagent un même qubit, et chaque variable est représentée par un opérateur de Pauli différent.
Le QUBO devient alors un hamiltonien relaxé qui nécessite moins de qubits que l'hamiltonien d'Ising. Les variables qui interagissent dans le QUBO doivent être placées sur des qubits différents. Si elles partageaient un qubit, le produit de leurs opérateurs de Pauli se réduirait à un seul opérateur sur ce qubit (par exemple, ), et l'hamiltonien relaxé ne représenterait plus leur interaction.
L'affectation des variables aux qubits détermine donc à la fois le nombre de qubits et la qualité de la relaxation, et SQOA Solver conçoit cette affectation dans son prétraitement.
-
Diagonalisation quantique par échantillonnage (SQD). L'ordinateur quantique prépare d'abord un état quantique qui a un recouvrement avec les états de basse énergie de l'hamiltonien relaxé, puis en échantillonne des chaînes de bits. Un ordinateur classique projette l'hamiltonien relaxé sur le sous-espace engendré par les chaînes de bits échantillonnées et le diagonalise pour approximer l'état fondamental.
Comme l'hamiltonien relaxé n'est pas diagonal, la diagonalisation combine les chaînes de bits échantillonnées en une superposition. Avec un hamiltonien d'Ising diagonal, chaque chaîne de bits est déjà un état propre, et la diagonalisation ne ferait que sélectionner le meilleur échantillon. La même approche a été appliquée à des problèmes à grande échelle en chimie quantique.
L'état fondamental approximatif obtenu par SQD ne correspond pas directement à une solution classique du problème d'origine, il faut donc en décoder la solution classique. Comme cet état est calculé sur un ordinateur classique, le décodage, appelé arrondi, est un post-traitement classique. SQOA Solver utilise des techniques de décodage conçues pour obtenir heuristiquement de meilleures solutions classiques.
Le tableau suivant compare SQOA à QAOA, une approche variationnelle courante pour la même classe de problèmes.
| QAOA | SQOA | |
|---|---|---|
| Qubits pour variables binaires | Un qubit contient jusqu'à trois des variables. Le nombre exact dépend de la structure du problème | |
| Utilisation du QPU | Estime de façon répétée l'énergie de circuits paramétrés dans une boucle d'optimisation classique | Échantillonne uniquement des chaînes de bits. Aucun paramètre de circuit n'est entraîné sur le QPU |
| Des échantillons à une solution | Sélectionne la meilleure chaîne de bits mesurée | Diagonalise l'hamiltonien relaxé dans le sous-espace échantillonné sur un ordinateur classique et arrondit l'état obtenu |
Autour de SQOA-QR, SQOA Solver ajoute un traitement classique. Son prétraitement fixe les variables dont les valeurs optimales peuvent être déterminées à l'avance et conçoit l'affectation des variables aux qubits. Son post-traitement affine la solution arrondie par une recherche locale, que tu peux désactiver avec postprocessing_level=0.
Benchmarks
Les performances peuvent dépendre à la fois de l'instance du problème et des étapes de traitement ultérieures. Dans certains cas, des échantillons classiques et des échantillons générés quantiquement peuvent atteindre une qualité de solution finale similaire après un post-traitement équivalent. L'évaluation doit donc prendre en compte l'ensemble du workflow d'optimisation.
Les métriques de benchmark suivantes donnent une indication générale de la qualité des solutions, de la compression des qubits et du temps d'exécution pour une sélection de tailles et de structures de problèmes. Le tableau liste une sélection d'instances de Maximum Independent Set issues de la Quantum Optimization Benchmarking Library (QOBLIB) et deux instances MaxCut 3-régulières. Tu peux charger les instances QOBLIB sous forme d'objets ommx.v1.Instance, avec leurs solutions optimales, grâce au paquet ommx-quantum-benchmarks.
Chaque instance a été exécutée 10 fois sur un processeur IBM Heron r2. Number of qubits compte les qubits réellement utilisés sur le matériel après le prétraitement et l'encodage QRAC. Le taux de compression dépend de l'instance. Approximation ratio (AR) indique la qualité de la meilleure solution trouvée sur les 10 exécutions :
où est la meilleure valeur d'objectif trouvée et est la valeur d'objectif optimale connue. Toutes les instances sont des problèmes de maximisation avec une valeur optimale positive, donc AR vaut au plus 100 %, et 100 % dans la colonne Approximation ratio indique que le solveur a trouvé une solution optimale. Total time est le temps moyen combiné de QPU et de CPU par exécution. QPU time est l'utilisation moyenne d'IBM Quantum Compute par exécution.
| Instance | Nombre de variables | Nombre de qubits | Taux d'approximation | Temps total (secondes) | Temps QPU (secondes) |
|---|---|---|---|---|---|
| maxcut_384_nodes | 384 | 129 | 98.5% | 62.1 | 12.0 |
| gen200_p0-9_44 | 200 | 67 | 100% | 38.0 | 12.0 |
| es60fst02 | 186 | 42 | 100% | 24.7 | 12.0 |
| es60fst04 | 162 | 29 | 100% | 17.9 | 12.0 |
| maxcut_150_nodes | 150 | 51 | 100% | 23.1 | 12.0 |
| sloane_1dc_128 | 128 | 37 | 93.8% | 19.1 | 12.0 |
| sloane_2dc_128 | 128 | 8 | 100% | 12.3 | 11.5 |
| C125-9 | 125 | 43 | 100% | 22.3 | 12.0 |
| es60fst01 | 123 | 12 | 100% | 13.6 | 12.0 |
| es60fst03 | 113 | 26 | 100% | 14.9 | 12.0 |
| sloane_1dc_64 | 64 | 16 | 100% | 13.4 | 11.9 |
| chesapeake | 39 | 13 | 100% | 13.1 | 12.0 |
| football | 35 | 6 | 100% | 12.5 | 12.0 |
| karate | 34 | 2 | 100% | 6.2 | 6.0 |
| ibm32 | 32 | 11 | 100% | 12.9 | 12.0 |
| farm | 17 | 4 | 100% | 8.5 | 8.0 |
Pour commencer
Trouve les informations d'accès à cette Qiskit Function dans le Qiskit Functions Catalog.
Cette section montre comment t'authentifier et charger la fonction, et comment préparer un problème au format dictionnaire accepté par SQOA Solver en utilisant OptimizationProblem de qiskit-addon-opt-mapper. Les exemples qui suivent exécutent la fonction et lisent le résultat.
S'authentifier et charger la fonction
Commence par t'authentifier avec ta clé d'API IBM Quantum. (Le code suivant suppose que tu as déjà enregistré ton compte dans ton environnement local.) Ensuite, crée un client de catalogue comme suit :
# 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")
Préparer l'entrée avec qiskit-addon-opt-mapper
Ce guide modélise les problèmes avec la classe OptimizationProblem de qiskit-addon-opt-mapper. SQOA Solver accepte un problème QUBO sous forme de dictionnaire de coefficients au format tuple-chaîne utilisé par les fonctions d'optimisation d'IBM, de sorte que chaque exemple de ce guide suit le même schéma de préparation côté client :
-
Écrire le modèle. Crée un
OptimizationProblem, ajoute des variables de décision binaires, puis définis l'objectif et les éventuelles contraintes. -
Convertir en QUBO. Convertis le problème avec
OptimizationProblemToQubo, qui ajoute les éventuelles contraintes à l'objectif sous forme de termes de pénalité et renvoie un problème de minimisation sans contrainte équivalent. -
Convertir en dictionnaire. Passe le QUBO à la fonction utilitaire
to_problem_dict()définie dans la section suivante, puis passe le résultat àsolver.run()commeproblem, avecvariable_type="binary".
SQOA Solver minimise toujours un problème sous forme de dictionnaire, ce qui correspond au problème de minimisation que renvoie OptimizationProblemToQubo. Pour un problème de maximisation, la valeur objective_value renvoyée est donc l'opposé de l'objectif d'origine. Pour lire le résultat en termes du problème d'origine, évalue l'affectation renvoyée avec OptimizationProblem, comme le montrent les exemples. Pour les détails du format dictionnaire, consulte Accepted problem formats dans la référence de l'API.
# %pip install qiskit-addon-opt-mapper
Définis une seule fois la fonction utilitaire suivante et réutilise-la dans chaque exemple. Elle convertit le QUBO renvoyé par OptimizationProblemToQubo au format dictionnaire. Les clés utilisent les indices de variables du QUBO, donc les clés de solution x_0, x_1, etc. dans le résultat correspondent à ces indices. Chaque variable reçoit une entrée linéaire, même avec un coefficient nul, afin que la solution renvoyée couvre toutes les 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()}
Exemple 1 : MaxCut sur un graphe 3-régulier
De nombreux problèmes de graphes, comme MaxCut, sont NP-difficiles et sont des candidats naturels pour l'optimisation quantique. Installe networkx comme dépendance supplémentaire pour exécuter cet exemple :
# %pip install networkx
1. Écrire le modèle
Associe une variable binaire à chaque sommet d'un graphe pour indiquer son côté de la coupe. Une arête est coupée lorsque ses extrémités sont de part et d'autre, donc la taille de la coupe est :
Cet objectif est déjà un QUBO sans contrainte, donc OptimizationProblemToQubo ne fait que transformer la maximisation en la minimisation équivalente et laisse les variables inchangées. La classe d'application Maxcut de qiskit_addon_opt_mapper.applications construit le même modèle avec 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. Exécuter le solveur
Convertis le modèle en QUBO puis en dictionnaire, et soumets-le. problem et variable_type sont obligatoires. backend_name est facultatif. Lorsqu'il est omis ou vaut None, la fonction sélectionne le QPU opérationnel le moins occupé disponible pour ton instance.
Le dictionnaire options accepte shots, seed, session, postprocessing_level et job_tags. Pour les descriptions et les valeurs par défaut, consulte la référence de l'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. Récupérer le résultat
job.result() renvoie un dictionnaire à quatre clés :
-
solutionest l'affectation complète des variables, indexée parx_i, oùiest l'indice de la variable (par exemple,x_3). -
objective_valueetfeasiblesont l'objectif et la faisabilité de cette affectation, évalués sur le dictionnaire soumis. -
metadatacontientsolver_infoetresource_usage.
Comme le QUBO est la forme de minimisation de MaxCut, objective_value est l'opposé de la taille de la coupe. Évalue l'affectation sur l'OptimizationProblem d'origine pour lire directement la taille de la coupe.
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. Vérifier l'utilisation des ressources
result["metadata"]["resource_usage"] indique le temps passé dans chaque phase d'exécution. Les phases autres que RUNNING: EXECUTING_QPU indiquent CPU_TIME, le temps réel écoulé de la phase en secondes, lorsqu'il est disponible.
La phase RUNNING: EXECUTING_QPU indique QPU_TIME, l'utilisation du QPU de tous les jobs Quantum Compute de l'exécution, si l'utilisation finale est disponible pour chaque job. Pour plus de détails, consulte la référence de l'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
Exemple 2 : Convertir un problème contraint en QUBO
SQOA Solver accepte les problèmes sans contrainte. Cet exemple montre comment convertir un problème contraint en QUBO avec OptimizationProblemToQubo et reporter le résultat sur les variables du problème d'origine.
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 ajoute les contraintes à l'objectif sous forme de termes de pénalité et convertit le problème en minimisation. Le poids de pénalité approprié dépend du problème.
Après l'exécution, interpret() reporte l'affectation du QUBO sur les variables du problème d'origine.
Évalue l'objectif et la faisabilité sur le problème d'origine. Pour un problème sous forme de dictionnaire, le champ feasible du résultat ne se rapporte qu'au domaine des variables, car le dictionnaire n'a aucune contrainte.
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.]
Exemple 3 : Soumettre une instance OMMX
SQOA Solver accepte aussi une ommx.v1.Instance du SDK OMMX, qui conserve ensemble les noms de variables, les indices et les métadonnées de conversion avec le problème. Par rapport à un dictionnaire, une entrée OMMX présente les avantages suivants :
-
Le résultat contient aussi la
ommx.v1.Solutioncanonique danssolver_info["ommx_solution"]. -
objective_valueest évalué au sens de l'instance, donc l'objectif d'un problème de maximisation n'est pas inversé. -
Pour une instance convertie sur place avec
Instance.to_qubo(),feasibleest évalué par rapport aux contraintes d'origine.
Cet exemple construit le modèle MaxCut de l'exemple 1 avec JijModeling, un outil de modélisation d'optimisation mathématique qui compile les modèles en instances OMMX. Installe JijModeling, qui installe aussi le paquet ommx :
# %pip install "jijmodeling~=2.8.0"
SQOA Solver échange les données OMMX sous forme de chaînes Base64 standard avec remplissage. Définis les fonctions utilitaires suivantes pour cette conversion :
-
to_problem_payload()sérialise uneommx.v1.Instanceen la chaîne que tu passes commeproblem. -
to_ommx_solution()décode laommx.v1.Solutioncanonique à partir du résultat.
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. Écrire le modèle avec JijModeling
La formulation de spin habituelle de MaxCut sur un graphe associe à chaque sommet. Une arête est coupée lorsque , donc la taille de la coupe est :
JijModeling ne fournit pas de variable de décision de spin native, et SQOA Solver accepte des variables binaires de QUBO. Déclare donc et définis l'expression à valeurs de spin dans le modèle. Avec cette expression, l'objectif reste sous la forme de spin standard, et l'instance compilée reste un QUBO binaire.
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 tu affiches maxcut_model dans un notebook, il montre la formulation suivante :
2. Compiler l'instance et exécuter le solveur
Lie le graphe de l'exemple 1 pour compiler une ommx.v1.Instance, puis soumets-la avec variable_type="binary". Une instance OMMX est toujours soumise comme un problème binaire.
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. Récupérer le résultat
Pour une entrée OMMX, objective_value est la taille de la coupe, et to_ommx_solution() décode la solution canonique afin que tu puisses lire l'affectation par nom 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]
Obtenir de l'aide
Pour obtenir de l'aide, écris à info@j-ij.com.
Étapes suivantes
- Demande un essai gratuit de SQOA Solver en remplissant ce formulaire.
- Consulte la référence de l'API de cette Qiskit Function.
- Essaie un exemple de bout en bout dans le tutoriel sur le problème de l'ensemble indépendant maximum.
- Découvre comment modéliser des problèmes d'optimisation avec qiskit-addon-opt-mapper.
- Découvre comment modéliser et échanger des problèmes d'optimisation avec JijModeling et OMMX.
- Lis l'article sur SQOA-QR [1] pour en savoir plus sur le cadre SQOA.
Références
[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