コード例 #1
0
    def test_gate_measured_par(self):
        """Test a gate with a MeasuredParameter argument."""

        bb_script = """\
        name test_program
        version 1.0

        MeasureX | 0
        Dgate(q0) | 1
        Rgate(2*q0) | 2
        """
        bb = blackbird.loads(bb_script)
        prog = io.to_program(bb)

        assert len(prog) == 3

        cmd = prog.circuit[1]
        assert cmd.op.__class__.__name__ == "Dgate"
        p = cmd.op.p[0]
        assert isinstance(p, MeasuredParameter)
        assert p.regref.ind == 0
        assert cmd.reg[0].ind == 1

        cmd = prog.circuit[2]
        assert cmd.op.__class__.__name__ == "Rgate"
        p = cmd.op.p[0]
        assert par_is_symbolic(p)  # symbolic expression
        assert cmd.reg[0].ind == 2
コード例 #2
0
    def test_gate_free_par(self):
        """Test a FreeParameter with some transformations converts properly"""

        bb_script = """\
        name test_program
        version 1.0

        Dgate(1-{ALPHA}, 0) | 0     # keyword arg, compound expr
        Rgate(theta={foo_bar1}) | 0  # keyword arg, atomic
        Dgate({ALPHA}**2, 0) | 0        # positional arg, compound expr
        Rgate({foo_bar2}) | 0        # positional arg, atomic
        """
        bb = blackbird.loads(bb_script)
        prog = io.to_program(bb)

        assert prog.free_params.keys() == set(
            ["foo_bar1", "foo_bar2", "ALPHA"])
        assert len(prog) == 4
        assert prog.circuit

        cmd = prog.circuit[0]
        assert cmd.op.__class__.__name__ == "Dgate"
        p = cmd.op.p[0]
        assert par_is_symbolic(p)
        assert cmd.reg[0].ind == 0

        cmd = prog.circuit[1]
        assert cmd.op.__class__.__name__ == "Rgate"
        p = cmd.op.p[0]
        assert isinstance(p, FreeParameter)
        assert p.name == "foo_bar1"
        assert cmd.reg[0].ind == 0

        cmd = prog.circuit[2]
        assert cmd.op.__class__.__name__ == "Dgate"
        p = cmd.op.p[0]
        assert par_is_symbolic(p)
        assert cmd.reg[0].ind == 0

        cmd = prog.circuit[3]
        assert cmd.op.__class__.__name__ == "Rgate"
        p = cmd.op.p[0]
        assert isinstance(p, FreeParameter)
        assert p.name == "foo_bar2"
        assert cmd.reg[0].ind == 0
コード例 #3
0
    def apply_op(self, cmd, modes, t):
        """Apply a particular operation on register q at timestep t."""
        params = cmd.op.p.copy()

        for i, _ in enumerate(params):
            if par_is_symbolic(params[i]):
                params[i] = self.parameters[params[i].name][t % self.timebins]

        self.append(cmd.op.__class__(*params), modes)
コード例 #4
0
    def apply_op(self, cmd, q, t):
        """Apply a particular operation on register q at timestep t"""
        params = cmd.op.p.copy()

        if par_is_symbolic(params[0]):
            arg_index = int(params[0].name[1:])
            params[0] = self.tdm_params[arg_index][t % self.timebins]

        self.append(cmd.op.__class__(*params), get_modes(cmd, q))
コード例 #5
0
def to_blackbird(prog, version="1.0"):
    """Convert a Strawberry Fields Program to a Blackbird Program.

    Args:
        prog (Program): the Strawberry Fields program
        version (str): Blackbird script version number

    Returns:
        blackbird.BlackbirdProgram:
    """
    bb = blackbird.BlackbirdProgram(name=prog.name, version=version)

    # TODO not sure if this makes sense: the program has *already been* compiled using this target
    if prog.target is not None:
        # set the target
        bb._target["name"] = prog.target

        # set the run options
        if prog.run_options:
            bb._target["options"].update(prog.run_options)

        if prog.backend_options:
            bb._target["options"].update(prog.backend_options)

    # fill in the quantum circuit
    for cmd in prog.circuit:
        op = {"kwargs": {}, "args": []}

        op["op"] = cmd.op.__class__.__name__
        op["modes"] = [i.ind for i in cmd.reg]

        if "Measure" in op["op"]:
            # special case to take into account 'select' keyword argument
            if cmd.op.select is not None:
                op["kwargs"]["select"] = cmd.op.select

            if cmd.op.p:
                # argument is quadrature phase
                op["kwargs"]["phi"] = cmd.op.p[0]

            if op["op"] == "MeasureFock":
                # special case to take into account 'dark_counts' keyword argument
                if cmd.op.dark_counts is not None:
                    op["kwargs"]["dark_counts"] = cmd.op.dark_counts

        else:
            for a in cmd.op.p:
                if sfpar.par_is_symbolic(a):
                    # SymPy object, convert to string
                    a = str(a)
                op["args"].append(a)

        bb._operations.append(op)

    return bb
コード例 #6
0
    def test_par_is_symbolic(self, r):
        """Recognizing symbolic parameters."""
        p = FreeParameter("x")
        q = MeasuredParameter(RegRef(0))

        assert not par_is_symbolic(r)
        assert par_is_symbolic(pf.sin(r))
        assert par_is_symbolic(q)
        assert par_is_symbolic(p)
        assert par_is_symbolic(pf.sin(p))
        assert par_is_symbolic(p + r)
        assert par_is_symbolic(p - r)
        assert par_is_symbolic(p * r)
        assert par_is_symbolic(p / r)
        assert par_is_symbolic(p**r)
        assert par_is_symbolic(p - p)  # no simplification

        # object array with symbols
        a = np.array([[0.1, 3, 0], [0.3, 2, p], [1, 2, 4]])
        assert a.dtype == object
        assert par_is_symbolic(a)

        # object array, no symbols
        a = np.array([[0.1, 3, 0], [0.3, 2, 0], [1, 2, 4]], dtype=object)
        assert a.dtype == object
        assert not par_is_symbolic(a)

        # float array, no symbols
        a = np.array([[0.1, 3, 0], [0.3, 2, 0], [1, 2, 4]])
        assert a.dtype != object
        assert not par_is_symbolic(a)
        assert par_is_symbolic(pf.sin(a))
コード例 #7
0
def to_blackbird(prog: Program,
                 version: str = "1.0") -> blackbird.BlackbirdProgram:
    """Convert a Strawberry Fields Program to a Blackbird Program.

    Args:
        prog (Program): the Strawberry Fields program
        version (str): Blackbird script version number

    Returns:
        blackbird.BlackbirdProgram:
    """
    bb = blackbird.BlackbirdProgram(name=prog.name, version=version)
    bb._modes = set(prog.reg_refs.keys())

    isMeasuredParameter = lambda x: isinstance(x, sfpar.MeasuredParameter)

    # not sure if this makes sense: the program has *already been* compiled using this target
    if prog.target is not None:
        # set the target
        bb._target["name"] = prog.target

        # set the run options
        if prog.run_options:
            bb._target["options"].update(prog.run_options)

        if prog.backend_options:
            bb._target["options"].update(prog.backend_options)

    # fill in the quantum circuit
    for cmd in prog.circuit:
        op = {"kwargs": {}, "args": []}

        op["op"] = cmd.op.__class__.__name__
        op["modes"] = [i.ind for i in cmd.reg]

        if "Measure" in op["op"]:
            # special case to take into account 'select' keyword argument
            if cmd.op.select is not None:
                op["kwargs"]["select"] = cmd.op.select

            if cmd.op.p:
                # argument is quadrature phase
                op["args"] = cmd.op.p

            if op["op"] == "MeasureFock":
                # special case to take into account 'dark_counts' keyword argument
                if cmd.op.dark_counts is not None:
                    op["kwargs"]["dark_counts"] = cmd.op.dark_counts

        else:
            for a in cmd.op.p:
                if sfpar.par_is_symbolic(a):
                    # SymPy object, convert to string
                    if any(map(isMeasuredParameter, a.free_symbols)):
                        # check if there are any measured parameters in `a`
                        a = blackbird.RegRefTransform(a)
                    else:
                        a = str(a)
                op["args"].append(a)

        # If program is a TDMProgram then add the looped-over arrays to the
        # blackbird program. `prog.loop_vars` are symbolic parameters (e.g.
        # `{p0}`), which should be replaced with `p.name` (e.g. `p0`) inside the
        # Blackbird operation (keyword) arguments.
        if isinstance(prog, TDMProgram):
            for p in prog.loop_vars:
                for i, ar in enumerate(op["args"]):
                    if str(p) == str(ar):
                        op["args"][i] = p.name
                for k, v in op["kwargs"].items():
                    if str(p) == str(v):
                        op["kwargs"][k] = p.name

        bb._operations.append(op)
    # add the specific "tdm" metadata to the Blackbird program
    if isinstance(prog, TDMProgram):
        bb._type["name"] = "tdm"
        bb._type["options"].update({
            "temporal_modes": prog.timebins,
        })
        bb._var.update({
            f"{p.name}": np.array([prog.tdm_params[i]])
            for i, p in enumerate(prog.loop_vars)
        })

    return bb
コード例 #8
0
ファイル: xir_io.py プロジェクト: XanaduAI/strawberryfields
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
コード例 #9
0
    def compile(self, *, device=None, compiler=None):
        """Compile the time-domain program given a Strawberry Fields photonic hardware device
        specification.

        The compilation checks that the program matches the device and sets the compile information
        and the program target to the correct device target.

        Args:
            device (~strawberryfields.DeviceSpec): device specification object to use for
                program compilation
            compiler (str, ~strawberryfields.compilers.Compiler): Compiler name or compile strategy
                to use. If a device is specified, this overrides the compile strategy specified by
                the hardware :class:`~.DeviceSpec`. If no compiler is passed, the default TDM
                compiler is used. Currently, the only other allowed compilers are "gaussian" and
                "passive".

        Returns:
            Program: compiled program
        """
        alt_compilers = ("gaussian", "passive")
        if compiler != "TDM":
            if compiler in alt_compilers or getattr(
                    device, "default_compiler") in alt_compilers:
                return super().compile(device=device, compiler=compiler)

        if device is not None:
            device_layout = bb.loads(device.layout)

            if device_layout.programtype["name"] != "tdm":
                raise TypeError(
                    'TDM compiler only supports "tdm" type device specification layouts. '
                    "Received {} type.".format(
                        device_layout.programtype["name"]))

            if device.modes is not None:
                self.assert_number_of_modes(device)

            # First check: the gates are in the correct order
            program_gates = [
                cmd.op.__class__.__name__ for cmd in self.rolled_circuit
            ]
            device_gates = [op["op"] for op in device_layout.operations]
            if device_gates != program_gates:
                raise CircuitError(
                    "The gates or the order of gates used in the Program is incompatible with the device '{}' "
                    .format(device.target))

            # Second check: the gates act on the correct modes
            program_modes = [[r.ind for r in cmd.reg]
                             for cmd in self.rolled_circuit]
            device_modes = [op["modes"] for op in device_layout.operations]
            if program_modes != device_modes:
                raise CircuitError(
                    "Program cannot be used with the device '{}' "
                    "due to incompatible mode ordering.".format(device.target))

            # Third check: the parameters of the gates are valid
            # We will loop over the different operations in the device specification

            for i, operation in enumerate(device_layout.operations):
                # We obtain the name of the parameter(s)
                param_names = operation["args"]

                program_params_len = len(self.rolled_circuit[i].op.p)
                device_params_len = len(param_names)
                # The next if is to make sure we do not flag incorrectly things like Sgate(r,0) being different Sgate(r)
                # This assumes that parameters other than the first one are zero if not explicitly stated.
                if device_params_len < program_params_len:
                    for j in range(1, program_params_len):
                        if self.rolled_circuit[i].op.p[j] != 0:
                            raise CircuitError(
                                "Program cannot be used with the device '{}' "
                                "due to incompatible parameter.".format(
                                    device.target))
                # Now we will check explicitly if the parameters in the program match
                for k, param_name in enumerate(param_names):
                    # Obtain the value of the corresponding parameter in the program
                    program_param = self.rolled_circuit[i].op.p[k]

                    # make sure that hardcoded parameters in the device layout are correct
                    if not isinstance(param_name,
                                      str) and not par_is_symbolic(param_name):
                        if not program_param == param_name:
                            raise CircuitError(
                                "Program cannot be used with the device '{}' "
                                "due to incompatible parameter. Parameter has value '{}' "
                                "while its valid value is '{}'".format(
                                    device.target, program_param, param_name))
                        continue

                    # Obtain the relevant parameter range from the device
                    param_range = device.gate_parameters.get(str(param_name))
                    if param_range is None:
                        raise CircuitError(
                            "Program cannot be used with the device '{}' "
                            "due to parameter '{}' not found in device specification."
                            .format(device.target, param_name))
                    if par_is_symbolic(program_param):
                        # If it is a symbolic value go and lookup its corresponding list in self.tdm_params
                        local_p_vals = self.parameters.get(
                            program_param.name, [])

                        for x in local_p_vals:
                            if not x in param_range:
                                raise CircuitError(
                                    "Program cannot be used with the device '{}' "
                                    "due to incompatible parameter. Parameter has value '{}' "
                                    "while its valid range is '{}'".format(
                                        device.target, x, param_range))

                    else:
                        # If it is a numerical value check directly
                        if not program_param in param_range:
                            raise CircuitError(
                                "Program cannot be used with the device '{}' "
                                "due to incompatible parameter. Parameter has value '{}' "
                                "while its valid range is '{}'".format(
                                    device.target, program_param, param_range))
            self._compile_info = (device, "TDM")
            self._target = device.target
            return self

        raise CircuitError(
            "TDM programs cannot be compiled without a valid device specification."
        )