Repository: Qiskit/qiskit

Issue:
Didn't wait time in 2-qubit circuit
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: 0.8.0(master)
- **Python version**: 3.7.1
- **Operating system**: macOS Mojave 10.14.4

### What is the current behavior?
I'm measuring T1 for a specific qubit of melbourne device, qubit 0. 
If I use a single-qubit circuit it works well:
![image](https://user-images.githubusercontent.com/48584677/57441886-1f9ce380-724b-11e9-9735-d7dd4ea72439.png)
But if I use a 2-qubit circuit, using the same algorithm, it seems like the state didn't decay, or the identity gate aren't applied.
![image](https://user-images.githubusercontent.com/48584677/57442369-2710bc80-724c-11e9-88d3-027815bc6380.png)




### Steps to reproduce the problem
```
# Importing needed libraries
from qiskit import *
from qiskit.mapper import Layout
import numpy as np
import matplotlib as mp
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

# Enable use of real device
IBMQ.load_accounts()
backend_exp = IBMQ.get_backend('ibmq_16_melbourne')

for u in range(0,1): # It isn't important, it is because I measured all qubit's T1
    u_st = str(u)
    file1 = 'T1__raw_qubit_' + u_st + '.txt'
    out1 = open( file1, 'w' )
    
    out1.write('# This is the qubit\'s ' + u_st +' T1 raw data \n' )
    
    circuit = []

    q = QuantumRegister(2, 'q') #Only changing this and the layout makes it works
    c1 = ClassicalRegister(1, 'c')
    qc = QuantumCircuit(q)
    mz = QuantumCircuit(q,c1)
    lay = Layout({ (q,0) : 0, (q,1):1 })

    # Exciting the qubit
    qc.x(q[0])
    qc.barrier(q)

    # Measurment on Z-axis
    mz.measure(q[0],c1[0])

    # Waiting time ( 30*0.12 us each iteration)
    for i in range(50):
        identity = QuantumCircuit(q,c1)
        identity.barrier(q)
        for k in range(i*30):
            identity.iden(q)
        identity.barrier(q)
        circuit.append(qc+identity+mz)

    # Running the experiment
    jobZ = execute(circuit, backend_exp, initial_layout=lay, shots=1024)
    
    out1.write('# N° id_gates Z-Measure Error \n')
    
    Result = jobZ.result() # Taking the results
    
    counts = []
    for i in range(50):
        counts.append(Result.get_counts(circuit[i]) )

    # Preparing the lists to make fits
    y = []
    x = []
    for i in range(50):
        py = counts[i]['1']/1024
        x.append(i*30*0.12)
        y.append( py )
        out1.write(str(i*30) + ' '+ str(py)  + '\n')       
    out1.write( '\n')
    
    def expo(x, amp, slope, high):
        y = amp*np.exp(-slope*x)+high
        return y

    x = np.array(x)
    y = np.array(y)
    err_y = np.array(err_y)
   

    params , paramscov = curve_fit(expo, x, y,p0=[1,0.02,0] )
    a =np.sqrt(np.diag(paramscov))
    out1.write('The raw T1 is ' + str(1/params[1])+ ' +- ' + str(a[1]/params[1]) + '\n')
    out1.close()
   
    
    plt.figure()
    plt.plot(x, expo(x, *params),
         label='Raw fitted function')
    plt.plot(x , y, 'ro', label= 'data')
    plt.xlabel( ' Time [us] ')
    plt.ylabel(' Probability of being in the excited state ')
    plt.legend()
    plt.savefig('plot_q_'+ u_st+ '_raw.png')
```



### What is the expected behavior?
I would expect the same behavior using 1-qubit circuit and 2-qubits circuit, because both times I put gates only on the first qubit.



### Suggested solutions
I don't know



Discussion:
Hi @Marco9719. You need to put barriers between your `id` gates, otherwise they all cancel and get optimized away. Here's how one of your circuits looks like:

`circuit[1].draw(output='mpl')`
![image](https://user-images.githubusercontent.com/8622381/57497254-ebeea780-72a4-11e9-9f0a-ebffd2ea497e.png)

By the way Qiskit Ignis has tools to do these kinds of T1 experiments so you don't have to manually set up the circuits. See here: https://github.com/Qiskit/qiskit-tutorials/blob/master/qiskit/ignis/relaxation_and_decoherence.ipynb
I'm sorry to continue this thread also if it is closed, but i didn't understand it too well.
@ajavadia are you saying that if i put a barrier after each identity it should work? 
Because this circuit still gives me the same results:
`circuit[1].draw(output='mpl')`
![Circ](https://user-images.githubusercontent.com/48584677/57515651-6fdf7880-7313-11e9-9b74-e0c79b654614.jpeg)

Where am I wrong?

And I know about the possibility of doing it by qiskit ignis function, but I explain this example because it si simpler but has the same problem of what i'm working on: measuring how much time the entanglement in a bell couple remains acceptable.


I'm sorry @ajavadia, but can you please answer me?
Seems like there is a bug here in that `iden` gates are being removed, even if they are the only gate between two barriers.
```
>>> from qiskit.ignis.characterization.coherence import t1_circuits
>>> c, d = t1_circuits([1,2,3,4,5], 1, [0])
>>> print(c[-1])
         ┌───┐ ░ ┌────┐ ░ ┌────┐ ░ ┌────┐ ░ ┌────┐ ░ ┌────┐ ░  ░ ┌─┐
q0_0: |0>┤ X ├─░─┤ Id ├─░─┤ Id ├─░─┤ Id ├─░─┤ Id ├─░─┤ Id ├─░──░─┤M├
         └───┘ ░ └────┘ ░ └────┘ ░ └────┘ ░ └────┘ ░ └────┘ ░  ░ └╥┘
 c0_0: 0 ═════════════════════════════════════════════════════════╩═

>>> print(qk.compiler.transpile(c[-1], backend=qk.IBMQ.get_backend('ibmqx4')))
        ┌─────────────────────┐ ░  ░  ░  ░  ░  ░ ┌─┐
q_0: |0>┤ U3(3.1416,0,3.1416) ├─░──░──░──░──░──░─┤M├
        └─────────────────────┘ ░  ░  ░  ░  ░  ░ └╥┘
q_1: |0>──────────────────────────────────────────╫─
                                                  ║
q_2: |0>──────────────────────────────────────────╫─
                                                  ║
q_3: |0>──────────────────────────────────────────╫─
                                                  ║
q_4: |0>──────────────────────────────────────────╫─
                                                  ║
c0_0: 0 ══════════════════════════════════════════╩═
```
But this would imply the 1q experiment wouldn't work either (though I'm not sure how that worked in the original example, as it didn't have barriers either). @Marco9719 , can you confirm if you are still able to replicate the single qubit T1 experiment?
I just tried again and it works with the 1 qubit register.
This is the circuit used at the first iteration:
![image](https://user-images.githubusercontent.com/48584677/57795931-7b81d380-7747-11e9-8eda-4336bb1d7c82.png)
I really don't know why, maybe it removes the `iden` only with a multiple qubit register.

Ok I see what is happening. This is due to the `Optimize1qGates` transpiler pass. It used to be that this pass only merged gates, so putting barriers between them prevented any collapse. However, now it also simplifies them, i.e. it replaces `iden` with a "nop" (eliminates it). So barriers don't help there.

I actually prefer this. Identities should be removed where possible. If you want to keep them, tell the transpiler to not optimize your circuit (use optimization_level 0):
```
job = qk.execute(circuit, backend, optimization_level=0)
```

or just skip the transpiler entirely:
```
qobj = qk.compiler.assemble(circuit, shots=1024)
job = backend.run(qobj)
```

(^ the above works with the latest release of qiskit.(
I agree that we should be removing `iden` gates on transpile, but I'd wager `iden` is used much more often now as a timed delay gate (e.g. `pad_id_gates` in ignis). This was not a change we publicized, so it's likely this will break a bunch of existing circuits/notebooks. I'd argue we should bring back the old behavior and then deprecate, but if we can't do that, what's the best way to inform users wanting to do characterization work with `iden` that they need to use optimization level 0?

Separately, do we think there is a use case for having an explicit timed wait gate, something like `delay`?
Sure i think you are right. Not sure how to deprecate it -- maybe have a message pop up whenever the Optimize1qGates pass tries to remove identities? It might be quite noisy though for circuits that have nothing to do with this behavior.
I think we have gone back and forth on having a `delay` gate, probably deferring to pulse. @jaygambetta do you have strong feelings here? We need to clarify our policy on `iden` vs. `u0` too.

Thanks, using the `optimization_level=0` it works!
Maybe I can change the title of this issue in something like "iden getting optimized even with barriers" to make it more visible to who might have the same problem.
Hey @Marco9719 

We are trying to achieve the same time delay and running into the same issues with identity gates being erased.  Would you mind posted a snip-it from your code that worked, where you were able to successfully implement a time delay with I gates.
To be honest I thought it worked, but it was the single register.
This approach works when working with only one qubit:
``` 
qobj = qk.compiler.assemble(circuit, shots=1024)
job = backend.run(qobj)
```
It didn't work if I try to use it in the entanglement measure: it gives me the error "the experiment failed", so I assumed that it was because the transpiler makes some optimization necessary to run a CNOT. 
And then I forgot to repost that it didn't work. Thanks to remind me.
Try the assemble method, and then if it doesn't work we will wait for an answer by the developers.

Resolving patch:
diff --git a/qiskit/extensions/standard/iden.py b/qiskit/extensions/standard/iden.py
--- a/qiskit/extensions/standard/iden.py
+++ b/qiskit/extensions/standard/iden.py
@@ -18,27 +18,19 @@
 import numpy
 from qiskit.circuit import Gate
 from qiskit.circuit import QuantumCircuit
-from qiskit.circuit import QuantumRegister
-from qiskit.extensions.standard.u3 import U3Gate
 
 
 class IdGate(Gate):
-    """Identity gate."""
+    """Identity gate.
+
+    Identity gate corresponds to a single-qubit gate wait cycle,
+    and should not be optimized or unrolled (it is an opaque gate).
+    """
 
     def __init__(self, label=None):
         """Create new Identity gate."""
         super().__init__("id", 1, [], label=label)
 
-    def _define(self):
-        definition = []
-        q = QuantumRegister(1, "q")
-        rule = [
-            (U3Gate(0, 0, 0), [q[0]], [])
-        ]
-        for inst in rule:
-            definition.append(inst)
-        self.definition = definition
-
     def inverse(self):
         """Invert this gate."""
         return IdGate()  # self-inverse
@@ -50,7 +42,11 @@ def to_matrix(self):
 
 
 def iden(self, q):
-    """Apply Identity to q."""
+    """Apply Identity to q.
+
+    Identity gate corresponds to a single-qubit gate wait cycle,
+    and should not be optimized or unrolled (it is an opaque gate).
+    """
     return self.append(IdGate(), [q], [])
 
 
diff --git a/qiskit/transpiler/passes/optimize_1q_gates.py b/qiskit/transpiler/passes/optimize_1q_gates.py
--- a/qiskit/transpiler/passes/optimize_1q_gates.py
+++ b/qiskit/transpiler/passes/optimize_1q_gates.py
@@ -39,7 +39,7 @@ class Optimize1qGates(TransformationPass):
     """Simplify runs of single qubit gates in the ["u1", "u2", "u3", "cx", "id"] basis."""
     def run(self, dag):
         """Return a new circuit that has been optimized."""
-        runs = dag.collect_runs(["u1", "u2", "u3", "id"])
+        runs = dag.collect_runs(["u1", "u2", "u3"])
         runs = _split_runs_on_parameters(runs)
         for run in runs:
             right_name = "u1"


Test patch:
diff --git a/test/python/circuit/test_diag.py b/test/python/circuit/test_diag.py
--- a/test/python/circuit/test_diag.py
+++ b/test/python/circuit/test_diag.py
@@ -42,7 +42,7 @@ def test_diag_gate(self):
                 qc = QuantumCircuit(q)
                 qc.diagGate(diag, q[0:num_qubits])
                 # Decompose the gate
-                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx'])
+                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx', 'id'])
                 # Simulate the decomposed gate
                 simulator = BasicAer.get_backend('unitary_simulator')
                 result = execute(qc, simulator).result()
diff --git a/test/python/circuit/test_isometry.py b/test/python/circuit/test_isometry.py
--- a/test/python/circuit/test_isometry.py
+++ b/test/python/circuit/test_isometry.py
@@ -50,7 +50,7 @@ def test_isometry(self):
                 qc = QuantumCircuit(q)
                 qc.iso(iso, q[:num_q_input], q[num_q_input:])
                 # Decompose the gate
-                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx'])
+                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx', 'id'])
                 # Simulate the decomposed gate
                 simulator = BasicAer.get_backend('unitary_simulator')
                 result = execute(qc, simulator).result()
diff --git a/test/python/circuit/test_squ.py b/test/python/circuit/test_squ.py
--- a/test/python/circuit/test_squ.py
+++ b/test/python/circuit/test_squ.py
@@ -47,7 +47,7 @@ def test_squ(self):
                 qc = QuantumCircuit(qr)
                 qc.squ(u, qr[0], up_to_diagonal=up_to_diagonal)
                 # Decompose the gate
-                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx'])
+                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx', 'id'])
                 # Simulate the decomposed gate
                 simulator = BasicAer.get_backend('unitary_simulator')
                 result = execute(qc, simulator).result()
diff --git a/test/python/circuit/test_ucg.py b/test/python/circuit/test_ucg.py
--- a/test/python/circuit/test_ucg.py
+++ b/test/python/circuit/test_ucg.py
@@ -57,7 +57,7 @@ def test_ucg(self):
                 qc = QuantumCircuit(q)
                 qc.ucg(squs, q[1:], q[0], up_to_diagonal=up_to_diagonal)
                 # Decompose the gate
-                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx'])
+                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx', 'id'])
                 # Simulate the decomposed gate
                 simulator = BasicAer.get_backend('unitary_simulator')
                 result = execute(qc, simulator).result()
diff --git a/test/python/circuit/test_ucx_y_z.py b/test/python/circuit/test_ucx_y_z.py
--- a/test/python/circuit/test_ucx_y_z.py
+++ b/test/python/circuit/test_ucx_y_z.py
@@ -53,7 +53,7 @@ def test_ucy(self):
                 else:
                     qc.ucz(angles, q[1:num_contr + 1], q[0])
                 # Decompose the gate
-                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx'])
+                qc = transpile(qc, basis_gates=['u1', 'u3', 'u2', 'cx', 'id'])
                 # Simulate the decomposed gate
                 simulator = BasicAer.get_backend('unitary_simulator')
                 result = execute(qc, simulator).result()
diff --git a/test/python/transpiler/test_optimize_1q_gates.py b/test/python/transpiler/test_optimize_1q_gates.py
--- a/test/python/transpiler/test_optimize_1q_gates.py
+++ b/test/python/transpiler/test_optimize_1q_gates.py
@@ -31,19 +31,22 @@
 class TestOptimize1qGates(QiskitTestCase):
     """Test for 1q gate optimizations. """
 
-    def test_optimize_id(self):
-        """ qr0:--[id]-- == qr0:------ """
+    def test_dont_optimize_id(self):
+        """Identity gates are like 'wait' commands.
+        They should never be optimized (even without barriers).
+
+        See: https://github.com/Qiskit/qiskit-terra/issues/2373
+        """
         qr = QuantumRegister(1, 'qr')
         circuit = QuantumCircuit(qr)
         circuit.iden(qr)
         circuit.iden(qr)
         dag = circuit_to_dag(circuit)
-        expected = QuantumCircuit(qr)
 
         pass_ = Optimize1qGates()
         after = pass_.run(dag)
 
-        self.assertEqual(circuit_to_dag(expected), after)
+        self.assertEqual(dag, after)
 
     def test_optimize_h_gates_pass_manager(self):
         """Transpile: qr:--[H]-[H]-[H]-- == qr:--[u2]-- """
@@ -63,7 +66,7 @@ def test_optimize_h_gates_pass_manager(self):
 
         self.assertEqual(expected, result)
 
-    def test_optimize_1q_gates_collapse_identity(self):
+    def test_optimize_1q_gates_collapse_identity_equivalent(self):
         """test optimize_1q_gates removes u1(2*pi) rotations.
 
         See: https://github.com/Qiskit/qiskit-terra/issues/159
diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py
--- a/test/python/transpiler/test_unroller.py
+++ b/test/python/transpiler/test_unroller.py
@@ -143,7 +143,7 @@ def test_unroll_all_instructions(self):
         circuit.snapshot('0')
         circuit.measure(qr, cr)
         dag = circuit_to_dag(circuit)
-        pass_ = Unroller(basis=['u3', 'cx'])
+        pass_ = Unroller(basis=['u3', 'cx', 'id'])
         unrolled_dag = pass_.run(dag)
 
         ref_circuit = QuantumCircuit(qr, cr)
@@ -213,7 +213,7 @@ def test_unroll_all_instructions(self):
         ref_circuit.u3(0, 0, pi/2, qr[2])
         ref_circuit.cx(qr[2], qr[0])
         ref_circuit.u3(pi/2, 0, pi, qr[0])
-        ref_circuit.u3(0, 0, 0, qr[0])
+        ref_circuit.iden(qr[0])
         ref_circuit.u3(0.1, -pi/2, pi/2, qr[0])
         ref_circuit.cx(qr[1], qr[0])
         ref_circuit.u3(0, 0, 0.6, qr[0])