def test_approx_negative_error(): """Check exception raised if matrix is negative""" A = np.ones([6, 6]) A[0, 0] = -1 with pytest.raises(ValueError, match="Input matrix must not have negative entries"): hafnian(A, approx=True)
def test_complex_wrapper(self): """Check hafnian(A)=haf_complex(A) for a random real matrix. """ A = np.complex128(np.random.random([6, 6])) A += 1j * np.random.random([6, 6]) A += A.T haf = hafnian(A) expected = haf_complex(A) assert np.allclose(haf, expected) haf = hafnian(A, loop=True) expected = haf_complex(A, loop=True) assert np.allclose(haf, expected)
def test_valid_output(self, random_matrix, n, fill): """Tests that sparse loop hafnian matches full implementation""" A = random_matrix(n, fill_factor=fill) assert np.allclose( hafnian_sparse(A, loop=True), hafnian_sparse(A, D=set(range(len(A))), loop=True), ) assert np.allclose( hafnian_sparse(A, loop=False), hafnian_sparse(A, D=set(range(len(A))), loop=False), ) assert np.allclose(hafnian(A, loop=True), hafnian_sparse(A, loop=True)) assert np.allclose(hafnian(A, loop=False), hafnian_sparse(A, loop=False))
def FockDensityMatrix(cov, mu, m, n, tol=1e-10): if np.max(cov - cov.T) > tol: raise ValueError("Covariance matrix must be symmetric.") else: cov = (cov + cov.T) / 2 N = np.int(cov.shape[0] / 2) cov_Q = RtoQmat(cov) cov_Q_inv = np.linalg.inv(cov_Q) cov_Q_det = np.linalg.det(cov_Q) mu_Q = RtoTvec(mu) T1 = np.exp(-0.5 * np.dot(np.dot(np.conj(mu_Q), cov_Q_inv), mu_Q)) T2 = np.sqrt(cov_Q_det * np.prod(special.factorial(m)) * np.prod(special.factorial(n))) T = T1 / T2 X = np.block([[np.zeros([N, N]), np.eye(N)], [np.eye(N), np.zeros([N, N])]]) A = np.dot(X, (np.eye(2 * N) - cov_Q_inv)) A = (A + A.T) / 2 # cancel the numeric error of symmetray A_rp = np.repeat(A, np.hstack([n, m]), axis=0) A_rp = np.repeat(A_rp, np.hstack([n, m]), axis=1) gamma = np.dot(np.conj(mu_Q), cov_Q_inv) gamma_rp = np.repeat(gamma, np.hstack([n, m])) np.fill_diagonal(A_rp, gamma_rp) prob = T * hafnian(A_rp, loop=True) return prob
def test_4x4_zero_diag(self, random_matrix): """Check 4x4 loop hafnian with zero diagonals""" A = random_matrix(4) A = A - np.diag(np.diag(A)) haf = hafnian(A, loop=True) expected = A[0, 1] * A[2, 3] + A[0, 2] * A[1, 3] + A[0, 3] * A[1, 2] assert np.allclose(haf, expected)
def test_diag(self, n): """Check loophafnian of diagonal matrix is product of diagonals""" v = np.random.rand(n) A = np.diag(v) haf = hafnian(A, loop=True) expected = np.prod(v) assert np.allclose(haf, expected)
def test_rank_r(r, n): """Test rank-r matrices""" G = np.random.rand(n, r) + 1j * np.random.rand(n, r) A = G @ G.T haf = low_rank_hafnian(G) expected = hafnian(A) assert np.allclose(haf, expected)
def test_int_wrapper_loop(self): """Check hafnian(A, loop=True)=haf_real(A, loop=True) for a random integer matrix. """ A = np.int64(np.ones([6, 6])) haf = hafnian(A, loop=True) expected = haf_real(np.float64(A), loop=True) assert np.allclose(haf, expected)
def test_rank_one(n): """Test the hafnian of rank one matrices so that it is within 10% of the exact value""" x = np.random.rand(n) A = np.outer(x, x) exact = factorial2(n - 1) * np.prod(x) approx = hafnian(A, approx=True, num_samples=10000) assert np.allclose(approx, exact, rtol=2e-1, atol=0)
def test_int_wrapper(self): """Check hafnian(A)=haf_int(A) for a random integer matrix. """ A = np.int64(np.ones([6, 6])) haf = hafnian(A) expected = haf_int(np.int64(A)) assert np.allclose(haf, expected)
def test_block_ones(self, n, dtype, recursive): """Check hafnian([[0, I_n], [I_n, 0]])=n!""" O = np.zeros([n, n]) B = np.ones([n, n]) A = np.vstack([np.hstack([O, B]), np.hstack([B, O])]) A = dtype(A) haf = hafnian(A, recursive=recursive) expected = float(fac(n)) assert np.allclose(haf, expected)
def test_4x4(self, random_matrix): """Check 4x4 loop hafnian""" A = random_matrix(4) haf = hafnian(A, loop=True) expected = (A[0, 1] * A[2, 3] + A[0, 2] * A[1, 3] + A[0, 3] * A[1, 2] + A[0, 0] * A[1, 1] * A[2, 3] + A[0, 1] * A[2, 2] * A[3, 3] + A[0, 2] * A[1, 1] * A[3, 3] + A[0, 0] * A[2, 2] * A[1, 3] + A[0, 0] * A[3, 3] * A[1, 2] + A[0, 3] * A[1, 1] * A[2, 2] + A[0, 0] * A[1, 1] * A[2, 2] * A[3, 3]) assert np.allclose(haf, expected)
def test_real_wrapper(self): """Check hafnian(A)=haf_real(A) for a random real matrix. """ A = np.random.random([6, 6]) A += A.T haf = hafnian(A) expected = haf_real(A) assert np.allclose(haf, expected) haf = hafnian(A, loop=True) expected = haf_real(A, loop=True) assert np.allclose(haf, expected) A = np.random.random([6, 6]) A += A.T A = np.array(A, dtype=np.complex128) haf = hafnian(A) expected = haf_real(np.float64(A.real)) assert np.allclose(haf, expected)
def test_slow_hafnian_four(self): """ Tests slow hafnian function against four-by-four graphs """ for i in range(1): # how many tests to perform graph = gnp_random_graph(10, 0.5) nx.draw(graph) plt.show() # displays graph (cumbersome for large tests) adj = to_numpy_array(graph) # create adjacency matrix walrus = thewalrus.hafnian(adj) # calculate hafnian with Xanadu library haf = hafnian.slow_hafnian(adj) # calculate my hafnian self.assertEqual(walrus, haf) # compare!
def test_4x4(self, random_matrix, recursive): """Check 4x4 hafnian""" A = random_matrix(4) haf = hafnian(A, recursive=recursive) expected = A[0, 1] * A[2, 3] + A[0, 2] * A[1, 3] + A[0, 3] * A[1, 2] assert np.allclose(haf, expected)
def test_nan(self): """Check exception for non-finite matrix""" A = np.array([[2, 1], [1, np.nan]]) with pytest.raises(ValueError): hafnian(A)
def test_empty_matrix(self): """Check empty matrix returns 1""" A = np.ndarray((0, 0)) res = hafnian(A) assert res == 1
def test_odd_dim(self): """Check hafnian for matrix with odd dimensions""" A = np.ones([3, 3]) assert hafnian(A) == 0
def test_non_symmetric_exception(self): """Check exception for non-symmetric matrix""" A = np.ones([4, 4]) A[0, 1] = 0.0 with pytest.raises(ValueError): hafnian(A)
def test_array_exception(self): """Check exception for non-matrix argument""" with pytest.raises(TypeError): hafnian(1)
def test_square_exception(self): """Check exception for non-square argument""" A = np.zeros([2, 3]) with pytest.raises(ValueError): hafnian(A)
def test_3x3(self, dtype, recursive): """Check 3x3 hafnian""" A = dtype(np.ones([3, 3])) haf = hafnian(A, recursive=recursive) assert haf == 0.0
def test_identity(self, n, dtype, recursive): """Check hafnian(I)=0""" A = dtype(np.identity(n)) haf = hafnian(A, recursive=recursive) assert np.allclose(haf, 0)
def test_ones(self, n, dtype, recursive): """Check hafnian(J_2n)=(2n)!/(n!2^n)""" A = dtype(np.ones([2 * n, 2 * n])) haf = hafnian(A, recursive=recursive) expected = fac(2 * n) / (fac(n) * (2**n)) assert np.allclose(haf, expected)
def test_2x2(self, random_matrix): """Check 2x2 loop hafnian""" A = random_matrix(2) haf = hafnian(A, loop=True) assert np.allclose(haf, A[0, 1] + A[0, 0] * A[1, 1])
def test_3x3(self, dtype): """Check 3x3 loop hafnian""" A = dtype(np.ones([3, 3])) haf = hafnian(A, loop=True) assert haf == 4.0
def test_approx_complex_error(): """Check exception raised if matrix is complex""" A = 1j * np.ones([6, 6]) with pytest.raises(ValueError, match="Input matrix must be real"): hafnian(A, approx=True)
def test_identity(self, n, dtype): """Check loop hafnian(I)=1""" A = dtype(np.identity(n)) haf = hafnian(A, loop=True) assert np.allclose(haf, 1)
def test_ones_approx(n): """Check hafnian_approx(J_2n)=(2n)!/(n!2^n)""" A = np.float64(np.ones([2 * n, 2 * n])) haf = hafnian(A, approx=True, num_samples=10000) expected = fac(2 * n) / (fac(n) * (2**n)) assert np.abs(haf - expected) / expected < 0.2
def test_ones(self, n, dtype): """Check loop hafnian(J_n)=T(n)""" A = dtype(np.ones([n, n])) haf = hafnian(A, loop=True) expected = T[n] assert np.allclose(haf, expected)