Skip to main content
IBM Quantum Platform

디버깅 및 추적

이 build() 함수는 주석이 달린 회로를 템플릿 회로와 샘플렉스 쌍으로 변환합니다. 복잡한 회로에서는 원래 회로의 어떤 상자가 템플릿의 어떤 장벽에 해당하는지, 혹은 샘플렉스 DAG의 어떤 노드에 해당하는지 파악하기 어려울 수 있습니다.

Samplomatic은 서로 보완적인 두 가지 트레이싱 도구를 제공합니다:

  • 배리어 레이블 : 템플릿 회로의 모든 배리어에는 그 기원을 나타내는 레이블이 붙어 있습니다. 이것들은 debug=True 가 설정되어 있는지 여부와 관계없이 항상 존재합니다.
  • 샘플렉스 노드의 추적 정보 : build() 가 와 함께 호출되면 debug=True, 각 샘플렉스 노드는 이를 생성한 박스 하나 또는 여러 개로 연결되는 TraceInfo 객체를 보유하게 됩니다.

두 도구 모두 상자에 주석이 Tag 달렸을 때 가장 유용하며, 주석은 상자에 ref 문자열을 연결해 줍니다. 또는, InjectNoise 참고 자료도 첨부되어 있습니다.


태그 상자

Tag 주석은 상자에 ref 문자열을 연결합니다. 이 ref 는 배리어 레이블과 samplex 노드의 추적 정보에 표시됩니다.

다음 예시 회로에는 세 개의 상자가 있습니다. 서로 겹치지 않는 큐비트 쌍에 연결된 두 개의 ‘CX’ 태그가 붙은 상자와, 태그가 없는 ‘right-dressed’ 측정 상자입니다. 두 번째 CX 박스에도 InjectNoise 주석이 붙어 있습니다. 이 박스의 tag ref와 noise는 모두 배리어 레이블에 ref 표시됩니다. 두 CX 박스는 서로 다른 큐비트를 다루기 때문에, 샘플렉스 최적화기는 이들의 전파 노드를 공유 노드로 통합할 수 있습니다. 이는 추적 정보 섹션에 표시됩니다.

from qiskit.circuit import QuantumCircuit

from samplomatic import InjectNoise, Tag, Twirl, build

circuit = QuantumCircuit(4, 4)

with circuit.box([Twirl(), Tag("cx_ab")]):
    circuit.cx(0, 1)

with circuit.box([Twirl(), InjectNoise("cx_noise"), Tag("cx_cd")]):
    circuit.cx(2, 3)

with circuit.box([Twirl(), Tag("meas_box")]):
    circuit.measure(range(4), range(4))

circuit.draw("mpl")
../_images/f6b6fe7b60a39ba897814008443fa79b66213005462ab09f49ffc89aab1f3668.png

템플릿 회로의 배리어 라벨

위의 회로에서 build() 호출을 수행하면, 장벽에 식별 라벨이 부여된 템플릿이 생성됩니다. 각 레이블은 다음과 같은 형식을 갖습니다 {side}{scope}@{key=value&...}:

  • 측면 : L = 왼쪽 정렬 경계, M = 내부 상자 내용 경계, R = 오른쪽 정렬 경계.
  • 범위 : 동일한 중첩 수준에 있는 여러 상자를 구별하기 위한 정수 인덱스(또는 중첩된 상자의 경우 밑줄로 구분된 목록).
  • 주석 : 상자의 주석에서 파생된, @‘-’ 접두사가 붙고 ‘-’로 &구분된 key=value 쌍의 목록입니다. 키 tag 중 하나는 Tag 어노테이션에서 비롯되고, 다른 하나는 InjectNoise 어노테이션에서 inject_noise 비롯됩니다.

태그가 없는 상자에서 생성된 장벽은 접미사 @ 없이 측면과 범위(예: L2)만 갖습니다.

template, samplex = build(circuit)
template.draw("mpl", fold=100)
../_images/e533d70a29504005a636aa27306d3ce3b1d2488358ac6a53f0674f2934698ab8.png

배리어 레이블은 프로그래밍 방식으로 추출할 수도 있습니다:

barrier_labels = [instr.operation.label for instr in template if instr.operation.name == "barrier"]
barrier_labels
['L0@tag=cx_ab',
 'M0@tag=cx_ab',
 'R0@tag=cx_ab',
 'L1@inject_noise=cx_noise&tag=cx_cd',
 'M1@inject_noise=cx_noise&tag=cx_cd',
 'R1@inject_noise=cx_noise&tag=cx_cd',
 'L2@tag=meas_box',
 'M2@tag=meas_box',
 'R2@tag=meas_box']

Samplex 노드에 대한 추적 정보

passing을 to debug=True 로 지정하면 모든 samplex 노드에 추적 정보가 첨부됩니다 build() . 각 노드의 trace_info 속성은 객체이며 TraceInfo , 이 객체의 trace_refs 사전은 주석 키(예: "tag" 및 "inject_noise")를 ref 문자열 집합에 매핑합니다. 해당 상자 주석이 없는 노드에는 trace_info=None.가 있습니다.

디버그 빌드된 samplex에서 이 함수가 draw() 호출되면, 대화형 그래프의 임의의 노드 위에 마우스를 올리면 해당 노드의 가 툴팁에 trace_refs 표시됩니다.

template, samplex = build(circuit, debug=True)
samplex.draw()

추적 정보는 프로그래밍 방식으로 확인할 수도 있습니다. 일부 노드에는 'cx_ab' 와 양쪽 모두로부터의 참조가 연결되어 있다는 점에 유의하십시오 'cx_cd'. Samplex 최적화기는 두 상자가 서로 겹치지 않는 큐비트를 다루고 있으며, 오른쪽 방향 측정 상자의 방출에서 공통된 선행자를 공유하기 때문에 병렬 전파 노드들을 병합했습니다.

for node in samplex.graph.nodes():
    if node.trace_info is not None:
        tags = node.trace_info.trace_refs.get("tag", set())
        merged = " ← merged" if len(tags) > 1 else ""
        print(f"{type(node).__name__:40s}  tags={tags}{merged}")
TwirlSamplingNode                         tags={'meas_box'}
InjectNoiseNode                           tags={'cx_cd'}
CollectZ2ToOutputNode                     tags={'cx_cd'}
TwirlSamplingNode                         tags={'cx_cd'}
CombineRegistersNode                      tags={'cx_cd'}
CollectTemplateValues                     tags={'cx_cd'}
TwirlSamplingNode                         tags={'cx_ab'}
CombineRegistersNode                      tags={'cx_ab', 'cx_cd'} ← merged
CollectTemplateValues                     tags={'cx_ab', 'cx_cd'} ← merged

특정 상자에서 시작된 모든 노드를 찾으려면 다음 "tag" 키로 필터링하세요:

tag_ref = "cx_ab"
matching_nodes = [
    node
    for node in samplex.graph.nodes()
    if node.trace_info is not None and tag_ref in node.trace_info.trace_refs.get("tag", set())
]

print(f"Nodes originating from box '{tag_ref}':")
for node in matching_nodes:
    print(f"  {type(node).__name__}")
Nodes originating from box 'cx_ab':
  TwirlSamplingNode
  CombineRegistersNode
  CollectTemplateValues

샘플렉스 DAG

에 의해 반환되는 샘플렉스는 유향 비순환 그래프(DAG)이며 build() , 여기서 간선은 레지스터 의존성을 나타냅니다. 즉, 노드 A에서 노드 B로 이어지는 에지는 B가 동작을 수행하기 전에 A가 공유 가상 레지스터에 대해 먼저 동작을 수행해야 함을 의미합니다. 이는 양자 회로의 DAG와 같은 시간적 순서가 아닙니다. 대신, 이 그래프는 무작위화를 생성하는 노드에서 이를 출력으로 합성하는 노드로 이어집니다.

노드 유형은 세 가지가 있으며, 각각 대화형 그래프에서 고유한 시각적 스타일을 가지고 있습니다:

형태
색상
유형
역할
스타빨간색SamplingNode분배 또는 입력에서 새로운 가상 레지스터를 생성합니다
원형초록색EvaluationNode가상 레지스터를 변환, 결합 또는 전파합니다
나비 넥타이파란색 / 보라색CollectionNode레지스터를 읽고 출력에 데이터를 sample() 기록합니다

실행은 다음 세 단계로 진행됩니다:

  1. 모든 샘플링 노드가 먼저 (병렬로) 실행됩니다.
  2. 다음으로 평가 노드들이 토폴로지 순서대로 실행됩니다(각 세대 내에서 병렬로 실행됨).
  3. 컬렉션 노드는 (병렬로) 마지막에 실행됩니다.

그래프비즈 레이아웃이 이를 반영하고 있습니다. 샘플링 노드는 상단에, 수집 노드는 하단에 표시됩니다.


마우스를 올리면 나타나는 툴팁

대화형 시각화에서 각 노드 위에 마우스를 올리면 툴팁이 표시됩니다. 툴팁에는 다음과 같은 정보가 포함되어 있습니다:

  • 노드 클래스 이름 과 해당 정수 그래프 인덱스.
  • 노드가 인스턴스화하고, 읽기, 쓰기 및 제거 작업을 수행하는 매니페스트를 등록합니다. 이것들은 노드 간에 데이터가 어떻게 흐르는지 알려줍니다.
  • 샘플링 노드의 분포 유형, 곱셈 노드의 피연산자, 컬렉션 노드의 템플릿 매개변수 인덱스 등을 포함한 노드별 세부 정보.
  • 노드를 그 노드가 생성된 박스로 다시 연결해 주는 주석 키 및 참조 문자열인 참조 추적 (해당 조건이 충족될 때만 debug=True)입니다.

플롯을 클릭한 다음 개별 노드 위에 마우스를 올려두는 것이 소스 코드를 읽지 않고도 특정 노드의 기능을 파악하는 가장 빠른 방법입니다.


Samplex 요약

시각화 내용을 살펴보기 전에, 노드 수, 필요한 입력값, 그리고 제공될 출력값에 대해 간략한 텍스트 요약이 print(samplex) 제공됩니다.

template, samplex = build(circuit)
print(samplex)
Samplex(<17 nodes>)
  Inputs:
  - 'pauli_lindblad_maps.cx_noise' <PauliLindbladMap>: A PauliLindblad map acting on 2
      qubits, with 'num_terms_cx_noise' terms.

  Outputs:
    * 'measurement_flips.c' <bool['num_randomizations', 1, 4]>: Bit-flip corrections for
        measurement twirling.
    * 'parameter_values' <float32['num_randomizations', 24]>: Parameter values valid for an
        associated template circuit.
    * 'pauli_signs' <bool['num_randomizations', 1]>: Signs from sampled Pauli Lindblad
        maps, where boolean values represent the parity of the number of non-trivial factors in the
        sampled error that arise from negative rates. In other words, in order to implement basic
        PEC, the sign used to correct expectation values should be ``(-1)**bool_value``. The order
        matches the iteration order of boxes in the original circuit with noise injection
        annotations.

레지스터 검사

passing은 keep_registers=True 샘플링이 끝날 때 활성 상태인 중간 VirtualRegister 객체들을 유지하고 sample() , 이를 에 저장합니다 outputs.metadata["registers"]. 각 레지스터는 가상 군 원소들로 구성된 2D 배열(모양 (num_subsystems, num_randomizations), 뒤에 게이트 모양의 차원이 추가될 수 있음)입니다.

이는 가상 게이트가 올바르게 결합되었는지 확인하거나, 원시 파울리 또는 유니터리 샘플이 회전 각도로 합성되기 전에 이를 검토하는 데 유용합니다.

from qiskit.quantum_info import PauliLindbladMap

outputs = samplex.sample(
    {"pauli_lindblad_maps.cx_noise": PauliLindbladMap.identity(2)},
    num_randomizations=3,
    keep_registers=True,
)
for name, reg in outputs.metadata["registers"].items():
    print(f"{name}: type={reg.TYPE.value}, shape={reg.virtual_gates.shape}")
lhs_0: type=pauli, shape=(4, 3)
rhs_0: type=pauli, shape=(4, 3)
lhs_3: type=pauli, shape=(2, 3)
rhs_3: type=pauli, shape=(2, 3)
inject_noise_1: type=pauli, shape=(2, 3)
sign_1: type=z2, shape=(1, 3)
lhs_7: type=pauli, shape=(2, 3)
rhs_7: type=pauli, shape=(2, 3)
meas_prop_6: type=pauli, shape=(4, 3)
collect_10: type=u2, shape=(2, 3, 2, 2)
meas_prop_z2a_6: type=z2, shape=(4, 3)
collect_9: type=u2, shape=(4, 3, 2, 2)
collect_5: type=u2, shape=(2, 3, 2, 2)

특정 레지스터의 최종 상태 내용을 확인할 수 있습니다. 다음 예제에서 레지스터의 데이터 형은 입니다 PauliRegister. 저장 형식에 대한 자세한 내용은 API documentation(/apidocs/index)__를 참조하십시오.

print("lhs_0:", outputs.metadata["registers"]["lhs_0"])
outputs.metadata["registers"]["lhs_0"].virtual_gates
lhs_0: PauliRegister(<4, 3>)
array([[0, 0, 1],
       [3, 1, 1],
       [3, 0, 0],
       [1, 0, 0]], dtype=uint8)

Samplex 노드가 템플릿 매개변수에 어떻게 매핑되는지

함수 가 반환하는 outputs["parameter_values"] 배열의 차원은 이며 sample()(num_randomizations, N) , 여기서 는 와 일치합니다 N``len(template.parameters) . 각 열은 템플릿 회로의 한 매개변수에 해당하며, i번째 열은 에 값을 입력합니다 template.parameters[i].

컬렉션 CollectTemplateValues 노드는 가상 레지스터와 템플릿 매개변수를 연결하는 역할을 합니다. 이러한 각 노드는 출력 배열의 어느 열에 데이터를 기록하는지를 나타내는 인덱스 정보를 보유하고 있습니다. 이를 통해 어떤 가상 게이트 하위 시스템이 어떤 템플릿 매개변수를 제어하는지 추적할 수 있습니다.

{Samplex inputs and outputs} samplex-io 가이드를 참고하여 샘플링된 매개변수 값을 템플릿 회로에 바인딩하고 실험을 실행하는 방법을 알아보세요.

from samplomatic.samplex.nodes import CollectTemplateValues

template, samplex = build(circuit, debug=True)
for node in samplex.graph.nodes():
    if isinstance(node, CollectTemplateValues):
        tags = node.trace_info.trace_refs.get("tag", set()) if node.trace_info else set()
        print(f"tags={tags}  →  template param indices: {node.template_idxs.tolist()}")
tags={'cx_cd'}  →  template param indices: [[6, 7, 8], [9, 10, 11]]
tags={'cx_ab', 'cx_cd'}  →  template param indices: [[12, 13, 14], [15, 16, 17], [18, 19, 20], [21, 22, 23]]
tags=set()  →  template param indices: [[0, 1, 2], [3, 4, 5]]

자동 태그 지정

를 사용할 때 generate_boxing_pass_manager(), add_tags 매개변수는 모든 상자에 Tag 주석을 자동으로 추가합니다. 다음과 같은 세 가지 모드를 사용할 수 있습니다:

  • "unique_instance": 회로 순서대로 상자에 순차적인 값( ref``t0 , t1, 등)을 할당합니다. 모든 상자는 그 구조와 ref 상관없이 고유한 식별자를 부여받습니다.
  • "unique_box": 각 상자의 내용에 대해 구조적 해시를 계산하고, 구조적으로 동등한 모든 상자에 ref 동일한 해시를 할당합니다. 이는 상자를 위치가 아닌 유형별로 그룹화하는 데 유용합니다.
  • "noise_ref": 각 상자의 InjectNoise 주석에서 ref 를 복사하고, 주석이 있는 상자만 태그합니다. 이미 의미 있는 노이즈 참조가 존재할 때 유용합니다.

다음 예제는 구조적으로 동등한 두 개의 CX 박스로 구성된 회로에 "unique_box" "unique_instance" 와 를 적용합니다. 의 경우 "unique_instance", 각각 고유한 를 갖게 되는 반면 ref, 의 경우 "unique_box", 이들은 하나의 를 공유합니다.

from samplomatic.transpiler import generate_boxing_pass_manager

base_circuit = QuantumCircuit(3)
base_circuit.cx(0, 1)
base_circuit.cx(1, 2)
base_circuit.measure_all()

# unique_instance: every box gets a distinct tag ref
pm = generate_boxing_pass_manager(add_tags="unique_instance")
boxed = pm.run(base_circuit)
template, _ = build(boxed)

print("unique_instance barrier labels:")
for instr in template:
    if instr.operation.name == "barrier" and instr.operation.label:
        print(f"  {instr.operation.label}")
unique_instance barrier labels:
  L0@tag=t0
  M0@tag=t0
  R0@tag=t0
  L1@tag=t1
  M1@tag=t1
  R1@tag=t1
  L2@tag=t2
  M2@tag=t2
  R2@tag=t2
이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.