Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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()
Ejemplo n.º 4
0
    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.")
Ejemplo n.º 5
0
    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}.")
Ejemplo n.º 6
0
    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}.")
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
    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."
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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]])