Skip to content

Commit

Permalink
Roll back the default on unitary to np.complex64, change default for …
Browse files Browse the repository at this point in the history
…final_state_vector (#5636)

Rolls back change in #5426 that set the default precision on `Circuit#unitary` to `np.complex128`.

Also sets the default on `Circuit#final_state_vector` to `np.complex128`.  There was a deprecation warning that this was going to be downgraded to `np.complex64`,, but this will now remain `np.complex128`.  This is breaking in that is someone explicitly passed `dtype=None` to this method it would now break.  

Rolls back #5426 #5616 #5537 #5535
  • Loading branch information
dabacon committed Jun 29, 2022
1 parent 3744981 commit f904a09
Show file tree
Hide file tree
Showing 39 changed files with 83 additions and 166 deletions.
21 changes: 7 additions & 14 deletions cirq-core/cirq/circuits/circuit.py
Expand Up @@ -1003,7 +1003,7 @@ def unitary(
qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT,
qubits_that_should_be_present: Iterable['cirq.Qid'] = (),
ignore_terminal_measurements: bool = True,
dtype: Type[np.complexfloating] = np.complex64,
dtype: Type[np.complexfloating] = np.complex128,
) -> np.ndarray:
"""Converts the circuit into a unitary matrix, if possible.
Expand All @@ -1018,10 +1018,11 @@ def unitary(
ignore_terminal_measurements: When set, measurements at the end of
the circuit are ignored instead of causing the method to
fail.
dtype: The numpy dtype for the returned unitary. `dtype` must be
a complex np.dtype, unless all operations in the circuit have
unitary matrices with exclusively real coefficients
(e.g. an H + TOFFOLI circuit).
dtype: The numpy dtype for the returned unitary. Defaults to
np.complex128. Specifying np.complex64 will run faster at the
cost of precision. `dtype` must be a complex np.dtype, unless
all operations in the circuit have unitary matrices with
exclusively real coefficients (e.g. an H + TOFFOLI circuit).
Returns:
A (possibly gigantic) 2d numpy array corresponding to a matrix
Expand Down Expand Up @@ -1093,7 +1094,7 @@ def final_state_vector(
qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT,
qubits_that_should_be_present: Iterable['cirq.Qid'] = (),
ignore_terminal_measurements: Optional[bool] = None,
dtype: Optional[Type[np.complexfloating]] = None,
dtype: Type[np.complexfloating] = np.complex128,
param_resolver: 'cirq.ParamResolverOrSimilarType' = None,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
Expand Down Expand Up @@ -1143,14 +1144,6 @@ def final_state_vector(
)
ignore_terminal_measurements = True

if dtype is None:
_compat._warn_or_error(
'`dtype` will default to np.complex64 in v0.16. '
'To use the previous default, please explicitly include '
'`dtype=np.complex128` when calling this method.'
)
dtype = np.complex128

from cirq.sim.mux import final_state_vector

program = Circuit(cirq.I(q) for q in qubits_that_should_be_present) + self
Expand Down
56 changes: 0 additions & 56 deletions cirq-core/cirq/circuits/circuit_test.py
Expand Up @@ -2957,62 +2957,6 @@ def test_final_state_vector(circuit_cls):
)


@pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit])
def test_final_state_vector_deprecated_params(circuit_cls):
a = cirq.NamedQubit('a')
b = cirq.NamedQubit('b')
# Extra qubits.
cirq.testing.assert_allclose_up_to_global_phase(
circuit_cls().final_state_vector(ignore_terminal_measurements=False, dtype=np.complex128),
np.array([1]),
atol=1e-8,
)
with cirq.testing.assert_deprecated("Inject identity operators", deadline="v0.16"):
cirq.testing.assert_allclose_up_to_global_phase(
circuit_cls().final_state_vector(
qubits_that_should_be_present=[a],
ignore_terminal_measurements=False,
dtype=np.complex128,
),
np.array([1, 0]),
atol=1e-8,
)
with cirq.testing.assert_deprecated("Inject identity operators", deadline="v0.16"):
cirq.testing.assert_allclose_up_to_global_phase(
circuit_cls(cirq.X(b)).final_state_vector(
qubits_that_should_be_present=[a],
ignore_terminal_measurements=False,
dtype=np.complex128,
),
np.array([0, 1, 0, 0]),
atol=1e-8,
)

with cirq.testing.assert_deprecated("To drop terminal measurements", deadline="v0.16"):
cirq.testing.assert_allclose_up_to_global_phase(
circuit_cls(cirq.X(a), cirq.measure(a)).final_state_vector(dtype=np.complex128),
np.array([0, 1]),
atol=1e-8,
)

with cirq.testing.assert_deprecated("`dtype` will default to np.complex64", deadline="v0.16"):
cirq.testing.assert_allclose_up_to_global_phase(
circuit_cls(cirq.X(a)).final_state_vector(ignore_terminal_measurements=False),
np.array([0, 1]),
atol=1e-8,
)

# Non-keyword args.
with cirq.testing.assert_deprecated("Only use keyword arguments", deadline="v0.16"):
cirq.testing.assert_allclose_up_to_global_phase(
circuit_cls(cirq.X(a) ** 0.5).final_state_vector(
1, ignore_terminal_measurements=False, dtype=np.complex128
),
np.array([1, 1j]) * np.sqrt(0.5),
atol=1e-8,
)


@pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit])
@pytest.mark.parametrize('resolve_fn', [cirq.resolve_parameters, cirq.resolve_parameters_once])
def test_is_parameterized(circuit_cls, resolve_fn):
Expand Down
4 changes: 1 addition & 3 deletions cirq-core/cirq/contrib/acquaintance/executor_test.py
Expand Up @@ -119,9 +119,7 @@ def test_executor_random(
circuit.append(cca.LinearPermutationGate(num_qubits, permutation)(*qubits))
actual_unitary = circuit.unitary()

np.testing.assert_allclose(
actual=actual_unitary, desired=expected_unitary, verbose=True, atol=1e-6
)
np.testing.assert_allclose(actual=actual_unitary, desired=expected_unitary, verbose=True)


def test_acquaintance_operation():
Expand Down
Expand Up @@ -121,4 +121,4 @@ def test_optimize_large_circuit():

c_opt = clifford_optimized_circuit(c_orig)

cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
12 changes: 6 additions & 6 deletions cirq-core/cirq/contrib/paulistring/optimize_test.py
Expand Up @@ -48,17 +48,17 @@ def test_optimize():

c_opt = optimized_circuit(c_orig)

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

# TODO(#5546) Fix '[Z]^1' (should be 'Z')
cirq.testing.assert_has_diagram(
c_opt,
"""
0: ───X^0.5────────────@──────────────────────────────────────────────
0: ───X^0.5────────────@────────────────────────────────────────
1: ───@───────X^-0.5───@───@────────────────@───Z^-0.5────────────────
1: ───@───────X^-0.5───@───@────────────────@───Z^-0.5──────────
│ │ │
2: ───@────────────────────@───[X]^(-7/8)───@───[X]^-0.25───[Z]^(1)───
2: ───@────────────────────@───[X]^(-7/8)───@───[X]^-0.25───Z───
""",
)

Expand All @@ -69,7 +69,7 @@ def test_optimize_large_circuit():

c_opt = optimized_circuit(c_orig)

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

assert (
sum(
Expand All @@ -87,7 +87,7 @@ def test_repeat_limit():

c_opt = optimized_circuit(c_orig, repeat=1)

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

assert (
sum(
Expand Down
Expand Up @@ -26,5 +26,5 @@ def test_pauli_string_dag_from_circuit():
c_left_reordered = c_left_dag.to_circuit()

cirq.testing.assert_allclose_up_to_global_phase(
c_left.unitary(), c_left_reordered.unitary(), atol=1e-6
c_left.unitary(), c_left_reordered.unitary(), atol=1e-7
)
Expand Up @@ -37,7 +37,7 @@ def test_optimize():
c_opt = pauli_string_optimized_circuit(c_orig)

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

cirq.testing.assert_has_diagram(
Expand Down Expand Up @@ -81,4 +81,4 @@ def test_optimize_large_circuit():

c_opt = pauli_string_optimized_circuit(c_orig)

cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-6)
cirq.testing.assert_allclose_up_to_global_phase(c_orig.unitary(), c_opt.unitary(), atol=1e-7)
2 changes: 1 addition & 1 deletion cirq-core/cirq/contrib/paulistring/separate_test.py
Expand Up @@ -23,7 +23,7 @@ def test_toffoli_separate():
c_left, c_right = convert_and_separate_circuit(circuit)

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

assert all(isinstance(op, cirq.PauliStringPhasor) for op in c_left.all_operations())
Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/contrib/qasm_import/qasm_test.py
Expand Up @@ -51,6 +51,6 @@ def test_consistency_with_qasm_output_and_qiskit():
circuit2 = circuit_from_qasm(qasm)

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

cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq_unitary)
2 changes: 1 addition & 1 deletion cirq-core/cirq/ion/convert_to_ion_gates_test.py
Expand Up @@ -88,7 +88,7 @@ def test_convert_to_ion_gates():
atol=1e-4,
)
assert cirq.allclose_up_to_global_phase(
cirq.unitary(cirq.Circuit(rcnot)), cirq.unitary(OtherCNOT().on(q0, q1)), atol=1e-6
cirq.unitary(cirq.Circuit(rcnot)), cirq.unitary(OtherCNOT().on(q0, q1)), atol=1e-7
)


Expand Down
14 changes: 3 additions & 11 deletions cirq-core/cirq/linalg/decompositions.py
Expand Up @@ -549,8 +549,6 @@ def scatter_plot_normalized_kak_interaction_coefficients(
*,
include_frame: bool = True,
ax: Optional[plt.Axes] = None,
rtol: float = 1e-5,
atol: float = 1e-6,
**kwargs,
):
r"""Plots the interaction coefficients of many two-qubit operations.
Expand Down Expand Up @@ -592,12 +590,6 @@ def scatter_plot_normalized_kak_interaction_coefficients(
wireframe. Defaults to `True`.
ax: A matplotlib 3d axes object to plot into. If not specified, a new
figure is created, plotted, and shown.
rtol: Per-matrix-entry relative tolerance on equality used if the
kak decomposition is calculated from the `interactions`.
atol: Per-matrix-entry absolute tolerance on equality used if the
kak decomposition is calculated from the `interaction`s. T
This determines how close $k_x$ must be to π/4 to guarantee
$k_z$ ≥ 0. Must be non-negative.
**kwargs: Arguments forwarded into the call to `scatter` that plots the
points. Working arguments include color `c='blue'`, scale `s=2`,
Expand Down Expand Up @@ -671,7 +663,7 @@ def coord_transform(
else:
interactions_extracted = [interactions]

points = kak_vector(interactions_extracted, rtol=rtol, atol=atol) * 4 / np.pi
points = kak_vector(interactions_extracted) * 4 / np.pi

ax.scatter(*coord_transform(points), **kwargs)
ax.set_xlim(0, +1)
Expand Down Expand Up @@ -819,7 +811,7 @@ def kak_decomposition(
],
*,
rtol: float = 1e-5,
atol: float = 1e-6,
atol: float = 1e-8,
check_preconditions: bool = True,
) -> KakDecomposition:
"""Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.
Expand Down Expand Up @@ -955,7 +947,7 @@ def kak_vector(

if check_preconditions:
actual = np.einsum('...ba,...bc', unitary.conj(), unitary) - np.eye(4)
if not np.allclose(np.zeros_like(actual), actual, rtol=rtol, atol=atol):
if not np.allclose(actual, np.zeros_like(actual), rtol=rtol, atol=atol):
raise ValueError(
'Input must correspond to a 4x4 unitary matrix or tensor of '
f'unitary matrices. Received input:\n{unitary}'
Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/linalg/decompositions_test.py
Expand Up @@ -782,4 +782,4 @@ def test_extract_right_diag(u):
assert cirq.num_cnots_required(u) == 3
diag = cirq.linalg.extract_right_diag(u)
assert cirq.is_diagonal(diag)
assert cirq.num_cnots_required(u @ diag, atol=1e-6) == 2
assert cirq.num_cnots_required(u @ diag) == 2
8 changes: 4 additions & 4 deletions cirq-core/cirq/ops/diagonal_gate_test.py
Expand Up @@ -54,7 +54,7 @@ def test_decomposition_unitary(n):

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


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

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

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

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

np.testing.assert_allclose(decomposed_f, expected_f, atol=1e-6)
np.testing.assert_allclose(decomposed_f, expected_f)


@pytest.mark.parametrize('n', [1, 2, 3, 4])
Expand All @@ -99,7 +99,7 @@ def test_decomposition_with_parameterization(n):
resolved_op = cirq.resolve_parameters(parameterized_op, resolver)
resolved_circuit = cirq.resolve_parameters(decomposed_circuit, resolver)
np.testing.assert_allclose(
cirq.unitary(resolved_op), cirq.unitary(resolved_circuit), atol=1e-6
cirq.unitary(resolved_op), cirq.unitary(resolved_circuit), atol=1e-8
)


Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/ops/fsim_gate_test.py
Expand Up @@ -317,7 +317,7 @@ def test_phased_fsim_from_fsim_rz(theta, phi, rz_angles_before, rz_angles_after)
cirq.rz(rz_angles_after[0]).on(q0),
cirq.rz(rz_angles_after[1]).on(q1),
)
cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(f), cirq.unitary(c), atol=1e-6)
cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(f), cirq.unitary(c), atol=1e-8)


@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/ops/matrix_gates.py
Expand Up @@ -56,7 +56,7 @@ def __init__(
name: str = None,
qid_shape: Optional[Iterable[int]] = None,
unitary_check_rtol: float = 1e-5,
unitary_check_atol: float = 1e-6,
unitary_check_atol: float = 1e-8,
) -> None:
"""Initializes a matrix gate.
Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/ops/parallel_gate_test.py
Expand Up @@ -119,7 +119,7 @@ def test_unitary(gate, num_copies, qubits):
step = gate.num_qubits()
qubit_lists = [qubits[i * step : (i + 1) * step] for i in range(num_copies)]
np.testing.assert_allclose(
cirq.unitary(g), cirq.unitary(cirq.Circuit(gate.on_each(qubit_lists))), atol=1e-6
cirq.unitary(g), cirq.unitary(cirq.Circuit(gate.on_each(qubit_lists))), atol=1e-8
)


Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/ops/phased_x_gate_test.py
Expand Up @@ -176,7 +176,7 @@ def test_parameterize(resolve_fn, global_shift):
np.testing.assert_allclose(
cirq.unitary(resolved_gate(q)),
cirq.unitary(resolve_fn(parameterized_decomposed_circuit, resolver)),
atol=1e-6,
atol=1e-8,
)

unparameterized_gate = cirq.PhasedXPowGate(
Expand Down
1 change: 0 additions & 1 deletion cirq-core/cirq/ops/two_qubit_diagonal_gate_test.py
Expand Up @@ -51,7 +51,6 @@ def test_parameterized_decompose():
np.testing.assert_allclose(
cirq.unitary(cirq.resolve_parameters(parameterized_op, resolver)),
cirq.unitary(cirq.resolve_parameters(decomposed_circuit, resolver)),
atol=1e-6,
)


Expand Down
4 changes: 2 additions & 2 deletions cirq-core/cirq/optimizers/merge_interactions_test.py
Expand Up @@ -54,7 +54,7 @@ def assert_optimization_not_broken(circuit):
cirq.MergeInteractions().optimize_circuit(circuit)
u_after = circuit.unitary()

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


def test_clears_paired_cnot():
Expand Down Expand Up @@ -254,4 +254,4 @@ def clean_up(operations):

u_before = c_orig.unitary()
u_after = circuit[1:-1].unitary()
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-6)
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-8)
3 changes: 1 addition & 2 deletions cirq-core/cirq/testing/circuit_compare_test.py
Expand Up @@ -126,13 +126,12 @@ def test_measuring_qubits():
'circuit', [cirq.testing.random_circuit(cirq.LineQubit.range(2), 4, 0.5) for _ in range(5)]
)
def test_random_same_matrix(circuit):
circuit_copy = circuit.copy()
a, b = cirq.LineQubit.range(2)
same = cirq.Circuit(
cirq.MatrixGate(circuit.unitary(qubits_that_should_be_present=[a, b])).on(a, b)
)

cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(circuit_copy, same)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(circuit, same)

mutable_circuit = circuit.copy()
mutable_circuit.append(cirq.measure(a))
Expand Down
4 changes: 2 additions & 2 deletions cirq-core/cirq/testing/consistent_decomposition.py
Expand Up @@ -43,10 +43,10 @@ def assert_decompose_is_consistent_with_unitary(val: Any, ignoring_global_phase:
actual = circuits.Circuit(dec).unitary(qubit_order=qubits)

if ignoring_global_phase:
lin_alg_utils.assert_allclose_up_to_global_phase(actual, expected, atol=1e-6)
lin_alg_utils.assert_allclose_up_to_global_phase(actual, expected, atol=1e-8)
else:
# coverage: ignore
np.testing.assert_allclose(actual, expected, atol=1e-6)
np.testing.assert_allclose(actual, expected, atol=1e-8)


def _known_gate_with_no_decomposition(val: Any):
Expand Down

0 comments on commit f904a09

Please sign in to comment.