From ba349391bd21f0e82b6ceb0f0d9610fd635c5981 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Mon, 31 Aug 2020 14:49:35 -0400 Subject: [PATCH 1/6] find_classical_subsystem --- thewalrus/quantum.py | 25 +++++++++++++++++++++ thewalrus/tests/test_quantum.py | 39 ++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/thewalrus/quantum.py b/thewalrus/quantum.py index e3a3094ee..59dceb418 100644 --- a/thewalrus/quantum.py +++ b/thewalrus/quantum.py @@ -947,6 +947,7 @@ def is_classical_cov(cov, hbar=2, atol=1e-08): Args: cov (array): a covariance matrix hbar (float): value of hbar in the uncertainty relation + atol (float): the absolute tolerance parameter used in `np.allclose` Returns: (bool): whether the given covariance matrix corresponds to a classical state @@ -962,6 +963,30 @@ def is_classical_cov(cov, hbar=2, atol=1e-08): return False +def find_classical_subsystem(cov, hbar=2, atol=1e-08): + """Find the largest integer `k` so that subsystem in modes `[0,1,...,k-1]` is a classical state. + + Args: + cov (array): a covariance matrix + hbar (float): value of hbar in the uncertainty relation + atol (float): the absolute tolerance parameter used in `np.allclose` + + Returns: + (int): the largest k so that modes `[0,1,...,k-1]` are in a classical state. + """ + n, m = cov.shape + nmodes = n // 2 + if is_classical_cov(cov, hbar=hbar, atol=atol): + return nmodes + k = 0 + mu = np.zeros(n) + is_classical = True + while is_classical: + _, Vk = reduced_gaussian(mu, cov, list(range(k + 1))) + is_classical = is_classical_cov(Vk, hbar=hbar, atol=atol) + k += 1 + return k - 1 + def gen_single_mode_dist(s, cutoff=50, N=1): """Generate the photon number distribution of :math:`N` identical single mode squeezed states. diff --git a/thewalrus/tests/test_quantum.py b/thewalrus/tests/test_quantum.py index fd5ff4ee3..c31e1b904 100644 --- a/thewalrus/tests/test_quantum.py +++ b/thewalrus/tests/test_quantum.py @@ -20,7 +20,7 @@ import numpy as np from scipy.stats import poisson -from thewalrus.symplectic import rotation, squeezing, interferometer, two_mode_squeezing, beam_splitter, loss +from thewalrus.symplectic import rotation, squeezing, interferometer, two_mode_squeezing, beam_splitter, loss, expand from thewalrus.random import random_covariance, random_interferometer @@ -45,6 +45,7 @@ pure_state_amplitude, state_vector, is_classical_cov, + find_classical_subsystem, total_photon_num_dist_pure_state, gen_single_mode_dist, fock_tensor, @@ -1299,3 +1300,39 @@ def test_photon_number_expectation_two_mode_squeezed(r, phi, hbar): for modes, expected in zip(mode_list, expected_vals): val = photon_number_squared_expectation(means, cov, modes=modes, hbar=hbar) assert np.allclose(val, expected) + +@pytest.mark.parametrize("hbar", [0.5, 1, 2, 1.6]) +def test_find_classical_susbsytem_tmsq(hbar): + """Test that for a system of 2*n squeezed vacua the first n are in a classical state""" + n = 10 + nmodes = 2 * n + S = np.identity(2 * nmodes) + for i in range(n): + S = expand(two_mode_squeezing(1.0, 0), [i, i + n], nmodes) @ S + cov = S @ S.T * hbar / 2 + k = find_classical_subsystem(cov, hbar=hbar) + assert k == n + + +@pytest.mark.parametrize("hbar", [0.5, 1, 2, 1.6]) +def test_find_classical_subsystem_product_sq(hbar): + """Tests that for a product state of squeezed vacua the classical system size is 0""" + nmodes = 10 + r = 1 + vals = np.ones([nmodes]) * hbar / 2 + cov = np.diag(np.concatenate([np.exp(2 * r) * vals, vals * np.exp(-2 * r)])) + k = find_classical_subsystem(cov, hbar=hbar) + assert k == 0 + + +@pytest.mark.parametrize("hbar", [0.5, 1, 2, 1.6]) +def test_find_classical_subsystem_thermal(hbar): + """Tests that for a multimode thermal state the whole system is classical""" + nmodes = 20 + diags = (2 * np.random.rand(nmodes) + 1) * hbar / 2 + cov = np.diag(np.concatenate([diags, diags])) + O = interferometer(random_interferometer(nmodes)) + cov = O @ cov @ O.T + k = find_classical_subsystem(cov, hbar=hbar) + assert k == nmodes + From f96f2e6a589de4c3cbf40eba1349ed32c816a542 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Mon, 31 Aug 2020 14:51:12 -0400 Subject: [PATCH 2/6] Adds function in autosummary --- thewalrus/quantum.py | 1 + 1 file changed, 1 insertion(+) diff --git a/thewalrus/quantum.py b/thewalrus/quantum.py index 59dceb418..0dccf2b4a 100644 --- a/thewalrus/quantum.py +++ b/thewalrus/quantum.py @@ -114,6 +114,7 @@ is_valid_cov is_pure_cov is_classical_cov + find_classical_subsystem total_photon_num_dist_pure_state gen_single_mode_dist gen_multi_mode_dist From 7cb10b677015b66f69c695dff30bfc430935235d Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Mon, 31 Aug 2020 14:51:47 -0400 Subject: [PATCH 3/6] make pylint happy --- thewalrus/quantum.py | 2 +- thewalrus/tests/test_quantum.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/thewalrus/quantum.py b/thewalrus/quantum.py index 0dccf2b4a..dbca0ec1e 100644 --- a/thewalrus/quantum.py +++ b/thewalrus/quantum.py @@ -975,7 +975,7 @@ def find_classical_subsystem(cov, hbar=2, atol=1e-08): Returns: (int): the largest k so that modes `[0,1,...,k-1]` are in a classical state. """ - n, m = cov.shape + n, _ = cov.shape nmodes = n // 2 if is_classical_cov(cov, hbar=hbar, atol=atol): return nmodes diff --git a/thewalrus/tests/test_quantum.py b/thewalrus/tests/test_quantum.py index c31e1b904..53f573823 100644 --- a/thewalrus/tests/test_quantum.py +++ b/thewalrus/tests/test_quantum.py @@ -1335,4 +1335,3 @@ def test_find_classical_subsystem_thermal(hbar): cov = O @ cov @ O.T k = find_classical_subsystem(cov, hbar=hbar) assert k == nmodes - From 2674cf4580ef888e69c661ff3d0eed2114f2a2be Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Thu, 3 Sep 2020 08:41:05 -0400 Subject: [PATCH 4/6] Update thewalrus/quantum.py Co-authored-by: Josh Izaac --- thewalrus/quantum.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thewalrus/quantum.py b/thewalrus/quantum.py index dbca0ec1e..7b0dd490d 100644 --- a/thewalrus/quantum.py +++ b/thewalrus/quantum.py @@ -965,7 +965,8 @@ def is_classical_cov(cov, hbar=2, atol=1e-08): def find_classical_subsystem(cov, hbar=2, atol=1e-08): - """Find the largest integer `k` so that subsystem in modes `[0,1,...,k-1]` is a classical state. + """Find the largest integer ``k`` so that subsystem in modes ``[0,1,...,k-1]`` is a classical state. + Args: cov (array): a covariance matrix From a06f8eac0cf663595197515963e8c537c2b60440 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Thu, 3 Sep 2020 08:42:17 -0400 Subject: [PATCH 5/6] Update thewalrus/quantum.py Co-authored-by: Josh Izaac --- thewalrus/quantum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/quantum.py b/thewalrus/quantum.py index 7b0dd490d..4387e746a 100644 --- a/thewalrus/quantum.py +++ b/thewalrus/quantum.py @@ -974,7 +974,7 @@ def find_classical_subsystem(cov, hbar=2, atol=1e-08): atol (float): the absolute tolerance parameter used in `np.allclose` Returns: - (int): the largest k so that modes `[0,1,...,k-1]` are in a classical state. + int: the largest k so that modes ``[0,1,...,k-1]`` are in a classical state. """ n, _ = cov.shape nmodes = n // 2 From 96a8fca5cbd258d7405715195bcb7c4ac9314593 Mon Sep 17 00:00:00 2001 From: Nicolas Quesada Date: Thu, 3 Sep 2020 08:42:30 -0400 Subject: [PATCH 6/6] Update thewalrus/quantum.py Co-authored-by: Josh Izaac --- thewalrus/quantum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thewalrus/quantum.py b/thewalrus/quantum.py index 4387e746a..332db93c9 100644 --- a/thewalrus/quantum.py +++ b/thewalrus/quantum.py @@ -971,7 +971,7 @@ def find_classical_subsystem(cov, hbar=2, atol=1e-08): Args: cov (array): a covariance matrix hbar (float): value of hbar in the uncertainty relation - atol (float): the absolute tolerance parameter used in `np.allclose` + atol (float): the absolute tolerance parameter used when determining if the state is classical Returns: int: the largest k so that modes ``[0,1,...,k-1]`` are in a classical state.