from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, transpile, Aer, execute
from qiskit.visualization import plot_bloch_multivector
from qiskit_ibm_provider import IBMProvider
from qiskit.providers.ibmq import least_busy

# Configurați token-ul IBM Quantum Experience
provider = IBMProvider('214b328990079017b35a5f3bab61f47aceb66ddd8a84fd01aa230faf616c8d48e94da0255e827a4b08a0a1b7eebc845e888adcec742eb7541461dce0697d5067')

# Crearea registrului cuantic și a celui clasic
qreg = QuantumRegister(2)
creg = ClassicalRegister(2)

# Crearea circuitului cuantic
circuit = QuantumCircuit(qreg, creg)

# Inițializarea într-o stare de suprapunere și înlănțuire
circuit.h(qreg[0])  # Poarta Hadamard pe primul qubit
circuit.cx(qreg[0], qreg[1])  # Înlănțuirea qubiților

# Simularea situației fără măsurare (interferență)
simulator = Aer.get_backend('statevector_simulator')
job = execute(circuit, simulator)
result = job.result()
statevector = result.get_statevector()
print("Stare fără măsurare (interferență):")
plot_bloch_multivector(statevector)

# Măsurarea celui de-al doilea qubit (comportament de particulă)
circuit.measure(qreg[0], creg[0])  # Măsurarea primului qubit

# Introducerea întârzierii pentru citirea celui de-al doilea qubit
# Metoda 1: Porți identitate
circuit.id(qreg[1])  # Porți identitate pentru a introduce întârziere

# Metoda 2: Porți Hadamard și inversă
circuit.h(qreg[1])
circuit.h(qreg[1])

# Metoda 3: Porți X și inversă
circuit.x(qreg[1])
circuit.x(qreg[1])

# Măsurarea celui de-al doilea qubit (întârziată)
circuit.measure(qreg[1], creg[1])

# Alegerea celui mai disponibil backend
backend = least_busy(provider.backends(filters=lambda x: x.configuration().n_qubits >= 2 and not x.configuration().simulator and x.status().operational==True))
print(f"\nVom rula pe: {backend}")

# Transpilarea circuitului pentru backend-ul selectat
transpiled_circuit = transpile(circuit, backend)

# Rularea circuitului
job = backend.run(transpiled_circuit, shots=1000)

# Obținerea și afișarea rezultatelor
result = job.result()
counts = result.get_counts(circuit)
print("\nStare cu măsurare (comportament de particulă):")
print(counts)
