참고
이 페이지는 tutorials/circuits_advanced/01_advanced_circuits.ipynb 로부터 생성되었다.
고급 회로¶
[1]:
import numpy as np
from qiskit import *
불투명한 게이트 (Opaque gates)¶
[2]:
from qiskit.circuit import Gate
my_gate = Gate(name='my_gate', num_qubits=2, params=[])
[3]:
qr = QuantumRegister(3, 'q')
circ = QuantumCircuit(qr)
circ.append(my_gate, [qr[0], qr[1]])
circ.append(my_gate, [qr[1], qr[2]])
circ.draw()
[3]:
┌──────────┐ q_0: ┤0 ├──────────── │ my_gate │┌──────────┐ q_1: ┤1 ├┤0 ├ └──────────┘│ my_gate │ q_2: ────────────┤1 ├ └──────────┘
합성 게이트들¶
[5]:
# Build a sub-circuit
sub_q = QuantumRegister(2)
sub_circ = QuantumCircuit(sub_q, name='sub_circ')
sub_circ.h(sub_q[0])
sub_circ.crz(1, sub_q[0], sub_q[1])
sub_circ.barrier()
sub_circ.id(sub_q[1])
sub_circ.u(1, 2, -2, sub_q[0])
# Convert to a gate and stick it into an arbitrary place in the bigger circuit
sub_inst = sub_circ.to_instruction()
qr = QuantumRegister(3, 'q')
circ = QuantumCircuit(qr)
circ.h(qr[0])
circ.cx(qr[0], qr[1])
circ.cx(qr[1], qr[2])
circ.append(sub_inst, [qr[1], qr[2]])
circ.draw()
[5]:
┌───┐ q_0: ┤ H ├──■──────────────────── └───┘┌─┴─┐ ┌───────────┐ q_1: ─────┤ X ├──■──┤0 ├ └───┘┌─┴─┐│ sub_circ │ q_2: ──────────┤ X ├┤1 ├ └───┘└───────────┘
회로들은 to_instruction
명령어에 의해 바로 분해되지는 않는데, 이는 회로 설계를 더 고차원의 추상화 단계에서 가능하게 해준다. 임의로 지정된 순간 또는 컴파일 전에, 하위 회로들은 메소드 decompose
에 의해 분해될 것이다.
[6]:
decomposed_circ = circ.decompose() # Does not modify original circuit
decomposed_circ.draw()
[6]:
┌─────────┐ q_0: ┤ U2(0,π) ├──■───────────────────────────────────── └─────────┘┌─┴─┐ ┌───┐ ░ ┌───────────┐ q_1: ───────────┤ X ├──■──┤ H ├────■─────░─┤ U(1,2,-2) ├ └───┘┌─┴─┐└───┘┌───┴───┐ ░ └───┬───┬───┘ q_2: ────────────────┤ X ├─────┤ Rz(1) ├─░─────┤ I ├──── └───┘ └───────┘ ░ └───┘
매개변수를 가진 회로들¶
[7]:
from qiskit.circuit import Parameter
theta = Parameter('θ')
n = 5
qc = QuantumCircuit(5, 1)
qc.h(0)
for i in range(n-1):
qc.cx(i, i+1)
qc.barrier()
qc.rz(theta, range(5))
qc.barrier()
for i in reversed(range(n-1)):
qc.cx(i, i+1)
qc.h(0)
qc.measure(0, 0)
qc.draw('mpl')
[7]:

We can inspect the circuit’s parameters
[8]:
print(qc.parameters)
ParameterView([Parameter(θ)])
값에 매개변수 바인딩하기¶
모든 회로의 매개변수는 회로를 백엔드로 보내기 전에 값을 할당해야 한다. 이 작업은 다음을 따라 수행 가능하다: bind_parameters
메서드는 Parameter
들의 값을 할당하는 딕셔너리를 받아들이고, 각각의 해당하는 매개변수가 그에 알맞는 값으로 바뀐 새로운 회로를 반환한다. 부분적인 값 지정도 지원되는데, 이 경우 반환된 회로는 특정 값에 할당된 적 없는 Parameter
들로 매개변수가 지정된다.
[9]:
import numpy as np
theta_range = np.linspace(0, 2 * np.pi, 128)
circuits = [qc.bind_parameters({theta: theta_val})
for theta_val in theta_range]
circuits[-1].draw()
[9]:
┌───┐ ░ ┌────────┐ ░ ┌───┐┌─┐ q_0: ┤ H ├──■──────────────────░─┤ Rz(2π) ├─░──────────────────■──┤ H ├┤M├ └───┘┌─┴─┐ ░ ├────────┤ ░ ┌─┴─┐└───┘└╥┘ q_1: ─────┤ X ├──■─────────────░─┤ Rz(2π) ├─░─────────────■──┤ X ├──────╫─ └───┘┌─┴─┐ ░ ├────────┤ ░ ┌─┴─┐└───┘ ║ q_2: ──────────┤ X ├──■────────░─┤ Rz(2π) ├─░────────■──┤ X ├───────────╫─ └───┘┌─┴─┐ ░ ├────────┤ ░ ┌─┴─┐└───┘ ║ q_3: ───────────────┤ X ├──■───░─┤ Rz(2π) ├─░───■──┤ X ├────────────────╫─ └───┘┌─┴─┐ ░ ├────────┤ ░ ┌─┴─┐└───┘ ║ q_4: ────────────────────┤ X ├─░─┤ Rz(2π) ├─░─┤ X ├─────────────────────╫─ └───┘ ░ └────────┘ ░ └───┘ ║ c: 1/═══════════════════════════════════════════════════════════════════╩═ 0
[12]:
backend = BasicAer.get_backend('qasm_simulator')
job = backend.run(transpile(circuits, backend))
counts = job.result().get_counts()
예제 회로에서, 우리는 전역 \(R_z(\theta)\) 회전을 5큐비트 얽힘 상태에 적용한다. 그에 따라 우리는 큐비트 0에서 \(5\theta\) 의 진동을 관찰할 수 있을 것이다.
[13]:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111)
ax.plot(theta_range, list(map(lambda c: c.get('0', 0), counts)), '.-', label='0')
ax.plot(theta_range, list(map(lambda c: c.get('1', 0), counts)), '.-', label='1')
ax.set_xticks([i * np.pi / 2 for i in range(5)])
ax.set_xticklabels(['0', r'$\frac{\pi}{2}$', r'$\pi$', r'$\frac{3\pi}{2}$', r'$2\pi$'], fontsize=14)
ax.set_xlabel('θ', fontsize=14)
ax.set_ylabel('Counts', fontsize=14)
ax.legend(fontsize=14)
[13]:
<matplotlib.legend.Legend at 0x7f8fcb307710>

컴파일 비용 줄이기¶
결합 전에 파라미터화된 회로를 컴파일하는 것은, 일부 경우에, 결합된 회로들의 세트를 통해 컴파일링하는 것과 비교하여 컴파일 시간을 상당히 감소시킬 수 있다.
[14]:
import time
from itertools import combinations
from qiskit.compiler import assemble
from qiskit.test.mock import FakeVigo
start = time.time()
qcs = []
theta_range = np.linspace(0, 2*np.pi, 32)
for n in theta_range:
qc = QuantumCircuit(5)
for k in range(8):
for i,j in combinations(range(5), 2):
qc.cx(i,j)
qc.rz(n, range(5))
for i,j in combinations(range(5), 2):
qc.cx(i,j)
qcs.append(qc)
compiled_circuits = transpile(qcs, backend=FakeVigo())
qobj = assemble(compiled_circuits, backend=FakeVigo())
end = time.time()
print('Time compiling over set of bound circuits: ', end-start)
Time compiling over set of bound circuits: 2.4267938137054443
[16]:
start = time.time()
qc = QuantumCircuit(5)
theta = Parameter('theta')
for k in range(8):
for i,j in combinations(range(5), 2):
qc.cx(i,j)
qc.rz(theta, range(5))
for i,j in combinations(range(5), 2):
qc.cx(i,j)
transpiled_qc = transpile(qc, backend=FakeVigo())
qobj = assemble([transpiled_qc.bind_parameters({theta: n})
for n in theta_range], backend=FakeVigo())
end = time.time()
print('Time compiling over parameterized circuit, then binding: ', end-start)
Time compiling over parameterized circuit, then binding: 1.4472951889038086
합성¶
매개변수화 회로(Parameterized circuits) 는 표준인 QuantumCircuit
와 같은 것으로 구성될 수 있다. 일반적으로, 두 개의 매개변수화 회로들을 구성할 때, 출력회로는 입력 회로들의 매개변수의 결합에 의해 매개변수를 가지게 된다.
그러나 매개변수 이름은 주어진 회로에서 고유해야 한다. 표적회로에 이름이 이미 있는 매개변수를 추가하려고 할 때: 소스와 표적이 동일한 Parameter
인스턴스를 공유하면, 매개변수가 동일한 것으로 간주된다. 만일 소스와 표적이 다른 Parameter
갖는 경우에는 오류가 발생한다.
[17]:
phi = Parameter('phi')
sub_circ1 = QuantumCircuit(2, name='sc_1')
sub_circ1.rz(phi, 0)
sub_circ1.rx(phi, 1)
sub_circ2 = QuantumCircuit(2, name='sc_2')
sub_circ2.rx(phi, 0)
sub_circ2.rz(phi, 1)
qc = QuantumCircuit(4)
qr = qc.qregs[0]
qc.append(sub_circ1.to_instruction(), [qr[0], qr[1]])
qc.append(sub_circ2.to_instruction(), [qr[0], qr[1]])
qc.append(sub_circ2.to_instruction(), [qr[2], qr[3]])
print(qc.draw())
# The following raises an error: "QiskitError: 'Name conflict on adding parameter: phi'"
# phi2 = Parameter('phi')
# qc.u3(0.1, phi2, 0.3, 0)
┌────────────┐┌────────────┐
q_0: ┤0 ├┤0 ├
│ sc_1(phi) ││ sc_2(phi) │
q_1: ┤1 ├┤1 ├
├────────────┤└────────────┘
q_2: ┤0 ├──────────────
│ sc_2(phi) │
q_3: ┤1 ├──────────────
└────────────┘
다른 매개변수화 과정을 거진 하위 회로를 추가하기 위해 메서드 to_instruction
은 추가 전달 인자 (parameter_map
) 을 가질 수 있는데, 이것이 설정된 경우 소스의 매개변수들이 새로운 매개변수들로 치환된 명령어들을 만들게 된다.
[18]:
p = Parameter('p')
qc = QuantumCircuit(3, name='oracle')
qc.rz(p, 0)
qc.cx(0, 1)
qc.rz(p, 1)
qc.cx(1, 2)
qc.rz(p, 2)
theta = Parameter('theta')
phi = Parameter('phi')
gamma = Parameter('gamma')
qr = QuantumRegister(9)
larger_qc = QuantumCircuit(qr)
larger_qc.append(qc.to_instruction({p: theta}), qr[0:3])
larger_qc.append(qc.to_instruction({p: phi}), qr[3:6])
larger_qc.append(qc.to_instruction({p: gamma}), qr[6:9])
print(larger_qc.draw())
print(larger_qc.decompose().draw())
┌────────────────┐
q24_0: ┤0 ├
│ │
q24_1: ┤1 oracle(theta) ├
│ │
q24_2: ┤2 ├
└┬──────────────┬┘
q24_3: ─┤0 ├─
│ │
q24_4: ─┤1 oracle(phi) ├─
│ │
q24_5: ─┤2 ├─
┌┴──────────────┴┐
q24_6: ┤0 ├
│ │
q24_7: ┤1 oracle(gamma) ├
│ │
q24_8: ┤2 ├
└────────────────┘
┌───────────┐
q24_0: ┤ Rz(theta) ├──■─────────────────────────────────
└───────────┘┌─┴─┐┌───────────┐
q24_1: ─────────────┤ X ├┤ Rz(theta) ├──■───────────────
└───┘└───────────┘┌─┴─┐┌───────────┐
q24_2: ───────────────────────────────┤ X ├┤ Rz(theta) ├
┌─────────┐ └───┘└───────────┘
q24_3: ─┤ Rz(phi) ├───■─────────────────────────────────
└─────────┘ ┌─┴─┐ ┌─────────┐
q24_4: ─────────────┤ X ├─┤ Rz(phi) ├───■───────────────
└───┘ └─────────┘ ┌─┴─┐ ┌─────────┐
q24_5: ───────────────────────────────┤ X ├─┤ Rz(phi) ├─
┌───────────┐ └───┘ └─────────┘
q24_6: ┤ Rz(gamma) ├──■─────────────────────────────────
└───────────┘┌─┴─┐┌───────────┐
q24_7: ─────────────┤ X ├┤ Rz(gamma) ├──■───────────────
└───┘└───────────┘┌─┴─┐┌───────────┐
q24_8: ───────────────────────────────┤ X ├┤ Rz(gamma) ├
└───┘└───────────┘
[19]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.19.0.dev0+be0ed5f |
qiskit-aer | 0.8.2 |
qiskit-ignis | 0.6.0 |
qiskit-ibmq-provider | 0.16.0.dev0+4e20edc |
System information | |
Python | 3.7.7 (default, May 6 2020, 04:59:01) [Clang 4.0.1 (tags/RELEASE_401/final)] |
OS | Darwin |
CPUs | 6 |
Memory (Gb) | 32.0 |
Sat Jul 31 01:02:16 2021 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.
[ ]: