def test_canonical(self): """Test that the returned canonical matrix has the right form.""" n = 7 # Obtain a random antisymmetric matrix rand_mat = numpy.random.randn(2 * n, 2 * n) antisymmetric_matrix = rand_mat - rand_mat.T canonical, orthogonal = 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] > -EQ_TOLERANCE) elif i >= n and j == i - n: self.assertTrue(canonical[i, j] < EQ_TOLERANCE) 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_diagonalizes_quadratic_hamiltonian(self): """Test that the unitary returned indeed diagonalizes a quadratic Hamiltonian.""" 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()) majorana_matrix, majorana_constant = self.quad_ham_npc.majorana_form() canonical, orthogonal = antisymmetric_canonical_form(majorana_matrix) ferm_unitary = diagonalizing_fermionic_unitary(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])
def test_diagonalizing_bogoliubov_transform(self): """Test getting the diagonalizing Bogoliubov transformation.""" 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()) ferm_unitary = self.quad_ham_npc.diagonalizing_bogoliubov_transform() # Check that the transformation is diagonalizing majorana_matrix, majorana_constant = self.quad_ham_npc.majorana_form() canonical, orthogonal = 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_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)