Skip to main content
IBM Quantum Platform

회로 주석

qiskit.circuit.annotation

이 모듈에는 사용자 지정 회로 주석 작업을 위한 인프라가 포함되어 있습니다.

qiskit.circuit.Annotation사용자가 주로 접하게 되는 클래스는 기본 클래스이며, 이 클래스 역시 이 모듈에서 재수출됩니다.


사용자 정의 주석 하위 클래스

Annotation 클래스는 서브클래스를 생성하기 위해 고안되었습니다. 하위 클래스는 해당 namespace 필드를 설정해야 합니다. 이는 인스턴스별로 다를 수도 있고, 하위 클래스 전체에 대해 정적일 수도 있습니다. 네임스페이스는 ‘네임스페이싱’ 섹션에 설명된 바와 같이 디스패치 메커니즘의 일부로 사용됩니다.

회로 동일성 검사는 순서에 따라 객체의 주석을 비교하기도 합니다. 모든 서브클래스에 __eq__() 마법 메서드를 구현하고 싶을 것입니다.

주석을 QPY 또는 :ref:` OpenQASM 3 <qiskit-qasm3> `를 통해 직렬화할 수 있도록 하려면 직렬화 및 역직렬화에서 설명한 대로 직렬화 및 역직렬화 방법을 별도로 구현해야 합니다.

네임스페이스

어노테이션의 '네임스페이스'는 소비자가 어떤 처리기를 호출할지 결정할 때 조회 키로 사용됩니다. 이는 QPY 및 OpenQASM 3 직렬화 컨텍스트에도 포함되지만, 일반적으로 트랜스파일러 패스는 어노테이션의 네임스페이스도 살펴보고 관련성이 있는지 확인합니다.

이는 표준 Python 식별자(예: my_namespace)일 수 있습니다 또는 점으로 구분된 식별자 목록 (예: my_namespace.subnamespace). 이 네임스페이스는 주석을 사용하는 모든 주체가 어떤 핸들러를 호출해야 하는지 결정하는 데 사용됩니다.

독립형 함수를 사용하면 네임스페이스와 상위 네임스페이스를 가장 구체적인 것부터 가장 구체적인 것까지 우선순위에 따라 반복할 수 있습니다.

iter_namespaces

qiskit.circuit.annotation.iter_namespaces(namespace)

GitHub

주어진 네임스페이스를 조회하는 데 사용할 수 있는 모든 네임스페이스에 대한 이터레이터입니다.

여기에는 네임스페이스와 루트 빈 문자열 네임스페이스를 포함한 모든 상위 네임스페이스가 포함됩니다.

예:

from qiskit.circuit.annotation import iter_namespaces
assert list(iter_namespaces("hello.world")) == ["hello.world", "hello", ""]

매개변수

namespace (str)

리턴 유형

Iterator [ str ]

직렬화 및 직렬화 해제

주석은 컴파일 후에도 유지될 수 있는 완전히 사용자 지정 데이터를 나타냅니다. 여기에는 백엔드 컴파일러에서 해석되는 추가 데이터와 같이 나중에 사용하기 위해 직렬화해야 하는 데이터가 포함될 수 있습니다. 키스킷의 네이티브 바이너리 QPY 형식( qiskit.qpy)은 버전 15부터 페이로드에 임의 어노테이션 개념을 지원합니다. OpenQASM 3( qiskit.qasm3)에서 어노테이션은 핵심 언어 기능이며, 키스킷의 OpenQASM 3 가져오기/내보내기 지원에는 어노테이션의 직렬화가 포함되어 있습니다.

그러나 어노테이션은 일반적으로 사용자 정의 하위 클래스이며 Qiskit에서는 인식하지 못하기 때문에, 직렬화에 대한 내장 지원을 제공할 수 없습니다. 직렬화 해제 측면에서 볼 때, Qiskit은 일반적으로 직렬화 해제 메서드를 호출할 수 있는 기존 Annotation 객체를 가지고 있지 않습니다. 또한 주석이 주어진 회로 컨텍스트 내에서 Qiskit이 인식하지 못하는 공유 상태와 관련될 수도 있을 것으로 예상됩니다.

이러한 모든 이유로 어노테이션의 직렬화 및 역직렬화는 관련 직렬화 함수의 인터페이스 지점에서 전달되어야 하는 사용자 정의 객체에 의해 처리됩니다. 예를 들어, QPY에서 annotation_factories 인수는 qpy.dump()qpy.load() 는 직렬화기를 전달하는 데 사용됩니다.

QPY 직렬화기

class qiskit.circuit.annotation.QPYSerializer

GitHub

베이스: ABC

QPY로 객체를 Annotation 직렬화 및 역직렬화하는 데 사용되는 인터페이스입니다.

QPY에 대한 자세한 내용은 qiskit.qpy.

이 인터페이스 정의 클래스는 서브 클래싱할 수 있도록 설계되었습니다. 개별 메서드에는 해당 메서드의 계약과 호출 방법이 설명되어 있습니다.

QPY 직렬화 및 역직렬화 중에 메인 QPY 로직은 팩토리 함수를 호출하여 이 클래스의 서브클래스의 인스턴스를 생성합니다. 지정된 팩토리 함수의 반환 값은 직렬화 또는 역직렬화 컨텍스트 중 하나에서 사용되지만 둘 다는 사용할 수 없습니다.

단일 회로를 직렬화하는 동안의 호출 구조는 다음과 같습니다:

  1. dump_annotation()대한 여러 호출이 이루어지며, 이 호출들은 모두 동일한 namespace 인자를 공유하게 되는데, 이 인자는 주어진 모든 Annotation 객체의 (비엄격한) 접두사가 됩니다.
  2. dump_state() 으로 한 번만 전화하세요.

QPY 페이로드에서 단일 회로를 역직렬화하는 동안 호출의 일반적인 구조는 다음과 같습니다:

  1. load_state() 으로 한 번 호출하여 namespace ("직렬화" 형식과 동일한 비 엄격한 접두사 동작)을 전달합니다.
  2. 해당 네임스페이스 접두사 조회에 따라 직렬화된 어노테이션에 해당하는 load_annotation() 에 대한 많은 호출이 있습니다.

이를 서브클래싱할 때, QPY는 엄격한 하위 호환성을 보장하도록 고안되었으며 주석 직렬화 서브클래스는 이를 유지하도록 강력히 권장한다는 점을 기억하세요. 특히, 사소한 직렬화기가 아닌 모든 직렬화기는 전체 '상태'에 직렬화기의 '버전' 정보를 포함하고( dump_state() 참조), 역직렬화는 동일한 직렬화기의 이전 버전과의 하위 호환성을 지원하기 위해 모든 노력을 기울여야 합니다.

QPYFromOpenQASM3Serializer

class qiskit.circuit.annotation.QPYFromOpenQASM3Serializer(inner)

GitHub

베이스: QPYSerializer

OpenQASM3SerializerQPYSerializer.

이는 OpenQASM 3 주석 직렬화기는 상태 비저장형이어야 하고 QPY가 허용하는 것의 하위 집합인 UTF-8-encoded 한 줄의 텍스트를 반환해야 하기 때문에 작동합니다.

일반적으로 OpenQASM 3 어노테이션 직렬화기의 as_qpy() 메서드를 사용하여 이 중 하나를 생성합니다.

예:

이 클래스의 인스턴스는 인자가 0인 함수처럼 호출되어 스스로를 반환할 수 있습니다. 이를 통해 다음과 같이 QPY 진입점에 대한 팩토리 함수로 직접 사용할 수 있습니다:

import io
from qiskit.circuit import OpenQASM3Serializer, Annotation
from qiskit import qpy

class MyAnnotation(Annotation):
    namespace = "my_namespace"

class MySerializer(OpenQASM3Serializer):
    def dump(self, annotation):
        if not isinstance(annotation, MyAnnotation):
            return NotImplemented
        return ""

    def load(self, namespace, payload):
        assert namespace == "my_namespace"
        assert payload == ""
        return MyAnnotation()

qc = QuantumCircuit(2)
with qc.box(annotations=[MyAnnotation()]):
    qc.cx(0, 1)

with io.BytesIO() as fptr:
    qpy.dump(fptr, qc, annotation_serializers = {"my_namespace": MySerializer().as_qpy()})

기본 OpenQASM 3 직렬화기는 반드시 상태가 없는 상태이므로 별도의 인스턴스를 반환하지 않고도 안전합니다.

매개변수

inner (OpenQASM3Serializer) – 에서 파생된 OpenQASM 3 직렬화기입니다.

OpenQASM3Serializer

class qiskit.circuit.annotation.OpenQASM3Serializer

GitHub

베이스: ABC

OpenQASM 3용 객체 직렬화기 및 역직렬화기의 Annotation 인터페이스.

키스킷의 OpenQASM 3 지원에 대한 자세한 내용은 qiskit.qasm3.

이 인터페이스 정의 클래스는 서브 클래싱할 수 있도록 설계되었습니다. OpenQASM 3 어노테이션은 프로그램 내에서 상태가 없으므로 서브클래스는 상태를 추적해서는 안 됩니다.


블록 컬렉션 트랜스파일러 패스

어노테이션 프레임워크의 주요 목표는 컴파일러에 진입할 때 사용자가 명령어 로컬 방식으로 사용자 정의 분석 및 명령을 회로에 저장하거나 나중에 사용할 수 있도록 하나의 컴파일러 패스에 정보를 저장할 수 있도록 하는 것입니다.

BoxOp예를 들어, 단일 큐비트 연산들의 실행 단위를 모아 각 실행 단위를 에 넣은 다음, 전체 유니터리 작용을 계산하여 사용자 정의 주석으로 첨부하는 간단한 트랜스파일러 패스를 작성할 수 있습니다. 이렇게 하면 각 블록의 내부 구조가 최적화되더라도 나중에 동일한 분석을 반복할 필요가 없습니다.

from qiskit.circuit import annotation, QuantumCircuit, BoxOp
from qiskit.quantum_info import Operator
from qiskit.transpiler import TransformationPass

class PerformsUnitary(annotation.Annotation):
    namespace = "unitary"
    def __init__(self, matrix):
        self.matrix = matrix

class Collect1qRuns(TransformationPass):
    def run(self, dag):
        for run in dag.collect_1q_runs():
            block = QuantumCircuit(1)
            for node in run:
                block.append(node.op, [0], [])
            box = BoxOp(block, annotations=[PerformsUnitary(Operator(block).data)])
            dag.replace_block_with_op(run, box, {run[0].qargs[0]: 0})
        return dag

OpenQASM 3에 주석을 직렬화하려면 분석 자체가 완전히 사용자 정의이므로 사용자 정의 로직을 정의해야 합니다. 직렬화는 어노테이션과 별개이므로 직렬화를 다르게 수행해야 하는 상황이 있을 수 있습니다.

import ast
import numpy as np

class Serializer(annotation.OpenQASM3Serializer):
    def dump(self, annotation):
        if annotation.namespace != "unitary":
            return NotImplemented
        line = lambda row: "[" + ", ".join(repr(x) for x in row) + "]"
        return "[" + ", ".join(line(row) for row in annotation.matrix.tolist()) + "]"

    def load(self, namespace, payload):
        if namespace != "unitary":
            return NotImplemented
        return PerformsUnitary(np.array(ast.literal_eval(payload), dtype=complex))

마지막으로, 이를 합쳐서 OpenQASM 3의 출력을 표시할 수 있습니다.

from qiskit import qasm3

qc = QuantumCircuit(3)
qc.s(0)
qc.t(0)
qc.y(1)
qc.x(1)
qc.h(2)
qc.s(2)
collected = Collect1qRuns()(qc)

handlers = {"unitary": Serializer()}
dumped = qasm3.dumps(collected, annotation_handlers=handlers)
print(dumped)
OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
@unitary[[(1+0j), 0j], [0j, (-0.7071067811865475+0.7071067811865475j)]]
box {
  s q[0];
  t q[0];
}
@unitary[[1j, 0j], [0j, -1j]]
box {
  y q[1];
  x q[1];
}
@unitary[[(0.7071067811865475+0j), (0.7071067811865475+0j)], [0.7071067811865475j, -0.7071067811865475j]]
box {
  h q[2];
  s q[2];
}
이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.