#############################
#  Pauli channel on IBMQX2  #
#############################

from qiskit import QuantumRegister, QuantumCircuit

# Quantum register
q = QuantumRegister(5, name="q")

# Quantum circuit
pauli = QuantumCircuit(q)

# Pauli channel acting on q_2
## Qubit identification
system = 2
a_0 = 3
a_1 = 4

## Define rotation angles
theta_1 = 0.0
theta_2 = 0.0
theta_3 = 0.0

## Construct circuit
pauli.ry(theta_1, q[a_0])
pauli.cx(q[a_0], q[a_1])
pauli.ry(theta_2, q[a_0])
pauli.ry(theta_3, q[a_1])
pauli.cx(q[a_0], q[system])
pauli.cy(q[a_1], q[system])

# Draw circuit
pauli.draw(output='mpl')

####################################
#  Depolarizing channel on IBMQX2  #
####################################

# Quantum register
q = QuantumRegister(5, name="q")

# Quantum circuit
depolarizing = QuantumCircuit(q)

# Depolarizing channel acting on q_2
## Qubit identification
system = 2
a_0 = 1
a_1 = 3
a_2 = 4


## Define rotation angles
theta = 0.0

## Construct circuit
depolarizing.ry(theta, q[a_0])
depolarizing.ry(theta, q[a_1])
depolarizing.ry(theta, q[a_2])
depolarizing.cx(q[a_0], q[system])
depolarizing.cy(q[a_1], q[system])
depolarizing.cz(q[a_2], q[system])

# Draw circuit
depolarizing.draw(output='mpl')

#######################
#  ZZ pump on IBMQX2  #
#######################

# Quantum register
q = QuantumRegister(5, name='q')

# Quantum circuit  
zz = QuantumCircuit(q)

# ZZ pump acting on system qubits
## Qubit identification
system = [2, 1]
a_zz = 0

## Define pump efficiency 
## and corresponding rotation
p = 0.5
theta = 2 * np.arcsin(np.sqrt(p))

## Construct circuit
### Map information to ancilla
zz.cx(q[system[0]], q[system[1]])
zz.x(q[a_zz])
zz.cx(q[system[1]], q[a_zz])
    
### Conditional rotation
zz.cu3(theta, 0.0, 0.0, q[a_zz], q[system[1]])
    
### Inverse mapping
zz.cx(q[system[1]], q[a_zz])
zz.cx(q[system[0]], q[system[1]])

# Draw circuit
zz.draw(output='mpl')

#######################
#  XX pump on IBMQX2  #
#######################

# Quantum register
q = QuantumRegister(5, name='q')

# Quantum circuit  
xx = QuantumCircuit(q)

# XX pump acting on system qubits
## Qubit identification
system = [2, 1]
a_xx = 4

## Define pump efficiency 
## and corresponding rotation
p = 0.5
theta = 2 * np.arcsin(np.sqrt(p))

## Construct circuit
### Map information to ancilla
xx.cx(q[system[0]], q[system[1]])
xx.h(q[system[0]])
xx.x(q[a_xx])
xx.cx(q[system[0]], q[a_xx])
    
### Conditional rotation
xx.cu3(theta, 0.0, 0.0, q[a_xx], q[system[0]])
    
### Inverse mapping
xx.cx(q[system[0]], q[a_xx])
xx.h(q[system[0]])
xx.cx(q[system[0]], q[system[1]])

# Draw circuit
xx.draw(output='mpl')

###########################
#  ZZ-XX pumps on IBMQX2  #
###########################

# Quantum register
q = QuantumRegister(5, name='q')

# Quantum circuit  
zz_xx = QuantumCircuit(q)

# ZZ and XX pumps acting on system qubits
## Qubit identification
system = [2, 1]
a_zz = 0
a_xx = 4

## Define pump efficiency 
## and corresponding rotation
p = 0.5
theta = 2 * np.arcsin(np.sqrt(p))

## Construct circuit
## ZZ pump
### Map information to ancilla
zz_xx.cx(q[system[0]], q[system[1]])
zz_xx.x(q[a_zz])
zz_xx.cx(q[system[1]], q[a_zz])
    
### Conditional rotation
zz_xx.cu3(theta, 0.0, 0.0, q[a_zz], q[system[1]])
    
### Inverse mapping
zz_xx.cx(q[system[1]], q[a_zz])
#zz_xx.cx(q[system[0]], q[system[1]])

## XX pump
### Map information to ancilla
#zz_xx.cx(q[system[0]], q[system[1]])
zz_xx.h(q[system[0]])
zz_xx.x(q[a_xx])
zz_xx.cx(q[system[0]], q[a_xx])
    
### Conditional rotation
zz_xx.cu3(theta, 0.0, 0.0, q[a_xx], q[system[0]])
    
### Inverse mapping
zz_xx.cx(q[system[0]], q[a_xx])
zz_xx.h(q[system[0]])
zz_xx.cx(q[system[0]], q[system[1]])

# Draw circuit
zz_xx.draw(output='mpl')