Repository: quantumlib/OpenFermion
Pull request #98 (2017-11-01 02:53:01)

Adds totally depolarizing channel to existing depolarizing channel
Adds option to specify "all" for target_qubit such that depolarizing channel will act as the totally depolarizing channel, mapping to the identity.

jarrodmcc: Those spaces fixed as well as some others

Patch:
diff --git a/src/openfermion/utils/_channel_state.py b/src/openfermion/utils/_channel_state.py
index 2cdd291..6ec6ec5 100644
--- a/src/openfermion/utils/_channel_state.py
+++ b/src/openfermion/utils/_channel_state.py
@@ -14,7 +14,7 @@
 
 from functools import reduce
 from itertools import chain
-from numpy import array, dot, eye, kron, log2, sqrt
+from numpy import array, conj, dot, eye, kron, log2, sqrt
 
 
 def _verify_channel_inputs(density_matrix, probability, target_qubit):
@@ -72,8 +72,8 @@ def amplitude_damping_channel(density_matrix, probability, target_qubit,
         density_matrix (numpy.ndarray): Density matrix of the system
         probability (float): Probability error is applied p \in [0, 1]
         target_qubit (int): target for the channel error.
-        transpose (bool): Transpose channel operators, useful for acting on
-            Hamiltonians in variational channel state models
+        transpose (bool): Conjugate transpose channel operators, useful for
+            acting on Hamiltonians in variational channel state models
 
     Returns:
         new_density_matrix(numpy.ndarray): Density matrix with the channel
@@ -111,8 +111,8 @@ def dephasing_channel(density_matrix, probability, target_qubit,
         density_matrix (numpy.ndarray): Density matrix of the system
         probability (float): Probability error is applied p \in [0, 1]
         target_qubit (int): target for the channel error.
-        transpose (bool): Transpose channel operators, useful for acting on
-            Hamiltonians in variational channel state models
+        transpose (bool): Conjugate transpose channel operators, useful for
+            acting on Hamiltonians in variational channel state models
 
     Returns:
         new_density_matrix (numpy.ndarray): Density matrix with the channel
@@ -147,38 +147,43 @@ def depolarizing_channel(density_matrix, probability, target_qubit,
     Args:
         density_matrix (numpy.ndarray): Density matrix of the system
         probability (float): Probability error is applied p \in [0, 1]
-        target_qubit (int): target for the channel error.
-        transpose (bool): Transpose channel operators, useful for acting on
-            Hamiltonians in variational channel state models
+        target_qubit (int/str): target for the channel error, if given special
+            value "all", then a total depolarizing channel is applied.
+        transpose (bool): Dummy parameter to match signature of other
+            channels but depolarizing channel is symmetric under
+            conjugate transpose.
 
     Returns:
         new_density_matrix (numpy.ndarray): Density matrix with the channel
             applied.
     """
-    _verify_channel_inputs(density_matrix, probability, target_qubit)
     n_qubits = int(log2(density_matrix.shape[0]))
 
+    # Toggle depolarizing channel on all qubits
+    if isinstance(target_qubit, str) and target_qubit.lower() == "all":
+        dimension = density_matrix.shape[0]
+        new_density_matrix = ((1.0 - probability) * density_matrix +
+                              probability * eye(dimension) / float(dimension))
+        return new_density_matrix
+
+    # For any other case, depolarize only the target qubit
+    _verify_channel_inputs(density_matrix, probability, target_qubit)
+
     E0 = _lift_operator(sqrt(1.0 - probability) * eye(2),
                         n_qubits, target_qubit)
-    E1 = _lift_operator(sqrt(probability/3.) * array([[0.0, 1.0],
-                                                      [1.0, 0.0]]),
+    E1 = _lift_operator(sqrt(probability / 3.) * array([[0.0, 1.0],
+                                                        [1.0, 0.0]]),
                         n_qubits, target_qubit)
-    E2 = _lift_operator(sqrt(probability/3.) * array([[0.0, -1.0j],
-                                                      [1.0j, 0.0]]),
+    E2 = _lift_operator(sqrt(probability / 3.) * array([[0.0, -1.0j],
+                                                        [1.0j, 0.0]]),
                         n_qubits, target_qubit)
-    E3 = _lift_operator(sqrt(probability/3.) * array([[1.0, 0.0],
-                                                      [0.0, -1.0]]),
+    E3 = _lift_operator(sqrt(probability / 3.) * array([[1.0, 0.0],
+                                                        [0.0, -1.0]]),
                         n_qubits, target_qubit)
 
-    if transpose:
-        E0 = E0.T
-        E1 = E1.T
-        E2 = E2.T
-        E3 = E3.T
-
-    new_density_matrix = (dot(E0, dot(density_matrix, E0.T)) +
-                          dot(E1, dot(density_matrix, E1.T)) +
-                          dot(E2, dot(density_matrix, E2.T)) +
-                          dot(E3, dot(density_matrix, E3.T)))
+    new_density_matrix = (dot(E0, dot(density_matrix, E0)) +
+                          dot(E1, dot(density_matrix, E1)) +
+                          dot(E2, dot(density_matrix, E2)) +
+                          dot(E3, dot(density_matrix, E3)))
 
     return new_density_matrix


Test patch:
diff --git a/src/openfermion/utils/_channel_state_test.py b/src/openfermion/utils/_channel_state_test.py
index aca937f..766c602 100644
--- a/src/openfermion/utils/_channel_state_test.py
+++ b/src/openfermion/utils/_channel_state_test.py
@@ -111,10 +111,11 @@ class ChannelTest(unittest.TestCase):
                                      test_density_matrix), 0.0)
 
         # With probability 1 on both qubits
-        correct_density_matrix = array([[0.0555555, 0.,  0.0,  0.27777778],
-                                        [0.00, 0.00, -0.22222222, 0.000],
-                                        [0.00, -0.22222222, 0., 0.],
-                                        [0.27777778, 0.0, 0.0, 0.05555556]])
+        correct_density_matrix = (
+            array([[0.27777778, 0.00000000, 0.00000000, 0.05555556],
+                   [0.00000000, 0.22222222, 0.00000000, 0.00000000],
+                   [0.00000000, 0.00000000, 0.22222222, 0.00000000],
+                   [0.05555556, 0.00000000, 0.00000000, 0.27777778]]))
 
         test_density_matrix = (
             depolarizing_channel(self.cat_matrix, 1, 0))
@@ -135,6 +136,13 @@ class ChannelTest(unittest.TestCase):
         self.assertAlmostEquals(norm(correct_density_matrix -
                                      test_density_matrix), 0.0, places=6)
 
+        # With probability 1 for total depolarization
+        correct_density_matrix = eye(4) / 4.0
+        test_density_matrix = (
+            depolarizing_channel(self.cat_matrix, 1, 'All'))
+        self.assertAlmostEquals(norm(correct_density_matrix -
+                                     test_density_matrix), 0.0, places=6)
+
     def test_verification(self):
         """Verify basic sanity checking on inputs"""
         with self.assertRaises(ValueError):