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 from_xir(xir_prog: xir.Program) -> Program: """Convert an XIR Program to a Strawberry Fields program. Args: xir_prog (xir.Program): the input XIR program object Returns: Program: corresponding Strawberry Fields program Raises: ValueError: if the XIR program is empty """ # only script-level statements are part of `xir_prog.statements`, which can only have integer # wires, leading to `xir_prog.wires` only containing integer wire labels if not xir_prog.wires: raise ValueError("The XIR program is empty and cannot be transformed " "into a Strawberry Fields program.") num_of_modes = int(max(xir_prog.wires)) + 1 name = xir_prog.options.get("_name_", "sf_from_xir") prog = Program(num_of_modes, name=name) # append the quantum operations with prog.context as q: for op in get_expanded_statements(xir_prog): # 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.name in ops.__all__: # get the quantum operation from the sf.ops module gate = getattr(ops, op.name) else: raise NameError(f"Quantum operation {op.name!r} not defined!") # create the list of regrefs regrefs = [q[i] for i in op.wires] if op.params: # convert symbolic expressions to symbolic expressions containing the corresponding # MeasuredParameter and FreeParameter instances. if isinstance(op.params, dict): vals = sfpar.par_convert(op.params.values(), prog) params = dict(zip(op.params.keys(), vals)) gate(**params) | regrefs # pylint:disable=expression-not-assigned else: params = [] for p in op.params: if isinstance(p, Decimal): params.append(float(p)) elif isinstance(p, Iterable): params.append(np.array(_listr(p))) else: params.append(p) params = sfpar.par_convert(params, prog) gate(*params) | regrefs # pylint:disable=expression-not-assigned else: gate() | regrefs # pylint:disable=expression-not-assigned,pointless-statement prog._target = xir_prog.options.get("_target_", None) # pylint: disable=protected-access if "shots" in xir_prog.options: prog.run_options["shots"] = xir_prog.options["shots"] if "cutoff_dim" in xir_prog.options: prog.backend_options["cutoff_dim"] = xir_prog.options["cutoff_dim"] return prog