Codificarea Pauli prin Corelație pentru reducerea cerințelor Max-Cut
Estimare de utilizare: 30 de minute pe un procesor Eagle r3 (NOTĂ: Aceasta este doar o estimare. Timpul tău de execuție poate varia.)
Fundal
Acest tutorial prezintă Codificarea Pauli prin Corelație (PCE) [1], o abordare concepută pentru a codifica probleme de optimizare în qubiți cu o eficiență mai mare pentru calculul cuantic. PCE mapează variabile clasice din problemele de optimizare la corelații multi-corp ale matricelor Pauli, rezultând o compresie polinomială a cerințelor de spațiu ale problemei. Prin utilizarea PCE, numărul de qubiți necesari pentru codificare este redus, ceea ce îl face deosebit de avantajos pentru dispozitivele cuantice pe termen scurt cu resurse limitate de qubiți. Mai mult, se demonstrează analitic că PCE atenuează în mod inerent platouri sterpe (barren plateaus), oferind reziliență super-polinomială față de acest fenomen. Această caracteristică integrată permite o performanță fără precedent în solvoarele de optimizare cuantică.
Prezentare generală
Abordarea PCE constă în trei pași principali, ilustrați în Figura 1 din [1] de mai jos:
- Codificarea problemei de optimizare într-un spațiu de corelație Pauli.
- Rezolvarea problemei folosind un solver de optimizare cuantico-clasic.
- Decodificarea soluției înapoi în spațiul original de optimizare.
Abordarea PCE este adaptabilă oricărui solver de optimizare cuantică capabil să proceseze matrici de corelație Pauli.
în Figura 1 din [1] , problema Max-Cut este folosită ca exemplu pentru a ilustra abordarea PCE. Problema Max-Cut cu noduri este codificată într-un spațiu de corelație Pauli, reprezentând problema de optimizare ca o matrice de corelație, mai precis corelații 2-corp ale matricelor Pauli pe qubiți . Culorile nodurilor indică șirul Pauli utilizat pentru fiecare nod codificat.
De exemplu, nodul 1, care corespunde variabilei binare , este codificat prin valoarea de așteptare a lui , în timp ce este codificat de .
Aceasta corespunde comprimării celor variabile ale problemei în qubiți. Mai general, corelațiile -corp permit compresii polinomiale de ordin . Setul Pauli ales cuprinde trei subseturi de șiruri Pauli mutual comutative, permițând estimarea experimentală a tuturor celor corelații cu doar trei configurații de măsurare.
O funcție de pierdere a valorilor de așteptare Pauli care imită funcția obiectiv originală Max-Cut este construită. Funcția de pierdere este apoi optimizată folosind un solver de optimizare cuantico-clasic, cum ar fi Variational Quantum Eigensolver (VQE).
Odată ce optimizarea este completă, soluția este decodificată înapoi în spațiul original de optimizare, obținând soluția optimă Max-Cut.
Cerințe
Înainte de a începe acest tutorial, asigură-te că ai instalat următoarele:
- Qiskit SDK v1.0 sau mai nou, cu suport pentru vizualizare
- Qiskit Runtime v0.22 sau mai nou (
pip install qiskit-ibm-runtime)
Configurare
# Added by doQumentation — required packages for this notebook
!pip install -q networkx numpy qiskit qiskit-ibm-runtime rustworkx scipy
from itertools import combinations
import numpy as np
import rustworkx as rx
from scipy.optimize import minimize
from qiskit.circuit.library import efficient_su2
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session
from rustworkx.visualization import mpl_draw
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
def calc_cut_size(graph, partition0, partition1):
"""Calculate the cut size of the given partitions of the graph."""
cut_size = 0
for edge0, edge1 in graph.edge_list():
if edge0 in partition0 and edge1 in partition1:
cut_size += 1
elif edge0 in partition1 and edge1 in partition0:
cut_size += 1
return cut_size
Pasul 1: Maparea intrărilor clasice la o problemă cuantică
Problema Max-Cut
Problema Max-Cut este o problemă de optimizare combinatorială definită pe un graf , unde este mulțimea vârfurilor și este mulțimea muchiilor. Scopul este de a partiția vârfurile în două mulțimi, și , astfel încât numărul de muchii dintre cele două mulțimi să fie maximizat. Pentru o descriere detaliată a problemei Max-Cut, consultă tutorialul "Algoritmul de optimizare cuantică aproximativă". De asemenea, problema Max-Cut este folosită ca exemplu în tutorialul "Tehnici avansate pentru QAOA". În acele tutoriale, algoritmul QAOA este utilizat pentru a rezolva problema Max-Cut.
Graf -> Hamiltonian
Acest tutorial folosește un graf aleatoriu cu 1000 de noduri.
Dimensiunea problemei poate fi greu de vizualizat, astfel că mai jos este prezentat un graf cu 100 de noduri. (Redarea unui graf cu 1.000 de noduri direct l-ar face prea dens pentru a putea vedea ceva!) Graful cu care lucrăm este de zece ori mai mare.
mpl_draw(rx.undirected_gnp_random_graph(100, 0.1, seed=42))

num_nodes = 1000 # Number of nodes in graph
graph = rx.undirected_gnp_random_graph(num_nodes, 0.1, seed=42)
import networkx as nx
nx_graph = nx.Graph()
nx_graph.add_nodes_from(range(num_nodes))
for edge in graph.edge_list():
nx_graph.add_edge(edge[0], edge[1])
curr_cut_size, partition = nx.approximation.one_exchange(nx_graph, seed=1)
print(f"Initial cut size: {curr_cut_size}")
Initial cut size: 28075
Codificăm graful cu 1000 de noduri în corelații 2-corp ale matricelor Pauli pe 100 de qubiți. Graful este reprezentat ca o matrice de corelație, unde fiecare nod este codificat printr-un șir Pauli. Semnul valorii de așteptare a șirului Pauli indică partiția nodului. De exemplu, nodul 0 este codificat printr-un șir Pauli, . Semnul valorii de așteptare a acestui șir Pauli indică partiția nodului 0. Definim o codificare Pauli prin corelație (PCE) relativ la ca
unde este partiția nodului și este valoarea de așteptare a șirului Pauli care codifică nodul peste o stare cuantică . Acum, să codificăm graful într-un Hamiltonian folosind PCE. Împărțim nodurile în trei mulțimi: , , și . Apoi, codificăm nodurile din fiecare mulțime folosind șirurile Pauli cu , și, respectiv, .
num_qubits = 100
list_size = num_nodes // 3
node_x = [i for i in range(list_size)]
node_y = [i for i in range(list_size, 2 * list_size)]
node_z = [i for i in range(2 * list_size, num_nodes)]
print("List 1:", node_x)
print("List 2:", node_y)
print("List 3:", node_z)
List 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332]
List 2: [333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665]
List 3: [666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999]
def build_pauli_correlation_encoding(pauli, node_list, n, k=2):
pauli_correlation_encoding = []
for idx, c in enumerate(combinations(range(n), k)):
if idx >= len(node_list):
break
paulis = ["I"] * n
paulis[c[0]], paulis[c[1]] = pauli, pauli
pauli_correlation_encoding.append(("".join(paulis)[::-1], 1))
hamiltonian = []
for pauli, weight in pauli_correlation_encoding:
hamiltonian.append(SparsePauliOp.from_list([(pauli, weight)]))
return hamiltonian
pauli_correlation_encoding_x = build_pauli_correlation_encoding(
"X", node_x, num_qubits
)
pauli_correlation_encoding_y = build_pauli_correlation_encoding(
"Y", node_y, num_qubits
)
pauli_correlation_encoding_z = build_pauli_correlation_encoding(
"Z", node_z, num_qubits
)
Pasul 2: Optimizarea problemei pentru execuția pe hardware cuantic
Circuit cuantic
Aici, starea este parametrizată cu , iar acești parametri sunt optimizați folosind o abordare varațională.
Acest tutorial folosește ansatz-ul efficient_su2 pentru algoritmul nostru variațional datorită capacităților sale expresive și ușurinței de implementare.
Folosim, de asemenea, funcția de pierdere relaxată, care va fi introdusă mai târziu în acest tutorial.
Ca rezultat, putem aborda probleme la scară largă cu mai puțini qubiți și adâncimi de circuit mai mici.
# Build the quantum circuit
qc = efficient_su2(num_qubits, ["ry", "rz"], reps=2)
# Optimize the circuit
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
qc = pm.run(qc)
Funcția de pierdere
Pentru funcția de pierdere , folosim o relaxare a funcției obiectiv Max-Cut descrisă în [1], care este definită ca