def test_measure_arg_postselect(self): """Test measurement with argument and postselection converts""" # create a test program prog = Program(1) with prog.context as q: ops.MeasureHomodyne(0.43, select=0.543) | q[0] bb = io.to_blackbird(prog) expected = { "op": "MeasureHomodyne", "modes": [0], "args": [], "kwargs": { "phi": 0.43, "select": 0.543 }, } assert bb.operations[0] == expected # repeat with kwargs only prog = Program(1) with prog.context as q: ops.MeasureHomodyne(phi=0.43, select=0.543) | q[0] bb = io.to_blackbird(prog) assert bb.operations[0] == expected
def test_metadata_run_options(self): """Test run options correctly converts""" prog = Program(4, name="test_program") bb = io.to_blackbird(prog.compile(compiler="gaussian", shots=1024)) assert bb.name == "test_program" assert bb.version == "1.0" assert bb.target["name"] == "gaussian" assert bb.target["options"] == {"shots": 1024}
def test_program_with_options(self): """Test that program with options is correctly converted""" # create a test program sf_prog = Program(4, name="test_program") sf_prog.run_options = {"shots": 2} sf_prog.backend_options = {"cutoff_dim": 5} xir_prog = io.to_xir(sf_prog) assert xir_prog.options == {"_name_": "test_program", "cutoff_dim": 5, "shots": 2}
def from_blackbird(bb: blackbird.BlackbirdProgram) -> Program: """Convert a Blackbird program to a Strawberry Fields program. Args: bb (blackbird.BlackbirdProgram): the input Blackbird program object Returns: Program: corresponding Strawberry Fields program Raises: NameError: if an applied quantum operation is not defined in Strawberry Fields """ # create a SF program prog = Program(max(bb.modes) + 1, name=bb.name) # append the quantum operations with prog.context as q: for op in bb.operations: # check if operation name is in the list of # defined StrawberryFields operations. # This is used by checking against the ops.py __all__ # module attribute, which contains the names # of all defined quantum operations if op["op"] in ops.__all__: # get the quantum operation from the sf.ops module gate = getattr(ops, op["op"]) else: raise NameError("Quantum operation {} not defined!".format( op["op"])) # create the list of regrefs regrefs = [q[i] for i in op["modes"]] if "args" in op and "kwargs" in op: # the gate has arguments args = op["args"] kwargs = op["kwargs"] # Convert symbolic expressions in args/kwargs containing measured and free parameters to # symbolic expressions containing the corresponding MeasuredParameter and FreeParameter instances. args = sfpar.par_convert(args, prog) vals = sfpar.par_convert(kwargs.values(), prog) kwargs = dict(zip(kwargs.keys(), vals)) gate(*args, **kwargs) | regrefs # pylint:disable=expression-not-assigned else: # the gate has no arguments gate | regrefs # pylint:disable=expression-not-assigned,pointless-statement prog._target = bb.target["name"] if "shots" in bb.target["options"]: prog.run_options["shots"] = bb.target["options"]["shots"] if "cutoff_dim" in bb.target["options"]: prog.backend_options["cutoff_dim"] = bb.target["options"]["cutoff_dim"] return prog
def test_free_par_str(self): """Test a FreeParameter with some transformations converts properly""" prog = Program(2) r, alpha = prog.params('r', 'alpha') with prog.context as q: ops.Sgate(r) | q[0] ops.Zgate(3 * pf.log(-alpha)) | q[1] bb = io.to_blackbird(prog) assert bb.operations[0] == {"op": "Sgate", "modes": [0], "args": ['{r}', 0.0], "kwargs": {}} assert bb.operations[1] == {"op": "Zgate", "modes": [1], "args": ['3*log(-{alpha})'], "kwargs": {}}
def test_pre_measure_eng(self, tol): """Test that the pre_measure method operates as expected by initializing the engine correctly""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) prog.append(op1, prog.register) dev.prog = prog dev.pre_measure() assert dev.eng.backend_name == "gaussian" assert dev.eng.backend_options == {"cutoff_dim": 3}
def test_free_par_str(self): """Test a FreeParameter with some transformations converts properly""" sf_prog = Program(2) r, alpha = sf_prog.params("r", "alpha") with sf_prog.context as q: ops.Sgate(r) | q[0] ops.Zgate(3 * pf.log(-alpha)) | q[1] xir_prog = io.to_xir(sf_prog) expected = [("Sgate", ["r", 0.0], (0,)), ("Zgate", ["3*log(-alpha)"], (1,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_pre_measure_state_and_samples(self, tol): """Test that the pre_measure method operates as expected in analytic mode by generating the correct output state and not generating samples""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) prog.append(op1, prog.register) dev.prog = prog dev.pre_measure() assert np.allclose(dev.state.displacement(), np.zeros(4)) assert np.allclose(dev.state.cov(), target_cov, atol=tol) assert dev.samples.size == 0
def test_metadata(self): """Test metadata correctly converts""" # create a test program prog = Program(4, name="test_program") bb = io.to_blackbird(prog) assert bb.name == "test_program" assert bb.version == "1.0" assert bb.target["name"] is None bb = io.to_blackbird(prog.compile(compiler="gaussian")) assert bb.name == "test_program" assert bb.version == "1.0" assert bb.target["name"] == "gaussian"
def test_decomposition_operation_compiled(self): """Test decomposition operation gets decomposed if compiled""" # create a test program prog = Program(1) with prog.context as q: ops.Pgate(0.43) | q[0] bb = io.to_blackbird(prog) expected = {"op": "Pgate", "modes": [0], "args": [0.43], "kwargs": {}} assert bb.operations[0] == expected bb = io.to_blackbird(prog.compile(compiler="gaussian")) assert bb.operations[0]["op"] == "Sgate" assert bb.operations[1]["op"] == "Rgate"
def test_pre_measure_state_and_samples_non_analytic(self, tol): """Test that the pre_measure method operates as expected in non-analytic mode by generating the correct output state and samples of the right shape""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3, analytic=False, shots=2) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) op2 = MeasureFock() prog.append(op1, prog.register) prog.append(op2, prog.register) dev.prog = prog dev.pre_measure() assert np.allclose(dev.state.displacement(), np.zeros(4)) assert np.allclose(dev.state.cov(), target_cov, atol=tol) assert dev.samples.shape == (2, 4)
def test_complex_first_argument_error(self, gate): """Test that passing a complex parameter to gates that previously accepted complex parameters raises an error.""" with pytest.raises(ValueError, match="cannot be complex"): prog = Program(1) with prog.context as q: gate(0.2 + 1j) | q
def _setup_eng(num_subsystems, **kwargs): """Factory function""" prog = Program(num_subsystems) setup_backend_pars.update(kwargs) # override defaults with kwargs eng = Engine(backend=setup_backend_pars['backend_name'], **setup_backend_pars) return eng, prog
def _setup_eng(num_subsystems, **kwargs): """Factory function""" prog = Program(num_subsystems) backend, backend_options = setup_backend_pars backend_options.update(kwargs) # override defaults with kwargs eng = LocalEngine(backend=backend, backend_options=backend_options) return eng, prog
def test_decomposition_operation_compiled(self): """Test decomposition operation gets decomposed if compiled""" # create a test program sf_prog = Program(1) with sf_prog.context as q: ops.Pgate(0.43) | q[0] xir_prog = io.to_xir(sf_prog) expected = [("Pgate", [0.43], (0,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected xir_prog = io.to_xir(sf_prog.compile(compiler="gaussian")) assert xir_prog.statements[0].name == "Sgate" assert xir_prog.statements[1].name == "Rgate"
def test_empty_program(self): """Test that an empty program is correctly converted""" # create a test program sf_prog = Program(4, name="") xir_prog = io.to_xir(sf_prog) assert xir_prog.serialize() == "" assert xir_prog.version == "0.1.0"
def test_catstate_complex_error(self): """Test that passing a complex parameter to gates that previously accepted complex parameters raises an error.""" with pytest.raises(ValueError, match="cannot be complex"): prog = Program(1) with prog.context as q: ops.Catstate(0.2 + 1j) | q eng = Engine("fock", backend_options={"cutoff_dim": 5}) res = eng.run(prog)
def test_measured_par_str(self): """Test a MeasuredParameter with some transformations converts properly""" prog = Program(2) with prog.context as q: ops.Sgate(0.43) | q[0] ops.MeasureX | q[0] ops.Zgate(2 * pf.sin(q[0].par)) | q[1] bb = io.to_blackbird(prog) expected = {"op": "Zgate", "modes": [1], "args": ["2*sin(q0)"], "kwargs": {}} assert bb.operations[-1] == expected
def test_regref_no_func_str(self): """Test a regreftransform with no function string raises exception""" prog = Program(2) with prog.context as q: ops.Sgate(0.43) | q[0] ops.MeasureX | q[0] ops.Zgate(ops.RR(q[0], lambda x: 2 * x)) | q[1] with pytest.raises(ValueError, match="not supported by Blackbird"): io.to_blackbird(prog)
def test_tf_batch_in_gates_previously_supporting_complex(gate): """Test if gates that previously accepted complex arguments support the input of TF tensors in batch form""" tf = pytest.importorskip("tensorflow") batch_size = 2 prog = Program(1) eng = Engine(backend="tf", backend_options={ "cutoff_dim": 3, "batch_size": batch_size }) theta = prog.params("theta") _theta = tf.Variable([0.1] * batch_size) with prog.context as q: gate(theta) | q[0] eng.run(prog, args={"theta": _theta})
def test_two_mode_gate(self): """Test two mode gate converts""" sf_prog = Program(4) with sf_prog.context as q: ops.BSgate(0.54, -0.324) | (q[3], q[0]) xir_prog = io.to_xir(sf_prog) expected = [("BSgate", [0.54, -0.324], (3, 0))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_measure_noarg(self): """Test measurement with no argument converts""" # create a test program prog = Program(1) with prog.context as q: ops.MeasureFock() | q[0] bb = io.to_blackbird(prog) expected = {"op": "MeasureFock", "modes": [0], "args": [], "kwargs": {}} assert bb.operations[0] == expected
def test_gate_noarg(self): """Test gate with no argument converts""" # create a test program sf_prog = Program(1) with sf_prog.context as q: ops.Vac | q[0] xir_prog = io.to_xir(sf_prog) expected = [("Vacuum", [], (0,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_gate_arg(self): """Test gate with argument converts""" # create a test program sf_prog = Program(2) with sf_prog.context as q: ops.Sgate(0.54, 0.324) | q[1] xir_prog = io.to_xir(sf_prog) expected = [("Sgate", [0.54, 0.324], (1,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_measure_arg(self): """Test measurement with argument converts""" # create a test program sf_prog = Program(1) with sf_prog.context as q: ops.MeasureHomodyne(0.43) | q[0] xir_prog = io.to_xir(sf_prog) expected = [("MeasureHomodyne", {"phi": 0.43}, (0,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_gate_noarg(self): """Test gate with no argument converts""" # create a test program prog = Program(1) with prog.context as q: ops.Vac | q[0] bb = io.to_blackbird(prog) expected = {"op": "Vacuum", "modes": [0], "args": [], "kwargs": {}} assert bb.operations[0] == expected
def test_measure_postselect(self): """Test measurement with postselection""" # create a test program sf_prog = Program(1) with sf_prog.context as q: ops.MeasureFock(select=2) | q[0] xir_prog = io.to_xir(sf_prog) expected = [("MeasureFock", {"select": [2]}, (0,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_measure_darkcounts(self): """Test measurement with dark counts""" # create a test program sf_prog = Program(1) with sf_prog.context as q: ops.MeasureFock(dark_counts=2) | q[0] xir_prog = io.to_xir(sf_prog) expected = [("MeasureFock", {"dark_counts": [2]}, (0,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected
def test_tf_batch_complex_raise(gate): """Test if an error is raised if complex TF tensors with a batch dimension are input for gates that previously accepted complex arguments""" tf = pytest.importorskip("tensorflow") batch_size = 2 prog = Program(1) eng = Engine(backend="tf", backend_options={ "cutoff_dim": 3, "batch_size": batch_size }) theta = prog.params("theta") _theta = tf.Variable([0.1j] * batch_size) with prog.context as q: gate(theta) | q[0] with pytest.raises(ValueError, match="cannot be complex"): eng.run(prog, args={"theta": _theta})
def test_measure_arg_postselect(self): """Test measurement with argument and postselection converts""" # create a test program sf_prog = Program(1) with sf_prog.context as q: ops.MeasureHomodyne(0.43, select=0.543) | q[0] xir_prog = io.to_xir(sf_prog) expected = [("MeasureHomodyne", {"phi": 0.43, "select": 0.543}, (0,))] assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected # repeat with kwargs only sf_prog = Program(1) with sf_prog.context as q: ops.MeasureHomodyne(phi=0.43, select=0.543) | q[0] xir_prog = io.to_xir(sf_prog) assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected