양자 회로 모델
qiskit.circuit
양자 컴퓨팅의 기본 요소는 양자 회로입니다. 이는 양자 처리 장치(QPU)에서 한 번에 한 번씩 실행할 수 있는 계산 루틴입니다. 회로는 단일 연산(게이트), 측정 및 리셋을 통해 미리 정의된 양의 양자 데이터(키스킷에서는 큐비트만 직접 지원)에 대해 작동합니다. 또한 양자 회로에는 실시간 계산 및 제어 흐름 구성을 포함한 기존 데이터에 대한 연산이 포함될 수 있으며, 이는 QPU의 컨트롤러에 의해 실행됩니다.
소개 자료를 건너뛰고 바로 본론으로 넘어갈 수 있습니다:
- 전체 회로 모듈의 API 개요
- 회로가 어떻게 표현되는지에 대한 자세한 논의
- 핵심
QuantumCircuit클래스에서 회로를 빌드하고 쿼리하는 방법을 확인하세요 - 건설 사용자 지정 지침에 대한 정보
- 회로 수준 객체로 작업하는 방법
- 회로, 행렬 및 상태 표시를 위한 키스킷 규칙에 대한 논의
양자 프로그램을 구축할 때 회로는 추상화 수준이 낮습니다. 이는 고급 오류 완화 기술 및 측정 최적화와 함께 양자 회로 실행의 여러 샷에서 얻은 데이터를 잘 유형화된 고전 데이터 및 오류 통계로 축적하는 양자 계산의 기본 요소와 같은 더 높은 수준의 추상화를 구축하는 데 사용되는 구조입니다.
키스킷에서 회로는 두 가지 체제 중 하나로 정의할 수 있습니다:
- 가상 큐비트와 캡슐화된 알고리즘 및 사용자 정의 게이트와 같은 임의의 상위 수준 연산으로 정의되는 추상 회로입니다.
- 특정 백엔드의 하드웨어 큐비트 측면에서 정의되고 이 백엔드가 기본적으로 지원하는 연산만 포함하는 물리적 회로입니다. 이 개념을 ISA 회로라고도 합니다.
키스킷의 트랜스필레이션 패키지를 사용하여 추상 회로에서 물리적 회로로 변환하는데, 그 중 최상위 액세스 포인트는 transpile(). 큐비트 인덱스가 물리적 큐비트를 참조하도록 의도하는 회로를 정의하는 경우, 큐비트 인덱스가 물리적 큐비트를 참조하도록 하기 위해 QuantumCircuit.ensure_physical() 를 사용하여 회로의 메타데이터를 다시 작성하여 키스킷이 해당 회로를 물리적 회로로 인식하도록 할 수 있지만, 트랜스필레이션과 달리 베이스 게이트 및 하드웨어 결합 제약 조건을 준수하도록 강제하지는 않습니다.
키스킷에서 양자 회로는 QuantumCircuit 클래스로 표현됩니다. 아래는 3큐비트 그린버거-호른-자일링거(GHZ) 상태를 다음과 같이 정의하는 양자 회로의 예시입니다:
from qiskit import QuantumCircuit
# Create a circuit with a register of three qubits
circ = QuantumCircuit(3)
# H gate on qubit 0, putting this qubit in a superposition of |0> + |1>.
circ.h(0)
# A CX (CNOT) gate on control qubit 0 and target qubit 1 generating a Bell state.
circ.cx(0, 1)
# CX (CNOT) gate on control qubit 0 and target qubit 2 resulting in a GHZ state.
circ.cx(0, 2)
# Draw the circuit
circ.draw('mpl')
회로 개념과 정의
양자 회로와 관련된 전문 용어가 많이 있습니다. 이 중 대부분은 양자 컴퓨팅 문헌에서 흔히 볼 수 있는 내용이며, 일부는 양자 소프트웨어 패키지에 더 특화된 내용이고, 일부는 키스킷에 특화된 내용입니다. 이 문서는 빠른 참조를 위해 몇 가지 중요한 개념을 알파벳순으로 나열한 것이지만 기본 개념에 대한 자세한 내용은 다루지 않습니다. 처음부터 시작하려면 IBM 퀀텀 러닝 플랫폼 사용을 고려하세요.
추상 회로
추상적인 수학 연산과 가상 큐비트의 관점에서 정의된 회로입니다. 이는 일반적으로 양자 알고리즘을 생각하는 방식입니다. 추상 회로는 완전히 임의의 단일 연산, 측정, 잠재적으로 실시간 클래식 계산으로 구성될 수 있으며, 어떤 큐비트끼리 상호 작용할 수 있는지에 대한 제한 없이 구성할 수 있습니다.
키스킷의 트랜스필레이션 패키지를 사용하여 추상 회로를 실제 회로 로 변환할 수 있습니다.
안실라 쿼비트
다른 큐비트에 대한 연산을 구현하는 데 사용되지만 최종 상태는 프로그램에 중요하지 않은 여분의 큐비트입니다.
회로
QPU에서 수행되는 단일 실행을 정의하는 계산 루틴입니다. 이는 추상적인 회로일 수도 있고 실제 회로일 수도 있습니다.
clbit
하나의 고전적인 데이터 비트를 의미하는 키스킷 전용 약어입니다.
게이트
하나 이상의 큐비트에 대한 단일 연산입니다.
하드웨어 큐비트
특정 QPU에서 단일 큐비트의 표현입니다. 하드웨어 큐비트는 초전도 회로와 같은 물리적인 양자 역학 시스템을 기반으로 하며, 가상 큐비트와 달리 특정한 결합 제약이 있고 특정 게이트만 특정 하드웨어 큐비트 그룹에 적용할 수 있습니다.
키스킷은 하드웨어 큐비트에 대해 이야기할 때 논리적 큐비트와 개별 물리적 큐비트를 구분하지 않습니다. QPU는 하드웨어 큐비트를 논리적 큐비트로 구현할 수 있으며, 각 하드웨어 큐비트는 제어 전자장치에 의해 키스킷에 불투명하게 제어되고 오류 수정되는 많은 물리적 큐비트로 구성됩니다. 단기적인 애플리케이션의 경우, 키스킷이 추론할 하드웨어 큐비트로서 QPU가 물리적 큐비트를 직접 노출할 가능성이 높습니다.
물리적 큐비트와 논리적 큐비트 모두 양자 간에는 결합 제약이 있고, 특정 양자 연산만 허용되며, 양자 간에는 스케줄링 문제가 있습니다. 키스킷은 하드웨어 큐비트라는 개념으로 이러한 문제를 함께 추상화합니다. 양자 오류 수정 초기에는 특정 백엔드에서 키스킷을 통해 높은 수준의 논리적 큐비트 또는 낮은 수준의 물리적 큐비트로 큐비트 리소스에 액세스하도록 허용할 수 있습니다.
ISA(Instruction Set Architecture)
특정 QPU의 어떤 하드웨어 큐비트 세트에서 어떤 연산을 사용할 수 있는지에 대한 추상 모델입니다. 예를 들어, 하나의 QPU는 모든 단일 하드웨어 큐비트에 대해 및 연산을 허용하고, 특정 하드웨어 큐비트 쌍에 대해 연산을 허용할 수 있습니다.
논리적 큐비트
실시간 양자 오류 보정을 적용하기 위해 (사용자 관점에서) QPU에 의해 함께 제어되는 여러 물리적 큐비트의 모음입니다. 논리적 큐비트는 키스킷을 위한 하드웨어 큐비트의 한 유형입니다.
측정
단일 큐비트 상태에서 데이터의 고전적인 비트 하나를 추출하는 행위입니다. 이는 되돌릴 수 없는 작업이며, 일반적으로 대상 큐비트와 나머지 시스템 간의 얽힘과 위상 일관성을 파괴합니다.
실제 회로
하드웨어 큐비트 측면에서 정의된 회로로, 특정 QPU의 ISA에서 사용할 수 있는 양자 연산만 가능합니다. 물리적 회로는 하나의 특정 QPU 아키텍처에 묶여 있으며, 호환되지 않는 다른 아키텍처에서는 실행되지 않습니다. 이를 ISA 회로라고도 합니다.
일반적으로 여러분이 구성한 추상 회로에 키스킷의 트랜스파일 루틴을 사용하여 실제 회로를 얻습니다.
물리적 큐비트
제어 가능한 2단계 양자 시스템. 이것은 말 그대로 트랜스몬이나 갇힌 이온의 전자 상태와 같은 하나의 "물리학" 큐비트입니다. QPU는 이를 하드웨어 큐비트로 직접 노출하거나 여러 개의 물리적 큐비트를 논리적 큐 비트로 결합할 수 있습니다.
양자 처리 장치(QPU)
기존 컴퓨팅의 CPU나 그래픽 처리의 GPU에 비유할 수 있는 QPU는 양자 데이터에 대한 양자 연산을 실행하는 하드웨어입니다. 계산 회로 모델을 사용하는 QPU는 항상 특정 게이트 세트와 측정 연산을 수행할 수 있을 것으로 기대할 수 있습니다. 특정 기술에 따라 고전적인 제어 흐름 및 고전적인 데이터에 대한 비트 단위 계산과 같은 일부 실시간 고전적인 계산도 실행할 수 있습니다.
큐비트
양자 정보의 기본 단위입니다.
실시간 클래식 계산
회로의 단일 샷 실행 중에 발생할 수 있는 모든 고전적 계산으로, 고전적 계산의 결과가 나중에 회로의 실행에 영향을 미칠 수 있습니다. 특정 QPU에서 사용할 수 있는 실시간 클래식 계산의 양은 제어 전자 장치와 사용 중인 큐비트 기술 등 여러 요인에 따라 크게 달라집니다. 이에 대한 자세한 내용은 하드웨어 공급업체의 설명서를 참조하세요.
단일 운영
양자 상태에 대한 가역적 연산입니다. 모든 양자 게이트는 (정의상) 단일 연산입니다.
가상 큐비트
추상적인 회로를 구축하는 데 사용되는 추상적이고 수학적 큐비트입니다. 가상 큐비트는 양자 알고리즘을 높은 수준에서 일반적으로 생각하는 방식으로, 모든 양자 게이트가 모든 가상 큐비트에서 유효하고 모든 가상 큐비트는 항상 다른 모든 가상 큐비트에 연결되어 있다고 가정합니다.
하드웨어에 매핑할 때는 가상 큐비트를 하드웨어 큐비트에 할당해야 합니다. 이 매핑은 일대일일 필요는 없습니다. 일반적으로 하나의 가상 큐비트는 회로 실행 과정에서 기본 QPU의 커플링 제약을 충족하기 위해 하드웨어 큐비트에서 다른 하드웨어 큐비트로 스왑되어야 합니다. 회로에 사용된 모든 가상 큐비트가 물리 회로의 특정 지점에서 물리 큐비트에 매핑될 필요는 없으며, 가상 큐비트가 측정(상태 붕괴)된 후 다시는 사용되지 않아 새로운 가상 큐비트가 그 자리를 대신할 수도 있습니다. 이러한 조건을 평가하여 가상 회로를 물리적 회로에 매핑하는 것이 키스킷의 트랜스필레이션 패키지가 하는 일입니다.
qiskit.circuit API 개요
여기에 있는 모든 개체는 다음 섹션에서 더 자세히 설명하며, 더 큰 맥락에서 설명합니다. 이 섹션에서는 여기에 설명된 API 요소에 대한 개요를 제공합니다.
주요 클래스는 QuantumCircuit로, 회로 구축에 대한 심층적인 섹션을 포함한 자체 문서 페이지가 있습니다. 양자 데이터와 가장 단순한 클래식 데이터는 '비트'와 '레지스터'로 표현됩니다:
회로 내에서, 각 완전한 CircuitInstruction 는 Operation (이는, Instruction, Gate 또는 그 밖의 하위 클래스일 수 있음)과 큐비트 및 클비트 피연산자로 구성됩니다. 여기에서 핵심 기본 클래스는 다음과 같습니다:
-
CircuitInstruction, 연산과 그 피연산자 -
InstructionSet, 회로 데이터 슬라이스에 대한 임시 핸들 -
Operation, 어떤 추상적인 수학적 대상이나 하드웨어 명령어든-
AnnotatedOperation, 추상 수식어가 적용된 하위 클래스
-
Instruction최소 추상 Operation 인터페이스의 가장 일반적인 구체적 하위 클래스는 입니다. 는 추상적인 수학적 대상도 포함할 수 있지만 Operation , 는 Instruction 하드웨어에서 직접 실행될 수 있는 것을 말한다. 이는 다시 와 ControlledGate 에 의해 Gate 하위 클래스로 정의되며, 이 클래스들은 여기에 단일성과 제어된 의미론을 추가로 적용합니다:
Instruction, 하드웨어 기반 명령어를 나타내는Gate, 단일 연산을 수행하는 하드웨어 명령어를 나타내는ControlledGate, 제어 구조를 갖춘 게이트를 나타냅니다.
키스킷에는 표준 게이트와 회로로 구성된 대규모 라이브러리가 포함되어 있으며, 이 라이브러리는 qiskit.circuit.library. 이들 중 다수는 Python -객체 싱글톤으로 선언됩니다. 이를 위한 메커니즘은 에 자세히 설명되어 있습니다 qiskit.circuit.singleton에 자세히 설명되어 있으며, 그 중 주요 클래스는 각각 표준 명령어 게이트 계층 구조의 싱글톤 형태입니다:
일부 명령어는 회로의 제어 흐름이나 데이터 흐름에 영향을 미친다는 점에서 특히 특별합니다. 최상위 레벨은 다음과 같습니다:
-
Barrier를 사용하여 회로의 독립적으로 최적화해야 하는 부분을 표시합니다 -
Delay을 클릭하여 실시간 대기 기간을 삽입합니다 -
Reset를 사용하여 큐비트를 상태로 되돌릴 수 없게 재설정합니다 -
Store를 사용하여 저장 위치에 실시간 클래식 표현식을 작성합니다 -
ControlFlowOp, 여기에는 다음과 같은 구체적인 하위 클래스가 있습니다:BreakLoopOp, 가장 가까운 포함 루프에서 벗어나기 위해ContinueLoopOp, 포함된 루프의 다음 반복으로 즉시 넘어가기 위해BoxOp, 명령어의 간단한 묶음ForLoopOp, 특정 값 범위를 순회하기 위해IfElseOp, 두 개의 하위 회로 중 하나에 조건부로 진입하기 위해SwitchCaseOp, 여러 하위 회로 중 하나에 조건부로 진입하기 위해WhileLoopOp, 특정 조건이 성립하지 않게 될 때까지 하위 회로를 반복한다.
특정 명령어에는 메타데이터를 “주석”으로 추가할 수 있으며, 이 메타데이터는 일반적으로 컴파일러 패스에서 해당 명령어 주변에서 처리되거나, 이후 백엔드 처리 단계에서 활용되도록 의도된 것입니다. BoxOp현재 이는.로 제한되어 있습니다. qiskit.circuit.annotationAnnotation이러한 주석은 의 사용자 정의 하위 클래스로 표현되며, 지원 인프라에 대한 자세한 내용은 에서 다뤄집니다.
회로에는 실시간으로 평가되는 고전적인 표현식이 포함될 수 있으며, QPU는 회로를 한 번만 실행합니다. 이는 주로 모듈 문서에 문서화되어 있습니다 qiskit.circuit.classical. 특히 베이스 클래스('루트'에서 노출되지 않는)에 관심이 있을 수 있습니다 qiskit.circuit 루트에서 노출되지 않음):
데이터의 고전적인 하드웨어 표현에 의해 제한되는 이러한 실시간 표현식 평가 외에도, 키스킷은 추상적인 기호 대수학으로 수행되는 "컴파일 타임" 매개변수화 개념을 가지고 있습니다. 이들은 일반적으로 수치 미분을 수행하고자 하는 고수준 알고리즘에서 게이트 각도를 표현하는 데 사용되지만, 실시간 평가보다는 키스킷의 오래된 부분이기 때문에 여전히 일부에서는 일반적인 매개변수화를 수행하는 데 사용됩니다. 주요 관련 클래스는 다음과 같습니다:
Parameter, 컴파일 시 표현식의 원자ParameterExpression, 매개변수에 대한 기호 계산ParameterVector, 다양한Parameters를 한데 모은 편리한 모음집ParameterVectorElement, 에 의해 사용되는 의Parameter하위 클래스ParameterVector
모듈은 qiskit.circuit 모듈은 컴파일 워크플로우를 지원하기 위해 회로와 함께 작동하는 일부 계산 클래스도 노출합니다. 주요 내용은 다음과 같습니다.
EquivalenceLibrary, 게이트와 회로 간의 분해 관계를 담은 데이터베이스BasisTranslatorSessionEquivalenceLibrary, 이는 컴파일러의 에서EquivalenceLibrary기본적으로 사용되는 가변 인스턴스입니다.
무작위 회로를 생성하는 유틸리티도 있습니다:
마지막으로 회로 모듈에는 회로별 방식으로 문제가 발생한 경우를 나타내는 자체 예외 클래스가 있습니다:
Qiskit에서의 회로 표현
회로를 표현하는 주요 사용자 대면 클래스는 QuantumCircuit. 이는 추상적인 회로일 수도 있고 실제 회로일 수도 있습니다. 클래스 자체에 대한 자세한 정보는 QuantumCircuit 클래스 자체와 클래스에서 사용할 수 있는 다양한 메서드에 대한 자세한 내용은 클래스 문서에서 확인할 수 있습니다.
내부적으로, a는 QuantumCircuit 큐비트, 고전 비트, 컴파일 시간 매개변수, 실시간 변수, 그리고 해당 객체가 처리하는 데이터와 매개변수화 방식에 관한 기타 추적 정보를 포함합니다. 그 다음에는 특정 연산(게이트, 측정 등)과 그 연산의 피연산자(큐비트와 고전 비트)를 포함하는 일련의 CircuitInstructions가 들어 있습니다.
C 언어와의 상호 운용성
QuantumCircuit Python 공간에서 이 타입은 네이티브 Rust 코드나 C-API 코드가 사용하는 타입과 정확히 동일하지 않습니다. C-API 유형은 유형을 갖는 내부 객체에 QuantumCircuit._data 의해 지원됩니다 QkCircuitCircuitData . Python 커뮤니티에서는 이에 대해 공개된 정보가 거의 없습니다.
CircuitData
class qiskit.circuit.CircuitData(<no public constructor>)
베이스: object
C-API에 해당하는 비공개 내부 Qiskit 객체입니다 QkCircuit.
이름과 관계없이, 이 객체의 모든 메서드와 속성은 비공개이며, Python 에서 사용자가 직접 사용할 수 없습니다. 이는 Qiskit의 구현 세부 사항입니다.
Python 사용자가 이 객체를 사용할 수 있는 유일한 방법은, circuits의 “native” 구성 요소를 매개변수로 받는 메서드에 이 객체를 전달하는 것입니다. 여기에는 예를 들어 C-API 함수가 포함됩니다 qk_circuit_borrow_from_python().
이 객체는 의 Rust/C 네이티브 구성 요소에 passmanager.IR 대응하는 것으로 사용할 수 있습니다 QuantumCircuit.
비트와 레지스터
큐비트와 기존 비트는 공유 베이스인 Bit 타입으로 표현되며, 클래스는 불변 객체라는 것 외에는 아무런 동작도 하지 않습니다:
비트
큐비트
클빗
큐비트와 클릿은 인수가 없는 사용자에 의해 인스턴스화됩니다(예: Qubit()). 비트는 동일한 Python 객체이거나 둘 다 동일한 이름과 크기의 레지스터에 의해 생성되고 해당 레지스터 내에서 동일한 인덱스를 참조하는 경우 동일하게 비교됩니다. "ancilla" 큐비트를 위한 특수 유형 태그도 있지만, 현재 키스킷 상태에서는 거의 사용되지 않습니다:
AncillaQubit
동일한 유형의 컬렉션 비트는 일치하는 유형의 레지스터에 캡슐화할 수 있습니다. 기본 기능은 직접 인스턴스화되지 않는 기본 클래스에 있습니다:
등록
class qiskit.circuit.Register
베이스: object
일반 레지스터를 구현합니다.
이 클래스는 직접 인스턴스화할 수 없습니다. 유일한 목적은 일반 유형 검사를 허용하는 것입니다 ClassicalRegister 와 QuantumRegister.
정의된 각 비트 하위 유형에는 기본 클래스와 동일한 생성자 서명, 메서드 및 속성을 가진 관련 레지스터가 있습니다:
QuantumRegister
ClassicalRegister
class qiskit.circuit.ClassicalRegister(size=None, name=None, bits=None)
베이스: Register
등록을 구현합니다.
AncillaRegister
class qiskit.circuit.AncillaRegister(size=None, name=None, bits=None)
베이스: QuantumRegister
안실라 레지스터를 구현합니다.
한 번에 여러 비트를 인스턴스화하는 일반적인 방법은 QuantumRegister("my_qreg", 5) 와 같이 레지스터를 생성하는 것입니다. 이렇게 하면 해당 비트 컬렉션에 이름을 지정할 수 있다는 장점이 있으며, 이는 회로 시각화(QuantumCircuit.draw()) 및 교환 언어로 내보내기( qasm2 및 qasm3). 이름과 미리 구성된 비트 목록을 전달할 수도 있지만 이렇게 하면 하드웨어에서 제대로 지원되지 않는 '앨리어싱 레지스터'가 생성됩니다.
회로는 레지스터를 추적하지만 레지스터 자체는 회로에 거의 동작 차이를 부여하지 않습니다. 유일한 예외는 ClassicalRegister를 부호 없는 정수로 암시적으로 캐스팅하여 제어 흐름 연산의 조건부 비교에 사용할 수 있다는 것입니다.
클래식 레지스터와 비트는 키스킷에서 클래식 데이터를 표현하는 최초의 방식이었으며 현재도 가장 많이 지원되고 있습니다. 장기적으로 데이터 모델은 다양한 클래식 데이터를 보다 완전하고 강력하게 유형화하여 표현하는 방향으로 나아가고 있지만( 실시간 클래식 계산 참조), 현재 키스킷에서는 여전히 클래식 비트를 매우 일반적으로 사용하고 있습니다.
지시 문맥
CircuitInstruction이 QuantumCircuit.data 시퀀스의 스칼라 유형은 “명령어 컨텍스트” 객체, 입니다. operation이는 본질적으로 수행해야 할 작업(그 것)과, 해당 작업이 적용되는 대상 qubits (와 clbits)을 나타내는 데이터를 포함하는 단순한 데이터 클래스일 뿐입니다.
칼럼 1 | 칼럼 2 |
|---|---|
CircuitInstruction(연산[, 큐비트, 클비트] ) | 의 단일 명령어는 QuantumCircuitoperation 와 다양한 피연산자로 구성된 단일 명령어입니다. |
프로그래밍적으로 볼 때, 이 클래스는 실제로 Rust로 구현되어 있으며, Rust 공간 내부의 내부 데이터에 대한 생성된 핸들입니다. 이 클래스의 인스턴스에 대한 변경 사항은 회로에 반영되지 않습니다. 일반적으로 회로에 이미 포함된 명령어 컨텍스트를 직접 변경할 수는 없습니다. 이 QuantumCircuit 인터페이스는 회로를 저장하고 구축하기 위해 설계된 반면, 회로를 변경할 수 있는 인터페이스는 트랜스파일러와 그 처리 단계, 그리고 중간 DAGCircuit 표현에서 찾아야 합니다.
InstructionSet회로에 명령어를 추가하는 메서드(예: append(), 그리고 모든 보조 표준 게이트 메서드)는 QuantumCircuit 여러 CircuitInstructions를 동시에 참조하는 핸들인 를 반환합니다.
칼럼 1 | 칼럼 2 |
|---|---|
InstructionSet(*[, resource_requester] ) | 인스트럭션 컬렉션 및 해당 컨텍스트. |
이 InstructionSet 기능은 현재 Qiskit에서 거의 사용되지 않습니다. 이 기능은 명령어에 대한 추가 후 수정(이 변경 사항은 회로로 전파됨)을 수행하기 위한 매우 최소한의 메서드 집합을 제공하지만, 현재는 이러한 사용이 권장되지 않으므로 해당 메서드에 명시된 대안을 사용해야 합니다.
작동, 명령어 및 게이트
OperationCircuitInstruction~ 내에서, 모든 연산이 충족해야 하는 최소한의 인터페이스는 ~입니다. 이는 매우 개략적인 설명이며, 추상적인 회로에 대해서만 적용할 수 있습니다. 연산을 로 Operation 취급하는 주된 목적은 임의의 수학적 대상(예: quantum_info.Operator)을 추상 회로에 직접 추가할 수 있도록 하기 위함이다.
칼럼 1 | 칼럼 2 |
|---|---|
Operation() | 양자 연산 인터페이스. |
Instruction물리적 회로에 대한 모든 연산을 포함하여 대부분의 연산은 보다 구체적으로 정의된 의 한 예입니다. Measure이는.과 같이 일부 QPU가 네이티브로 실행할 수 있는 모든 명령어를 의미합니다. GateInstruction 단일적일 필요는 없다( 가 Measure 그렇지 않은 것과 마찬가지로); 명령이 일 경우, 그 명령은 구체적으로 단일적이다.
칼럼 1 | 칼럼 2 |
|---|---|
Instruction(이름, 큐비트 수, 클래비트 수, 매개변수) | 일반적인 양자 인스트럭션. |
paramsInstructions는 s와 ClbitQubits에만 작용하고, 해당 s에 의해 매개변수화되는 한 거의 임의적일 수 있습니다. 단, 외부 회로 레지스터를 “포괄”하려고 시도해서는 안 되며, 내부에서 숨겨진 매개변수를 사용해서는 안 됩니다. Instructions는 다른 회로와 연결되어 해당 Instruction.definition 속성을 활용하여 분해를 제공할 수 있으며, 이는 국소적이고 일회성인 분해를 제공합니다. 이는 포함된 모든 게이트의 정의에 어떤 위상적 순서가 존재하기만 한다면, 사용자에게 가장 편리한 연산 기준 집합을 자유롭게 선택할 수 있습니다. 즉, 게이트의 정의가 그 부모 게이트에 의존하는 경우, 해당 게이트를 정의에 사용할 수 없습니다. None만약 가 Instruction 최적화 도구에게 완전히 불투명하게 간주되어야 한다면, 그 definition 는 일 수 있다. 자세한 내용은 ‘사용자 지정 지침 만들기 ’를 참조하십시오.
명령어의 는 params 기술적으로 임의로 정할 수 있지만, 일반적으로는 가능한 한 실수를 이용한 매개변수화를 따르도록 노력해야 합니다. Qiskit 자체도 여러 곳에서 이 규칙을 어기고 있으며, 필드 내에서 Instruction.params 온갖 특이한 유형들을 발견할 수 있지만, 이러한 유형들은 종종 유형을 고려한 특별한 처리가 필요함을 의미하기 때문에 성가신 버그의 원인이 됩니다. QuantumCircuit.assign_parameters()명령어가 각도를 기준으로 매개변수화되어 있다면, 해당 명령어 내에서 컴파일 시점 매개변수화를 안정적으로 사용할 수 있으며, 이는.와도 원활하게 통합될 것입니다.
Instruction는 반드시 유니터리(unitary)한 것은 아니지만 Instruction , 그 하위 클래스 Gate 는 유니터리성을 암시하며, 에서 상속받은 모든 메서드에 와 control() 메서드를 추가합니다 to_matrix() .
칼럼 1 | 칼럼 2 |
|---|---|
Gate(이름, 큐비트 수, 매개변수[, 레이블] ) | 단일 게이트. |
GateGate 는 에 Instruction 대한 모든 메서드를 상속받으며, 그 params 의 및 definition 필드에 관한 모든 고려 사항도 동일하게 적용되지만, 물론 s는 어떠한 고전적 자원에도 작용할 수 없다는 점을 제외하면 말이다.
EquivalenceLibrarydefinitionGate 인스턴스에는 기저가 있을 수 있으며(있어야 하지만), 를 사용하여 서로 다른 기저에 따른 여러 가지 분해를 지정할 수도 있습니다.
서브클래스 생성과 Gate관련하여, Qiskit에도 특별한 ControlledGate 클래스가 있습니다. 이 클래스는 (예: CXGate)와 같이 제어되는 많은 표준 라이브러리 게이트의 기반이 되며, 여러분은 주로 이러한 곳에서 이 클래스를 접하게 될 것입니다:
칼럼 1 | 칼럼 2 |
|---|---|
ControlledGate(이름, 큐비트 수, 매개변수[,...] ) | 제어된 단일 게이트. |
Instruction, Gate 및 각각에는 에서 설명된 기법을 사용하여 구축된 대응하는 단일 원소 유형이 ControlledGate 있습니다 qiskit.circuit.singleton. 모듈 수준 문서에는 에 대한 설명과 함께 SingletonInstruction, SingletonGate 및 에 대한 자세한 내용이 포함되어 있습니다 SingletonControlledGate. 사용자 관점에서 볼 때, 기본 클래스가 싱글톤인지 여부에 따라 달라지는 점은 거의 없습니다. 명령어의 수정 가능한 소유 사본을 안전하게 얻어야 할 경우, 항상 먼저 to_mutable() 를 호출해야 한다는 원칙은 변함없습니다(임의의 명령어가 수정 가능하다고 가정해서는 안 됩니다). 또한 직접적인 type 검사는 권장되지 않지만, 부득이하게 필요한 경우 잠재적으로 싱글톤일 수 있는 명령어의 “기본” 유형을 확인하는 신뢰할 수 있는 방법은 를 사용하는 것입니다 base_class.
ControlledGate 게이트의 서브클래싱과 동일한 메커니즘을 사용하여, 자신에 대한 고정된 지연 합성 방식을 정의합니다. 물론 이 방법은 하드웨어를 직접 인식하지는 않으며, 컴파일러의 합성 루틴에 통합하기가 더 어렵지만, 하드웨어에서 네이티브로 실행될 가능성이 있는 구체적인 Instruction 구현체로서 더 잘 작동합니다. base_opAnnotatedOperation합성 및 추상 최적화가 더 중요한 경우, Qiskit은 “게이트 수정자”(그 ControlModifier 중 하나가 입니다)를 추적하여 내부 에 적용하는,라는 조합 가능한 클래스를 제공합니다.
칼럼 1 | 칼럼 2 |
|---|---|
AnnotatedOperation(기본 연산자, 수정자) | 주석이 달린 작업. |
에 AnnotatedOperation 사용할 수 있는 수정자는 다음과 같습니다:
InverseModifier
ControlModifier
class qiskit.circuit.ControlModifier(num_ctrl_qubits=0, ctrl_state=None)
베이스: Modifier
제어 수정자: 작업이 num_ctrl_qubits 에 의해 제어되고 제어 상태 ctrl_state 를 갖도록 지정합니다.
매개변수
PowerModifier
class qiskit.circuit.PowerModifier(power)
베이스: Modifier
파워 수정자: 연산이 파워로 상승하도록 지정 power.
매개변수
power (float)
일회성 객체를 만드는 방법과 서브클래싱을 통해 재사용 가능한 파라메트릭 게이트 등 사용자 지정 게이트 및 인스트럭션을 만드는 방법에 대한 자세한 내용은 아래의 사용자 지정 인스트럭션 만들기를 참조하세요. 의 키스킷 회로 라이브러리에는 qiskit.circuit.library 에는 사용할 수 있는 많은 사전 정의된 게이트와 회로가 포함되어 있습니다.
내장 특수 명령어
Qiskit에는 어떤 면에서 “특별한” 몇 Instruction 가지 클래스가 포함되어 있습니다. 이러한 경우 일반적으로 회로 코드, 트랜스파일러 또는 하드웨어 모델에서 특별한 처리가 이루어집니다. 이것들은 대체로 여러분이 이미 잘 알고 계실 만한 지침들입니다.
키스킷의 측정은 하나의 Qubit 을 단일 Clbit. 이 두 가지가 지침이 적용되는 대상입니다. 측정값은 계산 기준입니다.
측정값
class qiskit.circuit.Measure(label=None)
베이스: SingletonInstruction
계산 기반의 양자 측정.
매개변수
레이블 - 이 지침에 대한 선택적 문자열 레이블입니다.
측정과 관련하여, 기존 데이터를 생성하지 않고 하드웨어에 Reset 연산이 있는데, 이 연산은 기존 데이터를 생성하지 않지만 하드웨어에 큐비트를 상태로 반환하도록 지시합니다. 이는 일관성 없이 발생하고 모든 얽힘이 붕괴되는 것으로 가정합니다.
재설정
class qiskit.circuit.Reset(label=None)
베이스: SingletonInstruction
큐비트를 상태로 일관성 없이 재설정합니다.
매개변수
레이블 - 이 인스트럭션의 선택적 문자열 레이블입니다.
하드웨어에 특정 큐비트에 대해 실시간 유휴 기간을 적용하도록 지시할 수 있다. Delayqiskit.transpiler예정 회로(참조)는 이 를 기준으로 큐비트의 모든 유휴 시간을 명시적으로 포함합니다. BoxOp 또한 해당 BoxOp.duration 필드에 명시적인 지속 시간이 지정될 수도 있습니다.
지연
class qiskit.circuit.Delay(duration, unit=None)
베이스: Instruction
아무것도 하지 않고 지정된 시간 동안 지연/대기/유휴 상태만 유지합니다.
매개변수
- 기간 - 기간의 길이입니다. 인 경우
Expr유형의 상수 표현식이어야 하며Duration이며unit매개 변수는 생략해야 합니다(또는 지정된 경우 "expr"이어야 함). - 단위 - 기간의 단위(
duration가 숫자 값인 경우)."dt", SI 접두사가 붙은 초 단위 또는 "expr"이어야 합니다.
레이즈
CircuitError - duration 식이 타이밍 기반이 아닌 확인된 유형으로 지정되었거나 unit 이 부적절하게 지정되었습니다.
지연 기간은 구체적인 상수 시간으로 지정하거나, 지연 해결이 가능한 expr.Stretch 오브젝트로 구축된 "기간 표현식"으로 지정할 수 있습니다. 이에 대한 자세한 내용은 지연된 해결 예약을 참조하세요.
명령어는 Barrier 명령어는 임의의 수의 큐비트와 클릿을 포함할 수 있으며 하드웨어에서 작동되지 않습니다. 그러나 번역 및 최적화 중에는 모든 최적화가 장벽을 '통과'하는 것을 차단합니다:
from qiskit.circuit import QuantumCircuit
qc = QuantumCircuit(1)
qc.x(0)
qc.barrier()
qc.x(0)옵티마이저가 두 개의 지침을 취소하는 것은 금지되어 있습니다.
장애물
class qiskit.circuit.Barrier(num_qubits, label=None)
베이스: Instruction
모든 최적화 또는 재작성이 장벽 사이에서만 작동하도록 제한되도록 회로의 조각을 분리하는 회로 컴파일 지시어입니다.
시각화에서도 시각적 마커로 표시됩니다.
매개변수
명령어는 특히 Store 명령어는 특히 특별한데, 실시간 고전 연산 표현식 (an expr.Expr)의 결과를 로컬 클래식 변수(a expr.Var). 어느 쪽도 Qubit 나 Clbit 피연산자를 취하지 않지만 명시적인 lvalue 와 rvalue.
예를 들어, 비트 문자열 cr 의 패리티를 결정하고 다른 레지스터 creg 에 저장하려면 Store 명령어를 다음과 같은 방식으로 사용할 수 있습니다:
parity = expr.lift(cr[0])
for i in range(1,n):
parity = expr.bit_xor(cr[i], parity)
qc.store(creg[0], parity)상점
class qiskit.circuit.Store(lvalue, rvalue)
베이스: Instruction
일부 클래식 값을 클래식 메모리 위치에 수동으로 저장합니다.
이것은 클래식 표현식 처리의 저수준 프리미티브입니다( Measure 가 양자 측정을 위한 프리미티브인 것과 유사합니다), 서브클래싱에는 안전하지 않습니다.
매개변수
lvalue
저장된 노드의 Expr 노드를 가져옵니다.
rvalue
L-값에 기록되는 r-값 Expr 노드를 가져옵니다.
실시간 고전적 계산
변수, 표현식 및 유형 시스템의 작동 방식, 이를 표현하는 데 사용되는 객체, 사용 가능한 클래식 연산에 대한 모듈 수준 문서입니다.
메서드 QuantumCircuit 메서드를 사용하여 단일 회로의 컨텍스트에서 이러한 변수로 작업할 수 있습니다.
키스킷은 QPU 실행 중에 발생하여 결과에 영향을 미치는 실시간 클래식 계산을 표현하기 위한 초보적인 로우레벨 지원을 제공합니다. 이러한 개념에 대한 하드웨어 지원은 아직 비교적 초기 단계이므로 실시간 클래식 계산을 최대한 활용하려면 하드웨어 제공업체의 설명서와 긴밀히 협력해야 한다는 점에 유의하세요.
이러한 실시간 계산은 표현식 및 유형 시스템에서 qiskit.circuit.classical. 높은 수준에서 모든 실시간 표현식은 모든 수준에서 연결된 잘 정의된 Expr 노드로 표현되며, 이는 표현식 "트리" 표현의 일부로, 모든 수준에서 잘 정의된 Type 이 연결되어 있습니다. 이러한 클래스의 내부 표현에 대한 자세한 내용은 모듈 수준 설명서를 참조하세요.
실시간 Expr 처리 결과는 특정 상황에서 바로 활용할 수 있습니다. SwitchCaseOpWhileLoopOp현재 이는 및 의 IfElseOp 조건과 의 대상에 국한됩니다. 결과는 노드를 expr.Var 기반으로 하는 명령어(또는 그 QuantumCircuit.store() 생성자)를 Store 사용하여, 유형이 지정된 기존 저장 위치에 저장할 수도 있습니다.
회로에는 내부적으로 수동 클래식 저장소 위치가 포함될 수 있으며, 이는 내부적으로 Var 노드로 표시되는 Expr 트리의 노드로 표현됩니다. 여기에는 다른 표현식과 마찬가지로 클래식 유형이 첨부되어 있습니다. 이들은 회로를 실행할 때마다 선언하고 초기화하거나(add_var()) 또는 회로에 입력(add_input()).
컴파일 시 매개변수화
Qiskit의 다양한 파라메트릭 Instruction 인스턴스는 컴파일 시점에 해결되도록 설계된 방식으로 매개변수화될 수 있습니다. 이것들은 및 ParameterExpression 클래스를 Parameter 사용한다는 점이 특징입니다.
칼럼 1 | 칼럼 2 |
|---|---|
Parameter(이름[, UUID] ) | 컴파일 타임 심볼릭 파라미터입니다. |
ParameterExpression(이름_맵, 식) | 매개변수 표현식입니다. |
이것이 실시간 고전적 계산에서 사용되는 expr.Var 변수와 다른 주된 점은, ParameterExpression 가 수학적 식을 기호적으로 표현한 것이라는 점입니다. 이 식의 의미론은 연속 실수(그리고 제한된 경우 복소수) 위에서 정의된 일반 수학의 의미론과 동일하다. 반면, Var 는 부동소수점 값이나 고정 폭 정수 등, 항상 이산적인 성질을 갖는 고전 컴퓨터에 저장된 변수에 대한 핸들입니다.
다시 말해, 와 같이 수학적으로 유효한 기호적 단순화를 수행할 수 있습니다 ParameterExpression . 이러한 단순화는 부동소수점 산술에서는 유효하지 않으며, 이 expr.Expr 기능은 이를 수행하지 않습니다.
이러한 파라미터의 '컴파일 시간' 부분은 일반적으로 실행을 위해 회로를 전송하기 전에 파라미터에 값을 '할당'하고 싶다는 의미입니다. 이러한 파라미터는 일반적으로 회전 게이트의 파라미터처럼 수학적 각도가 필요한 모든 곳에 사용할 수 있지만, 하드웨어는 일반적으로 실행 전에 적절한 클래식 타입의 값에 할당해야 한다는 점에 유의해야 합니다. 이 과제는 다음을 사용하여 수행할 수 있습니다 QuantumCircuit.assign_parameters().
서로 관련이 있는 여러 매개변수를 사용하고자 할 수도 있습니다. ParameterVector이 과정을 더 쉽게 하기 위해(그리고 여러분이 많은 이름을 직접 생각해내야 하는 번거로움을 피하기 위해), 편의 생성자를 사용할 수 있습니다. ParameterVectorElement벡터의 각 요소는 모두 특수한 하위 클래스의 유효한 Parameter 인스턴스입니다.
칼럼 1 | 칼럼 2 |
|---|---|
ParameterVector(이름[, 길이, UUID] ) | 서로 관련된 Parameter 여러 객체가 들어 있는 컨테이너. |
ParameterVectorElement(벡터, 인덱스[, UUID] ) | ParameterVector.의 구성 요소 중 하나. |
회로의 제어 흐름
ControlFlowOpQuantumCircuit에서, 고전적인 제어 흐름은 의 하위 클래스인 특정 Instructions로 표현됩니다.
칼럼 1 | 칼럼 2 |
|---|---|
ControlFlowOp(이름, 큐비트 수, 클래비트 수,...) | 추상 클래스를 사용하여 모든 제어 흐름 연산을 캡슐화합니다. |
편의를 위해 각 제어 흐름 연산의 속성을 Instruction.name 포함하는 frozenset 인스턴스가 있습니다.
qiskit.circuit.CONTROL_FLOW_OP_NAMES
키스킷의 알려진 제어 흐름 연산의 명령어 이름 집합입니다.
함수는 get_control_flow_name_mapping() 함수를 사용하면 각 이름에 연결된 제어 흐름 연산 클래스에 액세스할 수 있습니다.
get_control_flow_name_mapping
qiskit.circuit.get_control_flow_name_mapping()
제어 흐름 작업의 이름을 해당 클래스에 매핑하는 사전을 반환합니다."
예제
from qiskit.circuit import get_control_flow_name_mapping
ctrl_flow_name_map = get_control_flow_name_mapping()
if_else_object = ctrl_flow_name_map["if_else"]
print(if_else_object)<class 'qiskit.circuit.controlflow.if_else.IfElseOp'>이러한 제어 흐름 연산(IfElseOp, WhileLoopOp, SwitchCaseOp, ForLoopOp, 및 BoxOp)은 모두 분기 조건과 전략을 정의하는 특정 상태를 가지고 있지만, 해당 blocks 속성에는 진입할 가능성이 있는 모든 종류의 하위 회로 블록이 포함되어 있습니다.
칼럼 1 | 칼럼 2 |
|---|---|
IfElseOp(조건, true_body[, false_body,...] ) | 주어진 조건(condition)이 참으로 평가되면 프로그램(true_body)을 실행하고, 그렇지 않으면 선택적으로 다른 프로그램(false_body)을 평가하는 회로 연산입니다. |
WhileLoopOp(조건, 본문[, 레이블] ) | 조건(condition)이 False로 평가될 때까지 하위 회로(body)를 반복적으로 실행하는 회로 연산입니다. |
SwitchCaseOp(대상, 사례, *[, 레이블] ) | 주어진 target 을 values 의 정렬된 목록과 일치시켜 하나의 특정 회로 블록을 실행하는 회로 연산입니다. |
ForLoopOp(인덱스 세트, 루프 매개변수, 본문[,...] ) | indexset 에 제공된 정수 값 집합을 통해 파라미터 loop_parameter 로 매개변수화된 하위 회로(body)를 반복적으로 실행하는 회로 연산입니다. |
BoxOp(본문[, 기간, 단위, 레이블, 주석] ) | 더 큰 맥락에서 원자 단위로 취급되는 회로의 범위가 지정된 '박스' 연산입니다. |
또한 는 SwitchCaseOp 특별한 값을 인식합니다:
qiskit.circuit.CASE_DEFAULT
기본값: <default case>
스위치 문의 "기본" 대소문자를 나타내는 특수 객체입니다. 이것을 케이스 대상으로 사용하는 경우, 마지막 케이스여야 하며 아직 일치하지 않은 모든 항목과 일치합니다. 의 빌더 인터페이스를 사용하는 경우 QuantumCircuit.switch()의 빌더 인터페이스를 사용하는 경우 바인딩된 대소문자 빌더 객체의 DEFAULT 어트리뷰트로도 액세스할 수 있습니다.
블록 구조의 제어 흐름 연산 외에도 루프 내에서 제어 흐름에 영향을 주는 두 가지 특수 명령어가 있습니다. 이는 기존 프로그래밍 언어에서 break 및 continue 문의 일반적인 용도에 해당합니다.
칼럼 1 | 칼럼 2 |
|---|---|
BreakLoopOp(num_qubits, num_clbits[, label] ) | 가장 가까운 둘러싸는 루프의 끝으로 점프하는 회로 연산입니다. |
ContinueLoopOp(num_qubits, num_clbits[, label] ) | 발생 시 가장 가까운 둘러싸는 루프의 다음 반복으로 이동하는 회로 연산입니다. |
클래스 표현은 여기에 문서화되어 있지만, 이러한 클래스를 수동으로 구성하는 것은 사용자가 자주 수행할 필요가 없는 저수준 작업이라는 점에 유의하시기 바랍니다.
제어 흐름 지원 회로를 구축하는 데 권장되는 워크플로에 대해서는 회로에 제어 흐름 추가하기를 읽어 보세요.
하위 클래스들도 역시 Instruction 하위 클래스이므로 ControlFlowOp , 이는 인스턴스에 CircuitInstruction 저장되는 방식상 해당 클래스들이 인스턴스의 qubits 및 clbits 속성에 포함된 큐비트와 클비트의 시퀀스에 “적용”된다는 것을 의미합니다. CircuitInstruction이로 인해 미묘한 데이터 일관성 문제가 발생할 수 있습니다. 즉, 제어 흐름 연산자의 하위 회로 블록 내에서 사용되는 및 Clbit 객체가 Qubit 반드시 내의 해당 객체와 동일하지는 않을 수 있습니다. outer_instruction.qubits[i]Qiskit에서 제어 흐름 연산을 사용하는 모든 코드는 이 점을 염두에 두어야 합니다. 하위 회로 내에서는 를 마치 실제로 인 것처럼 취급해야 subcircuit.qubits[i] 하며, 이와 같은 방식이 계속 적용됩니다. 다음과 같이 하면 이에 대한 간단한 조회 테이블을 생성할 수 있습니다:
cf_instruction: CircuitInstruction = ...
cf_operation: ControlFlowOp = cf_instruction.operation
for block in blocks:
# Mappings of "inner" qubits/clbits to the outer ones.
qubit_map = dict(zip(block.qubits, cf_instruction.qubits))
clbit_map = dict(zip(block.clbits, cf_instruction.clbits))
# ... do something with `block` ...제어 흐름 작업의 하위 블록으로 재귀하는 경우 이 정보를 전파해야 한다는 점을 기억하세요.
위의 코드 블록에 제시된 루프가 zip 정상적으로 작동하려면, 내의 ControlFlowOp 모든 하위 회로 블록은 동일한 수의 Qubits와 Clbits를 포함해야 하며, 이들은 동일한 순서대로 동일한 외부 비트를 가리켜야 합니다. 내부 Bit 회로 내의 객체들이 문자 그대로 동일한 객체일 필요는 없습니다. {x: x}제어 흐름 빌더 인터페이스를 사용할 때(사용자들에게 이 인터페이스를 적극 권장한다는 점을 아무리 강조해도 지나치지 않습니다), 빌더는 내부 비트 객체가 외부 비트 객체와 동일 하도록 처리합니다. 위 코드 블록에서 qubit_map 는 항상 매핑이 되지만, 블록을 사용하는 경우 매핑이 필요할 수 있다는 점에 대비해야 합니다.
제어 흐름 하위 회로에서 사용되는 모든 ClassicalRegisters는 이를 포함하는 모든 블록( 즉, 이를 포함하는 모든 제어 흐름 연산 및 최외곽 회로)에도 존재해야 하며, 동일한 ControlFlowOp 회로 내의 모든 블록은 동일한 레지스터를 포함해야 합니다. 다시 말해, 빌더 인터페이스가 이를 자동으로 처리해 줄 것입니다(만약 처리할 수 없다면 즉시 오류를 발생시킵니다).
로우 레벨 구조를 사용하는 경우 내부 QuantumCircuit 블록은 사용하는 모든 외부 범위의 실시간 클래식 계산 변수를 수동으로 닫아야 합니다. 이는 해당 블록의 iter_captured_vars() 이터레이터에 있습니다. 이러한 블록을 수동으로 구성하는 라이브러리는 제어 흐름 회로 블록을 빌드할 때 이러한 캡처를 추적하고 다음을 사용하여 블록에 추가해야 합니다 add_capture() (또는 captures 생성자 인수)를 사용하여 블록에 추가해야 하지만 사용자 코드는 일반적으로 이를 자동으로 처리하는 제어 흐름 빌더 인터페이스를 사용합니다.
제어 흐름으로 회로를 구축하는 방법에 대한 자세한 내용은 제어 흐름 구축 문서를 참조하세요.
명령어 로컬 어노테이션
사용자 정의 어노테이션을 정의하는 방법, 시스템이 컴파일러 및 다른 형식으로의 직렬화와 상호 작용하는 방법 등 어노테이션 프레임워크에 대한 모듈 수준의 논의입니다.
특정 회로 명령어에는 명령어 국소 주석을 “부여”할 수 있습니다. BoxOpQiskit 2.1.0 기준, 이 기능은 다음으로 제한됩니다. 모든 어노테이션은 하나의 기본 인터페이스 정의 객체의 하위 클래스이지만, 일반적으로 완전히 사용자 정의된 분석 및 명령을 나타냅니다.
칼럼 1 | 칼럼 2 |
|---|---|
Annotation(*args, **kwargs) | 지침에 대한 임의의 주석입니다. |
교환 관계 조사
서킷에서 두 연산이 겹치는 경우 적용 순서를 바꿀 수 있습니다. 예를 들어 게이트를 병합하거나 취소할 수 있는 경우 최적화 및 간소화가 가능합니다:
┌─────────┐ ┌─────────┐ ┌─────────┐
q_0: ┤ Rz(0.5) ├──■──┤ Rz(1.2) ├──■── q_0: ┤ Rz(1.7) ├
└─────────┘┌─┴─┐└──┬───┬──┘┌─┴─┐ = └──┬───┬──┘
q_1: ───────────┤ X ├───┤ X ├───┤ X ├ q_1: ───┤ X ├───
└───┘ └───┘ └───┘ └───┘CommutationChecker이러한 최적화 작업은 트랜스파일러의 일부이지만, 교환을 분석하는 도구는.에서 사용할 수 있습니다.
칼럼 1 | 칼럼 2 |
|---|---|
CommutationChecker([...]) | 두 작업의 변환을 확인합니다. |
지연된 해결 스케줄링
일반적으로 Qiskit 컴파일러의 출력 결과는 QPU에서 직접 실행할 수 없습니다. 먼저, 이 신호는 특정 공급업체의 펄스 레벨 컴파일러를 거치게 될 가능성이 높으며, 이 컴파일러는 게이트와 측정값을 QPU의 제어 전자 장치로 전송되는 신호로 변환합니다. Qiskit은 Target 이러한 펄스가 갖게 될 타이밍 제약 조건 중 일부를 표현할 수는 있지만, 일반적으로 이를 완전히 모두 반영하지는 못합니다. 이는 특히 동적 회로(피드포워드 연산)가 관련된 경우에 더욱 그러합니다. 기존 구성 요소로 인해 발생하는 지연은 종종 백엔드 컴파일러의 최적화 후 저수준 세부 사항에 좌우되며, Qiskit으로는 이를 파악할 수 없습니다.
이러한 상황에서도 사용자는 '스트레치' 지속 시간을 사용하여 동적 디커플링과 같은 펄스의 상대적 스케줄링을 제어할 수 있습니다. 에 의해 구성되며 QuantumCircuit.add_stretch()에 의해 구성되며, 실시간 변경 가능하지는 않지만 qiskit.circuit.classical에 설명된 클래식 표현식 시스템과 상호 작용합니다(실시간 변경 가능하지는 않음).
예를 들어, 스트레치와 박스를 추가하여 동일한 큐비트에 두 개의 개별 동적 디커플링 시퀀스가 적용되는 반면 다른 한 쌍의 큐비트는 알 수 없는 기간의 지연을 거치는 시스템을 설정할 수 있습니다. 두 시퀀스는 내부적으로 구체적인 DD 펄스의 길이가 다르더라도 동일한 길이를 갖도록 제한됩니다.
from qiskit import QuantumCircuit
from qiskit.circuit.classical import expr
qc = QuantumCircuit(3, 3)
# This sets up three duration "degrees of freedom" that will
# be resolved later by a backend compiler.
a = qc.add_stretch("a")
b = qc.add_stretch("b")
c = qc.add_stretch("c")
# This set of operations involves feed-forward operations that
# Qiskit cannot know the length of.
with qc.box():
qc.h(1)
qc.cx(1, 2)
qc.measure([1, 2], [1, 2])
with qc.if_test(expr.equal(qc.clbits[1], qc.clbits[2])):
qc.h(1)
# While that stuff is happening to qubits (1, 2), we want
# qubit 0 to do two different DD sequences. The two DD
# sequences are fixed to be the same length as each other,
# even though they're both internally stretchy.
with qc.box(duration=a):
# Textbook NMRish XX DD.
qc.delay(b, 0)
qc.x(0)
qc.delay(expr.mul(2, b), 0)
qc.x(0)
qc.delay(b, 0)
with qc.box(duration=a):
# XY4-like DD.
for _ in range(2):
qc.delay(c, 0)
qc.y(0)
qc.delay(expr.mul(2, c), 0)
qc.x(0)
qc.delay(c, 0)사용자 지정 지침 생성
QuantumCircuit회로에 추가될 간단한 일회성 명령어나 게이트를 만들고자 하며, 해당 블록이 단지 시각화나 그룹화 목적으로만 사용되는 경우, 사용자 정의 명령어나 게이트를 만드는 가장 쉬운 방법은 해당 정의를 로 구성한 다음, 상황에 맞게 그 의 to_instruction() 또는 to_gate() 메서드를 사용하는 것입니다. 결과는 더 큰 회로에서 직접 에 QuantumCircuit.append() 전달될 수 있습니다. 이러한 메서드는 속성이 제공된 회로와 동일한 Instruction 또는 Gate 인스턴스를 생성합니다. 즉, 이 definition 속성은 트랜스파일러는 물론 회로를 분해하려는 다른 Qiskit 함수에서도 자동으로 접근할 수 있게 됩니다.
독립형 명령어와 게이트는 큐비트와 클릿에서만 작동해야 하며, 복잡한 제어 흐름을 사용해야 하는 명령어는 QuantumCircuit 에 compose()를 사용하여 인라인해야 한다는 점에 유의하세요.
지시 하위 클래스 생성
기본 클래스 Instruction, Gate 및 ControlledGate 는 모두 안전하게 하위 클래스를 생성할 수 있도록 설계되었으며, 하위 클래스가 구현할 수 있는 연결 지점을 갖추고 있습니다. 사용자 정의 게이트가 매개변수가 없고 상태를 유지하지 않는 경우, 예를 들어 SingletonGateqiskit.circuit.singleton와 같이 해당 싱글톤 클래스에서 상속받는 것도 고려해 볼 수 있습니다. 싱글톤 메커니즘에 대한 추가 메서드 및 후크 지점에 대해서는 의 qiskit.circuit.singleton 문서를 참조하시기 바랍니다.
하위 클래스는 일반적으로 해당 지침에 맞는 올바른 인자를 사용하여 :class`super` 생성자를 호출하는 기본 생성자를 정의해야 합니다. Instruction.params클래스에 추가적인 상태를 포함하는 것은 허용되지만, 오직 에만 의존하고, 이 매개변수들이 순수하게 게이트 각도일 때, 하위 클래스가 Qiskit의 나머지 메커니즘과 가장 안정적으로 통합될 수 있습니다.
(또는 그 하위 클래스 중 하나)의 Instruction 하위 클래스는 private Instruction._define() 메서드를 구현해야 하며, 이 메서드는 public definition 메서드를 뒷받침하는 숨겨진 _definition 캐시를 지연 로딩 방식으로 채웁니다.
_define
Instruction._define()
Instruction이 의 캐시된 _definition 필드를 채우십시오.
서브클래스는 공개 definition 속성에 대한 지연 생성 기능을 제공하기 위해 이 메서드를 구현해야 합니다. 파생 클래스는 호출 시점에 이를 params 사용할 수 있습니다. 이 메서드는 에 값을 QuantumCircuit 할당해야 _definition 하며, 값을 반환해서는 안 됩니다.
의 ControlledGate 하위 클래스에서는 메서드가 _define() 모든 비트가 1인 제어 상태에 대해서만 분해를 구현해야 합니다. 이 ControlledGate.definition 기계는 실제 제어 상태를 처리할 수 있도록 이를 수정할 것입니다.
서브클래스가 싱글톤 머신을 사용하는 경우, 주의하세요 _define() 는 표준 싱글톤 객체에 대한 정의 객체를 생성하기 위해 클래스 본문 문이 실행된 직후에 열심히 호출됩니다. 즉, 정의는 이미 정의된 게이트만 사용해야 하며, 싱글톤 게이트가 많은 라이브러리를 작성하는 경우 파일과 가져오기 순서를 지정하여 이것이 가능한지 확인해야 합니다.
__array__의 Gate 서브클래스들도 Numpy 배열 프로토콜의 인스턴스 메서드인 를 재정의하고 싶어 할 가능성이 높습니다. Gate.to_matrix()이는 에서 사용되며, 시그니처는 다음과 같습니다:
__array__
object.__array__(dtype=None, copy=None)
게이트를 나타내는 NumPy 배열을 반환합니다. 이 경우 게이트의 params 필드를 사용할 수 있으며, 해당 값들이 컴파일 시점 매개변수가 아닌 숫자 값이라고 가정할 수 있습니다(서브클래스가 이를 기대한다고 가정할 때).
최대의 효율성을 위해, 반환되는 배열의 dtype은 기본적으로 complex.로 설정되어야 합니다.
사용자 정의 하위 클래스에 제어형 또는 역형의 자연스러운 표현이 있는 경우, 및 control() 메서드를 inverse() 재정의할 수도 있습니다.
사용자 정의 게이트, 즉 축을 중심으로 한 단일 각도 회전을 정의하는 예시입니다. RZXGate본질적으로, 큐비트의 배열이 반대였다면 이런 식이 될 것이므로, 이를 바탕으로 정의를 작성해 보겠습니다. Gate우리는 파라메트릭이므로 싱글톤일 수는 없지만, 유니터리이므로 다음 중 하나여야 합니다:
import math
import numpy as np
from qiskit.circuit import Gate, QuantumCircuit
class RXZGate(Gate):
def __init__(self, theta):
# Initialize with our name, number of qubits and parameters.
super().__init__("rxz", 2, [theta])
def _define(self):
# Our base definition is an RZXGate, applied "backwards".
defn = QuantumCircuit(2)
defn.rzx(1, 0)
self._definition = defn
def inverse(self, annotated = False):
# We have an efficient representation of our inverse,
# so we'll override this method.
return RXZGate(-self.params[0])
def power(self, exponent: float):
# Also we have an efficient representation of power.
return RXZGate(exponent * self.params[0])
def __array__(self, dtype=None, copy=None):
if copy is False:
raise ValueError("unable to avoid copy while creating an array as requested")
cos = math.cos(0.5 * self.params[0])
isin = 1j * math.sin(0.5 * self.params[0])
return np.array([
[cos, -isin, 0, 0],
[-isin, cos, 0, 0],
[0, 0, cos, isin],
[0, 0, isin, cos],
], dtype=dtype)SessionEquivalenceLibraryRZXGate이 예제에서는 를 기준으로 기본 정의를 정의했지만, 다양한 기저에 대한 분해를 더 빠르게 수행하기 위해서는 에 몇 가지 동치 관계를 추가하는 것이 좋을 수 있습니다. 번역 검색은 BasisTranslator 가능한 모든 깊이에서 가능한 모든 등가 관계를 검색하므로, (예를 들어) XGate 를 기준으로 한 등가 관계를 제공하면 를 RXGate 기준으로 한 분해 결과도 자동으로 이용할 수 있게 됩니다.
임의의 기호 매개변수에 대해 , 및 와 같은 동등성을 추가해 보겠습니다:
from qiskit.circuit import SessionEquivalenceLibrary, Parameter
theta = Parameter("theta")
equiv = QuantumCircuit(2)
equiv.h(0)
equiv.cx(1, 0)
equiv.rz(theta, 0)
equiv.cx(1, 0)
equiv.h(0)
SessionEquivalenceLibrary.add_equivalence(RZXGate(theta), equiv)이후, Python 인터프리터 세션이 진행되는 동안, 와 같은 BasisTranslator 번역가들은 검색 결과에서 우리의 새로운 정의를 확인할 수 있게 될 것입니다.
회로 수준 객체 작업
추상 회로를 물리적 회로로 변환하기
초록 QuantumCircuit 는 하드웨어에서 안정적으로 실행할 수 없습니다. 회로 시뮬레이션에 연결된 일부 고급 시뮬레이터를 사용하여 소규모 회로의 경우 빠른 결과를 얻을 수 있지만, 유틸리티 규모의 회로를 실행하려면 실제 하드웨어를 사용해야 하며, 여기에는 실제 회로에 컴파일하는 작업이 포함됩니다.
transpile()이를 수행하는 고수준 함수는 입니다. 이 함수는 추상 회로와 하드웨어 backend 또는 target를 입력으로 받아 물리적 회로를 반환합니다. 실행될 패스의 각 단계에 대해 더 많은 접근 권한과 제어 기능을 얻으려면, 먼저 를 generate_preset_pass_manager() 사용하여 를 StagedPassManager 생성한 다음 이를 수정하십시오.
전체 트랜슬레이션 및 컴파일 기계는 모듈 문서에 자세히 설명되어 있습니다 qiskit.transpiler 모듈 문서에 자세히 설명되어 있으며, 키스킷에 내장된 모든 패스에 대한 자세한 내용은 qiskit.transpiler.passes.
회로 시뮬레이션
인터페이스의 일부는 아니지만 qiskit.circuit 인터페이스의 일부가 아니지만 가장 일반적인 요구 사항 중 하나는 QuantumCircuit 객체에 대한 빠른 시뮬레이션 결과를 얻는 것입니다. 이 섹션에서는 관련 정보를 찾기 위해 문서의 다른 위치로 빠르게 이동할 수 있는 링크를 제공합니다.
단일 회로의 경우, 를 QuantumCircuit 의 Statevector 기본 생성자에 직접 전달하여 상태에 미치는 영향을 시뮬레이션할 수 있습니다. 마찬가지로, 회로를 연산자로 나타내는 단위 행렬을 기본 생성자에 Operator 전달하여 얻을 수 있습니다. 물리적 회로가 있다면, 이를 메서드에 Operator.from_circuit() 전달하여 해당 QuantumCircuit.layout 회로에 대한 변환을 적용함으로써 이를 “추상적” 큐비트 공간으로 다시 매핑할 수도 있습니다.
보다 백엔드와 유사한 시뮬레이션 경험을 위해 모든 키스킷 하드웨어 인터페이스의 시뮬레이터 지원 구현이 있습니다. 특히 다음 사항에 관심이 있을 수 있습니다:
BasicProvider그리고 해당 백엔드가 사용자에게 반환할 수 있는 원시 데이터.StatevectorSimulator~를 둘러싸는 백엔드 스타일의 래퍼로서Statevector- 의
qiskit_aer를 사용하면 완벽한 고성능 시뮬레이션 기능을 사용할 수 있습니다. StatevectorSampler그리고StatevectorEstimatorQiskit 프리미티브 에 대한 시뮬레이터 기반의 참조 구현에 대해서는.
동치 관계 정의하기
추상 회로를 물리적 하드웨어에 매핑하고 그 결과를 최적화하는 과정에서 흔히 수행되는 작업 중 하나는, 특정 게이트를 다른 기저 집합으로 매핑하는 동치 관계를 찾는 것이다. EquivalenceLibraryQiskit은 이 정보를 라는 데이터베이스 클래스에 저장합니다.
칼럼 1 | 칼럼 2 |
|---|---|
EquivalenceLibrary( [기본] ) | Gates를 QuantumCircuits 와 같은 동등한 구현에 단방향 매핑을 제공하는 라이브러리입니다. |
키스킷은 모든 표준 게이트에 대해 미리 정의된 대규모 동등성 관계 세트를 제공합니다. 이 기본 라이브러리는 StandardEquivalenceLibrary라고 하며, 불변으로 취급해야 합니다.
qiskit.circuit.StandardEquivalenceLibrary
Qiskit의 모든 내장 표준 게이트 간의 관계를 저장하는 A EquivalenceLibrary . SessionEquivalenceLibrarybase이 객체를 직접 수정해서는 안 되며, 대신 이 객체를 기반으로 직접 객체를 EquivalenceLibrary 생성하거나 전역 상태를 수정해야 합니다.
Qiskit은 또한 공유 전역 상태 객체인 를 정의하는데, SessionEquivalenceLibrary 이는 Qiskit의 여러 부분, 특히 트랜스파일러 패스에서 BasisTranslator 기본 동등성으로 사용됩니다. BasisTranslator이 add_equivalence() 메서드를 사용하여 자유롭게 자신만의 대응 관계를 추가해도 되며, 이러한 대응 관계는 의 기본 인스턴스에서 자동으로 인식됩니다.
qiskit.circuit.SessionEquivalenceLibrary
EquivalenceLibrary의 기본 인스턴스로, 라이브러리를 수동으로 지정하지 않을 경우 대부분의 Qiskit 객체에서 이 인스턴스가 사용됩니다. add_equivalence().을 사용하여 여기에 등가식을 자유롭게 추가해도 됩니다. StandardEquivalenceLibrary이 기능은 의 모든 내장 규칙을 상속받습니다.
회로에 파울리 회전을 적용하다
양자 회로를 실행할 때 발생하는 노이즈에는 크게 두 가지 유형이 있습니다. 첫 번째는 주로 양자 프로세서와 양자 프로세서가 위치한 외부 환경 간의 원치 않는 상호 작용으로 인해 발생하는 확률적 또는 일관성 없는 노이즈입니다. 두 번째는 코히어런트 오류로 알려져 있으며, 이러한 오류는 양자 시스템의 불완전한 제어로 인해 발생합니다. 이는 해밀턴 시스템에서 원치 않는 용어, 즉 잘못된 단일 진화 또는 양자 시스템의 잘못된 시간 제어로 인한 오류(게이트에 대한 잘못된 펄스 모양 등)일 수 있습니다.
폴리 트월링은 무작위화를 사용하여 논리적으로 동등한 여러 회로의 결과를 결합하여 일관된 오류를 확률적 오류로 만드는 양자 오류 억제 기법입니다. 키스킷은 표준 2 큐비트 게이트에 대해 주어진 회로에 폴리 트월링을 적용하는 기능을 제공합니다. 자세한 내용은 아래 함수 설명서를 참조하세요:
pauli_twirl_2q_gates
qiskit.circuit.pauli_twirl_2q_gates(circuit, twirling_gate=None, seed=None, num_twirls=None, target=None)
지정된 두 큐비트 게이트에 폴리 트월링을 적용하여 주어진 회로의 복사본을 만듭니다.
하드웨어에서 실행할 회로를 돌리려는 의도로 이 기능을 실행하는 경우 가장 효율적인 방법이 아닐 수 있습니다. 특히 하드웨어 공급업체가 실행 인터페이스를 primitives 실행 인터페이스를 구현한 경우 SamplerV2 및 EstimatorV2 이 방법은 회로에 트위링을 적용하는 가장 좋은 방법이 아닐 가능성이 높으므로 지정된 하드웨어 공급업체의 SamplerV2 및/또는 EstimatorV2 구현을 참조하는 것이 좋습니다.
이 함수가 이후에 transpile() 실행되도록 의도된 경우, PassManager.run() 선택적 target 인수를 사용하여 삽입된 1 큐비트 파울리 게이트가 주어진 Target 와 호환되도록 합성되도록 할 수 있으며, 이를 통해 출력 회로가 여전히 호환성을 유지하게 됩니다.
매개변수
- circuit (QuantumCircuit) – 회전하는 회로
- twirling_gate (None | str |Gate |list[str] | list[Gate]) – 회전할 게이트로, 기본값은 None이며, 이는 모든 기본 게이트(
CXGate,CZGate,ECRGate, 및 )를 회전함을 의미합니다iSwapGate. 지정된 경우, 단일 게이트이거나 게이트 객체 또는 해당 문자열 이름으로 구성된 게이트 목록일 수 있습니다. 현재는 “cx”, “cz”, “ecr” 및 “iswap”이라는 이름만 지원됩니다. 기본 게이트 외부에 게이트 객체가 제공되는 경우, 해당 게이트가 회전될 수 있도록 해당to_matrix객체의 메서드에서 행렬이 정의되어 있어야 합니다. 유효한 트위링 구성을 계산할 수 없는 경우, 해당 게이트는 별다른 알림 없이 무시되며 트위링되지 않습니다. - seed (int | None) – 이 함수가 내부적으로 사용하는 난수 생성기의 정수 시드입니다. 이 값을 지정할 경우, 0에서 18,446,744,073,709,551,615 사이의 값이어야 합니다.
- num_twirls (int | None) – 만들 회전 회로의 개수. 이 설정은 기본적으로 로 설정되어 있으며
None, 하나의 회로를 반환합니다. 정수인 경우, num_twirls개의 회로로 구성된 회로 목록이 반환됩니다. - target (Target | None) – 회로에 추가된 파울리 게이트를 최적화하고 지정된 목표에 매핑하기 위한 파울리 트위링의 일환으로, 단일 큐비트 분해를 실행하는 데 사용할 인스턴스를
Target지정하는 경우.
리턴
지정된 트월링 게이트의 각 인스턴스에 폴리 트월링이 적용된 주어진 회로의 복사본입니다.
리턴 유형
QuantumCircuit | list [ QuantumCircuit ]
예외
거의 모든 회로 함수와 메서드는 키스킷 사용과 관련된 에러가 발생하면 CircuitError 를 발생시킵니다(일반적으로 해당 표준 Python 에러를 발생시키는 일반적인 타이핑 또는 인덱싱 문제와는 대조적으로).
CircuitError
exception qiskit.circuit.CircuitError(*message)
베이스: QiskitError
회로를 처리하는 동안 발생하는 오류에 대한 기본 클래스입니다.
오류 메시지를 설정합니다.
회로 표기법
추상적인 객체와 보다 구체적인 행렬로 회로를 구성할 때 비트 레이블 지정, 비트 순서 지정, 추상 텐서 곱이 구체적인 행렬 대수에서 구현되는 방법과 관련해 몇 가지 가능한 규칙이 있습니다.
키스킷의 규칙은 다음과 같습니다:
- 비트 문자열 표현에서 비트는 문자열의 가장 오른쪽 비트에 라는 레이블을, 비트 문자열의 가장 왼쪽 비트에 라는 레이블을 지정합니다.
- 회로 구성 함수에서 정수를 비트 지정 인덱스로 사용할 때 정수는 인덱스로 취급됩니다
QuantumCircuit.qubits(또는clbits). - 회로를 그릴 때 인덱스가 가장 낮은 비트를 맨 위에 배치합니다.
- 상태 벡터 표현에서 추상 텐서 곱을 크로네커 곱으로 구현하고, 이에 대한 인수를 정렬하여 계산 기준 상태 의 진폭이 이 정수로 해석되는 비트 문자열이 위치
statevector[x]에 오도록 합니다. - 게이트를 제어할 때 제어 큐비트는 인자 목록에서 가장 먼저 배치됩니다( 예:
qc.cx(0, 1)호출에서 큐비트 0이 제어가 되고 큐비트 1이 타깃이 됩니다). 마찬가지로, 수동 호출qc.append(CXGate(), [0, 1])에서는 큐비트 0이 컨트롤이 되고 큐비트 1이 타겟이 됩니다.
몇 가지 예를 들어 이러한 규칙을 설명해 보겠습니다.
비트 라벨링
회로를 가져갑니다:
from qiskit import QuantumCircuit
qc = QuantumCircuit(5, 5)
qc.x(0)
qc.x(1)
qc.x(4)
qc.measure(range(5), range(5))이는 큐비트 0, 1, 4의 상태를 에서 로 뒤집은 다음 모든 큐비트 를 계산( )을 사용하여 해당 클릿 으로 측정합니다. 노이즈 없이 시뮬레이션하면 이 회로에서 출력되는 비트 문자열은 매번 이며, 큐비트 0, 1, 4가 뒤집히고 비트 문자열의 '1' 값은 오른쪽에서 0번째, 첫 번째, 네 번째 자릿수에 있습니다.
키스킷에서는 측정 직전의 큐비트 상태를 케트 표기법 속기로 로 표기합니다. Ket 레이블은 기존 비트스트링과 일치하며 숫자 이진 값 19를 가집니다.
이 회로를 그려보면 키스킷이 0번째 큐비트를 회로 도면의 맨 위에 배치하는 것을 볼 수 있습니다:
qc.draw("mpl")
행렬 표현
상태 벡터는 2레벨 시스템의 경우 추상 표현과 행렬 표현의 관계는 다음과 같은 규칙에 정의되어 있습니다
여기서 및 은 복소수입니다. 상태벡터를 1D Numpy로 저장합니다 ndarray 데이터와 함께 sv = [alpha, beta], 즉 sv[0] == alpha 및 sv[1] == beta; 상태 벡터의 인덱스가 케트 레이블과 일치한다는 점에 유의하세요.
오른쪽에 큐비트 0, 왼쪽에 큐비트 1이 있는 크로네커 곱을 사용하여 행렬 대수에서 두 큐비트 상태의 텐서 곱을 구성하여 기저 상태 (여기서 는 비트 문자열의 정수 해석)가 상태 벡터 sv 에서 0이 아닌 항을 갖도록 sv[x] 합니다:
import numpy
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
state_0 = [1, 0] # defined representation of |0>
state_1 = [0, 1] # defined representation of |1>
# Circuit that creates basis state |10011>, where
# binary 10011 has the decimal value 19.
qc = QuantumCircuit(5)
qc.x(0)
qc.x(1)
qc.x(4)
qiskit_sv = Statevector(qc)
# List index 'n' corresponds to qubit 'n'.
individual_states = [
state_1,
state_1,
state_0,
state_0,
state_1,
]
# Start from a scalar.
manual_sv = [1]
for qubit_state in individual_states:
# Each new qubit goes "on the left".
manual_sv = numpy.kron(qubit_state, manual_sv)
# Now `qiskit_sv` and `manual_sv` are the same, and:
assert manual_sv[19] == 1
assert qiskit_sv[19] == 1이는 연산자의 행렬 표현으로 이어지며, 제어 연산자에 대한 비트 순서 규칙과 결합됩니다. 예를 들어, 의 CXGate 행렬 형태는 다음과 같습니다:
import numpy
from qiskit.circuit.library import CXGate
numpy.array(CXGate())이것은 에서 보았던 다른 행렬 표현과 다를 수 있지만, 행렬 표현의 선택은 일반적인 것이며, 이 형식은 제어 큐비트가 우선이고 텐서 곱이 "하나의 진폭"의 인덱스와 상태의 비트 문자열 값 사이에 대응이 있도록 표현된다는 키스킷의 규칙과 일치한다는 점을 상기하십시오.
(예: CCXGate )와 같이 게이트에 대한 제어 큐비트가 여러 개인 경우, 인수는 ctrl_state 동일한 0을 기준으로 한 번호 매기기 규칙을 사용하여 제어 큐비트의 비트열 값으로 해석됩니다. CCXGate예를 들어, 기본값이 ctrl_state 모두 1인 비트열이라고 가정하면, 에 ctrl_state = 1CCXGate 대한 행렬 형태는, 모두 1인 제어 상태 를 취하되, 게이트 진입 시점과 출구 시점에 인덱스가 더 높은 제어 큐비트의 값을 반전시킨 경우와 동일하다는 것을 알 수 있습니다:
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator
# Build the natural representation of `CCX` with the
# control qubits being `[0, 1]`, relative to the
# bitstring state "01", such that qubit 0 must be in |1>
# and qubit 1 must be in |0>. The target qubit is 2.
ccx_natural = QuantumCircuit(3)
ccx_natural.ccx(0, 1, 2, ctrl_state=1)
# Build the same circuit in terms of the all-ones CCX.
# Note that we flip _qubit 1_, because that's the one
# that differs from the all-ones state.
ccx_relative = QuantumCircuit(3)
ccx_relative.x(1)
ccx_relative.ccx(0, 1, 2)
ccx_relative.x(1)
assert Operator(ccx_relative) == Operator(ccx_natural)ctrl_state = 1 이 두 경우 모두에서, 의 CCXGate 행렬 형태는 다음과 같습니다: