import numpy as np
import scipy
from scipy.linalg import expm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.decomposition import PCA
import pandas as pd
from qiskit import BasicAer
from qiskit.aqua.input import ClassificationInput
from qiskit.aqua import run_algorithm, QuantumInstance, aqua_globals
from qiskit.aqua.components.optimizers import SPSA, COBYLA

def Currency(training_size, test_size, n, PLOT_DATA):
    class_labels = [r'Buy', r'Sell', r'Hold']

    training_url = "https://raw.githubusercontent.com/joshy91/PythonQiskit/master/EURUSDTrainingData.csv"
    training=pd.read_csv(training_url, sep=',',header=0)
    trainingNP = training.to_numpy()
    sample_train = trainingNP[:,:-2]
    label_train = trainingNP[:,-2]
    label_train[label_train == 'Buy'] = 0
    label_train[label_train == 'Sell'] = 1
    label_train[label_train == 'Hold'] = 2

    test_url = "https://raw.githubusercontent.com/joshy91/PythonQiskit/master/EURUSDTestData.csv"
    test=pd.read_csv(test_url, sep=',',header=0)
    testNP = test.to_numpy()
    sample_test = testNP[:,:-2]
    label_test = testNP[:,-2]
    label_test[label_test == 'Buy'] = 0
    label_test[label_test == 'Sell'] = 1
    label_test[label_test == 'Hold'] = 2
    
    # Now we standarize for gaussian around 0 with unit variance
    std_scale = StandardScaler().fit(sample_train)
    sample_train = std_scale.transform(sample_train)
    sample_test = std_scale.transform(sample_test)

    # Now reduce number of features to number of qubits
    pca = PCA(n_components=n).fit(sample_train)
    sample_train = pca.transform(sample_train)
    sample_test = pca.transform(sample_test)

    # Scale to the range (-1,+1)
    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)
    # Pick training size number of samples from each distro
    training_input = {key: (sample_train[label_train == k, :])[:training_size] for k, key in enumerate(class_labels)}
    test_input = {key: (sample_test[label_test == k, :])[:test_size] for k, key in enumerate(class_labels)}

    if PLOT_DATA:
        for k in range(0, 3):
            plt.scatter(sample_train[label_train == k, 0][:training_size],
                        sample_train[label_train == k, 1][:training_size])

        plt.title("PCA dim. reduced Currency dataset")
        plt.show()

    return sample_train, training_input, test_input, class_labels

import numpy as np
import scipy

from qiskit import BasicAer
from qiskit.aqua.input import ClassificationInput
from qiskit.aqua import run_algorithm, QuantumInstance, aqua_globals
from qiskit.aqua.components.optimizers import SPSA, COBYLA

feature_dim = 4 # dimension of each data point
training_dataset_size = 80
testing_dataset_size = 20
random_seed = 10598
np.random.seed(random_seed)

sample_Total, training_input, test_input, class_labels = Currency(
    training_size=training_dataset_size,
    test_size=testing_dataset_size,
    n=feature_dim, PLOT_DATA=False
)

classification_input = ClassificationInput(training_input, test_input)
params = {
    'problem': {'name': 'classification', 'random_seed': random_seed},
    'algorithm': {'name': 'VQC'},
    'backend': {'provider': 'qiskit.BasicAer', 'name': 'statevector_simulator'},
    'optimizer': {'name': 'COBYLA', 'maxiter':200},
    'variational_form': {'name': 'RYRZ', 'depth': 3},
    'feature_map': {'name': None},
}

params['feature_map']['name'] = 'RawFeatureVector'
result = run_algorithm(params, classification_input)
print("VQC accuracy with RawFeatureVector: ", result['testing_accuracy'])

params['feature_map']['name'] = 'SecondOrderExpansion'
result = run_algorithm(params, classification_input)
print("Test accuracy with SecondOrderExpansion: ", result['testing_accuracy'])

