Exemplo n.º 1
0
    def test_metadata_run_options(self):
        """Test run options correctly converts"""
        prog = Program(4, name="test_program")
        bb = io.to_blackbird(prog.compile(compiler="gaussian", shots=1024))

        assert bb.name == "test_program"
        assert bb.version == "1.0"
        assert bb.target["name"] == "gaussian"
        assert bb.target["options"] == {"shots": 1024}
Exemplo n.º 2
0
    def test_decomposition_operation_compiled(self):
        """Test decomposition operation gets decomposed if compiled"""
        # create a test program
        prog = Program(1)

        with prog.context as q:
            ops.Pgate(0.43) | q[0]

        bb = io.to_blackbird(prog)
        expected = {"op": "Pgate", "modes": [0], "args": [0.43], "kwargs": {}}
        assert bb.operations[0] == expected

        bb = io.to_blackbird(prog.compile(compiler="gaussian"))
        assert bb.operations[0]["op"] == "Sgate"
        assert bb.operations[1]["op"] == "Rgate"
Exemplo n.º 3
0
    def test_metadata(self):
        """Test metadata correctly converts"""
        # create a test program
        prog = Program(4, name="test_program")
        bb = io.to_blackbird(prog)

        assert bb.name == "test_program"
        assert bb.version == "1.0"
        assert bb.target["name"] is None

        bb = io.to_blackbird(prog.compile(compiler="gaussian"))

        assert bb.name == "test_program"
        assert bb.version == "1.0"
        assert bb.target["name"] == "gaussian"
Exemplo n.º 4
0
    def run_async(self,
                  program: Program,
                  *,
                  compile_options=None,
                  **kwargs) -> Job:
        """Runs a non-blocking remote job.

        In the non-blocking mode, a ``Job`` object is returned immediately, and the user can
        manually refresh the status and check for updated results of the job.

        Args:
            program (strawberryfields.Program): the quantum circuit
            compile_options (None, Dict[str, Any]): keyword arguments for :meth:`.Program.compile`

        Keyword Args:
            shots (Optional[int]): The number of shots for which to run the job. If this
                argument is not provided, the shots are derived from the given ``program``.

        Returns:
            strawberryfields.api.Job: the created remote job
        """
        # get the specific chip to submit the program to
        # TODO: this should be provided by the chip API, rather
        # than built-in to Strawberry Fields.
        compile_options = compile_options or {}
        kwargs.update(self._backend_options)

        if program.target is None or (program.target.split("_")[0] !=
                                      self.target.split("_")[0]):
            # Program is either:
            #
            # * uncompiled (program.target is None)
            # * compiled to a different chip family to the engine target
            #
            # In both cases, recompile the program to match the intended target.
            program = program.compile(self.target, **compile_options)

        # update the run options if provided
        run_options = {}
        run_options.update(program.run_options)
        run_options.update(kwargs or {})

        if "shots" not in run_options:
            raise ValueError("Number of shots must be specified.")

        return self._connection.create_job(self.target, program, run_options)
Exemplo n.º 5
0
    def test_decomposition_operation_compiled(self):
        """Test decomposition operation gets decomposed if compiled"""
        # create a test program
        sf_prog = Program(1)

        with sf_prog.context as q:
            ops.Pgate(0.43) | q[0]

        xir_prog = io.to_xir(sf_prog)

        expected = [("Pgate", [0.43], (0,))]
        assert [(stmt.name, stmt.params, stmt.wires) for stmt in xir_prog.statements] == expected

        xir_prog = io.to_xir(sf_prog.compile(compiler="gaussian"))

        assert xir_prog.statements[0].name == "Sgate"
        assert xir_prog.statements[1].name == "Rgate"
Exemplo n.º 6
0
    def run_async(self,
                  program: Program,
                  *,
                  compile_options=None,
                  **kwargs) -> Job:
        """Runs a non-blocking remote job.

        In the non-blocking mode, a ``Job`` object is returned immediately, and the user can
        manually refresh the status and check for updated results of the job.

        Args:
            program (strawberryfields.Program): the quantum circuit
            compile_options (None, Dict[str, Any]): keyword arguments for :meth:`.Program.compile`

        Keyword Args:
            shots (Optional[int]): The number of shots for which to run the job. If this
                argument is not provided, the shots are derived from the given ``program``.

        Returns:
            strawberryfields.api.Job: the created remote job
        """
        # get the specific chip to submit the program to
        compile_options = compile_options or {}
        kwargs.update(self._backend_options)

        device = self.device_spec

        compiler_name = compile_options.get("compiler",
                                            device.default_compiler)
        msg = f"Compiling program for device {device.target} using compiler {compiler_name}."
        self.log.info(msg)

        program = program.compile(device=device, **compile_options)

        # update the run options if provided
        run_options = {}
        run_options.update(program.run_options)
        run_options.update(kwargs or {})

        if "shots" not in run_options:
            raise ValueError("Number of shots must be specified.")

        return self._connection.create_job(self.target, program, run_options)
Exemplo n.º 7
0
    def run_async(self,
                  program: Program,
                  *,
                  compile_options=None,
                  recompile=False,
                  **kwargs) -> Job:
        """Runs a non-blocking remote job.

        In the non-blocking mode, a ``Job`` object is returned immediately, and the user can
        manually refresh the status and check for updated results of the job.

        Args:
            program (strawberryfields.Program): the quantum circuit
            compile_options (None, Dict[str, Any]): keyword arguments for :meth:`.Program.compile`
            recompile (bool): Specifies if ``program`` should be recompiled
                using ``compile_options``, or if not provided, the default compilation options.

        Keyword Args:
            shots (Optional[int]): The number of shots for which to run the job. If this
                argument is not provided, the shots are derived from the given ``program``.

        Returns:
            strawberryfields.api.Job: the created remote job
        """
        # get the specific chip to submit the program to
        compile_options = compile_options or {}
        kwargs.update(self._backend_options)

        device = self.device_spec
        if program.type == "tdm" and not device.layout_is_formatted():
            device.fill_template(program)

        compiler_name = compile_options.get("compiler",
                                            device.default_compiler)

        program_is_compiled = program.compile_info is not None

        if program_is_compiled and not recompile:
            # error handling for program compilation:
            # program was compiled but recompilation was not allowed by the
            # user

            if (program.compile_info[0].target != device.target
                    or program.compile_info[0]._spec != device._spec):
                # program was compiled for a different device
                raise ValueError(
                    "Cannot use program compiled with "
                    f"{program._compile_info[0].target} for target {self.target}. "
                    'Pass the "recompile=True" keyword argument '
                    f"to compile with {compiler_name}.")

        if not program_is_compiled:
            # program is not compiled
            msg = f"Compiling program for device {device.target} using compiler {compiler_name}."
            self.log.info(msg)
            program = program.compile(device=device, **compile_options)

        elif recompile:
            # recompiling program
            if compile_options:
                msg = f"Recompiling program for device {device.target} using the specified compiler options: {compile_options}."
            else:
                msg = f"Recompiling program for device {device.target} using compiler {compiler_name}."

            self.log.info(msg)
            program = program.compile(device=device, **compile_options)

        else:
            # validating program
            msg = (
                f"Program previously compiled for {device.target} using {program.compile_info[1]}. "
                f"Validating program against the Xstrict compiler.")
            self.log.info(msg)
            program = program.compile(device=device, compiler="Xstrict")

        # update the run options if provided
        run_options = {}
        run_options.update(program.run_options)
        run_options.update(kwargs or {})

        if "shots" not in run_options:
            raise ValueError("Number of shots must be specified.")

        return self._connection.create_job(self.target, program, run_options)
Exemplo n.º 8
0
    def run_async(self,
                  program: Program,
                  *,
                  compile_options=None,
                  recompile=False,
                  **kwargs) -> xcc.Job:
        """Runs a non-blocking remote job.

        In the non-blocking mode, a ``xcc.Job`` object is returned immediately, and the user can
        manually refresh the status and check for updated results of the job.

        Args:
            program (strawberryfields.Program): the quantum circuit
            compile_options (None, Dict[str, Any]): keyword arguments for :meth:`.Program.compile`
            recompile (bool): Specifies if ``program`` should be recompiled
                using ``compile_options``, or if not provided, the default compilation options.

        Keyword Args:
            shots (Optional[int]): The number of shots for which to run the job. If this
                argument is not provided, the shots are derived from the given ``program``.

        Returns:
            xcc.Job: the created remote job
        """
        # get the specific chip to submit the program to
        compile_options = compile_options or {}
        kwargs.update(self._backend_options)

        device = self.device
        compiler_name = compile_options.get("compiler",
                                            device.default_compiler)

        program_is_compiled = program.compile_info is not None

        if program_is_compiled and not recompile:
            # error handling for program compilation:
            # program was compiled but recompilation was not allowed by the
            # user

            if program.compile_info and (
                    program.compile_info[0].target != device.target
                    or program.compile_info[0]._spec != device._spec):
                compile_target = program.compile_info[0].target
                # program was compiled for a different device
                raise ValueError("Cannot use program compiled with "
                                 f"{compile_target} for target {self.target}. "
                                 'Pass the "recompile=True" keyword argument '
                                 f"to compile with {compiler_name}.")

        if not program_is_compiled:
            # program is not compiled
            msg = f"Compiling program for device {device.target} using compiler {compiler_name}."
            self.log.info(msg)
            program = program.compile(device=device, **compile_options)

        elif recompile:
            # recompiling program
            if compile_options:
                msg = f"Recompiling program for device {device.target} using the specified compiler options: {compile_options}."
            else:
                msg = f"Recompiling program for device {device.target} using compiler {compiler_name}."

            self.log.info(msg)
            program = program.compile(device=device, **compile_options)

        elif program.compile_info[1][0] == "X":
            # validating program
            msg = (
                f"Program previously compiled for {device.target} using {program.compile_info[1]}. "
                f"Validating program against the Xstrict compiler.")
            self.log.info(msg)
            program = program.compile(device=device, compiler="Xstrict")

        # Update and filter the run options if provided.
        # Forwarding the boolean `crop` run option to the hardware will result in undesired
        # behaviour as og-tdm also uses that keyword arg, hence it is removed.
        temp_run_options = {**program.run_options, **kwargs}
        skip_run_keys = ["crop"]
        run_options = {
            key: temp_run_options[key]
            for key in temp_run_options.keys() - skip_run_keys
        }

        if "shots" not in run_options:
            raise ValueError("Number of shots must be specified.")

        # Serialize a Blackbird circuit for network transmission
        bb = to_blackbird(program)
        bb._target["options"] = run_options
        circuit = bb.serialize()

        connection = self.connection

        job = xcc.Job.submit(
            connection=connection,
            name=program.name,
            target=self.target,
            circuit=circuit,
            language=f"blackbird:{bb.version}",
        )

        return job