def test_random_operators_are_reproducible(self):
        op1 = random_diagonal_coulomb_hamiltonian(5, seed=5947)
        op2 = random_diagonal_coulomb_hamiltonian(5, seed=5947)
        numpy.testing.assert_allclose(op1.one_body, op2.one_body)
        numpy.testing.assert_allclose(op1.two_body, op2.two_body)

        op1 = random_interaction_operator(5, seed=8911)
        op2 = random_interaction_operator(5, seed=8911)
        numpy.testing.assert_allclose(op1.one_body_tensor, op2.one_body_tensor)
        numpy.testing.assert_allclose(op1.two_body_tensor, op2.two_body_tensor)

        op1 = random_quadratic_hamiltonian(5, seed=17711)
        op2 = random_quadratic_hamiltonian(5, seed=17711)
        numpy.testing.assert_allclose(op1.combined_hermitian_part,
                                      op2.combined_hermitian_part)
        numpy.testing.assert_allclose(op1.antisymmetric_part,
                                      op2.antisymmetric_part)

        op1 = random_antisymmetric_matrix(5, seed=24074)
        op2 = random_antisymmetric_matrix(5, seed=24074)
        numpy.testing.assert_allclose(op1, op2)

        op1 = random_hermitian_matrix(5, seed=56753)
        op2 = random_hermitian_matrix(5, seed=56753)
        numpy.testing.assert_allclose(op1, op2)

        op1 = random_unitary_matrix(5, seed=56486)
        op2 = random_unitary_matrix(5, seed=56486)
        numpy.testing.assert_allclose(op1, op2)
    def test_square(self):
        m, n = (3, 3)

        # Obtain a random matrix of orthonormal rows
        Q = random_unitary_matrix(n)
        Q = Q[:m, :]
        Q = Q[:m, :]

        # Get Givens decomposition of Q
        givens_rotations, V, diagonal = givens_decomposition(Q)

        # There should be no Givens rotations
        self.assertEqual(givens_rotations, list())

        # Compute V * Q * U^\dagger
        W = V.dot(Q)

        # Construct the diagonal matrix
        D = numpy.zeros((m, n), dtype=complex)
        D[numpy.diag_indices(m)] = diagonal

        # Assert that W and D are the same
        for i in range(m):
            for j in range(n):
                self.assertAlmostEqual(D[i, j], W[i, j])
    def test_real_numbers(self):
        for m, n in self.test_dimensions:
            # Obtain a random real matrix of orthonormal rows
            Q = random_unitary_matrix(n, real=True)
            Q = Q[:m, :]

            # Get Givens decomposition of Q
            givens_rotations, V, diagonal = givens_decomposition(Q)

            # Compute U
            U = numpy.eye(n, dtype=complex)
            for parallel_set in givens_rotations:
                combined_givens = numpy.eye(n, dtype=complex)
                for i, j, theta, phi in reversed(parallel_set):
                    c = numpy.cos(theta)
                    s = numpy.sin(theta)
                    phase = numpy.exp(1.j * phi)
                    G = numpy.array([[c, -phase * s],
                                    [s, phase * c]], dtype=complex)
                    givens_rotate(combined_givens, G, i, j)
                U = combined_givens.dot(U)

            # Compute V * Q * U^\dagger
            W = V.dot(Q.dot(U.T.conj()))

            # Construct the diagonal matrix
            D = numpy.zeros((m, n), dtype=complex)
            D[numpy.diag_indices(m)] = diagonal

            # Assert that W and D are the same
            for i in range(m):
                for j in range(n):
                    self.assertAlmostEqual(D[i, j], W[i, j])
    def test_bad_dimensions(self):
        m, n = (3, 2)

        # Obtain a random matrix of orthonormal rows
        Q = random_unitary_matrix(m)
        Q = Q[:m, :]
        Q = Q[:m, :n]

        with self.assertRaises(ValueError):
            _ = givens_decomposition(Q)