Skip to content

Commit 2eeb3d3

Browse files
dabaconrht
authored andcommitted
Set default unitary precision np.complex64 (quantumlib#5426)
1 parent b4d7e3a commit 2eeb3d3

40 files changed

+147
-109
lines changed

cirq-core/cirq/circuits/circuit.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ def unitary(
998998
qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT,
999999
qubits_that_should_be_present: Iterable['cirq.Qid'] = (),
10001000
ignore_terminal_measurements: bool = True,
1001-
dtype: Type[np.number] = np.complex128,
1001+
dtype: Type[np.number] = np.complex64,
10021002
) -> np.ndarray:
10031003
"""Converts the circuit into a unitary matrix, if possible.
10041004
@@ -1013,11 +1013,10 @@ def unitary(
10131013
ignore_terminal_measurements: When set, measurements at the end of
10141014
the circuit are ignored instead of causing the method to
10151015
fail.
1016-
dtype: The numpy dtype for the returned unitary. Defaults to
1017-
np.complex128. Specifying np.complex64 will run faster at the
1018-
cost of precision. `dtype` must be a complex np.dtype, unless
1019-
all operations in the circuit have unitary matrices with
1020-
exclusively real coefficients (e.g. an H + TOFFOLI circuit).
1016+
dtype: The numpy dtype for the returned unitary. `dtype` must be
1017+
a complex np.dtype, unless all operations in the circuit have
1018+
unitary matrices with exclusively real coefficients
1019+
(e.g. an H + TOFFOLI circuit).
10211020
10221021
Returns:
10231022
A (possibly gigantic) 2d numpy array corresponding to a matrix

cirq-core/cirq/contrib/acquaintance/executor_test.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ def test_executor_random(
119119
circuit.append(cca.LinearPermutationGate(num_qubits, permutation)(*qubits))
120120
actual_unitary = circuit.unitary()
121121

122-
np.testing.assert_allclose(actual=actual_unitary, desired=expected_unitary, verbose=True)
122+
np.testing.assert_allclose(
123+
actual=actual_unitary, desired=expected_unitary, verbose=True, atol=1e-6
124+
)
123125

124126

125127
def test_acquaintance_operation():

cirq-core/cirq/contrib/paulistring/clifford_optimize_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,4 @@ def test_optimize_large_circuit():
121121

122122
c_opt = clifford_optimized_circuit(c_orig)
123123

124-
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
124+
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)

cirq-core/cirq/contrib/paulistring/convert_gate_set.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ def converted_gate_set(
2121
circuit: circuits.Circuit, no_clifford_gates: bool = False, atol: float = 1e-8
2222
) -> circuits.Circuit:
2323
"""Returns a new, equivalent circuit using the gate set
24-
{SingleQubitCliffordGate,
25-
CZ/PauliInteractionGate, PauliStringPhasor}.
24+
{SingleQubitCliffordGate, CZ/PauliInteractionGate, PauliStringPhasor}.
2625
"""
2726
conv_circuit = transformers.optimize_for_target_gateset(
2827
circuit, gateset=transformers.CZTargetGateset()

cirq-core/cirq/contrib/paulistring/optimize_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def test_optimize():
4848

4949
c_opt = optimized_circuit(c_orig)
5050

51-
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
51+
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)
5252

5353
cirq.testing.assert_has_diagram(
5454
c_opt,
@@ -68,7 +68,7 @@ def test_optimize_large_circuit():
6868

6969
c_opt = optimized_circuit(c_orig)
7070

71-
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
71+
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)
7272

7373
assert (
7474
sum(
@@ -86,7 +86,7 @@ def test_repeat_limit():
8686

8787
c_opt = optimized_circuit(c_orig, repeat=1)
8888

89-
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
89+
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)
9090

9191
assert (
9292
sum(

cirq-core/cirq/contrib/paulistring/pauli_string_dag_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ def test_pauli_string_dag_from_circuit():
2626
c_left_reordered = c_left_dag.to_circuit()
2727

2828
cirq.testing.assert_allclose_up_to_global_phase(
29-
c_left.unitary(), c_left_reordered.unitary(), atol=1e-7
29+
c_left.unitary(), c_left_reordered.unitary(), atol=1e-6
3030
)

cirq-core/cirq/contrib/paulistring/pauli_string_optimize_test.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ def test_optimize():
3636

3737
c_opt = pauli_string_optimized_circuit(c_orig)
3838

39-
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
40-
41-
assert c_opt == c_expected
39+
cirq.testing.assert_allclose_up_to_global_phase(
40+
c_orig.unitary(), c_expected.unitary(), atol=1e-6
41+
)
4242

4343
cirq.testing.assert_has_diagram(
4444
c_opt,
@@ -81,4 +81,4 @@ def test_optimize_large_circuit():
8181

8282
c_opt = pauli_string_optimized_circuit(c_orig)
8383

84-
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
84+
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)

cirq-core/cirq/contrib/paulistring/separate_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_toffoli_separate():
2323
c_left, c_right = convert_and_separate_circuit(circuit)
2424

2525
cirq.testing.assert_allclose_up_to_global_phase(
26-
circuit.unitary(), (c_left + c_right).unitary(), atol=1e-7
26+
circuit.unitary(), (c_left + c_right).unitary(), atol=1e-6
2727
)
2828

2929
assert all(isinstance(op, cirq.PauliStringPhasor) for op in c_left.all_operations())

cirq-core/cirq/contrib/qasm_import/qasm_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ def test_consistency_with_qasm_output_and_qiskit():
5151
circuit2 = circuit_from_qasm(qasm)
5252

5353
cirq_unitary = cirq.unitary(circuit2)
54-
ct.assert_allclose_up_to_global_phase(cirq_unitary, cirq.unitary(circuit1), atol=1e-8)
54+
ct.assert_allclose_up_to_global_phase(cirq_unitary, cirq.unitary(circuit1), atol=1e-6)
5555

5656
cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq_unitary)

cirq-core/cirq/ion/convert_to_ion_gates_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def test_convert_to_ion_gates():
7171
atol=1e-4,
7272
)
7373
assert cirq.allclose_up_to_global_phase(
74-
cirq.unitary(cirq.Circuit(rcnot)), cirq.unitary(OtherCNOT().on(q0, q1))
74+
cirq.unitary(cirq.Circuit(rcnot)), cirq.unitary(OtherCNOT().on(q0, q1)), atol=1e-6
7575
)
7676

7777

cirq-core/cirq/linalg/decompositions.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,8 @@ def scatter_plot_normalized_kak_interaction_coefficients(
549549
*,
550550
include_frame: bool = True,
551551
ax: Optional[plt.Axes] = None,
552+
rtol: float = 1e-5,
553+
atol: float = 1e-6,
552554
**kwargs,
553555
):
554556
r"""Plots the interaction coefficients of many two-qubit operations.
@@ -590,6 +592,13 @@ def scatter_plot_normalized_kak_interaction_coefficients(
590592
wireframe. Defaults to `True`.
591593
ax: A matplotlib 3d axes object to plot into. If not specified, a new
592594
figure is created, plotted, and shown.
595+
rtol: Per-matrix-entry relative tolerance on equality used if the
596+
kak decomposition is calculated from the `interactions`.
597+
atol: Per-matrix-entry absolute tolerance on equality used if the
598+
kak decomposition is calculated from the `interaction`s. T
599+
This determines how close $k_x$ must be to π/4 to guarantee
600+
$k_z$ ≥ 0. Must be non-negative.
601+
593602
**kwargs: Arguments forwarded into the call to `scatter` that plots the
594603
points. Working arguments include color `c='blue'`, scale `s=2`,
595604
labelling `label="theta=pi/4"`, etc. For reference see the
@@ -662,7 +671,7 @@ def coord_transform(
662671
else:
663672
interactions_extracted = [interactions]
664673

665-
points = kak_vector(interactions_extracted) * 4 / np.pi
674+
points = kak_vector(interactions_extracted, rtol=rtol, atol=atol) * 4 / np.pi
666675

667676
ax.scatter(*coord_transform(points), **kwargs)
668677
ax.set_xlim(0, +1)
@@ -810,7 +819,7 @@ def kak_decomposition(
810819
],
811820
*,
812821
rtol: float = 1e-5,
813-
atol: float = 1e-8,
822+
atol: float = 1e-6,
814823
check_preconditions: bool = True,
815824
) -> KakDecomposition:
816825
"""Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.
@@ -848,9 +857,7 @@ def kak_decomposition(
848857
if check_preconditions and (
849858
mat.shape != (4, 4) or not predicates.is_unitary(mat, rtol=rtol, atol=atol)
850859
):
851-
raise ValueError(
852-
'Input must correspond to a 4x4 unitary matrix. Received matrix:\n' + str(mat)
853-
)
860+
raise ValueError(f'Input must correspond to a 4x4 unitary matrix. Received matrix:\n{mat}')
854861

855862
# Diagonalize in magic basis.
856863
left, d, right = diagonalize.bidiagonalize_unitary_with_special_orthogonals(
@@ -948,7 +955,7 @@ def kak_vector(
948955

949956
if check_preconditions:
950957
actual = np.einsum('...ba,...bc', unitary.conj(), unitary) - np.eye(4)
951-
if not np.allclose(actual, np.zeros_like(actual), rtol, atol):
958+
if not np.allclose(np.zeros_like(actual), actual, rtol=rtol, atol=atol):
952959
raise ValueError(
953960
'Input must correspond to a 4x4 unitary matrix or tensor of '
954961
f'unitary matrices. Received input:\n{unitary}'

cirq-core/cirq/linalg/decompositions_test.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -738,15 +738,17 @@ def test_kak_vector_input_not_unitary():
738738
def test_kak_decompose(unitary: np.ndarray):
739739
kak = cirq.kak_decomposition(unitary)
740740
circuit = cirq.Circuit(kak._decompose_(cirq.LineQubit.range(2)))
741-
np.testing.assert_allclose(cirq.unitary(circuit), unitary, atol=1e-8)
741+
np.testing.assert_allclose(cirq.unitary(circuit), unitary, atol=1e-6)
742742
assert len(circuit) == 5
743743
assert len(list(circuit.all_operations())) == 8
744744

745745

746746
def test_num_two_qubit_gates_required():
747747
for i in range(4):
748748
assert (
749-
cirq.num_cnots_required(cirq.testing.random_two_qubit_circuit_with_czs(i).unitary())
749+
cirq.num_cnots_required(
750+
cirq.testing.random_two_qubit_circuit_with_czs(i).unitary(), atol=1e-6
751+
)
750752
== i
751753
)
752754

@@ -759,7 +761,7 @@ def test_num_two_qubit_gates_required_invalid():
759761

760762

761763
@pytest.mark.parametrize(
762-
"U",
764+
"u",
763765
[
764766
cirq.testing.random_two_qubit_circuit_with_czs(3).unitary(),
765767
# an example where gamma(special(u))=I, so the denominator becomes 0
@@ -776,8 +778,8 @@ def test_num_two_qubit_gates_required_invalid():
776778
),
777779
],
778780
)
779-
def test_extract_right_diag(U):
780-
assert cirq.num_cnots_required(U) == 3
781-
diag = cirq.linalg.extract_right_diag(U)
781+
def test_extract_right_diag(u):
782+
assert cirq.num_cnots_required(u) == 3
783+
diag = cirq.linalg.extract_right_diag(u)
782784
assert cirq.is_diagonal(diag)
783-
assert cirq.num_cnots_required(U @ diag) == 2
785+
assert cirq.num_cnots_required(u @ diag, atol=1e-6) == 2

cirq-core/cirq/ops/diagonal_gate_test.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ def test_decomposition_unitary(n):
5252
expected_f = [np.exp(1j * angle) for angle in diagonal_angles]
5353
decomposed_f = cirq.unitary(decomposed_circ).diagonal()
5454

55-
np.testing.assert_allclose(decomposed_f, expected_f)
55+
# For large qubit counts, the decomposed circuit is rather large, so we lose a lot of
56+
# precision.
57+
np.testing.assert_allclose(decomposed_f, expected_f, atol=5e-6)
5658

5759

5860
@pytest.mark.parametrize('n', [1, 2, 3, 4])
@@ -63,7 +65,7 @@ def test_diagonal_exponent(n):
6365
sqrt_diagonal_gate = diagonal_gate**0.5
6466

6567
expected_angles = [prime / 2 for prime in diagonal_angles]
66-
np.testing.assert_allclose(expected_angles, sqrt_diagonal_gate._diag_angles_radians, atol=1e-8)
68+
np.testing.assert_allclose(expected_angles, sqrt_diagonal_gate._diag_angles_radians, atol=1e-6)
6769

6870
assert cirq.pow(cirq.DiagonalGate(diagonal_angles), "test", None) is None
6971

@@ -78,7 +80,7 @@ def test_decomposition_diagonal_exponent(n):
7880
expected_f = [np.exp(1j * angle / 2) for angle in diagonal_angles]
7981
decomposed_f = cirq.unitary(decomposed_circ).diagonal()
8082

81-
np.testing.assert_allclose(decomposed_f, expected_f)
83+
np.testing.assert_allclose(decomposed_f, expected_f, atol=1e-6)
8284

8385

8486
@pytest.mark.parametrize('n', [1, 2, 3, 4])
@@ -97,7 +99,7 @@ def test_decomposition_with_parameterization(n):
9799
resolved_op = cirq.resolve_parameters(parameterized_op, resolver)
98100
resolved_circuit = cirq.resolve_parameters(decomposed_circuit, resolver)
99101
np.testing.assert_allclose(
100-
cirq.unitary(resolved_op), cirq.unitary(resolved_circuit), atol=1e-8
102+
cirq.unitary(resolved_op), cirq.unitary(resolved_circuit), atol=1e-6
101103
)
102104

103105

cirq-core/cirq/ops/fsim_gate_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def test_phased_fsim_from_fsim_rz(theta, phi, rz_angles_before, rz_angles_after)
317317
cirq.rz(rz_angles_after[0]).on(q0),
318318
cirq.rz(rz_angles_after[1]).on(q1),
319319
)
320-
cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(f), cirq.unitary(c), atol=1e-8)
320+
cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(f), cirq.unitary(c), atol=1e-6)
321321

322322

323323
@pytest.mark.parametrize(

cirq-core/cirq/ops/matrix_gates.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def __init__(
5656
name: str = None,
5757
qid_shape: Optional[Iterable[int]] = None,
5858
unitary_check_rtol: float = 1e-5,
59-
unitary_check_atol: float = 1e-8,
59+
unitary_check_atol: float = 1e-6,
6060
) -> None:
6161
"""Initializes a matrix gate.
6262

cirq-core/cirq/ops/parallel_gate_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def test_unitary(gate, num_copies, qubits):
119119
step = gate.num_qubits()
120120
qubit_lists = [qubits[i * step : (i + 1) * step] for i in range(num_copies)]
121121
np.testing.assert_allclose(
122-
cirq.unitary(g), cirq.unitary(cirq.Circuit(gate.on_each(qubit_lists))), atol=1e-8
122+
cirq.unitary(g), cirq.unitary(cirq.Circuit(gate.on_each(qubit_lists))), atol=1e-6
123123
)
124124

125125

cirq-core/cirq/ops/phased_x_gate_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def test_parameterize(resolve_fn, global_shift):
176176
np.testing.assert_allclose(
177177
cirq.unitary(resolved_gate(q)),
178178
cirq.unitary(resolve_fn(parameterized_decomposed_circuit, resolver)),
179-
atol=1e-8,
179+
atol=1e-6,
180180
)
181181

182182
unparameterized_gate = cirq.PhasedXPowGate(

cirq-core/cirq/ops/two_qubit_diagonal_gate_test.py

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def test_parameterized_decompose():
5151
np.testing.assert_allclose(
5252
cirq.unitary(cirq.resolve_parameters(parameterized_op, resolver)),
5353
cirq.unitary(cirq.resolve_parameters(decomposed_circuit, resolver)),
54+
atol=1e-6,
5455
)
5556

5657

cirq-core/cirq/optimizers/merge_interactions_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def assert_optimization_not_broken(circuit):
5454
cirq.MergeInteractions().optimize_circuit(circuit)
5555
u_after = circuit.unitary()
5656

57-
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-8)
57+
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-6)
5858

5959

6060
def test_clears_paired_cnot():
@@ -254,4 +254,4 @@ def clean_up(operations):
254254

255255
u_before = c_orig.unitary()
256256
u_after = circuit[1:-1].unitary()
257-
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-8)
257+
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-6)

cirq-core/cirq/testing/circuit_compare_test.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,13 @@ def test_measuring_qubits():
126126
'circuit', [cirq.testing.random_circuit(cirq.LineQubit.range(2), 4, 0.5) for _ in range(5)]
127127
)
128128
def test_random_same_matrix(circuit):
129+
circuit_copy = circuit.copy()
129130
a, b = cirq.LineQubit.range(2)
130131
same = cirq.Circuit(
131132
cirq.MatrixGate(circuit.unitary(qubits_that_should_be_present=[a, b])).on(a, b)
132133
)
133134

134-
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(circuit, same)
135+
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(circuit_copy, same)
135136

136137
mutable_circuit = circuit.copy()
137138
mutable_circuit.append(cirq.measure(a))

cirq-core/cirq/testing/consistent_decomposition.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ def assert_decompose_is_consistent_with_unitary(val: Any, ignoring_global_phase:
4343
actual = circuits.Circuit(dec).unitary(qubit_order=qubits)
4444

4545
if ignoring_global_phase:
46-
lin_alg_utils.assert_allclose_up_to_global_phase(actual, expected, atol=1e-8)
46+
lin_alg_utils.assert_allclose_up_to_global_phase(actual, expected, atol=1e-6)
4747
else:
4848
# coverage: ignore
49-
np.testing.assert_allclose(actual, expected, atol=1e-8)
49+
np.testing.assert_allclose(actual, expected, atol=1e-6)
5050

5151

5252
def _known_gate_with_no_decomposition(val: Any):

cirq-core/cirq/testing/consistent_qasm.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, unitary):
125125
qiskit_unitary = result.result().get_unitary()
126126
qiskit_unitary = _reorder_indices_of_matrix(qiskit_unitary, list(reversed(range(num_qubits))))
127127

128-
lin_alg_utils.assert_allclose_up_to_global_phase(unitary, qiskit_unitary, rtol=1e-8, atol=1e-8)
128+
lin_alg_utils.assert_allclose_up_to_global_phase(unitary, qiskit_unitary, rtol=1e-6, atol=1e-6)
129129

130130

131131
def _indent(*content: str) -> str:

cirq-core/cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_decompose_x():
4646
*qubits[0 : controls_count + 1]
4747
)
4848
expected_matrix = circuit2.unitary()
49-
assert np.allclose(expected_matrix, result_matrix)
49+
assert np.allclose(expected_matrix, result_matrix, atol=1e-6)
5050

5151

5252
def _random_unitary():
@@ -88,7 +88,9 @@ def _test_decompose(matrix, controls_count):
8888
[cirq.MatrixGate(matrix).on(qubits[-1]).controlled_by(*qubits[:-1])]
8989
).unitary()
9090

91-
assert np.allclose(expected_matrix, result_matrix)
91+
# Decompose can build rather large circuits for large controls_count,
92+
# so we lose a lot of precision.
93+
np.testing.assert_allclose(expected_matrix, result_matrix, atol=1e-5)
9294

9395

9496
def test_decompose_specific_matrices():

cirq-core/cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def assert_decomposition_valid(cphase_gate, fsim_gate):
8484
u_expected = cirq.unitary(cphase_gate)
8585
ops = cirq.decompose_cphase_into_two_fsim(cphase_gate, fsim_gate=fsim_gate)
8686
u_actual = cirq.unitary(cirq.Circuit(ops))
87-
assert np.allclose(u_actual, u_expected)
87+
assert np.allclose(u_actual, u_expected, atol=1e-6)
8888

8989

9090
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)