# %matplotlib inline
# Importing standard Qiskit libraries and configuring account
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer, IBMQ
from qiskit.compiler import transpile, assemble
from qiskit.tools.jupyter import *
from qiskit.visualization import *
from datetime import datetime
# import math
# Loading your IBM Q account(s)
# IBMQ.load_account()

backend = Aer.get_backend("qasm_simulator")

# global n_reg
# global m_reg
# global scratch_a
# global class_reg
# global backend
# global qc
# global test_timestamp

# def before_tests():
n_reg = QuantumRegister(6, 'n')
m_reg = QuantumRegister(6, 'm')
scratch_a = QuantumRegister(6, 'sca')
class_reg = ClassicalRegister(6, 'y')
qc = QuantumCircuit(n_reg, m_reg, scratch_a, class_reg)

backend = Aer.get_backend('qasm_simulator')

from ArithmaticFunctions import *
# time_stamp = str(datetime.now())

test_timestamp = str(datetime.now())

def setup_each_addition():
    n_reg = QuantumRegister(6, 'n')
    m_reg = QuantumRegister(6, 'm')
    scratch_a = QuantumRegister(6, 'sca')
    class_reg = ClassicalRegister(6, 'y')
    qc = QuantumCircuit(n_reg, m_reg, scratch_a, class_reg)
    
#     return {'n_reg': n_reg, 'm_reg': m_reg, 'scratch_a': scratch_a, 'class_reg': class_reg, 'qc': qc }

def get_results_of_last_test():
#     for bit in range(len(n_reg)):
#         qc.measure(n_reg[bit], class_reg[bit])

    simulate = execute(qc, backend=backend, shots=1024).result()
    return simulate.get_counts()

def verify_results(expected):
    
    if [expected] == list(results.keys()):
        print("PASSING - ", test_timestamp)
    else:
        print("FAILING - ", test_timestamp)
        print(f'Got - {results}')
    

setup_each_addition()

qc.x(m_reg[0])

CDKM_add(qc, n_reg, m_reg, scratch_a)

qc.measure(m_reg, class_reg)

results = get_results_of_last_test()

verify_results('000001')

setup_each_addition()

qc.x(n_reg[0])

CDKM_add(qc, n_reg, m_reg, scratch_a)

qc.measure(m_reg, class_reg)

results = get_results_of_last_test()

verify_results('000001')

setup_each_addition()

qc.x(n_reg[0])
qc.x(m_reg[0])
qc.barrier()

CDKM_add(qc, n_reg, m_reg, scratch_a)

qc.measure(n_reg, class_reg)

results = get_results_of_last_test()

# qc.draw()

verify_results('000010')



a = QuantumRegister(3, 'a')
b = QuantumRegister(3, 'b')
c = QuantumRegister(3, 'c')
y = ClassicalRegister(3, 'y')
circ = QuantumCircuit(a,b,c,y)

circ.x(a[1])
circ.x(b[1])

MAJ(circ, bit_a=a[0], bit_b=b[0], bit_c=c[0])
MAJ(circ, bit_a=a[1], bit_b=b[1], bit_c=a[0])
circ.cx(a[1], c[1])
UMA(circ, bit_a=a[1], bit_b=b[1], bit_c=a[0])
UMA(circ, bit_a=a[0], bit_b=b[0], bit_c=c[0])

circ.measure(c, y)
results = execute(circ, backend, shots=1024).result().get_counts()

print(results)

MAJ(circ, bit_a=a[0], bit_b=b[0], bit_c=c[0])
circ.draw()

len(scratch_a)

# setup_each_addition()

qc.x(n_reg[0])
qc.x(n_reg[1])
# qc.x(m_reg[0])
qc.barrier()
twos_compelement(qc, n_reg, scratch_a)

twos_compelement(qc, n_reg, scratch_a)
    
qc.measure(n_reg, class_reg)

results = get_results_of_last_test()

# qc.draw()

results = execute(qc, backend, shots=1024).result().get_counts()

print(results)

qc.draw()

a = QuantumRegister(4, 'a')
b = QuantumRegister(4, 'b')
c = QuantumRegister(4, 'c')
d = QuantumRegister(4, 'd')
y = ClassicalRegister(4, 'y')
z = ClassicalRegister(4, 'z')
qc = QuantumCircuit(a,b,c,d,y,z)

qc.x(a[0])
qc.x(b[1])
qc.barrier()
# twos_compelement(qc, a, c)
CDKM_add(qc, a, b, c)
# twos_compelement(qc, b, c)
# twos_compelement(qc, a, c)

qc.measure(a, y)
qc.measure(b, z)

results = execute(qc, backend, shots=1024).result().get_counts()

print(results)

qc.draw()

qc.x(a[1])
qc.x(b[0])
qc.barrier()
# twos_compelement(qc, a, c)
sub_b_from_a_in_place(qc, a, b, c)
# twos_compelement(qc, b, c)
# twos_compelement(qc, a, c)

qc.measure(c, y)
# qc.measure(d, z)

results = execute(qc, backend, shots=1024).result().get_counts()

print(results)

qc.x(a[1])
qc.x(b[1])
qc.barrier()
# twos_compelement(qc, a, c)
sub_b_from_a_in_place(qc, a, b, c)
# twos_compelement(qc, b, c)
# twos_compelement(qc, a, c)

qc.measure(c, y)
# qc.measure(d, z)

results = execute(qc, backend, shots=1024).result().get_counts()

print(results)

