양자 근사 최적화 알고리즘
사용 예상 시간: Heron r3 프로세서에서 22분(참고: 이는 예상치일 뿐입니다. 런타임은 다를 수 있습니다.)
학습 성과
- 고전적 조합 최적화 문제(최대 절단 문제)를 양자 해밀토니안으로 매핑하는 방법
- IBM Quantum 컴퓨트 서비스 세션을 사용하여 양자 근사 최적화 알고리즘(QAOA)을 구현하고 실행하는 방법
- 소규모 시뮬레이터 예제에서 유틸리티급 하드웨어 실행으로 QAOA 워크플로를 확장하는 방법
전제조건
- 양자 회로의 기초
- 변분 알고리즘
- QAOA 심층 분석 — QAOA 알고리즘에 대한 포괄적인 설명 및 대규모 전력망 적용 사례
배경
양자 근사 최적화 알고리즘(QAOA) 은 조합 최적화 문제를 해결하기 위한 양자-고전 하이브리드 반복법이다. 이 튜토리얼에서는 QAOA를 사용하여 최대 절단(max-cut) 문제를 해결할 것입니다. 이 문제는 클러스터링, 네트워크 과학, 통계 물리학 등에 응용되는 NP-완전 최적화 문제입니다. 가장자리로 연결된 노드들로 구성된 그래프가 주어졌을 때, 분할을 가로지르는 가장자리의 개수가 최대가 되도록 노드들을 두 집합으로 나누는 것이 목표이다.
고전 최적화에서 양자 회로에 이르기까지
맥스컷은 고전적인 이진 최적화 문제로 표현될 수 있다. 각 노드에는 자신이 속한 집합을 나타내는 이진 변수 가 할당됩니다. 목표는 양 끝점이 서로 다른 집합에 속하는 변의 개수를 최대화하는 것입니다:
이는 형태의 2차 무제약 이진 최적화(QUBO) 문제와 동등합니다. 표준 변수 대입( )을 통해, 이 QUBO는 기저 상태가 최적 해를 포함하는 비용 해밀토니안 으로 다시 표현될 수 있습니다. 일반적으로 이 해밀토니안은 2차 항과 1차 항을 모두 포함합니다:
여기서 다루는 가중치 없는 최대 절단 문제(unweighted max-cut problem)의 경우, 각 변에 대해 선형 계수들은 0이 되며( ), 이므로, 아래 코드에서 구현하게 될 더 간단한 형태인 가 남게 됩니다. 위에서 언급한 더 일반적인 형태는 이 워크플로를 가중 그래프나 기타 QUBO로 표현 가능한 문제로 적용할 때 필요한 것입니다.
QAOA의 작동 원리
QAOA는 초기 중첩 상태 에 비용 연산자 와 혼합 연산자 를 번갈아 가며 적용하여 후보 해를 도출합니다. 각도 와 는 고전적 피드백 루프를 통해 최적화되며, 양자 컴퓨터는 비용 함수를 평가하고, 고전적 최적화기는 수렴할 때까지 매개변수를 업데이트합니다. 이 반복 루프는 양자 컴퓨팅 세션 내에서 실행되며, 이를 통해 반복 과정 전반에 걸쳐 양자 장치가 예약된 상태를 유지함으로써 지연 시간을 줄입니다.
QUBO에서 해밀턴 연산자로의 완전한 유도 과정을 포함한 QAOA 이론에 대한 보다 심층적인 내용은 QAOA 강의 모듈 을 참고하십시오.
이 튜토리얼에서는 먼저 5개 노드로 구성된 작은 그래프에서 최대 절단(max-cut) 문제를 해결한 다음, 실제 하드웨어 환경에서 동일한 워크플로를 100개 노드로 구성된 대규모 유틸리티급 문제로 확장해 보겠습니다. 요금제 이용 관련 참고 사항: 이 튜토리얼에서는 ‘Quantum Compute’ 세션을 사용하며, 이 세션은 프리미엄 요금제에서만 이용할 수 있습니다. Open Plan 요금제를 이용 중이라면, 이 튜토리얼을 설명된 대로 실행할 수 없습니다. 대신, Session 를 작업 모드로 변경해야 합니다(즉, 최적화 루프를 로 감싸지 않고 각 반복을 독립적인 작업으로 제출해야 합니다 Session(...)). 워크플로는 여전히 실행되지만, 각 반복마다 예약된 장치를 재사용하는 대신 전체 큐 지연 시간이 발생합니다. 자세한 내용은 이용 가능한 요금제 개요를 참조하십시오.
요구사항
이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:
- Qiskit SDK v2.0 또는 그 이후 버전, 시각화 기능 지원
- Qiskit Runtime v0.22 또는 이후 (
pip install qiskit-ibm-runtime)
또한, IBM Quantum® Platform 에 있는 인스턴스에 접속할 수 있어야 합니다.
설정
import matplotlib.pyplot as plt
import rustworkx as rx
from rustworkx.visualization import mpl_draw as draw_graph
import numpy as np
from scipy.optimize import minimize
from collections import defaultdict
from typing import Sequence
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit.library import QAOAAnsatz
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session, EstimatorV2 as Estimator
from qiskit_ibm_runtime import SamplerV2 as Sampler간단한 예시
이 섹션에서는 5노드로 구성된 소규모 최대 절단(max-cut) 인스턴스를 예로 들어 QAOA 워크플로의 각 단계를 단계별로 설명합니다. “소규모”라는 표현이 붙었지만, 이 예제는 여전히 실제 IBM Quantum 하드웨어에서 실행됩니다. 코드는 127개 이상의 큐비트를 가진 백엔드를 선택하여 그곳에서 회로를 실행합니다.
노드로 그래프를 만들어 문제를 초기화합니다.
n_small = 5
graph = rx.PyGraph()
graph.add_nodes_from(np.arange(0, n_small, 1))
edge_list = [
(0, 1, 1.0),
(0, 2, 1.0),
(0, 4, 1.0),
(1, 2, 1.0),
(2, 3, 1.0),
(3, 4, 1.0),
]
graph.add_edges_from(edge_list)
draw_graph(graph, node_size=600, with_labels=True)Output:
1단계: 고전적 입력을 양자 문제에 매핑하기
고전 그래프를 양자 회로와 연산자로 매핑한다. ‘ 배경’에서 설명한 바와 같이, 가중치 없는 최대 절단(unweighted max-cut)의 경우 비용 해밀토니안은 로 환원되며, QAOA는 매개변수화된 안잭 회로를 사용하여 의 후보 기저 상태를 준비합니다.
비용 해밀토니안 구축
그래프의 변을 파울리 항으로 변환하여 를 구성한다(도출 과정은 ‘배경’ 참조).
def build_max_cut_paulis(
graph: rx.PyGraph,
) -> list[tuple[str, list[int], float]]:
"""Convert graph edges to a list of ZZ Pauli terms.
The returned list is in the sparse format expected by
``SparsePauliOp.from_sparse_list``: each element is
``(pauli_string, qubit_indices, coefficient)``.
"""
pauli_list = []
for edge in list(graph.edge_list()):
weight = graph.get_edge_data(edge[0], edge[1])
pauli_list.append(("ZZ", [edge[0], edge[1]], weight))
return pauli_list
max_cut_paulis = build_max_cut_paulis(graph)
cost_hamiltonian = SparsePauliOp.from_sparse_list(max_cut_paulis, n_small)
print("Cost Function Hamiltonian:", cost_hamiltonian)Output:
Cost Function Hamiltonian: SparsePauliOp(['IIIZZ', 'IIZIZ', 'ZIIIZ', 'IIZZI', 'IZZII', 'ZZIII'],
coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j])
QAOA 근사 회로 구축
를 QAOAAnsatz 사용하여 비용 해밀토니안으로부터 매개변수화된 QAOA 회로를 구성합니다. 여기서는 (두 개의 QAOA 층, 네 가지 매개변수: )를 사용합니다 reps=2 .
circuit = QAOAAnsatz(cost_operator=cost_hamiltonian, reps=2)
circuit.measure_all()
circuit.draw("mpl")Output:
circuit.parametersOutput:
ParameterView([ParameterVectorElement(β[0]), ParameterVectorElement(β[1]), ParameterVectorElement(γ[0]), ParameterVectorElement(γ[1])])
2단계: 양자 하드웨어 실행을 위한 문제 최적화
추상 회로를 하드웨어 전용 명령어로 변환한다. 이 단계에서는 큐비트 매핑, 게이트 분해, 라우팅 및 오류 억제를 처리합니다. 자세한 내용은 트랜스파일링 문 서를 참조하십시오.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
print(backend)
# Create pass manager for transpilation. Level 3 is the most aggressive
# preset: slower to transpile, but produces shorter circuits that are
# more robust to hardware noise.
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
candidate_circuit = pm.run(circuit)
candidate_circuit.draw("mpl", fold=False, idle_wires=False)Output:
<IBMBackend('ibm_pittsburgh')>
3단계: Qiskit primitives 명령어로 실행합니다
QAOA 최적화 루프는 양자 컴퓨팅 세션 내에서 실행되어, 반복 과정 전반에 걸쳐 장치가 예약된 상태를 유지합니다. 추정기는 각 단계에서 를 평가하며, 고전적 최적화기(COBYLA)는 수렴할 때까지 매개변수를 업데이트합니다.
초기 매개변수를 정의하고 최적화 루프를 실행합니다:
# QAOA doesn't prescribe principled default angles — any bounded choice
# works as a warm start for problems this small. beta and gamma are
# periodic (beta in [0, pi] and gamma in [0, 2*pi] modulo the underlying
# Pauli-rotation periods), and pi/2 and pi are just midpoints of those
# ranges. For harder problems you would typically warm start from known
# good angles or transfer parameters from smaller instances.
initial_gamma = np.pi
initial_beta = np.pi / 2
init_params = [initial_beta, initial_beta, initial_gamma, initial_gamma]def cost_func_estimator(params, ansatz, hamiltonian, estimator):
# transform the observable defined on virtual qubits to
# an observable defined on all physical qubits
isa_hamiltonian = hamiltonian.apply_layout(ansatz.layout)
pub = (ansatz, isa_hamiltonian, params)
job = estimator.run([pub])
results = job.result()[0]
cost = results.data.evs
objective_func_vals.append(cost)
return costobjective_func_vals = [] # Global variable
with Session(backend=backend) as session:
# If using qiskit-ibm-runtime<0.24.0, change `mode=` to `session=`
estimator = Estimator(mode=session)
estimator.options.default_shots = 1000
# Set simple error suppression/mitigation options
estimator.options.dynamical_decoupling.enable = True
estimator.options.dynamical_decoupling.sequence_type = "XY4"
estimator.options.twirling.enable_gates = True
estimator.options.twirling.num_randomizations = "auto"
estimator.options.environment.job_tags = ["TUT_QAOA"]
result = minimize(
cost_func_estimator,
init_params,
args=(candidate_circuit, cost_hamiltonian, estimator),
method="COBYLA",
tol=1e-2,
)
print(result)Output:
message: Return from COBYLA because the trust region radius reaches its lower bound.
success: True
status: 0
fun: -2.0402211719947774
x: [ 3.041e+00 1.212e+00 2.081e+00 4.471e+00]
nfev: 36
maxcv: 0.0
옵티마이저는 비용을 절감하고 회로의 더 나은 파라미터를 찾을 수 있었습니다.
점차 완만하게 감소하다가 평탄해지는 곡선은 수렴의 특징이다. 시끄럽고 비단조적인 곡선은 대개 상류 단계에서 해결해야 할 문제가 있음을 나타냅니다. 일반적인 원인으로는 평가당 샘플 수가 너무 적거나(추정량의 분산이 큼), 초기 매개변수가 부적절하거나, 하드웨어 노이즈의 영향이 큰 회로 등이 있습니다. COBYLA는 미분 연산이 필요 없으며 중간 정도의 노이즈에 대해 상당히 견고하지만, 노이즈가 단계당 실제 비용 개선 효과를 압도하게 되면, 이 알고리즘의 선형 근사 모델은 더 이상 실제 하강과 무작위 변동을 구분하지 못하게 되어 최적화 과정이 방황하게 됩니다.
plt.figure(figsize=(12, 6))
plt.plot(objective_func_vals)
plt.xlabel("Iteration")
plt.ylabel("Cost")
plt.show()Output:
최적화된 매개변수를 할당하고 Sampler 프리미티브를 사용하여 최종 분포를 샘플링합니다.
optimized_circuit = candidate_circuit.assign_parameters(result.x)
optimized_circuit.draw("mpl", fold=False, idle_wires=False)Output:
# If using qiskit-ibm-runtime<0.24.0, change `mode=` to `backend=`
sampler = Sampler(mode=backend)
sampler.options.default_shots = 10000
# Set simple error suppression/mitigation options
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XY4"
sampler.options.twirling.enable_gates = True
sampler.options.twirling.num_randomizations = "auto"
sampler.options.environment.job_tags = ["TUT_QAOA"]
pub = (optimized_circuit,)
job = sampler.run([pub], shots=int(1e4))
counts_int = job.result()[0].data.meas.get_int_counts()
counts_bin = job.result()[0].data.meas.get_counts()
shots = sum(counts_int.values())
final_distribution_int = {key: val / shots for key, val in counts_int.items()}
final_distribution_bin = {key: val / shots for key, val in counts_bin.items()}
print(final_distribution_int)Output:
{18: 0.039, 5: 0.0665, 20: 0.0973, 29: 0.0063, 9: 0.0899, 13: 0.0379, 2: 0.0047, 1: 0.0153, 11: 0.0932, 14: 0.0327, 12: 0.0314, 25: 0.0193, 21: 0.0398, 6: 0.0224, 4: 0.0197, 10: 0.0387, 3: 0.0181, 26: 0.07, 17: 0.0327, 19: 0.0332, 22: 0.0914, 24: 0.007, 0: 0.0033, 8: 0.0066, 30: 0.0158, 28: 0.0169, 27: 0.0222, 16: 0.0073, 7: 0.0057, 23: 0.0062, 15: 0.0054, 31: 0.0041}
4단계: 후처리 수행 및 원하는 클래식 형식으로 결과 반환
표본 분포에서 가장 가능성이 높은 비트열을 추출한다. 이는 QAOA가 찾아낸 최상의 결과입니다.
# auxiliary functions to sample most likely bitstring
def to_bitstring(integer, num_bits):
result = np.binary_repr(integer, width=num_bits)
return [int(digit) for digit in result]
keys = list(final_distribution_int.keys())
values = list(final_distribution_int.values())
most_likely = keys[np.argmax(np.abs(values))]
most_likely_bitstring = to_bitstring(most_likely, len(graph))
most_likely_bitstring.reverse()
print("Result bitstring:", most_likely_bitstring)Output:
Result bitstring: [0, 0, 1, 0, 1]
plt.rcParams.update({"font.size": 10})
final_bits = final_distribution_bin
values = np.abs(list(final_bits.values()))
top_4_values = sorted(values, reverse=True)[:4]
positions = []
for value in top_4_values:
positions.append(np.where(values == value)[0])
fig = plt.figure(figsize=(11, 6))
ax = fig.add_subplot(1, 1, 1)
plt.xticks(rotation=45)
plt.title("Result Distribution")
plt.xlabel("Bitstrings (reversed)")
plt.ylabel("Probability")
ax.bar(list(final_bits.keys()), list(final_bits.values()), color="tab:grey")
for p in positions:
ax.get_children()[int(p[0])].set_color("tab:purple")
plt.show()Output:
최적 절단 시각화
최적의 비트열을 바탕으로, 이 절단 부분을 원본 그래프에서 시각화할 수 있습니다.
# auxiliary function to plot graphs
def plot_result(G, x):
colors = ["tab:grey" if i == 0 else "tab:purple" for i in x]
pos, _default_axes = rx.spring_layout(G), plt.axes(frameon=True)
rx.visualization.mpl_draw(
G, node_color=colors, node_size=100, alpha=0.8, pos=pos
)
plot_result(graph, most_likely_bitstring)Output:
이제 절단면의 값을 계산해 봅시다:
def evaluate_sample(x: Sequence[int], graph: rx.PyGraph) -> float:
assert len(x) == len(
list(graph.nodes())
), "The length of x must coincide with the number of nodes in the graph."
return sum(
x[u] * (1 - x[v]) + x[v] * (1 - x[u])
for u, v in list(graph.edge_list())
)
cut_value = evaluate_sample(most_likely_bitstring, graph)
print("The value of the cut is:", cut_value)Output:
The value of the cut is: 5
그래프가 이 정도로 작다면 진정한 최적 해를 무차별 대입법으로 쉽게 구할 수 있으므로, QAOA 결과를 정확한 정답과 비교하여 결과를 다시 확인할 수 있습니다.
# Classical baseline: enumerate all 2**n_small bitstrings and take the best cut.
def brute_force_max_cut(graph: rx.PyGraph) -> tuple[int, list[int]]:
n = len(list(graph.nodes()))
best_cut = -1
best_x: list[int] = []
for i in range(2**n):
x = [(i >> k) & 1 for k in range(n)]
cut = evaluate_sample(x, graph)
if cut > best_cut:
best_cut = int(cut)
best_x = x
return best_cut, best_x
classical_best, classical_x = brute_force_max_cut(graph)
print(f"Classical optimum (brute force): {classical_best}")
print(f"QAOA cut value: {cut_value}")Output:
Classical optimum (brute force): 5
QAOA cut value: 5
대규모 하드웨어 예시
IBM Quantum Platform 에서는 100 큐비트 이상의 용량을 갖춘 다양한 장치를 이용할 수 있습니다. 100개의 노드를 가진 가중 그래프에서 최대 절단 문제를 풀기 위해 하나를 선택하십시오. 이는 “대규모” 문제입니다. 이 워크플로는 위와 동일한 단계를 따르지만, 훨씬 더 큰 그래프에 적용됩니다.
대규모 유틸리티 수준의 종단간 워크플로
100노드 그래프에 적용한 4단계의 전체 과정이 아래에 나와 있습니다. 구성은 소규모 예제와 동일합니다: 맵핑, 트랜스파일, 실행, 후처리 — 다만 문제 규모가 더 크며, 이해를 돕기 위해 아래의 네 개의 셀로 나누어 설명합니다.
# Precomputed parity lookup table: _PARITY[b] = +1 if popcount(b) is even, else -1.
# We use this to vectorize expectation-value evaluation across all Pauli terms.
_PARITY = np.array(
[-1 if bin(i).count("1") % 2 else 1 for i in range(256)],
dtype=np.complex128,
)
def evaluate_sparse_pauli(state: int, observable: SparsePauliOp) -> complex:
"""Expectation value of a SparsePauliOp on a single computational-basis state.
For a Z-only observable (which QAOA cost Hamiltonians are, after the
QUBO-to-Hamiltonian mapping), the eigenvalue of each Pauli term on a
computational-basis state is simply (-1)**popcount(z_mask AND state),
i.e., the parity of the bitwise-AND of the term's Z-support and the
measured bitstring.
This routine packs the Z-support of every Pauli term into bytes, ANDs
them against the measured state in a single vectorized op, and looks up
the parity in _PARITY. For a 100-qubit / ~hundreds-of-terms Hamiltonian
over 10_000 samples, this is dramatically faster than calling
SparsePauliOp.expectation_value per sample.
"""
packed_uint8 = np.packbits(observable.paulis.z, axis=1, bitorder="little")
state_bytes = np.frombuffer(
state.to_bytes(packed_uint8.shape[1], "little"), dtype=np.uint8
)
reduced = np.bitwise_xor.reduce(packed_uint8 & state_bytes, axis=1)
return np.sum(observable.coeffs * _PARITY[reduced])
def best_solution(samples, hamiltonian):
"""Return the sampled bitstring (as int) with the lowest Hamiltonian cost."""
min_cost = float("inf")
min_sol = None
for bit_str in samples.keys():
candidate_sol = int(bit_str)
fval = evaluate_sparse_pauli(candidate_sol, hamiltonian).real
if fval <= min_cost:
min_cost = fval
min_sol = candidate_sol
return min_sol
def _plot_cdf(objective_values: dict, ax, color):
x_vals = sorted(objective_values.keys(), reverse=True)
y_vals = np.cumsum([objective_values[x] for x in x_vals])
ax.plot(x_vals, y_vals, color=color)
def plot_cdf(dist, ax, title):
_plot_cdf(dist, ax, "C1")
ax.vlines(min(list(dist.keys())), 0, 1, "C1", linestyle="--")
ax.set_title(title)
ax.set_xlabel("Objective function value")
ax.set_ylabel("Cumulative distribution function")
ax.grid(alpha=0.3)
def samples_to_objective_values(samples, hamiltonian):
"""Convert the samples to values of the objective function."""
objective_values = defaultdict(float)
for bit_str, prob in samples.items():
candidate_sol = int(bit_str)
fval = evaluate_sparse_pauli(candidate_sol, hamiltonian).real
objective_values[fval] += prob
return objective_values1단계 : 그래프, 비용 해밀토니안 및 가정을 수립한다.
# Step 1: build the 100-node graph, cost Hamiltonian, and QAOA ansatz.
n_large = 100
graph_100 = rx.PyGraph()
graph_100.add_nodes_from(np.arange(0, n_large, 1))
elist = []
for edge in backend.coupling_map:
if edge[0] < n_large and edge[1] < n_large:
elist.append((edge[0], edge[1], 1.0))
graph_100.add_edges_from(elist)
max_cut_paulis_100 = build_max_cut_paulis(graph_100)
cost_hamiltonian_100 = SparsePauliOp.from_sparse_list(
max_cut_paulis_100, n_large
)
circuit_100 = QAOAAnsatz(cost_operator=cost_hamiltonian_100, reps=1)
circuit_100.measure_all()2단계 : 선택한 하드웨어 백엔드에 맞게 트랜스파일합니다.
# Step 2: transpile for hardware.
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
candidate_circuit_100 = pm.run(circuit_100)3단계 : 세션 내에서 QAOA 최적화 루프를 실행한 다음, 샘플링을 수행합니다.
# Step 3: run the QAOA optimization loop on the device, then sample the
# final distribution with the optimized parameters.
initial_gamma = np.pi
initial_beta = np.pi / 2
init_params = [initial_beta, initial_gamma]
objective_func_vals = [] # Global variable
with Session(backend=backend) as session:
estimator = Estimator(mode=session)
estimator.options.default_shots = 1000
# Set simple error suppression/mitigation options
estimator.options.dynamical_decoupling.enable = True
estimator.options.dynamical_decoupling.sequence_type = "XY4"
estimator.options.twirling.enable_gates = True
estimator.options.twirling.num_randomizations = "auto"
estimator.options.environment.job_tags = ["TUT_QAOA"]
result = minimize(
cost_func_estimator,
init_params,
args=(candidate_circuit_100, cost_hamiltonian_100, estimator),
method="COBYLA",
)
print(result)
# Assign optimal parameters and sample the final distribution.
optimized_circuit_100 = candidate_circuit_100.assign_parameters(result.x)
sampler = Sampler(mode=backend)
sampler.options.default_shots = 10000
# Set simple error suppression/mitigation options
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XY4"
sampler.options.twirling.enable_gates = True
sampler.options.twirling.num_randomizations = "auto"
# Add a unique tag to the job execution
sampler.options.environment.job_tags = ["TUT_QAOA"]
pub = (optimized_circuit_100,)
job = sampler.run([pub], shots=int(1e4))
counts_int = job.result()[0].data.meas.get_int_counts()
shots = sum(counts_int.values())
final_distribution_100_int = {
key: val / shots for key, val in counts_int.items()
}Output:
message: Return from COBYLA because the trust region radius reaches its lower bound.
success: True
status: 0
fun: -17.172689238986344
x: [ 2.574e+00 4.166e+00]
nfev: 28
maxcv: 0.0
4단계 : 샘플링된 분포를 후처리하여 최적의 절단점을 추출합니다.
# Step 4: find the best-cost sample and evaluate its cut value.
best_sol_100 = best_solution(final_distribution_100_int, cost_hamiltonian_100)
best_sol_bitstring_100 = to_bitstring(int(best_sol_100), len(graph_100))
best_sol_bitstring_100.reverse()
print("Result bitstring:", best_sol_bitstring_100)
cut_value_100 = evaluate_sample(best_sol_bitstring_100, graph_100)
print("The value of the cut is:", cut_value_100)Output:
Result bitstring: [1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0]
The value of the cut is: 156
최적화 루프에서 최소화하려는 비용이 수렴했는지 확인하고, 결과를 시각화합니다.
# Plot convergence
plt.figure(figsize=(12, 6))
plt.plot(objective_func_vals)
plt.xlabel("Iteration")
plt.ylabel("Cost")
plt.show()
# Visualize the cut
plot_result(graph_100, best_sol_bitstring_100)
# Plot cumulative distribution function
result_dist = samples_to_objective_values(
final_distribution_100_int, cost_hamiltonian_100
)
fig, ax = plt.subplots(1, 1, figsize=(8, 6))
plot_cdf(result_dist, ax, backend.name)Output:
다음 단계
이 글이 흥미로웠다면, 다음 자료도 참고해 보시기 바랍니다:
- QAOA를 위한 고급 기법 — QAOA 성능 향상을 위한 고급 전략을 탐구한다
- 다목적 최적화 챌린지 — 다목적 양자 최적화를 주제로 한 이번 커뮤니티 챌린지에서 여러분의 실력을 시험해 보세요
- 회로 최적화 미세 조정을 위한 트랜스파일레이션 문서
- 하드웨어 성능 향상을 위한 오류 억제 및 완화