from qiskit import QuantumCircuit

import quantum_utils_v1 as q

# ============================================================================
# TOFFOLI (CCX) GEJT — KVANTNO "I" (AND)
# ============================================================================
# Toffoli gejt (ccx) ima dva kontrolna kubita i jedan ciljni:
#   - ciljni kubit se invertuje (X) SAMO ako su OBA kontrolna kubita |1⟩;
#   - u svim ostalim slučajevima ciljni kubit ostaje nepromenjen.
#
# Ako je ciljni kubit na početku |0⟩, posle Toffolija on sadrži (kontrola1 AND
# kontrola2). Zato je Toffoli reverzibilna verzija klasičnog logičkog "I" kola
# i dovoljan je za izgradnju bilo kog klasičnog logičkog kola na kvantnom računaru.
#
# VAŽNO o redosledu bitova: Qiskit koristi "little-endian" zapis |q2 q1 q0⟩,
# gde je q0 krajnje desno. Zato kada postavimo q0=1 i q1=1 (a q2=0), funkcija
# print_state će stanje ispisati kao |011⟩, iako mi neformalno kažemo "|110⟩"
# čitajući kubite redom q0,q1,q2. To je ista stvar, samo različit smer čitanja.
# ============================================================================

# q0 i q1 su kontrolni kubiti, q2 je ciljni kubit. Treći klasični bit služi za merenje.
qc = QuantumCircuit(3, 1)

qc.barrier()
q.show_bloch_sphere(qc)
q.print_state(qc, "Početno stanje:", True)

# ============================================================================
# PRIPREMA: oba kontrolna kubita u |1⟩, ciljni ostaje |0⟩
# ============================================================================
qc.x(0)
qc.x(1)

qc.barrier()
print("\nPriprema stanja |110>")
q.show_bloch_sphere(qc)
q.print_state(qc, "Stanje:", True)

# ============================================================================
# PRIMENA TOFFOLI GEJTA
# ccx(control1, control2, target)
# ============================================================================
qc.ccx(0, 1, 2)

qc.barrier()
print("\nPosle primene Toffoli gejta")

q.show_bloch_sphere(qc)
q.print_state(qc, "Stanje:", True)
q.print_probabilities(qc, "Verovatnoće:")

# ============================================================================
# MERENJE CILJNOG KUBITA
# ============================================================================
qc.measure(2, 0)

q.show_qc(qc)
q.show_measurement(qc)