示例#1
0
 def test_n_mean(self, adj, n_mean, dim, threshold, embedding):
     """Test that n_mean returns the expected number of photons or clicks when using an
     identity W, so that we expect the mean number of photons to be equal to the input value
     of n_mean"""
     params = np.zeros(dim)
     gbs = train.VGBS(adj, n_mean, embedding, threshold)
     assert np.allclose(gbs.n_mean(params), n_mean)
示例#2
0
    def test_intermediate_cost(self, dim, n_mean, simple_embedding):
        """Test that the cost function evaluates as expected on non-initial parameters. This is
        done by comparing the cost function calculated using train.Stochastic with a manual
        calculation. The manual calculation involves sampling from VGBS with the non-initial
        params and averaging the cost function over the result."""
        n_samples = 10000
        objectives = np.linspace(0.5, 1.5, dim)
        h = self.h_setup(objectives)
        A = np.eye(dim)
        vgbs = train.VGBS(A, n_mean, simple_embedding, threshold=False)

        n_mean_by_mode = [n_mean / dim] * dim
        samples = self.identity_sampler(n_mean_by_mode, n_samples=n_samples)
        vgbs.add_A_init_samples(samples)

        params = np.linspace(0, 1 / dim, dim)
        cost_fn = train.Stochastic(h, vgbs)
        cost = cost_fn(params, n_samples=n_samples)

        # We need to generate new samples and then calculate the cost with respect to them
        new_n_mean_by_mode = vgbs.mean_photons_by_mode(params)
        new_samples = self.identity_sampler(new_n_mean_by_mode, n_samples=n_samples)
        expected_cost = np.mean(np.sum((new_samples - objectives) ** 2, axis=1))

        assert np.allclose(cost, expected_cost, rtol=0.1)
示例#3
0
 def test_add_A_init_samples_bad_shape(self, adj, n_mean, dim, embedding):
     """Test that add_A_init_samples raises a ValueError when input samples of incorrect
     shape, i.e. of dim + 1 modes"""
     gbs = train.VGBS(adj, n_mean, embedding, True)
     s = np.ones((2, dim + 1))
     with pytest.raises(ValueError, match="Must input samples of shape"):
         gbs.add_A_init_samples(s)
 def test_W(self, adj, n_mean, params, embedding):
     """Test that the W method correctly gives the diagonal matrix of square root embedded
     parameters"""
     gbs = train.VGBS(adj, n_mean, embedding, True)
     W = gbs.W(params)
     assert np.allclose(np.diag(W)**2,
                        embedding(params))  # check that diagonal squared
示例#5
0
 def test_add_A_init_samples_already_there(self, adj, n_mean, dim, embedding):
     """Test that add_A_init_samples correctly adds more samples when some are already there"""
     gbs = train.VGBS(adj, n_mean, embedding, True)
     gbs.A_init_samples = np.ones((2, dim))
     gbs.add_A_init_samples(np.zeros((2, dim)))
     assert gbs.A_init_samples.shape == (4, dim)
     assert np.allclose(gbs.A_init_samples[:2], np.ones((2, dim)))
     assert np.allclose(gbs.A_init_samples[2:3], np.zeros((2, dim)))
示例#6
0
    def test_photons_clicks_comparison(self, n_mean, dim, adj, embedding):
        """Test that compares mean_photons_by_mode and mean_clicks_by_mode. We expect elements of
        n_mean_vec_photon to always be larger than n_mean_vec_click and also for elements of
        n_mean_vec_click to not exceed one."""
        params = np.zeros(dim)
        gbs = train.VGBS(adj, n_mean, embedding, False)
        n_mean_vec_photon = gbs.mean_photons_by_mode(params)
        n_mean_vec_click = gbs.mean_clicks_by_mode(params)

        assert (n_mean_vec_click <= 1).all()
        assert (n_mean_vec_photon >= n_mean_vec_click).all()
示例#7
0
def test_VGBS_integration(adj, params, n_mean, threshold, dim, embedding):
    """Integration test for the class ``train.VGBS``. We access the output adjacency matrix,
    mean photon number, and samples to check that they have the expected shape."""
    n_samples = 3
    gbs = train.VGBS(adj, n_mean, embedding, threshold)
    A_prime = gbs.A(params)
    n_mean_prime = gbs.n_mean(params)
    samples = gbs.generate_samples(A_prime, n_samples)
    assert A_prime.shape == (dim, dim)
    assert isinstance(n_mean_prime, float)
    assert samples.shape == (n_samples, dim)
示例#8
0
    def test_prob_sample_vacuum(self, n_mean, dim, threshold, embedding):
        """Test if prob_sample returns the correct probability of the vacuum, which can be
        calculated directly as the prefactor in the GBS distribution."""
        adj = np.ones((dim, dim))
        params = np.zeros(dim)
        gbs = train.VGBS(adj, n_mean, embedding, threshold)
        sample = np.zeros(dim)
        p = gbs.prob_sample(params, sample)

        O = train.param._Omat(gbs.A(params))
        scale = np.sqrt(np.linalg.det(np.identity(2 * dim) - O))

        assert np.allclose(scale, p)
示例#9
0
 def test_get_A_init_samples_none_there(self, adj, n_mean, monkeypatch, dim, embedding):
     """Test if get_A_init_samples generates the required samples when none are present in
     A_init_samples. To speed up sampling, we monkeypatch torontonian_sample_state to always
     return a numpy array of ones."""
     gbs = train.VGBS(adj, n_mean, embedding, True)
     with monkeypatch.context() as m:
         m.setattr(
             thewalrus.samples,
             "torontonian_sample_state",
             lambda *args, **kwargs: np.ones((args[1], dim)),
         )
         samples = gbs.get_A_init_samples(1000)
     assert np.allclose(samples, np.ones((1000, dim)))
示例#10
0
    def test_mean_clicks_by_mode(self, n_mean, dim, embedding):
        """Test that mean_clicks_by_mode is correct when given a simple fully connected
        adjacency matrix and an identity W. We expect each mode to have the same mean click number
        and for that to add up to n_mean."""
        adj = np.ones((dim, dim))
        params = np.zeros(dim)
        gbs = train.VGBS(adj, n_mean, embedding, True)
        n_mean_vec = gbs.mean_clicks_by_mode(params)

        assert np.allclose(np.sum(n_mean_vec), n_mean)  # check that the vector sums to n_mean
        assert np.allclose(n_mean_vec - n_mean_vec[0], np.zeros(dim))  # check that the vector is
        # constant
        assert np.allclose(n_mean_vec[0], n_mean / dim)  # check that elements have correct values
示例#11
0
    def test_prob_sample_different(self, n_mean, dim, embedding):
        """Test if prob_sample returns different probabilities for the same sample when using
        threshold and pnr modes."""
        adj = np.ones((dim, dim))
        params = np.zeros(dim)
        gbs = train.VGBS(adj, n_mean, embedding, True)
        sample = np.array([1, 1] + [0] * (dim - 2))
        p1 = gbs.prob_sample(params, sample)

        gbs.threshold = False
        p2 = gbs.prob_sample(params, sample)

        assert not np.allclose(p1, p2)
示例#12
0
 def test_get_A_init_samples_already_there(self, adj, n_mean, monkeypatch, dim, embedding):
     """Test if get_A_init_samples generates the required samples when some are already
     present in A_init_samples. We pre-load 200 samples of all zeros into VGBS and then
     request 1000 samples back. The sampling is monkeypatched to always return samples of
     ones, so that we hence expect 200 zero samples then 800 ones samples."""
     gbs = train.VGBS(adj, n_mean, embedding, True, np.zeros((200, dim)))
     with monkeypatch.context() as m:
         m.setattr(
             thewalrus.samples,
             "torontonian_sample_state",
             lambda *args, **kwargs: np.ones((args[1], dim)),
         )
         samples = gbs.get_A_init_samples(1000)
     assert np.allclose(samples[:200], np.zeros((200, dim)))
     assert np.allclose(samples[200:], np.ones((800, dim)))
示例#13
0
    def test_gradient(self, dim, n_mean, simple_embedding):
        """Test that the gradient evaluates as expected when compared to a value calculated by
        hand.

        Consider the problem with respect to a single mode. We want to calculate
        E((s - x) ** 2) with s the number of photons in the mode, x the element of the fixed
        vector, and with the expectation value calculated with respect to the (twice) negative
        binomial distribution. We know that E(s) = 2 * r * (1 - q) / q and
        Var(s) = 4 * (1 - q) * r / q ** 2 in terms of the r and q parameters of the negative
        binomial distribution. Using q = 1 / (1 + n_mean) with n_mean the mean number of
        photons in that mode and r = 0.5, we can calculate
        E((s - x) ** 2) = 3 * n_mean ** 2 + 2 * (1 - x) * n_mean + x ** 2,
        This can be differentiated to give the derivative:
        d/dx E((s - x) ** 2) = 6 * n_mean + 2 * (1 - x).
        """
        n_samples = 20000  # We need a lot of shots due to the high variance in the distribution
        objectives = np.linspace(0.5, 1.5, dim)
        h = self.h_setup(objectives)
        A = np.eye(dim)
        vgbs = train.VGBS(A, n_mean, simple_embedding, threshold=False)

        n_mean_by_mode = [n_mean / dim] * dim
        samples = self.identity_sampler(n_mean_by_mode, n_samples=n_samples)
        vgbs.add_A_init_samples(samples)

        params = np.linspace(0, 1 / dim, dim)
        cost_fn = train.Stochastic(h, vgbs)

        # We want to calculate dcost_by_dn as this is available analytically, where n is the mean
        # photon number. The following calculates this using the chain rule:
        dcost_by_dtheta = cost_fn.grad(params, n_samples=n_samples)
        dtheta_by_dw = 1 / np.diag(simple_embedding.jacobian(params))
        A_diag = np.diag(vgbs.A(params))
        A_init_diag = np.diag(vgbs.A_init)
        # Differentiate Eq. (8) of https://arxiv.org/abs/2004.04770 and invert for the next line
        dw_by_dn = (1 - A_diag**2) ** 2 / (2 * A_diag * A_init_diag)
        # Now use the chain rule
        dcost_by_dn = dcost_by_dtheta * dtheta_by_dw * dw_by_dn

        n_mean_by_mode = vgbs.mean_photons_by_mode(params)

        dcost_by_dn_expected = 6 * n_mean_by_mode + 2 * (1 - objectives)

        assert np.allclose(dcost_by_dn, dcost_by_dn_expected, 0.5)
示例#14
0
    def test_initial_cost(self, dim, n_mean, simple_embedding):
        """Test that the cost function evaluates as expected on initial parameters of all zeros"""
        n_samples = 1000
        objectives = np.linspace(0.5, 1.5, dim)
        h = self.h_setup(objectives)
        A = np.eye(dim)
        vgbs = train.VGBS(A, n_mean, simple_embedding, threshold=False)

        n_mean_by_mode = [n_mean / dim] * dim
        samples = self.identity_sampler(n_mean_by_mode, n_samples=n_samples)
        vgbs.add_A_init_samples(samples)

        params = np.zeros(dim)
        cost_fn = train.Stochastic(h, vgbs)
        cost = cost_fn(params, n_samples=n_samples)

        # We can directly calculate the cost with respect to the samples
        expected_cost = np.mean(np.sum((samples - objectives) ** 2, axis=1))

        assert np.allclose(cost, expected_cost)
示例#15
0
    def test_generate_samples(self, adj, n_mean, monkeypatch, embedding):
        """Test that generate_samples correctly dispatches between torontonian and hafnian
        sampling based upon whether threshold=True or threshold=False. This is done by
        monkeypatching torontonian_sample_state and hafnian_sample_state so that they simply
        return 0 and 1, respectively, instead of calculating samples. We then check that the
        returned samples are 0 in threshold mode and 1 when not in threshold mode."""
        gbs = train.VGBS(adj, n_mean, embedding, True)

        with monkeypatch.context() as m:
            m.setattr(thewalrus.samples, "torontonian_sample_state", lambda *args, **kwargs: 0)
            s_threshold = gbs.generate_samples(gbs.A_init, 10)

        gbs.threshold = False

        with monkeypatch.context() as m:
            m.setattr(thewalrus.samples, "hafnian_sample_state", lambda *args, **kwargs: 1)
            s_pnr = gbs.generate_samples(gbs.A_init, 10)

        assert s_threshold == 0
        assert s_pnr == 1
示例#16
0
 def test_add_A_init_samples_none_there(self, adj, n_mean, dim, embedding):
     """Test that add_A_init_samples correctly adds samples"""
     gbs = train.VGBS(adj, n_mean, embedding, True)
     s = np.ones((2, dim))
     gbs.add_A_init_samples(s)
     assert np.allclose(gbs.A_init_samples, s)
示例#17
0
def vgbs(A, n_mean, embedding, threshold):
    """VGBS for the fully connected adjacency matrix using the exponential embedding"""
    return train.VGBS(A, n_mean, embedding, threshold)
示例#18
0
 def test_get_A_init_samples_lots_there(self, adj, n_mean, dim, embedding):
     """Test if get_A_init_samples returns a portion of the pre-generated samples if
     ``n_samples`` is less than the number of samples stored."""
     gbs = train.VGBS(adj, n_mean, embedding, True, np.zeros((1000, dim)))
     samples = gbs.get_A_init_samples(200)
     assert samples.shape == (200, dim)