Skip to content

Commit

Permalink
Merge ca08b94 into a9dbb37
Browse files Browse the repository at this point in the history
  • Loading branch information
xabomon committed Sep 6, 2019
2 parents a9dbb37 + ca08b94 commit e3eea69
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 25 deletions.
68 changes: 47 additions & 21 deletions src/openfermion/transforms/_qubit_operator_transforms.py
Expand Up @@ -19,7 +19,9 @@


def project_onto_sector(operator, qubits, sectors):
'''
"""
Remove qubit by projecting onto sector.
Takes a QubitOperator, and projects out a list
of qubits, into either the +1 or -1 sector.
Note - this requires knowledge of which sector
Expand All @@ -37,21 +39,32 @@ def project_onto_sector(operator, qubits, sectors):
projected_operator: the resultant operator
Raises:
TypeError: operator must be a QubitOperator
'''
if type(operator) is not QubitOperator:
raise TypeError('''Input operator must be a QubitOperator''')
TypeError: operator must be a QubitOperator.
TypeError: qubits and sector must be an array-like.
ValueError: If qubits and sectors have different length.
ValueError: If sector are not specified as 0 or 1.
"""
if not isinstance(operator, QubitOperator):
raise TypeError('Input operator must be a QubitOperator.')
if not isinstance(qubits, (list, numpy.ndarray)):
raise TypeError('Qubit input must be an array-like.')
if not isinstance(sectors, (list, numpy.ndarray)):
raise TypeError('Sector input must be an array-like.')
if len(qubits) != len(sectors):
raise ValueError('Number of qubits and sectors must be equal.')
for i in sectors:
if i not in [0, 1]:
raise ValueError('Sectors must be 0 or 1.')

projected_operator = QubitOperator()
for term, factor in operator.terms.items():

# Any term containing X or Y on the removed
# qubits has an expectation value of zero
if [t for t in term if t[0] in qubits
and t[1] in ['X', 'Y']]:
if [t for t in term if t[0] in qubits and t[1] in ['X', 'Y']]:
continue

new_term = tuple((t[0]-len([q for q in qubits if q < t[0]]), t[1])
new_term = tuple((t[0] - len([q for q in qubits if q < t[0]]), t[1])
for t in term if t[0] not in qubits)
new_factor =\
factor * (-1)**(sum([sectors[qubits.index(t[0])]
Expand All @@ -62,8 +75,8 @@ def project_onto_sector(operator, qubits, sectors):


def projection_error(operator, qubits, sectors):
'''
Calculates the error from the project_onto_sector function.
"""
Calculate the error from the project_onto_sector function.
Args:
operator: the QubitOperator to work on
Expand All @@ -77,26 +90,39 @@ def projection_error(operator, qubits, sectors):
error: the trace norm of the removed term.
Raises:
TypeError: operator must be a QubitOperator
'''
if type(operator) is not QubitOperator:
raise TypeError('''Input operator must be a QubitOperator''')
TypeError: operator must be a QubitOperator.
TypeError: qubits and sector must be an array-like.
ValueError: If qubits and sectors have different length.
ValueError: If sector are not specified as 0 or 1.
"""
if not isinstance(operator, QubitOperator):
raise TypeError('Input operator must be a QubitOperator.')
if not isinstance(qubits, (list, numpy.ndarray)):
raise TypeError('Qubit input must be an array-like.')
if not isinstance(sectors, (list, numpy.ndarray)):
raise TypeError('Sector input must be an array-like.')
if len(qubits) != len(sectors):
raise ValueError('Number of qubits and sectors must be equal.')
for i in sectors:
if i not in [0, 1]:
raise ValueError('Sectors must be 0 or 1.')

error = 0
for term, factor in operator.terms.items():

# Any term containing X or Y on the removed
# qubits contributes to the error
if [t for t in term if t[0] in qubits
and t[1] in ['X', 'Y']]:
if [t for t in term if t[0] in qubits and t[1] in ['X', 'Y']]:
error += abs(factor)**2

return numpy.sqrt(error)


def rotate_qubit_by_pauli(qop, pauli, angle):
'''
Performs the rotation e^{-i \theta * P}Qe^{i \theta * P}
r"""
Rotate qubit operator by exponential of Pauli.
Perform the rotation e^{-i \theta * P}Qe^{i \theta * P}
on a qubitoperator Q and a Pauli operator P.
Args:
Expand All @@ -113,7 +139,7 @@ def rotate_qubit_by_pauli(qop, pauli, angle):
TypeError: qop must be a QubitOperator
TypeError: pauli must be a Pauli Operator (QubitOperator
with single term and coefficient equal to 1).
'''
"""
pvals = list(pauli.terms.values())
if type(qop) is not QubitOperator:
raise TypeError('This can only rotate QubitOperators')
Expand All @@ -127,7 +153,7 @@ def rotate_qubit_by_pauli(qop, pauli, angle):
even_terms = 0.5 * (qop + pqp)
odd_terms = 0.5 * (qop - pqp)

rotated_op = even_terms + numpy.cos(2*angle) * odd_terms + \
1j * numpy.sin(2*angle) * odd_terms * pauli
rotated_op = even_terms + numpy.cos(2 * angle) * odd_terms + \
1j * numpy.sin(2 * angle) * odd_terms * pauli

return rotated_op
46 changes: 42 additions & 4 deletions src/openfermion/transforms/_qubit_operator_transforms_test.py
Expand Up @@ -26,14 +26,52 @@ class ProjectionTest(unittest.TestCase):
def setUp(self):
pass

def test_function_errors(self):
"""Test main function errors."""
operator = (QubitOperator('Z0 X1', 1.0) +
QubitOperator('X1', 2.0))
sector1 = [0]
sector2 = [1]
qbt_list = [0]
with self.assertRaises(TypeError):
project_onto_sector(operator=1.0, qubits=qbt_list, sectors=sector1)
with self.assertRaises(TypeError):
projection_error(operator=1.0, qubits=qbt_list, sectors=sector1)
with self.assertRaises(TypeError):
project_onto_sector(operator=operator, qubits=0.0, sectors=sector2)
with self.assertRaises(TypeError):
projection_error(operator=operator, qubits=0.0, sectors=sector2)
with self.assertRaises(TypeError):
project_onto_sector(operator=operator,
qubits=qbt_list, sectors=operator)
with self.assertRaises(TypeError):
projection_error(operator=operator,
qubits=qbt_list, sectors=operator)
with self.assertRaises(ValueError):
project_onto_sector(operator=operator, qubits=[
0, 1], sectors=sector1)
with self.assertRaises(ValueError):
projection_error(operator=operator, qubits=[0, 1], sectors=sector1)
with self.assertRaises(ValueError):
project_onto_sector(operator=operator,
qubits=qbt_list, sectors=[0, 0])
with self.assertRaises(ValueError):
projection_error(operator=operator,
qubits=qbt_list, sectors=[0, 0])
with self.assertRaises(ValueError):
project_onto_sector(operator=operator,
qubits=qbt_list, sectors=[-1])
with self.assertRaises(ValueError):
projection_error(operator=operator, qubits=qbt_list, sectors=[-1])

def test_projection(self):
coefficient = 0.5
opstring = ((0, 'X'), (1, 'X'), (2, 'Z'))
opstring2 = ((0, 'X'), (2, 'Z'), (3, 'Z'))
operator = QubitOperator(opstring, coefficient)
operator += QubitOperator(opstring2, coefficient)
new_operator = project_onto_sector(
operator, qubits=[2, 3], sectors=[0, 1])
operator, qubits=[2, 3], sectors=[0, 1])
error = projection_error(operator, qubits=[2, 3], sectors=[0, 1])
self.assertEqual(count_qubits(new_operator), 2)
self.assertEqual(error, 0)
Expand Down Expand Up @@ -67,7 +105,7 @@ def test_rotation(self):
qop += QubitOperator('Z0 Z1', 1)
rot_op = QubitOperator('Z1', 1)

rotated_qop = rotate_qubit_by_pauli(qop, rot_op, numpy.pi/4)
rotated_qop = rotate_qubit_by_pauli(qop, rot_op, numpy.pi / 4)
comp_op = QubitOperator('Z0 Z1', 1)
comp_op += QubitOperator('X0 Y1', 1)
self.assertEqual(comp_op, rotated_qop)
Expand All @@ -80,6 +118,6 @@ def test_exception_Pauli(self):
rot_op2 = QubitOperator('Z1', 1)
ferm_op = FermionOperator('1^ 2', 1)
with self.assertRaises(TypeError):
rotate_qubit_by_pauli(qop, rot_op, numpy.pi/4)
rotate_qubit_by_pauli(qop, rot_op, numpy.pi / 4)
with self.assertRaises(TypeError):
rotate_qubit_by_pauli(ferm_op, rot_op2, numpy.pi/4)
rotate_qubit_by_pauli(ferm_op, rot_op2, numpy.pi / 4)

0 comments on commit e3eea69

Please sign in to comment.