mirror of https://github.com/Qiskit/qiskit.git
253 lines
8.6 KiB
Python
253 lines
8.6 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) 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.
|
|
|
|
"""Test QuantumCircuit.tensor()."""
|
|
|
|
import unittest
|
|
|
|
from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit, Parameter
|
|
from qiskit.circuit.exceptions import CircuitError
|
|
from qiskit.quantum_info import Operator
|
|
from test import QiskitTestCase # pylint: disable=wrong-import-order
|
|
|
|
|
|
class TestCircuitCompose(QiskitTestCase):
|
|
"""Test composition of two circuits."""
|
|
|
|
def test_unnamed_tensor(self):
|
|
"""Test composing on unnamed circuits."""
|
|
top = QuantumCircuit(1, 1)
|
|
top.x(0)
|
|
top.measure(0, 0)
|
|
|
|
bottom = QuantumCircuit(2)
|
|
bottom.y(0)
|
|
bottom.z(1)
|
|
|
|
expect = QuantumCircuit(3, 1)
|
|
expect.x(0)
|
|
expect.y(1)
|
|
expect.z(2)
|
|
expect.measure(0, 0)
|
|
|
|
with self.subTest("bottom.tensor(top)"):
|
|
self.assertEqual(bottom.tensor(top), expect)
|
|
|
|
expect = QuantumCircuit(3, 1)
|
|
expect.y(0)
|
|
expect.z(1)
|
|
expect.x(2)
|
|
expect.measure(2, 0)
|
|
|
|
with self.subTest("top.tensor(bottom)"):
|
|
self.assertEqual(top.tensor(bottom), expect)
|
|
|
|
def test_mixed(self):
|
|
"""Test composing on named and unnamed registers."""
|
|
qr = QuantumRegister(1, "my_qr")
|
|
cr = ClassicalRegister(1, "my_cr")
|
|
top = QuantumCircuit(qr, cr)
|
|
top.x(0)
|
|
top.measure(0, 0)
|
|
|
|
bottom = QuantumCircuit(2)
|
|
bottom.y(0)
|
|
bottom.z(1)
|
|
|
|
expect = QuantumCircuit(qr, *bottom.qregs, cr)
|
|
expect.x(0)
|
|
expect.y(1)
|
|
expect.z(2)
|
|
expect.measure(0, 0)
|
|
|
|
self.assertEqual(bottom.tensor(top), expect)
|
|
|
|
def test_named(self):
|
|
"""Test composing on named and unnamed registers."""
|
|
qr0 = QuantumRegister(1, "my_qr")
|
|
cr0 = ClassicalRegister(1, "my_cr")
|
|
top = QuantumCircuit(qr0, cr0)
|
|
top.x(0)
|
|
top.measure(0, 0)
|
|
|
|
qr1 = QuantumRegister(2, "my_qr")
|
|
bottom = QuantumCircuit(qr1)
|
|
bottom.y(0)
|
|
bottom.z(1)
|
|
|
|
with self.subTest("same name raises"):
|
|
with self.assertRaises(CircuitError):
|
|
_ = bottom.tensor(top)
|
|
|
|
qr1 = QuantumRegister(2, "other_qr")
|
|
bottom = QuantumCircuit(qr1)
|
|
bottom.y(0)
|
|
bottom.z(1)
|
|
|
|
expect = QuantumCircuit(qr0, qr1, cr0)
|
|
expect.x(0)
|
|
expect.y(1)
|
|
expect.z(2)
|
|
expect.measure(0, 0)
|
|
|
|
with self.subTest("assert circuit is correct"):
|
|
self.assertEqual(bottom.tensor(top), expect)
|
|
|
|
def test_measure_all(self):
|
|
"""Test ``tensor`` works if ``measure_all`` is called on both circuits."""
|
|
qr0 = QuantumRegister(1, "my_qr")
|
|
top = QuantumCircuit(qr0)
|
|
top.x(0)
|
|
top.measure_all()
|
|
|
|
qr1 = QuantumRegister(2, "other_qr")
|
|
bottom = QuantumCircuit(qr1)
|
|
bottom.y(0)
|
|
bottom.z(1)
|
|
bottom.measure_all()
|
|
|
|
cr = ClassicalRegister(3, "meas")
|
|
expect = QuantumCircuit(qr0, qr1, cr)
|
|
expect.x(0)
|
|
expect.y(1)
|
|
expect.z(2)
|
|
expect.barrier(0) # since barriers have been applied to the subcircuits
|
|
expect.barrier([1, 2])
|
|
expect.measure([0, 1, 2], [0, 1, 2])
|
|
|
|
self.assertEqual(bottom.tensor(top), expect)
|
|
|
|
def test_multiple_registers(self):
|
|
"""Test tensoring circuits with multiple registers."""
|
|
p, q = Parameter("p"), Parameter("q")
|
|
qrs = [QuantumRegister(1) for _ in range(6)]
|
|
crs = [ClassicalRegister(1) for _ in range(2)]
|
|
|
|
# ┌───┐
|
|
# q0: ┤ H ├───────■──────────────
|
|
# ├───┤┌───┐ │
|
|
# q1: ┤ X ├┤ H ├──■──────────────
|
|
# └───┘└───┘ │ ┌───────┐┌─┐
|
|
# q2: ────────────┼──┤ Ry(p) ├┤M├
|
|
# ┌─┴─┐└───┬───┘└╥┘
|
|
# q3: ──────────┤ X ├────■─────╫─
|
|
# └───┘ ║
|
|
# c0: 1/═══════════════════════╩═
|
|
# 0
|
|
top = QuantumCircuit(*qrs[:4], crs[0])
|
|
top.h(0)
|
|
top.x(1)
|
|
top.h(1)
|
|
top.ccx(0, 1, 3)
|
|
top.cry(p, 3, 2)
|
|
top.measure(2, 0)
|
|
|
|
# ┌────┐┌──────┐
|
|
# q4: ┤ √X ├┤ P(q) ├──■─────
|
|
# └────┘└──────┘┌─┴─┐┌─┐
|
|
# q5: ──────────────┤ X ├┤M├
|
|
# └───┘└╥┘
|
|
# c1: 1/══════════════════╩═
|
|
# 0
|
|
bottom = QuantumCircuit(*qrs[4:], crs[1])
|
|
bottom.sx(0)
|
|
bottom.p(q, 0)
|
|
bottom.cx(0, 1)
|
|
bottom.measure(1, 0)
|
|
|
|
# ┌───┐
|
|
# q0: ┤ H ├───────────■──────────────
|
|
# ├───┤ ┌───┐ │
|
|
# q1: ┤ X ├──┤ H ├────■──────────────
|
|
# └───┘ └───┘ │ ┌───────┐┌─┐
|
|
# q2: ────────────────┼──┤ Ry(p) ├┤M├
|
|
# ┌─┴─┐└───┬───┘└╥┘
|
|
# q3: ──────────────┤ X ├────■─────╫─
|
|
# ┌────┐┌──────┐└───┘ ║
|
|
# q4: ┤ √X ├┤ P(q) ├──■────────────╫─
|
|
# └────┘└──────┘┌─┴─┐ ┌─┐ ║
|
|
# q5: ──────────────┤ X ├───┤M├────╫─
|
|
# └───┘ └╥┘ ║
|
|
# c0: 1/═════════════════════╬═════╩═
|
|
# ║ 0
|
|
# c1: 1/═════════════════════╩═══════
|
|
# 0
|
|
expect = QuantumCircuit(*qrs, *crs)
|
|
expect.h(0)
|
|
expect.x(1)
|
|
expect.h(1)
|
|
expect.ccx(0, 1, 3)
|
|
expect.cry(p, 3, 2)
|
|
expect.measure(2, 0)
|
|
|
|
expect.sx(4)
|
|
expect.p(q, 4)
|
|
expect.cx(4, 5)
|
|
expect.measure(5, 1)
|
|
|
|
self.assertEqual(bottom.tensor(top), expect)
|
|
|
|
def test_consistent_with_quantum_info(self):
|
|
"""Test that the ordering is consistent with quantum_info's Operator."""
|
|
|
|
with self.subTest(msg="simple, single register example"):
|
|
x = QuantumCircuit(1)
|
|
x.x(0)
|
|
|
|
i = QuantumCircuit(1)
|
|
|
|
circuit = x.tensor(i)
|
|
operator = Operator(x).tensor(Operator(i))
|
|
|
|
self.assertEqual(Operator(circuit), operator)
|
|
|
|
with self.subTest(msg="multi register example"):
|
|
qrs = [QuantumRegister(1) for _ in range(6)]
|
|
|
|
top = QuantumCircuit(*qrs[:4])
|
|
top.h(0)
|
|
top.x(1)
|
|
top.h(1)
|
|
top.ccx(0, 1, 3)
|
|
top.cry(-1.2, 3, 2)
|
|
|
|
bottom = QuantumCircuit(*qrs[4:])
|
|
bottom.sx(0)
|
|
bottom.p(3.01, 0)
|
|
bottom.cx(0, 1)
|
|
|
|
circuit = bottom.tensor(top)
|
|
operator = Operator(bottom).tensor(Operator(top))
|
|
|
|
self.assertEqual(Operator(circuit), operator)
|
|
|
|
with self.subTest(msg="nested circuits"):
|
|
sub = QuantumCircuit(3)
|
|
sub.h(0)
|
|
sub.swap(0, 1)
|
|
sub.cx(1, 2)
|
|
sub.cx(2, 0)
|
|
|
|
larger = QuantumCircuit(4)
|
|
larger.h(range(3))
|
|
larger.append(sub.to_instruction(), [3, 2, 1])
|
|
larger.append(sub.control(), [0, 1, 2, 3])
|
|
|
|
circuit = larger.tensor(larger)
|
|
operator = Operator(larger).tensor(Operator(larger))
|
|
|
|
self.assertEqual(Operator(circuit), operator)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|