コード例 #1
0
    def test_invalid_multiple_match(self):
        """test exception raised if match involving duplicated
        template parameters results in inconsistent values"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(-{r}, 0.45) | 1
            Vac | 2
            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(1.45, -1.432*pi) | 0
            Dgate(-0.543, 0.45) | 1
            Vac | 2
            """))

        with pytest.raises(TemplateError, match="matches inconsistent values"):
            match_template(template, program)
コード例 #2
0
    def test_multiple_match(self):
        """test a match involving duplicated template parameters"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(-{r}, 0.45) | 1
            Vac | 2
            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate(-0.543, 0.45) | 1
            Vac | 2
            """))

        res = match_template(template, program)
        expected = {'r': 0.543, 'phi': -1.432 * np.pi}
        assert res == expected
コード例 #3
0
    def test_match(self):
        """test a simple match"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(0.543, 0.45) | 1
            Vac | 2
            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate(0.543, 0.45) | 1
            Vac | 2
            """))

        res = match_template(template, program)
        expected = {'r': 0.543, 'phi': -1.432 * np.pi}
        assert res == expected
コード例 #4
0
    def test_implicit_variable_solving(self):
        """test solver is used for parameter arithmetic"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(0.543, 0.45) | 1
            Sgate(2*{r}, {phi}-1) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate(0.412, 0.45) | 1
            """))

        res = match_template(template, program)
        expected = {'r': 0.543 / 2, 'phi': -1.432 * np.pi + 1}
        assert np.allclose(res['r'], expected['r'])
        assert np.allclose(res['phi'], expected['phi'])
コード例 #5
0
    def test_different_version(self):
        """Test exception raised if versions don't match"""
        template = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.1

            Sgate(0.543, pi) | 0
            """))

        with pytest.raises(TemplateError,
                           match="Mismatching Blackbird version"):
            match_template(template, program)
コード例 #6
0
    def test_different_target(self):
        """Test exception raised if targets don't match"""
        template = loads(
            dedent("""\
            name prog
            version 0.0
            target dev1

            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0
            target dev2

            Sgate(0.543, pi) | 0
            """))

        with pytest.raises(TemplateError, match="Mismatching target"):
            match_template(template, program)
コード例 #7
0
ファイル: test_utils.py プロジェクト: stjordanis/blackbird
    def test_multiple_match_tdm(self):
        """test a match involving duplicated template parameters with p-type variables"""

        template = loads(
            dedent("""\
            name template_td3_fake
            version 1.0
            target TD3_fake (shots=1)
            type tdm (temporal_modes=3, copies=1)

            Sgate({s}, 0.0) | 43
            Rgate({r}) | 43
            BSgate({bs}, 1.5707963267948966) | [42, 43]
            Rgate({offset}) | 43
            MeasureFock() | 0
            """))

        program = loads(
            dedent("""\
            name None
            version 1.0
            target TD3_fake (shots=1)
            type tdm (temporal_modes=259)

            float array p0 =
                0.999, 0.965, 0.678
            float array p1 =
                0.211, 0.042, 0.347
            float array p2 =
                0.042, 0.673, 0.924
            int array p3 =
                4, 4, 4

            Sgate(p0, 0.0) | 43
            Rgate(p1) | 43
            BSgate(p2, 1.5707963267948966) | [42, 43]
            Rgate(p3) | 43
            MeasureFock() | 0
            """))

        res = match_template(template, program)
        expected = {
            's': np.array([[0.999, 0.965, 0.678]]),
            'r': np.array([[0.211, 0.042, 0.347]]),
            'bs': np.array([[0.042, 0.673, 0.924]]),
            'offset': np.array([[4, 4, 4]])
        }

        assert res.keys() == expected.keys()
        assert all(
            np.allclose(r, e) for r, e in zip(res.values(), expected.values()))
コード例 #8
0
    def test_different_program(self):
        """test exception raised if template not the same program"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(0.543, 0.45) | 0
            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate(0.543, 0.45) | 0
            """))

        with pytest.raises(TemplateError, match="Not the same program"):
            match_template(template, program)
コード例 #9
0
    def test_too_many_template_parameters(self):
        """test exception raised if gate contains multiple template parameters"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(0.543, 0.45) | 1
            Sgate({r}+{s}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate(0.543, 0.45) | 1
            """))

        with pytest.raises(TemplateError,
                           match="only supports one template parameter"):
            match_template(template, program)
コード例 #10
0
    def test_not_program(self):
        """test exception raised if second argument is a template"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(0.543, 0.45) | 0
            Sgate({r}, {phi}) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate({alpha}, 0.45) | 0
            """))

        with pytest.raises(TemplateError,
                           match="Argument 2 cannot be a template"):
            match_template(template, program)
コード例 #11
0
    def test_not_template(self):
        """test exception raised if first argument is not a template"""

        template = loads(
            dedent("""\
            name prog
            version 0.0

            Dgate(0.543, 0.45) | 1
            Sgate(0.543, 0.123) | 0
            """))

        program = loads(
            dedent("""\
            name prog
            version 0.0

            Sgate(0.543, -1.432*pi) | 0
            Dgate(0.543, 0.45) | 1
            """))

        with pytest.raises(TemplateError,
                           match="Argument 1 is not a template"):
            match_template(template, program)
コード例 #12
0
    def compile(self, *, device=None, compiler=None, **kwargs):
        """Compile the program given a Strawberry Fields photonic compiler, or
        hardware device specification.

        The compilation process can involve up to three stages:

        1. **Validation:** Validates properties of the program, including number of modes and
           allowed operations, making sure all the :doc:`/introduction/ops` used are accepted by the
           compiler.

        2. **Decomposition:** Once the program has been validated, decomposition are performed,
           transforming certain gates into sequences of simpler gates.

        3. **General compilation:** Finally, the compiler might specify bespoke compilation logic
           for transforming the  quantum circuit into an equivalent circuit which can be executed
           by the target device.

        **Example:**

        The ``gbs`` compile target will
        compile a circuit consisting of Gaussian operations and Fock measurements
        into canonical Gaussian boson sampling form.

        >>> prog2 = prog.compile(compiler="gbs")

        For a hardware device a :class:`~.DeviceSpec` object, and optionally a specified compile strategy,
        must be supplied. If no compile strategy is supplied the default compiler from the device
        specification is used.

        >>> eng = sf.RemoteEngine("X8")
        >>> device = eng.device_spec
        >>> prog2 = prog.compile(device=device, compiler="Xcov")

        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`.

        Keyword Args:
            optimize (bool): If True, try to optimize the program by merging and canceling gates.
                The default is False.
            warn_connected (bool): If True, the user is warned if the quantum circuit is not weakly
                connected. The default is True.
            shots (int): Number of times the program measurement evaluation is repeated. Passed
                along to the compiled program's ``run_options``.

        Returns:
            Program: compiled program
        """
        # pylint: disable=too-many-branches
        if device is None and compiler is None:
            raise ValueError(
                "Either one or both of 'device' and 'compiler' must be specified"
            )

        def _get_compiler(compiler_or_name):
            if compiler_or_name in compiler_db:
                return compiler_db[compiler_or_name]()

            if isinstance(compiler_or_name, Compiler):
                return compiler_or_name

            raise ValueError(f"Unknown compiler '{compiler_or_name}'.")

        if device is not None:
            target = device.target

            if compiler is None:
                # get the default compiler from the device spec
                compiler = compiler_db[device.default_compiler]()
            else:
                compiler = _get_compiler(compiler)

            if device.modes is not None:
                if isinstance(device.modes, int):
                    # check that the number of modes is correct, if device.modes
                    # is provided as an integer
                    self.assert_number_of_modes(device)
                else:
                    # check that the number of measurements is within the allowed
                    # limits for each measurement type; device.modes will be a dictionary
                    self.assert_max_number_of_measurements(device)

        else:
            compiler = _get_compiler(compiler)
            target = compiler.short_name

        seq = compiler.decompose(self.circuit)

        if kwargs.get("warn_connected", True):
            DAG = pu.list_to_DAG(seq)
            temp = nx.algorithms.components.number_weakly_connected_components(
                DAG)
            if temp > 1:
                warnings.warn(
                    "The circuit consists of {} disconnected components.".
                    format(temp))

        # run optimizations
        if kwargs.get("optimize", False):
            seq = pu.optimize_circuit(seq)

        seq = compiler.compile(seq, self.register)

        # create the compiled Program
        compiled = self._linked_copy()
        compiled.circuit = seq
        compiled._target = target
        compiled._compile_info = (device, compiler.short_name)

        # Get run options of compiled program.
        run_options = {
            k: kwargs[k]
            for k in ALLOWED_RUN_OPTIONS if k in kwargs
        }
        compiled.run_options.update(run_options)

        # set backend options of the program
        backend_options = {
            k: kwargs[k]
            for k in kwargs if k not in ALLOWED_RUN_OPTIONS
        }
        compiled.backend_options.update(backend_options)

        # validate gate parameters
        if device is not None and device.gate_parameters:
            bb_device = bb.loads(device.layout)
            bb_compiled = sf.io.to_blackbird(compiled)

            try:
                user_parameters = match_template(bb_device, bb_compiled)
            except bb.utils.TemplateError as e:
                raise CircuitError(
                    "Program cannot be used with the compiler '{}' "
                    "due to incompatible topology.".format(
                        compiler.short_name)) from e

            device.validate_parameters(**user_parameters)

        return compiled