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

Better tolerances for gate decompositions #5827

Merged
merged 50 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
13746ec
global phase in TwoQubitBasisDecomposer
georgios-ts Feb 1, 2021
0c9a68d
Merge branch 'master' into TwoQubit
georgios-ts Feb 1, 2021
39a5491
Tolerances for checks
levbishop Feb 5, 2021
fa95b3b
Tolerance and global phase for 1q/2q decompositions
levbishop Feb 5, 2021
e358370
Merge branch 'master' of git://github.com/Qiskit/qiskit-terra into to…
levbishop Feb 9, 2021
80944e8
Subclass Weyl decompositions for numeric stability
levbishop Mar 1, 2021
d9fb6ca
Merge tolerances branch
levbishop Mar 2, 2021
916c146
improve 1q decomposition and testing
levbishop Mar 3, 2021
19d2633
Streamline TwoQubitBasisDecomposer testing
levbishop Mar 3, 2021
b76d465
OneQubitEulerDecomposer performance and correctness
levbishop Mar 3, 2021
ebd7302
Merge branch 'master' into tolerances
levbishop Mar 3, 2021
f82a03b
Pass tests
levbishop Mar 4, 2021
63837c6
Specialize the circuit representation
levbishop Mar 4, 2021
3a7e7da
testing, special case fixes
levbishop Mar 5, 2021
01e9806
Add ZSXX basis to 1q euler decomposer
mtreinish Jan 29, 2021
a369f9f
more tweaks
levbishop Mar 8, 2021
b9ba2a5
Merge branch 'tolerances' of github.com:levbishop/qiskit-terra into t…
levbishop Mar 8, 2021
d180fee
circuit __eq__ check phase mod 2pi
levbishop Mar 8, 2021
eb369b2
merge with origin/master
levbishop Mar 8, 2021
34b625f
fixup merge, better phase comparison
levbishop Mar 9, 2021
1dc6c8a
drop numpy.typing hints (1.20+ feature)
levbishop Mar 9, 2021
f12a15b
Merge branch 'master' into tolerances
levbishop Mar 9, 2021
babe4cd
Merge branch 'master' into tolerances
levbishop Mar 10, 2021
f99712e
Comments and test coverage
levbishop Mar 12, 2021
222f4ad
Update __repr__ and testing
levbishop Mar 14, 2021
86d7543
Broader test numerical tolerance
levbishop Mar 14, 2021
0081a06
Add back previously failing test
levbishop Mar 15, 2021
ed5f1cb
Merge branch 'master' into tolerances
levbishop Mar 15, 2021
1558c04
Avoid accidentally making object ndarrays
levbishop Mar 16, 2021
58ee299
Merge branch 'master' into tolerances
levbishop Mar 16, 2021
c2ab47d
Update test/python/transpiler/test_optimize_1q_decomposition.py
mtreinish Mar 16, 2021
f219acf
Merge branch 'master' into zsxx-basis
mtreinish Mar 16, 2021
3eb59ff
Merge zsxx-basis into tolerances
mtreinish Mar 16, 2021
b977685
Fix decomposition and tests
levbishop Mar 17, 2021
c552958
Merge branch 'master' into tolerances
levbishop Mar 17, 2021
dbf1c36
TIghten test tolerance, clamp angle wrapping
levbishop Mar 17, 2021
3c1a588
Merge branch 'master' into tolerances
levbishop Mar 17, 2021
b0af209
circuit.__eq__ false equalities, fixup test
levbishop Mar 17, 2021
b45dd1b
Default simplify=True typo
levbishop Mar 17, 2021
a6e114b
Merge branch 'master' into tolerances
levbishop Mar 23, 2021
a20fe63
Fixes for review
levbishop Mar 23, 2021
e796f57
propagate circuit.global_phase changes to dags
levbishop Mar 23, 2021
ce15be5
Merge branch 'master' into tolerances
levbishop Apr 7, 2021
17506d4
Merge branch 'master' into tolerances
jaygambetta Apr 10, 2021
42c9803
Docstrings and fix failing test
levbishop Apr 13, 2021
5b7087c
Merge branch 'master' into tolerances
levbishop Apr 13, 2021
5d4afa1
Add release note
levbishop Apr 13, 2021
af76248
Release note
levbishop Apr 13, 2021
7c563d6
Merge branch 'master' into tolerances
jaygambetta Apr 13, 2021
a357219
Merge branch 'master' into tolerances
mergify[bot] Apr 14, 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
4 changes: 1 addition & 3 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1881,12 +1881,10 @@ def global_phase(self, angle):
if isinstance(angle, ParameterExpression) and angle.parameters:
self._global_phase = angle
else:
# Set the phase to the [-2 * pi, 2 * pi] interval
# Set the phase to the [0, 2π) interval
angle = float(angle)
if not angle:
self._global_phase = 0
elif angle < 0:
self._global_phase = angle % (-2 * np.pi)
else:
self._global_phase = angle % (2 * np.pi)

Expand Down
4 changes: 2 additions & 2 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,10 +889,11 @@ def __eq__(self, other):
# Try to convert to float, but in case of unbound ParameterExpressions
# a TypeError will be raise, fallback to normal equality in those
# cases

try:
self_phase = float(self.global_phase)
other_phase = float(other.global_phase)
if not np.isclose(self_phase, other_phase):
if (self_phase - other_phase + np.pi) % (2 * np.pi) - np.pi > 1.E-10: # XXX: tolerance
return False
except TypeError:
if self.global_phase != other.global_phase:
Expand All @@ -916,7 +917,6 @@ def __eq__(self, other):
for regname, reg in other.qregs.items()]
other_creg_indices = [(regname, [other_bit_indices[bit] for bit in reg])
for regname, reg in other.cregs.items()]

if (
self_qreg_indices != other_qreg_indices
or self_creg_indices != other_creg_indices
Expand Down
306 changes: 136 additions & 170 deletions qiskit/quantum_info/synthesis/one_qubit_decompose.py

Large diffs are not rendered by default.

555 changes: 450 additions & 105 deletions qiskit/quantum_info/synthesis/two_qubit_decompose.py

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions test/python/circuit/test_unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,10 @@ def test_qasm_2q_unitary(self):
qr = QuantumRegister(2, 'q0')
cr = ClassicalRegister(1, 'c0')
qc = QuantumCircuit(qr, cr)
matrix = numpy.eye(4)
matrix = numpy.asarray([[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 0]])
unitary_gate = UnitaryGate(matrix, label="custom_gate")

qc.x(qr[0])
Expand All @@ -271,8 +274,8 @@ def test_qasm_2q_unitary(self):
"creg c0[1];\n" \
"x q0[0];\n" \
"gate custom_gate p0,p1 {\n" \
"\tu3(0,0,0) p0;\n" \
"\tu3(0,0,0) p1;\n" \
"\tu3(pi,-pi/2,pi/2) p0;\n" \
"\tu3(pi,pi/2,-pi/2) p1;\n" \
"}\n" \
"custom_gate q0[0],q0[1];\n" \
"custom_gate q0[1],q0[0];\n"
Expand Down
11 changes: 6 additions & 5 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ def test_optimize_to_nothing(self):
basis_gates=['u3', 'u2', 'u1', 'cx'])

expected = QuantumCircuit(QuantumRegister(2, 'q'), global_phase=-np.pi/2)
self.assertEqual(after, expected)
msg = f"after:\n{after}\nexpected:\n{expected}"
self.assertEqual(after, expected, msg=msg)

def test_pass_manager_empty(self):
"""Test passing an empty PassManager() to the transpiler.
Expand Down Expand Up @@ -995,12 +996,12 @@ def test_no_infinite_loop(self, optimization_level):
# for the second and third RZ gates in the U3 decomposition.
expected = QuantumCircuit(1, global_phase=-np.pi/2 - 0.5 * (0.2 + np.pi) - 0.5 * 3 * np.pi)
expected.sx(0)
expected.p(np.pi + 0.2, 0)
expected.p(-np.pi + 0.2, 0)
expected.sx(0)
expected.p(np.pi, 0)
expected.p(-np.pi, 0)

error_message = "\nOutput circuit:\n%s\nExpected circuit:\n%s" % (
str(out), str(expected))
error_message = (f"\nOutput circuit:\n{out!s}\n{Operator(out).data}\n"
f"Expected circuit:\n{expected!s}\n{Operator(expected).data}")
self.assertEqual(out, expected, error_message)

@data(0, 1, 2, 3)
Expand Down
2 changes: 1 addition & 1 deletion test/python/quantum_info/states/test_statevector.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ def test_global_phase(self):
qc2 = transpile(qc, basis_gates=['p'])
sv = Statevector.from_instruction(qc2)
expected = np.array([0.96891242-0.24740396j, 0])
self.assertEqual(float(qc2.global_phase), -1/4)
self.assertEqual(float(qc2.global_phase), 2*np.pi - 0.25)
self.assertEqual(sv, Statevector(expected))

def test_reverse_qargs(self):
Expand Down
606 changes: 536 additions & 70 deletions test/python/quantum_info/test_synthesis.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion test/python/transpiler/test_basis_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,5 +775,6 @@ def test_global_phase(self):
expected.global_phase = circ_angle - gate_angle / 2
expected_dag = circuit_to_dag(expected)
self.assertEqual(out_dag, expected_dag)
self.assertEqual(float(out_dag.global_phase), float(expected_dag.global_phase))
self.assertAlmostEqual(float(out_dag.global_phase), float(expected_dag.global_phase),
places=14)
self.assertEqual(Operator(dag_to_circuit(out_dag)), Operator(expected))
3 changes: 2 additions & 1 deletion test/python/transpiler/test_commutative_cancellation.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@ def test_commutative_circuit3(self):
expected.append(RZGate(np.pi * 2 / 3), [qr[3]])
expected.cx(qr[2], qr[1])

self.assertEqual(expected, new_circuit)
self.assertEqual(expected, new_circuit,
msg=f'expected:\n{expected}\nnew_circuit:\n{new_circuit}')

def test_cnot_cascade(self):
"""
Expand Down
14 changes: 9 additions & 5 deletions test/python/transpiler/test_optimize_1q_decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ def test_euler_decomposition_worse(self):
result = passmanager.run(circuit)
# decomposition of circuit will result in 3 gates instead of 2
# assert optimization pass doesn't use it.
self.assertEqual(result, circuit)
self.assertEqual(circuit, result, f"Circuit:\n{circuit}\nResult:\n{result}")

def test_optimize_u_to_phase_gate(self):
"""U(0, 0, pi/4) -> p(pi/4). Basis [p, sx]."""
Expand All @@ -363,7 +363,8 @@ def test_optimize_u_to_phase_gate(self):
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)
msg = f"expected:\n{expected}\nresult:\n{result}"
self.assertEqual(expected, result, msg=msg)

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]."""
Expand All @@ -382,7 +383,8 @@ def test_optimize_u_to_p_sx_p(self):
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)
msg = f"expected:\n{expected}\nresult:\n{result}"
self.assertEqual(expected, result, msg=msg)

def test_optimize_u3_to_u1(self):
"""U3(0, 0, pi/4) -> U1(pi/4). Basis [u1, u2, u3]."""
Expand All @@ -399,7 +401,8 @@ def test_optimize_u3_to_u1(self):
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)
msg = f"expected:\n{expected}\nresult:\n{result}"
self.assertEqual(expected, result, msg=msg)

def test_optimize_u3_to_u2(self):
"""U3(pi/2, 0, pi/4) -> U2(0, pi/4). Basis [u1, u2, u3]."""
Expand All @@ -416,7 +419,8 @@ def test_optimize_u3_to_u2(self):
passmanager.append(Optimize1qGatesDecomposition(basis))
result = passmanager.run(circuit)

self.assertEqual(expected, result)
msg = f"expected:\n{expected}\nresult:\n{result}"
self.assertEqual(expected, result, msg=msg)


if __name__ == '__main__':
Expand Down