import numpy as np

# for plotting results
import matplotlib.pyplot as plt

# Import Scikit-learn(QML library for Python)
from sklearn import datasets
from sklearn.model_selection import train_test_split # for splitting test data
from sklearn.svm import SVC # SVM Classification
from sklearn.decomposition import PCA # Principal component analysis
from sklearn.preprocessing import StandardScaler, MinMaxScaler # for standardization, normalization scale conversion

# Import Qiskit
from qiskit import Aer, execute
from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector
from qiskit.circuit.library import PauliFeatureMap, ZFeatureMap, ZZFeatureMap
from qiskit_machine_learning.kernels import QuantumKernel

# Reads two classes of data (0 and 1) from a numeric data set
digits = datasets.load_digits(n_class=2)   

# Plot the first 100 images loaded
fig, axes = plt.subplots(10, 10, figsize=(15, 15), subplot_kw={'xticks':[], 'yticks':[]}, gridspec_kw=dict(hspace=0.5, wspace=0.5))
for i, ax in enumerate(axes.flat):
    ax.set_axis_off()
    ax.imshow(digits.images[i], cmap=plt.cm.gray_r, interpolation='nearest')
    ax.set_title(digits.target[i])

print(digits.images[0])

# Splitting the dataset
sample_train, sample_test, labels_train, labels_test = train_test_split(
     digits.data, digits.target, test_size=0.2, random_state=22)

# Delete dimension
n_dim = 4
pca = PCA(n_components=n_dim).fit(sample_train)
sample_train = pca.transform(sample_train)
sample_test = pca.transform(sample_test)

# Standardize
std_scale = StandardScaler().fit(sample_train)
sample_train = std_scale.transform(sample_train)
sample_test = std_scale.transform(sample_test)

# Normalize
samples = np.append(sample_train, sample_test, axis=0)
minmax_scale = MinMaxScaler((-1, 1)).fit(samples)
sample_train = minmax_scale.transform(sample_train)
sample_test = minmax_scale.transform(sample_test)

# Select 100 for training and 20 for testing
train_size = 100
sample_train = sample_train[:train_size]
labels_train = labels_train[:train_size]

test_size = 20
sample_test = sample_test[:test_size]
labels_test = labels_test[:test_size]

# Display each of the first data
print(sample_train[0], labels_train[0])
print(sample_test[0], labels_test[0])

# ZZFeatureMap with 4 features and depth (number of iterations)1
zz_map = ZZFeatureMap(feature_dimension=4, reps=1, entanglement='linear', insert_barriers=True)
zz_map.decompose().draw('mpl')

zz_kernel = QuantumKernel(feature_map=zz_map, quantum_instance=Aer.get_backend('statevector_simulator'))

print(sample_train[0])
print(sample_train[1])

zz_circuit = zz_kernel.construct_circuit(sample_train[0], sample_train[1])
zz_circuit.decompose().decompose().draw(output='mpl')

backend = Aer.get_backend('qasm_simulator')
job = execute(zz_circuit, backend, shots=8192, 
              seed_simulator=1024, seed_transpiler=1024)
counts = job.result().get_counts(zz_circuit)

counts['0000']/sum(counts.values())

matrix_train = zz_kernel.evaluate(x_vec=sample_train)
matrix_test = zz_kernel.evaluate(x_vec=sample_test, y_vec=sample_train)

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

zzpc_svc = SVC(kernel='precomputed')
zzpc_svc.fit(matrix_train, labels_train)    # Train
zzpc_score = zzpc_svc.score(matrix_test, labels_test)    # Determine the percentage of correct answers

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


# General imports
import os
import gzip
import numpy as np
import matplotlib.pyplot as plt
from pylab import cm
import warnings

warnings.filterwarnings("ignore")

# Import Scikit-learn(QML library for Python)
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.decomposition import PCA
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score

# Import Qiskit
from qiskit import Aer, execute
from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector
from qiskit.circuit.library import PauliFeatureMap, ZFeatureMap, ZZFeatureMap
from qiskit.circuit.library import TwoLocal, NLocal, RealAmplitudes, EfficientSU2
from qiskit.circuit.library import HGate, RXGate, RYGate, RZGate, CXGate, CRXGate, CRZGate
from qiskit_machine_learning.kernels import QuantumKernel

# Load data
DATA_PATH = 'fashion.npz'
data = np.load(DATA_PATH)

sample_train = data['sample_train']
labels_train = data['labels_train']
sample_test = data['sample_test']

# Splitting the dataset
sample_train, sample_test, labels_train, labels_test = train_test_split(
    sample_train, labels_train, test_size=0.2, random_state=42)

# Show data
fig = plt.figure()
LABELS = [2,3]
num_labels = len(LABELS)
for i in range(num_labels):
    ax = fig.add_subplot(2, num_labels, i+1)
    img = sample_train[labels_train==LABELS[i]][0].reshape((28, 28))
    ax.imshow(img, cmap="Greys")

# change the dimension
N_DIM = 4
pca = PCA(n_components=N_DIM).fit(sample_train)
sample_train = pca.transform(sample_train)
sample_test = pca.transform(sample_test)

# standardize
std_scale = StandardScaler().fit(sample_train)
sample_train = std_scale.transform(sample_train)
sample_test = std_scale.transform(sample_test)

# normalize
samples = np.append(sample_train, sample_test, axis=0)
minmax_scale = MinMaxScaler((-1, 1)).fit(samples)
sample_train = minmax_scale.transform(sample_train)
sample_test = minmax_scale.transform(sample_test)

# Display each of the first data
print(sample_train[0], labels_train[0])
print(sample_test[0], labels_test[0])

zz_map = # Write your featuremap here
zz_map.decompose().draw('mpl')

zz_kernel = # Construct your kernel here

print(sample_train[0])
print(sample_train[1])

zz_circuit = zz_kernel.construct_circuit(sample_train[0], sample_train[1])
zz_circuit.decompose().decompose().draw(output='mpl') 

backend = Aer.get_backend('qasm_simulator')
job = execute(zz_circuit, backend, shots=8192, 
              seed_simulator=1024, seed_transpiler=1024)
counts = job.result().get_counts(zz_circuit)

counts['0000']/sum(counts.values())

matrix_train = # Write your code here
matrix_test = # Write your code here

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

zzpc_svc = # Write your code here
zzpc_svc.fit(matrix_train, labels_train)    # Train
zzpc_score = zzpc_svc.score(matrix_test, labels_test)    # Determine the percentage of correct answers

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