from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer, IBMQ
import qiskit_tools as qt
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

digit_A = 5.25
digit_B = 7.5

print(digit_A,'+',digit_B,'=',digit_A+digit_B)

nint = qt.get_nint([digit_A+digit_B,digit_A,digit_B])
npres = qt.get_npres([digit_A+digit_B,digit_A,digit_B])
n = nint + npres + 1

phase = True

binary_A = qt.my_binary_repr(digit_A, n, nint=nint, phase=phase)
binary_B = qt.my_binary_repr(digit_B, n, nint=nint, phase=phase)

print(binary_A,binary_B)

qregA = QuantumRegister(n, 'A')
qregB = QuantumRegister(n, 'B')
out_reg = ClassicalRegister(n, 'A+B')
circ = QuantumCircuit(qregA, qregB, out_reg)

A_gate = qt.input_bits_to_qubits(binary_A, circ, reg=qregA, wrap=True)
B_gate = qt.input_bits_to_qubits(binary_B, circ, reg=qregB, wrap=True)
circ.append(A_gate, qregA);
circ.append(B_gate, qregB);

add_gate = qt.QFTAddition(circ, qregA, qregB, wrap=True)
circ.append(add_gate, [*qregA, *qregB]);

circ.measure(qregB, out_reg);

circ.draw(output="latex")

shots=20
emulator = Aer.get_backend('qasm_simulator')
job = execute(circ, emulator, shots=shots )
hist = job.result().get_counts()

print('Target:')
print(digit_B,'+',digit_A,'=',digit_B+digit_A,'->',qt.my_binary_repr(digit_B+digit_A, n, nint=nint, phase=phase))

print('Result:')
for label in hist.keys():
    print(digit_B,'+',digit_A,'=',qt.bin_to_dec(label, nint=nint, phase=phase),'->',label,'with probability',float(hist[label])/shots)

digit_A = 5.25
digit_B = -7.5

print(digit_A,'+',digit_B,'=',digit_A+digit_B)

nint = qt.get_nint([digit_A+digit_B,digit_A,digit_B])
npres = qt.get_npres([digit_A+digit_B,digit_A,digit_B])
n = nint + npres + 1

phase = True

binary_A = qt.my_binary_repr(digit_A, n, nint=nint, phase=phase)
binary_B = qt.my_binary_repr(digit_B, n, nint=nint, phase=phase)

print(binary_A,binary_B)

qregA = QuantumRegister(n, 'A')
qregB = QuantumRegister(n, 'B')
out_reg = ClassicalRegister(n, 'A+B')
circ = QuantumCircuit(qregA, qregB, out_reg)

A_gate = qt.input_bits_to_qubits(binary_A, circ, reg=qregA, wrap=True)
B_gate = qt.input_bits_to_qubits(binary_B, circ, reg=qregB, wrap=True)
circ.append(A_gate, qregA);
circ.append(B_gate, qregB);

add_gate = qt.QFTAddition(circ, qregA, qregB, wrap=True)
circ.append(add_gate, [*qregA, *qregB]);

circ.measure(qregB, out_reg);

circ.draw(output="latex")

shots=20
emulator = Aer.get_backend('qasm_simulator')
job = execute(circ, emulator, shots=shots )
hist = job.result().get_counts()

print('Target:')
print(digit_B,'+',digit_A,'=',digit_B+digit_A,'->',qt.my_binary_repr(digit_B+digit_A, n, nint=nint, phase=phase))

print('Result:')
for label in hist.keys():
    print(digit_B,'+',digit_A,'=',qt.bin_to_dec(label, nint=nint, phase=phase),'->',label,'with probability',float(hist[label])/shots)

digit_A = 5.25
digit_B = 7.5

nint = qt.get_nint([digit_A-digit_B,digit_A,digit_B])
npres = qt.get_npres([digit_A-digit_B,digit_A,digit_B])
n = nint + npres + 1

phase = True

binary_A = qt.my_binary_repr(digit_A, n, nint=nint, phase=phase)
binary_B = qt.my_binary_repr(digit_B, n, nint=nint, phase=phase)

print(binary_A,binary_B)

qregA = QuantumRegister(n, 'A')
qregB = QuantumRegister(n, 'B')
out_reg = ClassicalRegister(n, 'A+B')
circ = QuantumCircuit(qregA, qregB, out_reg)

A_gate = qt.input_bits_to_qubits(binary_A, circ, reg=qregA, wrap=True)
B_gate = qt.input_bits_to_qubits(binary_B, circ, reg=qregB, wrap=True)
circ.append(A_gate, qregA);
circ.append(B_gate, qregB);

tc_gate = qt.TwosCompliment(circ, qregB, wrap=True)
circ.append(tc_gate, qregB);

add_gate = qt.QFTAddition(circ, qregA, qregB, wrap=True)
circ.append(add_gate, [*qregA, *qregB]);

circ.measure(qregB, out_reg);

circ.draw(output="latex")

shots=20
emulator = Aer.get_backend('qasm_simulator')
job = execute(circ, emulator, shots=shots )
hist = job.result().get_counts()

print('Target:')
print(digit_B,'-',digit_A,'=',digit_B-digit_A,'->',qt.my_binary_repr(digit_A-digit_B, n, nint=nint, phase=phase))

print('Result:')
for label in hist.keys():
    print(digit_B,'-',digit_A,'=',qt.bin_to_dec(label, nint=nint, phase=phase),'->',label,'with probability',float(hist[label])/shots)

digit_A = -5.5
digit_B = 7.25

nintA = qt.get_nint([digit_A])
npresA = qt.get_npres([digit_A])
nA = nintA + npresA + 1

nintB = qt.get_nint([digit_B,digit_A+digit_B])
npresB = qt.get_npres([digit_B,digit_A+digit_B])
nB = nintB + npresB + 1

phase = True

binary_A = qt.my_binary_repr(digit_A, nA, nint=nintA, phase=phase)
binary_B = qt.my_binary_repr(digit_B, nB, nint=nintB, phase=phase)

print(binary_A,binary_B)

qregA = QuantumRegister(nA, 'A')
qregB = QuantumRegister(nB, 'B')
out_reg = ClassicalRegister(nB, 'A+B')
circ = QuantumCircuit(qregA, qregB, out_reg)

A_gate = qt.input_bits_to_qubits(binary_A, circ, reg=qregA, wrap=True)
B_gate = qt.input_bits_to_qubits(binary_B, circ, reg=qregB, wrap=True)
circ.append(A_gate, qregA);
circ.append(B_gate, qregB);

circ = qt.QFTAddition(circ, qregA, qregB, nint1=nintA, nint2=nintB, phase=phase)

circ.measure(qregB, out_reg);

shots=20
emulator = Aer.get_backend('qasm_simulator')
job = execute(circ, emulator, shots=shots )
hist = job.result().get_counts()

print('Target:')
print(digit_B,'+',digit_A,'=',digit_B+digit_A,'->',qt.my_binary_repr(digit_A+digit_B, nB, nint=nintB, phase=phase))

print('Result:')
for label in hist.keys():
    print(digit_B,'+',digit_A,'=',qt.bin_to_dec(label, nint=nintB, phase=phase),'->',label,'with probability',float(hist[label])/shots)