Constrained Quantum Optimizer - funkcja Qiskit firmy Aqarios
Zobacz dokumentację API
Qiskit Functions to funkcja eksperymentalna dostępna wyłącznie dla użytkowników planów IBM Quantum® Premium Plan, Flex Plan oraz On-Prem (poprzez IBM Quantum Platform API). Znajdują się w stanie wersji zapoznawczej (preview) i mogą ulec zmianie.
Przegląd
Dzięki Constrained Quantum Optimizer firmy Aqarios możesz rozwiązywać problemy optymalizacji binarnej z ograniczeniami na sprzęcie kwantowym IBM® bez ręcznej reformulacji i mapowania obwodów. Wystarczy dostarczyć problem jako plik LP, plik MPS lub Luna Model. Funkcja automatycznie obsługuje reformulację, syntezę obwodów, transpilację i wykonanie na sprzęcie. Solver wykorzystuje iteracyjną rozgrzewkę (warm-starting) [1] algorytmu FlexQAOA, rozszerzenia natywnego dla ograniczeń algorytmu Quantum Approximate Optimization Algorithm (QAOA).
Optymalizator jest przeznaczony do problemów binarnych z ograniczeniami. W szczególności ograniczenia typu one-hot oraz ograniczenia typu set-packing mogą być natywnie egzekwowane za pomocą mikserów XY. Pozostałe typy ograniczeń są automatycznie przekształcane w składniki kary (penalty terms).
Funkcja rozwiązuje wyłącznie problemy dyskretne. Każda zmienna decyzyjna musi być binarna albo całkowitoliczbowa z jawnie podaną dolną i górną granicą, tak aby można ją było zakodować w kubitach. Zmienne ciągłe (rzeczywiste) nie są obsługiwane: model, który je zawiera, zostaje odrzucony z kodem błędu 4710.
Opis
Wydajność może zależeć zarówno od instancji problemu, jak i kolejnych etapów przetwarzania. W niektórych przypadkach próbki klasyczne i próbki wygenerowane kwantowo mogą osiągnąć podobną ostateczną jakość rozwiązania po równoważnym przetwarzaniu końcowym. Dlatego ocena powinna uwzględniać cały przebieg procesu optymalizacji.
Constrained Quantum Optimizer implementuje algorytm Iterative warm-start XY-mixer QAOA (IWS-QAOA) [1]. Algorytm uruchamia na sprzęcie kwantowym obwody QAOA o stałych kątach i aktualizuje początkowe prawdopodobieństwa rozgrzewki (warm-start) każdego obwodu na podstawie wyników pomiarów z poprzedniej iteracji. Nie jest wymagane trenowanie parametrów wariacyjnych; zamiast tego wybierana jest stała parametryzacja w postaci liniowej rampy (linear ramp).
Wykorzystując miksery XY do egzekwowania ograniczeń typu one-hot, można drastycznie poprawić jakość rozwiązań dla problemów z ograniczeniami, ponieważ przestrzeń przeszukiwań jest praktycznie zredukowana do mniejszej przestrzeni rozwiązań dopuszczalnych — a do krajobrazu optymalizacji nie wprowadza się dodatkowej złożoności wynikającej ze składników kary.
Przebieg pracy
Przebieg pracy funkcji opisano poniżej:
-
Wstępne przetwarzanie: Przed syntezą obwodu optymalizator analizuje strukturę ograniczeń problemu wejściowego:
-
Wstępne przetwarzanie grafu: Jeśli ma to zastosowanie do problemu, jest on analizowany jako graf, w którym krawędzie określają zależności między zmiennymi. Ta analiza grafu umożliwia dwa usprawnienia wstępnego przetwarzania problemu. Po pierwsze, pojedyncze ograniczenia mogą zostać zagregowane w jedno duże ograniczenie za pomocą łączenia klik (clique merging), tak aby były reprezentowane przez pojedynczy mikser XY. Po drugie, zmienne mające tylko jednego sąsiada mogą zostać ustalone w sposób deterministyczny, co zmniejsza rozmiar i złożoność problemu.
-
Rozwiązywanie ograniczeń: Preprocesor obsługuje każde ograniczenie osobno: jeśli ograniczenie jest typu one-hot, może zostać wyegzekwowane za pomocą mikserów XY. Jeśli jest to ograniczenie typu set-packing, zostanie ono najpierw przekształcone w ograniczenie typu one-hot. Ograniczenia równościowe są obsługiwane za pomocą kar kwadratowych, a ograniczenia nierównościowe za pomocą niezrównoważonej penalizacji.
-
Wyznaczanie kary: Ograniczenia, których nie można wyrazić jako ograniczenia równościowe typu one-hot, są przekształcane w składniki kary. Optymalizator automatycznie wyznacza siłę kary na podstawie struktury problemu.
-
-
Iteracyjna rozgrzewka (warm-starting): Optymalizator uruchamia wiele równoległych łańcuchów rozgrzewki. Każdy łańcuch przechowuje rozkład prawdopodobieństwa przypisań zmiennych, który jest wykorzystywany jako początkowe prawdopodobieństwo obwodu QAOA (stan rozgrzewki). W każdej iteracji łańcuch pobiera próbki z obwodu kwantowego, stosuje klasyczne przetwarzanie końcowe i aktualizuje swój rozkład na podstawie występowania próbek. Na przestrzeni iteracji koncentruje to przeszukiwanie na rozwiązaniach wysokiej jakości bez pętli optymalizacji wariacyjnej.
Liczba łańcuchów (num_parallel), całkowity budżet strzałów na łańcuch (total_shots) oraz liczba powtórzeń QAOA (reps) to główne parametry umożliwiające kompromis między jakością rozwiązania a czasem wykonania.
Testy porównawcze
Poniższe testy porównawcze pokazują, że funkcja Qiskit Constrained Quantum Optimizer jest w stanie znaleźć wysokiej jakości, dopuszczalne rozwiązania problemów optymalizacji z ograniczeniami ze znacznie ponad 100 zmiennymi binarnymi. Dokładność to stosunek znalezionej wartości funkcji celu do znanego optimum. Czas wykonania to czas rzeczywisty (wall-clock) od wywołania funkcji do dostarczenia wyniku. Zużycie QPU to rozliczany czas obliczeń kwantowych (Quantum Compute time).
Zbadano dwa problemy: problem Maximum Independent Set (MIS) oraz Max--Cut, który jest rozszerzeniem dobrze znanego problemu MaxCut na więcej niż dwie kategorie. Max--Cut jest również odpowiednikiem problemu decyzyjnego kolorowania grafu w postaci problemu optymalizacyjnego (gdy wszystkie krawędzie są przecięte, graf jest -kolorowalny).
| Problem | Zmienne | Ograniczenia | Kubity | Dokładność | Wykonalność | Całkowity czas wykonania (s) | Zużycie QPU (s) | Łączna liczba strzałów |
|---|---|---|---|---|---|---|---|---|
| MIS es60fst02 | 186 | 280 | 124 | 100.0% | True | 940.2 | 147.0 | 25.0k |
| MIS sloane_2dc_128 | 128 | 5173 | 74 | 100.0% | True | 347.6 | 106.0 | 12.5k |
| Max-3-Cut Karate Club | 99 | 33 | 99 | 98.7% | True | 279.5 | 166.0 | 25.0k |
| Max-4-Cut Karate Club | 132 | 33 | 132 | 100.0% | True | 258.3 | 200.0 | 25.0k |
Uwagi do testów porównawczych
-
Powyższe wyniki uzyskano na procesorze
ibm_marrakeshHeron r2 z domyślnymi opcjami i włączoną opcjąuse_session. Dla instancjisloane_2dc_128użytototal_shots=12500. -
Zmniejszona liczba kubitów dla instancji MIS (74 i 124 wobec 128 i 186 zmiennych) odzwierciedla ustalanie zmiennych podczas wstępnego przetwarzania.
-
Instancje problemu MIS pochodzą z Quantum Optimization Benchmarking Library. - Instancją problemu Max--Cut jest graf Zachary Karate Club, który ma liczbę chromatyczną równą 5.
Rozpoczęcie pracy
Ten przewodnik przedstawia podstawowe użycie Constrained Quantum Optimizer, pokazując, jak wczytać funkcję i uruchomić proste problemy. Bardziej szczegółowy samouczek znajdziesz w Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer.
Uwierzytelnij się za pomocą klucza API IBM Quantum i CRN instancji, a następnie wczytaj funkcję z katalogu.
Poniższy kod zakłada, że zapisałeś swoje dane uwierzytelniające. Aby je skonfigurować, postępuj zgodnie z instrukcjami w 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")
Przykład 1: Prosty problem z ograniczeniami
Pierwszy przykład pokazuje, jak używać funkcji z plikami LP, powszechnie stosowaną specyfikacją problemów optymalizacyjnych w badaniach operacyjnych. Sformułujesz następujący przykładowy problem optymalizacyjny z pięcioma zmiennymi binarnymi podlegający dwóm ograniczeniom:
1. Sformułuj problem
Zapisz bezpośrednio wyrażenie matematyczne w następującym formacie LP-string:
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
"""
Zwróć uwagę, że [ ... ] / 2 to wymagana notacja dla celów kwadratowych zgodnie ze standardem LP.
2. Uruchom optymalizator
Rozwiąż problem za pomocą optymalizatora.
# 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. Pobierz wynik
Rozwiązanie, mapujące nazwy zmiennych na powiązane przypisania, jest dostarczane przez wynik.
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}}}}
Pole solutions w zwracanym słowniku zawiera wszystkie znalezione zdegenerowane najlepsze rozwiązania, w postaci słowników przypisujących każdej nazwie zmiennej jej wartość. Te same rozwiązania są również zwracane jako ciągi bitów w solution_bitstrings; metadata.solver_info.variable_mapping wskazuje, która pozycja znaku w ciągu bitów odpowiada której zmiennej. Oprócz danych rozwiązania dostępne są objective_value, flaga feasible oraz dodatkowe metadata.
Przykład 2: Maximum Independent Set
Problem Maximum Independent Set (MIS) polega na znalezieniu największego podzbioru wierzchołków grafu, w którym żadne dwa wierzchołki podzbioru nie są połączone krawędzią. Ten przykład rozwiązuje MIS na regularnym grafie z 12 węzłami. Więcej informacji o problemie i większy przykład znajdziesz w samouczku.
Problem jest budowany za pomocą qiskit-addon-opt-mapper. Zainstaluj wymagane pakiety, jeśli to konieczne:
# %pip install networkx qiskit-addon-opt-mapper
Krok 1: Zdefiniuj problem
Zbuduj losowy graf 3-regularny i utwórz problem optymalizacyjny MIS. Każdy węzeł grafu staje się zmienną binarną, a każda krawędź wprowadza ograniczenie zapewniające, że wybrany zostanie co najwyżej jeden z jej końców.
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
Krok 2: Uruchom optymalizator
Rozwiąż problem za pomocą optymalizatora.
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'
Krok 3: Pobierz i zinterpretuj wyniki
Na koniec pobieramy rozwiązanie i weryfikujemy jego poprawność.
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: []
Przykład 3: Kolorowanie grafu 3 kolorami (Max-3-Cut)
Problem Max--Cut dzieli wierzchołki grafu na grup, aby zmaksymalizować liczbę krawędzi, których końce należą do różnych grup. Dla jest to równoważne znalezieniu 3-kolorowania, które maksymalizuje liczbę krawędzi między różnymi kolorami.
Formalnie, przypisz każdy węzeł do jednej z grup za pomocą zmiennych binarnych dla koloru . Ograniczenie typu one-hot dla każdego węzła wymusza unikalne przypisanie. Funkcja celu maksymalizuje krawędzie między grupami:
Ograniczenia typu one-hot są idealne dla mikserów XY, które optymalizator obsługuje natywnie.
Ten przykład wykorzystuje graf Zachary Karate Club (34 węzły, 78 krawędzi) i buduje model za pomocą Luna Model. Zainstaluj wymagane pakiety, jeśli to konieczne:
# %pip install networkx matplotlib luna-model
Krok 1: Zdefiniuj problem
Najpierw wygeneruj zmienne binarne za pomocą pakietu luna-model. Następnie zdefiniuj funkcję celu i dodaj ograniczenia do modelu.
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()
Krok 2: Uruchom optymalizator
Rozwiąż problem za pomocą optymalizatora.
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'
Krok 3: Pobierz i zwizualizuj wyniki
Pobierz i zwizualizuj wyniki.
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

Dziennik zmian
[0.4.0] - 2026-09-22
Zmiany łamiące zgodność
- Zmieniono nazwę parametru wejściowego
modelnaproblem. - Zmieniono nazwę pola wyjściowego
obj_valuenaobjective_value. - Zastąpiono opcję
postprocessingopcjąpostprocessing_level, która przyjmuje liczbę całkowitą z zakresu[0, 3]zamiast łańcucha znaków. Poprzednie wartości odpowiadają:"off"->0,"weak"->1,"medium"->2oraz"strong"->3, a wartość domyślna pozostaje bez zmian i wynosi3. - Zmieniono strukturę
metadata.circuit_metrics. Zawiera ona teraznum_qubits,gate_count,depth,two_qubit_gate_count,two_qubit_gate_depthioperationsosobno dlabefore_transpilationiafter_transpilation, zamiast jednego płaskiego słownika uśrednionych liczb bramek. Pole ma wartośćNone, gdy problem został rozwiązany podczas przetwarzania wstępnego i nie uruchomiono żadnego obwodu (kod błędu4712).
Nowe funkcjonalności
- Dodano opcję
seed_transpiler, aby synteza i routing obwodu były powtarzalne między uruchomieniami. - Dodano opcję
job_tags, aby dołączać własne tagi do każdego zadania Qiskit Runtime przesyłanego przez funkcję. - Dodano pole wyjściowe
solution_bitstrings, które zwraca te same rozwiązania cosolutionsw postaci ciągów bitów. - Dodano
metadata.solver_info.variable_mapping, które mapuje nazwę każdej zmiennej na jej pozycję znaku we wpisachsolution_bitstrings.
Dokumentacja
- Udokumentowano, że zmienne ciągłe (rzeczywiste) nie są obsługiwane, a zmienne całkowitoliczbowe wymagają jawnych granic. Takie modele kończą się błędem z kodem
4710.
Uzyskaj pomoc
W przypadku pytań lub problemów skontaktuj się pod adresem support@aqarios.com, podając identyfikator zadania (job ID).
Kolejne kroki
- Poproś o dostęp do Constrained Quantum Optimizer firmy Aqarios.
- Odwiedź dokumentację API, aby zapoznać się z pełną dokumentacją parametrów i wyników.
- Wypróbuj samouczek Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer, aby dogłębnie poznać rzeczywistą instancję testową QOBLIB.
- Zapoznaj się z publikacją Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers.
Bibliografia
- Bucher et al. (2026), Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers 10.1088/1367-2630/ae8ea2