# import packages

import streamlit as st
import pandas as pd
import numpy as np # this package is for data calculation
import matplotlib.pyplot as plt # for data visualization
from sklearn.preprocessing import MinMaxScaler
import tensorflow as tf
import torch
from torch import nn

#=======================================================================================================================

# Side Panel
df = pd.read_csv('./function11_1.csv')
df2 = pd.read_csv('./function11_1.csv',parse_dates=['Start_Date'],index_col='Start_Date')
df3 = pd.read_csv('./function11_2.csv',parse_dates = ['Start_Date'] )

df4 = pd.read_csv('./function11_1.csv')
df4 = df4.drop(labels=['carpark','home','other','street','work','start_temperature','id'],axis='columns')
df4.set_index('Start_Date' , inplace=True)
print(df4)

reload_model_bilstm = tf.keras.models.load_model('./keras_model_bilstm_3.h5')
reload_model_bilstm.summary()

reload_model_gru= tf.keras.models.load_model('./keras_model_gru_3.h5')
reload_model_gru.summary()
#====================================================================================================================

st.sidebar.header("Predict Part")
selected_status_6 = st.sidebar.selectbox('Select model', options = ["GRU", "Bi-LSTM", "LSTM", "CNN-LSTM","XGBoost","MLP","Transformer"])
selected_status_7 = st.sidebar.slider('Predict days', min_value=7, max_value=28, step=7)

st.sidebar.write('Evaluation model')
selected_status_8_1 = st.sidebar.checkbox('RMSE')
selected_status_8_2 = st.sidebar.checkbox('MSE')
selected_status_8_3 = st.sidebar.checkbox('MAE')

# ===================================================================================================================
if selected_status_6 == 'GRU':

    tf.random.set_seed(1234)

    # Check for missing values
    print('Total num of missing values:')
    print(df3.Total_kWh.isna().sum())
    print(' ')
    # Locate the missing value
    df_missing_date = df3.loc[df3.Total_kWh.isna() == True]
    print('The date of missing value:')
    print(df_missing_date.loc[:,['Start_Date']])
    # Replcase missing value with interpolation
    df3.Total_kWh.interpolate(inplace = True)
    # Keep WC and drop Date
    df3 = df3.drop('Start_Date', axis = 1)

    # Split train data and test data
    train_size = int(len(df3)*0.8)

    train_data = df3.iloc[:train_size]
    test_data = df3.iloc[train_size:]

    scaler = MinMaxScaler().fit(train_data)
    train_scaled = scaler.transform(train_data)
    test_scaled = scaler.transform(test_data)

    print(train_data.shape)

    # Create input dataset
    def create_dataset (X, look_back = 1):
        Xs, ys = [], []

        for i in range(len(X)-look_back):
            v = X[i:i+look_back]
            Xs.append(v)
            ys.append(X[i+look_back])

        return np.array(Xs), np.array(ys)
    LOOK_BACK = 7
    X_train, y_train = create_dataset(train_scaled,LOOK_BACK)
    X_test, y_test = create_dataset(test_scaled,LOOK_BACK)
    # Print data shape
    print('X_train.shape: ', X_train.shape)
    print('y_train.shape: ', y_train.shape)
    print('X_test.shape: ', X_test.shape)
    print('y_test.shape: ', y_test.shape)

    print(X_test[:33].shape)

    y_test = scaler.inverse_transform(y_test)
    y_train = scaler.inverse_transform(y_train)

    # Plot test data vs prediction
    if selected_status_7 == 7:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:24]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)
    elif selected_status_7 == 14:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:31]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)
    elif selected_status_7 == 21:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:38]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)
    elif selected_status_7 == 28:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:45]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)

#==========================================================================================
    st.subheader("Predict Part")

    # Make prediction for new data
    def prediction(model):
        prediction = model.predict(X_30)
        prediction = scaler.inverse_transform(prediction)
        return prediction
    prediction_gru = prediction(reload_model_gru)

    # Plot history and future
    def plot_multi_step(history, prediction1):

        fig4 = plt.figure(figsize=(15, 6))

        range_history = len(history)
        range_future = list(range(range_history, range_history + len(prediction1)))

        plt.plot(np.arange(range_history), np.array(history), label='History')
        plt.plot(range_future, np.array(prediction1),label='Forecasted with GRU')

        plt.legend(loc='upper right')
        plt.xlabel('Time step')
        plt.ylabel('Tital_kwh')
        st.pyplot(fig4)
    plot_multi_step(new_data, prediction_gru)
    if selected_status_7 == 7:
        st.write('Predicted value of charging energy consumption in the next 7 days')
    elif selected_status_7 == 14:
        st.write('Predicted value of charging energy consumption in the next 14 days')
    elif selected_status_7 == 21:
        st.write('Predicted value of charging energy consumption in the next 21 days')
    else:
        st.write('Predicted value of charging energy consumption in the next 28 days')

    st.write(prediction_gru)

    # Make prediction
    def prediction(model):
        prediction = model.predict(X_test)
        prediction = scaler.inverse_transform(prediction)
        return prediction
    prediction_gru = prediction(reload_model_gru)

    # def plot_future(prediction, model_name, y_test):
    #     st.subheader(model_name + ' model accuracy')
    #     fig3 =  plt.figure(figsize=(10, 6))
    #     range_future = len(prediction)
    #     plt.plot(np.arange(range_future), np.array(y_test),
    #             label='Actual value')
    #     plt.plot(np.arange(range_future),
    #             np.array(prediction),label='Predict value')
    #     plt.title('Actual value vs predict value for ' + model_name)
    #     plt.legend(loc='upper left')
    #     plt.xlabel('Time (day)')
    #     plt.ylabel('Total_kwh')
    #     st.pyplot(fig3)
    # plot_future(prediction_gru, 'GRU', y_test)

    def evaluate_prediction(predictions, actual, model_name):
        errors = predictions - actual
        mse = np.square(errors).mean()
        rmse = np.sqrt(mse)
        mae = np.abs(errors).mean()
        st.write(model_name +' Evaluation Metrics(Please choose selected box)'+ ':')
        if selected_status_8_1:
            st.write('RMSE: {:.4f}'.format(rmse))
        if selected_status_8_2:
            st.write('MSE: {:.4f}'.format(mse))
        if selected_status_8_3:
            st.write('MAE: {:.4f}'.format(mae))
        st.write('')
    evaluate_prediction(prediction_gru, y_test,'GRU')

elif selected_status_6 == 'Bi-LSTM':
    tf.random.set_seed(1234)

    # Check for missing values
    print('Total num of missing values:')
    print(df3.Total_kWh.isna().sum())
    print(' ')
    # Locate the missing value
    df_missing_date = df3.loc[df3.Total_kWh.isna() == True]
    print('The date of missing value:')
    print(df_missing_date.loc[:,['Start_Date']])
    # Replcase missing value with interpolation
    df3.Total_kWh.interpolate(inplace = True)
    # Keep WC and drop Date
    df3 = df3.drop('Start_Date', axis = 1)

    # Split train data and test data
    train_size = int(len(df3)*0.8)

    train_data = df3.iloc[:train_size]
    test_data = df3.iloc[train_size:]

    scaler = MinMaxScaler().fit(train_data)
    train_scaled = scaler.transform(train_data)
    test_scaled = scaler.transform(test_data)

    print(train_data.shape)

    # Create input dataset
    def create_dataset (X, look_back = 1):
        Xs, ys = [], []

        for i in range(len(X)-look_back):
            v = X[i:i+look_back]
            Xs.append(v)
            ys.append(X[i+look_back])

        return np.array(Xs), np.array(ys)
    LOOK_BACK = 7
    X_train, y_train = create_dataset(train_scaled,LOOK_BACK)
    X_test, y_test = create_dataset(test_scaled,LOOK_BACK)
    # Print data shape
    print('X_train.shape: ', X_train.shape)
    print('y_train.shape: ', y_train.shape)
    print('X_test.shape: ', X_test.shape)
    print('y_test.shape: ', y_test.shape)

    print(X_test[:33].shape)

    y_test = scaler.inverse_transform(y_test)
    y_train = scaler.inverse_transform(y_train)

        # Plot test data vs prediction
    if selected_status_7 == 7:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:24]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)
    elif selected_status_7 == 14:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:31]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)
    elif selected_status_7 == 21:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:38]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)
    elif selected_status_7 == 28:
        # Select 60 days of data from test data
        new_data = test_data.iloc[10:45]
        # Scale the input
        scaled_data = scaler.transform(new_data)
        # Reshape the input
        def create_dataset (X, look_back = 7):
            Xs = []
            for i in range(len(X)-look_back):
                v = X[i:i+look_back]
                Xs.append(v)

            return np.array(Xs)

        X_30= create_dataset(scaled_data,7)
        print('X_30.shape: ', X_30.shape)

    st.subheader("Predict Part")

    # Make prediction for new data
    def prediction(model):
        prediction = model.predict(X_30)
        prediction = scaler.inverse_transform(prediction)
        return prediction
    prediction_bilstm = prediction(reload_model_bilstm)

    # Plot history and future
    def plot_multi_step(history, prediction1):
        fig4 = plt.figure(figsize=(15, 6))
        range_history = len(history)
        range_future = list(range(range_history, range_history + len(prediction1)))
        plt.plot(np.arange(range_history), np.array(history), label='History')
        plt.plot(range_future, np.array(prediction1),label='Forecasted with BiLSTM')
        plt.legend(loc='upper right')
        plt.xlabel('Time step')
        plt.ylabel('Tital_kwh')
        st.pyplot(fig4)
    plot_multi_step(new_data, prediction_bilstm)
    if selected_status_7 == 7:
        st.write('Predicted value of charging energy consumption in the next 7 days')
    elif selected_status_7 == 14:
        st.write('Predicted value of charging energy consumption in the next 14 days')
    elif selected_status_7 == 21:
        st.write('Predicted value of charging energy consumption in the next 21 days')
    else:
        st.write('Predicted value of charging energy consumption in the next 28 days')

    st.write(prediction_bilstm)

    # Make prediction
    def prediction(model):
        prediction = model.predict(X_test)
        prediction = scaler.inverse_transform(prediction)
        return prediction
    prediction_bilstm = prediction(reload_model_bilstm)

    # # Plot test data vs prediction
    # def plot_future(prediction, model_name, y_test):
    #     fig3 =  plt.figure(figsize=(10, 6))
    #     range_future = len(prediction)
    #     plt.plot(np.arange(range_future), np.array(y_test),
    #             label='Actual value')
    #     plt.plot(np.arange(range_future),
    #             np.array(prediction),label='Predict value')
    #     plt.title('Actual value vs predict value for ' + model_name)
    #     plt.legend(loc='upper left')
    #     plt.xlabel('Time (day)')
    #     plt.ylabel('Total_kwh')
    #     st.pyplot(fig3)
    # plot_future(prediction_bilstm, 'Bidirectional LSTM', y_test)

#===============================================================================================
    def evaluate_prediction(predictions, actual, model_name):
        errors = predictions - actual
        mse = np.square(errors).mean()
        rmse = np.sqrt(mse)
        mae = np.abs(errors).mean()
        st.write(model_name +' Evaluation Metrics(Please choose selected box)'+ ':')
        if selected_status_8_1:
            st.write('RMSE: {:.4f}'.format(rmse))
        if selected_status_8_2:
            st.write('MSE: {:.4f}'.format(mse))
        if selected_status_8_3:
            st.write('MAE: {:.4f}'.format(mae))
        st.write('')

    evaluate_prediction(prediction_bilstm, y_test, 'Bidirectiona LSTM')

    # model_gru.save('./keras_model_gru_3.h5')
    # model_bilstm.save('./keras_model_bilstm_3.h5')
# ===========================================================================================================================
elif selected_status_6 == 'CNN-LSTM':
    st.subheader("Predict Part")
    def create_sequences(data, seq_length):
        xs = []
        ys = []
        for i in range(len(df4)-seq_length):
            x = data.iloc[i:(i+seq_length)]
            y = data.iloc[i+seq_length]
            xs.append(x)
            ys.append(y)
        return np.array(xs), np.array(ys)

    # Data transformation for supervised learning data.
    seq_length = 7
    X, y = create_sequences(df4, seq_length)

    # Dividing the dataset into traning, validation, and test sets.
    train_size = int(363 * 0.8)
    X_train, y_train = X[:train_size], y[:train_size]
    X_val, y_val = X[train_size:train_size+33], y[train_size:train_size+33]

    if selected_status_7 == 7:
        X_test, y_test = X[train_size+59:], y[train_size+59:]
    elif selected_status_7 == 14:
        X_test, y_test = X[train_size+52:], y[train_size+52:]
    elif selected_status_7 == 21:
        X_test, y_test = X[train_size+45:], y[train_size+45:]
    elif selected_status_7 == 28:
        X_test, y_test = X[train_size+38:], y[train_size+38:]

    # print(X_test)
    # print(train_size)

    MIN = X_train.min()
    MAX = X_train.max()

    def MinMaxScale(array, min, max):

        return (array - min) / (max - min)

    # MinMax scaling
    X_train = MinMaxScale(X_train, MIN, MAX)
    y_train = MinMaxScale(y_train, MIN, MAX)
    X_val = MinMaxScale(X_val, MIN, MAX)
    y_val = MinMaxScale(y_val, MIN, MAX)
    X_test = MinMaxScale(X_test, MIN, MAX)
    y_test = MinMaxScale(y_test, MIN, MAX)

    # Tensor transformation
    def make_Tensor(array):
        return torch.from_numpy(array).float()

    X_train = make_Tensor(X_train)
    y_train = make_Tensor(y_train)
    X_val = make_Tensor(X_val)
    y_val = make_Tensor(y_val)
    X_test = make_Tensor(X_test)
    y_test = make_Tensor(y_test)

    c = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=2, stride=1)
    input = torch.Tensor([[[1,2,3,4,5,6,7]]])
    output = c(input)
    # print(output)

    for param in c.parameters():
        print(param)

    w_list = []
    for param in c.parameters():
        w_list.append(param)

    w = w_list[0]
    b = w_list[1]

    w1 = w[0][0][0]
    w2 = w[0][0][1]

    print(w1)
    print(w2)
    print(b)

    w1 * 3 + w2 * 4 + b

    # print(output)

    class CovidPredictor(nn.Module):
        def __init__(self, n_features, n_hidden, seq_len, n_layers):
            super(CovidPredictor, self).__init__()
            self.n_hidden = n_hidden
            self.seq_len = seq_len
            self.n_layers = n_layers
            self.c1 = nn.Conv1d(in_channels=1, out_channels=1, kernel_size = 2, stride = 1) # Add a 1D CNN layer
            self.lstm = nn.LSTM(
                input_size=n_features,
                hidden_size=n_hidden,
                num_layers=n_layers
            )
            self.linear = nn.Linear(in_features=n_hidden, out_features=1)
        def reset_hidden_state(self):
            self.hidden = (
                torch.zeros(self.n_layers, self.seq_len-1, self.n_hidden),
                torch.zeros(self.n_layers, self.seq_len-1, self.n_hidden)
            )
        def forward(self, sequences):
            sequences = self.c1(sequences.view(len(sequences), 1, -1))
            lstm_out, self.hidden = self.lstm(
                sequences.view(len(sequences), self.seq_len-1, -1),
                self.hidden
            )
            last_time_step = lstm_out.view(self.seq_len-1, len(sequences), self.n_hidden)[-1]
            y_pred = self.linear(last_time_step)
            return y_pred

    def train_model(model, train_data, train_labels, val_data=None, val_labels=None, num_epochs=100, verbose = 10, patience = 10):
        loss_fn = torch.nn.L1Loss() #
        optimiser = torch.optim.Adam(model.parameters(), lr=0.001)
        train_hist = []
        val_hist = []
        for t in range(num_epochs):

            epoch_loss = 0

            for idx, seq in enumerate(train_data): # hidden state needs to be reset after every sample

                model.reset_hidden_state()

                # train loss
                seq = torch.unsqueeze(seq, 0)
                y_pred = model(seq)
                loss = loss_fn(y_pred[0].float(), train_labels[idx]) # calculated loss after 1 step

                # update weights
                optimiser.zero_grad()
                loss.backward()
                optimiser.step()

                epoch_loss += loss.item()

            train_hist.append(epoch_loss / len(train_data))

            if val_data is not None:

                with torch.no_grad():

                    val_loss = 0

                    for val_idx, val_seq in enumerate(val_data):

                        model.reset_hidden_state() # hidden state reset every sequence

                        val_seq = torch.unsqueeze(val_seq, 0)
                        y_val_pred = model(val_seq)
                        val_step_loss = loss_fn(y_val_pred[0].float(), val_labels[val_idx])

                        val_loss += val_step_loss

                val_hist.append(val_loss / len(val_data)) # append in val hist

                ## print loss for every `verbose` times
                if t % verbose == 0:
                    print(f'Epoch {t} train loss: {epoch_loss / len(train_data)} val loss: {val_loss / len(val_data)}')

                ## check early stopping for every `patience` times
                if (t % patience == 0) & (t != 0):

                    ## if loss increased, perform early stopping
                    if val_hist[t - patience] < val_hist[t] :

                        print('\n Early Stopping')

                        break

            # elif t % verbose == 0:
            #     print(f'Epoch {t} train loss: {epoch_loss / len(train_data)}')

        return model, train_hist, val_hist

    model = CovidPredictor(
        n_features=1,
        n_hidden=4,
        seq_len=seq_length,
        n_layers=1
    )
    print(model)

    FILE = "model.pth"
    model = torch.load(FILE)
    model.eval()

    pred_dataset = X_test

    with torch.no_grad():
        preds = []
        for _ in range(len(pred_dataset)):
            model.reset_hidden_state()
            y_test_pred = model(torch.unsqueeze(pred_dataset[_], 0))
            pred = torch.flatten(y_test_pred).item()
            preds.append(pred)

    print(np.array(preds)*MAX)

    def plot_multi_step(history, prediction1):
        fig5 = plt.figure(figsize=(15, 6))
        range_history = len(history)
        range_future = list(range(range_history, range_history + len(prediction1)))
        plt.plot(np.arange(range_history), np.array(history), label='History')
        plt.plot(range_future, np.array(prediction1),label='Forecasted with CNN-LSTM')
        plt.legend(loc='upper right')
        plt.xlabel('days')
        plt.ylabel('Tital_kwh')
        st.pyplot(fig5)
    plot_multi_step(np.array(y_test)*MAX, np.array(preds)*MAX)

    if selected_status_7 == 7:
        st.write('Predicted value of charging energy consumption in the next 7 days')
    elif selected_status_7 == 14:
        st.write('Predicted value of charging energy consumption in the next 14 days')
    elif selected_status_7 == 21:
        st.write('Predicted value of charging energy consumption in the next 21 days')
    else:
        st.write('Predicted value of charging energy consumption in the next 28 days')

    st.write(np.array(preds)*MAX)

    def evaluate_prediction(predictions, actual, model_name):
        errors = predictions - actual
        mse = np.square(errors).mean()
        rmse = np.sqrt(mse)
        mae = np.abs(errors).mean()
        st.write(model_name +' Evaluation Metrics(Please choose selected box)'+ ':')
        if selected_status_8_1:
            st.write('RMSE: {:.4f}'.format(rmse))
        if selected_status_8_2:
            st.write('MSE: {:.4f}'.format(mse))
        if selected_status_8_3:
            st.write('MAE: {:.4f}'.format(mae))
        st.write('')
    evaluate_prediction(np.array(y_test)*MAX, np.array(preds)*MAX,'CNN-LSTM')

#=================================================================================================================================
elif selected_status_6 == 'LSTM':
    st.subheader("Predict Part")
    test_data_size = 30

    all_data = df3['Total_kWh'].values.astype(float)

    train_data_X = all_data[:-test_data_size]
    test_data_X = all_data[-test_data_size:]
    test_data_y = test_data_X

    print(len(train_data_X))
    print(len(test_data_X))

    print(test_data_X)

    from sklearn.preprocessing import MinMaxScaler

    scaler = MinMaxScaler(feature_range=(-1, 1))
    train_data_normalized = scaler.fit_transform(train_data_X .reshape(-1, 1))

    train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)
    if selected_status_7 == 7:
        train_window = 7
    elif selected_status_7 == 14:
        train_window = 14
    elif selected_status_7 == 21:
        train_window = 21
    elif selected_status_7 == 28:
        train_window = 28

    def create_inout_sequences(input_data, tw):
        inout_seq = []
        L = len(input_data)
        for i in range(L-tw):
            train_seq = input_data[i:i+tw]
            train_label = input_data[i+tw:i+tw+1]
            inout_seq.append((train_seq ,train_label))
        return inout_seq

    train_inout_seq = create_inout_sequences(train_data_normalized, train_window)

    class LSTM(nn.Module):
        def __init__(self, input_size=1, hidden_layer_size=100, output_size=1):
            super().__init__()
            self.hidden_layer_size = hidden_layer_size

            self.lstm = nn.LSTM(input_size, hidden_layer_size)

            self.linear = nn.Linear(hidden_layer_size, output_size)

            self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
                                torch.zeros(1,1,self.hidden_layer_size))

        def forward(self, input_seq):
            lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
            predictions = self.linear(lstm_out.view(len(input_seq), -1))
            return predictions[-1]

    model = LSTM()
    loss_function = nn.MSELoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
    print(model)

    # epochs = 200

    # for i in range(epochs):
    #     for seq, labels in train_inout_seq:
    #         optimizer.zero_grad()
    #         model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
    #                         torch.zeros(1, 1, model.hidden_layer_size))

    #         y_pred = model(seq)

    #         single_loss = loss_function(y_pred, labels)
    #         single_loss.backward()
    #         optimizer.step()

    #     if i%25 == 1:
    #         print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')

    # print(f'epoch: {i:3} loss: {single_loss.item():10.10f}')
    FILE = "model_LSTM.pth"
    model = torch.load(FILE)
    model.eval()

    if selected_status_7 == 7:
        fut_pred = 7
    elif selected_status_7 == 14:
        fut_pred = 14
    elif selected_status_7 == 21:
        fut_pred = 21
    elif selected_status_7 == 28:
        fut_pred = 28

    test_inputs = train_data_normalized[-train_window:].tolist()
    print(test_inputs)

    model.eval()

    for i in range(fut_pred):
        seq = torch.FloatTensor(test_inputs[-train_window:])
        with torch.no_grad():
            model.hidden = (torch.zeros(1, 1, model.hidden_layer_size),
                            torch.zeros(1, 1, model.hidden_layer_size))
            test_inputs.append(model(seq).item())

    print(test_inputs[fut_pred:])

    actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:] ).reshape(-1, 1))

    x = np.arange(333, 363, 1)
    print(x)

    # plt.title('Days vs Total_kwh')
    # plt.ylabel('Total_kwh')
    # plt.grid(True)
    # plt.autoscale(axis='x', tight=True)
    # plt.plot(df['Total_kWh'])
    # plt.plot(x,actual_predictions)
    # plt.show()

    # plt.title('Days vs Total_kwh')
    # plt.ylabel('Total_kwh')
    # plt.grid(True)
    # plt.autoscale(axis='x', tight=True)

    # plt.plot(df['Total_kWh'][-train_window:])
    # plt.plot(x,actual_predictions)
    # plt.show()

    def plot_multi_step(history, prediction1):
        fig6 = plt.figure(figsize=(15, 6))
        range_history = len(history)
        range_future = list(range(range_history, range_history + len(prediction1)))
        plt.plot(np.arange(range_history), np.array(history), label='History')
        plt.plot(range_future, np.array(prediction1),label='Forecasted with LSTM')
        plt.legend(loc='upper right')
        plt.xlabel('days')
        plt.ylabel('Tital_kwh')
        st.pyplot(fig6)
    plot_multi_step(df['Total_kWh'][-train_window:], actual_predictions)

    if selected_status_7 == 7:
        st.write('Predicted value of charging energy consumption in the next 7 days')
    elif selected_status_7 == 14:
        st.write('Predicted value of charging energy consumption in the next 14 days')
    elif selected_status_7 == 21:
        st.write('Predicted value of charging energy consumption in the next 21 days')
    else:
        st.write('Predicted value of charging energy consumption in the next 28 days')
    st.write(actual_predictions)

    def evaluate_prediction(predictions, actual, model_name):
        errors = predictions - actual
        mse = np.square(errors).mean()
        rmse = np.sqrt(mse)
        mae = np.abs(errors).mean()
        st.write(model_name +' Evaluation Metrics(Please choose selected box)'+ ':')
        if selected_status_8_1:
            st.write('RMSE: {:.4f}'.format(rmse))
        if selected_status_8_2:
            st.write('MSE: {:.4f}'.format(mse))
        if selected_status_8_3:
            st.write('MAE: {:.4f}'.format(mae))
        st.write('')
    evaluate_prediction(actual_predictions, test_data_y,'LSTM')
#=================================================================================================================================

# st.sidebar.header("Predict Part")
# st.subheader("Predict Part")


import argparse
import torch
import torch.nn as nn
from torch.utils import data, model_zoo
import numpy as np
import pickle
from torch.autograd import Variable
import torch.optim as optim
import scipy.misc
import torch.backends.cudnn as cudnn
import torch.nn.functional as F
import sys
import os
import os.path as osp
import random
from tensorboardX import SummaryWriter

from model.deeplab_multi import DeeplabMulti
from model.deeplab import Res_Deeplab
from modeling.deeplab import DeepLab
from model.discriminator import FCDiscriminator
from utils.loss import CrossEntropy2d
from dataset.gta5_dataset import GTA5DataSet
from dataset.cityscapes_dataset import cityscapesDataSet
from utils.LoadDataSeg import data_loader
from collections import OrderedDict
IMG_MEAN = np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32)

MODEL = 'DeepLab'
BATCH_SIZE = 1
ITER_SIZE = 1
NUM_WORKERS = 4
DATA_DIRECTORY = './data/GTA5'
DATA_LIST_PATH = './dataset/gta5_list/train.txt'
IGNORE_LABEL = 255
INPUT_SIZE = '1280,720'
DATA_DIRECTORY_TARGET = './data/Cityscapes/data'
DATA_LIST_PATH_TARGET = './dataset/cityscapes_list/train.txt'
INPUT_SIZE_TARGET = '1024,512'
LEARNING_RATE = 2.5e-4
MOMENTUM = 0.9
NUM_CLASSES = 2
NUM_STEPS = 100000
NUM_STEPS_STOP = 100000  # early stopping
POWER = 0.9
RANDOM_SEED = 1234
#RESTORE_FROM = 'http://vllab.ucmerced.edu/ytsai/CVPR18/DeepLab_resnet_pretrained_init-f81d91e8.pth'
#RESTORE_FROM ='https://download.pytorch.org/models/resnet50-19c8e357.pth'
RESTORE_FROM ='./snapshots/voc2012_1_50000.pth'
RESTORE_FROM_D ='./snapshots/voc2012_1_50000_D1.pth'
SAVE_NUM_IMAGES = 2
SAVE_PRED_EVERY = 10000
SNAPSHOT_DIR = './snapshots/'
WEIGHT_DECAY = 0.0005
LOG_DIR = './log'

LEARNING_RATE_D = 1e-4
LAMBDA_SEG = 0.1
LAMBDA_ADV_TARGET1 = 0.001
LAMBDA_ADV_TARGET2 = 0.001
#LAMBDA_ADV_TARGET1 = 0.0002
#LAMBDA_ADV_TARGET2 = 0.001
GAN = 'Vanilla'

TARGET = 'cityscapes'
SET = 'train'

def get_arguments():
    """Parse all the arguments provided from the CLI.

    Returns:
      A list of parsed arguments.
    """
    parser = argparse.ArgumentParser(description="DeepLab-ResNet Network")
    parser.add_argument("--model", type=str, default=MODEL,
                        help="available options : DeepLab")
    parser.add_argument("--target", type=str, default=TARGET,
                        help="available options : cityscapes")
    parser.add_argument("--batch-size", type=int, default=BATCH_SIZE,
                        help="Number of images sent to the network in one step.")
    parser.add_argument("--iter-size", type=int, default=ITER_SIZE,
                        help="Accumulate gradients for ITER_SIZE iterations.")
    parser.add_argument("--num-workers", type=int, default=NUM_WORKERS,
                        help="number of workers for multithread dataloading.")
    parser.add_argument("--data-dir", type=str, default=DATA_DIRECTORY,
                        help="Path to the directory containing the source dataset.")
    parser.add_argument("--data-list", type=str, default=DATA_LIST_PATH,
                        help="Path to the file listing the images in the source dataset.")
    parser.add_argument("--ignore-label", type=int, default=IGNORE_LABEL,
                        help="The index of the label to ignore during the training.")
    parser.add_argument("--input-size", type=str, default=INPUT_SIZE,
                        help="Comma-separated string with height and width of source images.")
    parser.add_argument("--data-dir-target", type=str, default=DATA_DIRECTORY_TARGET,
                        help="Path to the directory containing the target dataset.")
    parser.add_argument("--data-list-target", type=str, default=DATA_LIST_PATH_TARGET,
                        help="Path to the file listing the images in the target dataset.")
    parser.add_argument("--input-size-target", type=str, default=INPUT_SIZE_TARGET,
                        help="Comma-separated string with height and width of target images.")
    parser.add_argument("--is-training", action="store_true",
                        help="Whether to updates the running means and variances during the training.")
    parser.add_argument("--learning-rate", type=float, default=LEARNING_RATE,
                        help="Base learning rate for training with polynomial decay.")
    parser.add_argument("--learning-rate-D", type=float, default=LEARNING_RATE_D,
                        help="Base learning rate for discriminator.")
    parser.add_argument("--lambda-seg", type=float, default=LAMBDA_SEG,
                        help="lambda_seg.")
    parser.add_argument("--lambda-adv-target1", type=float, default=LAMBDA_ADV_TARGET1,
                        help="lambda_adv for adversarial training.")
    parser.add_argument("--lambda-adv-target2", type=float, default=LAMBDA_ADV_TARGET2,
                        help="lambda_adv for adversarial training.")
    parser.add_argument("--momentum", type=float, default=MOMENTUM,
                        help="Momentum component of the optimiser.")
    parser.add_argument("--not-restore-last", action="store_true",
                        help="Whether to not restore last (FC) layers.")
    parser.add_argument("--num-classes", type=int, default=NUM_CLASSES,
                        help="Number of classes to predict (including background).")
    parser.add_argument("--num-steps", type=int, default=NUM_STEPS,
                        help="Number of training steps.")
    parser.add_argument("--num-steps-stop", type=int, default=NUM_STEPS_STOP,
                        help="Number of training steps for early stopping.")
    parser.add_argument("--power", type=float, default=POWER,
                        help="Decay parameter to compute the learning rate.")
    parser.add_argument("--random-mirror", action="store_true",
                        help="Whether to randomly mirror the inputs during the training.")
    parser.add_argument("--random-scale", action="store_true",
                        help="Whether to randomly scale the inputs during the training.")
    parser.add_argument("--random-seed", type=int, default=RANDOM_SEED,
                        help="Random seed to have reproducible results.")

    parser.add_argument("--restore-from", type=str, default=RESTORE_FROM,
                        help="Where restore model parameters from.")
    parser.add_argument("--restore-from-D", type=str, default=RESTORE_FROM_D,
                        help="Where restore model parameters from.")
    parser.add_argument("--save-num-images", type=int, default=SAVE_NUM_IMAGES,
                        help="How many images to save.")
    parser.add_argument("--save-pred-every", type=int, default=SAVE_PRED_EVERY,
                        help="Save summaries and checkpoint every often.")
    parser.add_argument("--snapshot-dir", type=str, default=SNAPSHOT_DIR,
                        help="Where to save snapshots of the model.")
    parser.add_argument("--weight-decay", type=float, default=WEIGHT_DECAY,
                        help="Regularisation parameter for L2-loss.")
    parser.add_argument("--cpu", action='store_true', help="choose to use cpu device.")
    parser.add_argument("--tensorboard", action='store_true', help="choose whether to use tensorboard.")
    parser.add_argument("--log-dir", type=str, default=LOG_DIR,
                        help="Path to the directory of log.")
    parser.add_argument("--set", type=str, default=SET,
                        help="choose adaptation set.")
    parser.add_argument("--gan", type=str, default=GAN,
                        help="choose the GAN objective.")
    parser.add_argument("--arch", type=str, default='onemodel_sg_one')
    parser.add_argument("--max_steps", type=int, default=100001)
    parser.add_argument("--lr", type=float, default=1e-5)
    # parser.add_argument("--decay_points", type=str, default='none')
    parser.add_argument("--disp_interval", type=int, default=100)
    parser.add_argument("--save_interval", type=int, default=5000)
    parser.add_argument("--snapshot_dir", type=str, default=SNAPSHOT_DIR)
    #parser.add_argument("--restore_from", type=str,default='/home/prlab/willow/Oneshot/SG-One-master/snapshots/onemodel_sg_one_scale/group_1_of_4/step_80000.pth.tar')
    parser.add_argument("--resume", action='store_true')
    parser.add_argument("--start_count", type=int, default=50000)

    # parser.add_argument("--split", type=str, default='train')
    parser.add_argument("--split", type=str, default='train')
    parser.add_argument("--group", type=int, default=1)
    parser.add_argument('--num_folds', type=int, default=4)
    return parser.parse_args()

args = get_arguments()

def lr_poly(base_lr, iter, max_iter, power):
    return base_lr * ((1 - float(iter) / max_iter) ** (power))

def adjust_learning_rate(optimizer, i_iter):
    lr = lr_poly(args.learning_rate, i_iter, args.num_steps, args.power)
    optimizer.param_groups[0]['lr'] = lr
    if len(optimizer.param_groups) > 1:
        optimizer.param_groups[1]['lr'] = lr * 10

def adjust_learning_rate_D(optimizer, i_iter):
    lr = lr_poly(args.learning_rate_D, i_iter, args.num_steps, args.power)
    optimizer.param_groups[0]['lr'] = lr
    if len(optimizer.param_groups) > 1:
        optimizer.param_groups[1]['lr'] = lr * 10
def restore(model, pre_model):
    try:
        model.load_state_dict(pre_model)
    except RuntimeError:
        print("KeyError")
        model_dict = model.state_dict()
        new_model_dict = OrderedDict()
        for k_model, k_pretrained in zip(list(model_dict.keys()), list(pre_model.keys())[:len(model_dict.keys())]):#增加了list
            if model_dict[k_model].size() == pre_model[k_pretrained].size():
                print("%s\t<--->\t%s"%(k_model, k_pretrained))
                new_model_dict[k_model] = pre_model[k_pretrained]
            else:
                print('Fail to load %s'%(k_model))

        model_dict.update(new_model_dict)
        model.load_state_dict(model_dict)
    except KeyError:
        print("Loading pre-trained values failed.")
        raise
# else:
#     print("=> no checkpoint found at '{}'".format(snapshot))

def one_hot(label):
    label = label.squeeze().unsqueeze(0).cpu().numpy()
    one_hot = np.zeros((label.shape[0], args.num_classes, label.shape[1], label.shape[2]), dtype=label.dtype)
    for i in range(args.num_classes):
        one_hot[:,i,...] = (label==i)
    #handle ignore labels
    return torch.FloatTensor(one_hot)

def main():
    """Create the model and start the training."""

    device = torch.device("cuda" if not args.cpu else "cpu")

    w, h = map(int, args.input_size.split(','))
    input_size = (w, h)

    w, h = map(int, args.input_size_target.split(','))
    input_size_target = (w, h)

    cudnn.enabled = True

    # Create network
    if args.model == 'DeepLab':
        #model = DeeplabMulti(num_classes=args.num_classes)
        #model = Res_Deeplab(num_classes=args.num_classes)
        model = DeepLab(backbone='resnet', output_stride=16)
        '''
        if args.restore_from[:4] == 'http' :
            saved_state_dict = model_zoo.load_url(args.restore_from)
        else:
            saved_state_dict = torch.load(args.restore_from)
        #restore(model, saved_state_dict)

        new_params = model.state_dict().copy()
        for i in saved_state_dict:
            # Scale.layer5.conv2d_list.3.weight
            i_parts = i.split('.')
            # print i_parts
            if not i_parts[0] == 'layer4' and not i_parts[0] == 'fc':
                #new_params['.'.join(i_parts[1:])] = saved_state_dict[i]
                new_params[i] = saved_state_dict[i]
                # print i_parts
        model.load_state_dict(new_params)
        '''
    else:
        raise NotImplementedError

    model.train()
    model.to(device)

    cudnn.benchmark = True

    # init D
    model_D1 = FCDiscriminator(num_classes=args.num_classes).to(device)

    # if args.restore_from_D[:4] == 'http':
    #     saved_state_dict = model_zoo.load_url(args.restore_from_D)
    # else:
    #     saved_state_dict = torch.load(args.restore_from_D)
    #     ### for running different versions of pytorch
    # model_dict = model_D1.state_dict()
    # saved_state_dict = {k: v for k, v in saved_state_dict.items() if k in model_dict}
    # model_dict.update(saved_state_dict)
    # model_D1.load_state_dict(saved_state_dict)

    model_D1.train()
    model_D1.to(device)

    if not os.path.exists(args.snapshot_dir):
        os.makedirs(args.snapshot_dir)

    train_loader = data_loader(args)

    # implement model.optim_parameters(args) to handle different models' lr setting

    optimizer = optim.SGD(model.optim_parameters(args),
                          lr=args.learning_rate, momentum=args.momentum, weight_decay=args.weight_decay)
    optimizer.zero_grad()

    optimizer_D1 = optim.Adam(model_D1.parameters(), lr=args.learning_rate_D, betas=(0.9, 0.99))
    optimizer_D1.zero_grad()

    if args.gan == 'Vanilla':
        bce_loss = torch.nn.BCEWithLogitsLoss()
    elif args.gan == 'LS':
        bce_loss = torch.nn.MSELoss()
    seg_loss = torch.nn.CrossEntropyLoss()

    interp = nn.Upsample(size=(416, 416), mode='bilinear', align_corners=True)
    #interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', align_corners=True)

    # labels for adversarial training

    # set up tensorboard
    if args.tensorboard:
        if not os.path.exists(args.log_dir):
            os.makedirs(args.log_dir)

        writer = SummaryWriter(args.log_dir)

    count = args.start_count  # 迭代次数
    for dat in train_loader:
        if count > args.num_steps:
            break

        loss_seg_value1_anchor = 0
        loss_adv_target_value1 = 0
        loss_D_value1 = 0

        optimizer.zero_grad()
        adjust_learning_rate(optimizer, count)

        optimizer_D1.zero_grad()

        adjust_learning_rate_D(optimizer_D1, count)

        for sub_i in range(args.iter_size):

            # train G

            # don't accumulate grads in D
            for param in model_D1.parameters():
                param.requires_grad = False

            # 相当于group=0时，训练样本对应的类有15类为[0,1,2,3,4,5,6,7,8,9,10,....]，验证集有5类，
            # 现在从训练集类中随机选择两类，然后从其中一类中选择两张图片，对应为基准图片和正样本图片，
            # 两者属于同一类，接着从另一类中选择一张图片作为负样本，属于不同类。其中基准图片对应的是查询集图片
            #############################
            anchor_img, anchor_mask, pos_img, pos_mask, neg_img, neg_mask = dat  # 返回的是基准图片以及mask，正样本以及mask（和基准图片属于同一类），负样本以及mask（和基准图片属于不同类）

            anchor_img, anchor_mask, pos_img, pos_mask, \
                = anchor_img.cuda(), anchor_mask.cuda(), pos_img.cuda(), pos_mask.cuda()  # [1, 3, 386, 500],[1, 386, 500],[1, 3, 374, 500],[1, 374, 500]

            anchor_mask = torch.unsqueeze(anchor_mask, dim=1)  # [1, 1, 386, 500]
            pos_mask = torch.unsqueeze(pos_mask, dim=1)  # [1,1, 374, 500]
            samples = torch.cat([pos_img, anchor_img], 0)

            pred = model(samples, pos_mask)  ##[2, 2, 53, 53],#[2, 2, 53, 53]
            pred = interp(pred)

            loss_seg1_anchor = seg_loss(pred, anchor_mask.squeeze().unsqueeze(0).long())
            D_out1 = model_D1(F.softmax(pred))
            loss_adv_target1 = bce_loss(D_out1, torch.FloatTensor(D_out1.data.size()).fill_(1).to(
                device))  # 相当于将源域的标签设置为1,然后判断判别网络得到的目标预测与源域对应的损失
            '''
            s = torch.stack([s, 1-s])
            loss_s = seg_loss()
            '''
            loss = loss_seg1_anchor + args.lambda_adv_target1 * loss_adv_target1

            # proper normalization
            loss = loss / args.iter_size
            loss.backward()

            loss_seg_value1_anchor += loss_seg1_anchor.item() / args.iter_size
            loss_adv_target_value1 += loss_adv_target1.item() / args.iter_size

            # train D# bring back requires_grad
            for param in model_D1.parameters():
                param.requires_grad = True

            # train with anchor
            pred_target1 = pred.detach()
            D_out1 = model_D1(F.softmax(pred_target1))
            loss_D1 = bce_loss(D_out1, torch.FloatTensor(D_out1.data.size()).fill_(0).to(device))
            loss_D1 = loss_D1 / args.iter_size / 2
            loss_D1.backward()
            loss_D_value1 += loss_D1.item()

            # train with GT
            anchor_gt = Variable(one_hot(anchor_mask)).cuda()
            D_out1 = model_D1(anchor_gt)
            loss_D1 = bce_loss(D_out1, torch.FloatTensor(D_out1.data.size()).fill_(1).to(device))
            loss_D1 = loss_D1 / args.iter_size / 2
            loss_D1.backward()
            loss_D_value1 += loss_D1.item()

        optimizer.step()
        optimizer_D1.step()

        count = count + 1
        if args.tensorboard:
            scalar_info = {

                'loss_seg1_anchor': loss_seg_value1_anchor,
                'loss_adv_target1': loss_adv_target_value1,
                'loss_D1': loss_D_value1,

            }

            if count % 10 == 0:
                for key, val in scalar_info.items():
                    writer.add_scalar(key, val, count)

        # print('exp = {}'.format(args.snapshot_dir))
        print(
        'iter = {0:8d}/{1:8d}, loss_seg1 = {2:.3f}, loss_adv1 = {3:.3f}, loss_D1 = {4:.3f}'.format(
            count, args.num_steps, loss_seg_value1_anchor,loss_adv_target_value1,loss_D_value1))

        if count >= args.num_steps_stop - 1:
            print('save model ...')
            torch.save(model.state_dict(), osp.join(args.snapshot_dir, 'voc2012_' + str(args.num_steps_stop) + '.pth'))
            torch.save(model_D1.state_dict(), osp.join(args.snapshot_dir, 'voc2012_' + str(args.num_steps_stop) + '_D1.pth'))
            break

        if count % args.save_pred_every == 0 and count != 0:
            print('taking snapshot ...')
            torch.save(model.state_dict(), osp.join(args.snapshot_dir, 'voc2012_' + str(count) + '.pth'))
            torch.save(model_D1.state_dict(), osp.join(args.snapshot_dir, 'voc2012_' + str(count) + '_D1.pth'))

    if args.tensorboard:
        writer.close()

if __name__ == '__main__':
    main()


from typing import Tuple, List

import numpy as np

Matrix = np.array
Vector = np.array

# the eigenvalues for this matrix are 2, 9, and 12
M: Matrix = np.array([[6, -4, 1],
                      [-4, 6, -1],
                      [1, -1, 11]])

def power_method(matrix: Matrix, num_iterations: int) -> Tuple:
    """
        The power method starts with a vector (v_0) containing N=3 number of real numbers
        and iterates through the matrix multiplying v_0 with the matrix, creating v_1.
        Then v_1 is normalized and we recalculate v_0 by dividing v_1 by its normalization.
        As this process is iterated over, we get closer to our eigenvector and its associated
        (highest) eigenvalue of the matrix.
    :param matrix: 3 x 3 matrix
    :param num_iterations: the number of times the power method should iterate
    :return: a tuple (eigenvector, highest_eigenvalue)
    """
    v_0: Vector = np.random.rand(matrix.shape[1])
    v_1_norm: np.linalg.norm = 0
    for x in range(num_iterations):
        v_1: Vector = np.dot(matrix, v_0)

        v_1_norm = np.linalg.norm(v_1)

        v_0 = v_1 / v_1_norm
    return v_0, v_1_norm

def check(test_eigenvector: Vector, matrix: Matrix, high_eigenvalue: int) -> bool:
    """
        This function checks to make sure that the eigenvector we calculated
        is correct.
    :param test_eigenvector: The eigenvector associated with the highest eigenvalue
    :param matrix: The matrix we want to test the eigenvector with
    :return:
    """
    checked_vector: Vector = []
    is_eigenvector = True
    for row in matrix:
        new_val = 0
        for index, val in enumerate(test_eigenvector):
            new_val = new_val + row[index] * val
        checked_vector.append(new_val)
    for i, val in enumerate(test_eigenvector):
        if val * high_eigenvalue != checked_vector[i]:
            is_eigenvector = False
            break
    return is_eigenvector

if __name__ == '__main__':
    highest_eigenvector_basis, highest_eigenvalue = power_method(M, 1000)
    checked = check(highest_eigenvector_basis, M, highest_eigenvalue)
    if checked:
        print(f'Highest eigenvalue is {highest_eigenvalue} \n'
              f'and the basis eigenvector for the eigenspace is \n'
              f'{highest_eigenvector_basis}')
    else:
        print(f'We failed to find the highest eigenvalue and its \n'
              f'corresponding basis of the eigenspace')


# -*- coding: utf-8 -*-
"""
Created on Tue Jul 21 12:52:47 2020

@author: AjaySai
"""

"""### Importing the libraries"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
tf.__version__
"""## Importing the dataset"""

dataset = pd.read_csv('Credit_Card_Applications.csv')
X = dataset.iloc[:, :-1].values
y = dataset.iloc[:, -1].values

"""## Feature Scaling"""

from sklearn.preprocessing import MinMaxScaler
sc = MinMaxScaler(feature_range = (0,1))
X = sc.fit_transform(X)

"""##Training the SOM"""

from minisom import MiniSom
som = MiniSom(x=10, y=10, input_len= 15, sigma= 1.0, learning_rate = 0.5,random_seed=19)
som.random_weights_init(X)
som.train_random(data = X, num_iteration = 100)

"""##Visualizing the results"""

from pylab import bone, pcolor, colorbar, plot, show
bone()
pcolor(som.distance_map().T)
colorbar()
markers = ['o', 's']
colors = ['r', 'g']
for i, x in enumerate(X):
    w = som.winner(x)
    plot(w[0] + 0.5,
         w[1] + 0.5,
         markers[y[i]],
         markeredgecolor = colors[y[i]],
         markerfacecolor = 'None',
         markersize = 10,
         markeredgewidth = 2)
show()

"""## Finding the frauds"""

mappings = som.win_map(X)
frauds = np.concatenate((mappings[(4,5)], mappings[(3,7)]), axis = 0)
frauds = sc.inverse_transform(frauds)

"""##Printing the Fraunch Clients"""

print('Fraud Customer IDs')
for i in frauds[:, 0]:
  print(int(i))

"""#Part 2 - Going from Unsupervised to Supervised Deep Learning

##Create Matrix of Features
"""

customers = dataset.iloc[:, :-1].values

"""## Create Dependent Variable"""

is_fraud = np.zeros(len(dataset))
for i in range(len(dataset)):
  if dataset.iloc[i,0] in frauds:
    is_fraud[i] = 1

# Splitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(customers, is_fraud, test_size = 0.2, random_state = 0)

# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

# Part 2 - Building the ANN

# Initializing the ANN
ann = tf.keras.models.Sequential()

# Adding the input layer and the first hidden layer
ann.add(tf.keras.layers.Dense(units=6, activation='relu'))

# Adding the second hidden layer
ann.add(tf.keras.layers.Dense(units=6, activation='relu'))

# Adding the output layer
ann.add(tf.keras.layers.Dense(units=1, activation='sigmoid'))

# Part 3 - Training the ANN

# Compiling the ANN
ann.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])

# Training the ANN on the Training set
ann.fit(X_train, y_train, batch_size = 32, epochs = 100)

# Part 4 - Making the predictions and evaluating the model

# Predicting the result of a single observation

# Predicting the Test set results
y_pred = ann.predict(X_test)
y_pred = (y_pred > 0.5)
print(np.concatenate((y_pred.reshape(len(y_pred),1), y_test.reshape(len(y_test),1)),1))

from sklearn.metrics import confusion_matrix, accuracy_score,precision_score
from sklearn.metrics import roc_curve, roc_auc_score
cm = confusion_matrix(y_test, y_pred)
print(cm)
acs=accuracy_score(y_test, y_pred)
prs=precision_score(y_test, y_pred)
sensitivity1 = cm[0,0]/(cm[0,0]+cm[0,1])
specificity1 = cm[1,1]/(cm[1,0]+cm[1,1])
print("acuuracy =",acs)
print('Specificity : ', specificity1)
print('Sensitivity : ', sensitivity1 )
print("precision :",prs)

false_positive_rate1, true_positive_rate1, threshold1 = roc_curve(y_test, y_pred)
print('roc_auc_score for ANN: ', roc_auc_score(y_test, y_pred))
plt.title('Receiver Operating Characteristic - SOM+ANN')
plt.plot(false_positive_rate1, true_positive_rate1)
plt.plot([0, 1], ls="--")
plt.plot([0, 0], [1, 0] , c=".7"), plt.plot([1, 1] , c=".7")
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
plt.show()

print(ann.predict(sc.transform([[1,222.8,11.46,2,4,4,1.585,0,0,0,1,2,100,1213,0]])))


runstate = True
playerList = []

class Player:
	id = None
	score = None

	def __init__(self, _id):
		self.id = _id
		self.score = 0

p1 = Player(1)
p2 = Player(2)

playerList.append(p1)
playerList.append(p2)

print (3 in [x.id for x in playerList])

items = []
pl = [x.id for x in playerList]

diff = list(set([x.id for x in playerList]).difference(items))

print(diff)


class Product:

    def __init__(self, PID, Pname, ProPrice):

        self.PID = PID

        self.Pname = Pname

        self.ProPrice = ProPrice

    def PID(self): return self.__PID

    def PID(self,value): self.__PID = Value

    def Pname(self): return self.__Pname

    def Pname(self,value): self.__Pname = Value

    def ProPrice(self): return self.__ProPrice

    def ProPrice(self,value):

        if value<0 :

            raise Exception("price must be greater than zero")

        else:

            self.__ProPrice = value

    def __str__(self):

        return self.PID + ',' + self. Pname + ','+ self.ProPrice

class datalayer:

    #Data

    objFile = None #File Handle

    strUserInput = None #A string which holds user input

    #Processing

    def WriteProductUserInput(File):

        try:

            print("Type in a Product Id, Name, and Price you want to add to the file")

            print("(Enter 'Exit' to quit!)")

            while(True):

                strUserInput = input("Enter the Id, Name, and Price (ex.1,ProductA,9.99): ")

                if(strUserInput.lower() == "exit"): break

                else: File.write(strUserInput + "\n")

        except Exception as e:

            print("Error: " + str(e))

    def ReadAllFileData(File, Message="Contents of File"):

        try:

            print(Message)

            File.seek(0)

            print(File.read())

            File.seek(0)

            for row in File:

                list = row.strip().split(',')

                p = Product(list[0], list[1], list[2])

                print(p)

        except Exception as e:

            print("Error: " + str(e))

#I/O

try:

    datalayer.objFile = open("/Users/satya/Documents/Personal stuff/AdvancedPyTraining/Assignment_Sridevi/Product.txt", "r+")

    datalayer.ReadAllFileData(datalayer.objFile, "Here is the current data:")

    datalayer.WriteProductUserInput(datalayer.objFile)

    datalayer.ReadAllFileData(datalayer.objFile, "Here is this data was saved:")

except FileNotFoundError as e:

    print("Error: " + str(e) + "\n Please check the file name")

except Exception as e:

   print("Error: " + str(e))

finally:

    if(datalayer.objFile != None):datalayer.objFile.close()


s1, s2 = input().strip(), input().strip()
l1, l2 = len(s1), len(s2)
dp = [[0] * (l2 + 1) for _ in range(l1 + 1)]        # dp[s1][s2]
for i in range(1, l1 + 1):
    for j in range(1, l2 + 1):
        if s1[i - 1] == s2[j - 1]:      # 같다면 이전 수열의 값 + 1
            dp[i][j] = dp[i - 1][j - 1] + 1
        else:       # 다르다면 이전 수열 중에 최댓값을 찾으면 됨
            dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

max_str = ''
sy, sx = l1, l2
while True:     # 역추적해서 문자열을 찾음
    if sy == 0 or sx == 0:
        break
    if dp[sy][sx] == dp[sy - 1][sx]: sy -= 1        # 값이 같다면 위로
    elif dp[sy][sx] == dp[sy][sx - 1]: sx -= 1      # 값이 같다면 아래로
    else:       # 대각선과 값이 같다는 것은 문자도 공통된 것이므로 문자열에 추가함
        sy -= 1
        sx -= 1
        max_str = s1[sy] + max_str

print(dp[l1][l2])
print(max_str)


sample_rate = 32000

"""int: Target sample rate during feature extraction"""

window_size = 2048
"""int: Size of FFT window"""

overlap = 1024
"""int: Amount of overlap between frames"""

mel_bins = 64
"""int: Number of Mel bins"""

kmax = 3

labels = ['Acoustic_guitar', 'Applause', 'Bark', 'Bass_drum',
          'Burping_or_eructation', 'Bus', 'Cello', 'Chime', 'Clarinet',
          'Computer_keyboard', 'Cough', 'Cowbell', 'Double_bass',
          'Drawer_open_or_close', 'Electric_piano', 'Fart', 'Finger_snapping',
          'Fireworks', 'Flute', 'Glockenspiel', 'Gong', 'Gunshot_or_gunfire',
          'Harmonica', 'Hi-hat', 'Keys_jangling', 'Knock', 'Laughter', 'Meow',
          'Microwave_oven', 'Oboe', 'Saxophone', 'Scissors', 'Shatter',
          'Snare_drum', 'Squeak', 'Tambourine', 'Tearing', 'Telephone',
          'Trumpet', 'Violin_or_fiddle', 'Writing']

lb_to_ix = {lb: i for i, lb in enumerate(labels)}
ix_to_lb = {i: lb for i, lb in enumerate(labels)}

corrupted_files = ['0b0427e2.wav', '6ea0099f.wav', 'b39975f5.wav']


import os

from collections import Counter, OrderedDict
from functools import partial

from bs4 import BeautifulSoup
from english_words import english_words_set

from grobid.feature_utils import token_in_forbid_zones, \
    tokenize, get_bucket_num, capital, digital, punct, \
    build_font_feature_map, vectorize, fullPunctuations, \
    special_pattern_test, special_set_test, rect_contains, PUNCT_TRANS
from grobid.cmd_utils import wapiti_infer
from grobid.alto_file import AltoFile

PAGE_INFO = ["PAGESTART", "PAGEIN", "PAGEEND"]
BLOCK_INFO = ["BLOCKSTART", "BLOCKIN", "BLOCKEND"]
LINE_INFO = ["LINESTART", "LINEIN", "LINEEND"]

feature_cols = {
    "segment": ["token_text","2nd_token_text","lower_token","token_prefix","block_info","page_info","font_type","font_size_type","font_bold","font_italics","is_captal","is_digital","single_char","proper_name","common_name","first_name","year","mounth","email","http","relative_document_position","relative_page_position_characters","punct_profile","punct_profile_len","line_len","bitmap_around","vector_around","repetitive_pattern","first_repetitive_pattern", "in_main_area"],
    "fulltext": ["token_text", "lower_token", "token_prefix", "token_suffix", "block_info", "line_info", "align_status", "font_type", "font_size_type", "font_bold", "font_italics", "is_captal", "is_digital", "single_char", "punct_info", "relative_document_position", "relative_page_position_characters", "bitmap_around", "calloutType", "calloutKnown", "superscript"]
    }

class FeatureFactory():
    """
    """
    def __init__(self, alto_path):
        self.alto_path = alto_path
        self.feature_map = {}
        self.font_map = {}
        self.dump_map = {}
        self.valid_lines = set()

    def prepare(self):
        with open(self.alto_path) as f:
            self.alto_root = BeautifulSoup(f.read(), "xml")

        self.font_map = build_font_feature_map(self.alto_root.Styles)

    def _dump_feature(self, feature_type, output_path):
        feature_vectorise = partial(vectorize, feature_cols[feature_type])
        col_feature = map(feature_vectorise, self.feature_map[feature_type])

        with open(output_path, "w+") as w:
            for feature in col_feature:
                feature_line = " ".join(feature) + "\n"
                w.write(feature_line)

        self.dump_map[feature_type] = output_path

    def build_fulltext_feature(self, seg_results, output_path="", extern_feature={}):
        # 直接读取原始的alto.xml，build
        # self.feature_map["segment"] = self._extract_for_segment()

        # segment_feature_path = "segment.feature"

        # if output_path:
        #     segment_feature_path = os.path.join(output_path, segment_feature_path)

        # self._dump_feature("segment", segment_feature_path)

        # # 调用分类器，获取segment分类结果
        # seg_results = wapiti_infer(wapiti_model_map["segment"], self.dump_map["segment"])

        # with open(segment_feature_path + ".out", "w+") as w:
        #     for l in seg_results:
        #         w.write(l)

        # 根据segment分类结果，将文档分为不同部分
        self.block_map = self._build_block_map(seg_results)

        # 获取fulltext需要分类的部分，使用fulltext
        fulltext_feature = []
        extern_features = extern_feature
        for block in self.block_map["<body>"]:
            page_height = float(block.parent.parent.attrs["HEIGHT"])
            extern_feature["page_height"] = page_height
            token_features = self._extract_for_fulltext(block, extern_feature)
            fulltext_feature.extend(token_features)

        self.feature_map["fulltext"] = fulltext_feature

        fulltext_feature_path = "fulltext.feature"

        if output_path:
            fulltext_feature_path = os.path.join(output_path, fulltext_feature_path)

        self._dump_feature("fulltext", fulltext_feature_path)

        # 调用分类器，获取fulltext分类结果
        # fulltext_results = wapiti_infer(wapiti_model_map["fulltext"], self.dump_map["fulltext"])

        # with open(fulltext_feature_path + ".out", "w+") as w:
        #     for l in fulltext_results:
        #         w.write(l)

        return fulltext_feature_path

    def build_segment_feature(self, output_path=""):
        # 直接读取原始的alto.xml，build
        self.feature_map["segment"] = self._extract_for_segment()

        segment_feature_path = "segment.feature"

        if output_path:
            segment_feature_path = os.path.join(output_path, segment_feature_path)

        self._dump_feature("segment", segment_feature_path)
        return segment_feature_path

    def _extract_for_segment(self):
        doc_layout = self.alto_root.Layout

        alto_file = AltoFile(self.alto_path)
        main_area = alto_file.calc_page_main_areas()

        font = ""
        font_size = 0

        feature_list = []

        doc_token_len = len(doc_layout.find_all("String"))
        doc_level_pos = 0

        for page_zone in doc_layout:
            page_info = PAGE_INFO[0]
            page = page_zone.PrintSpace

            page_token_len = len(page.find_all("String"))
            page_level_pos = 0

            for text_block in page.children:
                top = float(text_block.attrs["VPOS"])
                left = float(text_block.attrs["HPOS"])
                bottom = top + float(text_block.attrs["HEIGHT"])
                right = left + float(text_block.attrs["WIDTH"])

                in_main_area = rect_contains(main_area, (left, top, right, bottom))

                block_info = BLOCK_INFO[0]
                max_line_len = 1

                for text_line in text_block.children:
                    first_token = text_line.next
                    feature_token = first_token
                    first_token_text = first_token.attrs["CONTENT"].strip()

                    if not first_token_text:
                        continue
                    else:
                        self.valid_lines.add(text_line.attrs["ID"])

                    if first_token.next.name == "SP":
                        second_token_text = first_token.next.next.attrs["CONTENT"]
                    elif first_token.next.name == "String":
                        second_token_text = first_token.next.attrs["CONTENT"]
                    else:
                        second_token_text = first_token_text

                    first_token_text = first_token_text.translate(PUNCT_TRANS)
                    second_token_text = second_token_text.strip()

                    # 获取字体信息
                    cur_font = first_token.attrs["STYLEREFS"]
                    if font != cur_font:
                        font_style = "NEWFONT"
                        font = cur_font
                    else:
                        font_style = "SAMEFONT"

                    # 获取字体信息
                    if font_size < self.font_map[cur_font]["fontsize"]:
                        font_size = self.font_map[cur_font]["fontsize"]
                        font_size_style = "HIGHERFONT"
                    elif self.font_map[cur_font]["fontsize"] == font_size:
                        font_size_style = "SAMEFONTSIZE"
                    elif self.font_map[cur_font]["fontsize"] < font_size:
                        font_size = self.font_map[cur_font]["fontsize"]
                        font_size_style = "LOWERFONT"

                    line_token = [c for c in text_line.children if c and c.name == "String"]
                    full_line = " ".join([t.attrs["CONTENT"] for t  in line_token])
                    line_len = len(full_line)
                    if max_line_len < line_len:
                        max_line_len = line_len

                    punct_profile = "".join([c for c in full_line if c != " " and c in fullPunctuations])
                    if not punct_profile:
                        punct_profile = "no"
                        punct_profile_len = "0"
                    else:
                        punct_profile_len = len(punct_profile)

                    feature_list.append({
                        # features
                        "token_text": first_token_text,
                        "2nd_token_text": second_token_text,
                        "lower_token": first_token_text.lower(),
                        "token_prefix": [first_token_text[:i] for i in range(1, 5)],
                        "block_info": block_info,
                        "page_info": page_info, # 8.
                        "font_type": font_style,
                        "font_size_type": font_size_style, # 10.
                        "font_bold": self.font_map[cur_font]["bold"], # 字体加粗
                        "font_italics": self.font_map[cur_font]["italics"], # 字体变斜
                        "is_captal": capital(first_token_text), # 大写情况
                        "is_digital": digital(first_token_text), #
                        "single_char": "1" if len(first_token_text)==1 else "0",
                        "proper_name": "0", # properName
                        "common_name": special_set_test("common", first_token_text), # 17. commonName
                        "first_name": "0", # firstName
                        "year": special_pattern_test("year", first_token_text), # year
                        "mounth": special_set_test("month", first_token_text), # 20. month
                        "email": special_pattern_test("email", first_token_text), # email
                        "http": special_pattern_test("http", first_token_text), # http
                        "relative_document_position": get_bucket_num(doc_level_pos, doc_token_len, 12), # relative document position
                        "relative_page_position_characters": get_bucket_num(page_level_pos, page_token_len, 12), # relative page position characters
                        "punct_profile": punct_profile, # 25. punctuation profile
                        "punct_profile_len": punct_profile_len, # punctuation profile
                        "line_len": line_len, # 27. round(10 * len(first_token_text) / max_len,  # lineLength
                        "bitmap_around": "0", # bitmapAround
                        "vector_around": "0", # vectorAround
                        "repetitive_pattern": "0", # repetitivePattern
                        "first_repetitive_pattern": "0", # firstRepetitivePattern
                        "in_main_area": in_main_area, # inMainArea
                        # extra info for debug
                        "full_line": full_line,
                        "line_id": text_line.attrs["ID"],
                    })

                    if block_info == BLOCK_INFO[0]:
                        block_info = BLOCK_INFO[1]

                    if page_info == PAGE_INFO[0]:
                        page_info = PAGE_INFO[1]

                for i in range(1, len(text_block)+1):
                    line_len = feature_list[-i]["line_len"]
                    feature_list[-i]["line_len"] = get_bucket_num(line_len, max_line_len, 10)

                if 1 < len(text_block):
                    feature_list[-1]["block_info"] = BLOCK_INFO[-1] # fix block info

                block_token_len = len(text_block.find_all("String"))
                page_level_pos += block_token_len
                doc_level_pos += block_token_len

            feature_list[-1]["page_info"] = PAGE_INFO[-1] # fix page info

        return feature_list

    def _extract_for_fulltext(self, text_block, extern_feature={}):
        font = ""
        font_size = 0

        feature_list = []

        block_info = BLOCK_INFO[0]
        max_line_len = 1

        forbid_zones = extern_feature.get("forbid_zones", [])

        prev_line_start = None

        for text_line in text_block.children:
            line_info = LINE_INFO[0]

            line_tokens = text_line.find_all("String")

            # 根据前后两行的开始位置判断当前行是否居中
            cur_line_start = float(text_line.attrs["HPOS"])
            if not prev_line_start:
                prev_line_start = cur_line_start

            average_char_width = float(line_tokens[0].attrs["WIDTH"]) / len(line_tokens[0].attrs["CONTENT"])

            indented = False
            if prev_line_start - cur_line_start > average_char_width:
                indented = False
            elif cur_line_start - prev_line_start > average_char_width:
                indented = True

            prev_line_start = cur_line_start
            align_status = "LINEINDENT" if indented else "ALIGNEDLEFT"

            for i, token in enumerate(line_tokens, start=1):
                # if token_in_forbid_zones(token, forbid_zones):
                #     # To do: Skip this feature
                #     continue

                feature_token = token
                full_token_text = token.attrs["CONTENT"]

                # 获取字体信息
                cur_font = feature_token.attrs["STYLEREFS"]
                if font != cur_font:
                    font_style = "NEWFONT"
                    font = cur_font
                else:
                    font_style = "SAMEFONT"

                # 获取字体信息
                if font_size < self.font_map[cur_font]["fontsize"]:
                    font_size = self.font_map[cur_font]["fontsize"]
                    font_size_style = "HIGHERFONT"
                elif self.font_map[cur_font]["fontsize"] == font_size:
                    font_size_style = "SAMEFONTSIZE"
                elif self.font_map[cur_font]["fontsize"] < font_size:
                    font_size = self.font_map[cur_font]["fontsize"]
                    font_size_style = "LOWERFONT"

                token_y_pos = float(feature_token.attrs["VPOS"])

                tokenized_text = tokenize(full_token_text)

                for token_text in tokenized_text:
                    a_feature = {
                        # features
                        "token_text": token_text,
                        "lower_token": token_text.lower(),
                        "token_prefix": [token_text[:i] for i in range(1, 5)],
                        "token_suffix": [token_text[i:] for i in range(-1, -5, -1)],
                        "block_info": block_info,
                        "line_info": line_info,
                        # "line_pos": get_bucket_num(i, len(line_tokens), 10),
                        "align_status": align_status,
                        "font_type": font_style,
                        "font_size_type": font_size_style, # 10.
                        "font_bold": self.font_map[cur_font]["bold"], # 字体加粗
                        "font_italics": self.font_map[cur_font]["italics"], # 字体变斜
                        "is_captal": capital(token_text), # 大写情况
                        "is_digital": digital(token_text), #
                        "single_char": "1" if len(token_text)==1 else "0",
                        "punct_info": punct(token_text), # 25. punctuation type
                        "relative_document_position": 0, # get_bucket_num(doc_level_pos, doc_token_len, 12), # relative document position
                        "relative_page_position_characters": get_bucket_num(token_y_pos, extern_feature.get("page_height", 1.0), 12),#get_bucket_num(page_level_pos, page_token_len, 12), # relative page position characters
                        "bitmap_around": "0", # bitmapAround
                        "calloutType": "UNKNOWN",
                        "calloutKnown": 0,
                        "superscript": self.font_map[cur_font]["superscript"],
                        # extra info for debug
                        "line_id": token.parent.attrs["ID"],
                        "str_id": token.attrs["ID"],
                    }

                    feature_list.append(a_feature)

                    if line_info == LINE_INFO[0]:
                        line_info = LINE_INFO[1]

                    if block_info == BLOCK_INFO[0]:
                        block_info = BLOCK_INFO[1]

            if 1 < len(text_line):
                feature_list[-1]["line_info"] = LINE_INFO[-1] # fix line info

        if 1 < len(text_block):
            feature_list[-1]["block_info"] = BLOCK_INFO[-1] # fix block info

        return feature_list

    def _build_block_map(self, features):
        doc_layout = self.alto_root.Layout

        feature_idx = 0
        block_map = OrderedDict()

        for page_zone in doc_layout:
            page = page_zone.PrintSpace

            for text_block in page.children:
                line_labels = set()

                # 归并相同label的特征行，经过验证，label相同的行一定属于同一个block
                for text_line in text_block.children:
                    first_token = text_line.next
                    feature_token = first_token
                    first_token_text = first_token.attrs["CONTENT"].strip()

                    if not first_token_text:
                        continue

                    label = features[feature_idx].split("\t")[1]
                    line_labels.add(label.strip().lstrip("I-"))
                    feature_idx += 1

                if len(line_labels) == 1:
                    seg_type = line_labels.pop()
                    if seg_type not in block_map:
                        block_map[seg_type] = []

                    if feature_idx >= len(features):
                        feature_idx -= 1

                    line_feature = features[feature_idx].split("\t")[0].split()
                    rel_page_pos = line_feature[27] if len(line_feature) > 30 else "0"

                    block_map[seg_type].append(text_block)

        return block_map

if __name__ == '__main__':
    ff = FeatureFactor("../tests/data/2020.emnlp-main.31.xml")
    ff.prepare()
    ff.build_feature()


"""
828. 字模式
给定一个模式和一个字符串str，查找str是否遵循相同的模式。
这里遵循的意思是一个完整的匹配，在一个字母的模式和一个非空的单词str之间有一个双向连接的模式对应。

样例
给定模式= "abba"， str = "dog cat cat dog"，返回true。给定模式= "abba"， str = "dog cat cat fish"，返回false。
给定模式= "aaaa"， str = "dog cat cat dog"，返回false。给定模式= "abba"， str = "dog dog dog dog"，返回false。

注意事项
您可以假设模式只包含小写字母，而str包含由单个空间分隔的小写字母。
"""

# short solution from LeetCode
class Solution:
    """
    @param pattern: a string, denote pattern string
    @param teststr: a string, denote matching string
    @return: an boolean, denote whether the pattern string and the matching string match or not
    """
    def wordPattern(self, pattern, teststr):
        # write your code here
        str_list = teststr.split()
        return list(map(pattern.find, pattern)) == list(map(str_list.index, str_list))

    def wordPattern1(self, pattern, teststr):
        # write your code here
        f = lambda s: map({}.setdefault, s, range(len(s)))
        return list(f(pattern)) == list(f(teststr.split()))

    def wordPattern2(self, pattern, teststr):
        # write your code here
        s = pattern
        t = teststr.split()
        return len(set(zip(s, t))) == len(set(s)) == len(set(t)) and len(s) == len(t)

# 用一个set保存不重复的字符串
class Solution1:
    """
    @param pattern: a string, denote pattern string
    @param teststr: a string, denote matching string
    @return: an boolean, denote whether the pattern string and the matching string match or not
    """
    def wordPattern(self, pattern, teststr):
        # write your code here
        word_map = {}
        # set用来预防：ab = "cat cat"这种情况
        unique_strs = set()
        str_list = teststr.split()

        # 如果长度不相等直接return False
        if len(pattern) != len(str_list):
            return False

        for i in range(len(pattern)):
            if pattern[i] not in word_map:
                # 如果set中没有就代表此时的pattern和str都是新的，添加
                if str_list[i] not in unique_strs:
                    word_map[pattern[i]] = str_list[i]
                    unique_strs.add(str_list[i])
                # 如果set中存在，代表之前有的pattern已经表示了str，返回False
                else:
                    return False

            if str_list[i] != word_map[pattern[i]]:
                return False

        return True

# 用HashMap记录pattern - word对应关系。
# 如果key 存在，value不一样，退出；如果key不存在，value存在，退出
class Solution2:
    """
    @param pattern: a string, denote pattern string
    @param teststr: a string, denote matching string
    @return: an boolean, denote whether the pattern string and the matching string match or not
    """
    def wordPattern(self, pattern, teststr):
        # write your code here
        h = {}
        strs = teststr.split()
        for i in range(len(pattern)):
            c = pattern[i]
            if c not in h:
                if strs[i] in h.values():
                    return False
                h[c] = strs[i]
            else:
                if strs[i] != h[c]:
                    return False
        return True

if __name__ == '__main__':
    print(Solution().wordPattern("aa", "bog bod"))
    print(Solution().wordPattern("abba", "dog cat cat dog"))


import pandas as pd
from re import search

def get_id_like_columns(cols: list) -> list:
    candidates = []
    for col in cols:
        if search("id$|_id", col) is not None:
            candidates.append(col)
    return candidates

def explore_unique_keys(cons: pd.DataFrame, cons_email: pd.DataFrame, cons_sub: pd.DataFrame) -> None:
    def comparison_to_cons(cons_comp: pd.DataFrame, tag: str):
        for col in get_id_like_columns(list(cons.columns)):
            cons_max = cons[col].max()
            cons_min = cons[col].min()
            cons_un = cons[col].nunique()
            cons_set = set(cons[col].unique())
            print(f"Cons column (len {len(cons)}): {col} has a maximum of {cons_max} and a minimum of {cons_min} and {cons_un} unique values\n")
            for col_comp in get_id_like_columns(list(cons_comp.columns)):
                print(f"{tag} column: {col} in cons when compared to {col_comp} in cons_{tag}")
                comp_max = cons_comp[col_comp].max()
                comp_min = cons_comp[col_comp].min()
                comp_un = cons_comp[col_comp].nunique()
                comp_set = set(cons_comp[col_comp].unique())
                print(f"{tag} column (len {len(cons_comp)}): {col_comp} has a maximum of {comp_max} and a minimum of {comp_min} and {comp_un} unique values")
                cons_in_comp = len(cons_set.difference(comp_set))
                print(f" - Of {cons_un} unique in cons file, there are {cons_in_comp} that are not in this column of the {tag} file")
                comp_in_cons = len(comp_set.difference(cons_set))
                print(f" - Of {comp_un} unique in {tag} file, there are {comp_in_cons} that are not in this column of the cons file")
                print("")

    comparison_to_cons(cons_email,"Email")
    print("\n\n\n")
    comparison_to_cons(cons_sub, "sub")


import unittest

from ..utils import check_for_torch_backend

class FocalLossTestPyTorch(unittest.TestCase):

    @unittest.skipUnless(check_for_torch_backend(),
                         reason="No torch backend installed")
    def test_focalloss(self):
        """
        Test some predefines focal loss values
        """

        from delira.training.losses import BCEFocalLossLogitPyTorch, \
            BCEFocalLossPyTorch
        import torch.nn as nn
        import torch
        import torch.nn.functional as F

        # examples
        #######################################################################
        # binary values
        p = torch.Tensor([[0, 0.2, 0.5, 1.0], [0, 0.2, 0.5, 1.0]])
        t = torch.Tensor([[0, 0, 0, 0], [1, 1, 1, 1]])
        p_l = torch.Tensor([[-2, -1, 0, 2], [-2, -1, 0, 1]])

        #######################################################################
        # params
        gamma = 2
        alpha = 0.25
        eps = 1e-8

        #######################################################################
        # compute targets
        # target for focal loss
        p_t = p * t + (1 - p) * (1 - t)
        alpha_t = torch.Tensor([alpha]).expand_as(t) * t + \
            (1 - t) * (1 - torch.Tensor([alpha]).expand_as(t))
        w = alpha_t * (1 - p_t).pow(torch.Tensor([gamma]))
        fc_value = F.binary_cross_entropy(p, t, w, reduction='none')

        # target for focal loss with logit
        p_tmp = torch.sigmoid(p_l)
        p_t = p_tmp * t + (1 - p_tmp) * (1 - t)
        alpha_t = torch.Tensor([alpha]).expand_as(t) * t + \
            (1 - t) * (1 - torch.Tensor([alpha]).expand_as(t))
        w = alpha_t * (1 - p_t).pow(torch.Tensor([gamma]))

        fc_value_logit = \
            F.binary_cross_entropy_with_logits(p_l, t, w, reduction='none')

        #######################################################################
        # test against BCE and CE =>focal loss with gamma=0, alpha=None
        # test against binary_cross_entropy
        bce = nn.BCELoss(reduction='none')
        focal = BCEFocalLossPyTorch(alpha=None, gamma=0, reduction='none')
        bce_loss = bce(p, t)
        focal_loss = focal(p, t)

        self.assertTrue((torch.abs(bce_loss - focal_loss) < eps).all())

        # test against binary_cross_entropy with logit
        bce = nn.BCEWithLogitsLoss()
        focal = BCEFocalLossLogitPyTorch(alpha=None, gamma=0)
        bce_loss = bce(p_l, t)
        focal_loss = focal(p_l, t)
        self.assertTrue((torch.abs(bce_loss - focal_loss) < eps).all())

        #######################################################################
        # test focal loss with pre computed values
        # test focal loss binary (values manually pre computed)
        focal = BCEFocalLossPyTorch(gamma=gamma, alpha=alpha, reduction='none')
        focal_loss = focal(p, t)
        self.assertTrue((torch.abs(fc_value - focal_loss) < eps).all())

        # test focal loss binary with logit (values manually pre computed)
        # Note that now p_l is used as prediction
        focal = BCEFocalLossLogitPyTorch(
            gamma=gamma, alpha=alpha, reduction='none')
        focal_loss = focal(p_l, t)
        self.assertTrue((torch.abs(fc_value_logit - focal_loss) < eps).all())

        #######################################################################
        # test if backward function works
        p.requires_grad = True
        focal = BCEFocalLossPyTorch(gamma=gamma, alpha=alpha)
        focal_loss = focal(p, t)
        try:
            focal_loss.backward()
        except BaseException:
            self.assertTrue(False, "Backward function failed for focal loss")

        p_l.requires_grad = True
        focal = BCEFocalLossLogitPyTorch(gamma=gamma, alpha=alpha)
        focal_loss = focal(p_l, t)
        try:
            focal_loss.backward()
        except BaseException:
            self.assertTrue(
                False, "Backward function failed for focal loss with logits")

if __name__ == "__main__":
    unittest.main()


def bubbleSort(lista):
    recorrer_array = True
    pos = 0
    aux = 0
    while recorrer_array == True:
        recorrer_array = False
        while pos < len(lista) - 1:
            if lista[pos] > lista[pos + 1]:
                aux = lista[pos]
                lista[pos] = lista[pos + 1]
                lista[pos + 1] = aux

                recorrer_array = True
            pos += 1
        pos = 0
    return lista

if __name__ == "__main__":

    # TEST CASES #

    assert bubbleSort([13,76,54,34,23,67,89]) == [13,23,34,54,67,76,89]
    assert bubbleSort([10,2,4,7,99]) == [2,4,7,10,99]
    assert bubbleSort(['a', 'u', 'i', 'e', 'o']) == sorted(['a', 'u', 'i', 'e', 'o'])
    assert bubbleSort(['spam', 'ham', 'elmo']) == sorted(['spam', 'ham', 'elmo'])
    assert bubbleSort(['a', 'b', 'A', 'd', 'c', 'P']) == sorted(['a', 'b', 'A', 'd', 'c', 'P'])
    assert bubbleSort([1.4, 5, 3, 3.5, 2, 4.1]) == sorted([1.4, 5, 3, 3.5, 2, 4.1])


def toInteger(array):

    for i in range(len(array)):

        array[i] = int(array[i])

def getValues(array, processingPoints, tests, minimumStick):

    stickCounter = 0

    elementSum = 0

    for i in range(processingPoints):

        for j in range(tests):

            elementSum += array[j][i]

            if array[j][i] == 0:

                if elementSum >= minimumStick:

                    stickCounter += 1

                elementSum = 0

        if(elementSum >= minimumStick):

            stickCounter += 1

        elementSum = 0

    return stickCounter

while(True):

    values = input().split()

    toInteger(values)

    if(sum(values)) == 0:

        break

    vector = [None] * values[1]

    for i in range(values[1]):

        raw = input().split()

        toInteger(raw)

        vector[i] = raw

    sticks = getValues(vector, values[0], values[1], values[2])

    print(sticks)


class Protocol:

    UNKNOWN = "p0"
    PLAYER_IS_REGISTERED = "p1"
    SYNC_SUCCESS = "p2"
    ALREADY_SYNCED = "p3"
    WRONG_CODE = "p4"
    USER_SEND_CODE = "p5"
    IS_PLAYER_REGISTERED = "p6"
    PLUGIN_GENERATED_CODE = "p7"
    PLAYER_LEFT = "p8"
    PLAYER_JOINED = "p9"
    HANDSHAKE = "p10"
    USER_JOINED_VOICE = "p11"
    USER_UNMUTED_HEADPHONES = "p12"
    USER_UNMUTED_MIC = "p13"
    USER_END_STREAM = "p14"
    USER_START_STREAM = "p15"
    USER_MUTED_HEADPHONES = "p16"
    USER_MUTED_MIC = "p17"
    USER_LEFT_VOICE = "p18"
    UNATTACH = "p19"