import numpy as np
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit import Aer, execute
from qiskit.circuit import Gate
from qiskit.visualization import plot_histogram, plot_bloch_multivector

circ = QuantumCircuit(2, 1)
circ.reset([0, 1])
circ.x(0)
circ.barrier()
circ.h([0, 1])
circ.barrier()
circ.append(Gate(name="$U_f$", num_qubits=2, params=[]), [0, 1])
circ.barrier()
circ.h(1)
circ.barrier()
circ.measure(1, 0)
circ.draw('mpl', reverse_bits=True)

# Implementation of f1(x)
f1 = QuantumCircuit(2, name='f1')
f1.id(0)
f1.draw('mpl', reverse_bits=True)

# Implementation of f2(x)
f2 = QuantumCircuit(2, name='f2')
f2.cx(1, 0)
f2.id(0)
f2.draw('mpl', reverse_bits=True)

# Implementation of f3(x)
f3 = QuantumCircuit(2, name='f3')
f3.cx(1, 0)
f3.x(0)
f3.draw('mpl', reverse_bits=True)

# Implementation of f4(x)
f4 = QuantumCircuit(2, name='f4')
f4.x(0)
f4.draw('mpl', reverse_bits=True)

circ = QuantumCircuit(2)
circ.x(0)
circ.barrier()
circ.h([0, 1])
circ.append(f4.to_instruction(), [0, 1])
circ.h(1)
circ.draw(reverse_bits=True, plot_barriers=False)

simulator = Aer.get_backend('statevector_simulator')
result = execute(circ, simulator).result()
state = result.get_statevector(circ)
plot_bloch_multivector(state)

circ = QuantumCircuit(2)
circ.x(0)
circ.barrier()
circ.h([0, 1])
circ.append(f2.to_instruction(), [0, 1])
circ.h(1)
circ.draw(reverse_bits=True, plot_barriers=False)

simulator = Aer.get_backend('statevector_simulator')
result = execute(circ, simulator).result()
state = result.get_statevector(circ)
plot_bloch_multivector(state)

circ = QuantumCircuit(2, 1)
circ.x(0)
circ.barrier()
circ.h([0, 1])
circ.append(f2.to_instruction(), [0, 1])
circ.h(1)
circ.measure(1, 0)
circ.draw(reverse_bits=True, plot_barriers=False)

simulator = Aer.get_backend('qasm_simulator')
result = execute(circ, simulator, shots=1000).result()
counts = result.get_counts(circ)
plot_histogram(counts)