주 콘텐츠로 건너뛰기

Circuit 구성

패키지 버전

이 페이지의 코드는 아래 요구 사항을 사용하여 개발되었습니다. 해당 버전 이상을 사용하길 권장해요.

qiskit[all]~=2.3.0

이 페이지에서는 Qiskit SDK의 QuantumCircuit 클래스를 더 자세히 살펴보고, 양자 Circuit을 만드는 데 사용할 수 있는 고급 메서드들을 소개합니다.

양자 Circuit이란 무엇인가요?

간단한 양자 Circuit은 Qubit의 집합과 해당 Qubit에 작용하는 명령어 목록으로 구성됩니다. 이를 설명하기 위해 다음 셀에서는 두 개의 새로운 Qubit으로 새 Circuit을 만들고, Circuit의 qubits 속성을 표시합니다. 이 속성은 최하위 비트 q0q_0부터 최상위 비트 qnq_n 순서로 나열된 Qubit 목록입니다.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumCircuit

qc = QuantumCircuit(2)
qc.qubits
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]

여러 QuantumRegisterClassicalRegister 객체를 결합하여 Circuit을 만들 수 있습니다. 각 QuantumRegisterClassicalRegister에는 이름을 지정할 수도 있습니다.

from qiskit.circuit import QuantumRegister, ClassicalRegister

qr1 = QuantumRegister(2, "qreg1") # Create a QuantumRegister with 2 qubits
qr2 = QuantumRegister(1, "qreg2") # Create a QuantumRegister with 1 qubit
cr1 = ClassicalRegister(3, "creg1") # Create a ClassicalRegister with 3 cbits

combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # Create a quantum circuit with 2 QuantumRegisters and 1 ClassicalRegister
combined_circ.qubits
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]

Circuit의 find_bit 메서드와 그 속성을 사용하면 Qubit의 인덱스와 레지스터를 확인할 수 있습니다.

desired_qubit = qr2[0]  # Qubit 0 of register 'qreg2'

print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]

Circuit에 명령어를 추가하면 해당 명령어가 Circuit의 data 속성에 추가됩니다. 다음 셀 출력에서 볼 수 있듯이, dataCircuitInstruction 객체의 목록이며, 각 객체는 operation 속성과 qubits 속성을 가집니다.

qc.x(0)  # Add X-gate to qubit 0
qc.data
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]

이 정보를 가장 쉽게 확인하는 방법은 draw 메서드를 사용하는 것입니다. 이 메서드는 Circuit의 시각화 결과를 반환합니다. 양자 Circuit을 다양한 방식으로 표시하는 방법은 Circuit 시각화를 참고하세요.

qc.draw("mpl")

Output of the previous code cell

Circuit 명령어 객체는 더 기본적인 명령어로 해당 명령어를 설명하는 "정의" Circuit을 포함할 수 있습니다. 예를 들어, X-gate는 더 일반적인 단일 Qubit Gate인 U3-gate의 특수한 경우로 정의됩니다.

# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")

Output of the previous code cell

명령어와 Circuit은 모두 비트와 Qubit에 대한 연산을 설명한다는 점에서 유사하지만, 목적이 다릅니다.

  • 명령어는 고정된 것으로 취급되며, 해당 메서드는 일반적으로 새로운 명령어를 반환합니다(원본 객체를 변경하지 않음).
  • Circuit은 여러 줄의 코드에 걸쳐 구성하도록 설계되어 있으며, QuantumCircuit 메서드는 기존 객체를 직접 변경하는 경우가 많습니다.

Circuit 깊이란 무엇인가요?

양자 Circuit의 depth()는 Circuit이 정의한 계산을 완료하는 데 필요한, 병렬로 실행되는 양자 Gate "레이어"의 수를 나타내는 척도입니다. 양자 Gate를 구현하는 데 시간이 걸리기 때문에, Circuit의 깊이는 양자 컴퓨터가 해당 Circuit을 실행하는 데 소요되는 시간에 대략적으로 대응합니다. 따라서 Circuit의 깊이는 양자 Circuit을 장치에서 실행할 수 있는지 판단하는 데 사용되는 중요한 지표 중 하나입니다.

이 페이지의 나머지 부분에서는 양자 Circuit을 다루는 방법을 설명합니다.

Circuit 구성

QuantumCircuit.hQuantumCircuit.cx와 같은 메서드는 Circuit에 특정 명령어를 추가합니다. 보다 일반적인 방법으로 Circuit에 명령어를 추가하려면 append 메서드를 사용하세요. 이 메서드는 명령어와 해당 명령어를 적용할 Qubit 목록을 인수로 받습니다. 지원되는 명령어 목록은 Circuit Library API 문서를 참고하세요.

from qiskit.circuit.library import HGate

qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")

Output of the previous code cell

두 Circuit을 결합하려면 compose 메서드를 사용하세요. 이 메서드는 다른 QuantumCircuit과 선택적 Qubit 매핑 목록을 인수로 받습니다.

참고

compose 메서드는 새로운 Circuit을 반환하며, 작용하는 두 Circuit을 변경하지 않습니다. compose 메서드를 호출하는 Circuit을 직접 변경하려면 inplace=True 인수를 사용하세요.

qc_a = QuantumCircuit(4)
qc_a.x(0)

qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)

# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")

Output of the previous code cell

Circuit을 체계적으로 관리하기 위해 Circuit을 명령어로 컴파일할 수도 있습니다. to_instruction 메서드를 사용하면 Circuit을 명령어로 변환하고, 다른 명령어와 마찬가지로 다른 Circuit에 추가할 수 있습니다. 다음 셀에 그려진 Circuit은 이전 셀에서 그려진 Circuit과 기능적으로 동일합니다.

inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")

Output of the previous code cell

Circuit이 유니타리(unitary)라면 to_gate 메서드를 사용하여 Gate로 변환할 수 있습니다. Gate 객체는 양자 제어를 추가하는 control 메서드 등 몇 가지 추가 기능을 갖춘 특수한 유형의 명령어입니다.

gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")

Output of the previous code cell

내부를 확인하려면 decompose 메서드를 사용하여 각 명령어를 정의에 따라 펼쳐볼 수 있습니다.

참고

decompose 메서드는 새로운 Circuit을 반환하며, 작용하는 Circuit을 변경하지 않습니다.

qc_a.decompose().draw("mpl")

Output of the previous code cell

Qubit 측정

측정은 개별 Qubit의 상태를 샘플링하고 결과를 고전 레지스터로 전달하는 데 사용됩니다. Sampler 프리미티브에 Circuit을 제출하는 경우 측정이 필요합니다. 그러나 Estimator 프리미티브에 제출하는 Circuit에는 측정이 포함되어서는 안 됩니다.

Qubit은 measure, measure_all, measure_active 세 가지 메서드로 측정할 수 있습니다. 측정 결과를 시각화하는 방법은 결과 시각화 페이지를 참고하세요.

  1. QuantumCircuit.measure : 첫 번째 인수의 각 Qubit을 두 번째 인수로 지정된 고전 비트에 측정합니다. 이 메서드는 측정 결과가 저장되는 위치를 완전히 제어할 수 있습니다.

  2. QuantumCircuit.measure_all : 인수를 받지 않으며, 미리 정의된 고전 비트가 없는 양자 Circuit에 사용할 수 있습니다. 고전 와이어를 생성하고 측정 결과를 순서대로 저장합니다(예: Qubit qiq_i의 측정 결과는 cbit measimeas_i에 저장됩니다). 측정 전에 배리어(barrier)도 추가됩니다.

  3. QuantumCircuit.measure_active : measure_all과 유사하지만, 연산이 있는 Qubit만 측정합니다.

qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)

Output of the previous code cell

qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)

Output of the previous code cell

qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)

Output of the previous code cell

파라미터화된 Circuit

근거리 양자 알고리즘 중 다수는 양자 Circuit의 여러 변형을 실행하는 과정을 포함합니다. 대규모 Circuit을 구성하고 최적화하는 데 연산 비용이 많이 들 수 있으므로, Qiskit은 파라미터화된 Circuit을 지원합니다. 이러한 Circuit에는 정의되지 않은 파라미터가 있으며, Circuit을 실행하기 직전까지 값을 정의할 필요가 없습니다. 덕분에 Circuit 구성과 최적화를 주요 프로그램 루프 밖으로 이동할 수 있습니다. 다음 셀에서는 파라미터화된 Circuit을 만들고 표시합니다.

from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter

angle = Parameter("angle") # undefined number

# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)

qc.draw("mpl")

Output of the previous code cell

다음 셀에서는 이 Circuit의 다양한 변형을 여러 개 만들고 그 중 하나를 표시합니다.

circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))

circuits[0].draw("mpl")

Output of the previous code cell

Circuit에 정의되지 않은 파라미터 목록은 parameters 속성에서 확인할 수 있습니다.

qc.parameters
ParameterView([Parameter(angle)])

파라미터 이름 변경

기본적으로 파라미터화된 Circuit의 파라미터 이름에는 x- 접두사가 붙습니다(예: x[0]). 다음 예시와 같이 정의된 후에도 이름을 변경할 수 있습니다.

from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector

# Define a parameterized circuit with default names
# For example, x[0]
circuit = z_feature_map(2)

# Set new parameter names
# They will now be prefixed by `hi` instead
# For example, hi[0]
training_params = ParameterVector("hi", 2)

# Assign parameter names to the quantum circuit
circuit = circuit.assign_parameters(parameters=training_params)
메서드 이름이 기억나지 않으시나요? Qiskit Code Assistant에게 물어보세요.

다음 단계

추천 자료