mirror of https://github.com/Qiskit/qiskit.git
481 lines
20 KiB
Python
481 lines
20 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) Copyright IBM 2017, 2024.
|
|
#
|
|
# 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.
|
|
|
|
"""Compiler Test."""
|
|
|
|
import os
|
|
import unittest
|
|
|
|
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
|
|
from qiskit.transpiler import PassManager, CouplingMap
|
|
from qiskit.circuit.library import U1Gate, U2Gate
|
|
from qiskit.compiler import transpile
|
|
from qiskit.providers.basic_provider import BasicSimulator
|
|
from qiskit.qasm2 import dumps
|
|
from test import QiskitTestCase # pylint: disable=wrong-import-order
|
|
|
|
|
|
class TestCompiler(QiskitTestCase):
|
|
"""Qiskit Compiler Tests."""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.seed_simulator = 42
|
|
self.backend = BasicSimulator()
|
|
|
|
def test_example_multiple_compile(self):
|
|
"""Test a toy example compiling multiple circuits.
|
|
|
|
Pass if the results are correct.
|
|
"""
|
|
backend = BasicSimulator()
|
|
coupling_map = [[0, 1], [0, 2], [1, 2], [3, 2], [3, 4], [4, 2]]
|
|
|
|
qr = QuantumRegister(5)
|
|
cr = ClassicalRegister(5)
|
|
bell = QuantumCircuit(qr, cr)
|
|
ghz = QuantumCircuit(qr, cr)
|
|
# Create a GHZ state
|
|
ghz.h(qr[0])
|
|
for i in range(4):
|
|
ghz.cx(qr[i], qr[i + 1])
|
|
# Insert a barrier before measurement
|
|
ghz.barrier()
|
|
# Measure all of the qubits in the standard basis
|
|
for i in range(5):
|
|
ghz.measure(qr[i], cr[i])
|
|
# Create a Bell state
|
|
bell.h(qr[0])
|
|
bell.cx(qr[0], qr[1])
|
|
bell.barrier()
|
|
bell.measure(qr[0], cr[0])
|
|
bell.measure(qr[1], cr[1])
|
|
shots = 2048
|
|
bell_qcirc = transpile(bell, backend=backend)
|
|
ghz_qcirc = transpile(ghz, backend=backend, coupling_map=coupling_map)
|
|
bell_result = backend.run(bell_qcirc, shots=shots, seed_simulator=10).result()
|
|
ghz_result = backend.run(ghz_qcirc, shots=shots, seed_simulator=10).result()
|
|
|
|
threshold = 0.05 * shots
|
|
counts_bell = bell_result.get_counts()
|
|
target_bell = {"00000": shots / 2, "00011": shots / 2}
|
|
self.assertDictAlmostEqual(counts_bell, target_bell, threshold)
|
|
|
|
counts_ghz = ghz_result.get_counts()
|
|
target_ghz = {"00000": shots / 2, "11111": shots / 2}
|
|
self.assertDictAlmostEqual(counts_ghz, target_ghz, threshold)
|
|
|
|
def test_compile_coupling_map(self):
|
|
"""Test compile_coupling_map.
|
|
If all correct should return data with the same stats. The circuit may
|
|
be different.
|
|
"""
|
|
backend = BasicSimulator()
|
|
|
|
qr = QuantumRegister(3, "qr")
|
|
cr = ClassicalRegister(3, "cr")
|
|
qc = QuantumCircuit(qr, cr, name="qccccccc")
|
|
qc.h(qr[0])
|
|
qc.cx(qr[0], qr[1])
|
|
qc.cx(qr[0], qr[2])
|
|
qc.measure(qr[0], cr[0])
|
|
qc.measure(qr[1], cr[1])
|
|
qc.measure(qr[2], cr[2])
|
|
shots = 2048
|
|
coupling_map = [[0, 1], [1, 2]]
|
|
initial_layout = [0, 1, 2]
|
|
qc_b = transpile(
|
|
qc, backend=backend, coupling_map=coupling_map, initial_layout=initial_layout
|
|
)
|
|
job = backend.run(qc_b, shots=shots, seed_simulator=88)
|
|
result = job.result()
|
|
qasm_to_check = dumps(qc)
|
|
self.assertEqual(len(qasm_to_check), 172)
|
|
|
|
counts = result.get_counts(qc)
|
|
target = {"000": shots / 2, "111": shots / 2}
|
|
threshold = 0.05 * shots
|
|
self.assertDictAlmostEqual(counts, target, threshold)
|
|
|
|
def test_example_swap_bits(self):
|
|
"""Test a toy example swapping a set bit around.
|
|
|
|
Uses the mapper. Pass if results are correct.
|
|
"""
|
|
backend = BasicSimulator()
|
|
coupling_map = [
|
|
[0, 1],
|
|
[0, 8],
|
|
[1, 2],
|
|
[1, 9],
|
|
[2, 3],
|
|
[2, 10],
|
|
[3, 4],
|
|
[3, 11],
|
|
[4, 5],
|
|
[4, 12],
|
|
[5, 6],
|
|
[5, 13],
|
|
[6, 7],
|
|
[6, 14],
|
|
[7, 15],
|
|
[8, 9],
|
|
[9, 10],
|
|
[10, 11],
|
|
[11, 12],
|
|
[12, 13],
|
|
[13, 14],
|
|
[14, 15],
|
|
]
|
|
|
|
# ┌───┐ ░ ┌─┐
|
|
# q0_0: ┤ X ├─X───────────░─┤M├───────────────
|
|
# └───┘ │ ░ └╥┘ ┌─┐
|
|
# q0_1: ──────┼─────X──X──░──╫────┤M├─────────
|
|
# │ │ │ ░ ║ └╥┘ ┌─┐
|
|
# q0_2: ──────X──X──┼──┼──░──╫─────╫────┤M├───
|
|
# │ │ │ ░ ║ ┌─┐ ║ └╥┘
|
|
# q1_0: ─────────┼──┼──┼──░──╫─┤M├─╫─────╫────
|
|
# │ │ │ ░ ║ └╥┘ ║ ┌─┐ ║
|
|
# q1_1: ─────────┼──┼──X──░──╫──╫──╫─┤M├─╫────
|
|
# │ │ ░ ║ ║ ║ └╥┘ ║ ┌─┐
|
|
# q1_2: ─────────X──X─────░──╫──╫──╫──╫──╫─┤M├
|
|
# ░ ║ ║ ║ ║ ║ └╥┘
|
|
# c0: 6/═════════════════════╩══╩══╩══╩══╩══╩═
|
|
# 0 3 1 4 2 5
|
|
n = 3 # make this at least 3
|
|
qr0 = QuantumRegister(n)
|
|
qr1 = QuantumRegister(n)
|
|
ans = ClassicalRegister(2 * n)
|
|
qc = QuantumCircuit(qr0, qr1, ans)
|
|
# Set the first bit of qr0
|
|
qc.x(qr0[0])
|
|
# Swap the set bit
|
|
qc.swap(qr0[0], qr0[n - 1])
|
|
qc.swap(qr0[n - 1], qr1[n - 1])
|
|
qc.swap(qr1[n - 1], qr0[1])
|
|
qc.swap(qr0[1], qr1[1])
|
|
# Insert a barrier before measurement
|
|
qc.barrier()
|
|
# Measure all of the qubits in the standard basis
|
|
for j in range(n):
|
|
qc.measure(qr0[j], ans[j])
|
|
qc.measure(qr1[j], ans[j + n])
|
|
# First version: no mapping
|
|
result = backend.run(
|
|
transpile(qc, backend, coupling_map=None), shots=1024, seed_simulator=14
|
|
).result()
|
|
self.assertEqual(result.get_counts(qc), {"010000": 1024})
|
|
# Second version: map to coupling graph
|
|
result = backend.run(
|
|
transpile(qc, backend, coupling_map=coupling_map),
|
|
shots=1024,
|
|
seed_simulator=14,
|
|
).result()
|
|
self.assertEqual(result.get_counts(qc), {"010000": 1024})
|
|
|
|
def test_no_conflict_backend_passmanager(self):
|
|
"""See: https://github.com/Qiskit/qiskit-terra/issues/5037"""
|
|
backend = BasicSimulator()
|
|
qc = QuantumCircuit(2)
|
|
qc.append(U1Gate(0), [0])
|
|
qc.measure_all()
|
|
job = backend.run(PassManager().run(qc))
|
|
result = job.result().get_counts()
|
|
self.assertEqual(result, {"00": 1024})
|
|
|
|
def test_compile_single_qubit(self):
|
|
"""Compile a single-qubit circuit in a non-trivial layout"""
|
|
qr = QuantumRegister(1, "qr")
|
|
circuit = QuantumCircuit(qr)
|
|
circuit.h(qr[0])
|
|
layout = {qr[0]: 12}
|
|
cmap = [
|
|
[1, 0],
|
|
[1, 2],
|
|
[2, 3],
|
|
[4, 3],
|
|
[4, 10],
|
|
[5, 4],
|
|
[5, 6],
|
|
[5, 9],
|
|
[6, 8],
|
|
[7, 8],
|
|
[9, 8],
|
|
[9, 10],
|
|
[11, 3],
|
|
[11, 10],
|
|
[11, 12],
|
|
[12, 2],
|
|
[13, 1],
|
|
[13, 12],
|
|
]
|
|
|
|
circuit2 = transpile(
|
|
circuit, backend=None, coupling_map=cmap, basis_gates=["u2"], initial_layout=layout
|
|
)
|
|
|
|
compiled_instruction = circuit2.data[0]
|
|
|
|
self.assertEqual(compiled_instruction.name, "u2")
|
|
self.assertEqual(circuit2.find_bit(compiled_instruction.qubits[0]).index, 12)
|
|
self.assertEqual(compiled_instruction.params, [0, 3.141592653589793])
|
|
|
|
def test_compile_pass_manager(self):
|
|
"""Test compile with and without an empty pass manager."""
|
|
qr = QuantumRegister(2)
|
|
cr = ClassicalRegister(2)
|
|
qc = QuantumCircuit(qr, cr)
|
|
qc.append(U1Gate(3.14), [qr[0]])
|
|
qc.append(U2Gate(3.14, 1.57), [qr[0]])
|
|
qc.barrier(qr)
|
|
qc.measure(qr, cr)
|
|
backend = BasicSimulator()
|
|
qrtrue = transpile(qc, backend, seed_transpiler=8)
|
|
rtrue = backend.run(qrtrue, seed_simulator=42).result()
|
|
qrfalse = PassManager().run(qc)
|
|
rfalse = backend.run(qrfalse, seed_simulator=42).result()
|
|
self.assertEqual(rtrue.get_counts(), rfalse.get_counts())
|
|
|
|
def test_mapper_overoptimization(self):
|
|
"""Check mapper overoptimization.
|
|
|
|
The mapper should not change the semantics of the input.
|
|
An overoptimization introduced issue #81:
|
|
https://github.com/Qiskit/qiskit-terra/issues/81
|
|
"""
|
|
# ┌───┐ ┌─┐
|
|
# q0_0: ┤ X ├──■───────┤M├───────────
|
|
# ├───┤┌─┴─┐┌───┐└╥┘ ┌─┐
|
|
# q0_1: ┤ Y ├┤ X ├┤ S ├─╫───■──┤M├───
|
|
# ├───┤└───┘├───┤ ║ ┌─┴─┐└╥┘┌─┐
|
|
# q0_2: ┤ Z ├──■──┤ T ├─╫─┤ X ├─╫─┤M├
|
|
# └───┘┌─┴─┐├───┤ ║ └┬─┬┘ ║ └╥┘
|
|
# q0_3: ─────┤ X ├┤ H ├─╫──┤M├──╫──╫─
|
|
# └───┘└───┘ ║ └╥┘ ║ ║
|
|
# c0: 4/════════════════╩═══╩═══╩══╩═
|
|
# 0 3 1 2
|
|
qr = QuantumRegister(4)
|
|
cr = ClassicalRegister(4)
|
|
circ = QuantumCircuit(qr, cr)
|
|
circ.x(qr[0])
|
|
circ.y(qr[1])
|
|
circ.z(qr[2])
|
|
circ.cx(qr[0], qr[1])
|
|
circ.cx(qr[2], qr[3])
|
|
circ.s(qr[1])
|
|
circ.t(qr[2])
|
|
circ.h(qr[3])
|
|
circ.cx(qr[1], qr[2])
|
|
circ.measure(qr[0], cr[0])
|
|
circ.measure(qr[1], cr[1])
|
|
circ.measure(qr[2], cr[2])
|
|
circ.measure(qr[3], cr[3])
|
|
|
|
coupling_map = [[0, 2], [1, 2], [2, 3]]
|
|
shots = 1000
|
|
|
|
result1 = self.backend.run(
|
|
transpile(circ, backend=self.backend, coupling_map=coupling_map, seed_transpiler=8),
|
|
seed_simulator=self.seed_simulator,
|
|
shots=shots,
|
|
)
|
|
count1 = result1.result().get_counts()
|
|
result2 = self.backend.run(
|
|
transpile(
|
|
circ,
|
|
backend=self.backend,
|
|
coupling_map=None,
|
|
seed_transpiler=8,
|
|
),
|
|
seed_simulator=self.seed_simulator,
|
|
shots=shots,
|
|
)
|
|
count2 = result2.result().get_counts()
|
|
self.assertDictAlmostEqual(count1, count2, shots * 0.02)
|
|
|
|
def test_grovers_circuit(self):
|
|
"""Testing a circuit originated in the Grover algorithm"""
|
|
shots = 1000
|
|
coupling_map = None
|
|
|
|
# 6-qubit grovers
|
|
#
|
|
# ┌───┐┌───┐ ┌───┐┌───┐ ┌───┐ ┌───┐┌───┐ ░ ┌─┐
|
|
# q0_0: ┤ H ├┤ X ├──■──┤ X ├┤ X ├──■──┤ X ├──■──┤ X ├┤ H ├──────░─┤M├───
|
|
# ├───┤└───┘ │ └───┘└───┘ │ ├───┤ │ ├───┤├───┤ ░ └╥┘┌─┐
|
|
# q0_1: ┤ H ├──■────┼─────────■────┼──┤ X ├──■──┤ X ├┤ H ├──────░──╫─┤M├
|
|
# ├───┤ │ ┌─┴─┐ │ ┌─┴─┐└───┘ │ └───┘└───┘ ░ ║ └╥┘
|
|
# q0_2: ┤ X ├──┼──┤ X ├──■────┼──┤ X ├───────┼──────────────────░──╫──╫─
|
|
# ├───┤┌─┴─┐└───┘ │ ┌─┴─┐└───┘ │ ░ ║ ║
|
|
# q0_3: ┤ X ├┤ X ├───────■──┤ X ├────────────┼──────────────────░──╫──╫─
|
|
# └───┘└───┘ ┌─┴─┐├───┤┌───┐ ┌─┴─┐┌───┐┌───┐┌───┐ ░ ║ ║
|
|
# q0_4: ───────────────┤ X ├┤ X ├┤ H ├─────┤ X ├┤ H ├┤ X ├┤ H ├─░──╫──╫─
|
|
# └───┘└───┘└───┘ └───┘└───┘└───┘└───┘ ░ ║ ║
|
|
# q0_5: ────────────────────────────────────────────────────────░──╫──╫─
|
|
# ░ ║ ║
|
|
# c0: 2/═══════════════════════════════════════════════════════════╩══╩═
|
|
# 0 1
|
|
qr = QuantumRegister(6)
|
|
cr = ClassicalRegister(2)
|
|
circuit = QuantumCircuit(qr, cr, name="grovers")
|
|
|
|
circuit.h(qr[0])
|
|
circuit.h(qr[1])
|
|
circuit.x(qr[2])
|
|
circuit.x(qr[3])
|
|
circuit.x(qr[0])
|
|
circuit.cx(qr[0], qr[2])
|
|
circuit.x(qr[0])
|
|
circuit.cx(qr[1], qr[3])
|
|
circuit.ccx(qr[2], qr[3], qr[4])
|
|
circuit.cx(qr[1], qr[3])
|
|
circuit.x(qr[0])
|
|
circuit.cx(qr[0], qr[2])
|
|
circuit.x(qr[0])
|
|
circuit.x(qr[1])
|
|
circuit.x(qr[4])
|
|
circuit.h(qr[4])
|
|
circuit.ccx(qr[0], qr[1], qr[4])
|
|
circuit.h(qr[4])
|
|
circuit.x(qr[0])
|
|
circuit.x(qr[1])
|
|
circuit.x(qr[4])
|
|
circuit.h(qr[0])
|
|
circuit.h(qr[1])
|
|
circuit.h(qr[4])
|
|
circuit.barrier(qr)
|
|
circuit.measure(qr[0], cr[0])
|
|
circuit.measure(qr[1], cr[1])
|
|
|
|
result = self.backend.run(
|
|
transpile(
|
|
circuit,
|
|
self.backend,
|
|
coupling_map=coupling_map,
|
|
),
|
|
seed_simulator=self.seed_simulator,
|
|
shots=shots,
|
|
)
|
|
counts = result.result().get_counts()
|
|
|
|
expected_probs = {"00": 0.64, "01": 0.117, "10": 0.113, "11": 0.13}
|
|
|
|
target = {key: shots * val for key, val in expected_probs.items()}
|
|
threshold = 0.04 * shots
|
|
self.assertDictAlmostEqual(counts, target, threshold)
|
|
|
|
def test_math_domain_error(self):
|
|
"""Check for floating point errors.
|
|
|
|
The math library operates over floats and introduces floating point
|
|
errors that should be avoided.
|
|
See: https://github.com/Qiskit/qiskit-terra/issues/111
|
|
"""
|
|
# ┌───┐┌───┐ ┌─┐
|
|
# q0_0: ┤ Y ├┤ X ├─────┤M├─────────────────────
|
|
# └───┘└─┬─┘ └╥┘ ┌─┐
|
|
# q0_1: ───────■────────╫─────────────■──┤M├───
|
|
# ┌───┐┌───┐┌───┐ ║ ┌───┐┌───┐┌─┴─┐└╥┘┌─┐
|
|
# q0_2: ┤ Z ├┤ H ├┤ Y ├─╫─┤ T ├┤ Z ├┤ X ├─╫─┤M├
|
|
# └┬─┬┘└───┘└───┘ ║ └───┘└───┘└───┘ ║ └╥┘
|
|
# q0_3: ─┤M├────────────╫─────────────────╫──╫─
|
|
# └╥┘ ║ ║ ║
|
|
# c0: 4/══╩═════════════╩═════════════════╩══╩═
|
|
# 3 0 1 2
|
|
qr = QuantumRegister(4)
|
|
cr = ClassicalRegister(4)
|
|
circ = QuantumCircuit(qr, cr)
|
|
circ.y(qr[0])
|
|
circ.z(qr[2])
|
|
circ.h(qr[2])
|
|
circ.cx(qr[1], qr[0])
|
|
circ.y(qr[2])
|
|
circ.t(qr[2])
|
|
circ.z(qr[2])
|
|
circ.cx(qr[1], qr[2])
|
|
circ.measure(qr[0], cr[0])
|
|
circ.measure(qr[1], cr[1])
|
|
circ.measure(qr[2], cr[2])
|
|
circ.measure(qr[3], cr[3])
|
|
|
|
coupling_map = [[0, 2], [1, 2], [2, 3]]
|
|
shots = 2000
|
|
job = self.backend.run(
|
|
transpile(
|
|
circ,
|
|
backend=self.backend,
|
|
coupling_map=coupling_map,
|
|
),
|
|
seed_simulator=self.seed_simulator,
|
|
shots=shots,
|
|
)
|
|
counts = job.result().get_counts()
|
|
target = {"0001": shots / 2, "0101": shots / 2}
|
|
threshold = 0.04 * shots
|
|
self.assertDictAlmostEqual(counts, target, threshold)
|
|
|
|
def test_random_parameter_circuit(self):
|
|
"""Run a circuit with randomly generated parameters."""
|
|
qasm_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "qasm")
|
|
circ = QuantumCircuit.from_qasm_file(os.path.join(qasm_dir, "random_n5_d5.qasm"))
|
|
coupling_map = CouplingMap([[0, 1], [1, 2], [2, 3], [3, 4]])
|
|
coupling_map.make_symmetric()
|
|
shots = 1024
|
|
qobj = self.backend.run(
|
|
transpile(circ, backend=self.backend, coupling_map=coupling_map, seed_transpiler=42),
|
|
shots=shots,
|
|
seed_simulator=self.seed_simulator,
|
|
)
|
|
counts = qobj.result().get_counts()
|
|
expected_probs = {
|
|
"00000": 0.079239867254200971,
|
|
"00001": 0.032859032998526903,
|
|
"00010": 0.10752610993531816,
|
|
"00011": 0.018818532050952699,
|
|
"00100": 0.054830807251011054,
|
|
"00101": 0.0034141983951965164,
|
|
"00110": 0.041649309748902276,
|
|
"00111": 0.039967731207338125,
|
|
"01000": 0.10516937819949743,
|
|
"01001": 0.026635620063700002,
|
|
"01010": 0.0053475143548793866,
|
|
"01011": 0.01940513314416064,
|
|
"01100": 0.0044028405481225047,
|
|
"01101": 0.057524760052126644,
|
|
"01110": 0.010795354134597078,
|
|
"01111": 0.026491296821535528,
|
|
"10000": 0.094827455395274859,
|
|
"10001": 0.0008373965072688836,
|
|
"10010": 0.029082297894094441,
|
|
"10011": 0.012386622870598416,
|
|
"10100": 0.018739140061148799,
|
|
"10101": 0.01367656456536896,
|
|
"10110": 0.039184170706009248,
|
|
"10111": 0.062339335178438288,
|
|
"11000": 0.00293674365989009,
|
|
"11001": 0.012848433960739968,
|
|
"11010": 0.018472497159499782,
|
|
"11011": 0.0088903691234912003,
|
|
"11100": 0.031305389080034329,
|
|
"11101": 0.0004788556283690458,
|
|
"11110": 0.002232419390471667,
|
|
"11111": 0.017684822659235985,
|
|
}
|
|
target = {key: shots * val for key, val in expected_probs.items()}
|
|
threshold = 0.04 * shots
|
|
self.assertDictAlmostEqual(counts, target, threshold)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|