# Importing Packages
from qiskit import IBMQ, Aer
from qiskit.providers.ibmq import least_busy
from qiskit import QuantumCircuit, transpile, assemble, QuantumRegister, ClassicalRegister
from qiskit.visualization import plot_histogram
from qiskit_textbook.tools import simon_oracle

bb =  input("Enter the input string:\n")

### Using in-built "simon_oracle" from QISKIT

# importing Qiskit
from qiskit import IBMQ, Aer
from qiskit.providers.ibmq import least_busy
from qiskit import QuantumCircuit, transpile, assemble

# import basic plot tools
from qiskit.visualization import plot_histogram
from qiskit_textbook.tools import simon_oracle

n = len(bb)
simon_circuit = QuantumCircuit(n*2, n)

# Apply Hadamard gates before querying the oracle
simon_circuit.h(range(n))    
    
# Apply barrier for visual separation
simon_circuit.barrier()

simon_circuit += simon_oracle(b)

# Apply barrier for visual separation
simon_circuit.barrier()

# Apply Hadamard gates to the input register
simon_circuit.h(range(n))

# Measure qubits
simon_circuit.measure(range(n), range(n))
simon_circuit.draw(output="mpl")

# use local simulator
aer_sim = Aer.get_backend('aer_simulator')
shots = 500
qobj = assemble(simon_circuit, shots=shots)
results = aer_sim.run(qobj).result()
counts = results.get_counts()
print(counts)
plot_histogram(counts)

# Calculate the dot product of the results
def bdotz(b, z):
    accum = 0
    for i in range(len(b)):
        accum += int(b[i]) * int(z[i])
    return (accum % 2)

for z in counts:
    print( '{}.{} = {} (mod 2)'.format(b, z, bdotz(b,z)) )

b = input("Enter a binary string:\n")

# Actual b = 011
b_rev = b[::-1]
flagbit = b_rev.find('1')
n=len(b)

q1=QuantumRegister(n,'q1')
q2=QuantumRegister(n,'q2')
c1=ClassicalRegister(n)
qc = QuantumCircuit(q1,q2,c1)
qc.barrier()

qc.h(q1)
qc.barrier()

for i in range(n):
    qc.cx(q1[i],q2[i])
qc.barrier()

if flagbit != -1:
#     print("test1")
    for ind, bit in enumerate(b_rev):
#         print("test2")
        if bit == "1":
#             print("test3")
            qc.cx(flagbit, q2[ind])
            
qc.barrier()

qc.h(q1)
qc.barrier()

qc.measure(q1,c1)

qc.draw("mpl")
    

aer_sim = Aer.get_backend('aer_simulator')
shots = 500
qobj = assemble(qc, shots=shots)
results = aer_sim.run(qobj).result()
counts = results.get_counts()
print(counts)
plot_histogram(counts)

# Actual b = 011
b="1"
b_rev = "1"
flagbit = b_rev.find('1')
n=len(b)

q1=QuantumRegister(n,'q1')
q2=QuantumRegister(n,'q2')
c1=ClassicalRegister(n)
qc = QuantumCircuit(q1,q2,c1)
qc.barrier()

qc.h(q1)
qc.barrier()

for i in range(n):
    qc.cx(q1[i],q2[i])
qc.barrier()

if flagbit != -1:
#     print("test1")
    for ind, bit in enumerate(b_rev):
#         print("test2")
        if bit == "1":
#             print("test3")
            qc.cx(flagbit, q2[ind])
qc.barrier()

qc.h(q1)
qc.barrier()

# qc.measure(q1,c1)

# qc.draw("mpl")

# Simulate the unitary
usim = Aer.get_backend('aer_simulator')
qc.save_unitary()
qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
# Display the results:
array_to_latex(unitary, prefix="\\text{Circuit = } ")