Repository: Qiskit/qiskit

Issue:
Duplicated code in _simulatortools.py and qasm_simulator_py.py
### Informations

- **Qiskit Terra version**: 0.6.1
- **Python version**: 3.6.1
- **Operating system**: Darwin 18.0.0

### The issue

While working on #1153, @charlesastaylor found several functions duplicated in `qiskit/backends/aer/_simulatortools.py` and `qiskit//backends/aer/qasm_simulator_py.py` (such as `index1`). This duplication should be removed.


Discussion:
Also, the docstring for the `_index2()` function (in both places) reads `"""Magic index1 function.` Is that a typo?

Didn't think this was worth a new issue, apologies if this is wrong place to mention.
it can be fixed in the same move. And yes, it's probably a typ0.

Resolving patch:
diff --git a/qiskit/backends/aer/_simulatortools.py b/qiskit/backends/aer/_simulatortools.py
--- a/qiskit/backends/aer/_simulatortools.py
+++ b/qiskit/backends/aer/_simulatortools.py
@@ -15,8 +15,8 @@
 """
 
 from string import ascii_uppercase, ascii_lowercase
+
 import numpy as np
-from sympy import Matrix, pi, E, I, cos, sin, N, sympify
 
 from qiskit import QISKitError
 
@@ -42,7 +42,7 @@ def index1(b, i, k):
 
 
 def index2(b1, i1, b2, i2, k):
-    """Magic index1 function.
+    """Magic index2 function.
 
     Takes a bitstring k and inserts bits b1 as the i1th bit
     and b2 as the i2th bit
@@ -157,52 +157,3 @@ def einsum_matmul_index(gate_indices, number_of_qubits):
            "{tens_lin}{tens_r}->{tens_lout}{tens_r}".format(tens_lin=idx_left_in,
                                                             tens_lout=idx_left_out,
                                                             tens_r=idx_right)
-
-
-# Functions used by the sympy simulators.
-
-def regulate(theta):
-    """
-    Return the regulated symbolic representation of `theta`::
-        * if it has a representation close enough to `pi` transformations,
-            return that representation (for example, `3.14` -> `sympy.pi`).
-        * otherwise, return a sympified representation of theta (for example,
-            `1.23` ->  `sympy.Float(1.23)`).
-
-    See also `UGateGeneric`.
-
-    Args:
-        theta (float or sympy.Basic): the float value (e.g., 3.14) or the
-            symbolic value (e.g., pi)
-
-    Returns:
-        sympy.Basic: the sympy-regulated representation of `theta`
-    """
-    error_margin = 0.01
-    targets = [pi, pi/2, pi * 2, pi / 4]
-
-    for t in targets:
-        if abs(N(theta - t)) < error_margin:
-            return t
-
-    return sympify(theta)
-
-
-def compute_ugate_matrix(parameters):
-    """Compute the matrix associated with a parameterized U gate.
-
-    Args:
-        parameters (list[float]): parameters carried by the U gate
-    Returns:
-        sympy.Matrix: the matrix associated with a parameterized U gate
-    """
-    theta = regulate(parameters[0])
-    phi = regulate(parameters[1])
-    lamb = regulate(parameters[2])
-
-    left_up = cos(theta/2)
-    right_up = (-E**(I*lamb)) * sin(theta/2)
-    left_down = (E**(I*phi)) * sin(theta/2)
-    right_down = (E**(I*(phi + lamb))) * cos(theta/2)
-
-    return Matrix([[left_up, right_up], [left_down, right_down]])
diff --git a/qiskit/backends/aer/qasm_simulator_py.py b/qiskit/backends/aer/qasm_simulator_py.py
--- a/qiskit/backends/aer/qasm_simulator_py.py
+++ b/qiskit/backends/aer/qasm_simulator_py.py
@@ -82,7 +82,7 @@
 from qiskit.backends import BaseBackend
 from qiskit.backends.aer.aerjob import AerJob
 from ._simulatorerror import SimulatorError
-from ._simulatortools import single_gate_matrix
+from ._simulatortools import index2, single_gate_matrix
 logger = logging.getLogger(__name__)
 
 
@@ -114,46 +114,6 @@ def __init__(self, configuration=None, provider=None):
         self._shots = 0
         self._qobj_config = None
 
-    @staticmethod
-    def _index1(b, i, k):
-        """Magic index1 function.
-
-        Takes a bitstring k and inserts bit b as the ith bit,
-        shifting bits >= i over to make room.
-        """
-        retval = k
-        lowbits = k & ((1 << i) - 1)  # get the low i bits
-
-        retval >>= i
-        retval <<= 1
-
-        retval |= b
-
-        retval <<= i
-        retval |= lowbits
-
-        return retval
-
-    @staticmethod
-    def _index2(b1, i1, b2, i2, k):
-        """Magic index1 function.
-
-        Takes a bitstring k and inserts bits b1 as the i1th bit
-        and b2 as the i2th bit
-        """
-        if i1 == i2:
-            raise SimulatorError("can't insert two bits to same place")
-
-        if i1 > i2:
-            # insert as (i1-1)th bit, will be shifted left 1 by next line
-            retval = QasmSimulatorPy._index1(b1, i1-1, k)
-            retval = QasmSimulatorPy._index1(b2, i2, retval)
-        else:  # i2>i1
-            # insert as (i2-1)th bit, will be shifted left 1 by next line
-            retval = QasmSimulatorPy._index1(b2, i2-1, k)
-            retval = QasmSimulatorPy._index1(b1, i1, retval)
-        return retval
-
     def _add_qasm_single(self, gate, qubit):
         """Apply an arbitrary 1-qubit operator to a qubit.
 
@@ -179,9 +139,9 @@ def _add_qasm_cx(self, q0, q1):
         psi = self._statevector
         for k in range(0, 1 << (self._number_of_qubits - 2)):
             # first bit is control, second is target
-            ind1 = self._index2(1, q0, 0, q1, k)
+            ind1 = index2(1, q0, 0, q1, k)
             # swap target if control is 1
-            ind3 = self._index2(1, q0, 1, q1, k)
+            ind3 = index2(1, q0, 1, q1, k)
             cache0 = psi[ind1]
             cache1 = psi[ind3]
             psi[ind3] = cache0


Test patch: