from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, transpile
from qiskit.providers.aer import AerProvider
from qiskit.tools.visualization import plot_histogram
import random
import numpy as np

def ghz(n):
    # 객체의 선언
    qr_ghz = QuantumRegister(n)
    cr_ghz = ClassicalRegister(n)
    qc_ghz = QuantumCircuit(qr_ghz, cr_ghz)

    # 회로 구성
    qc_ghz.h(qr_ghz[0])
    for i in range(1, n):
        qc_ghz.cx(0, i)

    qc_ghz.barrier()
    qc_ghz.measure(qr_ghz, cr_ghz)

    return qc_ghz

# 5-ghz 회로 출력
qc = ghz(5)
qc.draw('mpl');

# qasm 시뮬레이션
qasm_simulator = AerProvider().get_backend("qasm_simulator")
job_qasm = execute(qc, backend=qasm_simulator, shots=1024)
counts = job_qasm.result().get_counts()

# 시각화
plot_histogram(counts);

bell_qr = QuantumRegister(2, 'bell')
message_qr = QuantumRegister(1, 'message')
cr1 = ClassicalRegister(1)
cr2 = ClassicalRegister(1)
qtel_qc = QuantumCircuit(message_qr, bell_qr, cr1, cr2)

a1, a2, a3 = ( random.random() * np.pi for _ in range(3) )

# complete the circuit
qtel_qc.h(bell_qr[0])
qtel_qc.cx(bell_qr[0], bell_qr[1])
qtel_qc.barrier()

qtel_qc.u3(a1, a2, a3, message_qr)

qtel_qc.cx(message_qr, bell_qr[0])
qtel_qc.h(message_qr)
qtel_qc.barrier()

qtel_qc.measure(message_qr, cr1)
qtel_qc.measure(bell_qr[0], cr2)
qtel_qc.barrier()

qtel_qc.x(bell_qr[1]).c_if(cr2, 1)
qtel_qc.z(bell_qr[1]).c_if(cr1, 1)

qtel_qc.draw('mpl');

sv_simulator = AerProvider().get_backend('statevector_simulator')
job_sv = sv_simulator.run(qtel_qc)
sv = job_sv.result().get_statevector()
print(sv)
print([sum(sv[:4]), sum(sv[4:])])

verif_ckt = QuantumCircuit(1)
verif_ckt.u3(a1, a2, a3, 0)
sv_verif = sv_simulator.run(verif_ckt).result().get_statevector()
print(sv_verif)

from qiskit.circuit.library.basis_change.qft import QFT

qft_ckt = QFT(5)
qft_ckt.draw("mpl");

qft_ckt_tr = transpile(qft_ckt, basis_gates=['u1', 'u2', 'cx'])
qft_ckt_tr.draw('mpl');

coupling_map = list()
for i in range(5 - 1):
    coupling_map.append([i, i+1])
    coupling_map.append([i+1, i])
qft_ckt_tr_lin = transpile(qft_ckt, basis_gates=['u1', 'u2', 'cx'],
                           coupling_map=coupling_map)
print(coupling_map)
qft_ckt_tr_lin.draw('mpl');