def test_move_vac_modes(self, N, crop, expected):
        """Test the `move_vac_modes` function"""
        samples = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]],
                            [[9, 10], [11, 12]]])
        res = move_vac_modes(samples, N, crop=crop)

        assert np.all(res == expected)
    def test_ghz(self):
        """Generates a GHZ state and checks that the correct correlations (noise reductions) are observed
        from the samples
        See Eq. 5 of https://advances.sciencemag.org/content/5/5/eaaw4530
        """
        # Set up the circuit
        np.random.seed(42)
        vac_modes = 1
        n = 4
        shots = 100
        sq_r = 5
        alpha = [
            np.arccos(np.sqrt(1 / (n - i + 1))) if i != n + 1 else 0
            for i in range(n)
        ]
        alpha[0] = 0.0
        phi = [0] * n
        phi[0] = np.pi / 2
        timebins_per_shot = len(alpha)

        # Measuring X nullifier
        theta = [0] * n
        samples_X = singleloop(sq_r, alpha, phi, theta, shots)
        reshaped_samples_X = move_vac_modes(samples_X, 2, crop=True)

        # Measuring P nullifier
        theta = [np.pi / 2] * n
        samples_P = singleloop(sq_r, alpha, phi, theta, shots)
        reshaped_samples_P = move_vac_modes(samples_P, 2, crop=True)

        # We will check that the x of all the modes equal the x of the last one
        nullifier_X = lambda sample: (sample - sample[-1])[:-1]
        val_nullifier_X = np.var(
            [nullifier_X(x[0]) for x in reshaped_samples_X], axis=0)
        assert np.allclose(val_nullifier_X,
                           sf.hbar * np.exp(-2 * sq_r),
                           rtol=5 / np.sqrt(shots))

        # We will check that the sum of all the p is equal to zero
        val_nullifier_P = np.var([np.sum(p[0]) for p in reshaped_samples_P],
                                 axis=0)
        assert np.allclose(val_nullifier_P,
                           0.5 * sf.hbar * n * np.exp(-2 * sq_r),
                           rtol=5 / np.sqrt(shots))
    def test_epr(self):
        """Generates an EPR state and checks that the correct correlations (noise reductions) are observed
        from the samples"""
        np.random.seed(42)
        vac_modes = 1
        sq_r = 5.0
        c = 2
        shots = 100

        # This will generate c EPRstates per copy. I chose c = 4 because it allows us to make 4 EPR pairs per copy that can each be measured in different basis permutations.
        alpha = [0, np.pi / 4] * c
        phi = [np.pi / 2, 0] * c

        # Measurement of 2 subsequent EPR states in XX, PP to investigate nearest-neighbour correlations in all basis permutations
        theta = [np.pi / 2, 0, 0, np.pi / 2]

        timebins_per_shot = len(alpha)

        samples = singleloop(sq_r, alpha, phi, theta, shots)
        reshaped_samples = move_vac_modes(samples, 2, crop=True)

        X0 = reshaped_samples[:, 0, 0]
        X1 = reshaped_samples[:, 0, 1]
        P2 = reshaped_samples[:, 0, 2]
        P3 = reshaped_samples[:, 0, 3]

        rtol = 5 / np.sqrt(shots)
        minusstdX1X0 = (X1 - X0).var()
        plusstdX1X0 = (X1 + X0).var()
        squeezed_std = np.exp(-2 * sq_r)
        expected_minus = sf.hbar * squeezed_std
        expected_plus = sf.hbar / squeezed_std
        assert np.allclose(minusstdX1X0, expected_minus, rtol=rtol)
        assert np.allclose(plusstdX1X0, expected_plus, rtol=rtol)

        minusstdP2P3 = (P2 - P3).var()
        plusstdP2P3 = (P2 + P3).var()
        assert np.allclose(minusstdP2P3, expected_plus, rtol=rtol)
        assert np.allclose(plusstdP2P3, expected_minus, rtol=rtol)