# Methods to use in the  notebook
%load_ext autoreload
%autoreload 2
from IPython.display import clear_output

# Libaries to manipulate, print, plot, and save the data.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# Random generator for the problem
from random import seed,randrange, randint

# OpenQAOA libraries to design, execute the algorithm in different backends and optimisers
from openqaoa.problems.problem import NumberPartition
from openqaoa.workflows.optimizer import QAOA 
from openqaoa.devices import create_device
from openqaoa.optimizers.qaoa_optimizer import available_optimizers
from openqaoa.utilities import ground_state_hamiltonian

# To reproduce the code and make this a problem that has optimal states in the bipartition problem,
# the following seed is used
seed(9)

# Generate four random number with a range between (1,5) callend the variable in_list
in_list = [randrange(1, 5, 1) for i in range(4)]
in_list

qubo = NumberPartition(in_list).get_qubo_problem()
qubo.asdict()

# In OpenQAOA you can use different devices either local 
# or from different cloud backends such as Qiskit, Pyquil.
sim = create_device(location='local', name='vectorized')

# Init the object QAOA and certain of its properties can be modified
q = QAOA()
q.set_device(sim)
q.compile(qubo) 

# Execute the quantum algorithm
q.optimize()

print("solution bitstring: ",q.results.most_probable_states['solutions_bitstrings'])
print("ground state: ",ground_state_hamiltonian(q.cost_hamil)[1])

optimisers = available_optimizers()['scipy']+ available_optimizers()['custom_scipy_gradient']
optimisers

jac = ['finite_difference', 'param_shift','grad_spsa', 'stoch_param_shift']

hess = jac[0]