Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
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("chip2")
"""Test 50-50 BSgates correctly compile"""
prog = sf.Program(4)
with prog.context as q:
ops.S2gate(0.5) | (q[0], q[2])
ops.S2gate(0.5) | (q[1], q[3])
ops.BSgate() | (q[0], q[1])
ops.BSgate() | (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])
# corresponds to BSgate() on modes [0, 1]
ops.Rgate(0) | (q[0])
ops.BSgate(np.pi / 4, np.pi / 2) | (q[0], q[1])
ops.Rgate(3 * np.pi / 2) | (q[0])
ops.BSgate(np.pi / 4, np.pi / 2) | (q[0], q[1])
ops.Rgate(3 * np.pi / 4) | (q[0])
ops.Rgate(-np.pi / 4) | (q[1])
# corresponds to BSgate() on modes [2, 3]
ops.Rgate(0) | (q[2])
ops.BSgate(np.pi / 4, np.pi / 2) | (q[2], q[3])
ops.Rgate(3 * np.pi / 2) | (q[2])
ops.BSgate(np.pi / 4, np.pi / 2) | (q[2], q[3])
ops.Rgate(3 * np.pi / 4) | (q[2])
prog = sf.Program(4)
with prog.context as q:
ops.S2gate(0.5) | (q[0], q[2])
ops.S2gate(0.5) | (q[1], q[3])
ops.MeasureFock() | q
res = prog.compile("chip0")
for cmd in res.circuit:
print(cmd)
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])
# corresponds to an identity on modes [0, 1]
ops.Rgate(0) | q[0]
ops.BSgate(np.pi / 4, np.pi / 2) | (q[0], q[1])
ops.Rgate(np.pi) | q[0]
ops.BSgate(np.pi / 4, np.pi / 2) | (q[0], q[1])
ops.Rgate(np.pi) | q[0]
ops.Rgate(0) | q[1]
# corresponds to an identity on modes [2, 3]
ops.Rgate(0) | q[2]
ops.BSgate(np.pi / 4, np.pi / 2) | (q[2], q[3])
ops.Rgate(np.pi) | q[2]
ops.BSgate(np.pi / 4, np.pi / 2) | (q[3], q[2])
ops.Rgate(np.pi) | q[2]
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 SF_expectation_reference(sf_expectation, wires, num_wires, *args):
"""SF reference circuit for expectation tests"""
eng = sf.Engine("gaussian")
# Allows returning the variance of tensor number for 3 modes
prog = sf.Program(num_wires)
with prog.context as q:
sf.ops.Dgate(0.1) | q[0]
sf.ops.S2gate(0.1) | (q[0], q[1])
state = eng.run(prog).state
return sf_expectation(state, wires, args)[0]
def test_heterodyne(self, setup_eng, tol):
"""Test that heterodyne detection on a TMS state
returns post-selected value."""
alpha = 0.43 - 0.12j
r = 5
eng, prog = setup_eng(2)
with prog.context as q:
ops.S2gate(r) | q
ops.MeasureHeterodyne(select=alpha) | q[0]
eng.run(prog)
assert np.allclose(q[0].val, alpha, atol=tol, rtol=0)
def SF_gate_reference(sf_op, wires, *args):
"""SF reference circuit for gate tests"""
eng = sf.Engine("gaussian")
prog = sf.Program(2)
with prog.context as q:
sf.ops.S2gate(0.1) | q
sf_op(*args) | [q[i] for i in wires]
state = eng.run(prog).state
return state.mean_photon(0)[0], state.mean_photon(1)[0]
def test_S2gate_decomp_equal(self, setup_eng, r, tol):
"""Tests that the S2gate gives the same transformation as its decomposition."""
eng, prog = setup_eng(2)
phi = 0.273
BS = ops.BSgate(np.pi / 4, 0)
with prog.context as q:
ops.S2gate(r, phi) | q
# run decomposition with reversed arguments
BS | q
ops.Sgate(-r, phi) | q[0]
ops.Sgate(r, phi) | q[1]
BS.H | q
eng.run(prog)
assert np.all(eng.backend.is_vacuum(tol))
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 = [i.x for i in cmd.op.p]
assert -r in sq
assert phi == 0
S = _two_mode_squeezing(r, phi, modes, 2*n) @ S
allowed_sq_value = {(0.0, 0.0), (self.sq_amplitude, 0.0)}
sq_params = {(float(np.round(cmd.op.p[0], 3)), float(cmd.op.p[1])) for cmd in B}
if not sq_params.issubset(allowed_sq_value):
wrong_params = sq_params - allowed_sq_value
raise CircuitError(
"Incorrect squeezing value(s) (r, phi)={}. Allowed squeezing "
"value(s) are (r, phi)={}.".format(wrong_params, allowed_sq_value)
)
# determine which modes do not have input S2gates specified
missing = allowed_modes - regrefs
for i, j in missing:
# insert S2gates with 0 squeezing
seq.insert(0, Command(ops.S2gate(0, 0), [registers[i], registers[j]]))
# Check if matches the circuit template
# --------------------------------------------
# This will avoid superfluous unitary compilation.
try:
seq = super().compile(seq, registers)
except CircuitError:
# failed topology check. Continue to more general
# compilation below.
pass
else:
return seq
# Compile the unitary: combine and then decompose all unitaries
# -------------------------------------------------------------
A, B, C = group_operations(seq, lambda x: isinstance(x, (ops.Rgate, ops.BSgate, ops.MZgate)))