def test_missing_s2gates(self, chip, tol): """Test identity S2gates are inserted when some (but not all) S2gates are included.""" prog = sf.Program(12) U = random_interferometer(6) with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[1], q[7]) ops.S2gate(SQ_AMPLITUDE) | (q[3], q[9]) ops.S2gate(SQ_AMPLITUDE) | (q[5], q[11]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3], q[4], q[5]) ops.Interferometer(U) | (q[6], q[7], q[8], q[9], q[10], q[11]) ops.MeasureFock() | q expected = sf.Program(12) with expected.context as q: ops.S2gate(0) | (q[0], q[6]) ops.S2gate(SQ_AMPLITUDE) | (q[1], q[7]) ops.S2gate(0) | (q[2], q[8]) ops.S2gate(SQ_AMPLITUDE) | (q[3], q[9]) ops.S2gate(0) | (q[4], q[10]) ops.S2gate(SQ_AMPLITUDE) | (q[5], q[11]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3], q[4], q[5]) ops.Interferometer(U) | (q[6], q[7], q[8], q[9], q[10], q[11]) ops.MeasureFock() | q res = prog.compile(chip.short_name) expected = expected.compile(chip.short_name) assert program_equivalence(res, expected, atol=tol)
def test_interferometers(self, tol): """Test interferometers correctly decompose to MZ gates""" prog = sf.Program(4) U = random_interferometer(2) with prog.context as q: ops.S2gate(0.5) | (q[0], q[2]) ops.S2gate(0.5) | (q[1], q[3]) ops.Interferometer(U) | (q[0], q[1]) ops.Interferometer(U) | (q[2], q[3]) ops.MeasureFock() | q res = prog.compile("chip0") expected = sf.Program(4) with expected.context as q: ops.S2gate(0.5, 0) | (q[0], q[2]) ops.S2gate(0.5, 0) | (q[1], q[3]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | (q[0], q[1]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | (q[2], q[3]) ops.MeasureFock() | q expected = expected.compile(DummyCircuit()) assert program_equivalence(res, expected, atol=tol)
def test_missing_s2gates(self, num_pairs, tol): """Test identity S2gates are inserted when some (but not all) S2gates are included.""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) assert num_pairs > 3 with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[1], q[num_pairs + 1]) ops.S2gate(SQ_AMPLITUDE) | (q[3], q[num_pairs + 3]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q expected = sf.Program(2 * num_pairs) with expected.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[1], q[num_pairs + 1]) ops.S2gate(0) | (q[0], q[num_pairs + 0]) ops.S2gate(SQ_AMPLITUDE) | (q[3], q[num_pairs + 3]) ops.S2gate(0) | (q[2], q[num_pairs + 2]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q res = prog.compile("Xunitary") expected = expected.compile("Xunitary") assert program_equivalence(res, expected, atol=tol)
def test_no_s2gates(self, num_pairs, tol): """Test identity S2gates are inserted when no S2gates are provided.""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) with prog.context as q: ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q expected = sf.Program(2 * num_pairs) with expected.context as q: for i in range(num_pairs): ops.S2gate(0) | (q[i], q[i + num_pairs]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q # with pytest.raises(CircuitError, match="There can be no operations before the S2gates."): res = prog.compile("Xunitary") # with pytest.raises(CircuitError, match="There can be no operations before the S2gates."): expected = expected.compile("Xunitary") assert program_equivalence(res, expected, atol=tol)
def test_interferometers(self, num_pairs, tol): """Test that the compilation correctly decomposes the interferometer using the rectangular_symmetric mesh""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) with prog.context as q: for i in range(0, num_pairs): ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q res = prog.compile("Xunitary") expected = sf.Program(2 * num_pairs) with expected.context as q: for i in range(0, num_pairs): ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | tuple( q[i] for i in range(num_pairs) ) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | tuple( q[i] for i in range(num_pairs, 2 * num_pairs) ) ops.MeasureFock() | q expected = expected.compile(DummyCircuit()) # Note that since DummyCircuit() has a hard coded limit of 8 modes we only check for this number assert program_equivalence(res, expected, atol=tol, compare_params=False)
def test_interferometers(self, tol): """Test that the compilation correctly decomposes the interferometer using the rectangular_symmetric mesh""" prog = sf.Program(8) U = random_interferometer(4) with prog.context as q: ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[4]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[5]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[6]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[7]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | q res = prog.compile("X8_01") expected = sf.Program(8) with expected.context as q: ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[4]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[5]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[6]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[7]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | q expected = expected.compile(DummyCircuit()) assert program_equivalence(res, expected, atol=tol)
def test_no_s2gates(self, tol): """Test identity S2gates are inserted when no S2gates are provided.""" prog = sf.Program(8) U = random_interferometer(4) with prog.context as q: ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | q expected = sf.Program(8) with expected.context as q: ops.S2gate(0) | (q[0], q[4]) ops.S2gate(0) | (q[1], q[5]) ops.S2gate(0) | (q[2], q[6]) ops.S2gate(0) | (q[3], q[7]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | q res = prog.compile("X8_01") expected = expected.compile("X8_01") assert program_equivalence(res, expected, atol=tol)
def test_modes_subset(depth): """Tests that the compiler recognizes which modes are not being modified and acts accordingly""" width = 10 eng = sf.LocalEngine(backend="gaussian") eng1 = sf.LocalEngine(backend="gaussian") circuit = sf.Program(width) indices = (1, 4, 2, 6, 7) active_modes = len(indices) with circuit.context as q: for _ in range(depth): U, s, V, _ = random_params(active_modes, 2.0 / depth, 1.0) ops.Interferometer(U) | tuple(q[i] for i in indices) for i, index in enumerate(indices): ops.Sgate(s[i]) | q[index] ops.Interferometer(V) | tuple(q[i] for i in indices) compiled_circuit = circuit.compile(compiler="gaussian_unitary") cv = eng.run(circuit).state.cov() mean = eng.run(circuit).state.means() cv1 = eng1.run(compiled_circuit).state.cov() mean1 = eng1.run(compiled_circuit).state.means() assert np.allclose(cv, cv1) assert np.allclose(mean, mean1) assert len(compiled_circuit.circuit[0].reg) == 5 indices = [compiled_circuit.circuit[0].reg[i].ind for i in range(5)] assert indices == sorted(list(indices))
def runJob(self, eng): num_subsystem = 8 prog = sf.Program(num_subsystem, name="remote_job") U = random_interferometer(4) with prog.context as q: # Initial squeezed states # Allowed values are r=1.0 or r=0.0 ops.S2gate(1.0) | (q[0], q[4]) ops.S2gate(1.0) | (q[1], q[5]) ops.S2gate(1.0) | (q[3], q[7]) # Interferometer on the signal modes (0-3) ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.BSgate(0.543, 0.123) | (q[2], q[0]) ops.Rgate(0.453) | q[1] ops.MZgate(0.65, -0.54) | (q[2], q[3]) # *Same* interferometer on the idler modes (4-7) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.BSgate(0.543, 0.123) | (q[6], q[4]) ops.Rgate(0.453) | q[5] ops.MZgate(0.65, -0.54) | (q[6], q[7]) ops.MeasureFock() | q eng = eng results =eng.run(prog, shots=10) # state = results.state # measurements = results.samples return results.samples
def test_no_s2gates(self, num_pairs, tol): """Test identity S2gates are inserted when no S2gates are provided.""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) with prog.context as q: ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple( q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q expected = sf.Program(2 * num_pairs) with expected.context as q: for i in range(num_pairs): ops.S2gate(0) | (q[i], q[i + num_pairs]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple( q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q res = prog.compile(compiler="Xcov") expected = expected.compile(compiler="Xcov") assert program_equivalence(res, expected, atol=tol)
def test_interferometers(self, chip, tol): """Test that the compilation correctly decomposes the interferometer using the rectangular_symmetric mesh""" prog = sf.Program(12) U = random_interferometer(6) with prog.context as q: ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[6]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[7]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[8]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[9]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[4], q[10]) ops.S2gate(SQ_AMPLITUDE, 0) | (q[5], q[11]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3], q[4], q[5]) ops.Interferometer(U) | (q[6], q[7], q[8], q[9], q[10], q[11]) ops.MeasureFock() | q res = prog.compile(chip.short_name) expected = sf.Program(12) with expected.context as q: for i, j in np.arange(12).reshape(2, -1).T: ops.S2gate(SQ_AMPLITUDE, 0) | (q[i], q[j]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | (q[0], q[1], q[2], q[3], q[4], q[5]) ops.Interferometer(U, mesh="rectangular_symmetric", drop_identity=False) | (q[6], q[7], q[8], q[9], q[10], q[11]) ops.MeasureFock() | q expected = expected.compile(DummyCircuit()) assert program_equivalence(res, expected, atol=tol)
def test_all_passive_gates(hbar, tol): """test that all gates run and do not cause anything to crash""" eng = sf.LocalEngine(backend="gaussian") circuit = sf.Program(4) with circuit.context as q: for i in range(4): ops.Sgate(1, 0.3) | q[i] ops.Rgate(np.pi) | q[0] ops.PassiveChannel(np.ones((2, 2))) | (q[1], q[2]) ops.LossChannel(0.9) | q[1] ops.MZgate(0.25 * np.pi, 0) | (q[2], q[3]) ops.PassiveChannel(np.array([[0.83]])) | q[0] ops.sMZgate(0.11, -2.1) | (q[0], q[3]) ops.Interferometer(np.array([[np.exp(1j * 2)]])) | q[1] ops.BSgate(0.8, 0.4) | (q[1], q[3]) ops.Interferometer(0.5**0.5 * np.fft.fft(np.eye(2))) | (q[0], q[2]) ops.PassiveChannel(0.1 * np.ones((3, 3))) | (q[3], q[1], q[0]) cov = eng.run(circuit).state.cov() circuit = sf.Program(4) with circuit.context as q: ops.Rgate(np.pi) | q[0] ops.PassiveChannel(np.ones((2, 2))) | (q[1], q[2]) ops.LossChannel(0.9) | q[1] ops.MZgate(0.25 * np.pi, 0) | (q[2], q[3]) ops.PassiveChannel(np.array([[0.83]])) | q[0] ops.sMZgate(0.11, -2.1) | (q[0], q[3]) ops.Interferometer(np.array([[np.exp(1j * 2)]])) | q[1] ops.BSgate(0.8, 0.4) | (q[1], q[3]) ops.Interferometer(0.5**0.5 * np.fft.fft(np.eye(2))) | (q[0], q[2]) ops.PassiveChannel(0.1 * np.ones((3, 3))) | (q[3], q[1], q[0]) compiled_circuit = circuit.compile(compiler="passive") T = compiled_circuit.circuit[0].op.p[0] S_sq = np.eye(8, dtype=np.complex128) r = 1 phi = 0.3 for i in range(4): S_sq[i, i] = np.cosh(r) - np.sinh(r) * np.cos(phi) S_sq[i, i + 4] = -np.sinh(r) * np.sin(phi) S_sq[i + 4, i] = -np.sinh(r) * np.sin(phi) S_sq[i + 4, i + 4] = np.cosh(r) + np.sinh(r) * np.cos(phi) cov_sq = (hbar / 2) * S_sq @ S_sq.T mu = np.zeros(8) P = interferometer(T) L = (hbar / 2) * (np.eye(P.shape[0]) - P @ P.T) cov2 = P @ cov_sq @ P.T + L assert np.allclose(cov, cov2, atol=tol, rtol=0)
def test_no_s2gates(self): """Test exceptions raised if no S2gates are present""" prog = sf.Program(4) U = random_interferometer(2) with prog.context as q: ops.Interferometer(U) | (q[0], q[1]) ops.Interferometer(U) | (q[2], q[3]) ops.MeasureFock() | q with pytest.raises(CircuitError, match="must start with two S2gates"): res = prog.compile("chip0")
def test_not_all_modes_measured(self, num_pairs): """Test exceptions raised if not all modes are measured""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) with prog.context as q: for i in range(num_pairs): ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | (q[0], q[num_pairs]) with pytest.raises(CircuitError, match="All modes must be measured"): prog.compile("Xunitary")
def test_s2gate_repeated_modes(self): """Test exceptions raised if S2gates are repeated""" prog = sf.Program(8) U = random_interferometer(4) with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4]) ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | q with pytest.raises(CircuitError, match="incompatible topology."): res = prog.compile("X8_01")
def test_incorrect_s2gates(self): """Test exceptions raised if S2gates do not appear on correct modes""" prog = sf.Program(4) U = random_interferometer(2) with prog.context as q: ops.S2gate(0.5) | (q[0], q[2]) ops.Interferometer(U) | (q[0], q[1]) ops.Interferometer(U) | (q[2], q[3]) ops.MeasureFock() | q with pytest.raises(CircuitError, match="S2gates do not appear on the correct modes"): res = prog.compile("chip0")
def test_not_all_modes_measured(self): """Test exceptions raised if not all modes are measured""" prog = sf.Program(4) U = random_interferometer(2) with prog.context as q: ops.S2gate(0.5) | (q[0], q[2]) ops.S2gate(0.5) | (q[1], q[3]) ops.Interferometer(U) | (q[0], q[1]) ops.Interferometer(U) | (q[2], q[3]) ops.MeasureFock() | (q[0], q[1]) with pytest.raises(CircuitError, match="All modes must be measured"): res = prog.compile("chip0")
def test_s2gate_repeated_modes(self, chip): """Test exceptions raised if S2gates are repeated""" prog = sf.Program(12) U = random_interferometer(6) with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[0], q[6]) ops.S2gate(SQ_AMPLITUDE) | (q[0], q[6]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3], q[4], q[5]) ops.Interferometer(U) | (q[6], q[7], q[8], q[9], q[10], q[11]) ops.MeasureFock() | q with pytest.raises(CircuitError, match="incompatible topology."): res = prog.compile(chip.short_name)
def test_merge(self, tol): """Test that two interferometers merge: U = U1 @ U2""" n = 3 U1 = random_interferometer(n) U2 = random_interferometer(n) int1 = ops.Interferometer(U1) int1inv = ops.Interferometer(U1.conj().T) int2 = ops.Interferometer(U2) # an interferometer merged with its inverse is identity assert int1.merge(int1inv) is None # two merged unitaries are the same as their product assert np.allclose(int1.merge(int2).p[0].x, U2 @ U1, atol=tol, rtol=0)
def test_s2gate_repeated_modes(self, num_pairs): """Test exceptions raised if S2gates are repeated""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) with prog.context as q: for i in range(num_pairs): ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs]) ops.S2gate(SQ_AMPLITUDE + 0.1) | (q[0], q[num_pairs]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q with pytest.raises(CircuitError, match=r"Incorrect squeezing val"): prog.compile("Xunitary")
def test_incorrect_s2gate_modes(self, num_pairs): """Test exceptions raised if S2gates do not appear on correct modes""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) n_modes = 2 * num_pairs half_n_modes = n_modes // 2 with prog.context as q: for i in range(num_pairs): ops.S2gate(SQ_AMPLITUDE) | (q[2 * i], q[2 * i + 1]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.MeasureFock() | q with pytest.raises(CircuitError, match="S2gates do not appear on the correct modes."): res = prog.compile("Xunitary")
def test_decomposition(self, tol): """Test that an interferometer is correctly decomposed""" n = 3 prog = sf.Program(n) U = random_interferometer(n) BS1, BS2, R = dec.clements(U) G = ops.Interferometer(U) cmds = G.decompose(prog.register) S = np.identity(2 * n) # calculating the resulting decomposed symplectic for cmd in cmds: # all operations should be BSgates or Rgates assert isinstance(cmd.op, (ops.BSgate, ops.Rgate)) # build up the symplectic transform modes = [i.ind for i in cmd.reg] if isinstance(cmd.op, ops.Rgate): S = _rotation(cmd.op.p[0].x, modes, n) @ S if isinstance(cmd.op, ops.BSgate): S = _beamsplitter(cmd.op.p[0].x, cmd.op.p[1].x, modes, n) @ S # the resulting applied unitary X1 = S[:n, :n] P1 = S[n:, :n] U_applied = X1 + 1j * P1 assert np.allclose(U, U_applied, atol=tol, rtol=0)
def test_not_all_modes_measured(self): """Test exceptions raised if not all modes are measured""" prog = sf.Program(8) U = random_interferometer(4) with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4]) ops.S2gate(SQ_AMPLITUDE) | (q[1], q[5]) ops.S2gate(SQ_AMPLITUDE) | (q[2], q[6]) ops.S2gate(SQ_AMPLITUDE) | (q[3], q[7]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | (q[0], q[1]) with pytest.raises(CircuitError, match="All modes must be measured"): res = prog.compile("X8_01")
def test_unitaries_do_not_match(self, num_pairs): """Test exception raised if the unitary applied to modes [0, 1, 2, 3] is different to the unitary applied to modes [4, 5, 6, 7]""" prog = sf.Program(2 * num_pairs) U = random_interferometer(num_pairs) with prog.context as q: for i in range(0, num_pairs): ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs]) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs)) ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs, 2 * num_pairs)) ops.BSgate() | (q[2], q[3]) ops.MeasureFock() | q with pytest.raises(CircuitError, match="The applied unitary on modes"): prog.compile("Xunitary")
def test_invalid_decompositions(self, monkeypatch): """Test that an exception is raised if the device spec requests a decomposition that doesn't exist""" class DummyDevice(DeviceSpecs): modes = None remote = False local = True interactive = True primitives = {'Rgate', 'Interferometer'} decompositions = {'Rgate': {}} dev = DummyDevice() prog = sf.Program(3) U = np.array([[0, 1], [1, 0]]) with prog.context as q: ops.Rgate(0.6) | q[0] ops.Interferometer(U) | [q[0], q[1]] with monkeypatch.context() as m: # monkeypatch our DummyDevice into the # backend database db = {'dummy': DummyDevice} m.setattr("strawberryfields.devicespecs.backend_specs", db) with pytest.raises(NotImplementedError, match="No decomposition available: Rgate"): new_prog = prog.compile(backend='dummy')
def test_no_decompositions(self, monkeypatch): """Test that no decompositions take place if the device doesn't support it.""" class DummyDevice(DeviceSpecs): """A device with no decompositions""" modes = None remote = False local = True interactive = True primitives = {'S2gate', 'Interferometer'} decompositions = set() dev = DummyDevice() prog = sf.Program(3) U = np.array([[0, 1], [1, 0]]) with prog.context as q: ops.S2gate(0.6) | [q[0], q[1]] ops.Interferometer(U) | [q[0], q[1]] with monkeypatch.context() as m: # monkeypatch our DummyDevice into the # backend database db = {'dummy': DummyDevice} m.setattr("strawberryfields.devicespecs.backend_specs", db) new_prog = prog.compile(backend='dummy') # check compiled program only has two gates assert len(new_prog) == 2 # test gates are correct circuit = new_prog.circuit assert circuit[0].op.__class__.__name__ == "S2gate" assert circuit[1].op.__class__.__name__ == "Interferometer"
def test_incorrect_s2gate_params(self): """Test exceptions raised if S2gates have illegal parameters""" prog = sf.Program(8) U = random_interferometer(4) with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4]) ops.S2gate(0) | (q[1], q[5]) ops.S2gate(SQ_AMPLITUDE) | (q[2], q[6]) ops.S2gate(SQ_AMPLITUDE+0.1) | (q[3], q[7]) ops.Interferometer(U) | (q[0], q[1], q[2], q[3]) ops.Interferometer(U) | (q[4], q[5], q[6], q[7]) ops.MeasureFock() | q with pytest.raises(CircuitError, match=r"Incorrect squeezing value\(s\) \(r, phi\)={\(1.1, 0.0\)}"): res = prog.compile("X8_01")
def test_no_decompositions(self): """Test that no decompositions take place if the circuit spec doesn't support it.""" class DummyCircuit(CircuitSpecs): """A circuit spec with no decompositions""" modes = None remote = False local = True interactive = True primitives = {'S2gate', 'Interferometer'} decompositions = set() prog = sf.Program(3) U = np.array([[0, 1], [1, 0]]) with prog.context as q: ops.S2gate(0.6) | [q[0], q[1]] ops.Interferometer(U) | [q[0], q[1]] new_prog = prog.compile(target=DummyCircuit()) # check compiled program only has two gates assert len(new_prog) == 2 # test gates are correct circuit = new_prog.circuit assert circuit[0].op.__class__.__name__ == "S2gate" assert circuit[1].op.__class__.__name__ == "Interferometer"
def test_decompositions(self): """Test that decompositions take place if the circuit spec requests it.""" class DummyCircuit(CircuitSpecs): modes = None remote = False local = True interactive = True primitives = {'S2gate', 'Interferometer', 'BSgate', 'Sgate'} decompositions = {'S2gate': {}} prog = sf.Program(3) U = np.array([[0, 1], [1, 0]]) with prog.context as q: ops.S2gate(0.6) | [q[0], q[1]] ops.Interferometer(U) | [q[0], q[1]] new_prog = prog.compile(target=DummyCircuit()) # check compiled program now has 5 gates # the S2gate should decompose into two BS and two Sgates assert len(new_prog) == 5 # test gates are correct circuit = new_prog.circuit assert circuit[0].op.__class__.__name__ == "BSgate" assert circuit[1].op.__class__.__name__ == "Sgate" assert circuit[2].op.__class__.__name__ == "Sgate" assert circuit[3].op.__class__.__name__ == "BSgate" assert circuit[4].op.__class__.__name__ == "Interferometer"
def test_nothing_happens_and_nothing_crashes(self): """Test that even a program that does nothing compiles correctly""" n_modes = 4 squeezing_amplitudes = [0] * n_modes unitary = np.identity(n_modes) prog = sf.Program(n_modes * 2) with prog.context as q: for i in range(n_modes): ops.S2gate(squeezing_amplitudes[i]) | (q[i], q[i + n_modes]) for qumodes in (q[:n_modes], q[n_modes:]): ops.Interferometer(unitary) | qumodes ops.MeasureFock() | q res = prog.compile(compiler="Xcov") # check that all squeezing is 0 assert all(cmd.op.p[0] == 0 for cmd in res.circuit if isinstance(cmd.op, ops.S2gate)) # check that all phase shifts are 0 assert all(cmd.op.p[0] == 0 for cmd in res.circuit if isinstance(cmd.op, ops.Rgate)) # check that all MZgate angles are pi assert all(cmd.op.p[0] == np.pi for cmd in res.circuit if isinstance(cmd.op, ops.MZgate))