def from_xir_to_tdm(xir_prog: xir.Program) -> TDMProgram: """Convert an XIR Program to a ``TDMProgram``. Args: xir_prog (xir.Program): the input XIR program object Returns: TDMProgram: corresponding ``TDMProgram`` Raises: ValueError: if the number of modes 'N' is missing from the XIR program options NameError: if an applied quantum operation is not defined in Strawberry Fields """ N = xir_prog.options.get("N") if not N: raise ValueError( "Number of modes 'N' is missing from the XIR program options.") prog = TDMProgram(N, name=xir_prog.options.get("_name_", "xir")) # extract the tdm gate arguments from the xir program constants args = [val for key, val in xir_prog.constants.items() if is_ptype(key)] # convert arguments to float/complex if stored as Decimal/DecimalComplex objects for i, params in enumerate(args): for j, p in enumerate(params): if isinstance(p, Decimal): args[i][j] = float(p) elif isinstance(p, xir.DecimalComplex): args[i][j] = complex(p) # append the quantum operations with prog.context(*args) as (p, 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[int(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)) for key, val in params.items(): if is_ptype(val): params[key] = p[int(val[1:])] gate(**params) | regrefs # pylint:disable=expression-not-assigned else: params = [] for param in op.params: if isinstance(param, Decimal): params.append(float(param)) elif isinstance(param, (list, np.ndarray)): params.append(np.array(_listr(param))) elif isinstance(param, str) and is_ptype(param): params.append(p[int(param[1:])]) else: params.append(param) 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"] return prog
def from_blackbird_to_tdm(bb: blackbird.BlackbirdProgram) -> TDMProgram: """Convert a ``BlackbirdProgram`` to a ``TDMProgram``. Args: bb (blackbird.BlackbirdProgram): the input Blackbird program object Returns: TDMProgram: corresponding ``TDMProgram`` Raises: NameError: if an applied quantum operation is not defined in Strawberry Fields """ prog = TDMProgram(max(bb.modes) + 1, name=bb.name) def is_free_param(param): return isinstance(param, str) and is_ptype(param) # retrieve all the free parameters in the Blackbird program (e.g. "p0", "p1" # etc.) and add their corresponding values to args args = [] for k in bb._var.keys(): if is_free_param(k): v = bb._var[k].flatten() args.append(v) # append the quantum operations with prog.context(*args) as (p, 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: # the gate has arguments args = op["args"] kwargs = op["kwargs"] for i, p in enumerate(args): if is_free_param(p): args[i] = sfpar.FreeParameter(p) for k, v in kwargs.items(): if is_free_param(v): kwargs[k] = sfpar.FreeParameter(v) # 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