Repository: Qiskit/qiskit

Issue:
Process Tomography
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Informations

- **Qiskit Terra version**: 0.6.1
- **Python version**: 3.7
- **Operating system**: OsX

### What is the current behavior?

The process tomography for a teleported state seems providing awkward results. Conversely, state tomography for the same circuit works just fine

Specifically, this is the ideal Chi matrix for a X Gate.
![unknowny8lhsy80zi8](https://user-images.githubusercontent.com/45635859/49563462-4b284480-f920-11e8-8a0f-28c02f507a3c.png)

And this is the Chi matrix as output of process tomography
![unknown-1sy8d9drrjql](https://user-images.githubusercontent.com/45635859/49563493-65622280-f920-11e8-91f1-7c86b62e12f7.png)

### Steps to reproduce the problem

```
import numpy as np
import time

# importing Qiskit
from qiskit import Aer, IBMQ
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import register, execute

# import backend utilities
from qiskit.backends import JobStatus

# import tomography library
import qiskit.tools.qcvv.tomography as tomo

# useful additional packages 
from qiskit.tools.visualization import plot_state
from qiskit.tools.visualization import plot_histogram
from qiskit.tools.qi.qi import *
from qiskit.wrapper.jupyter import *
#from qiskit.backends.ibmq import least_busy

# Load saved IBMQ accounts
IBMQ.load_accounts()

#U_id = np.array([[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]])
#U_id = np.array([[1,1],[1,-1]])
U_id = np.array([[0,1],[1,0]])
# compute Choi-matrix from unitary
id_choi = outer(vectorize(U_id))
#plot_state(id_choi)

# Creating circuit for tomography
q = QuantumRegister(3)
c = ClassicalRegister(3)
qc = QuantumCircuit(q, c, name='teleportation')

# inizializing qubit ⓪ to be teleported
#qc.u1(0.5, q[0])
qc.x(q[0])
#qc.h(q[0])
qc.barrier()

# creating entangled pair between qubit ① and qubit ②
qc.h(q[1])
qc.cx(q[1], q[2])
qc.barrier(q)

# teleportation
qc.cx(q[0], q[1])
qc.barrier(q)

# Measure qubit ⓪ in the + - basis
qc.h(q[0])
qc.cz(q[0],q[2])
#qc.measure(q[0], c[0])
#if c[0] == 1:
#    qc.z(q[2])
qc.barrier(q)
    
# Measure qubit ① in the computational basis
qc.cx(q[1],q[2])
#qc.measure(q[1], c[1])
#if c[1] == 1:
#    qc.x(q[2])
qc.barrier(q)

# measuring for executing the circuit.. to be removed for tomography
#qc.measure(q[0], c[0])
#qc.measure(q[1], c[1])
#qc.measure(q[2], c[2])

# Construct state tomography set for measurement of qubits [0, 1] in the Pauli basis
tomo_set = tomo.process_tomography_set([2])
# Add the state tomography measurement circuits to the Quantum Program
tomo_circuits = tomo.create_tomography_circuits(qc, q, c, tomo_set)

backend = Aer.get_backend('qasm_simulator')
shots = 1000
job_exp = execute(qc, backend=backend, shots=shots)
result_exp = job_exp.result()
counts_exp = result_exp.get_counts(qc)
plot_histogram(counts_exp)

tomo_job = execute(tomo_circuits, backend=backend, shots=shots)
tomo_results = tomo_job.result()
process_data = tomo.tomography_data(tomo_results, qc.name, tomo_set)
choi_fit = tomo.fit_tomography_data(process_data, options={'trace':2})
plot_state(id_choi)
plot_state(choi_fit)
print('Process Fidelity = ', state_fidelity(vectorize(U_id)/2, choi_fit))
```

[code.txt](https://github.com/Qiskit/qiskit-terra/files/2650016/code.txt)

### What is the expected behavior?

returning a Chi matrix equal or close to id_choi 

### Suggested solutions



Discussion:
There are two issues here:

1. You have commented out the measurement and conditional corrections on the ancilla qubits needed for teleportation. Without these the output state of the teleported qubit is effectively random.

2. The process tomography function cannot really handle a teleportation circuit as the function assumes you are preparing and measuring the same qubits. In tomography of a teleportation circuit your input states would be on qubit-0, and your final measurements would be on qubit-2. Where as the process tomography function is applying both the different input states and measurements to qubit-2, which is one of the teleportation ancilla that should be always prepared in 0.
Chriseclectic, thanks for replying.

1. Indeed, measurements and conditional corrections have been commented. But they have been replaced by CX and CZ in agreement with the principle of deferred measurements. See as instance, Fig. 4 in [https://arxiv.org/pdf/1112.3489.pdf](url) attached also here:
<img width="1249" alt="schermata 2018-12-06 alle 18 59 11" src="https://user-images.githubusercontent.com/45635859/49602603-20bea180-f989-11e8-8082-27b794984598.png">

Indeed, this is confirmed by state tomography. Please see the code below, which performs state tomography by comparing the teleported state at qubit [2] for different setting of qubit [0] (x, h, or arbitrary u3)
```
import numpy as np
import time

# importing Qiskit
from qiskit import Aer, IBMQ
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import register, execute

# import backend utilities
from qiskit.backends import JobStatus

# import tomography library
import qiskit.tools.qcvv.tomography as tomo

# useful additional packages 
from qiskit.tools.visualization import plot_state
from qiskit.tools.qi.qi import *
from qiskit.wrapper.jupyter import *
#from qiskit.backends.ibmq import least_busy

# Load saved IBMQ accounts
#IBMQ.load_accounts()

# Creating registers
q = QuantumRegister(3)
c = ClassicalRegister(3)
qc = QuantumCircuit(q, c, name='teleportation')

# inizializing qubit ⓪ to be teleported
#qc.u1(0.5, q[0])
#qc.x(q[0])
#qc.h(q[0])
qc.u3(0.5, 0.5, 0.5, q[0])
qc.barrier(q)

# creating entangled pair between qubit ① and qubit ②
qc.h(q[1])
qc.cx(q[1], q[2])
qc.barrier(q)

# teleportation
qc.cx(q[0], q[1])
qc.barrier(q)

# Measure qubit ⓪ in the + - basis
qc.h(q[0])
qc.cz(q[0],q[2])
## If needed Perform a phase correction to qubit ③
#qc.measure(q[0], c[0])
#if c[0] == 1:
#    qc.z(q[2])
qc.barrier(q)
    
# Measure qubit ① in the computational basis
qc.cx(q[1],q[2])
## If needed Perform a bit flip correction to qubit ②
#qc.measure(q[1], c[1])
#if c[1] == 1:
#    qc.x(q[2])
qc.barrier(q)

# Construct state tomography set for measurement of qubits [0, 1] in the Pauli basis
tomo_set = tomo.state_tomography_set([2])
# Add the state tomography measurement circuits to the Quantum Program
tomo_circuits = tomo.create_tomography_circuits(qc, q, c, tomo_set)

backend = Aer.get_backend('qasm_simulator')
shots = 1000
tomo_job = execute(tomo_circuits, backend=backend, shots=shots)
tomo_results = tomo_job.result()

tomo_data = tomo.tomography_data(tomo_results, 'teleportation', tomo_set)
rho_fit = tomo.fit_tomography_data(tomo_data)
# plot the state
plot_state(rho_fit,'paulivec')

backend = Aer.get_backend('statevector_simulator')
# Creating registers
q = QuantumRegister(1)
c = ClassicalRegister(1)
qc = QuantumCircuit(q, c, name='teleportation')
# inizializing qubit ⓪ to be teleported
#qc.u1(0.5, q[0])
#qc.x(q[0])
#qc.h(q[0])
qc.u3(0.5, 0.5, 0.5, q[0])
job = execute(qc, backend=backend)
psi = job.result().get_statevector(qc)
# construct the density matrix from the state vector
rho = outer(psi) 
# plot the state
plot_state(rho,'paulivec')
```

This is the ideal density matrix of u3(0.5,0.5,0.5) applied to state |0>
![unknown-2](https://user-images.githubusercontent.com/45635859/49603208-e6560400-f98a-11e8-998e-de42f0471958.png)

And this is the density matrix as output of the state tomography for qubit [2] (Bob's side) with qubit [0] (Alice's side) initialized to u3(0.5,0.5,0.5) as well
![unknown](https://user-images.githubusercontent.com/45635859/49603254-0980b380-f98b-11e8-9c26-198d768bdb42.png)


------------------------------------------------------------------------------------------------


2. Here I didn't get you. You meant that I should perform process tomography for all the three qubits? Or what? And if so, why state tomography seems working just fine?

Thanks!
Ah ok, I didn't pay enough attention to your circuit. Yes if you do the controlled gates then my first point doesn't matter. State tomography works because you are performing measurements on qubit-2 for an input prepared on qubit-0. Process tomography doesn't work for the reasons I said above: the function is returning circuits that prepare the different tomographic input states on qubit-2, and tomographic measurement on qubit-2. You need the input states prepared on qubit-0, not qubit-2, and measurements on qubit-2.
Any hint or suggestion on how to do it will be greatly appreciated.
There isn't an easy way to do this at the moment. You would have to edit the tomography functions to specify lists of input and output qubits separately.
Chriseclectic, I believe you mean something like this:

```
{'qubits': [2], 'circuits': [{'prep': {0: ('S', 0)}, 'meas': {2: 'X'}}, {'prep': {0: ('S', 0)}, 'meas': {2: 'Y'}}, {'prep': {0: ('S', 0)}, 'meas': {2: 'Z'}}, {'prep': {0: ('S', 1)}, 'meas': {2: 'X'}}, {'prep': {0: ('S', 1)}, 'meas': {2: 'Y'}}, {'prep': {0: ('S', 1)}, 'meas': {2: 'Z'}}, {'prep': {0: ('S', 2)}, 'meas': {2: 'X'}}, {'prep': {0: ('S', 2)}, 'meas': {2: 'Y'}}, {'prep': {0: ('S', 2)}, 'meas': {2: 'Z'}}, {'prep': {0: ('S', 3)}, 'meas': {2: 'X'}}, {'prep': {0: ('S', 3)}, 'meas': {2: 'Y'}}, {'prep': {0: ('S', 3)}, 'meas': {2: 'Z'}}], 'circuit_labels': ['_prep_S0(0)_meas_X(2)', '_prep_S0(0)_meas_Y(2)', '_prep_S0(0)_meas_Z(2)', '_prep_S1(0)_meas_X(2)', '_prep_S1(0)_meas_Y(2)', '_prep_S1(0)_meas_Z(2)', '_prep_S2(0)_meas_X(2)', '_prep_S2(0)_meas_Y(2)', '_prep_S2(0)_meas_Z(2)', '_prep_S3(0)_meas_X(2)', '_prep_S3(0)_meas_Y(2)', '_prep_S3(0)_meas_Z(2)'], 'prep_basis': {'S': [array([[1, 0],
     [0, 0]]), array([[0.33333333, 0.47140452],
       [0.47140452, 0.66666667]]), array([[ 0.33333333+0.j        , -0.23570226+0.40824829j],
       [-0.23570226-0.40824829j,  0.66666667+0.j        ]]), array([[ 0.33333333+0.j        , -0.23570226-0.40824829j],
       [-0.23570226+0.40824829j,  0.66666667+0.j        ]])]}, 'meas_basis': {'X': [array([[0.5, 0.5],
       [0.5, 0.5]]), array([[ 0.5, -0.5],
       [-0.5,  0.5]])], 'Y': [array([[ 0.5+0.j , -0. -0.5j],
       [ 0. +0.5j,  0.5+0.j ]]), array([[ 0.5+0.j ,  0. +0.5j],
       [-0. -0.5j,  0.5+0.j ]])], 'Z': [array([[1, 0],
       [0, 0]]), array([[0, 0],
       [0, 1]])]}}
```

It seems working just fine, if needed by someone I can share the code (a couple of lines in process_tomography_set)

Resolving patch:
diff --git a/qiskit/tools/qcvv/tomography.py b/qiskit/tools/qcvv/tomography.py
--- a/qiskit/tools/qcvv/tomography.py
+++ b/qiskit/tools/qcvv/tomography.py
@@ -263,8 +263,9 @@ def __sic_prep_gates(circuit, qreg, op):
 ###############################################################################
 
 
-def tomography_set(qubits,
+def tomography_set(meas_qubits,
                    meas_basis='Pauli',
+                   prep_qubits=None,
                    prep_basis=None):
     """
     Generate a dictionary of tomography experiment configurations.
@@ -293,9 +294,11 @@ def tomography_set(qubits,
                  total preparation states).
 
     Args:
-        qubits (list): The qubits being measured.
+        meas_qubits (list): The qubits being measured.
         meas_basis (tomography_basis or str): The qubit measurement basis.
             The default value is 'Pauli'.
+        prep_qubits (list or None): The qubits being prepared. If None then
+            meas_qubits will be used for process tomography experiments.
         prep_basis (tomography_basis or None): The optional qubit preparation
             basis. If no basis is specified state tomography will be performed
             instead of process tomography. A built in basis may be specified by
@@ -320,10 +323,16 @@ def tomography_set(qubits,
     Raises:
         QiskitError: if the Qubits argument is not a list.
     """
-    if not isinstance(qubits, list):
+    if not isinstance(meas_qubits, list):
         raise QiskitError('Qubits argument must be a list')
+    num_of_qubits = len(meas_qubits)
 
-    num_of_qubits = len(qubits)
+    if prep_qubits is None:
+        prep_qubits = meas_qubits
+    if not isinstance(prep_qubits, list):
+        raise QiskitError('prep_qubits argument must be a list')
+    if len(prep_qubits) != len(meas_qubits):
+        raise QiskitError('meas_qubits and prep_qubitsare different length')
 
     if isinstance(meas_basis, str):
         if meas_basis.lower() == 'pauli':
@@ -342,14 +351,14 @@ def tomography_set(qubits,
     if prep_basis is None:
         # State Tomography
         for meas_product in product(meas_basis.keys(), repeat=num_of_qubits):
-            meas = dict(zip(qubits, meas_product))
+            meas = dict(zip(meas_qubits, meas_product))
             circuits.append({'meas': meas})
             # Make label
             label = '_meas_'
             for qubit, op in meas.items():
                 label += '%s(%d)' % (op[0], qubit)
             circuit_labels.append(label)
-        return {'qubits': qubits,
+        return {'qubits': meas_qubits,
                 'circuits': circuits,
                 'circuit_labels': circuit_labels,
                 'meas_basis': meas_basis}
@@ -362,8 +371,8 @@ def tomography_set(qubits,
     for plst_product in product(plst_single, repeat=num_of_qubits):
         for meas_product in product(meas_basis.keys(),
                                     repeat=num_of_qubits):
-            prep = dict(zip(qubits, plst_product))
-            meas = dict(zip(qubits, meas_product))
+            prep = dict(zip(prep_qubits, plst_product))
+            meas = dict(zip(meas_qubits, meas_product))
             circuits.append({'prep': prep, 'meas': meas})
             # Make label
             label = '_prep_'
@@ -373,7 +382,7 @@ def tomography_set(qubits,
             for qubit, op in meas.items():
                 label += '%s(%d)' % (op[0], qubit)
             circuit_labels.append(label)
-    return {'qubits': qubits,
+    return {'qubits': meas_qubits,
             'circuits': circuits,
             'circuit_labels': circuit_labels,
             'prep_basis': prep_basis,
@@ -429,7 +438,8 @@ def state_tomography_set(qubits, meas_basis='Pauli'):
     return tomography_set(qubits, meas_basis=meas_basis)
 
 
-def process_tomography_set(qubits, meas_basis='Pauli', prep_basis='SIC'):
+def process_tomography_set(meas_qubits, meas_basis='Pauli',
+                           prep_qubits=None, prep_basis='SIC'):
     """
     Generate a dictionary of process tomography experiment configurations.
 
@@ -450,9 +460,11 @@ def process_tomography_set(qubits, meas_basis='Pauli', prep_basis='SIC'):
              total preparation states).
 
     Args:
-        qubits (list): The qubits being measured.
+        meas_qubits (list): The qubits being measured.
         meas_basis (tomography_basis or str): The qubit measurement basis.
             The default value is 'Pauli'.
+        prep_qubits (list or None): The qubits being prepared. If None then
+            meas_qubits will be used for process tomography experiments.
         prep_basis (tomography_basis or str): The qubit preparation basis.
             The default value is 'SIC'.
 
@@ -471,7 +483,8 @@ def process_tomography_set(qubits, meas_basis='Pauli', prep_basis='SIC'):
         }
         ```
     """
-    return tomography_set(qubits, meas_basis=meas_basis, prep_basis=prep_basis)
+    return tomography_set(meas_qubits, meas_basis=meas_basis,
+                          prep_qubits=prep_qubits, prep_basis=prep_basis)
 
 
 def tomography_circuit_names(tomo_set, name=''):


Test patch: