def test_recompilation_precompiled(self, prog, infolog, device): """Test that recompilation happens when: 1. the program was precompiled, but 2. the recompile keyword argument was set to ``True``. The program is considered to be precompiled if ``program.compile_info`` is set. """ device.specification["compiler"] = [] # Set compile_info to a fake device specification and compiler name. dummy_spec = { "target": "DummyDevice", "modes": 2, "layout": None, "gate_parameters": None, "compiler": [None], } X8_spec = DeviceSpec(spec=dummy_spec) prog._compile_info = (X8_spec, "fake_compiler") engine = sf.RemoteEngine("X8") engine.run_async(prog, shots=10, compile_options=None, recompile=True) want_message = "Recompiling program for device X8_01 using compiler Xunitary." assert infolog.records[-1].message == want_message
def __init__(self, *, backend, wires=None, cutoff_dim=5, shots=1000, hbar=2, sf_token=None): self.backend = backend self.cutoff = cutoff_dim eng = sf.RemoteEngine(self.backend) self.num_wires = eng.device_spec.modes if wires is None: # infer the number of modes from the device specs # and use consecutive integer wire labels wires = range(self.num_wires) if isinstance(wires, int): raise ValueError( "Device has a fixed number of {} modes. The wires argument can only be used " "to specify an iterable of wire labels.".format(self.num_wires) ) if self.num_wires != len(wires): raise ValueError( "Device has a fixed number of {} modes and " "cannot be created with {} wires.".format(self.num_wires, len(wires)) ) super().__init__(wires, analytic=False, shots=shots, hbar=hbar) self.eng = eng if sf_token is not None: sf.store_account(sf_token)
def __init__(self, *, backend, wires=None, cutoff_dim=5, shots=1000, hbar=2, sf_token=None): if shots is None: raise ValueError( "The strawberryfields.remote device does not support analytic expectation values" ) self.backend = backend self.cutoff = cutoff_dim eng = sf.RemoteEngine(self.backend) self.num_wires = eng.device.modes if wires is None: # infer the number of modes from the device specs # and use consecutive integer wire labels wires = range(self.num_wires) if isinstance(wires, int): raise ValueError( f"Device has a fixed number of {self.num_wires} modes. The wires argument can " f"only be used to specify an iterable of wire labels." ) if self.num_wires != len(wires): raise ValueError( f"Device has a fixed number of {self.num_wires} modes and " f"cannot be created with {len(wires)} wires." ) super().__init__(wires, shots=shots, hbar=hbar) self.eng = eng if sf_token is not None: xcc.Settings(REFRESH_TOKEN=sf_token).save()
def test_validation(self, prog, monkeypatch, caplog): """Test that validation happens (no recompilation) when the target device and device spec match.""" compiler = "Xunitary" caplog.set_level(logging.INFO) test_device_dict = mock_device_dict.copy() test_device_dict["compiler"] = compiler monkeypatch.setattr(Connection, "create_job", lambda self, target, program, run_options: program) monkeypatch.setattr(Connection, "_get_device_dict", lambda *args: test_device_dict) engine = sf.RemoteEngine("X8_01") device = engine.device_spec # Setting compile_info prog._compile_info = (device, device.compiler) program = engine.run_async(prog, shots=10) # No recompilation, original Program assert caplog.records[-1].message == ( f"Program previously compiled for {device.target} using {prog.compile_info[1]}. " f"Validating program against the Xstrict compiler.")
def test_recompilation_run_async(self, prog, monkeypatch, caplog): """Test that recompilation happens when the recompile keyword argument was set to True.""" compiler = "Xunitary" caplog.set_level(logging.INFO) test_device_dict = mock_device_dict.copy() test_device_dict["compiler"] = compiler monkeypatch.setattr(Connection, "create_job", lambda self, target, program, run_options: program) monkeypatch.setattr(Connection, "_get_device_dict", lambda *args: test_device_dict) compile_options = {"compiler": compiler} engine = sf.RemoteEngine("X8") device = engine.device_spec # Setting compile_info prog._compile_info = (device, device.compiler) program = engine.run_async(prog, shots=10, compile_options=compile_options, recompile=True) # No recompilation, original Program assert caplog.records[-1].message == ( f"Recompiling program for device " f"{device.target} using the specified compiler options: " f"{compile_options}.")
def test_recompilation_run(self, prog, monkeypatch, caplog): """Test that recompilation happens when the recompile keyword argument was set to True and engine.run was called.""" compiler = "Xunitary" caplog.set_level(logging.INFO) test_device_dict = mock_device_dict.copy() test_device_dict["compiler"] = compiler monkeypatch.setattr( Connection, "create_job", lambda self, target, program, run_options: MockJob(program)) monkeypatch.setattr(Connection, "_get_device_dict", lambda *args: test_device_dict) class MockJob: """Mock job that acts like a job, but also stores a program.""" def __init__(self, prog): # Store the program as result self.result = prog self.status = "complete" self.id = 0 def refresh(self): pass compile_options = {"compiler": compiler} engine = sf.RemoteEngine("X8") device = engine.device_spec # Setting compile_info prog._compile_info = (device, device.compiler) program = engine.run(prog, shots=10, compile_options=compile_options, recompile=True) # No recompilation, original Program assert caplog.records[-1].message == ( "The remote job 0 has been completed.") assert caplog.records[-2].message == ( f"Recompiling program for device " f"{device.target} using the specified compiler options: " f"{compile_options}.")
def test_validation(self, prog, infolog, device): """Test that validation happens (i.e., no recompilation) when the target device and device specification match. """ device.specification["compiler"] = ["Xunitary"] engine = sf.RemoteEngine("X8_01") device = engine.device_spec prog._compile_info = (device, device.compiler) engine.run_async(prog, shots=10) want_message = ( f"Program previously compiled for {device.target} using {prog.compile_info[1]}. " f"Validating program against the Xstrict compiler." ) assert infolog.records[-1].message == want_message
def test_recompilation_run_async(self, prog, infolog, device): """Test that recompilation happens when the recompile keyword argument is set to ``True``. """ device.specification["compiler"] = ["Xunitary"] engine = sf.RemoteEngine("X8") device = engine.device_spec prog._compile_info = (device, device.compiler) compile_options = {"compiler": "Xunitary"} engine.run_async(prog, shots=10, compile_options=compile_options, recompile=True) want_message = ( f"Recompiling program for device {device.target} using the " f"specified compiler options: {compile_options}." ) assert infolog.records[-1].message == want_message
def test_compile_device_invalid_device_error(self, prog, device): """Tests that a ValueError is raised if a program is compiled for one device but run on a different device without recompilation. """ device.specification["compiler"] = [] # Setting compile_info with a dummy devicespec and compiler name dummy_spec = { "target": "DummyDevice", "modes": 2, "layout": None, "gate_parameters": None, "compiler": [None], } X8_spec = DeviceSpec(spec=dummy_spec) prog._compile_info = (X8_spec, "dummy_compiler") engine = sf.RemoteEngine("X8") with pytest.raises(ValueError, match="Cannot use program compiled"): engine.run_async(prog, shots=10)
def test_recompilation_run(self, prog, infolog, device): """Test that recompilation happens when the recompile keyword argument was set to ``True`` and :meth:`RemoteEngin.run` is called.""" device.specification["compiler"] = ["Xunitary"] engine = sf.RemoteEngine("X8") device = engine.device_spec prog._compile_info = (device, device.compiler) compile_options = {"compiler": "Xunitary"} engine.run(prog, shots=10, compile_options=compile_options, recompile=True) want_message_1 = "The remote job 123 has been completed." assert infolog.records[-1].message == want_message_1 want_message_2 = ( f"Recompiling program for device {device.target} using the " f"specified compiler options: {compile_options}." ) assert infolog.records[-2].message == want_message_2
def test_compile_device_invalid_device_error(self, prog, monkeypatch, caplog): """Tests that an error is raised if the program was compiled for another device and recompilation was not requested.""" caplog.set_level(logging.INFO) test_device_dict = mock_device_dict.copy() test_device_dict["compiler"] = [] monkeypatch.setattr(Connection, "create_job", lambda self, target, program, run_options: program) monkeypatch.setattr(Connection, "_get_device_dict", lambda *args: test_device_dict) monkeypatch.setattr(Program, "compile", lambda *args, **kwargs: self.MockProgram()) # Setting compile_info with a dummy devicespec and compiler name X8_spec = DeviceSpec(target="DummyDevice", connection=None, spec=None) prog._compile_info = (X8_spec, "dummy_compiler") engine = sf.RemoteEngine("X8") with pytest.raises(ValueError, match="Cannot use program compiled"): program = engine.run_async(prog, shots=10)
def test_recompilation_precompiled(self, prog, monkeypatch, caplog): """Test that recompilation happens when: 1. the program was precompiled 2. but the recompile keyword argument was set to True. The program is considered to be precompiled if program.compile_info was set (setting it in the test case). """ caplog.set_level(logging.INFO) test_device_dict = mock_device_dict.copy() test_device_dict["compiler"] = [] monkeypatch.setattr(Connection, "create_job", lambda self, target, program, run_options: program) monkeypatch.setattr(Connection, "_get_device_dict", lambda *args: test_device_dict) monkeypatch.setattr(Program, "compile", lambda *args, **kwargs: self.MockProgram()) # Setting compile_info prog._compile_info = (None, "dummy_compiler") # Setting compile_info with a dummy devicespec and compiler name X8_spec = DeviceSpec(target="DummyDevice", connection=None, spec=None) prog._compile_info = (X8_spec, "dummy_compiler") engine = sf.RemoteEngine("X8") compile_options = None # Setting recompile in keyword arguments program = engine.run_async(prog, shots=10, compile_options=compile_options, recompile=True) assert isinstance(program, self.MockProgram) assert caplog.records[ -1].message == "Recompiling program for device X8_01 using compiler Xunitary."
def vibronic( t: np.ndarray, U1: np.ndarray, r: np.ndarray, U2: np.ndarray, alpha: np.ndarray, n_samples: int, loss: float = 0.0, engine='local', ) -> list: """Generate samples for computing vibronic spectra. The following gates are applied to input vacuum states: 1. Two-mode squeezing on all :math:`2N` modes with parameters ``t`` 2. Interferometer ``U1`` on the first :math:`N` modes 3. Squeezing on the first :math:`N` modes with parameters ``r`` 4. Interferometer ``U2`` on the first :math:`N` modes 5. Displacement on the first :math:`N` modes with parameters ``alpha`` A sample is generated by measuring the number of photons in each of the :math:`2N` modes. In the special case that all of the two-mode squeezing parameters ``t`` are zero, only :math:`N` modes are considered, which speeds up calculations. **Example usage:** >>> formic = data.Formic() >>> w = formic.w >>> wp = formic.wp >>> Ud = formic.Ud >>> delta = formic.delta >>> T = 0 >>> t, U1, r, U2, alpha = vibronic.gbs_params(w, wp, Ud, delta, T) >>> sample.vibronic(t, U1, r, U2, alpha, 2, 0.0) [[0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] Args: t (array): two-mode squeezing parameters U1 (array): unitary matrix for the first interferometer r (array): squeezing parameters U2 (array): unitary matrix for the second interferometer alpha (array): displacement parameters n_samples (int): number of samples to be generated loss (float): loss parameter denoting the fraction of generated photons that are lost Returns: list[list[int]]: a list of samples from GBS """ if n_samples < 1: raise ValueError("Number of samples must be at least one") if not 0 <= loss <= 1: raise ValueError("Loss parameter must take a value between zero and one") n_modes = len(t) if engine=='X8': #VGG check you engine using sf.ping() print("Atemting to use X8 ... ") eng = sf.RemoteEngine("X8") else: eng = sf.LocalEngine(backend="gaussian") if np.any(t != 0): gbs = sf.Program(n_modes * 2) else: gbs = sf.Program(n_modes) # pylint: disable=expression-not-assigned,pointless-statement with gbs.context as q: if np.any(t != 0): for i in range(n_modes): sf.ops.S2gate(t[i]) | (q[i], q[i + n_modes]) sf.ops.Interferometer(U1) | q[:n_modes] for i in range(n_modes): sf.ops.Sgate(r[i]) | q[i] sf.ops.Interferometer(U2) | q[:n_modes] for i in range(n_modes): sf.ops.Dgate(alpha[i]) | q[i] if loss: for _q in q: sf.ops.LossChannel(1 - loss) | _q sf.ops.MeasureFock() | q with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=UserWarning, message="Cannot simulate non-") if engine=='X8': #VGG check you engine using sf.ping() s = eng.run(gbs,shots=n_samples,state=True).samples else: s = eng.run(gbs, shots=n_samples).samples s = np.array(s).tolist() # convert all generated samples to list if np.any(t == 0): s = np.pad(s, ((0, 0), (0, n_modes))).tolist() return s
def sample( A: np.ndarray, n_mean: float, n_samples: int = 1, threshold: bool = True, loss: float = 0.0, engine='local',) -> list: r"""Generate simulated samples from GBS encoded with a symmetric matrix :math:`A`. **Example usage:** >>> g = nx.erdos_renyi_graph(5, 0.7) >>> a = nx.to_numpy_array(g) >>> sample(a, 3, 4) [[1, 1, 1, 1, 1], [1, 1, 0, 1, 1], [0, 0, 0, 0, 0], [1, 0, 0, 0, 1]] Args: A (array): the symmetric matrix to sample from n_mean (float): mean photon number n_samples (int): number of samples threshold (bool): perform GBS with threshold detectors if ``True`` or photon-number resolving detectors if ``False`` loss (float): fraction of generated photons that are lost while passing through device. Parameter should range from ``loss=0`` (ideal noise-free GBS) to ``loss=1``. Returns: list[list[int]]: a list of samples from GBS with respect to the input symmetric matrix """ if not np.allclose(A, A.T): raise ValueError("Input must be a NumPy array corresponding to a symmetric matrix") if n_samples < 1: raise ValueError("Number of samples must be at least one") if n_mean < 0: raise ValueError("Mean photon number must be non-negative") if not 0 <= loss <= 1: raise ValueError("Loss parameter must take a value between zero and one") nodes = len(A) p = sf.Program(nodes) if engine=='X8': #VGG check you engine using sf.ping() print("Will try to use X8 ...") eng=sf.RemoteEngine("X8") else: eng = sf.LocalEngine(backend="gaussian") mean_photon_per_mode = n_mean / float(nodes) # pylint: disable=expression-not-assigned,pointless-statement with p.context as q: sf.ops.GraphEmbed(A, mean_photon_per_mode=mean_photon_per_mode) | q if loss: for _q in q: sf.ops.LossChannel(1 - loss) | _q if threshold: sf.ops.MeasureThreshold() | q else: sf.ops.MeasureFock() | q with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=UserWarning, message="Cannot simulate non-") if engine=='X8': #VGG check you engine using sf.ping() s = eng.run(p, shots=n_samples,state=True).samples else: s = eng.run(p, shots=n_samples).samples return s.tolist()
f"median: {seconds_to_string(np.median(runtimes))}, average: {seconds_to_string(np.mean(runtimes))}, brightest: {seconds_to_string(np.max(runtimes))}, total: {seconds_to_string(np.sum(runtimes))}", fontsize=fs_axlabel, ) ax.set_xlabel("$N_c$", fontsize=fs_axlabel) ax.set_ylabel("$G$", fontsize=fs_axlabel) ax.tick_params(axis="x", labelsize=fs_ticklabel) ax.tick_params(axis="y", labelsize=fs_ticklabel) ax.legend(fontsize=fs_legend) return fig, ax if __name__ == "__main__": # connect to the remote engine and obtain a ``device`` object eng = sf.RemoteEngine("borealis") device = eng.device # create a list of list of gate arguments for a GBS instance gate_args_list = borealis_gbs(device, modes=288, squeezing="high") # create a Strawberry Fields program delays = [1, 6, 36] vac_modes = sum(delays) n, N = get_mode_indices(delays) prog = sf.TDMProgram(N) with prog.context(*gate_args_list) as (p, q): Sgate(p[0]) | q[n[0]] for i in range(len(delays)): Rgate(p[2 * i + 1]) | q[n[i]] BSgate(p[2 * i + 2], np.pi / 2) | (q[n[i + 1]], q[n[i]])