qiskit/test/randomized/test_synthesis.py

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