Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simplify of U3->U1/U2 in OneQubitEulerDecomposer #5554

Merged
merged 63 commits into from
Feb 19, 2021
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
42a5c46
U3 to U2, U1 and U to P-Sx-P, P
enavarro51 Dec 17, 2020
2103dc4
Refine U3 and U reductions
enavarro51 Dec 18, 2020
6457473
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Dec 20, 2020
915e2d7
Move to U31 and U32 bases
enavarro51 Dec 21, 2020
1f6b6ea
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Dec 21, 2020
17a9fad
Further testing and cleanup
enavarro51 Dec 21, 2020
bc2993f
Interim reset/delay testing
enavarro51 Dec 23, 2020
4588706
Optimize bypass delay and snapshot, update reset
enavarro51 Dec 24, 2020
e7e2241
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Dec 24, 2020
733cb67
Set opt 1 to use 1qGates and opt 2 and 3 to 1qGatesDecomp only
enavarro51 Dec 24, 2020
bbc5c76
Unused imports
enavarro51 Dec 24, 2020
1753375
Allow zeroed U3s
enavarro51 Dec 24, 2020
b633c8c
Do filter_fn check and simplify O1QD
enavarro51 Jan 3, 2021
f81b36c
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 3, 2021
18fcb27
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 5, 2021
4e7ff22
Merge master and fix conflict
enavarro51 Jan 7, 2021
eb1b109
Merge master and fix conflict
enavarro51 Jan 12, 2021
0de5d83
Add u3_only and update tests
enavarro51 Jan 14, 2021
a6ca819
Put u3_only in all OneQubitEulerDecomposition tests
enavarro51 Jan 14, 2021
9adc3f2
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 14, 2021
4210a55
Fix lint
enavarro51 Jan 14, 2021
7579947
Fix lint2
enavarro51 Jan 14, 2021
4bd8482
Finalize optimize choice and additional u3_only
enavarro51 Jan 15, 2021
2df014f
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 15, 2021
a45544d
Use U321 and circuit_u321 instead of u3_only kwarg
enavarro51 Jan 19, 2021
d06620e
Merge branch 'optimize_1q_gates_5468_5531' of https://github.com/enav…
enavarro51 Jan 19, 2021
b54947d
Change U321 to include u2 and u1
enavarro51 Jan 21, 2021
6fb08df
Use Optimize1qGatesDecomposition only and fix bug and tests
enavarro51 Jan 22, 2021
8e30152
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 22, 2021
a877407
Fix lint and test_optimize_to_nothing
enavarro51 Jan 22, 2021
e400f84
Fix optimize_to_nothing
enavarro51 Jan 22, 2021
2e604e0
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 23, 2021
b5036da
Fix tests
enavarro51 Jan 23, 2021
8953b59
Try test_isometry
enavarro51 Jan 23, 2021
ad2b56f
Fix test_isometry with seed
enavarro51 Jan 25, 2021
0a1ad3f
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 25, 2021
eabed24
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 26, 2021
7b9bade
Release note
enavarro51 Jan 31, 2021
0ccebb5
Lint
enavarro51 Jan 31, 2021
0fe0995
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 31, 2021
1d70fb3
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Jan 31, 2021
8a8b82b
Fix test_isometry with rtol in one_qubit_decompose
enavarro51 Jan 31, 2021
457b1fa
Merge branch 'optimize_1q_gates_5468_5531' of https://github.com/enav…
enavarro51 Jan 31, 2021
d498b28
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 1, 2021
b61b709
Remove supersets and subsets from optimize_1q_decomp and clean up docs
enavarro51 Feb 2, 2021
06ac5eb
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 2, 2021
aeed31e
Reorder subset check for lint
enavarro51 Feb 2, 2021
c3defd8
Merge branch 'optimize_1q_gates_5468_5531' of https://github.com/enav…
enavarro51 Feb 2, 2021
badcf8c
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 2, 2021
de90252
Docs fix
enavarro51 Feb 2, 2021
2e026ab
Merge branch 'optimize_1q_gates_5468_5531' of https://github.com/enav…
enavarro51 Feb 2, 2021
0b9b78c
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 2, 2021
c3ebf07
Add single U3 in optimize_1q_decomp and adjust tests
enavarro51 Feb 4, 2021
7cd17cc
Merge branch 'optimize_1q_gates_5468_5531' of https://github.com/enav…
enavarro51 Feb 4, 2021
ddc8506
Change U3 docs and do copy in optimize_1q_decomp
enavarro51 Feb 9, 2021
344e5ef
Test whether ParameterExpression failures from collect_1q_runs
enavarro51 Feb 19, 2021
1bddfaa
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 19, 2021
4010838
Add name != u3 check
enavarro51 Feb 19, 2021
2894996
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 19, 2021
09f333f
Merge branch 'optimize_1q_gates_5468_5531' of https://github.com/enav…
enavarro51 Feb 19, 2021
b89a6b8
Fix ParameterExpression problem with U3 check
enavarro51 Feb 19, 2021
57f3802
Lint
enavarro51 Feb 19, 2021
27c0fc4
Merge branch 'master' into optimize_1q_gates_5468_5531
enavarro51 Feb 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions qiskit/quantum_info/synthesis/one_qubit_decompose.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@
import scipy.linalg as la

from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.circuit.library.standard_gates import (PhaseGate, U3Gate,
U1Gate, RXGate, RYGate,
from qiskit.circuit.library.standard_gates import (UGate, PhaseGate, U3Gate,
U2Gate, U1Gate, RXGate, RYGate,
RZGate, RGate, SXGate)
from qiskit.exceptions import QiskitError
from qiskit.quantum_info.operators.predicates import is_unitary_matrix

DEFAULT_ATOL = 1e-12

ONE_QUBIT_EULER_BASIS_GATES = {
# 'U321' must precede 'U3' in the list
kdk marked this conversation as resolved.
Show resolved Hide resolved
'U321': ['u3', 'u2', 'u1'],
'U3': ['u3'],
'U': ['u'],
'PSX': ['p', 'sx'],
Expand Down Expand Up @@ -156,6 +158,7 @@ def basis(self):
def basis(self, basis):
"""Set the decomposition basis."""
basis_methods = {
'U321': (self._params_u3, self._circuit_u321),
'U3': (self._params_u3, self._circuit_u3),
'U': (self._params_u3, self._circuit_u),
'PSX': (self._params_u1x, self._circuit_psx),
Expand Down Expand Up @@ -281,13 +284,12 @@ def _circuit_zxz(theta,
phi,
lam,
phase,
simplify=False,
simplify=True,
atol=DEFAULT_ATOL):
circuit = QuantumCircuit(1, global_phase=phase)
if simplify and np.isclose(theta, 0.0, atol=atol):
circuit = QuantumCircuit(1, global_phase=phase)
circuit.append(RZGate(phi + lam), [0])
return circuit
circuit = QuantumCircuit(1, global_phase=phase)
if not simplify or not np.isclose(lam, 0.0, atol=atol):
circuit.append(RZGate(lam), [0])
if not simplify or not np.isclose(theta, 0.0, atol=atol):
Expand Down Expand Up @@ -327,6 +329,23 @@ def _circuit_u3(theta,
circuit.append(U3Gate(theta, phi, lam), [0])
return circuit

@staticmethod
def _circuit_u321(theta,
phi,
lam,
phase,
simplify=True,
atol=DEFAULT_ATOL):
circuit = QuantumCircuit(1, global_phase=phase)
if simplify and (np.isclose(theta, 0.0, atol=atol)):
if not np.isclose(phi+lam, [0.0, 2*np.pi], atol=atol).any():
circuit.append(U1Gate(_mod2pi(phi+lam)), [0])
elif simplify and np.isclose(abs(theta), np.pi/2, atol=atol):
circuit.append(U2Gate(phi, lam), [0])
else:
circuit.append(U3Gate(theta, phi, lam), [0])
return circuit

@staticmethod
def _circuit_u(theta,
phi,
Expand All @@ -336,7 +355,7 @@ def _circuit_u(theta,
atol=DEFAULT_ATOL):
# pylint: disable=unused-argument
circuit = QuantumCircuit(1, global_phase=phase)
circuit.u(theta, phi, lam, 0)
circuit.append(UGate(theta, phi, lam), [0])
return circuit

@staticmethod
Expand Down
7 changes: 1 addition & 6 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
from qiskit.transpiler.passes import FixedPoint
from qiskit.transpiler.passes import Depth
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import Optimize1qGates
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes import ApplyLayout
from qiskit.transpiler.passes import CheckCXDirection
Expand Down Expand Up @@ -179,11 +178,7 @@ def _direction_condition(property_set):
def _opt_control(property_set):
return not property_set['depth_fixed_point']

if basis_gates and ('u1' in basis_gates or 'u2' in basis_gates or
'u3' in basis_gates):
_opt = [Optimize1qGates(basis_gates), CXCancellation()]
else:
_opt = [Optimize1qGatesDecomposition(basis_gates), CXCancellation()]
_opt = [Optimize1qGatesDecomposition(basis_gates), CXCancellation()]
kdk marked this conversation as resolved.
Show resolved Hide resolved

# 10. Schedule the circuit only when scheduling_method is supplied
if scheduling_method:
Expand Down
7 changes: 1 addition & 6 deletions qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
from qiskit.transpiler.passes import FixedPoint
from qiskit.transpiler.passes import Depth
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import Optimize1qGates
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes import CommutativeCancellation
from qiskit.transpiler.passes import ApplyLayout
Expand Down Expand Up @@ -175,11 +174,7 @@ def _direction_condition(property_set):
def _opt_control(property_set):
return not property_set['depth_fixed_point']

if basis_gates and ('u1' in basis_gates or 'u2' in basis_gates or
'u3' in basis_gates):
_opt = [Optimize1qGates(basis_gates), CommutativeCancellation()]
else:
_opt = [Optimize1qGatesDecomposition(basis_gates), CommutativeCancellation()]
_opt = [Optimize1qGatesDecomposition(basis_gates), CommutativeCancellation()]

# 9. Schedule the circuit only when scheduling_method is supplied
if scheduling_method:
Expand Down
25 changes: 7 additions & 18 deletions qiskit/transpiler/preset_passmanagers/level3.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
from qiskit.transpiler.passes import FixedPoint
from qiskit.transpiler.passes import Depth
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import Optimize1qGates
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes import CommutativeCancellation
from qiskit.transpiler.passes import OptimizeSwapBeforeMeasure
Expand Down Expand Up @@ -180,23 +179,13 @@ def _opt_control(property_set):

_meas = [OptimizeSwapBeforeMeasure(), RemoveDiagonalGatesBeforeMeasure()]

if basis_gates and ('u1' in basis_gates or 'u2' in basis_gates or
'u3' in basis_gates):
_opt = [
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates),
UnitarySynthesis(basis_gates),
Optimize1qGates(basis_gates),
CommutativeCancellation(),
]
else:
_opt = [
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates),
UnitarySynthesis(basis_gates),
Optimize1qGatesDecomposition(basis_gates),
CommutativeCancellation(),
]
_opt = [
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates),
UnitarySynthesis(basis_gates),
Optimize1qGatesDecomposition(basis_gates),
CommutativeCancellation(),
]

# Schedule the circuit only when scheduling_method is supplied
if scheduling_method:
Expand Down
13 changes: 8 additions & 5 deletions test/python/circuit/test_isometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,20 @@
from qiskit.quantum_info import Operator
from qiskit.extensions.quantum_initializer.isometry import Isometry

SEED = 125


@ddt
class TestIsometry(QiskitTestCase):
"""Qiskit isometry tests."""

@data(np.eye(2, 2), random_unitary(2).data, np.eye(4, 4),
random_unitary(4).data[:, 0],
np.eye(4, 4)[:, 0:2], random_unitary(4).data,
@data(np.eye(2, 2), random_unitary(2, seed=SEED).data, np.eye(4, 4),
random_unitary(4, seed=SEED).data[:, 0],
np.eye(4, 4)[:, 0:2], random_unitary(4, seed=SEED).data,
np.eye(4, 4)[:, np.random.permutation(np.eye(4, 4).shape[1])][:, 0:2],
np.eye(8, 8)[:, np.random.permutation(np.eye(8, 8).shape[1])],
random_unitary(8).data[:, 0:4], random_unitary(8).data, random_unitary(16).data,
random_unitary(16).data[:, 0:8])
random_unitary(8, seed=SEED).data[:, 0:4], random_unitary(8, seed=SEED).data,
random_unitary(16, seed=SEED).data, random_unitary(16, seed=SEED).data[:, 0:8])
def test_isometry(self, iso):
"""Tests for the decomposition of isometries from m to n qubits"""
if len(iso.shape) == 1:
Expand All @@ -62,6 +64,7 @@ def test_isometry(self, iso):
unitary = result.get_unitary(qc)
iso_from_circuit = unitary[::, 0:2 ** num_q_input]
iso_desired = iso

self.assertTrue(matrix_equal(iso_from_circuit, iso_desired, ignore_phase=True))

@data(np.eye(2, 2), random_unitary(2).data, np.eye(4, 4),
Expand Down
4 changes: 2 additions & 2 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,9 @@ def test_optimize_to_nothing(self):
circ.cx(qr[0], qr[1])

after = transpile(circ, coupling_map=[[0, 1], [1, 0]],
basis_gates=['u3', 'cx'])
basis_gates=['u3', 'u2', 'u1', 'cx'])
kdk marked this conversation as resolved.
Show resolved Hide resolved

expected = QuantumCircuit(QuantumRegister(2, 'q'))
expected = QuantumCircuit(QuantumRegister(2, 'q'), global_phase=-np.pi/2)
self.assertEqual(after, expected)

def test_pass_manager_empty(self):
Expand Down
3 changes: 2 additions & 1 deletion test/python/quantum_info/test_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,8 @@ def test_seed_289(self):
self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose)

@combine(seed=range(10),
euler_bases=[('U3', ['u3']), ('U', ['u']), ('U1X', ['u1', 'rx']), ('RR', ['r']),
euler_bases=[('U321', ['u3', 'u2', 'u1']), ('U3', ['u3']), ('U', ['u']),
('U1X', ['u1', 'rx']), ('RR', ['r']),
('PSX', ['p', 'sx']), ('ZYZ', ['rz', 'ry']), ('ZXZ', ['rz', 'rx']),
('XYX', ['rx', 'ry']), ('ZSX', ['rz', 'sx'])],
kak_gates=[(CXGate(), 'cx'), (CZGate(), 'cz'), (iSwapGate(), 'iswap'),
Expand Down
78 changes: 77 additions & 1 deletion test/python/transpiler/test_optimize_1q_decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
import numpy as np

from qiskit.circuit import QuantumRegister, QuantumCircuit, ClassicalRegister
from qiskit.circuit.library.standard_gates import U3Gate
from qiskit.circuit.library.standard_gates import UGate, SXGate, PhaseGate
from qiskit.circuit.library.standard_gates import U3Gate, U2Gate, U1Gate
from qiskit.circuit.random import random_circuit
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
Expand Down Expand Up @@ -61,6 +62,7 @@ def test_optimize_h_gates_pass_manager(self, basis):
passmanager.append(BasisTranslator(sel, basis))
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertTrue(Operator(circuit).equiv(Operator(result)))

@ddt.data(
Expand Down Expand Up @@ -344,6 +346,80 @@ def test_euler_decomposition_worse(self):
# assert optimization pass doesn't use it.
self.assertEqual(result, circuit)

def test_optimize_u_to_phase_gate(self):
"""U(0, 0, pi/4) -> p(pi/4). Basis [p, sx]."""
qr = QuantumRegister(2, 'qr')
circuit = QuantumCircuit(qr)
circuit.append(UGate(0, 0, np.pi / 4), [qr[0]])

expected = QuantumCircuit(qr)
expected.append(PhaseGate(np.pi / 4), [qr[0]])

basis = ['p', 'sx']
passmanager = PassManager()
passmanager.append(BasisTranslator(sel, basis))
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)

def test_optimize_u_to_p_sx_p(self):
"""U(pi/2, 0, pi/4) -> p(-pi/4)-sx-p(p/2). Basis [p, sx, cx]."""
qr = QuantumRegister(2, 'qr')
circuit = QuantumCircuit(qr)
circuit.append(UGate(np.pi / 2, 0, np.pi / 4), [qr[0]])
circuit.cx(0, 1)

expected = QuantumCircuit(qr, global_phase=-np.pi/4)
expected.append(PhaseGate(-np.pi / 4), [qr[0]])
expected.append(SXGate(), [qr[0]])
expected.append(PhaseGate(np.pi / 2), [qr[0]])
expected.cx(0, 1)

basis = ['p', 'sx', 'cx']
passmanager = PassManager()
passmanager.append(BasisTranslator(sel, basis))
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)

def test_optimize_u3_to_u1(self):
"""U3(0, 0, pi/4) -> U1(pi/4). Basis [u1, u2, u3]."""
qr = QuantumRegister(2, 'qr')
circuit = QuantumCircuit(qr)
circuit.append(U3Gate(0, 0, np.pi / 4), [qr[0]])
circuit.append(U3Gate(0, 0, np.pi / 2), [qr[0]])

expected = QuantumCircuit(qr)
expected.append(U1Gate(3 * np.pi / 4), [qr[0]])

basis = ['u1', 'u2', 'u3']
passmanager = PassManager()
passmanager.append(BasisTranslator(sel, basis))
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)

def test_optimize_u3_to_u2(self):
"""U3(pi/2, 0, pi/4) -> U2(0, pi/4). Basis [u1, u2, u3]."""
qr = QuantumRegister(2, 'qr')
circuit = QuantumCircuit(qr)
circuit.append(U3Gate(np.pi / 2, 0, np.pi / 4), [qr[0]])
circuit.append(U3Gate(0, 0, np.pi / 4), [qr[0]])

expected = QuantumCircuit(qr)
expected.append(U2Gate(np.pi / 4, np.pi / 4), [qr[0]])

basis = ['u1', 'u2', 'u3']
passmanager = PassManager()
passmanager.append(BasisTranslator(sel, basis))
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)


if __name__ == '__main__':
unittest.main()