from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer, IBMQ, BasicAer
from qiskit.visualization import plot_bloch_multivector,plot_bloch_vector, plot_histogram, plot_state_qsphere
from qiskit.quantum_info import Statevector, partial_trace
import random
import numpy as np 
import matplotlib

backend_statevector = BasicAer.get_backend('statevector_simulator')# This backend executes a single shot of a Qiskit QuantumCircuit and returns the final quantum statevector of the simulation.
style = {'backgroundcolor': 'lightyellow'} # Style of the circuits

backend_qasm = BasicAer.get_backend('qasm_simulator')# This backend is designed to mimic an actual device. 
                                                     #It executes a Qiskit QuantumCircuit and returns a count dictionary containing the final values of any classical registers in the circuit. 
shots = 1024 #Number of individual shots 

qreg = QuantumRegister(2)
registerBell = ClassicalRegister(2) 

qBell = QuantumCircuit(qreg,registerBell )

qBell.h(0)
qBell.cx(0,1)
qBell.draw(output='mpl', style=style)

out_vectorBell = execute(qBell, backend_statevector).result().get_statevector()
plot_state_qsphere(out_vectorBell)

qBell.measure(qreg[0],registerBell [0])
qBell.measure(qreg[1],registerBell [1])
qBell.draw(output='mpl', style=style)

results = execute(qBell, backend=backend_qasm, shots=shots).result()
answer = results.get_counts()

plot_histogram(answer)





def gate_errorX():
    ############################################################
    # This function will return ['X'] with a probability 0.2   #
    # ['Z'] with a probability 0.2                             #
    # and ['I'] with a probability 0.6                         #
    ##########################################################
    random_gate = random.choices(population= ['Z', 'X', 'I'],weights=[0.2,0.2, 0.6],k=1)
    
    return(random_gate)



def noise(qcirc):
    
    if gate_errorX() == ['X']:
    ### Bit-flip in the qubit 0 #####
        qcirc.x(0)
    elif gate_errorX() == ['Z']:
    ### phase-flip in the qubit 0 #####
        qcirc.z(0)
    else:
        qcirc.i(0)
        
    if gate_errorX() == ['X']:
    ### Bit-flip in the qubit 1 #####    
        qcirc.x(1)
    elif gate_errorX() == ['Z']:
    ### phase-flip in the qubit 0 #####
        qcirc.z(1)
    else:
        qcirc.i(1)
        
    return qcirc

qregNoise = QuantumRegister(2)
registerBellNoise = ClassicalRegister(2) 
qBellNoise = QuantumCircuit(qregNoise,registerBellNoise )

qBellNoise.h(0)
qBellNoise.barrier()
noise(qBellNoise)
#qBellNoise.z(0)
qBellNoise.barrier()
qBellNoise.cx(0,1)

qBellNoise.draw(output='mpl', style=style)

out_vectorBellNoise = execute(qBellNoise, backend_statevector).result().get_statevector()
plot_state_qsphere(out_vectorBellNoise)

plot_state_qsphere(out_vectorBell)

qBellNoise.measure(qregNoise[0],registerBellNoise[0])
qBellNoise.measure(qregNoise[1],registerBellNoise[1])
qBellNoise.draw(output='mpl', style=style)

resultsNoise = execute(qBellNoise, backend=backend_qasm, shots=shots).result()
answerNoise = resultsNoise.get_counts()

plot_histogram(answerNoise)

qreg_X1_Noise = QuantumRegister(2)
registerBell_X1_Noise = ClassicalRegister(2) 
qBell_X1_Noise = QuantumCircuit(qreg_X1_Noise,registerBell_X1_Noise )

qBell_X1_Noise.h(0)
qBell_X1_Noise.barrier()
#noise(qBellNoise)
qBell_X1_Noise.x(1)
qBell_X1_Noise.barrier()
qBell_X1_Noise.cx(0,1)

qBell_X1_Noise.draw(output='mpl', style=style)

out_vectorBell_X1_Noise = execute(qBell_X1_Noise, backend_statevector).result().get_statevector()
plot_state_qsphere(out_vectorBell_X1_Noise)



Qreg1 = QuantumRegister(1)
Qreg2 = QuantumRegister(2)

qc_bit_flip = QuantumCircuit(Qreg1,Qreg2)

state_to_protect = [np.sqrt(0.2),np.sqrt(0.8)]

qc_bit_flip.initialize(state_to_protect,0) # Apply initialisation operation to the 0th qubit
qc_bit_flip.barrier()

Initial_state = Statevector.from_instruction(qc_bit_flip)
plot_bloch_multivector(Initial_state, title='Initial state')

qc_bit_flip.cx(0,1)
qc_bit_flip.cx(0,2)
qc_bit_flip.draw(output='mpl', style=style) 

qc_bit_flip.barrier()
qc_bit_flip.x(0)

qc_bit_flip.barrier()
qc_bit_flip.cx(0,2)
qc_bit_flip.cx(0,1)

qc_bit_flip.barrier()
qc_bit_flip.ccx(2,1,0)

qc_bit_flip.draw(output='mpl', style=style) 

out_vector = execute(qc_bit_flip, backend_statevector).result().get_statevector()
plot_bloch_multivector(out_vector, title='Final state')

plot_bloch_multivector(Initial_state, title='Initial state')



qregister1 = QuantumRegister(1)
qregister2 = QuantumRegister(2)
cregister = ClassicalRegister(2, 'c') 

qc_bit_flip_measurements = QuantumCircuit(qregister1,qregister2,cregister)

qc_bit_flip_measurements.initialize(state_to_protect,0) # Apply initialisation operation to the 0th qubit

Initial_state1 = Statevector.from_instruction(qc_bit_flip_measurements)
plot_bloch_multivector(Initial_state1, title='Initial state')

### Perfmoing the encoding #####
qc_bit_flip_measurements.barrier()
qc_bit_flip_measurements.cx(0,1)
qc_bit_flip_measurements.cx(0,2)

### Apply some noise #####
qc_bit_flip_measurements.barrier()
#noise(qc)
qc_bit_flip_measurements.x(0)

### Aplying the inverse of the encoding procedure ###
qc_bit_flip_measurements.barrier()
qc_bit_flip_measurements.cx(0,2)
qc_bit_flip_measurements.cx(0,1)

qc_bit_flip_measurements.barrier()
qc_bit_flip_measurements.measure(qregister2,cregister)

qc_bit_flip_measurements.x(0).c_if(cregister, 3)

qc_bit_flip_measurements.draw(output='mpl', style=style) 

out_vector1 = execute(qc_bit_flip_measurements, backend_statevector).result().get_statevector()
plot_bloch_multivector(out_vector1, title='Final state')

plot_bloch_multivector(Initial_state1, title='Initial state')

qEncoding = QuantumRegister(3)
qAncillas = QuantumRegister(2, 'ancilla')
AncillasRegister = ClassicalRegister(2, 'c') 

qc_bit_flip_ancillas_measuremnts = QuantumCircuit(qEncoding,qAncillas,AncillasRegister)

qc_bit_flip_ancillas_measuremnts.initialize(state_to_protect,0) # Apply initialisation operation to the 0th qubit

Initial_state2 = Statevector.from_instruction(qc_bit_flip_ancillas_measuremnts)
plot_bloch_multivector(Initial_state2, title='Initial state')

### Perfmoing the encoding #####
qc_bit_flip_ancillas_measuremnts.barrier()
qc_bit_flip_ancillas_measuremnts.cx(0,1)
qc_bit_flip_ancillas_measuremnts.cx(0,2)

### Apply some noise #####
qc_bit_flip_ancillas_measuremnts.barrier()
#noise(qc)
qc_bit_flip_ancillas_measuremnts.x(0)

qc_bit_flip_ancillas_measuremnts.barrier()
qc_bit_flip_ancillas_measuremnts.cx(0,4)
qc_bit_flip_ancillas_measuremnts.cx(1,4)

qc_bit_flip_ancillas_measuremnts.barrier()
qc_bit_flip_ancillas_measuremnts.cx(1,3)
qc_bit_flip_ancillas_measuremnts.cx(2,3)

qc_bit_flip_ancillas_measuremnts.barrier()
qc_bit_flip_ancillas_measuremnts.measure(qAncillas,AncillasRegister)

qc_bit_flip_ancillas_measuremnts.x(0).c_if(AncillasRegister, 2)
qc_bit_flip_ancillas_measuremnts.x(1).c_if(AncillasRegister, 3)
qc_bit_flip_ancillas_measuremnts.x(2).c_if(AncillasRegister, 1)

qc_bit_flip_ancillas_measuremnts.barrier()
qc_bit_flip_ancillas_measuremnts.cx(0,2)
qc_bit_flip_ancillas_measuremnts.cx(0,1)

qc_bit_flip_ancillas_measuremnts.draw(output='mpl', style=style) 

out_vector2 = execute(qc_bit_flip_ancillas_measuremnts,backend_statevector).result().get_statevector()
plot_bloch_multivector(out_vector2, title='Final state')

plot_bloch_multivector(Initial_state2, title='Initial state')

qregister_to_protect = QuantumRegister(1)
qregister = QuantumRegister(2)
creg = ClassicalRegister(2, 'c') 

qc_phase_flip = QuantumCircuit(qregister_to_protect,qregister,creg)

qc_phase_flip.initialize(state_to_protect,0) # Apply initialisation operation to the 0th qubit

Initial_state3 = Statevector.from_instruction(qc_phase_flip)
plot_bloch_multivector(Initial_state3, title='Initial state')

### Perfmoing the encoding #####
qc_phase_flip.barrier()
qc_phase_flip.cx(0,1)
qc_phase_flip.cx(0,2)

### Apply thje hadamard gates #####
qc_phase_flip.barrier()
qc_phase_flip.h(0)
qc_phase_flip.h(1)
qc_phase_flip.h(2)

### Apply some noise #####
qc_phase_flip.barrier()
#noise(qc)
qc_phase_flip.z(0)

qc_phase_flip.barrier()

### Apply thje hadamard gates #####
qc_phase_flip.h(0)
qc_phase_flip.h(1)
qc_phase_flip.h(2)

### Aplying the inverse of the encoding procedure ###
qc_phase_flip.barrier()

qc_phase_flip.cx(0,2)
qc_phase_flip.cx(0,1)

qc_phase_flip.barrier()
qc_phase_flip.measure(qregister,creg)

qc_phase_flip.x(0).c_if(cregister, 3)

qc_phase_flip.draw(output='mpl', style=style) 

out_vector4 = execute(qc_phase_flip, backend_statevector).result().get_statevector()
plot_bloch_multivector(out_vector4)

plot_bloch_multivector(Initial_state3, title='Initial state')

qregA = QuantumRegister(1)
qr1 = QuantumRegister(2)
qregB = QuantumRegister(1)
qr2 = QuantumRegister(2)
qregC = QuantumRegister(1)
qr3 = QuantumRegister(2)
r1 = ClassicalRegister(2, 'c1') 
r2 = ClassicalRegister(2, 'c2') 
r3 = ClassicalRegister(2, 'c3') 
registerBC = ClassicalRegister(2, 'c')

qc_shor_code = QuantumCircuit(qregA, qr1,qregB, qr2,qregC,qr3,r1,r2,r3,registerBC)

qc_shor_code.initialize(state_to_protect,0) # Apply initialisation operation to the 0th qubit
qc_shor_code.barrier()

Initial_state4 = Statevector.from_instruction(qc_shor_code)
plot_bloch_multivector(Initial_state4, title='Initial state')

qc_shor_code.cx(0,3)
qc_shor_code.cx(0,6)
qc_shor_code.h(0)
qc_shor_code.h(3)
qc_shor_code.h(6)

qc_shor_code.barrier()

qc_shor_code.cx(0,1)
qc_shor_code.cx(0,2)

qc_shor_code.cx(3,4)
qc_shor_code.cx(3,5)

qc_shor_code.cx(6,7)
qc_shor_code.cx(6,8)

qc_shor_code.draw(output='mpl', style=style) 

### Apply some gate error, in this case X y Z gate ###
qc_shor_code.barrier()
qc_shor_code.x(0)
qc_shor_code.z(6)

## This is the saame as the bit-flip code with measurements (Part 3.2) repeated  3 times ##
qc_shor_code.barrier()

qc_shor_code.cx(0,2)
qc_shor_code.cx(0,1)

qc_shor_code.cx(3,5)
qc_shor_code.cx(3,4)

qc_shor_code.cx(6,8)
qc_shor_code.cx(6,7)

qc_shor_code.barrier()
qc_shor_code.measure(qr1,r1)
qc_shor_code.measure(qr2,r2)
qc_shor_code.measure(qr3,r3)


qc_shor_code.x(qregA).c_if(r1, 3)
qc_shor_code.x(qregB).c_if(r2, 3)
qc_shor_code.x(qregC).c_if(r3, 3)

### Aplying the inverse of the encoding procedure ###

qc_shor_code.barrier()
qc_shor_code.h(0)
qc_shor_code.h(3)
qc_shor_code.h(6)

qc_shor_code.cx(0,6)
qc_shor_code.cx(0,3)

qc_shor_code.measure(qregB,registerBC[0])
qc_shor_code.measure(qregC,registerBC[1])

qc_shor_code.x(qregA).c_if(registerBC, 3)

qc_shor_code.draw(output='mpl', style=style, fold= 30) 

out_vector5 = execute(qc_shor_code,backend_statevector).result().get_statevector()
plot_bloch_multivector(out_vector5)

reduced_state_shor_code = partial_trace(out_vector5 , [1,2,3,4,5,6,7,8])

plot_bloch_multivector(reduced_state_shor_code)

plot_bloch_multivector(Initial_state4, title='Initial state')

reduced_intial_state_shor_code = partial_trace(Initial_state4 , [1,2,3,4,5,6,7,8])

plot_bloch_multivector(reduced_intial_state_shor_code)

def shor_encoding(qc_shor_encode):
    ## Encoding for the shor code ##
    ################################
    qc_shor_encode.cx(0,3)
    qc_shor_encode.cx(0,6)
    qc_shor_encode.h(0)
    qc_shor_encode.h(3)
    qc_shor_encode.h(6)

    qc_shor_encode.barrier()

    qc_shor_encode.cx(0,1)
    qc_shor_encode.cx(0,2)

    qc_shor_encode.cx(3,4)
    qc_shor_encode.cx(3,5)

    qc_shor_encode.cx(6,7)
    qc_shor_encode.cx(6,8)

    qc_shor_encode.barrier()
    
    return(qc_shor_encode)

def shor_correct(qc_shor_code_correct,qCorrect_regA, qCorrect_r1,qCorrect_regB, qCorrect_r2,qCorrect_regC,qCorrect_r3,rCorrect1,rCorrect2,rCorrect3,registerCorrectBC ):
    ## Correction of the error in the shor code ##
    ##############################################
    qc_shor_code_correct.barrier()
    qc_shor_code_correct.cx(0,2)
    qc_shor_code_correct.cx(0,1)

    qc_shor_code_correct.cx(3,5)
    qc_shor_code_correct.cx(3,4)

    qc_shor_code_correct.cx(6,8)
    qc_shor_code_correct.cx(6,7)

    qc_shor_code_correct.barrier()
    qc_shor_code_correct.measure(qCorrect_r1,rCorrect1)
    qc_shor_code_correct.measure(qCorrect_r2,rCorrect2)
    qc_shor_code_correct.measure(qCorrect_r3,rCorrect3)

    qc_shor_code_correct.x(qCorrect_regA).c_if(rCorrect1, 3)
    qc_shor_code_correct.x(qCorrect_regB).c_if(rCorrect2, 3)
    qc_shor_code_correct.x(qCorrect_regC).c_if(rCorrect3, 3)

    qc_shor_code_correct.barrier()
    qc_shor_code_correct.h(0)
    qc_shor_code_correct.h(3)
    qc_shor_code_correct.h(6)

    qc_shor_code_correct.cx(0,6)
    qc_shor_code_correct.cx(0,3)

    qc_shor_code_correct.measure(qCorrect_regB,registerCorrectBC[0])
    qc_shor_code_correct.measure(qCorrect_regC,registerCorrectBC[1])

    qc_shor_code_correct.x(qCorrect_regA).c_if(registerCorrectBC, 3)
    
    return(qc_shor_code_correct)

### Ciruit to encode the state for the bit-flip code ####
q_Encoding_bit_flip_reg1 = QuantumRegister(1)
q_Encoding_bit_flip_reg2 = QuantumRegister(2)

qc_Encoding_bit_flip = QuantumCircuit(Qreg1,Qreg2)

qc_Encoding_bit_flip.cx(0,1)
qc_Encoding_bit_flip.cx(0,2)

### Ciruit to correct the state for the bit-flip code ####
qBit_flip_correct_register1 = QuantumRegister(1)
qBit_flip_correct_register2 = QuantumRegister(2)
cBit_flip_correct_register = ClassicalRegister(2, 'c') 

qcBit_flip_correct = QuantumCircuit(qBit_flip_correct_register1,qBit_flip_correct_register2,cBit_flip_correct_register)

qcBit_flip_correct.barrier()
qcBit_flip_correct.cx(0,2)
qcBit_flip_correct.cx(0,1)
qcBit_flip_correct.barrier()
qcBit_flip_correct.measure(qBit_flip_correct_register2,cBit_flip_correct_register)
qcBit_flip_correct.x(0).c_if(cBit_flip_correct_register, 3)
qcBit_flip_correct.barrier()

q_To_Protect1 = QuantumRegister(1, name = 'state_to_protect1')
qCorrect_r1 = QuantumRegister(2)
qCorrect_regB = QuantumRegister(1)
qCorrect_r2 = QuantumRegister(2)
qCorrect_regC = QuantumRegister(1)
qCorrect_r3 = QuantumRegister(2)
rCorrect1 = ClassicalRegister(2, 'c1') 
rCorrect2 = ClassicalRegister(2, 'c2') 
rCorrect3 = ClassicalRegister(2, 'c3') 
registerCorrectBC = ClassicalRegister(2, 'c')
q_To_Protect2 =  QuantumRegister(1, name = 'state_to_protect2')
qregister_test2 = QuantumRegister(2)

qbell_test = QuantumCircuit(q_To_Protect1, qCorrect_r1,qCorrect_regB, qCorrect_r2,qCorrect_regC,qCorrect_r3,rCorrect1,rCorrect2,rCorrect3,registerCorrectBC, q_To_Protect2, qregister_test2)

qbell_test.h(0)
qbell_test.barrier()
qbell_test.draw(output='mpl', style=style)

shor_encoding(qbell_test)

new_qc1 = qbell_test.compose(qc_Encoding_bit_flip,[9,10,11])

new_qc1.draw(output='mpl', style=style)

new_qc1.barrier()
new_qc1.x(0)
new_qc1.z(9)

new_qc2 = new_qc1.compose(qcBit_flip_correct,[9,10,11])

shor_correct(new_qc2,q_To_Protect1, qCorrect_r1,qCorrect_regB, qCorrect_r2,qCorrect_regC,qCorrect_r3,rCorrect1,rCorrect2,rCorrect3,registerCorrectBC)

new_qc2.barrier()
new_qc2.cx(0,9)

new_qc2.draw(output='mpl', style=style, fold= 42)

out_vector8 = execute(new_qc2,backend_statevector).result().get_statevector()
reduced_state1 = partial_trace(out_vector8 , [1,2,3,4,5,6,7,8,10,11])

plot_state_qsphere(reduced_state1)

q_To_Protect1_ZX = QuantumRegister(1, name = 'state_to_protect1')
qCorrect_r1_ZX = QuantumRegister(2)
qCorrect_regB_ZX = QuantumRegister(1)
qCorrect_r2_ZX = QuantumRegister(2)
qCorrect_regC_ZX = QuantumRegister(1)
qCorrect_r3_ZX = QuantumRegister(2)
rCorrect1_ZX = ClassicalRegister(2, 'c1') 
rCorrect2_ZX = ClassicalRegister(2, 'c2') 
rCorrect3_ZX = ClassicalRegister(2, 'c3') 
registerCorrectBC_ZX = ClassicalRegister(2, 'c')
q_To_Protect2_ZX =  QuantumRegister(1, name = 'state_to_protect2')
qregister_test2_ZX = QuantumRegister(2)

qbell_test_ZX = QuantumCircuit(q_To_Protect1_ZX, qCorrect_r1_ZX,qCorrect_regB_ZX, qCorrect_r2_ZX,qCorrect_regC_ZX,qCorrect_r3_ZX,rCorrect1_ZX,rCorrect2_ZX,rCorrect3_ZX,registerCorrectBC_ZX, q_To_Protect2_ZX, qregister_test2_ZX)

qbell_test_ZX.h(0)
qbell_test_ZX.barrier()

shor_encoding(qbell_test_ZX)

new_qc1_ZX = qbell_test_ZX.compose(qc_Encoding_bit_flip,[9,10,11])

#### Error gates ######
new_qc1_ZX.barrier()
new_qc1_ZX.z(0)
new_qc1_ZX.x(9)

new_qc2_ZX = new_qc1_ZX.compose(qcBit_flip_correct,[9,10,11])

shor_correct(new_qc2_ZX,q_To_Protect1_ZX , qCorrect_r1_ZX ,qCorrect_regB_ZX, qCorrect_r2_ZX,qCorrect_regC_ZX,qCorrect_r3_ZX,rCorrect1_ZX,rCorrect2_ZX,rCorrect3_ZX,registerCorrectBC_ZX)

new_qc2_ZX.barrier()
new_qc2_ZX.cx(0,9)

new_qc2_ZX.draw(output='mpl', style=style, fold= 42)

out_vector8 = execute(new_qc2,backend_statevector).result().get_statevector()
reduced_state1 = partial_trace(out_vector8 , [1,2,3,4,5,6,7,8,10,11])

plot_state_qsphere(reduced_state1)

q_To_Protect1_YX = QuantumRegister(1, name = 'state_to_protect1')
qCorrect_r1_YX = QuantumRegister(2)
qCorrect_regB_YX = QuantumRegister(1)
qCorrect_r2_YX = QuantumRegister(2)
qCorrect_regC_YX = QuantumRegister(1)
qCorrect_r3_YX = QuantumRegister(2)
rCorrect1_YX = ClassicalRegister(2, 'c1') 
rCorrect2_YX = ClassicalRegister(2, 'c2') 
rCorrect3_YX = ClassicalRegister(2, 'c3') 
registerCorrectBC_YX = ClassicalRegister(2, 'c')
q_To_Protect2_YX =  QuantumRegister(1, name = 'state_to_protect2')
qregister_test2_YX = QuantumRegister(2)

qbell_test_YX = QuantumCircuit(q_To_Protect1_YX, qCorrect_r1_YX,qCorrect_regB_YX, qCorrect_r2_YX,qCorrect_regC_YX,qCorrect_r3_YX,rCorrect1_YX,rCorrect2_YX,rCorrect3_YX,registerCorrectBC_YX, q_To_Protect2_YX, qregister_test2_YX)

qbell_test_YX.h(0)
qbell_test_YX.barrier()
qbell_test_YX.draw(output='mpl', style=style)

shor_encoding(qbell_test_YX)

new_qc1_YX = qbell_test_YX.compose(qc_Encoding_bit_flip,[9,10,11])

#### Error gates ######
new_qc1_YX.barrier()
new_qc1_YX.y(0)
new_qc1_YX.x(9)

new_qc2_YX = new_qc1_YX.compose(qcBit_flip_correct,[9,10,11])

shor_correct(new_qc2_YX,q_To_Protect1_YX , qCorrect_r1_YX ,qCorrect_regB_YX, qCorrect_r2_YX,qCorrect_regC_YX,qCorrect_r3_YX,rCorrect1_YX,rCorrect2_YX,rCorrect3_YX,registerCorrectBC_YX)

new_qc2_YX.barrier()
new_qc2_YX.cx(0,9)

new_qc2_YX.draw(output='mpl', style=style, fold= 42)

out_vector9 = execute(new_qc2_YX,backend_statevector).result().get_statevector()
reduced_state2 = partial_trace(out_vector9 , [1,2,3,4,5,6,7,8,10,11])

plot_state_qsphere(reduced_state2)

def random_error_gate(qcirc):
    
    if gate_errorX() == ['X']:
    ### Bit-flip in the qubit 0 #####
        qcirc.x(0)
    elif gate_errorX() == ['Z']:
    ### phase-flip in the qubit 0 #####
        qcirc.z(0)
    else:
        qcirc.i(0)
        
    if gate_errorX() == ['X']:
    ### Bit-flip in the qubit 9 #####    
        qcirc.x(9)
    elif gate_errorX() == ['Z']:
    ### phase-flip in the qubit 9 #####
        qcirc.z(9)
    else:
        qcirc.i(9)
        
    return qcirc

q_To_Protect1_Random = QuantumRegister(1, name = 'state_to_protect1')
qCorrect_r1_Random = QuantumRegister(2)
qCorrect_regB_Random = QuantumRegister(1)
qCorrect_r2_Random = QuantumRegister(2)
qCorrect_regC_Random = QuantumRegister(1)
qCorrect_r3_Random = QuantumRegister(2)
rCorrect1_Random = ClassicalRegister(2, 'c1') 
rCorrect2_Random = ClassicalRegister(2, 'c2') 
rCorrect3_Random = ClassicalRegister(2, 'c3') 
registerCorrectBC_Random = ClassicalRegister(2, 'c')
q_To_Protect2_Random =  QuantumRegister(1, name = 'state_to_protect2')
qregister_test2_Random = QuantumRegister(2)

qbell_test_Random = QuantumCircuit(q_To_Protect1_Random, qCorrect_r1_Random,qCorrect_regB_Random, qCorrect_r2_Random,qCorrect_regC_Random,qCorrect_r3_Random,rCorrect1_Random,rCorrect2_Random,rCorrect3_Random,registerCorrectBC_Random, q_To_Protect2_Random, qregister_test2_Random)

qbell_test_Random.h(0)
qbell_test_Random.barrier()

shor_encoding(qbell_test_Random)

new_qc1_Random = qbell_test_Random.compose(qc_Encoding_bit_flip,[9,10,11])

#### Error gates ######
new_qc1_Random.barrier()
random_error_gate(new_qc1_Random)
################################

new_qc2_Random = new_qc1_Random.compose(qcBit_flip_correct,[9,10,11])

shor_correct(new_qc2_Random,q_To_Protect1_Random , qCorrect_r1_Random ,qCorrect_regB_Random, qCorrect_r2_Random,qCorrect_regC_Random,qCorrect_r3_Random,rCorrect1_Random,rCorrect2_Random,rCorrect3_Random,registerCorrectBC_Random)

new_qc2_Random.barrier()
new_qc2_Random.cx(0,9)

new_qc2_Random.draw(output='mpl', style=style, fold= 42)

out_vector10 = execute(new_qc2_Random,backend_statevector).result().get_statevector()
reduced_state3 = partial_trace(out_vector10 , [1,2,3,4,5,6,7,8,10,11])

plot_state_qsphere(reduced_state3)

