def layer(params, q): """CV quantum neural network layer acting on ``N`` modes. Args: params (list[float]): list of length ``2*(max(1, N-1) + N**2 + n)`` containing the number of parameters for the layer q (list[RegRef]): list of Strawberry Fields quantum registers the layer is to be applied to """ N = len(q) M = int(N * (N - 1)) + max(1, N - 1) int1 = params[:M] s = params[M:M + N] int2 = params[M + N:2 * M + N] dr = params[2 * M + N:2 * M + 2 * N] dp = params[2 * M + 2 * N:2 * M + 3 * N] k = params[2 * M + 3 * N:2 * M + 4 * N] # begin layer interferometer(int1, q) for i in range(N): ops.Sgate(s[i]) | q[i] interferometer(int2, q) for i in range(N): ops.Dgate(dr[i], dp[i]) | q[i] ops.Kgate(k[i]) | q[i]
def test_extract_arbitrary_unitary_one_mode(self, setup_eng, cutoff, tol): """Test that arbitrary unitary extraction works for 1 mode""" S = ops.Sgate(0.4, -1.2) D = ops.Dgate(2, 0.9) K = ops.Kgate(-1.5) # not a state but it doesn't matter initial_state = np.random.rand(cutoff) + 1j * np.random.rand(cutoff) eng_ref, p0 = setup_eng(1) with p0.context as q: ops.Ket(initial_state) | q prog = sf.Program(p0) with prog.context as q: S | q D | q K | q U = utils.extract_unitary(prog, cutoff_dim=cutoff, backend=eng_ref.backend_name) if isinstance(U, tf.Tensor): U = U.numpy() final_state = U @ initial_state expected_state = eng_ref.run([p0, prog]).state.ket() assert np.allclose(final_state, expected_state, atol=tol, rtol=0)
def test_extract_arbitrary_unitary_one_mode(self, setup_eng, cutoff, tol): """Test that arbitrary unitary extraction works for 1 mode""" S = ops.Sgate(0.4, -1.2) D = ops.Dgate(2, 0.9) K = ops.Kgate(-1.5) # not a state but it doesn't matter initial_state = np.random.rand(cutoff) + 1j * np.random.rand(cutoff) eng_ref, p0 = setup_eng(1) with p0.context as q: ops.Ket(initial_state) | q prog = sf.Program(p0) with prog.context as q: S | q D | q K | q U = utils.extract_unitary(prog, cutoff_dim=cutoff, backend=eng_ref.backend_name) if isinstance(U, tf.Tensor): with tf.Session() as sess: sess.run(tf.global_variables_initializer()) in_state = tf.constant(initial_state.reshape([-1]), dtype=tf.complex64) final_state = sess.run(tf.einsum("ab,b", U, in_state)) else: final_state = U @ initial_state expected_state = eng_ref.run([p0, prog]).ket() assert np.allclose(final_state, expected_state, atol=tol, rtol=0)
def test_invalid_primitive(self): """Test that an exception is raised if the program contains a primitive not allowed on the circuit spec. Here, we can simply use the guassian circuit spec and the Kerr gate as an existing example. """ prog = sf.Program(3) with prog.context as q: ops.Kgate(0.6) | q[0] with pytest.raises(program.CircuitError, match="Kgate cannot be used with the target"): new_prog = prog.compile(target='gaussian')
def test_one_mode_gates_from_operators(self, drawer): prog = sf.Program(3) with prog.context as q: ops.Xgate(1) | (q[0]) ops.Zgate(1) | (q[0]) ops.Kgate(1) | (q[0]) ops.Vgate(1) | (q[0]) ops.Pgate(1) | (q[0]) ops.Rgate(1) | (q[0]) ops.Sgate(1) | (q[0]) ops.Dgate(1) | (q[0]) for op in prog.circuit: method, mode = drawer._gate_from_operator(op) assert callable(method) and hasattr(drawer, method.__name__) assert mode == 1
def test_one_mode_gates_from_operators(self, drawer): eng, q = sf.Engine(3) with eng: ops.Xgate(1) | (q[0]) ops.Zgate(1) | (q[0]) ops.Kgate(1) | (q[0]) ops.Vgate(1) | (q[0]) ops.Pgate(1) | (q[0]) ops.Rgate(1) | (q[0]) ops.Sgate(1) | (q[0]) ops.Dgate(1) | (q[0]) for op in eng.cmd_queue: method, mode = drawer._gate_from_operator(op) assert callable(method) and hasattr(drawer, method.__name__) assert mode == 1
def test_extract_kerr(self, backend_name, cutoff, tol): """test that the Kerr gate is correctly extracted""" prog = sf.Program(1) kappa = 0.432 with prog.context as q: ops.Kgate(kappa) | q U = utils.extract_unitary(prog, cutoff_dim=cutoff, backend=backend_name) expected = np.diag(np.exp(1j * kappa * np.arange(cutoff)**2)) if isinstance(U, tf.Tensor): U = U.numpy() assert np.allclose(U, expected, atol=tol, rtol=0)
def test_parse_op(self, drawer): prog = sf.Program(3) with prog.context as q: ops.Xgate(1) | (q[0]) ops.Zgate(1) | (q[0]) ops.CXgate(1) | (q[0], q[1]) ops.CZgate(1) | (q[0], q[1]) ops.BSgate(0, 1) | (q[0], q[1]) ops.S2gate(0, 1) | (q[0], q[1]) ops.CKgate(1) | (q[0], q[1]) ops.Kgate(1) | (q[0]) ops.Vgate(1) | (q[0]) ops.Pgate(1) | (q[0]) ops.Rgate(1) | (q[0]) ops.Sgate(1) | (q[0]) ops.Dgate(1) | (q[0]) for op in prog.circuit: drawer.parse_op(op) expected_circuit_matrix = [ [ "\\gate{X}", "\\gate{Z}", "\\ctrl{1}", "\\ctrl{1}", "\\multigate{1}{BS}", "\\multigate{1}{S}", "\\ctrl{1}", "\\gate{K}", "\\gate{V}", "\\gate{P}", "\\gate{R}", "\\gate{S}", "\\gate{D}", ], ["\\qw"] * 2 + ["\\targ", "\\gate{Z}", "\\ghost{BS}", "\\ghost{S}", "\\gate{K}"] + ["\\qw"] * 6, ["\\qw"] * 13, ] assert drawer._circuit_matrix == expected_circuit_matrix
def test_parse_op(self, drawer): eng, q = sf.Engine(3) with eng: ops.Xgate(1) | (q[0]) ops.Zgate(1) | (q[0]) ops.CXgate(1) | (q[0], q[1]) ops.CZgate(1) | (q[0], q[1]) ops.BSgate(0, 1) | (q[0], q[1]) ops.S2gate(0, 1) | (q[0], q[1]) ops.CKgate(1) | (q[0], q[1]) ops.Kgate(1) | (q[0]) ops.Vgate(1) | (q[0]) ops.Pgate(1) | (q[0]) ops.Rgate(1) | (q[0]) ops.Sgate(1) | (q[0]) ops.Dgate(1) | (q[0]) for op in eng.cmd_queue: drawer.parse_op(op) expected_circuit_matrix = [ [ "\\gate{X}", "\\gate{Z}", "\\ctrl{1}", "\\ctrl{1}", "\\multigate{1}{BS}", "\\multigate{1}{S}", "\\ctrl{1}", "\\gate{K}", "\\gate{V}", "\\gate{P}", "\\gate{R}", "\\gate{S}", "\\gate{D}", ], ["\\qw"] * 2 + ["\\targ", "\\gate{Z}", "\\ghost{BS}", "\\ghost{S}", "\\gate{K}"] + ["\\qw"] * 6, ["\\qw"] * 13, ] assert drawer._circuit_matrix == expected_circuit_matrix
def test_k_1(self, tmpdir): prog = sf.Program(3) with prog.context as q: ops.Kgate(1) | (q[1]) k_test_1_output = dedent(r""" \documentclass{article} \usepackage{qcircuit} \begin{document} \Qcircuit { & \qw & \qw \\ & \gate{K} & \qw \\ & \qw & \qw \\ } \end{document}""") result = prog.draw_circuit(tex_dir=tmpdir)[1] assert result == k_test_1_output, failure_message( result, k_test_1_output)
def test_k_1(self, tmpdir): eng, q = sf.Engine(3) with eng: ops.Kgate(1) | (q[1]) k_test_1_output = dedent(r""" \documentclass{article} \usepackage{qcircuit} \begin{document} \Qcircuit { & \qw & \qw \\ & \gate{K} & \qw \\ & \qw & \qw \\ } \end{document}""") result = eng.draw_circuit(print_queued_ops=True, tex_dir=tmpdir)[1] assert result == k_test_1_output, failure_message( result, k_test_1_output)
def test_extract_kerr(self, setup_backend, cutoff, tol): """test that the Kerr gate is correctly extracted""" backend = setup_backend(1) eng, q = sf.Engine(1) kappa = 0.432 with eng: ops.Kgate(kappa) | q U = utils.extract_unitary(eng, cutoff_dim=cutoff, backend=backend._short_name) expected = np.diag(np.exp(1j * kappa * np.arange(cutoff)**2)) if isinstance(U, tf.Tensor): U = tf.Session().run(U) assert np.allclose(U, expected, atol=tol, rtol=0)
def test_complex(init): modes = 4 cutoff_dim = 6 initial_state = np.zeros([cutoff_dim] * modes, dtype=complex) # The ket below corresponds to a single photon going into each of the modes initial_state[init] = 1 prog = sf.Program(modes) s_d_params = 0.01 with prog.context as q: ops.Ket(initial_state) | q # Initial state preparation # Gaussian Layer ops.S2gate(s_d_params, s_d_params) | (q[0], q[1]) ops.BSgate(1.9, 1.7) | (q[1], q[2]) ops.BSgate(0.9, 0.2) | (q[0], q[1]) # Non-Gaussian Layer ops.Kgate(0.5) | q[3] ops.CKgate(0.7) | (q[2], q[3]) # Gaussian Layer ops.BSgate(1.0, 0.4) | (q[0], q[1]) ops.BSgate(2.0, 1.5) | (q[1], q[2]) ops.Dgate(s_d_params) | q[0] ops.Dgate(s_d_params) | q[0] ops.Sgate(s_d_params, s_d_params) | q[1] # Non-Gaussian Layer ops.Vgate(0.5) | q[2] # We run the simulation eng = sf.Engine("fock", backend_options={"cutoff_dim": cutoff_dim}) results_norm = eng.run(prog) prog_merged = prog.compile(compiler="gaussian_merge") results_merged = eng.run(prog_merged) ket = results_norm.state.ket() ket_merged = results_merged.state.ket() assert np.allclose(np.abs(np.sum(np.conj(ket) * ket_merged)), 1)