def test_diagonalizing_bogoliubov_transform(self):
        """Test diagonalizing Bogoliubov transform."""
        hermitian_part = numpy.array(
            [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], dtype=complex)
        antisymmetric_part = numpy.array(
            [[0.0, 1.0j, 0.0], [-1.0j, 0.0, 1.0j], [0.0, -1.0j, 0.0]],
            dtype=complex)
        quad_ham = QuadraticHamiltonian(hermitian_part, antisymmetric_part)
        block_matrix = numpy.zeros((6, 6), dtype=complex)
        block_matrix[:3, :3] = antisymmetric_part
        block_matrix[:3, 3:] = hermitian_part
        block_matrix[3:, :3] = -hermitian_part.conj()
        block_matrix[3:, 3:] = -antisymmetric_part.conj()

        _, transformation_matrix, _ = (
            quad_ham.diagonalizing_bogoliubov_transform())
        left_block = transformation_matrix[:, :3]
        right_block = transformation_matrix[:, 3:]
        ferm_unitary = numpy.zeros((6, 6), dtype=complex)
        ferm_unitary[:3, :3] = left_block
        ferm_unitary[:3, 3:] = right_block
        ferm_unitary[3:, :3] = numpy.conjugate(right_block)
        ferm_unitary[3:, 3:] = numpy.conjugate(left_block)

        # Check that the transformation is diagonalizing
        majorana_matrix, _ = quad_ham.majorana_form()
        canonical, _ = antisymmetric_canonical_form(majorana_matrix)
        diagonalized = ferm_unitary.conj().dot(
            block_matrix.dot(ferm_unitary.T.conj()))
        for i in numpy.ndindex((6, 6)):
            self.assertAlmostEqual(diagonalized[i], canonical[i])
 def test_equality(self):
     """Test that the decomposition is valid."""
     n = 7
     antisymmetric_matrix = random_antisymmetric_matrix(2 * n,
                                                        real=True,
                                                        seed=9799)
     canonical, orthogonal = antisymmetric_canonical_form(
         antisymmetric_matrix)
     result_matrix = orthogonal.dot(antisymmetric_matrix.dot(orthogonal.T))
     for i in numpy.ndindex(result_matrix.shape):
         self.assertAlmostEqual(result_matrix[i], canonical[i])
    def test_diagonalizing_bogoliubov_transform_non_particle_conserving(self):
        """Test non-particle-conserving diagonalizing Bogoliubov transform."""
        hermitian_part = self.quad_ham_npc.combined_hermitian_part
        antisymmetric_part = self.quad_ham_npc.antisymmetric_part
        block_matrix = numpy.zeros((2 * self.n_qubits, 2 * self.n_qubits),
                                   dtype=complex)
        block_matrix[:self.n_qubits, :self.n_qubits] = antisymmetric_part
        block_matrix[:self.n_qubits, self.n_qubits:] = hermitian_part
        block_matrix[self.n_qubits:, :self.n_qubits] = -hermitian_part.conj()
        block_matrix[self.n_qubits:,
                     self.n_qubits:] = (-antisymmetric_part.conj())

        _, transformation_matrix, _ = (
            self.quad_ham_npc.diagonalizing_bogoliubov_transform())
        left_block = transformation_matrix[:, :self.n_qubits]
        right_block = transformation_matrix[:, self.n_qubits:]
        ferm_unitary = numpy.zeros((2 * self.n_qubits, 2 * self.n_qubits),
                                   dtype=complex)
        ferm_unitary[:self.n_qubits, :self.n_qubits] = left_block
        ferm_unitary[:self.n_qubits, self.n_qubits:] = right_block
        ferm_unitary[self.n_qubits:, :self.n_qubits] = numpy.conjugate(
            right_block)
        ferm_unitary[self.n_qubits:,
                     self.n_qubits:] = numpy.conjugate(left_block)

        # Check that the transformation is diagonalizing
        majorana_matrix, _ = self.quad_ham_npc.majorana_form()
        canonical, _ = antisymmetric_canonical_form(majorana_matrix)
        diagonalized = ferm_unitary.conj().dot(
            block_matrix.dot(ferm_unitary.T.conj()))
        for i in numpy.ndindex((2 * self.n_qubits, 2 * self.n_qubits)):
            self.assertAlmostEqual(diagonalized[i], canonical[i])

        lower_unitary = ferm_unitary[self.n_qubits:]
        lower_left = lower_unitary[:, :self.n_qubits]
        lower_right = lower_unitary[:, self.n_qubits:]

        # Check that lower_left and lower_right satisfy the constraints
        # necessary for the transformed fermionic operators to satisfy
        # the fermionic anticommutation relations
        constraint_matrix_1 = (lower_left.dot(lower_left.T.conj()) +
                               lower_right.dot(lower_right.T.conj()))
        constraint_matrix_2 = (lower_left.dot(lower_right.T) +
                               lower_right.dot(lower_left.T))

        identity = numpy.eye(self.n_qubits, dtype=complex)
        for i in numpy.ndindex((self.n_qubits, self.n_qubits)):
            self.assertAlmostEqual(identity[i], constraint_matrix_1[i])
            self.assertAlmostEqual(0., constraint_matrix_2[i])
    def test_canonical(self):
        """Test that the returned canonical matrix has the right form."""
        n = 7
        # Obtain a random antisymmetric matrix
        antisymmetric_matrix = random_antisymmetric_matrix(2 * n,
                                                           real=True,
                                                           seed=29206)
        canonical, _ = antisymmetric_canonical_form(antisymmetric_matrix)
        for i in range(2 * n):
            for j in range(2 * n):
                if i < n and j == n + i:
                    self.assertTrue(canonical[i, j] >= 0.0)
                elif i >= n and j == i - n:
                    self.assertTrue(canonical[i, j] < 0.0)
                else:
                    self.assertAlmostEqual(canonical[i, j], 0.)

        diagonal = canonical[range(n), range(n, 2 * n)]
        for i in range(n - 1):
            self.assertTrue(diagonal[i] <= diagonal[i + 1])
 def test_not_antisymmetric(self):
     n = 4
     ones_mat = numpy.ones((n, n))
     with self.assertRaises(ValueError):
         _ = antisymmetric_canonical_form(ones_mat)
 def test_bad_dimensions(self):
     n, p = (3, 4)
     ones_mat = numpy.ones((n, p))
     with self.assertRaises(ValueError):
         _ = antisymmetric_canonical_form(ones_mat)