def beamsplitter(t, r, phi, trunc, save=False, directory=None): r""" The beamsplitter :math:`B(cos^{-1} t, phi)`. """ # pylint: disable=bad-whitespace try: prefac = so.load_bs_factors(trunc, directory) except FileNotFoundError: prefac = so.generate_bs_factors(trunc) if save: so.save_bs_factors(prefac, directory) dim_array = np.arange(trunc) N = dim_array.reshape((-1, 1, 1, 1, 1)) n = dim_array.reshape((1, -1, 1, 1, 1)) M = dim_array.reshape((1, 1, -1, 1, 1)) k = dim_array.reshape((1, 1, 1, 1, -1)) tpwr = M - n + 2 * k rpwr = n + N - 2 * k T = np.power(t, tpwr) if t != 0 else np.where(tpwr != 0, 0, 1) R = np.power(r, rpwr) if r != 0 else np.where(rpwr != 0, 0, 1) BS = np.sum(exp(-1j * (pi + phi) * (n - N)) * T * R * prefac[:trunc, :trunc, :trunc, :trunc, :trunc], axis=-1) BS = BS.swapaxes(0, 1).swapaxes(2, 3) return BS
def test_save_load_bs_factors(self): factors = so.generate_bs_factors(4) so.save_bs_factors(factors, directory="./") factors = so.load_bs_factors(4, directory="./") factors_val = factors[factors != 0.] factors_idx = np.array(np.nonzero(factors)) self.assertAllAlmostEqual(factors_val, bs_4_val, delta=self.tol) self.assertAllAlmostEqual(factors_idx, bs_4_idx, delta=self.tol)
def test_save_load(self, tmpdir, tol): """test saving and loading of beamsplitter factors""" factors = so.generate_bs_factors(4) so.save_bs_factors(factors, directory=str(tmpdir)) factors = so.load_bs_factors(4, directory=str(tmpdir)) factors_val = factors[factors != 0.0] factors_idx = np.array(np.nonzero(factors)) assert np.allclose(factors_val, BS_4_VAL, atol=tol, rtol=0) assert np.allclose(factors_idx, BS_4_IDX, atol=tol, rtol=0)
def get_prefac_tensor(D, directory, save): """Equivalent to the functionality of shared_ops the bs_factors functions from shared_ops, but caches the return value as a tensor. This allows us to re-use the same prefactors and save space on the computational graph.""" try: prefac = load_bs_factors(D, directory) except FileNotFoundError: prefac = generate_bs_factors(D) if save: save_bs_factors(prefac, directory) prefac = tf.expand_dims(tf.cast(prefac[:D, :D, :D, :D, :D], def_type), 0) return prefac
def squeezing(r, theta, trunc, save=False, directory=None): r"""The squeezing operator :math:`S(re^{i\theta})`. Args: r (float): the magnitude of the squeezing in the x direction theta (float): the squeezing angle trunc (int): the Fock cutoff """ # pylint: disable=duplicate-code if r == 0: # return the identity ret = np.eye(trunc, dtype=def_type) else: # broadcast the index arrays dim_array = np.arange(trunc) N = dim_array.reshape((-1, 1, 1)) n = dim_array.reshape((1, -1, 1)) k = dim_array.reshape((1, 1, -1)) try: prefac = so.load_squeeze_factors(trunc, directory) except FileNotFoundError: prefac = so.generate_squeeze_factors(trunc) if save: so.save_bs_factors(prefac, directory) # we only perform the sum when n+N is divisible by 2 # in which case we sum 0 <= k <= min(N,n) # mask = np.logical_and((n+N)%2 == 0, k <= np.minimum(N, n)) mask = np.logical_and((n + N) % 2 == 0, k <= np.minimum(N, n)) # perform the summation over k scale = mask * np.power(sinh(r) / 2, mask * (N + n - 2 * k) / 2) / (cosh(r)**( (N + n + 1) / 2)) ph = exp(1j * theta * (N - n) / 2) ret = np.sum(scale * ph * prefac, axis=-1) return ret