def test_mean_photon(self, tol, make_symmetric): """Test that the mean photon number is correct in graph_embed""" num_modes = 6 A = np.random.random([num_modes, num_modes]) + 1j * np.random.random([num_modes, num_modes]) if make_symmetric: A += A.T n_mean = 1.0 sc, _, _ = dec.bipartite_graph_embed(A, mean_photon_per_mode=n_mean) n_mean_calc = np.sum(np.sinh(sc) ** 2) / (num_modes) assert np.allclose(n_mean, n_mean_calc, atol=tol, rtol=0)
def test_correct_graph(self, tol, make_symmetric): """Test that the graph is embeded correctly""" num_modes = 3 A = np.random.random([num_modes, num_modes]) + 1j * np.random.random([num_modes, num_modes]) U, l, V = np.linalg.svd(A) new_l = np.array([np.tanh(np.arcsinh(np.sqrt(i))) for i in range(1, num_modes + 1)]) n_mean = 0.5 * (num_modes + 1) if make_symmetric: At = U @ np.diag(new_l) @ U.T else: At = U @ np.diag(new_l) @ V.T sqf, Uf, Vf = dec.bipartite_graph_embed(At, mean_photon_per_mode=n_mean) assert np.allclose(np.tanh(-np.flip(sqf)), new_l) assert np.allclose(Uf @ np.diag(np.tanh(-sqf)) @ Vf.T, At)
def test_square_validation(self): """Test that the graph_embed decomposition raises exception if not square""" A = np.random.random([4, 5]) + 1j * np.random.random([4, 5]) with pytest.raises(ValueError, match="matrix is not square"): dec.bipartite_graph_embed(A)
def test_decomposition(self, tol): """Test that a graph is correctly decomposed""" n = 3 prog = sf.Program(2*n) A = np.zeros([2*n, 2*n]) B = np.random.random([n, n]) A[:n, n:] = B A += A.T sq, U, V = dec.bipartite_graph_embed(B) G = ops.BipartiteGraphEmbed(A) cmds = G.decompose(prog.register) S = np.identity(4 * n) # calculating the resulting decomposed symplectic for cmd in cmds: # all operations should be BSgates, Rgates, or S2gates assert isinstance( cmd.op, (ops.Interferometer, ops.S2gate) ) # build up the symplectic transform modes = [i.ind for i in cmd.reg] if isinstance(cmd.op, ops.S2gate): # check that the registers are i, i+n assert len(modes) == 2 assert modes[1] == modes[0] + n r, phi = par_evaluate(cmd.op.p) assert -r in sq assert phi == 0 S = _two_mode_squeezing(r, phi, modes, 2*n) @ S if isinstance(cmd.op, ops.Interferometer): # check that each unitary only applies to half the modes assert len(modes) == n assert modes in ([0, 1, 2], [3, 4, 5]) # check matrix is unitary U1 = par_evaluate(cmd.op.p[0]) assert np.allclose(U1 @ U1.conj().T, np.identity(n), atol=tol, rtol=0) if modes[0] == 0: assert np.allclose(U1, U, atol=tol, rtol=0) else: assert modes[0] == 3 assert np.allclose(U1, V, atol=tol, rtol=0) S_U = np.vstack( [np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real])] ) S = expand(S_U, modes, 2*n) @ S # the resulting covariance state cov = S @ S.T A_res = Amat(cov)[:2*n, :2*n] # The bottom right corner of A_res should be identical to A, # up to some constant scaling factor. Check if the ratio # of all elements is one ratio = np.real_if_close(A_res[n:, :n] / B.T) ratio /= ratio[0, 0] assert np.allclose(ratio, np.ones([n, n]), atol=tol, rtol=0)