mirror of https://github.com/Qiskit/qiskit.git
147 lines
5.3 KiB
Python
147 lines
5.3 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) Copyright IBM 2017, 2023.
|
|
#
|
|
# 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.
|
|
|
|
"""Randomized tests of quantum synthesis."""
|
|
import unittest
|
|
from test.python.synthesis.test_synthesis import CheckDecompositions
|
|
from hypothesis import given, strategies, settings
|
|
import numpy as np
|
|
|
|
from qiskit.circuit import QuantumCircuit, QuantumRegister
|
|
from qiskit.circuit.library import UnitaryGate
|
|
from qiskit.quantum_info import Operator
|
|
from qiskit.quantum_info.random import random_unitary
|
|
from qiskit.synthesis.two_qubit.two_qubit_decompose import (
|
|
two_qubit_cnot_decompose,
|
|
TwoQubitBasisDecomposer,
|
|
)
|
|
from qiskit._accelerate.two_qubit_decompose import Ud
|
|
|
|
|
|
class TestSynthesis(CheckDecompositions):
|
|
"""Test synthesis"""
|
|
|
|
seed = strategies.integers(min_value=0, max_value=2**32 - 1)
|
|
rotation = strategies.floats(min_value=-np.pi * 10, max_value=np.pi * 10)
|
|
|
|
@given(seed)
|
|
def test_1q_random(self, seed):
|
|
"""Checks one qubit decompositions"""
|
|
unitary = random_unitary(2, seed=seed)
|
|
self.check_one_qubit_euler_angles(unitary)
|
|
self.check_one_qubit_euler_angles(unitary, "U3")
|
|
self.check_one_qubit_euler_angles(unitary, "U1X")
|
|
self.check_one_qubit_euler_angles(unitary, "PSX")
|
|
self.check_one_qubit_euler_angles(unitary, "ZSX")
|
|
self.check_one_qubit_euler_angles(unitary, "ZYZ")
|
|
self.check_one_qubit_euler_angles(unitary, "ZXZ")
|
|
self.check_one_qubit_euler_angles(unitary, "XYX")
|
|
self.check_one_qubit_euler_angles(unitary, "RR")
|
|
|
|
@settings(deadline=None)
|
|
@given(seed)
|
|
def test_2q_random(self, seed):
|
|
"""Checks two qubit decompositions"""
|
|
unitary = random_unitary(4, seed=seed)
|
|
self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose)
|
|
|
|
@given(strategies.tuples(*[seed] * 5))
|
|
def test_exact_supercontrolled_decompose_random(self, seeds):
|
|
"""Exact decomposition for random supercontrolled basis and random target"""
|
|
k1 = np.kron(random_unitary(2, seed=seeds[0]).data, random_unitary(2, seed=seeds[1]).data)
|
|
k2 = np.kron(random_unitary(2, seed=seeds[2]).data, random_unitary(2, seed=seeds[3]).data)
|
|
basis_unitary = k1 @ Ud(np.pi / 4, 0, 0) @ k2
|
|
decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary))
|
|
self.check_exact_decomposition(random_unitary(4, seed=seeds[4]).data, decomposer)
|
|
|
|
@given(strategies.tuples(*[rotation] * 6))
|
|
def test_cx_equivalence_0cx_random(self, rnd):
|
|
"""Check random circuits with 0 cx gates locally equivalent to identity."""
|
|
qr = QuantumRegister(2, name="q")
|
|
qc = QuantumCircuit(qr)
|
|
|
|
qc.u(rnd[0], rnd[1], rnd[2], qr[0])
|
|
qc.u(rnd[3], rnd[4], rnd[5], qr[1])
|
|
|
|
unitary = Operator(qc)
|
|
self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0)
|
|
|
|
@given(strategies.tuples(*[rotation] * 12))
|
|
def test_cx_equivalence_1cx_random(self, rnd):
|
|
"""Check random circuits with 1 cx gates locally equivalent to a cx."""
|
|
qr = QuantumRegister(2, name="q")
|
|
qc = QuantumCircuit(qr)
|
|
|
|
qc.u(rnd[0], rnd[1], rnd[2], qr[0])
|
|
qc.u(rnd[3], rnd[4], rnd[5], qr[1])
|
|
|
|
qc.cx(qr[1], qr[0])
|
|
|
|
qc.u(rnd[6], rnd[7], rnd[8], qr[0])
|
|
qc.u(rnd[9], rnd[10], rnd[11], qr[1])
|
|
|
|
unitary = Operator(qc)
|
|
self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1)
|
|
|
|
@given(strategies.tuples(*[rotation] * 18))
|
|
def test_cx_equivalence_2cx_random(self, rnd):
|
|
"""Check random circuits with 2 cx gates locally equivalent to some circuit with 2 cx."""
|
|
qr = QuantumRegister(2, name="q")
|
|
qc = QuantumCircuit(qr)
|
|
|
|
qc.u(rnd[0], rnd[1], rnd[2], qr[0])
|
|
qc.u(rnd[3], rnd[4], rnd[5], qr[1])
|
|
|
|
qc.cx(qr[1], qr[0])
|
|
|
|
qc.u(rnd[6], rnd[7], rnd[8], qr[0])
|
|
qc.u(rnd[9], rnd[10], rnd[11], qr[1])
|
|
|
|
qc.cx(qr[0], qr[1])
|
|
|
|
qc.u(rnd[12], rnd[13], rnd[14], qr[0])
|
|
qc.u(rnd[15], rnd[16], rnd[17], qr[1])
|
|
|
|
unitary = Operator(qc)
|
|
self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2)
|
|
|
|
@given(strategies.tuples(*[rotation] * 24))
|
|
def test_cx_equivalence_3cx_random(self, rnd):
|
|
"""Check random circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions."""
|
|
qr = QuantumRegister(2, name="q")
|
|
qc = QuantumCircuit(qr)
|
|
|
|
qc.u(rnd[0], rnd[1], rnd[2], qr[0])
|
|
qc.u(rnd[3], rnd[4], rnd[5], qr[1])
|
|
|
|
qc.cx(qr[1], qr[0])
|
|
|
|
qc.u(rnd[6], rnd[7], rnd[8], qr[0])
|
|
qc.u(rnd[9], rnd[10], rnd[11], qr[1])
|
|
|
|
qc.cx(qr[0], qr[1])
|
|
|
|
qc.u(rnd[12], rnd[13], rnd[14], qr[0])
|
|
qc.u(rnd[15], rnd[16], rnd[17], qr[1])
|
|
|
|
qc.cx(qr[1], qr[0])
|
|
|
|
qc.u(rnd[18], rnd[19], rnd[20], qr[0])
|
|
qc.u(rnd[21], rnd[22], rnd[23], qr[1])
|
|
|
|
unitary = Operator(qc)
|
|
self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|