Repository: quantumlib/OpenFermion
Pull request #622 (2020-07-24 09:23:46)

Givens rotation always insert
Adds option to keep trivial gates in Givens rotation circuit - useful in NISQ for circuit stability.

obriente: Whoops, just noticed that I'd left a print statement in the reorg pull request. I've removed it here.

Patch:
diff --git a/src/openfermion/linalg/givens_rotations.py b/src/openfermion/linalg/givens_rotations.py
index c29b2e1..ae073b9 100644
--- a/src/openfermion/linalg/givens_rotations.py
+++ b/src/openfermion/linalg/givens_rotations.py
@@ -144,7 +144,7 @@ def double_givens_rotate(operator, givens_rotation, i, j, which='row'):
         raise ValueError('"which" must be equal to "row" or "col".')
 
 
-def givens_decomposition_square(unitary_matrix):
+def givens_decomposition_square(unitary_matrix, always_insert=False):
     r"""Decompose a square matrix into a sequence of Givens rotations.
 
     The input is a square :math:`n \times n` matrix :math:`Q`.
@@ -216,7 +216,7 @@ def givens_decomposition_square(unitary_matrix):
             # Compute the Givens rotation to zero out the (i, j) element,
             # if needed
             right_element = current_matrix[i, j].conj()
-            if abs(right_element) > EQ_TOLERANCE:
+            if always_insert or abs(right_element) > EQ_TOLERANCE:
                 # We actually need to perform a Givens rotation
                 left_element = current_matrix[i, j - 1].conj()
                 givens_rotation = givens_matrix_elements(left_element,
@@ -246,7 +246,7 @@ def givens_decomposition_square(unitary_matrix):
     return decomposition, diagonal
 
 
-def givens_decomposition(unitary_rows):
+def givens_decomposition(unitary_rows, always_insert=False):
     r"""Decompose a matrix into a sequence of Givens rotations.
 
     The input is an :math:`m \times n` matrix :math:`Q` with :math:`m \leq n`.
@@ -365,7 +365,7 @@ def givens_decomposition(unitary_rows):
                 # Compute the Givens rotation to zero out the (i, j) element,
                 # if needed
                 right_element = current_matrix[i, j].conj()
-                if abs(right_element) > EQ_TOLERANCE:
+                if always_insert or abs(right_element) > EQ_TOLERANCE:
                     # We actually need to perform a Givens rotation
                     left_element = current_matrix[i, j - 1].conj()
                     givens_rotation = givens_matrix_elements(left_element,
diff --git a/src/openfermion/ops/operators/symbolic_operator.py b/src/openfermion/ops/operators/symbolic_operator.py
index 8b9b2f9..0f818a0 100644
--- a/src/openfermion/ops/operators/symbolic_operator.py
+++ b/src/openfermion/ops/operators/symbolic_operator.py
@@ -136,14 +136,12 @@ class SymbolicOperator(metaclass=abc.ABCMeta):
         if term is None:
             return
 
-        print(term)
         # Parse the term
         # Sequence input
         if isinstance(term, (list, tuple)):
             term = self._parse_sequence(term)
         # String input
         elif isinstance(term, str):
-            print('parsing string')
             term = self._parse_string(term)
         # Invalid input type
         else:
@@ -251,7 +249,6 @@ class SymbolicOperator(metaclass=abc.ABCMeta):
         # Convert the string representations of the factors to tuples
         processed_term = []
         for factor in factors:
-            print(factor)
             # Get the index and action string
             if self.action_before_index:
                 # The index is at the end of the string; find where it starts.


Test patch:
diff --git a/src/openfermion/linalg/givens_rotations_test.py b/src/openfermion/linalg/givens_rotations_test.py
index b618844..c8825f1 100644
--- a/src/openfermion/linalg/givens_rotations_test.py
+++ b/src/openfermion/linalg/givens_rotations_test.py
@@ -18,7 +18,8 @@ from openfermion.testing.testing_utils import (random_quadratic_hamiltonian,
 
 from openfermion.linalg.givens_rotations import (
     double_givens_rotate, fermionic_gaussian_decomposition, swap_columns,
-    givens_matrix_elements, givens_rotate, givens_decomposition, swap_rows)
+    givens_matrix_elements, givens_rotate, givens_decomposition, swap_rows,
+    givens_decomposition_square)
 
 
 class SwapTests(unittest.TestCase):
@@ -128,6 +129,17 @@ class GivensDecompositionTest(unittest.TestCase):
         self.test_dimensions = [(3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9),
                                 (4, 7), (4, 8), (4, 9)]
 
+    def test_forced_insertion(self):
+        Q = numpy.zeros([2, 4])
+        Q[0, 0] = Q[1, 1] = 1
+        givens_rotations, _, _ = givens_decomposition(Q, always_insert=True)
+        assert len(givens_rotations) == 3
+
+    def test_forced_insertion_square(self):
+        Q = numpy.eye(4)
+        givens_rotations, _ = givens_decomposition_square(Q, always_insert=True)
+        assert len(givens_rotations) == 5
+
     def test_main_procedure(self):
         for m, n in self.test_dimensions:
             # Obtain a random matrix of orthonormal rows