/
conversions.py
252 lines (196 loc) · 8.4 KB
/
conversions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Union
import itertools
import numpy
import sympy
from openfermion.ops.operators import QuadOperator, BosonOperator, FermionOperator, MajoranaOperator
from openfermion.ops.representations import PolynomialTensor, DiagonalCoulombHamiltonian
from openfermion.utils.operator_utils import count_qubits
def get_quad_operator(operator, hbar=1.0):
"""Convert to QuadOperator.
Args:
operator: BosonOperator.
hbar (float): the value of hbar used in the definition
of the commutator [q_i, p_j] = i hbar delta_ij.
By default hbar=1.
Returns:
quad_operator: An instance of the QuadOperator class.
"""
quad_operator = QuadOperator()
if isinstance(operator, BosonOperator):
for term, coefficient in operator.terms.items():
tmp = QuadOperator('', coefficient)
for i, d in term:
tmp *= (1.0 / numpy.sqrt(2.0 * hbar)) * (
QuadOperator(((i, 'q'))) + QuadOperator(((i, 'p')), 1j * (-1) ** d)
)
quad_operator += tmp
else:
raise TypeError("Only BosonOperator is currently " "supported for get_quad_operator.")
return quad_operator
def check_no_sympy(operator):
"""Checks whether a SymbolicOperator contains any
sympy expressions, which will prevent it being converted
to a PolynomialTensor or DiagonalCoulombHamiltonian
Args:
operator(SymbolicOperator): the operator to be tested
"""
for key in operator.terms:
if isinstance(operator.terms[key], sympy.Expr):
raise TypeError(
'This conversion is currently not supported '
+ 'for operators with sympy expressions '
+ 'as coefficients'
)
def get_boson_operator(operator, hbar=1.0):
"""Convert to BosonOperator.
Args:
operator: QuadOperator.
hbar (float): the value of hbar used in the definition
of the commutator [q_i, p_j] = i hbar delta_ij.
By default hbar=1.
Returns:
boson_operator: An instance of the BosonOperator class.
"""
boson_operator = BosonOperator()
if isinstance(operator, QuadOperator):
for term, coefficient in operator.terms.items():
tmp = BosonOperator('', coefficient)
for i, d in term:
if d == 'q':
coeff = numpy.sqrt(hbar / 2)
sign = 1
elif d == 'p':
coeff = -1j * numpy.sqrt(hbar / 2)
sign = -1
tmp *= coeff * (BosonOperator(((i, 0))) + BosonOperator(((i, 1)), sign))
boson_operator += tmp
else:
raise TypeError("Only QuadOperator is currently " "supported for get_boson_operator.")
return boson_operator
def get_fermion_operator(operator):
"""Convert to FermionOperator.
Returns:
fermion_operator: An instance of the FermionOperator class.
"""
if isinstance(operator, PolynomialTensor):
return _polynomial_tensor_to_fermion_operator(operator)
elif isinstance(operator, DiagonalCoulombHamiltonian):
return _diagonal_coulomb_hamiltonian_to_fermion_operator(operator)
elif isinstance(operator, MajoranaOperator):
return _majorana_operator_to_fermion_operator(operator)
else:
raise TypeError('{} cannot be converted to FermionOperator'.format(type(operator)))
def _polynomial_tensor_to_fermion_operator(operator):
fermion_operator = FermionOperator()
for term in operator:
fermion_operator += FermionOperator(term, operator[term])
return fermion_operator
def _diagonal_coulomb_hamiltonian_to_fermion_operator(operator):
fermion_operator = FermionOperator()
n_qubits = count_qubits(operator)
fermion_operator += FermionOperator((), operator.constant)
for p, q in itertools.product(range(n_qubits), repeat=2):
fermion_operator += FermionOperator(((p, 1), (q, 0)), operator.one_body[p, q])
fermion_operator += FermionOperator(
((p, 1), (p, 0), (q, 1), (q, 0)), operator.two_body[p, q]
)
return fermion_operator
def _majorana_operator_to_fermion_operator(majorana_operator):
fermion_operator = FermionOperator()
for term, coeff in majorana_operator.terms.items():
converted_term = _majorana_term_to_fermion_operator(term)
converted_term *= coeff
fermion_operator += converted_term
return fermion_operator
def _majorana_term_to_fermion_operator(term):
converted_term = FermionOperator(())
for index in term:
j, b = divmod(index, 2)
if b:
converted_op = FermionOperator((j, 0), -1j)
converted_op += FermionOperator((j, 1), 1j)
else:
converted_op = FermionOperator((j, 0))
converted_op += FermionOperator((j, 1))
converted_term *= converted_op
return converted_term
def get_majorana_operator(
operator: Union[PolynomialTensor, DiagonalCoulombHamiltonian, FermionOperator]
) -> MajoranaOperator:
"""
Convert to MajoranaOperator.
Uses the convention of even + odd indexing of Majorana modes derived from
a fermionic mode:
fermion annhil. c_k -> ( gamma_{2k} + 1.j * gamma_{2k+1} ) / 2
fermion creation c^_k -> ( gamma_{2k} - 1.j * gamma_{2k+1} ) / 2
Args:
operator (PolynomialTensor,
DiagonalCoulombHamiltonian or
FermionOperator): Operator to write as Majorana Operator.
Returns:
majorana_operator: An instance of the MajoranaOperator class.
Raises:
TypeError: If operator is not of PolynomialTensor,
DiagonalCoulombHamiltonian or FermionOperator.
"""
if isinstance(operator, FermionOperator):
return _fermion_operator_to_majorana_operator(operator)
elif isinstance(operator, (PolynomialTensor, DiagonalCoulombHamiltonian)):
return _fermion_operator_to_majorana_operator(get_fermion_operator(operator))
raise TypeError('{} cannot be converted to MajoranaOperator'.format(type(operator)))
def _fermion_operator_to_majorana_operator(fermion_operator: FermionOperator) -> MajoranaOperator:
"""
Convert FermionOperator to MajoranaOperator.
Auxiliar function of get_majorana_operator.
Args:
fermion_operator (FermionOperator): To convert to MajoranaOperator.
Returns:
majorana_operator object.
Raises:
TypeError: if input is not a FermionOperator.
"""
if not isinstance(fermion_operator, FermionOperator):
raise TypeError('Input a FermionOperator.')
majorana_operator = MajoranaOperator()
for term, coeff in fermion_operator.terms.items():
converted_term = _fermion_term_to_majorana_operator(term)
converted_term *= coeff
majorana_operator += converted_term
return majorana_operator
def _fermion_term_to_majorana_operator(term: tuple) -> MajoranaOperator:
"""
Convert single terms of FermionOperator to Majorana.
(Auxiliary function of get_majorana_operator.)
Convention: even + odd indexing of Majorana modes derived from a
fermionic mode:
fermion annhil. c_k -> ( gamma_{2k} + 1.j * gamma_{2k+1} ) / 2
fermion creation c^_k -> ( gamma_{2k} - 1.j * gamma_{2k+1} ) / 2
Args:
term (tuple): single FermionOperator term.
Returns:
converted_term: single MajoranaOperator term.
Raises:
TypeError: if term is a tuple.
"""
if not isinstance(term, tuple):
raise TypeError('Term does not have the correct Type.')
converted_term = MajoranaOperator(())
for index, action in term:
converted_op = MajoranaOperator((2 * index,), 0.5)
if action:
converted_op += MajoranaOperator((2 * index + 1,), -0.5j)
else:
converted_op += MajoranaOperator((2 * index + 1,), 0.5j)
converted_term *= converted_op
return converted_term