def test_rescaling_thermal(): r"""Test that the rescaled eigenvalues of the matrix give the correct mean photon number for thermal rescaling""" n = 10 A = generate_positive_definite_matrix(n) n_mean = 1.0 ls, _ = rescale_adjacency_matrix_thermal(A, n_mean) assert np.allclose(n_mean, np.sum(ls / (1 - ls)))
def test_mean_thermal(): r"""Test that the thermal samples have the correct mean photon number""" n = 10 n_samples = 100000 A = generate_positive_definite_matrix(n) n_mean = 10.0 ls, O = rescale_adjacency_matrix_thermal(A, n_mean) samples = np.array(generate_thermal_samples(ls, O, num_samples=n_samples)) tot_photon_sample = np.sum(samples, axis=1) n_mean_calc = tot_photon_sample.mean() assert np.allclose(n_mean_calc, n_mean, rtol=10 / np.sqrt(n_samples))
def test_dist_thermal(): r"""Test that the thermal sampling for a single mode produces the correct photon number distribution""" n_samples = 100000 n_mean = 1.0 A = generate_positive_definite_matrix(1) ls, O = rescale_adjacency_matrix_thermal(A, n_mean) samples = np.array(generate_thermal_samples(ls, O, num_samples=n_samples)) bins = np.arange(0, max(samples), 1) (freq, _) = np.histogram(samples, bins=bins) rel_freq = freq / n_samples expected = (1 / (1 + n_mean)) * (n_mean / (1 + n_mean))**(np.arange(len(rel_freq))) assert np.allclose(rel_freq, expected, atol=10 / np.sqrt(n_samples))
def sample(K: np.ndarray, n_mean: float, n_samples: int) -> list: """Sample subsets of points using the permanental point process. Points are encoded through a radial basis function kernel, provided in :func:`kernel`, that is a function of the distance between pairs of points. Subsets of points are sampled with probabilities that are proportional to the permanent of the *sub*matrix of the kernel selected by those points. This permanental point process is likely to sample points that are clustered together :cite:`jahangiri2019point`. It can be realised using a variant of Gaussian boson sampling with thermal states as input. **Example usage:** >>> K = np.array([[1., 0.36787944, 0.60653066, 0.60653066], >>> [0.36787944, 1., 0.60653066, 0.60653066], >>> [0.60653066, 0.60653066, 1., 0.36787944], >>> [0.60653066, 0.60653066, 0.36787944, 1.]]) >>> sample(K, 1.0, 10) [[0, 1, 1, 1], [0, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 0], [2, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 0, 0]] Args: K (array): the kernel matrix n_mean (float): average number of points n_samples (int): number of samples to be generated Returns: samples (list[list[int]]): samples generated by the point process """ ls, O = rescale_adjacency_matrix_thermal(K, n_mean) return np.array(generate_thermal_samples(ls, O, num_samples=n_samples)).tolist()
def test_number_moments_multimode_thermal(nmodes): r"""Test the correct values of the photon number means and covariances""" # This test requires nmodes > 1 n_samples = 100000 n_mean = 3.0 A = generate_positive_definite_matrix(nmodes) ls, O = rescale_adjacency_matrix_thermal(A, n_mean) Nmat = O @ np.diag(ls / (1.0 - ls)) @ O.T samples = np.array(generate_thermal_samples(ls, O, n_samples)) nmean_est = samples.mean(axis=0) cov_est = np.cov(samples.T) expected_cov = np.zeros_like(cov_est) for i in range(nmodes): for j in range(i): expected_cov[i, j] = Nmat[i, i] * Nmat[j, j] + Nmat[i, j]**2 expected_cov[j, i] = expected_cov[i, j] expected_cov[i, i] = 2 * (Nmat[i, i]**2) + Nmat[i, i] ## These moments are obtained using Wick's theorem for a multimode thermal state expected_cov = expected_cov - np.outer(np.diag(Nmat), np.diag(Nmat)) # To construct the covariance matrix we need to subtract the projector onto the mean assert np.allclose(nmean_est, np.diag(Nmat), rtol=20 / np.sqrt(n_samples)) assert np.allclose(expected_cov, cov_est, rtol=20 / np.sqrt(n_samples))