Skip to main content
IBM Quantum Platform

트랜스파일러 최적화 수준 설정

  • 이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 다음 버전 이상을 사용하는 것이 좋습니다.

    qiskit[all]~=2.5.2
    qiskit-ibm-runtime~=0.47.0
    

실제 양자 소자는 노이즈와 게이트 오류가 발생할 수 있으므로 회로를 최적화하여 깊이와 게이트 수를 줄이면 해당 회로를 실행하여 얻은 결과를 크게 향상시킬 수 있습니다. 함수에는 generate_preset_pass_manager 함수에는 트랜스파일러가 회로를 최적화하는 데 얼마나 많은 노력을 기울이는지 제어하는 하나의 필수 위치 인수( optimization_level)가 있습니다. 이 인수는 0, 1, 2, 3 중 하나의 값을 취하는 정수일 수 있습니다. 최적화 수준이 높을수록 컴파일 시간이 길어지는 대신 더 최적화된 회로를 생성합니다. 다음 표에서는 각 설정에서 수행되는 최적화에 대해 설명합니다.

최적화 레벨
설명
0

최적화 없음: 일반적으로 하드웨어 특성 분석에 사용됩니다

  • 기본 번역
  • 레이아웃/라우팅: TrivialLayout 에서 가상과 동일한 물리적 큐비트 번호를 선택하고 SWAP을 삽입하여 작동하도록 합니다( SabreSwap 사용)
1

조명 최적화:

  • 레이아웃/라우팅: 레이아웃은 TrivialLayout 으로 처음 시도됩니다. 추가 스왑이 필요한 경우 SabreSwap 을 사용하여 최소 스왑 수를 가진 레이아웃을 찾은 다음 VF2LayoutPostLayout 을 사용하여 그래프에서 최적의 큐비트를 선택하려고 시도합니다.
  • InverseCancellation
  • 1Q 게이트 최적화
2

중간 최적화:

  • 레이아웃/라우팅: 최적화 레벨 1(사소하지 않음) + 휴리스틱 최적화 + 더 큰 검색 깊이와 검색 깊이 및 최적화 기능의 시험. TrivialLayout 을 사용하지 않으므로 동일한 물리적 큐비트 번호와 가상 큐비트 번호를 사용하려고 시도하지 않습니다.
  • CommutativeCancellation
3

높은 최적화:

  • 최적화 레벨 2 + 더 많은 노력/시도를 통해 레이아웃/라우팅에 최적화된 휴리스틱 최적화
  • 카르탄의 KAK 분해를 사용한 2큐비트 블록 재합성.
  • 균일성 파괴 패스:
    • OptimizeSwapBeforeMeasure: 스왑을 피하기 위해 측정값을 이동합니다
    • RemoveDiagonalGatesBeforeMeasure: 측정에 영향을 미치지 않는 측정 전 게이트를 제거합니다

최적화 수준 적용 사례

일반적으로 2큐비트 게이트가 가장 큰 오류의 원인이므로, 결과 회로에서 2큐비트 게이트의 수를 세어 트랜스필레이션의 '하드웨어 효율성'을 대략적으로 정량화할 수 있습니다. 여기서는 무작위 유니티와 SWAP 게이트로 구성된 입력 회로에서 다양한 최적화 수준을 시도해 보겠습니다.

from qiskit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary

UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)

qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw("mpl", style="iqp")

Output:

Output of the previous code cell
Note

이 예제에서는 의 모의 FakeSherbrooke``qiskit_ibm_runtime 백엔드를 사용하지만, Qiskit과 호환되는 실제 또는 모의 백엔드라면 어떤 것이든 사용해 볼 수 있습니다. 결과는 다를 수 있습니다.

먼저, 최적화 수준 0을 사용하여 트랜스파일해 봅시다.

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
    optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

트랜스파일된 회로에는 2쿼비트 ECR 게이트 6개가 있습니다.

최적화 레벨 1에 대해 반복합니다:

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
    optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

트랜스파일된 회로에는 여전히 6개의 ECR 게이트가 있지만 단일 큐비트 게이트의 수가 줄었습니다.

최적화 레벨 2에 대해 반복합니다:

pass_manager = generate_preset_pass_manager(
    optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

이렇게 하면 최적화 레벨 1과 동일한 결과가 나옵니다. 최적화 수준을 높인다고 해서 항상 달라지는 것은 아닙니다.

최적화 레벨 3으로 다시 반복합니다:

pass_manager = generate_preset_pass_manager(
    optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

이제 ECR 게이트는 세 개뿐입니다. 최적화 레벨 3에서 키스킷은 2큐비트 블록의 게이트를 재합성하려고 시도하고, 최대 3개의 ECR 게이트를 사용하여 2큐비트 게이트를 구현할 수 있기 때문에 이러한 결과를 얻을 수 있습니다. approximation_degree 을 1보다 작은 값으로 설정하면 트랜스파일러가 게이트 분해에 약간의 오차가 발생할 수 있는 근사치를 만들 수 있으므로 더 적은 수의 ECR 게이트를 얻을 수 있습니다( 트랜스파일에 일반적으로 사용되는 매개변수 참조):

pass_manager = generate_preset_pass_manager(
    optimization_level=3,
    approximation_degree=0.99,
    backend=backend,
    seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

이 회로에는 두 개의 ECR 게이트만 있지만 대략적인 회로입니다. 그 효과가 정확한 회로와 어떻게 다른지 이해하기 위해 이 회로가 구현하는 단항 연산자와 정확한 단항 사이의 충실도를 계산할 수 있습니다. 계산을 수행하기 전에 먼저 127개의 큐비트를 포함하는 트랜스파일된 회로를 활성 큐비트만 포함하는 회로로 축소하고, 이 중 두 개의 큐비트만 포함합니다.

import numpy as np


def trace_to_fidelity_2q(trace: float) -> float:
    return (4.0 + trace * trace.conjugate()) / 20.0


# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)

# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
    np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
    np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
    f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)

Output:

Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j

최적화 수준을 조정하면 ECR 게이트의 수뿐만 아니라 회로의 다른 측면에도 변화가 생길 수 있습니다. 최적화 수준 설정이 레이아웃에 어떤 영향을 미치는지 확인하려면 ‘양자 컴퓨터 표현’을 참조하십시오.


다음 단계

권장사항
이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.