# Checking the version of PYTHON; we only support 3 at the moment
import sys
if sys.version_info < (3,0):
    raise Exception('Please use Python version 3 or greater.')
    
# useful additional packages 
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import time
from pprint import pprint

# importing the QISKit
from qiskit import QuantumCircuit, QuantumProgram 
#import Qconfig 
# import basic plot tools
from qiskit.tools.visualization import plot_histogram

QPS_SPECS = {
    'circuits': [{
        'name': 'W_states',
        'quantum_registers': [{
            'name':'q',
            'size':5
        }],
        'classical_registers': [{
            'name':'c',
            'size':5
        }]}],
}
Q_program = QuantumProgram(specs=QPS_SPECS)
#Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])  

"Choice of the backend"
# The flag_qx2 must be "True" for using the ibmqx2. 
# "True" is also better when using the simulator (shorter circuit)
#backend = 'ibmqx2'
#backend = 'ibmqx4'
backend = 'local_qasm_simulator'  

#backend = 'ibmqx_hpc_qasm_simulator'  
flag_qx2 = True
if backend == 'ibmqx4':
        flag_qx2 = False
        
print("Your choice for the backend is: ", backend, "flag_qx2 is: ", flag_qx2)

# Here, two useful routine
# Define a F_gate
def F_gate(circ,q,i,j,n,k) :
    theta = np.arccos(np.sqrt(1/(n-k+1)))
    circ.ry(-theta,q[j])       
    circ.cz(q[i],q[j])
    circ.ry(theta,q[j])
    circ.barrier(q[i])
# Define the cxrv gate which uses reverse CNOT instead of CNOT
def  cxrv(circ,q,i,j) :
    circ.h(q[i])
    circ.h(q[j])
    circ.cx(q[j],q[i])
    circ.h(q[i])
    circ.h(q[j])
    circ.barrier(q[i],q[j])

# 3-qubit W state Step 1

Q_program = QuantumProgram(specs=QPS_SPECS)
#Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])  
W_states = Q_program.get_circuit('W_states') 
q = Q_program.get_quantum_register('q') 
c = Q_program.get_classical_register('c')

W_states.x(q[2]) #start is |100>
F_gate(W_states,q,2,1,3,1) # Applying F12
    
for i in range(3) :
    W_states.measure(q[i] , c[i]) 

circuits = ['W_states']

shots = 1024
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('start W state 3-qubit (step 1) on', backend, "N=", shots,time_exp)
result = Q_program.execute(circuits, backend=backend, shots=shots, max_credits=5, wait=5, timeout=600)
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('end   W state 3-qubit (step 1) on', backend, "N=", shots,time_exp)
plot_histogram(result.get_counts('W_states'))

# 3-qubit W state, first and second steps

Q_program = QuantumProgram(specs=QPS_SPECS)
#Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])  
W_states = Q_program.get_circuit('W_states') 
q = Q_program.get_quantum_register('q') 
c = Q_program.get_classical_register('c')
        

W_states.x(q[2]) #start is |100>
F_gate(W_states,q,2,1,3,1) # Applying F12
F_gate(W_states,q,1,0,3,2) # Applying F23
       
for i in range(3) :
    W_states.measure(q[i] , c[i]) 

circuits = ['W_states']

shots = 1024
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('start W state 3-qubit (steps 1 + 2) on', backend, "N=", shots,time_exp)
result = Q_program.execute(circuits, backend=backend, shots=shots, max_credits=5, wait=5, timeout=600)
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('end   W state 3-qubit (steps 1 + 2) on', backend, "N=", shots,time_exp)
plot_histogram(result.get_counts('W_states'))

# 3-qubit W state

Q_program = QuantumProgram(specs=QPS_SPECS)
#Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])   
W_states = Q_program.get_circuit('W_states') 
q = Q_program.get_quantum_register('q') 
c = Q_program.get_classical_register('c')

W_states.x(q[2]) #start is |100>
F_gate(W_states,q,2,1,3,1) # Applying F12
F_gate(W_states,q,1,0,3,2) # Applying F23

if flag_qx2 : # option ibmqx2 
    W_states.cx(q[1],q[2]) # cNOT 21
    W_states.cx(q[0],q[1]) # cNOT 32
    
else :        # option ibmqx4  
    cxrv(W_states,q,1,2)
    cxrv(W_states,q,0,1)

for i in range(3) :
    W_states.measure(q[i] , c[i]) 
    
circuits = ['W_states']

shots = 1024
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('start W state 3-qubit on', backend, "N=", shots,time_exp)
result = Q_program.execute(circuits, backend=backend, shots=shots, max_credits=5, wait=5, timeout=600)
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('end   W state 3-qubit on', backend, "N=", shots,time_exp)
plot_histogram(result.get_counts('W_states'))

# 4-qubit W state

Q_program = QuantumProgram(specs=QPS_SPECS)
# Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])  
W_states = Q_program.get_circuit('W_states') 
q = Q_program.get_quantum_register('q') 
c = Q_program.get_classical_register('c')

W_states.x(q[3]) #start is |1000>
F_gate(W_states,q,3,2,4,1) # Applying F12
F_gate(W_states,q,2,1,4,2) # Applying F23
F_gate(W_states,q,1,0,4,3) # Applying F34        
cxrv(W_states,q,2,3) # cNOT 21
if flag_qx2 : # option ibmqx2  
    W_states.cx(q[1],q[2]) # cNOT 32
    W_states.cx(q[0],q[1]) # cNOT 43

else :        # option ibmqx4 
    cxrv(W_states,q,1,2)
    cxrv(W_states,q,0,1)

for i in range(4) :
    W_states.measure(q[i] , c[i]) 

circuits = ['W_states']

shots = 1024
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('start W state 4-qubit ', backend, "N=", shots,time_exp)
result = Q_program.execute(circuits, backend=backend, shots=shots, max_credits=5, wait=5, timeout=600)
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('end   W state 4-qubit on', backend, "N=", shots,time_exp)
plot_histogram(result.get_counts('W_states'))

# 5-qubit W state

Q_program = QuantumProgram(specs=QPS_SPECS)
#Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])  
W_states = Q_program.get_circuit('W_states') 
q = Q_program.get_quantum_register('q') 
c = Q_program.get_classical_register('c')

W_states.x(q[4]) #start is |10000>
F_gate(W_states,q,4,3,5,1) # Applying F12
F_gate(W_states,q,3,2,5,2) # Applying F23
F_gate(W_states,q,2,1,5,3) # Applying F34
F_gate(W_states,q,1,0,5,4) # Applying F45
W_states.cx(q[3],q[4]) # cNOT 21
cxrv(W_states,q,2,3)   # cNOT 32
if flag_qx2 : # option ibmqx2 
    W_states.cx(q[1],q[2]) # cNOT 43
    W_states.cx(q[0],q[1]) # cNOT 54
    
else :        # option ibmqx4 
    cxrv(W_states,q,1,2)
    cxrv(W_states,q,0,1)     
    
for i in range(5) :
    W_states.measure(q[i] , c[i]) 

circuits = ['W_states']

shots = 1024
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('start W state 5-qubit on', backend, "N=", shots,time_exp)
result = Q_program.execute(circuits, backend=backend, shots=shots, max_credits=5, wait=5, timeout=1200)
time_exp = time.strftime('%d/%m/%Y %H:%M:%S')
print('end   W state 5-qubit on', backend, "N=", shots,time_exp)
plot_histogram(result.get_counts('W_states'))

