注釈

当ページは tutorials/circuits_advanced/1_advanced_circuits.ipynb から生成されました。

高度な回路

[1]:
import numpy as np
from qiskit import *

抽象(Opaque) ゲート

[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         ├
                 └──────────┘

複合(Composite) ゲート

[4]:
# 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.u3(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()
[4]:
     ┌───┐
q_0: ┤ H ├──■────────────────────
     └───┘┌─┴─┐     ┌───────────┐
q_1: ─────┤ X ├──■──┤0          ├
          └───┘┌─┴─┐│  sub_circ │
q_2: ──────────┤ X ├┤1          ├
               └───┘└───────────┘

回路設計を高度抽象化するため、to_instruction での変換では、即座に分解された状態になりません。必要に応じて、コンパイル前に、サブ回路は decompose メソッドで分解することができます。

[5]:
decomposed_circ = circ.decompose() # Does not modify original circuit
decomposed_circ.draw()
[5]:
     ┌──────────┐
q_0: ┤ U2(0,pi) ├──■──────────────────────────────────────
     └──────────┘┌─┴─┐     ┌───┐          ░ ┌────────────┐
q_1: ────────────┤ X ├──■──┤ H ├────■─────░─┤ U3(1,2,-2) ├
                 └───┘┌─┴─┐└───┘┌───┴───┐ ░ └───┬───┬────┘
q_2: ─────────────────┤ X ├─────┤ RZ(1) ├─░─────┤ I ├─────
                      └───┘     └───────┘ ░     └───┘     

パラメータ化された回路

[6]:
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')
[6]:
../../_images/tutorials_circuits_advanced_1_advanced_circuits_10_0.png

回路パラメータを調べることが出来ます。

[7]:
print(qc.parameters)
{Parameter(θ)}

パラメータを値にバインド

全ての回路パラメータは回路をバックエンドに送る前にバインド(値の設定)される必要があります。これには2つの方法があります: bind_parameters メソッドは、Parameter を値にマップするディクショナリーを受け取り、各パラメータを対応する値に置き換えた新しい回路を返します。部分バインドもサポートされ、この場合、値にマップされなかった Parameter によるパラメータ化された回路がリターンされます。

[8]:
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()
[8]:
     ┌───┐                     ░ ┌─────────┐ ░                     ┌───┐┌─┐
q_0: ┤ H ├──■──────────────────░─┤ RZ(2pi) ├─░──────────────────■──┤ H ├┤M├
     └───┘┌─┴─┐                ░ ├─────────┤ ░                ┌─┴─┐└───┘└╥┘
q_1: ─────┤ X ├──■─────────────░─┤ RZ(2pi) ├─░─────────────■──┤ X ├──────╫─
          └───┘┌─┴─┐           ░ ├─────────┤ ░           ┌─┴─┐└───┘      ║
q_2: ──────────┤ X ├──■────────░─┤ RZ(2pi) ├─░────────■──┤ X ├───────────╫─
               └───┘┌─┴─┐      ░ ├─────────┤ ░      ┌─┴─┐└───┘           ║
q_3: ───────────────┤ X ├──■───░─┤ RZ(2pi) ├─░───■──┤ X ├────────────────╫─
                    └───┘┌─┴─┐ ░ ├─────────┤ ░ ┌─┴─┐└───┘                ║
q_4: ────────────────────┤ X ├─░─┤ RZ(2pi) ├─░─┤ X ├─────────────────────╫─
                         └───┘ ░ └─────────┘ ░ └───┘                     ║
c_0: ════════════════════════════════════════════════════════════════════╩═
                                                                           
  • qiskit.execute は、Parameter を値にマップしたディクショナリーのリストとして指定された parameter_binds キーワード引数を受け取り、リスト中のディクショナリーの全てのマッピングに対してバインドし、回路を実行します。

[9]:
job = execute(qc,
              backend=BasicAer.get_backend('qasm_simulator'),
              parameter_binds=[{theta: theta_val} for theta_val in theta_range])

counts = job.result().get_counts()

回路例では、5つの量子ビットエンタングル状態に対して、\(R_z(\theta)\) グローバル回転を適用し、量子ビット 0 で、\(5\theta\) の振動を期待しています。

[10]:
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)
[10]:
<matplotlib.legend.Legend at 0x11dce80a0>
../../_images/tutorials_circuits_advanced_1_advanced_circuits_19_1.png

コンパイルコストを減らす

バインドする前にパラメータ回路をコンパイルしておくと、特定のケースでは、バインドされた回路のセットをコンパイルするのに比べて大幅にコンパイル時間を減らすことができます。

[11]:
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:  8.771650075912476
[12]:
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:  0.8169369697570801

コンポジション

パラメータ回路は標準の QuantumCircuit (複数) と同様、合成できます。一般的に、2つのパラメータ回路を合成する時には、結果の回路は入力回路のパラメータの結合としてパラメータ化されます。

しかしながら、パラメータ名は与えられた回路でユニークである必要があります。ターゲットの回路にすでに存在しているパラメータを追加しようとする時: 仮にソースとターゲットが同じ Parameter インスタンスを共有する場合には、パラメータは同じと見なされ結合されます。もし、ソースとターゲットが異なる Parameter インスタンスの場合にはエラーとなります。

[13]:
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) を受け取り、ソースパラメータが存在する場合には、新しいパラメータに置き換える Instruction が生成されます。

[14]:
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())
      ┌────────────────┐
q1_0: ┤0               ├
      │                │
q1_1: ┤1 oracle(theta) ├
      │                │
q1_2: ┤2               ├
      └┬──────────────┬┘
q1_3: ─┤0             ├─
       │              │
q1_4: ─┤1 oracle(phi) ├─
       │              │
q1_5: ─┤2             ├─
      ┌┴──────────────┴┐
q1_6: ┤0               ├
      │                │
q1_7: ┤1 oracle(gamma) ├
      │                │
q1_8: ┤2               ├
      └────────────────┘
      ┌───────────┐
q1_0: ┤ RZ(theta) ├──■─────────────────────────────────
      └───────────┘┌─┴─┐┌───────────┐
q1_1: ─────────────┤ X ├┤ RZ(theta) ├──■───────────────
                   └───┘└───────────┘┌─┴─┐┌───────────┐
q1_2: ───────────────────────────────┤ X ├┤ RZ(theta) ├
       ┌─────────┐                   └───┘└───────────┘
q1_3: ─┤ RZ(phi) ├───■─────────────────────────────────
       └─────────┘ ┌─┴─┐ ┌─────────┐
q1_4: ─────────────┤ X ├─┤ RZ(phi) ├───■───────────────
                   └───┘ └─────────┘ ┌─┴─┐ ┌─────────┐
q1_5: ───────────────────────────────┤ X ├─┤ RZ(phi) ├─
      ┌───────────┐                  └───┘ └─────────┘
q1_6: ┤ RZ(gamma) ├──■─────────────────────────────────
      └───────────┘┌─┴─┐┌───────────┐
q1_7: ─────────────┤ X ├┤ RZ(gamma) ├──■───────────────
                   └───┘└───────────┘┌─┴─┐┌───────────┐
q1_8: ───────────────────────────────┤ X ├┤ RZ(gamma) ├
                                     └───┘└───────────┘
[15]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
QiskitNone
Terra0.15.0
Aer0.5.1
IgnisNone
AquaNone
IBM Q Provider0.7.0
System information
Python3.8.2 (default, Mar 26 2020, 10:43:30) [Clang 4.0.1 (tags/RELEASE_401/final)]
OSDarwin
CPUs4
Memory (Gb)16.0
Fri May 08 08:42:21 2020 EDT

This code is a part of Qiskit

© Copyright IBM 2017, 2020.

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.

[ ]: