def qnn_layer(layer_number): with tf.name_scope('layer_{}'.format(layer_number)): BSgate(bs_variables[layer_number, 0, 0, 0], bs_variables[layer_number, 0, 0, 1]) \ | (q[0], q[1]) for i in range(mode_number): Rgate(phase_variables[layer_number, i, 0]) | q[i] for i in range(mode_number): Sgate( tf.clip_by_value(sq_magnitude_variables[layer_number, i], -sq_clip, sq_clip), sq_phase_variables[layer_number, i]) | q[i] BSgate(bs_variables[layer_number, 0, 1, 0], bs_variables[layer_number, 0, 1, 1]) \ | (q[0], q[1]) for i in range(mode_number): Rgate(phase_variables[layer_number, i, 1]) | q[i] for i in range(mode_number): Dgate( tf.clip_by_value(disp_magnitude_variables[layer_number, i], -disp_clip, disp_clip), disp_phase_variables[layer_number, i]) | q[i] for i in range(mode_number): Kgate( tf.clip_by_value(kerr_variables[layer_number, i], -kerr_clip, kerr_clip)) | q[i]
def layer(l): with tf.name_scope('layer_{}'.format(l)): BSgate(theta1[l], phi1[l]) | (q[0], q[1]) Rgate(r1[l]) | q[0] Sgate(tf.clip_by_value(sqr1[l], -sq_clip, sq_clip), sqphi1[l]) | q[0] Sgate(tf.clip_by_value(sqr2[l], -sq_clip, sq_clip), sqphi2[l]) | q[1] BSgate(theta2[l], phi2[l]) | (q[0], q[1]) Rgate(r2[l]) | q[0] Dgate(tf.clip_by_value(dr1[l], -disp_clip, disp_clip), dphi1[l]) | q[0] Dgate(tf.clip_by_value(dr2[l], -disp_clip, disp_clip), dphi2[l]) | q[1] Kgate(tf.clip_by_value(kappa1[l], -kerr_clip, kerr_clip)) | q[0] Kgate(tf.clip_by_value(kappa2[l], -kerr_clip, kerr_clip)) | q[1]
def test_cov_is_pure(): """Tests space unrolling when going into the Gaussian backend""" delays = [1, 6, 36] modes = 216 angles = np.concatenate([ generate_valid_bs_sequence(delays, modes), generate_valid_r_sequence(delays, modes) ]) net = modes + sum(delays) d = len(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram([N]) vac_modes = sum(delays) with prog.context(*angles) as (p, q): Sgate(0.8) | q[n[0]] for i in range(d): Rgate(p[i + d]) | q[n[i]] BSgate(p[i], np.pi / 2) | (q[n[i + 1]], q[n[i]]) prog.space_unroll() eng = sf.Engine(backend="gaussian") results = eng.run(prog) cov = results.state.cov() mu = np.zeros(len(cov)) mu_vac, cov_vac = reduced_state(mu, cov, list(range(vac_modes))) mu_comp, cov_comp = reduced_state(mu, cov, list(range(vac_modes, net))) assert np.allclose(cov_vac, 0.5 * (sf.hbar) * np.identity(2 * vac_modes)) assert is_pure_cov(cov_comp, hbar=sf.hbar)
def test_is_permutation_when_angle_pi_on_two(delays, modes): """Checks that if all the beamsplitters are cross then the absolute value output matrix is a permutation matrix""" delays = list(delays) net = modes + sum(delays) angles = np.concatenate([ generate_valid_bs_sequence(delays, modes), generate_valid_r_sequence(delays, modes) ]) angles[0] = np.pi / 2 * np.random.randint(2, size=net) angles[1] = np.pi / 2 * np.random.randint(2, size=net) angles[2] = np.pi / 2 * np.random.randint(2, size=net) d = len(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram([N]) vac_modes = sum(delays) with prog.context(*angles) as (p, q): for i in range(d): Rgate(p[i + d]) | q[n[i]] BSgate(p[i], np.pi / 2) | (q[n[i + 1]], q[n[i]]) prog.space_unroll() compiled = prog.compile(compiler="passive") passive_elem = compiled.circuit[0] U = passive_elem.op.p[0] assert np.allclose(U @ U.T.conj(), np.identity(len(U))) assert np.allclose(list(map(max, np.abs(U))), 1.0)
def test_no_entanglement_between_padding_and_computational_modes( delays, modes): """Test that the U matrix is the identity if there is no beamsplitter mixing and no rotations""" delays = list(delays) angles = np.concatenate([ generate_valid_bs_sequence(delays, modes), generate_valid_r_sequence(delays, modes) ]) d = len(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram([N]) vac_modes = sum(delays) with prog.context(*angles) as (p, q): for i in range(d): Rgate(p[i + d]) | q[n[i]] BSgate(p[i], np.pi / 2) | (q[n[i + 1]], q[n[i]]) prog.space_unroll() compiled = prog.compile(compiler="passive") passive_elem = compiled.circuit[0] U = passive_elem.op.p[0] # Check that it is indeed the identity U_AA = U[:vac_modes, :vac_modes] U_AB = U[vac_modes:, :vac_modes] U_BA = U[:vac_modes, vac_modes:] U_BB = U[vac_modes:, vac_modes:] assert np.allclose(U_AA, np.identity(vac_modes)) assert np.allclose(U_AB, 0) assert np.allclose(U_BA, 0) assert np.allclose(U_BB @ U_BB.T.conj(), np.identity(len(U_BB)))
def decompose(self, reg): # make BS gate theta = self.layer['BS'][0] phi = self.layer['BS'][1] BS = BSgate(theta, phi) # make Kerr gate K = Kgate(self.layer['K'][0]) # make rotation gate R = Rgate(self.layer['R'][0]) cmds = [] for i in range(self.num_layers): #pylint: disable=unused-variable for q0, q1 in self.layer['BS'][2]: cmds.append(Command(BS, (reg[q0], reg[q1]))) for mode in self.layer['K'][1]: cmds.append(Command(K, reg[mode])) for mode in self.layer['R'][1]: cmds.append(Command(R, reg[mode])) return cmds
def input_qnn_layer(): with tf.name_scope('inputlayer'): Sgate(tf.clip_by_value(output_layer[:, 0], -sq_clip, sq_clip), output_layer[:, 1]) | q[0] Sgate(tf.clip_by_value(output_layer[:, 2], -sq_clip, sq_clip), output_layer[:, 3]) | q[1] BSgate(output_layer[:, 4], output_layer[:, 5]) | (q[0], q[1]) Rgate(output_layer[:, 6]) | q[0] Rgate(output_layer[:, 7]) | q[1] Dgate(tf.clip_by_value(output_layer[:, 8], -disp_clip, disp_clip), output_layer[:, 9]) \ | q[0] Dgate(tf.clip_by_value(output_layer[:, 10], -disp_clip, disp_clip), output_layer[:, 11]) \ | q[0] Kgate(tf.clip_by_value(output_layer[:, 12], -kerr_clip, kerr_clip)) | q[0] Kgate(tf.clip_by_value(output_layer[:, 13], -kerr_clip, kerr_clip)) | q[0]
def test_outside_context(self): """test setting hbar outside of engine context""" H, t = rotation(self.phi) Ugate = GaussianPropagation(H, t, hbar=self.hbar) resD, resV = self.ref_circuit(Ugate) expD, expV = self.ref_circuit(Rgate(self.phi)) # test the covariance matrix self.assertTrue(np.allclose(resV, expV)) # test the vector of means self.assertTrue(np.allclose(resD, expD))
def test_single_mode_gate(self, hbar): """Test Rgate gives correct means and cov in global mode""" H, t = rotation(self.phi, mode=1, hbar=hbar) resD, resV = self.H_circuit(H, t) gate = Rgate(self.phi) expD, expV = self.ref_circuit(gate, 1) # test the covariance matrix assert np.allclose(resV, expV) # test the vector of means assert np.allclose(resD, expD)
def test_single_mode_gate(self): """Test Rgate gives correct means and cov in global mode""" self.eng.reset() q = self.eng.register H, t = rotation(self.phi, mode=1, hbar=self.hbar) resD, resV = self.H_circuit(H, t) gate = Rgate(self.phi) expD, expV = self.ref_circuit(gate, q[1]) # test the covariance matrix self.assertTrue(np.allclose(resV, expV)) # test the vector of means self.assertTrue(np.allclose(resD, expD))
def decompose(self, reg): # make BS gate theta = self.layer['BS'][0] phi = self.layer['BS'][1] BS = BSgate(theta, phi) # make cross-Kerr gate CK = None param = self.layer.get('CK', [0])[0] if param != 0: CK = CKgate(param) # make Kerr gate K = None param = self.layer.get('K', [0])[0] if param != 0: K = Kgate(param) # make rotation gate R = None param = self.layer.get('R', [0])[0] if param != 0: R = Rgate(param) cmds = [] for i in range(self.num_layers): #pylint: disable=unused-variable for q0, q1 in self.layer['BS'][2]: cmds.append(Command(BS, (reg[q0], reg[q1]))) if CK is not None: for q0, q1 in self.layer['CK'][1]: cmds.append(Command(CK, (reg[q0], reg[q1]))) if K is not None: for mode in self.layer['K'][1]: cmds.append(Command(K, reg[mode])) if R is not None: for mode in self.layer['R'][1]: cmds.append(Command(R, reg[mode])) return cmds
def test_lossless_no_mixing_no_rotation_U(delays, modes): """Test that the U matrix is the identity if there is no beamsplitter mixing and no rotations""" delays = list(delays) angles = np.zeros([2 * len(delays), modes + sum(delays)]) d = len(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram([N]) with prog.context(*angles) as (p, q): for i in range(d): Rgate(p[i + d]) | q[n[i]] BSgate(p[i], np.pi / 2) | (q[n[i + 1]], q[n[i]]) prog.space_unroll() compiled = prog.compile(compiler="passive") passive_elem = compiled.circuit[0] U = passive_elem.op.p[0] # Check that it is indeed the identity assert np.allclose(U, np.identity(len(U)))
def test_space_unrolling(): """Tests that space-unrolling works and that it can be done twice""" delays = [1, 6, 36] modes = 216 angles = np.concatenate([ generate_valid_bs_sequence(delays, modes), generate_valid_r_sequence(delays, modes) ]) d = len(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram([N]) with prog.context(*angles) as (p, q): Sgate(0.8) | q[n[0]] for i in range(d): Rgate(p[i + d]) | q[n[i]] BSgate(p[i], np.pi / 2) | (q[n[i + 1]], q[n[i]]) assert prog.is_unrolled == False prog.space_unroll() assert prog.timebins == 259 vac_modes = prog.concurr_modes - 1 assert prog.num_subsystems == prog.timebins + vac_modes # check that the number of gates are correct. assert [isinstance(cmd.op, Sgate) for cmd in prog.circuit].count(True) == prog.timebins assert [isinstance(cmd.op, Rgate) for cmd in prog.circuit].count(True) == 259 * len(delays) assert [isinstance(cmd.op, BSgate) for cmd in prog.circuit].count(True) == 259 * len(delays) prog.space_unroll() # space-unroll the program twice to check that it works assert prog.is_unrolled == True
def test_rolling_space_unrolled(): """Tests that rolling a space-unrolled circuit works""" delays = [1, 6, 36] modes = 216 angles = np.concatenate([ generate_valid_bs_sequence(delays, modes), generate_valid_r_sequence(delays, modes) ]) d = len(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram([N]) with prog.context(*angles) as (p, q): Sgate(0.8) | q[n[0]] for i in range(d): Rgate(p[i + d]) | q[n[i]] BSgate(p[i], np.pi / 2) | (q[n[i + 1]], q[n[i]]) rolled_circuit = prog.circuit.copy() num_subsystems_pre_roll = prog.num_subsystems init_num_subsystems_pre_roll = prog.init_num_subsystems assert prog.is_unrolled == False # space-unroll the program prog.space_unroll() assert prog.is_unrolled == True # roll the program back up prog.roll() assert prog.is_unrolled == False assert prog.num_subsystems == num_subsystems_pre_roll assert prog.init_num_subsystems == init_num_subsystems_pre_roll assert len(prog.circuit) == len(rolled_circuit) assert prog.circuit == rolled_circuit
# Copyright 2018 Xanadu Quantum Technologies Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. r""" Operations ========== This file contains the Strawberry Fields quantum operations that decompose the BosonOperator and QuadOperator from OpenFermion. These operations are used directly in BlackBird code, complementing existing operations. For example: .. code-block:: python prog = sf.Program(3) eng = sf.Engine("gaussian") H1 = BosonOperator('0^ 0')
# connect to the remote engine and obtain a ``device`` object eng = sf.RemoteEngine("borealis") device = eng.device # create a list of list of gate arguments for a GBS instance gate_args_list = borealis_gbs(device, modes=288, squeezing="high") # create a Strawberry Fields program delays = [1, 6, 36] vac_modes = sum(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram(N) with prog.context(*gate_args_list) as (p, q): Sgate(p[0]) | q[n[0]] for i in range(len(delays)): Rgate(p[2 * i + 1]) | q[n[i]] BSgate(p[2 * i + 2], np.pi / 2) | (q[n[i + 1]], q[n[i]]) MeasureFock() | q[0] # define number of shots and submit job to hardware shots = 250_000 results = eng.run(prog, shots=shots, crop=True) # the GBS samples samples = results.samples # plot the estimated simulation times of the experimental samples plot_simulation_time(samples) # obtain first and second moment of the photon-number distribution: mean photon # number and photon-number covariance
def layer(i, size): Rgate(rtheta_1[i, 0]) | (q[0]) BSgate(phi_1[i, 0], 0) | (q[0], q[1]) Rgate(rtheta_1[i, 2]) | (q[1]) for j in range(size): Sgate(r[i, j]) | q[j] Rgate(rtheta_2[i, 0]) | (q[0]) BSgate(phi_2[i, 0], 0) | (q[0], q[1]) Rgate(rtheta_2[i, 2]) | (q[2]) BSgate(phi_2[i, 2], theta_2[i, 3]) | (q[2], q[3]) Rgate(rtheta_2[i, 1]) | (q[1]) BSgate(phi_2[i, 1], 0) | (q[1], q[2]) Rgate(rtheta_2[i, 0]) | (q[0]) BSgate(phi_2[i, 0], 0) | (q[0], q[1]) Rgate(rtheta_2[i, 0]) | (q[0]) Rgate(rtheta_2[i, 1]) | (q[1]) Rgate(rtheta_2[i, 2]) | (q[2]) Rgate(rtheta_2[i, 3]) | (q[3]) BSgate(phi_2[i, 2], 0) | (q[2], q[3]) Rgate(rtheta_2[i, 2]) | (q[2]) BSgate(phi_2[i, 1], 0) | (q[1], q[2]) Rgate(rtheta_2[i, 1]) | (q[1]) for j in range(size): Kgate(kappa[i, j]) | q[j]