Repository: quantumlib/OpenFermion
Pull request #514 (2019-05-02 00:46:27)

Implement conversion from MajoranaOperator to FermionOperator


Patch:
diff --git a/src/openfermion/transforms/_conversion.py b/src/openfermion/transforms/_conversion.py
index 2f058f0..f1ffdf8 100644
--- a/src/openfermion/transforms/_conversion.py
+++ b/src/openfermion/transforms/_conversion.py
@@ -24,6 +24,7 @@ from openfermion.ops import (DiagonalCoulombHamiltonian,
                              FermionOperator,
                              InteractionOperator,
                              InteractionRDM,
+                             MajoranaOperator,
                              PolynomialTensor,
                              QuadraticHamiltonian,
                              QubitOperator,
@@ -377,26 +378,61 @@ def get_fermion_operator(operator):
     Returns:
         fermion_operator: An instance of the FermionOperator class.
     """
-    n_qubits = count_qubits(operator)
+    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
 
-    if isinstance(operator, PolynomialTensor):
-        for term in operator:
-            fermion_operator += FermionOperator(term, operator[term])
 
-    elif isinstance(operator, DiagonalCoulombHamiltonian):
-        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])
+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_molecular_data(interaction_operator,
                        geometry=None, basis=None, multiplicity=None,
                        n_electrons=None, reduce_spin=True,


Test patch:
diff --git a/src/openfermion/transforms/_conversion_test.py b/src/openfermion/transforms/_conversion_test.py
index 82bf5f2..ad7985f 100644
--- a/src/openfermion/transforms/_conversion_test.py
+++ b/src/openfermion/transforms/_conversion_test.py
@@ -16,11 +16,13 @@ from __future__ import absolute_import
 import unittest
 
 import numpy
+import pytest
 
 from openfermion.hamiltonians import fermi_hubbard
 from openfermion.ops import (BosonOperator,
                              DiagonalCoulombHamiltonian,
                              FermionOperator,
+                             MajoranaOperator,
                              QuadOperator,
                              QubitOperator)
 from openfermion.transforms import jordan_wigner
@@ -486,3 +488,22 @@ class GetBosonOperatorTest(unittest.TestCase):
                + (BosonOperator('0') - BosonOperator('0^'))
                * (BosonOperator('0') + BosonOperator('0^')))
         self.assertTrue(b == expected)
+
+
+def test_get_fermion_operator_majorana_operator():
+    a = MajoranaOperator((0, 3), 2.0) + MajoranaOperator((1, 2, 3))
+    op = get_fermion_operator(a)
+    expected_op = (-2j*(FermionOperator(((0, 0), (1, 0)))
+                        - FermionOperator(((0, 0), (1, 1)))
+                        + FermionOperator(((0, 1), (1, 0)))
+                        - FermionOperator(((0, 1), (1, 1))))
+                   - 2*FermionOperator(((0, 0), (1, 1), (1, 0)))
+                   + 2*FermionOperator(((0, 1), (1, 1), (1, 0)))
+                   + FermionOperator((0, 0))
+                   - FermionOperator((0, 1)))
+    assert normal_ordered(op) == normal_ordered(expected_op)
+
+
+def test_get_fermion_operator_wrong_type():
+    with pytest.raises(TypeError):
+        _ = get_fermion_operator(QubitOperator())