import matplotlib.pyplot as plt
import numpy as np

from qiskit.utils import algorithm_globals

seed = 12345
algorithm_globals.random_seed = seed

from qiskit_machine_learning.datasets import ad_hoc_data

train_features, train_labels, test_features, test_labels, adhoc_total = ad_hoc_data(
    training_size=20,
    test_size=5,
    n=2,
    gap=0.3,
    plot_data=False, one_hot=False, include_sample_total=True
)

def plot_adhoc_dataset(train_features, train_labels, test_features, test_labels, adhoc_total):
    plt.figure(figsize=(8, 8))
    plt.ylim(0, 2 * np.pi)
    plt.xlim(0, 2 * np.pi)
    plt.imshow(np.asmatrix(adhoc_total).T, interpolation='nearest',
               origin='lower', cmap='RdBu', extent=[0, 2 * np.pi, 0, 2 * np.pi])

    plt.scatter(train_features[np.where(train_labels[:] == 0), 0], train_features[np.where(train_labels[:] == 0), 1],
                marker='s', facecolors='w', edgecolors='b', label="A train")
    plt.scatter(train_features[np.where(train_labels[:] == 1), 0], train_features[np.where(train_labels[:] == 1), 1],
                marker='o', facecolors='w', edgecolors='r', label="B train")
    plt.scatter(test_features[np.where(test_labels[:] == 0), 0], test_features[np.where(test_labels[:] == 0), 1],
                marker='s', facecolors='b', edgecolors='w', label="A test")
    plt.scatter(test_features[np.where(test_labels[:] == 1), 0], test_features[np.where(test_labels[:] == 1), 1],
                marker='o', facecolors='r', edgecolors='w', label="B test")

    plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
    plt.title("Ad hoc dataset for classification")

    plt.show()

plot_adhoc_dataset(train_features, train_labels, test_features, test_labels, adhoc_total)

print(train_features[0], train_labels[0])
print(train_features[20], train_labels[20])

from qiskit.circuit.library import EfficientSU2

circuit = EfficientSU2(num_qubits=3, reps=1, insert_barriers=True)
circuit.decompose().draw(output='mpl')

x = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2]

encode = circuit.bind_parameters(x)
encode.decompose().draw(output='mpl')

from qiskit.circuit.library import ZZFeatureMap

circuit = ZZFeatureMap(3, reps=1, insert_barriers=True)
circuit.decompose().draw(output='mpl')

x = [0.1,0.2,0.3]

encode = circuit.bind_parameters(x)
encode.decompose().draw(output='mpl')

from qiskit import Aer
from qiskit.utils import QuantumInstance

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

from qiskit.circuit.library import ZZFeatureMap
from qiskit_machine_learning.kernels import QuantumKernel

zz_feature_map = ZZFeatureMap(feature_dimension=2, reps=2)

zz_kernel = QuantumKernel(feature_map=zz_feature_map, quantum_instance=quantum_instance)

train_matrix = zz_kernel.evaluate(x_vec=train_features)
test_matrix = zz_kernel.evaluate(x_vec=test_features, y_vec=train_features)

fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(np.asmatrix(train_matrix),
              interpolation='nearest', origin='upper', cmap='Blues')
axs[0].set_title("training kernel matrix")
axs[1].imshow(np.asmatrix(test_matrix),
              interpolation='nearest', origin='upper', cmap='Reds')
axs[1].set_title("testing kernel matrix")
plt.show()

from sklearn.svm import SVC

zzpc_svc = SVC(kernel='precomputed')
zzpc_svc.fit(train_matrix, train_labels)
zzpc_score = zzpc_svc.score(test_matrix, test_labels)

print(f'Precomputed kernel classification test score: {zzpc_score}')

zzcb_svc = SVC(kernel=zz_kernel.evaluate)
zzcb_svc.fit(train_features, train_labels)
zzcb_score = zzcb_svc.score(test_features, test_labels)

print(f'Callable kernel classification test score: {zzcb_score}')

from sklearn.preprocessing import OneHotEncoder

encoder = OneHotEncoder()
train_labels_oh = encoder.fit_transform(train_labels.reshape(-1, 1)).toarray()
test_labels_oh = encoder.fit_transform(test_labels.reshape(-1, 1)).toarray()

feature_map = ZZFeatureMap(feature_dimension=2, reps=2)
feature_map.decompose().draw('mpl')

from qiskit.circuit.library import RealAmplitudes

var_form = RealAmplitudes(2, reps=2)
var_form.decompose().draw('mpl')

# Optimizer callback function for plotting purposes
def store_intermediate_result(evaluation, parameter, cost, stepsize, accept):
    evaluations.append(evaluation)
    parameters.append(parameter)
    costs.append(cost)

#initial_point = np.random.random(var_form.num_parameters)
initial_point = np.array([0.78969092, 0.50252316, 0.45244703, 
                          0.83243915, 0.79595478, 0.42169888])

from qiskit_machine_learning.algorithms.classifiers import VQC
from qiskit.algorithms.optimizers import SPSA

vqc = VQC(feature_map=feature_map,
          ansatz=var_form,
          loss='cross_entropy',
          optimizer=SPSA(callback=store_intermediate_result),
          initial_point=initial_point,
          quantum_instance=Aer.get_backend('statevector_simulator'))

parameters = []
costs = []
evaluations = []

vqc.fit(train_features, train_labels_oh)

fig = plt.figure()
plt.plot(evaluations, costs)
plt.xlabel('Steps')
plt.ylabel('Cost')
plt.show()

vqc.score(test_features, test_labels_oh)

import qiskit.tools.jupyter

%qiskit_version_table