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_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 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_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_random_inteferometer_is_unitary(self, modes, tol, real): """Test that a random interferometer is unitary""" U = utils.random_interferometer(modes, real=real) assert np.allclose(U @ U.conj().T, np.identity(modes), atol=tol, rtol=0)
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, 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_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_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_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_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_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, 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 sample_average_fidelity(V, U, cutoff, samples=10000): r"""The average fidelity between the two unitaries, calculated via Monte-Carlo integration. This function returns the following average fidelity: .. math:: \bar{F} = \frac{1}{N} \sum_{i=0}^{N} |\langle 0 \mid W_i^\dagger V^\dagger U(\vec{\theta}) W_i \mid 0\rangle|^2 where :math:`W_i` is a Haar-distributed random unitary, :math:`V` the target unitary, and :math:`U` the learnt unitary. The target unitary should be of shape [c**m, c**m], where m is the number of modes, and c is the simulation cutoff. The learnt unitary should be of shape [c**m, d**m], where m is the number of modes, c is the simulation cutoff, and d is unitary truncation. Args: V (array): the target unitary. U (array): the learnt unitary. cutoff (int): the simulation Fock basis truncation. samples (int): the number of samples to perform in the Monte-Carlo integration. Returns: float: Returns the sampled averaged fidelity :math:`\bar{F}`. """ # simulation cutoff c = cutoff # number of modes m = get_modes(V, c) # gate cutoff d = np.int(U.shape[1]**(1/m)) if m == 1: # single mode unitary # reshape the target unitary to be shape [c, d] Ut = V[:, :d] elif m == 2: # two mode unitary # reshape the target unitary to be shape [c^2, d^2] Ut = V.reshape(c, c, c, c)[:, :, :d, :d].reshape(c**2, d**2) fid = [] Wlist = [] for i in range(samples): W = random_interferometer(d**m) Wlist.append(W) f = np.abs(W[:, 0].conj().T @ Ut.conj().T @ U @ W[:, 0])**2 fid.append(f) return np.mean(fid)
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_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_unitary_too_large(self, chip): """Test exception raised if the unitary is applied to more than just modes [0, 1, 2, 3] and [4, 5, 6, 7].""" prog = sf.Program(12) U = random_interferometer(12) with prog.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) | q ops.MeasureFock() | q with pytest.raises(CircuitError, match="must be applied separately"): res = prog.compile(chip.short_name)
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_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): """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_unitary_too_large(self, num_pairs): """Test exception raised if the unitary is applied to more than just modes [0, 1, 2, 3, ..., num_pairs-1] and [num_pairs, num_pairs+1, ..., 2*num_pairs-1].""" prog = sf.Program(2 * num_pairs) U = random_interferometer(2 * 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) | q ops.MeasureFock() | q with pytest.raises(CircuitError, match="The applied unitary cannot mix between the modes"): res = prog.compile("Xunitary")
def test_unitary_too_large(self): """Test exception raised if the unitary is applied to more than just modes [0, 1] and [2, 3].""" prog = sf.Program(4) U = random_interferometer(4) 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 ops.BSgate() | (q[2], q[3]) ops.MeasureFock() | q with pytest.raises(CircuitError, match="must be applied separately"): res = prog.compile("chip0")
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_incorrect_s2gate_modes(self): """Test exceptions raised if S2gates do not appear on correct modes""" prog = sf.Program(8) U = random_interferometer(4) with prog.context as q: ops.S2gate(SQ_AMPLITUDE) | (q[0], q[1]) ops.S2gate(SQ_AMPLITUDE) | (q[2], q[3]) ops.S2gate(SQ_AMPLITUDE) | (q[4], q[5]) ops.S2gate(SQ_AMPLITUDE) | (q[7], q[6]) 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="S2gates do not appear on the correct modes"): res = prog.compile("X8_01")
def test_unitary_too_large(self): """Test exception raised if the unitary is applied to more than just modes [0, 1, 2, 3] and [4, 5, 6, 7].""" prog = sf.Program(8) U = random_interferometer(8) 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 ops.MeasureFock() | q with pytest.raises(CircuitError, match="must be applied separately"): res = prog.compile("X8_01")
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_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")