Iskay Quantum Optimizer – funkcja Qiskit od Kipu Quantum
- Funkcje Qiskit to funkcja eksperymentalna dostępna wyłącznie dla użytkowników planów IBM Quantum® Premium Plan, Flex Plan i On-Prem (przez IBM Quantum Platform API). Mają one status wersji przedpremierowej i mogą ulec zmianie.
Przegląd
Dzięki Iskay Quantum Optimizer od Kipu Quantum możesz rozwiązywać złożone problemy optymalizacyjne przy użyciu komputerów kwantowych IBM®. Ten solver wykorzystuje najnowocześniejszy algorytm bf-DCQO firmy Kipu, który wymaga jedynie funkcji celu jako danych wejściowych, aby automatycznie dostarczać rozwiązania problemów. Radzi sobie z problemami optymalizacyjnymi obejmującymi do 156 Qubitów, umożliwiając wykorzystanie wszystkich Qubitów urządzeń kwantowych IBM. Optimizer stosuje odwzorowanie 1-do-1 między zmiennymi klasycznymi a Qubitami, co pozwala rozwiązywać problemy optymalizacyjne z maksymalnie 156 zmiennymi binarnymi.
Optimizer umożliwia rozwiązywanie binarnych problemów optymalizacyjnych bez ograniczeń. Oprócz powszechnie stosowanej formulacji QUBO (Quadratic Unconstrained Binary Optimization) obsługuje również problemy optymalizacyjne wyższego rzędu (HUBO). Solver wykorzystuje niewariacyjny algorytm kwantowy, wykonując większość obliczeń na urządzeniach kwantowych.
Poniżej znajdziesz więcej szczegółów na temat zastosowanego algorytmu oraz krótki przewodnik po sposobie korzystania z funkcji, a także wyniki testów porównawczych dla różnych instancji problemów o różnych rozmiarach i złożonościach.
Opis
Optimizer to gotowa do użycia implementacja najnowocześniejszych algorytmów optymalizacji kwantowej. Rozwiązuje problemy optymalizacyjne, uruchamiając wysoce skompresowane Circuit na sprzęcie kwantowym. Kompresja ta jest osiągana poprzez wprowadzenie terminów kontradiabatycznych do bazowej ewolucji czasowej układu kwantowego. Algorytm wykonuje kilka iteracji uruchomień sprzętowych, aby uzyskać końcowe rozwiązania, i łączy je z przetwarzaniem końcowym. Kroki te są płynnie zintegrowane z przepływem pracy Optimizera i wykonywane automatycznie.
Jak działa Quantum Optimizer?
Ta sekcja przedstawia podstawy zaimplementowanego algorytmu bf-DCQO. Wprowadzenie do algorytmu można również znaleźć na kanale YouTube Qiskit.
Algorytm opiera się na ewolucji czasowej układu kwantowego, który zmienia się w czasie, przy czym rozwiązanie problemu jest zakodowane w stanie podstawowym układu kwantowego na końcu ewolucji. Zgodnie z twierdzeniem adiabatycznym, ta ewolucja musi przebiegać powoli, aby układ pozostawał w swoim stanie podstawowym. Digitalizacja tej ewolucji stanowi podstawę cyfrowego kwantowego obliczania adiabatycznego (DQA) i niesławnego algorytmu QAOA. Jednak wymagana powolna ewolucja nie jest wykonalna dla coraz większych rozmiarów problemów, ponieważ skutkuje rosnącą głębokością Circuit. Stosując protokoły kontradiabatyczne, możesz tłumić niechciane wzbudzenia pojawiające się w krótkich czasach ewolucji, pozostając jednocześnie w stanie podstawowym. Tutaj digitalizacja tego krótszego czasu ewolucji skutkuje Circuit o mniejszej głębokości i mniejszej liczbie bramek splątujących.
Circuit algorytmów bf-DCQO zazwyczaj wykorzystują do dziesięciu razy mniej bramek splątujących niż DQA oraz od trzech do czterech razy mniej bramek splątujących niż standardowe implementacje QAOA. Ze względu na mniejszą liczbę Gate, podczas wykonywania Circuit na sprzęcie pojawia się mniej błędów. Dlatego optimizer nie wymaga stosowania technik takich jak tłumienie błędów czy łagodzenie błędów. Ich implementacja w przyszłych wersjach może jeszcze bardziej poprawić jakość rozwiązań.
Choć algorytm bf-DCQO korzysta z iteracji, jest niewariacyjny. Po każdej iteracji algorytmu mierzona jest dystrybucja stanów. Uzyskana dystrybucja służy do obliczenia tzw. pola biasu. Pole biasu umożliwia rozpoczęcie następnej iteracji ze stanu energetycznego bliskiego poprzednio znalezionemu rozwiązaniu. W ten sposób algorytm z każdą iteracją przesuwa się ku rozwiązaniom o niższej energii. Zazwyczaj około dziesięciu iteracji wystarczy, aby zbiec do rozwiązania, co łącznie wymaga znacznie mniejszej liczby iteracji niż algorytmy wariacyjne, gdzie wynosi ona rzędu około 100 iteracji.
Optimizer łączy algorytm bf-DCQO z klasycznym przetwarzaniem końcowym. Po zmierzeniu dystrybucji stanów wykonywane jest lokalne przeszukiwanie. W trakcie lokalnego przeszukiwania bity zmierzonego rozwiązania są losowo odwracane. Po odwróceniu oceniana jest energia nowego ciągu bitów. Jeśli energia jest niższa, ciąg bitów jest zachowywany jako nowe rozwiązanie. Lokalne przeszukiwanie skaluje się jedynie liniowo z liczbą Qubitów, jest więc obliczeniowo tanie. Ponieważ przetwarzanie końcowe koryguje lokalne odwrócenia bitów, kompensuje błędy odwrócenia bitów, które często są wynikiem niedoskonałości sprzętowych i błędów odczytu.
Przepływ pracy
Poniżej przedstawiono schemat przepływu pracy Quantum Optimizera.
Korzystając z Quantum Optimizera, rozwiązanie problemu optymalizacyjnego na sprzęcie kwantowym można sprowadzić do:
- Sformułowania funkcji celu problemu
- Uzyskania dostępu do Optimizera przez Qiskit Functions
- Uruchomienia Optimizera i zebrania wyników
Testy porównawcze
Poniższe wskaźniki testów porównawczych pokazują, że Optimizer skutecznie rozwiązuje problemy obejmujące do 156 Qubitów i oferują ogólny przegląd dokładności oraz skalowalności optimizera w różnych typach problemów. Zwróć uwagę, że rzeczywiste wskaźniki wydajności mogą się różnić w zależności od specyficznych właściwości problemu, takich jak liczba zmiennych, gęstość i lokalność terminów w funkcji celu oraz rząd wielomianu.
Poniższa tabela zawiera współczynnik aproksymacji (AR), który jest zdefiniowany następująco:
gdzie to funkcja celu, , to odpowiednio jej wartość minimalna i maksymalna, a to koszt najlepszego znalezionego rozwiązania. Zatem AR=100% oznacza, że uzyskano stan podstawowy problemu.
| Przykład | Liczba Qubitów | Współczynnik aproksymacji | Łączny czas (s) | Czas użycia Runtime (s) | Łączna liczba pomiarów | Liczba iteracji |
|---|---|---|---|---|---|---|
| Unweighted MaxCut | 28 | 100% | 180 | 30 | 30k | 5 |
| Unweighted MaxCut | 30 | 100% | 180 | 30 | 30k | 5 |
| Unweighted MaxCut | 32 | 100% | 180 | 30 | 30k | 5 |
| Unweighted MaxCut | 80 | 100% | 480 | 60 | 90k | 9 |
| Unweighted MaxCut | 100 | 100% | 330 | 60 | 60k | 6 |
| Unweighted MaxCut | 120 | 100% | 370 | 60 | 60k | 6 |
| HUBO 1 | 156 | 100% | 600 | 70 | 100k | 10 |
| HUBO 2 | 156 | 100% | 600 | 70 | 100k | 10 |
- Instancje MaxCut z 28, 30 i 32 Qubitami były uruchamiane na ibm_sherbrooke. Instancje z 80, 100 i 120 Qubitami były uruchamiane na procesorze Heron r2.
- Instancje HUBO były również uruchamiane na procesorze Heron r2.
Wszystkie instancje testów porównawczych są dostępne na GitHubie (zob. instancje testów Kipu). Przykład uruchomienia tych instancji można znaleźć w Przykładzie 3: Instancje testów porównawczych.
Wejście i wyjście
Wejście
W poniższej tabeli znajdziesz wszystkie parametry wejściowe akceptowane przez Quantum Optimizer. Następna sekcja Opcje zawiera więcej szczegółów na temat dostępnych options.
| Nazwa | Typ | Opis | Wymagane | Domyślnie | Przykład |
|---|---|---|---|---|---|
| problem | Dict[str, float] | Współczynniki problemu optymalizacyjnego sformułowanego w formacie QUBO/HUBO lub spinowym. Więcej informacji na temat specyfikacji problemu znajdziesz w sekcji Akceptowane formaty problemu | Tak | N/A | {"()": -21.0, "(0, 4)": 0.5,"(0, 2)": 0.5,"(0, 1)": 0.5,"(1, 3)": 0.5} |
| problem_type | str | Określ, czy współczynniki problemu są w formacie binarnym (QUBO/HUBO), czy spinowym. Dwie możliwości to "spin" lub "binary" | Tak | N/A | "spin" |
| backend_name | str | Nazwa Backend, do którego kierowane jest zapytanie | Tak | N/A | "ibm_fez" |
| options | Dict[str, Any] | Opcje obsługi zgłoszenia sprzętowego, takie jak liczba pomiarów. Więcej szczegółów na temat konfiguracji opcji znajdziesz w sekcji Opcje | Nie | Domyślne wartości konfiguracji opcji znajdziesz w sekcji Opcje | {"shots": 5000, "num_iterations": 3, "use_session": True, "seed_transpiler": 42} |
Akceptowane formaty problemu
Argumenty problem i problem_type kodują problem optymalizacyjny postaci
gdzie
- Wybierając
problem_type = "binary", określasz, że funkcja kosztu jest w formaciebinary, co oznacza, że , tzn. funkcja kosztu jest zapisana w formulacji QUBO/HUBO. - Natomiast wybierając
problem_type = "spin", funkcja kosztu jest zapisana w formulacji Isinga, gdzie .
Współczynniki problemu należy zakodować w słowniku w następujący sposób:
- Zwróć uwagę, że klucze słownika muszą być ciągami znaków zawierającymi poprawną krotkę niepowtarzających się liczb całkowitych.
Opcje
Iskay udostępnia możliwości dokładnego dostrajania za pomocą opcjonalnych parametrów. Cho ć domyślne wartości sprawdzają się w większości problemów, możesz dostosować zachowanie do konkretnych wymagań:
| Parametr | Typ | Domyślnie | Opis |
|---|---|---|---|
| shots | int | 10000 | Liczba pomiarów kwantowych na iterację (wyższa wartość = większa dokładność) |
| num_iterations | int | 10 | Liczba iteracji algorytmu (więcej iteracji może poprawić jakość rozwiązania) |
| use_session | bool | True | Użyj sesji IBM w celu skrócenia czasu oczekiwania w kolejce |
| seed_transpiler | int | None | Ustaw, aby zapewnić powtarzalną kompilację Circuit kwantowego |
| direct_qubit_mapping | bool | False | Mapuj wirtualne Qubit bezpośrednio na fizyczne Qubit |
| job_tags | List[str] | None | Niestandardowe tagi do śledzenia zadań |
| preprocessing_level | int | 0 | Intensywność wstępnego przetwarzania problemu (0–3) — szczegóły poniżej |
| postprocessing_level | int | 2 | Poziom dopracowania rozwiązania (0–2) — szczegóły poniżej |
| transpilation_level | int | 0 | Liczba prób optymalizacji Transpiler (0–5) — szczegóły poniżej |
| transpile_only | bool | False | Analizuj optymalizację Circuit bez uruchamiania pełnego wykonania |
Poziomy wstępnego przetwarzania (0–3): Szczególnie istotne w przypadku większych problemów, które aktualnie nie mieszczą się w czasie dekoherencji sprzętu. Wyższe poziomy wstępnego przetwarzania osiągają mniejsze głębokości Circuit poprzez aproksymacje w transpilacji problemu:
- Poziom 0: Dokładny, dłuższe Circuit
- Poziom 1: Dobry balans między dokładnością a aproksymacją — pomija tylko Gate z kątami w najniższym 10. percentylu
- Poziom 2: Nieco wyższa aproksymacja — pomija Gate z kątami w najniższym 20. percentylu i używa
approximation_degree=0.95podczas transpilacji - Poziom 3: Maksymalny poziom aproksymacji — pomija Gate w najniższym 30. percentylu i używa
approximation_degree=0.90podczas transpilacji
Poziomy transpilacji (0–5): Kontrolują zaawansowane próby optymalizacji Transpiler przy kompilacji Circuit kwantowego. Może to zwiększyć narzut klasyczny, a w niektórych przypadkach może nie zmieniać głębokości Circuit. Wartość domyślna 2 na ogół daje najmniejszy Circuit i jest relatywnie szybka.
- Poziom 0: Optymalizacja rozłożonego Circuit DCQO (układ, routing, harmonogramowanie)
- Poziom 1: Optymalizacja
PauliEvolutionGate, a następnie rozłożonego Circuit DCQO (max_trials=10) - Poziom 2: Optymalizacja
PauliEvolutionGate, a następnie rozłożonego Circuit DCQO (max_trials=15) - Poziom 3: Optymalizacja
PauliEvolutionGate, a następnie rozłożonego Circuit DCQO (max_trials=20) - Poziom 4: Optymalizacja
PauliEvolutionGate, a następnie rozłożonego Circuit DCQO (max_trials=25) - Poziom 5: Optymalizacja
PauliEvolutionGate, a następnie rozłożonego Circuit DCQO (max_trials=50)
Poziomy postprocessingu (0–2): Kontrolują ilość klasycznej optymalizacji kompensującej błędy odwrócenia bitów, z różną liczbą zachłannych przebiegów lokalnego przeszukiwania:
- Poziom 0: 1 przebieg
- Poziom 1: 2 przebiegi
- Poziom 2: 3 przebiegi
Tryb tylko transpilacji: Dostępny teraz dla użytkowników, którzy chcą analizować optymalizację Circuit bez uruchamiania pełnego wykonania algorytmu kwantowego.
Przykład niestandardowej konfiguracji: Oto jak możesz skonfigurować Iskay z różnymi ustawieniami:
# Added by doQumentation — required packages for this notebook
!pip install -q PyGithub networkx qiskit-ibm-catalog
custom_options = {
"shots": 15_000, # Higher shot count for better statistics
"num_iterations": 12, # More iterations for solution refinement
"preprocessing_level": 1, # Light preprocessing for problem simplification
"postprocessing_level": 2, # Maximum postprocessing for solution quality
"transpilation_level": 3, # Using higher transpilation level for circuit optimization
"seed_transpiler": 42, # Fixed seed for reproducible results
"job_tags": ["custom_config"], # Custom tracking tags
}
Optymalizacja ziarna: Pamiętaj, że seed_transpiler jest domyślnie ustawiony na None. Umożliwia to automatyczny proces optymalizacji Transpiler. Gdy wartość wynosi None, system rozpocznie próbę z wieloma ziarnami i wybierze to, które daje najlepszą głębokość Circuit, w pełni wykorzystując parametr max_trials dla każdego poziomu transpilacji.
Wydajność poziomów transpilacji: Zwiększanie liczby max_trials przez ustawianie wyższych wartości transpilation_level nieuchronnie wydłuży czas transpilacji, ale nie zawsze zmieni ostateczny Circuit — zależy to w dużej mierze od konkretnej struktury i złożoności Circuit. Jednak w przypadku niektórych Circuit/problemów różnica między 10 próbami (poziom 1) a 50 próbami (poziom 5) może być dramatyczna, dlatego eksploracja tych parametrów może być kluczem do skutecznego znalezienia rozwiązania.
Output
| Name | Type | Description | Example |
|---|---|---|---|
| result | Dict[str, Any] | Rozwiązanie i metadane. Struktura zależy od opcji transpile_only. | Zobacz „Zawartość słownika wyników" poniżej |
Zawartość słownika wyników
Struktura słownika wyników zależy od trybu wykonania:
| Field | Type | Mode | Description | Example |
|---|---|---|---|---|
| solution | Dict[str, int] | Standard | Posortowane zmapowane rozwiązanie, w którym klucze są indeksami zmiennych (jako ciągi znaków) posortowanymi numerycznie, a wartości są odpowiadającymi wartościami zmiennych (1/-1 dla problemów spinowych, 1/0 dla problemów binarnych). | {'0': -1, '1': -1, '2': -1, '3': 1, '4': 1} |
| solution_info | Dict[str, Any] | Standard | Szczegółowe informacje o rozwiązaniu (szczegóły poniżej) | {'bitstring': '11100', 'cost': -13.8, 'seed_transpiler': 42, 'mapping': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}} |
| prob_type | str | Standard | Typ problemu optymalizacyjnego ('spin' lub 'binary') | 'spin' |
| transpilation_info | Dict[str, Any] | Tylko transpilacja | Analiza Circuit i szczegóły transpilacji (szczegóły poniżej) | {'best_seed': 42, 'transpilation_time_seconds': 50.06, 'transpiled_circuit': {'depth': 576, 'gate_count': 4177, 'num_qubits': 156, 'width': 176, 'operations': {'sx': 1325, 'rx': 891, 'cz': 783, 'rz': 650, 'rzz': 466, 'x': 42, 'measure': 20}}} |
Standardowe wykonanie
Gdy opcjonalny parametr transpile_only=False:
Słownik solution_info:
- "bitstring" (
str): Surowa reprezentacja bitstring rozwiązania. - "cost" (
float): Wartość kosztu/energii powiązana z rozwiązaniem. - "seed_transpiler" (
int): Losowe ziarno użyte przez Transpiler, który wyprodukował ten wynik. - "mapping" (
Dict[int, int]): Oryginalne mapowanie Qubit na zmienne użyte w obliczeniach. - "qpu_time" (
float, opcjonalnie): Czas wykonania QPU w sekundach.
Uwagi dotyczące mapowania zmiennych:
- Słownik
solutionjest uzyskiwany z bitstring rozwiązania przy użyciu obiektumappingdo indeksowania zmiennych. - Gdy
problem_type=spin, stosujemy przypisanie . - Klucze w słowniku rozwiązania są indeksami zmiennych posortowanymi numerycznie jako ciągi znaków.
Analiza transpilacji
Gdy opcjonalny parametr transpile_only=True:
Słownik transpilation_info:
- "best_seed" (
int): Optymalne ziarno znalezione dla transpilacji - "transpilation_time_seconds" (
float): Czas poświęcony na proces transpilacji - "transpiled_circuit" (
Dict): Analiza Circuit zawierająca:- "depth" (
int): Głębokość Circuit (liczba warstw) - "gate_count" (
int): Całkowita liczba Gate w Circuit - "num_qubits" (
int): Liczba użytych Qubit - "width" (
int): Szerokość Circuit - "operations" (
Dict[str, int]): Liczba każdego użytego typu Gate
- "depth" (
Użycie trybu tylko transpilacji:
- Dostępny dla użytkowników, którzy chcą analizować optymalizację Circuit bez uruchamiania pełnego wykonania algorytmu kwantowego.
Pierwsze kroki
W tej dokumentacji przeprowadzimy cię przez kolejne etapy korzystania z Iskay Quantum Optimizer. Po drodze pokażemy, jak załadować funkcję z katalogu i jak przekształcić swój problem na prawidłowe dane wejściowe, demonstrując jednocześnie eksperymentowanie z różnymi opcjonalnymi parametrami.
Bardziej szczegółowy przykład znajdziesz w samouczku Rozwiąż problem podziału rynku z Iskay Quantum Optimizer od Kipu Quantum, w którym przechodzimy przez cały proces korzystania z Iskay Solver w celu rozwiązania problemu Market Split — rzeczywistego wyzwania alokacji zasobów, gdzie rynki muszą być podzielone na zrównoważone regiony sprzedaży spełniające dokładne cele popytu.
Uwierzytelnij się za pomocą klucza API, który znajdziesz na pulpicie nawigacyjnym IBM Quantum Platform, a następnie wybierz Qiskit Function w następujący sposób:
# ruff: noqa: F821
Poniższy kod zakłada, że zapisałeś już swoje dane uwierzytelniające. Jeśli tego nie zrobiłeś, postępuj zgodnie z instrukcjami w sekcji zapisz swoje konto IBM Cloud, aby uwierzytelnić się za pomocą klucza API.
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(
channel="ibm_quantum_platform",
instance="INSTANCE_CRN",
token="YOUR_API_KEY", # Use the 44-character API_KEY you created and saved from the IBM Quantum Platform Home dashboard
)
# Access Function
optimizer = catalog.load("kipu-quantum/iskay-quantum-optimizer")
Przykład 1: Prosta funkcja kosztów
Rozważmy funkcję kosztów w sformułowaniu spinowym:
gdzie .
Rozwiązaniem tej prostej funkcji kosztów jest
z wartością minimalną
1. Utwórz funkcję celu
Zaczynamy od utworzenia słownika ze współczynnikami funkcji celu:
objective_func = {
"()": 1,
"(0,)": 1.5,
"(1,)": 2,
"(2,)": 1.3,
"(0, 3)": 2.5,
"(1, 4)": 3.5,
"(0, 1, 2)": 4,
}
2. Uruchom Optimizer
Rozwiązujemy problem, uruchamiając optimizer. Ponieważ , musimy ustawić problem_type=spin.
# Setup options to run the optimizer
options = {"shots": 5000, "num_iterations": 5, "use_session": True}
arguments = {
"problem": objective_func,
"problem_type": "spin",
"backend_name": backend_name, # such as "ibm_fez"
"options": options,
}
job = optimizer.run(**arguments)
3. Pobierz wynik
Rozwiązanie problemu optymalizacji jest dostarczane bezpośrednio przez optimizer.
print(job.result())
Wyświetlony zostanie słownik w następującej postaci:
{'solution': {'0': -1, '1': -1, '2': -1, '3': 1, '4': 1},
'solution_info': {'bitstring': '11100',
'cost': -13.8,
'seed_transpiler': 42,
'mapping': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}},
'prob_type': 'spin'}
Zauważ, że słownik solution wyświetla wektor wynikowy