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}
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"
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"
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)
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"
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)
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)
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