#Video_classification

import math
import numpy as np
import h5py
import pandas as pd
from numpy import genfromtxt
import matplotlib.pyplot as plt
import tensorflow.compat.v1 as tf
from tensorflow.python.framework import ops
from tf_utils import  random_mini_batches, convert_to_one_hot, predict, loading_train_test, loading_source_new, loading_target1, loading_target2, loading_target3, loading_sketch, loading_clipart 
from sklearn.covariance import EmpiricalCovariance


from numpy import genfromtxt

features_CricketBowling_Train = genfromtxt('features_CricketBowling_Train.csv', delimiter=',')
features_CricketBowling_Test = genfromtxt('features_CricketBowling_Test.csv', delimiter=',')

features_CricketShot_Train = genfromtxt('features_CricketShot_Train.csv', delimiter=',')
features_CricketShot_Test = genfromtxt('features_CricketShot_Test.csv', delimiter=',')

features_FrontCrawl_Train = genfromtxt('features_FrontCrawl_Train.csv', delimiter=',')
features_FrontCrawl_Test = genfromtxt('features_FrontCrawl_Test.csv', delimiter=',')

features_TableTennisShot_Train = genfromtxt('features_TableTennisShot_Train.csv', delimiter=',')
features_TableTennisShot_Test = genfromtxt('features_TableTennisShot_Test.csv', delimiter=',')

features_BaseballPitch_Train = genfromtxt('features_BaseballPitch_Train.csv', delimiter=',')
features_BaseballPitch_Test = genfromtxt('features_BaseballPitch_Test.csv', delimiter=',')


###
len_source_binary=94+99
len_source_binary_test=37+35
Y_source_binary=np.zeros((len_source_binary,1))
Y_source_test_binary=np.zeros((len_source_binary_test,1))

Y_source_binary[:94,0]=0
Y_source_binary[94:,0]=1
Y_source_test_binary[:37,0]=0
Y_source_test_binary[37:,0]=1

X_source_binary=features_BasketballDunk_Train
X_source_binary=np.append(X_source_binary,features_Basketball_Train,axis=0)

X_source_test_binary=features_BasketballDunk_Test
X_source_test_binary=np.append(X_source_test_binary,features_Basketball_Test,axis=0)

###




len_target_binary=103+101
len_target_binary_test=36+39
Y_target_binary=np.zeros((len_target_binary,1))
Y_target_test_binary=np.zeros((len_target_binary_test,1))

Y_target_binary[:103,0]=0
Y_target_binary[103:,0]=1
Y_target_test_binary[:36,0]=0
Y_target_test_binary[36:,0]=1

X_target_binary=features_CricketBowling_Train
X_target_binary=np.append(X_target_binary,features_TableTennisShot_Train,axis=0)

X_target_test_binary=features_CricketBowling_Test
X_target_test_binary=np.append(X_target_test_binary,features_TableTennisShot_Test,axis=0)






for i in range(len(Y_source_binary)):
    #print(num1)
    if Y_source_binary[i]==num1_S:
        Y_source_binary[i]=0
    if Y_source_binary[i]==num2_S:
        Y_source_binary[i]=1

for i in range(len(Y_source_test_binary)):
    if Y_source_test_binary[i]==num1_S:
        Y_source_test_binary[i]=0
    if Y_source_test_binary[i]==num2_S:
        Y_source_test_binary[i]=1        

        
for i in range(len(Y_target_test_binary)):
    if Y_target_test_binary[i]==num1_T:
        Y_target_test_binary[i]=0
    if Y_target_test_binary[i]==num2_T:
        Y_target_test_binary[i]=1
        
for i in range(len(Y_target_binary)):
    if Y_target_binary[i]==num1_T:
        Y_target_binary[i]=0
    if Y_target_binary[i]==num2_T:
        Y_target_binary[i]=1




Y_source_binary=Y_source_binary.T
Y_source_test_binary=Y_source_test_binary.T
Y_target_binary=Y_target_binary.T
Y_target_test_binary=Y_target_test_binary.T



X_source_binary=X_source_binary.T
X_source_test_binary=X_source_test_binary.T
X_target_binary=X_target_binary.T
X_target_test_binary=X_target_test_binary.T




Y_S=np.zeros((1, Y_source_binary.shape[1]))
Y_S_test=np.zeros((1, Y_source_test_binary.shape[1]))
Y_T=np.zeros((1, Y_target_binary.shape[1]))
Y_T_test=np.zeros((1, Y_target_test_binary.shape[1]))


for i in range(Y_source_binary.shape[1]):
    Y_S[0,i]=Y_source_binary[0][i]
for i in range(Y_source_test_binary.shape[1]):
    Y_S_test[0,i]=Y_source_test_binary[0][i]
for i in range(Y_target_binary.shape[1]):
    Y_T[0,i]=Y_target_binary[0][i]
for i in range(Y_target_test_binary.shape[1]):
    Y_T_test[0,i]=Y_target_test_binary[0][i]


from random import shuffle
N=Y_S.shape[1]
ind_list = list(range(N))
shuffle(ind_list)
Y_S=Y_S[:,ind_list]
X_source_binary=X_source_binary[:,ind_list]

N=Y_S_test.shape[1]
ind_list = list(range(N))
shuffle(ind_list)
Y_S_test=Y_S_test[:,ind_list]
X_source_test_binary=X_source_test_binary[:,ind_list]

N=Y_T.shape[1]
ind_list = list(range(N))
shuffle(ind_list)
Y_T=Y_T[:,ind_list]
X_target_binary=X_target_binary[:,ind_list]


N=Y_T_test.shape[1]
ind_list = list(range(N))
shuffle(ind_list)
Y_T_test=Y_T_test[:,ind_list]
X_target_test_binary=X_target_test_binary[:,ind_list]


def create_placeholders(n_x, n_y):
    
    
    X = tf.placeholder(tf.float32, shape=[n_x, None])
    Y = tf.placeholder(tf.float32, shape=[n_y, None])
    
    
    return X, Y


def initialize_parameters_source_classification():
    
    
    tf.set_random_seed(1)                   
        
    
    W1 = tf.get_variable("W1", [15,2048], initializer = tf.glorot_uniform_initializer(seed = 1))
    b1 = tf.get_variable("b1", [15,1], initializer = tf.zeros_initializer())
    
    W2 = tf.get_variable("W2", [1,15], initializer = tf.glorot_uniform_initializer(seed = 1))
    b2 = tf.get_variable("b2", [1,1], initializer = tf.zeros_initializer())
    
    ### END CODE HERE ###

    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2,
                  }
    
    return parameters


def initialize_parameters_target_classification():
    
    
    tf.set_random_seed(1)                   
        
    
    W1 = tf.get_variable("W1", [15,2048], initializer = tf.glorot_uniform_initializer(seed = 1))
    b1 = tf.get_variable("b1", [15,1], initializer = tf.zeros_initializer())
    
    W2 = tf.get_variable("W2", [1,15], initializer = tf.glorot_uniform_initializer(seed = 1))
    b2 = tf.get_variable("b2", [1,1], initializer = tf.zeros_initializer())
    
    ### END CODE HERE ###

    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2,
                  }
    
    return parameters


def forward_propagation_classification(X, parameters):
    
    W1 = parameters['W1']
    b1 = parameters['b1']
    
    W2 = parameters['W2']
    b2 = parameters['b2']
    
   
    
                  
    Z1 = tf.add(tf.matmul(W1,X),b1)                                             
    
    A1= tf.nn.relu(Z1)
    
    Z2 =tf.add(tf.matmul(W2,A1),b2)    
                                                                                            
    
    
    return Z2

def compute_cost_classification(Z2, Y):
    
    
    logits = tf.transpose(Z2)
    labels = tf.transpose(Y)
    cost = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=labels))
    
    
    return cost



def compute_cost_weighted(Z2_source, Y_source,Z2_target,Y_target,Lam=.2):
    
   
    
    logits = tf.transpose(Z2_source)
    labels = tf.transpose(Y_source)
    cost1 = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=labels))
    inter=tf.multiply(cost1,Lam)
    
    logits1 = tf.transpose(Z2_target)
    labels1 = tf.transpose(Y_target)
    cost2 = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits1, labels=labels1))
    inter1=tf.multiply(cost2,1-Lam)
    
    cost=tf.add(inter,inter1)
    
 
    
    
    return cost




def model_weighted(X_train_source, Y_train_source,X_train_target,Y_train_target,X_test_target, Y_test_target,lam=.2, learning_rate = 0.0001,
    
    
    ops.reset_default_graph()                         # to be able to rerun the model without overwriting tf variables                            # to keep consistent results
    seed = 3                                          # to keep consistent results
    (n_x_source, m_source) = X_train_source.shape
    (n_x_target, m_target) = X_train_target.shape                          # (n_x: input size, m : number of examples in the train set)
    n_y_source = Y_train_source.shape[0] 
    n_y_target = Y_train_target.shape[0]                            # n_y : output size
    costs = []                                        # To keep track of the cost
    
    # Create Placeholders of shape (n_x, n_y)
    
    X_source, Y_source = create_placeholders(n_x_source, n_y_source)
    X_target, Y_target = create_placeholders(n_x_target, n_y_target)
    parameters=initialize_parameters_target_classification()
    
   

   
    Z2_source = forward_propagation_classification(X_source, parameters)
    Z2_target = forward_propagation_classification(X_target, parameters)
    
    
    # Cost function: Add cost function to tensorflow graph
    
    cost = compute_cost_weighted(Z2_source, Y_source,Z2_target,Y_target,lam)
    #cost1 = compute_cost1(Z2_target, Y_target)
    
    
    # Backpropagation: Define the tensorflow optimizer.
    
    optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(cost)
    
    
    # Initialize all the variables
    init = tf.global_variables_initializer()

    # Start the session to compute the tensorflow graph
    with tf.Session() as sess:
        
        # Run the initialization
        sess.run(init)
        
        # Do the training loop
        for epoch in range(num_epochs):

            epoch_cost = 0.                       # Defines a cost related to an epoch
            #num_minibatches = int(m / minibatch_size) # number of minibatches of size minibatch_size in the train set
            seed = seed + 1
            #minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)

            #for minibatch in minibatches:

                # Select a minibatch
             #   (minibatch_X, minibatch_Y) = minibatch
                
                # IMPORTANT: The line that runs the graph on a minibatch.
                # Run the session to execute the "optimizer" and the "cost", the feedict should contain a minibatch for (X,Y).
                ### START CODE HERE ### (1 line)
            _ , minibatch_cost = sess.run([optimizer, cost], feed_dict={X_source: X_train_source, Y_source: Y_train_source, X_target: X_train_target, Y_target: Y_train_target})
                ### END CODE HERE ###
                
            epoch_cost += minibatch_cost 
            
            
        parameters = sess.run(parameters)
        
        
        return parameters

def sigmoid(X):
   return 1/(1+np.exp(-X))

def relu(x):
    return np.maximum(0, x)



M=np.zeros((5,150))
lam_index=np.zeros((5,150))
NN=np.zeros((6,2))

for f in range(5):
    for k in range(1,150):
        ind_list = list(range(204))
        shuffle(ind_list)
        X1=X_target_binary[:,ind_list[:k]]
        Y1=Y_T[:,ind_list[:k]]
        NN=np.zeros((6,2));
        for tt in range(0,12,2):
            lam=tt/10.0
            jj=int(tt/2)
            parameters_target_iterate = model_weighted(X_source_binary[:,:193], Y_S[:,:193],X1,Y1,X_target_test_binary[:,:2],Y_target_test_binary[:,:2],lam,source=True, target=False)
            

            test_acc=0
            N1=Y_T_test.shape[1]*1.0
            for i in range(Y_T_test.shape[1]):
                a=np.dot(parameters_target_iterate['W1'],X_target_test_binary[:,i])
                mid_size=parameters_target_iterate['W1'].shape[0]
                a=a.reshape((mid_size, 1))
                a=a+parameters_target_iterate['b1']
                #print(a.shape)
                a=relu(a)
                a=np.dot(parameters_target_iterate['W2'],a)+parameters_target_iterate['b2']
                a=sigmoid(a)
                if a>.5 and Y_T_test[:,i]==1:
                    test_acc=test_acc+1
                if a<.5 and Y_T_test[:,i]==0:
                    test_acc=test_acc+1
            test_acc=test_acc/N1
            NN[jj,0]=test_acc
            NN[jj,1]=lam
        index=np.argmax(NN[:,0])
        lam_index[f,k]=NN[index,1]
        M[f,k]=NN[index,0]
        print(k)
        print(f)
        print(lam_index[f,k])
        print(M[f,k])
    print(np.min(M[f,:]))


from numpy import savetxt
savetxt('upper-bound-video-weighted-source3.csv', M, delimiter=',')
savetxt('lambda-weighted-source3-video-.csv', lam_index, delimiter=',')

                   



