# 高度な回路¶

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

[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]:


[7]:

print(qc.parameters)

{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()



[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>


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

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

[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 (複数) と同様、合成できます。一般的に、２つのパラメータ回路を合成する時には、結果の回路は入力回路のパラメータの結合としてパラメータ化されます。

しかしながら、パラメータ名は与えられた回路でユニークである必要があります。ターゲットの回路にすでに存在しているパラメータを追加しようとする時: 仮にソースとターゲットが同じ 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           ├──────────────
└────────────┘


[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.

[ ]: