# useful additional packages 
import matplotlib.pyplot as plt
import matplotlib.axes as axes
%matplotlib inline
import numpy as np
import networkx as nx

from qiskit import BasicAer
from qiskit.tools.visualization import plot_histogram
from qiskit.aqua import run_algorithm
from qiskit.aqua.input import EnergyInput
from qiskit.aqua.translators.ising import max_cut, tsp
from qiskit.aqua.algorithms import VQE, ExactEigensolver
from qiskit.aqua.components.optimizers import SPSA
from qiskit.aqua.components.variational_forms import RY
from qiskit.aqua import QuantumInstance

from qiskit.quantum_info import Pauli
from qiskit.aqua.operators import WeightedPauliOperator
from collections import OrderedDict

# setup aqua logging
import logging
from qiskit.aqua import set_qiskit_aqua_logging
# set_qiskit_aqua_logging(logging.DEBUG)  # choose INFO, DEBUG to see the log

def get_values_qubitops(values):
    num_values = len(values)
    pauli_list = []
    shift = 0
    for i in range(num_values):
        xp = np.zeros(num_values, dtype=np.bool)
        zp = np.zeros(num_values, dtype=np.bool)
        zp[i] = True
        pauli_list.append([0.5 * values[i], Pauli(zp, xp)])
        shift -= 0.5 * values[i]
    return WeightedPauliOperator(paulis=pauli_list), shift
    

values = [3, 6, -4, 8]
qubitOp, offset = get_values_qubitops(values)

algo_input = EnergyInput(qubitOp)
ee = ExactEigensolver(qubitOp, k=1)
result = ee.run()

def sample_most_likely(state_vector):
    if isinstance(state_vector, dict) or isinstance(state_vector, OrderedDict):
        # get the binary string with the largest count
        binary_string = sorted(state_vector.items(), key=lambda kv: kv[1])[-1][0]
        x = np.asarray([int(y) for y in reversed(list(binary_string))])
        return x
    else:
        n = int(np.log2(state_vector.shape[0]))
        k = np.argmax(np.abs(state_vector))
        x = np.zeros(n)
        for i in range(n):
            x[i] = k % 2
            k >>= 1
        return x

most_lightly = result['eigvecs'][0]
x = sample_most_likely(most_lightly)
x

seed = 10598

spsa = SPSA(max_trials=300)
ry = RY(qubitOp.num_qubits, depth=5, entanglement='linear')
vqe = VQE(qubitOp, ry, spsa)

backend = BasicAer.get_backend('statevector_simulator')
quantum_instance = QuantumInstance(backend, seed_simulator=seed, seed_transpiler=seed)

result_statevector = vqe.run(quantum_instance)

most_lightly = result_statevector['eigvecs'][0]
x_statevector = sample_most_likely(most_lightly)
x_statevector

# run quantum algorithm with shots
seed = 10598

spsa = SPSA(max_trials=300)
ry = RY(qubitOp.num_qubits, depth=5, entanglement='linear')
vqe = VQE(qubitOp, ry, spsa)

backend = BasicAer.get_backend('qasm_simulator')
quantum_instance = QuantumInstance(backend, shots=1024, seed_simulator=seed, seed_transpiler=seed)

result_shots = vqe.run(quantum_instance)

most_lightly_shots = result_shots['eigvecs'][0]
x_shots = sample_most_likely(most_lightly_shots)
x_shots

