def test_gate_not_defined(self): """Test unknown gate raises error""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("np", [1, 2, 3], (0,))) with pytest.raises(NameError, match="operation 'np' not defined"): io.to_program(xir_prog)
def test_empty_program(self): """Test empty program raises error""" xir_prog = xir.Program() with pytest.raises( ValueError, match="is empty and cannot be transformed into a Strawberry Fields program" ): io.to_program(xir_prog)
def test_tdm_program(self): """Test converting a TDM XIR program to a TDMProgram""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("Sgate", [0.7, 0], (1,))) xir_prog.add_statement(xir.Statement("BSgate", ["p0", 0.0], (0, 1))) xir_prog.add_statement(xir.Statement("Rgate", ["p1"], (1,))) xir_prog.add_statement(xir.Statement("MeasureHomodyne", {"phi": "p2"}, (0,))) xir_prog.add_constant("p0", [1, 2]) xir_prog.add_constant("p1", [3, 4]) xir_prog.add_constant("p2", [5, 6]) xir_prog.add_option("_type_", "tdm") xir_prog.add_option("N", [2]) xir_prog.add_option("shots", 3) sf_prog = io.to_program(xir_prog) assert isinstance(sf_prog, TDMProgram) assert sf_prog.run_options == {"shots": 3} assert len(sf_prog) == 4 assert sf_prog.circuit assert sf_prog.circuit[0].op.__class__.__name__ == "Sgate" assert sf_prog.circuit[0].op.p[0] == 0.7 assert sf_prog.circuit[0].op.p[1] == 0 assert sf_prog.circuit[0].reg[0].ind == 1 assert sf_prog.circuit[1].op.__class__.__name__ == "BSgate" assert sf_prog.circuit[1].op.p[0] == FreeParameter("p0") assert sf_prog.circuit[1].op.p[1] == 0.0 assert sf_prog.circuit[1].reg[0].ind == 0 assert sf_prog.circuit[1].reg[1].ind == 1 assert sf_prog.circuit[2].op.__class__.__name__ == "Rgate" assert sf_prog.circuit[2].op.p[0] == FreeParameter("p1") assert sf_prog.circuit[2].reg[0].ind == 1 assert sf_prog.circuit[3].op.__class__.__name__ == "MeasureHomodyne" assert sf_prog.circuit[3].op.p[0] == FreeParameter("p2") assert sf_prog.circuit[3].reg[0].ind == 0 assert sf_prog.concurr_modes == 2 assert sf_prog.timebins == 2 assert sf_prog.spatial_modes == 1 assert sf_prog.free_params == { "p0": FreeParameter("p0"), "p1": FreeParameter("p1"), "p2": FreeParameter("p2"), } assert all(sf_prog.tdm_params[0] == np.array([1, 2])) assert all(sf_prog.tdm_params[1] == np.array([3, 4])) assert all(sf_prog.tdm_params[2] == np.array([5, 6]))
def test_gate_no_arg(self): """Test gate with no argument converts""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("Vacuum", [], (0,))) sf_prog = io.to_program(xir_prog) assert len(sf_prog) == 1 assert sf_prog.circuit assert sf_prog.circuit[0].op.__class__.__name__ == "Vacuum" assert sf_prog.circuit[0].reg[0].ind == 0
def test_gate_kwarg(self): """Test gate with keyword argument converts""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("Dgate", {"r": 0.54, "phi": 0}, (0,))) sf_prog = io.to_program(xir_prog) assert len(sf_prog) == 1 assert sf_prog.circuit assert sf_prog.circuit[0].op.__class__.__name__ == "Dgate" assert sf_prog.circuit[0].op.p[0] == 0.54 assert sf_prog.circuit[0].reg[0].ind == 0
def test_program_with_options(self): """Test program with options raises error""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("Vacuum", [], (0,))) xir_prog.add_option("cutoff_dim", 5) xir_prog.add_option("shots", 3) sf_prog = io.to_program(xir_prog) assert sf_prog.run_options == {"shots": 3} assert sf_prog.backend_options == {"cutoff_dim": 5}
def test_gate_arg(self): """Test gate with arguments converts""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("Sgate", [0.54, 0.12], (0,))) sf_prog = io.to_program(xir_prog) assert len(sf_prog) == 1 assert sf_prog.circuit assert sf_prog.circuit[0].op.__class__.__name__ == "Sgate" assert sf_prog.circuit[0].op.p[0] == 0.54 assert sf_prog.circuit[0].op.p[1] == 0.12 assert sf_prog.circuit[0].reg[0].ind == 0
def test_gate_multimode(self): """Test multimode gate converts""" xir_prog = xir.Program() xir_prog.add_statement(xir.Statement("BSgate", {"theta": 0.54, "phi": np.pi}, (0, 2))) sf_prog = io.to_program(xir_prog) assert len(sf_prog) == 1 assert sf_prog.circuit assert sf_prog.circuit[0].op.__class__.__name__ == "BSgate" assert sf_prog.circuit[0].op.p[0] == 0.54 assert sf_prog.circuit[0].op.p[1] == np.pi assert sf_prog.circuit[0].reg[0].ind == 0 assert sf_prog.circuit[0].reg[1].ind == 2
def test_gate_not_defined_tdm(self): """Test unknown gate in a TDM program raises error""" xir_prog = xir.Program() xir_prog.add_constant("p0", [1, 2]) xir_prog.add_constant("p1", [3, 4]) xir_prog.add_constant("p2", [5, 6]) xir_prog.add_option("_type_", "tdm") xir_prog.add_option("N", [2]) xir_prog.add_statement(xir.Statement("np", [1, 2, 3], (0,))) with pytest.raises(NameError, match="operation 'np' not defined"): io.to_program(xir_prog)
def to_xir(prog: Program, **kwargs) -> xir.Program: """Convert a Strawberry Fields Program to an XIR Program. Args: prog (Program): the Strawberry Fields program Keyword Args: add_decl (bool): Whether gate and output declarations should be added to the XIR program. Default is ``False``. Returns: xir.Program """ xir_prog = xir.Program() add_decl = kwargs.get("add_decl", False) if isinstance(prog, TDMProgram): xir_prog.add_option("_type_", "tdm") xir_prog.add_option("N", prog.N) for i, p in enumerate(prog.tdm_params): xir_prog.add_constant(f"p{i}", _listr(p)) if prog.name: xir_prog.add_option("_name_", prog.name) if prog.target: xir_prog.add_option("target", prog.target) # pylint: disable=protected-access if "cutoff_dim" in prog.backend_options: xir_prog.add_option("cutoff_dim", prog.backend_options["cutoff_dim"]) if "shots" in prog.run_options: xir_prog.add_option("shots", prog.run_options["shots"]) # fill in the quantum circuit for cmd in prog.circuit or []: name = cmd.op.__class__.__name__ wires = tuple(i.ind for i in cmd.reg) if "Measure" in name: if add_decl: output_decl = xir.Declaration(name, type_="out", wires=wires) xir_prog.add_declaration(output_decl) params = {} if cmd.op.p: # argument is quadrature phase a = cmd.op.p[0] if a in getattr(prog, "loop_vars", ()): params["phi"] = a.name else: params["phi"] = a # special case to take into account 'select' keyword argument if cmd.op.select is not None: params["select"] = cmd.op.select if name == "MeasureFock": # special case to take into account 'dark_counts' keyword argument if cmd.op.dark_counts is not None: params["dark_counts"] = cmd.op.dark_counts else: if add_decl: if name not in [ gdecl.name for gdecl in xir_prog.declarations["gate"] ]: params = [f"p{i}" for i, _ in enumerate(cmd.op.p)] gate_decl = xir.Declaration(name, type_="gate", params=params, wires=tuple(range(len(wires)))) xir_prog.add_declaration(gate_decl) params = [] for i, a in enumerate(cmd.op.p): if sfpar.par_is_symbolic(a): # try to evaluate symbolic parameter try: a = sfpar.par_evaluate(a) except sfpar.ParameterError: # if a tdm param if a in getattr(prog, "loop_vars", ()): a = a.name # if a pure symbol (free parameter), convert to string elif a.is_symbol: a = a.name # else, assume it's a symbolic function and replace all free parameters # with string representations else: symbolic_func = a.copy() for s in symbolic_func.free_symbols: symbolic_func = symbolic_func.subs(s, s.name) a = str(symbolic_func) elif isinstance(a, str): pass elif isinstance(a, Iterable): # if an iterable, make sure it only consists of lists and Python types a = _listr(a) params.append(a) op = xir.Statement(name, params, wires) xir_prog.add_statement(op) return xir_prog