import qiskit
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram

import numpy as np

from qiskit import execute, Aer

simulator = Aer.get_backend('qasm_simulator')

import matplotlib.pyplot as plt

import warnings
warnings.filterwarnings('ignore')

from qiskit.quantum_info import DensityMatrix, Statevector, Operator

def getDensityMatrix(circuit):
    return DensityMatrix(circuit).data

from functools import reduce

Dag = lambda matrix: matrix.conj().T
Kron = lambda *matrices: reduce(np.kron, matrices)

def pm(matrix):
    for row in range(len(matrix)):
        for col in range (len(matrix[row])):
            print("{:.3f}".format(matrix[row][col]), end = " ")
        print()

def initCircuit(n):
    circuit = QuantumCircuit(n, n)
    
    for i in range(n):
        circuit.h(i)    
    circuit.barrier()
    
    return circuit

inputCircuit_2q = initCircuit(2)
inputCircuit_2q.draw(output='mpl')

def createEvenOracle():
    circuit = QuantumCircuit(2, 2)
    
    circuit.x(0)
    circuit.x(1)
    circuit.cz(0, 1)
    circuit.x(1)
    circuit.cz(0, 1)
    circuit.x(0)
    circuit.barrier()
    
    return circuit

evenOracle = createEvenOracle()
evenOracle.draw(output='mpl')

Operator(evenOracle).data # find 0 and 2

def createR_2q():
    circuit = QuantumCircuit(2, 2)
    
    circuit.z(0)
    circuit.z(1)
    circuit.cz(0, 1)
    
    return circuit

def createDiffuser_2q():
    circuit = QuantumCircuit(2, 2)
    
    circuit.h(0)
    circuit.h(1)
    circuit = circuit.compose(createR_2q())
    circuit.h(0)
    circuit.h(1)
    circuit.barrier()
    
    return circuit

diffuserCircuit_2q = createDiffuser_2q()
diffuserCircuit_2q.draw(output='mpl')

grover_even = initCircuit(2).compose(createEvenOracle()).compose(createDiffuser_2q())
grover_even.draw(output='mpl')

grover_even.measure([0, 1], [0, 1])

job = execute(grover_even, simulator, shots = 10000)
results = job.result()
counts = results.get_counts(grover_even)
print(counts)

plot_histogram(counts, figsize=(5, 5), color="#66CCCC", title="origin grover - find evens")

