import logging
import numpy as np
import glob
import os
import h5py
import warnings

from intan2kwik.core.h5 import tables
from intan2kwik.core import reading
#from intan2kwik.core.reading import rh_search_string

logger = logging.getLogger('intan2kwik.kwd')

def h5_unicode_hack(x):
    if isinstance(x, str):
        x = x.encode('utf8')
    return x

def list_chan_names(header, include_channels):
    ch_groups = [c + '_channels' for c in include_channels]

    c_names = []
    for chgrp in ch_groups:
        ch_list = header[chgrp]
        c_names += [ch['custom_channel_name'] for ch in ch_list]
    return c_names

def list_chan_bit_volts(header, include_channels):
    v_multipliers = [0.195, 50.354e-6]
    if header['eval_board_mode'] == 1:
        v_multipliers[1] = 152.59e-6

    ch_groups = [c + '_channels' for c in include_channels]
    b_volts = []

    for chgrp in ch_groups:
        ch_list = header[chgrp]
        if 'adc' in chgrp:
            b_value = v_multipliers[1]
        elif 'amplifier' in chgrp:
            b_value = v_multipliers[0]
        b_volts += [b_value for ch in ch_list]

    return np.array(b_volts, dtype=np.float)

def rhd_data_block(rhd_file, include_chans, times_too=False):
    read_block = reading.read_data(rhd_file)
    # identify channels, make numy array with all the block and a list of metadata for each
    block_data = np.vstack([read_block['{}_data'.format(ch_grp)] for ch_grp in include_chans])
    block_t = np.vstack([read_block['t_{}'.format(ch_grp)] for ch_grp in include_chans])

    if times_too:
        ret_value = (block_data, block_t)
    else:
        ret_value = block_data

    return ret_value

def rhd_rec_to_table(rhd_list, parent_group, chan_groups_wishlist):
    '''
    :param rhd_list: (list of strings) paths of files to include in this rec
    :param parent_group: (h5 object group) parent group for this rec
    :param chan_groups_wishlist: (flat ndarray/list) channel groups to get from the rhd files
    :return:
    '''
    # make the table
    # read the blocks and append them to the table
    # set the attributes of the table
    logger.info('Appending {} files to data table in {}'.format(len(rhd_list),
                                                                parent_group))

    total_samples_in = 0
    total_samples_in_dig =0

    last_t = 0
    s_f = parent_group.attrs.get('sample_rate')

    for i, rhd_file in enumerate(rhd_list):
        logger.info('Reading file {0}/{1}'.format(i+1, len(rhd_list)))
        read_block = reading.read_data(rhd_file)
        if i == 0:
            # filter include groups, warn if a group wasn't in the data and remove it from the list
            include_chan_groups = []
            for g in chan_groups_wishlist:
                if '{}_data'.format(g) in read_block.keys():
                    include_chan_groups.append(g)
                else:
                    logger.warn('Channel data group {} is not in the recordings'.format(g))
        # The main data (neural chans and dac chans; from include_chans)
        block_data = np.vstack([read_block['{}_data'.format(ch_grp)] for ch_grp in include_chan_groups])
        block_t = np.vstack([read_block['t_{}'.format(ch_grp)] for ch_grp in include_chan_groups])
        save_block = block_data.T.astype(np.int32) - 32768
        # assuming the first block in include_chans is amplifier
        save_t = block_t[0].reshape([-1, 1])
        name_t = 't_{}'.format(include_chan_groups[0])

        # The digital channels

        try:
            dig_in_data = read_block['board_dig_in_data'].T.astype(np.short)
            dig_in_t = read_block['t_dig'].reshape([-1, 1])
            has_digital_in = True
        except KeyError as k:
            logger.warn('No digital channels')
            has_digital_in = False

        # data comes in as uint16
        if i == 0:
            logger.info('Creating tables of neural/adc data')
            dset = tables.unlimited_rows_data(parent_group, 'data',
                                              save_block.astype(np.int16))
            tset = tables.unlimited_rows_data(parent_group, name_t, save_t)

            if has_digital_in:
                logger.info('Creating tables of digital data')
                dset_dig = tables.unlimited_rows_data(parent_group, 'dig_in',
                                                      dig_in_data.astype(np.short))
                tset_dig = tables.unlimited_rows_data(parent_group, 't_dig', dig_in_t)

        else:
            tables.append_rows(dset, save_block.astype(np.int16))
            tables.append_rows(tset, save_t)

            if has_digital_in:
                tables.append_rows(dset_dig, dig_in_data.astype(np.short))
                tables.append_rows(tset_dig, dig_in_t)

            # assert time continuity
            more_control_d_samples = (save_t[0] * s_f - total_samples_in)
            logger.info('Delta cum_samples/cum_t is {}'.format(more_control_d_samples))

            control_dt = save_t[0] - last_t
            control_delta_samples = int(np.round(control_dt * s_f))
            # logger.info('Delta samples between rhd files is {}'.format(control_delta_samples))
            if not control_delta_samples == 1:
                warn_msg = 'Skipped a beat i rhd files diff is {}s'.format(control_dt)
                warnings.warn(warn_msg, RuntimeWarning)

        last_t = save_t[-1]
        total_samples_in += save_block.shape[0]

        if has_digital_in:
            last_t_dig = dig_in_t[-1]
            total_samples_in_dig += last_t_dig.shape[0]

    # only atrribute for table is valid_samples
    dset.attrs.create('valid_samples', np.ones(save_block.shape[1]) * total_samples_in)

    if has_digital_in:
        dset_dig.attrs.create('valid_samples', np.ones(dig_in_data.shape[1]) * total_samples_in_dig)

def create_data_grp(rec_grp, intan_hdr, include_channels, rec):
    logger.debug('Creating data group for this rec {}'.format(rec))

    data_grp = rec_grp.create_group('{}'.format(rec))
    # append the metadata to this data group
    data_grp.attrs.create('bit_depth', 16)
    data_grp.attrs.create('sample_rate', intan_hdr['sample_rate'])
    data_grp.attrs.create('name', rec)
    data_grp.attrs.create('start_sample', 0)
    data_grp.attrs.create('start_time', 1)

    all_chan_names = list_chan_names(intan_hdr, include_channels)
    all_chan_names_uni = [h5_unicode_hack(x) for x in all_chan_names]
    all_bit_volts = list_chan_bit_volts(intan_hdr, include_channels)
    n_chan = len(all_chan_names)
    all_rates = np.ones(n_chan) * intan_hdr['sample_rate']

    # create application data
    app_data_grp = data_grp.create_group('application_data')
    app_data_grp.attrs.create('is_multiSampleRate_data', 0)
    app_data_grp.attrs.create('channels_sample_rate', all_rates)
    app_data_grp.attrs.create('channel_bit_volts', all_bit_volts)
    app_data_grp.attrs.create('channel_names', all_chan_names_uni)

    return data_grp

def which_board(folder):
    rhx_files = glob.glob(os.path.join(folder, '*.rh[d,s]'))
    if len(rhx_files) < 1:
        raise RuntimeError('No .rh[d, x] found in folder {}'.format(folder))
    return os.path.split(rhx_files[0])[-1].split('.')[-1]

def neural_ports_meta(folder):
    """
    :param folder: (string) folder with .rh? files
    :return: (tuple) of dictionaries:
        chans: {port: list of channels}
        count: {port: channel count
    """
    board = which_board(folder)
    all_rhx_files = glob.glob(os.path.join(folder, '*.{}'.format(board)))
    all_rhx_files.sort()
    intan_read = reading.read_data(all_rhx_files[0])
    chans, count = used_neural_channels(intan_read)
    return chans, count

def intan_to_kwd(folder, dest_file_path, rec=0, include_channels=None, board='auto'):
    """
    :param folder: (string) folder where the .rh? files are
    :param dest_file_path: (string) dest of the kw? files
    :param rec: (int)
    :param include_channels: (flat ndarray/list)
    :param board: (str) 'rhd' or 'rhs' for rhd2000 or rhs2000, 'auto' for detecting from extension
    :return:
    """
    # make the .kwd file
    # make the /recording/0 group
    # dump header to application data
    # run rhd_rec_to table to create the table in the group
    if include_channels is None:
        include_channels = ['amplifier', 'board_adc']
    logger.info('reading intan chans data across all of rec {0}'.format(folder))

    if board=='auto':
        board = which_board(folder)
    all_rhx_files = glob.glob(os.path.join(folder, '*.{}'.format(board)))
    all_rhx_files.sort()
    logger.info('Found {} .{} files to process'.format(len(all_rhx_files), board))

    # attributes from the header
    first_header = reading.read_intan_header(all_rhx_files[0])
    # logger.info('First header {}'.format(first_header))
    v_multipliers = [0.195, 50.354e-6]
    if first_header['eval_board_mode'] == 1:
        v_multipliers[1] = 152.59e-6

    # chan_names =

    # list all the chunk files:
    logger.debug('dest file: {}'.format(dest_file_path))
    with h5py.File(dest_file_path, 'a') as kwd_file:
        logger.debug('Creating the /recordings/{}'.format(rec))
        rec_grp = kwd_file.require_group('recordings')
        data_grp = create_data_grp(rec_grp, first_header, include_channels, rec)
        # create application data with all metadata
        logger.debug('Creating data table and going throug the recs')
        rhd_rec_to_table(all_rhx_files, data_grp, include_channels)

    return first_header


#!/usr/bin/env python
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import tasks
import sys
import run_model

def plot(seq_length):
    i, o = tasks.copy(8, seq_length)
    weights, outputs = do_task(i)
    plt.figure(1, figsize=(20, 7))
    plt.subplot(311)
    plt.imshow(i.T, interpolation='nearest')
    plt.subplot(312)
    plt.imshow(o.T, interpolation='nearest')
    plt.subplot(313)
    plt.imshow(outputs.T, interpolation='nearest')
    plt.show()

def plot_weights(seq_length):
    i, o = tasks.copy(8, seq_length)
    weights, outputs = do_task(i)
    plt.figure(1, figsize=(20, 20))
    plt.imshow(weights.T[100:123], interpolation='nearest', cmap=cm.gray)
    plt.show()

if __name__ == "__main__":
    P, do_task = run_model.make_model()
    P.load('l2_low_learning_rate.mdl')
    plot(130)
    # plot_weights(8)


import sys
from typing import IO, Tuple, Callable, Dict, Any, Optional
import spacy
from spacy import Language
from pathlib import Path

@spacy.registry.loggers("custom_logger.v1")
def custom_logger(log_path):
    def setup_logger(
        nlp: Language,
        stdout: IO=sys.stdout,
        stderr: IO=sys.stderr
    ) -> Tuple[Callable, Callable]:
        stdout.write(f"Logging to {log_path}\n")
        log_file = Path(log_path).open("w", encoding="utf8")
        log_file.write("step\t")
        log_file.write("score\t")
        for pipe in nlp.pipe_names:
            log_file.write(f"loss_{pipe}\t")
        log_file.write("\n")

        def log_step(info: Optional[Dict[str, Any]]):
            if info:
                log_file.write(f"{info['step']}\t")
                log_file.write(f"{info['score']}\t")
                for pipe in nlp.pipe_names:
                    log_file.write(f"{info['losses'][pipe]}\t")
                log_file.write("\n")

        def finalize():
            log_file.close()

        return log_step, finalize

    return setup_logger


import torch
import torch.nn as nn
from model import TextCNN, TextRNN, RNN_Attention, bert

class Ensemble(nn.Module):
    def __init__(self, config):
        super(Ensemble, self).__init__()
        self.config = config

        self.TextCNN = TextCNN.TextCNN(config)
        self.bert = bert.BERT(config)

        num_class = 23
        # dim_embedding = args.CNN_dim_embedding * 8 + args.RNN_dim_embedding * 2 * 2 + args.d_model
        dim_embedding = 128 + 768

        # print('dim_embedding', dim_embedding)
        self.linear1 = nn.Linear(dim_embedding, dim_embedding // 2)
        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()
        self.leakyrelu = nn.LeakyReLU()
        self.linear2 = nn.Linear(dim_embedding // 2, num_class)

    def forward(self, data):
        _, TextCNN_embedding = self.TextCNN(data)
        bert_embedding = self.bert(data)["pooler_output"]

        # embeddings = [embedding1, embedding2, embedding3, embedding4]
        embeddings = [TextCNN_embedding, bert_embedding]

        # print('input_ids', input_ids.size())
        # print('embedding1', embedding1.size())
        # print('embedding2', embedding2.size())

        embeddings = torch.cat(embeddings, dim=-1)
        # print('embeddings', embeddings.size())

        out = self.linear1(embeddings)
        out = self.leakyrelu(out)
        logits = self.linear2(out)
        return logits, bert_embedding


import zipfile
import os
import shutil
import sys
import time

# Function to get the directory that this script resides in to use as cwd
def get_script_path():
    return os.path.dirname(os.path.realpath(sys.argv[0]))
cwd = get_script_path()

assignment = "lab02"
extensionLookingFor = ".java"
# Set up our folders to work from our current working directory
fromFolder = cwd+"/"+"submissions"+assignment
extractedFolder = cwd+"/"+"submissionsExtracted"+assignment
outFolder = cwd+"/"+assignment+"FilesMOSS"

# print(cwd)
# If output files have already been generated then delete them and their contents
try:
    shutil.rmtree(outFolder)
    shutil.rmtree(extractedFolder)
except:
    pass

os.makedirs(extractedFolder) # create folder for unziped files
os.makedirs(outFolder) #create output folder
# cwd = os.getcwd() #find current working directory

'''
Function that finds the paths to all the files in a given folder with a certian extension and returns the paths
Params:
    filepath: path to folder to search
    filetype: file extension that we want to search for
'''
def list_files(filepath, filetype):
   paths = []
   for root, dirs, files in os.walk(filepath):
      for file in files:
         if file.lower().endswith(filetype.lower()):
            paths.append(os.path.join(root, file))
   return(paths)

'''
Function that unzips all the files in the submission folder and puts them in the extractedFolder sorted into folders by student name
'''
def unzipFiles():
    for folder in os.listdir(fromFolder):
        if folder.endswith(".zip"):
            studentName = folder.split("_", 1)[0] #get student name
            try:
                with zipfile.ZipFile(fromFolder+"/"+folder, "r") as zip_ref:
                    zip_ref.extractall(extractedFolder+"/"+studentName+"/")
            except:
                print("Bad zip: "+studentName)

'''
Function that finds the java files in each student folder in our extractedFolder and copies them to our output folder and prepends the students name on the file name
'''
def copyFiles():
    files = list_files(extractedFolder, ".java")
    for file in files:
        if file.endswith(extensionLookingFor) and file.find("MACOSX") == -1:
            extractedFolderPlus = extractedFolder +"\\"
            start = file.find(extractedFolderPlus) + len(extractedFolderPlus)
            end = file.find("\\", start)
            nameOfStudent = file[start:end]
            nameOfFile = file.rsplit("\\", 1)[1]
            shutil.copy2(file, outFolder+"/"+nameOfStudent+"_"+nameOfFile)

unzipFiles()
copyFiles()


import logging
import logging
import multiprocessing
import os
import pathlib
import pickle
import time
import zipfile
from pathlib import Path

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
import yaml
from sklearn.preprocessing import OneHotEncoder
from torch.nn.utils.rnn import pad_sequence
from torch.utils.data import Dataset, DataLoader
from tqdm import tqdm

from dataloader import load_graph_adj_mtx, load_graph_node_features
from model import GCN, NodeAttnMap, UserEmbeddings, Time2Vec, CategoryEmbeddings, FuseEmbeddings, TransformerModel, \
    GraphSage,GRUModel
from param_parser import parameter_parser
from utils import increment_path, calculate_laplacian_matrix, zipdir, top_k_acc_last_timestep, \
    mAP_metric_last_timestep, MRR_metric_last_timestep, maksed_mse_loss, adj_list, split_list, random_walk_with_restart,\
    split_list_by_ratio

def train(args):
    args.save_dir = increment_path(Path(args.project) / args.name, exist_ok=args.exist_ok, sep='-')
    if not os.path.exists(args.save_dir): os.makedirs(args.save_dir)

    # Setup logger
    for handler in logging.root.handlers[:]:
        logging.root.removeHandler(handler)
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        filename=os.path.join(args.save_dir, f"log_training.txt"),
                        filemode='w')
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
    console.setFormatter(formatter)
    logging.getLogger('').addHandler(console)
    logging.getLogger('matplotlib.font_manager').disabled = True

    # Save run settings
    logging.info(args)
    with open(os.path.join(args.save_dir, 'args.yaml'), 'w') as f:
        yaml.dump(vars(args), f, sort_keys=False)

    # Save python code
    zipf = zipfile.ZipFile(os.path.join(args.save_dir, 'code.zip'), 'w', zipfile.ZIP_DEFLATED)
    zipdir(pathlib.Path().absolute(), zipf, include_format=['.py'])
    zipf.close()

    # %% ====================== Load data ======================
    # Read check-in train data
    train_df = pd.read_csv(args.data_train)
    val_df = pd.read_csv(args.data_val)
    if args.data_train!='dataset/dataset_tsmc2014/NYC_train.csv':
        train_df['timestamp'] = pd.to_datetime(train_df['local_time']).astype('int64') // 10 ** 9
        val_df['timestamp'] = pd.to_datetime(val_df['local_time']).astype('int64') // 10 ** 9

    # Build POI graph (built from train_df)
    print('Loading POI graph...')
    raw_A = load_graph_adj_mtx(args.data_adj_mtx)
    raw_X = load_graph_node_features(args.data_node_feats,
                                     args.feature1,
                                     args.feature2,
                                     args.feature3,
                                     args.feature4)
    logging.info(
        f"raw_X.shape: {raw_X.shape}; "
        f"Four features: {args.feature1}, {args.feature2}, {args.feature3}, {args.feature4}.")
    logging.info(f"raw_A.shape: {raw_A.shape}; Edge from row_index to col_index with weight (frequency).")
    num_pois = raw_X.shape[0]

    # One-hot encoding poi categories
    logging.info('One-hot encoding poi categories id')
    one_hot_encoder = OneHotEncoder()
    cat_list = list(raw_X[:, 1])
    one_hot_encoder.fit(list(map(lambda x: [x], cat_list)))
    one_hot_rlt = one_hot_encoder.transform(list(map(lambda x: [x], cat_list))).toarray()
    num_cats = one_hot_rlt.shape[-1]
    X = np.zeros((num_pois, raw_X.shape[-1] - 1 + num_cats), dtype=np.float32)
    X[:, 0] = raw_X[:, 0]
    X[:, 1:num_cats + 1] = one_hot_rlt
    X[:, num_cats + 1:] = raw_X[:, 2:]
    logging.info(f"After one hot encoding poi cat, X.shape: {X.shape}")
    logging.info(f'POI categories: {list(one_hot_encoder.categories_[0])}')
    # Save ont-hot encoder
    with open(os.path.join(args.save_dir, 'one-hot-encoder.pkl'), "wb") as f:
        pickle.dump(one_hot_encoder, f)

    # Normalization
    print('Laplician matrix...')
    A = calculate_laplacian_matrix(raw_A, mat_type='hat_rw_normd_lap_mat')

    # POI id to index
    nodes_df = pd.read_csv(args.data_node_feats)
    poi_ids = nodes_df['node_name/poi_id'].tolist()
    poi_id2idx_dict = dict(zip(poi_ids, range(len(poi_ids))))

    # Cat id to index
    cat_ids = list(set(nodes_df[args.feature2].tolist()))
    cat_id2idx_dict = dict(zip(cat_ids, range(len(cat_ids))))

    # Poi idx to cat idx
    poi_idx2cat_idx_dict = {}
    for i, row in nodes_df.iterrows():
        poi_idx2cat_idx_dict[poi_id2idx_dict[row['node_name/poi_id']]] = \
            cat_id2idx_dict[row[args.feature2]]

    # User id to index
    user_ids = [str(each) for each in list(set(train_df['user_id'].to_list()))]
    user_id2idx_dict = dict(zip(user_ids, range(len(user_ids))))

    # Print user-trajectories count
    traj_list = list(set(train_df['trajectory_id'].tolist()))
    print('load adj_list')
    if os.path.exists(os.path.join(args.adj_path, 'adj.pkl')):
        with open(os.path.join(args.adj_path, 'adj.pkl'), 'rb') as f:  # 打开pickle文件
            adj = pickle.load(f)  # 读取字典
        with open(os.path.join(args.adj_path, 'dis.pkl'), 'rb') as f:  # 打开pickle文件
            dis = pickle.load(f)  # 读取字典
    else:
        adj, dis = adj_list(raw_A, raw_X, args.geo_dis)
        with open(os.path.join(args.adj_path, 'adj.pkl'), 'wb') as f:
            pickle.dump(adj, f)  # 把字典写入pickle文件
        with open(os.path.join(args.adj_path, 'dis.pkl'), 'wb') as f:
            pickle.dump(dis, f)  # 把字典写入pickle文件

    # %% ====================== Define Dataset ======================
    class TrajectoryDatasetTrain(Dataset):
        def __init__(self, train_df):
            self.df = train_df
            self.traj_seqs = []  # traj id: user id + traj no.
            self.input_seqs = []
            self.label_seqs = []

            for traj_id in tqdm(set(train_df['trajectory_id'].tolist())):
                traj_df = train_df[train_df['trajectory_id'] == traj_id]
                poi_ids = traj_df['POI_id'].to_list()
                poi_idxs = [poi_id2idx_dict[each] for each in poi_ids]
                time_feature = traj_df[args.time_feature].to_list()
                ts = traj_df['timestamp'].to_list()

                input_seq = []
                label_seq = []
                for i in range(len(poi_idxs) - 1):
                    input_seq.append((poi_idxs[i], time_feature[i],ts[i]))
                    label_seq.append((poi_idxs[i + 1], time_feature[i + 1],ts[i+1]))

                if len(input_seq) < args.short_traj_thres:
                    continue

                self.traj_seqs.append(traj_id)
                self.input_seqs.append(input_seq)
                self.label_seqs.append(label_seq)

        def __len__(self):
            assert len(self.input_seqs) == len(self.label_seqs) == len(self.traj_seqs)
            return len(self.traj_seqs)

        def __getitem__(self, index):
            return (self.traj_seqs[index], self.input_seqs[index], self.label_seqs[index])

    class TrajectoryDatasetVal(Dataset):
        def __init__(self, df):
            self.df = df
            self.traj_seqs = []
            self.input_seqs = []
            self.label_seqs = []

            for traj_id in tqdm(set(df['trajectory_id'].tolist())):
                user_id = traj_id.split('_')[0]

                # Ignore user if not in training set
                if user_id not in user_id2idx_dict.keys():
                    continue

                # Ger POIs idx in this trajectory
                traj_df = df[df['trajectory_id'] == traj_id]
                poi_ids = traj_df['POI_id'].to_list()
                poi_idxs = []
                time_feature = traj_df[args.time_feature].to_list()
                ts = traj_df['timestamp'].to_list()

                for each in poi_ids:
                    if each in poi_id2idx_dict.keys():
                        poi_idxs.append(poi_id2idx_dict[each])
                    else:
                        # Ignore poi if not in training set
                        continue

                # Construct input seq and label seq
                input_seq = []
                label_seq = []
                for i in range(len(poi_idxs) - 1):
                    input_seq.append((poi_idxs[i], time_feature[i],ts[i]))
                    label_seq.append((poi_idxs[i + 1], time_feature[i + 1],ts[i+1]))

                # Ignore seq if too short
                if len(input_seq) < args.short_traj_thres:
                    continue

                self.input_seqs.append(input_seq)
                self.label_seqs.append(label_seq)
                self.traj_seqs.append(traj_id)

        def __len__(self):
            assert len(self.input_seqs) == len(self.label_seqs) == len(self.traj_seqs)
            return len(self.traj_seqs)

        def __getitem__(self, index):
            return (self.traj_seqs[index], self.input_seqs[index], self.label_seqs[index])

    # %% ====================== Define dataloader ======================
    print('Prepare dataloader...')
    train_dataset = TrajectoryDatasetTrain(train_df)
    val_dataset = TrajectoryDatasetVal(val_df)

    train_loader = DataLoader(train_dataset,
                              batch_size=args.batch,
                              shuffle=True, drop_last=False,
                              pin_memory=True, num_workers=args.workers,
                              collate_fn=lambda x: x)
    val_loader = DataLoader(val_dataset,
                            batch_size=args.batch,
                            shuffle=False, drop_last=False,
                            pin_memory=True, num_workers=args.workers,
                            collate_fn=lambda x: x)

    class produceSampleProcess(multiprocessing.Process):
        def __init__(self, tasks, queues, adj_list, restart_prob, num_walks, threshold, adjOrdis, stop_event, id):
            super().__init__()
            self.tasks = tasks
            self.queues = queues
            self.threshold = threshold
            self.adjOrdis = adjOrdis
            self.stop_event = stop_event
            self.id = id
            self.adj_list = adj_list
            self.restart_prob = restart_prob
            self.num_walks = num_walks
            self.count_dict={key:threshold for key in tasks}
            self.missing_dict={key:0 for key in tasks}

        def run(self):
            while True:
                for node in self.tasks:
                    q = self.queues[node]
                    if q.qsize() < self.threshold/2:
                        for _ in range(self.count_dict[node]-q.qsize()):
                            random_walk = random_walk_with_restart(self.adj_list, node, self.restart_prob, self.num_walks,
                                                               self.adjOrdis)
                            q.put(random_walk)
                        self.missing_dict[node]+=1
                        if self.missing_dict[node]>2:
                            self.missing_dict[node]=0
                            self.count_dict[node]+=self.threshold
                if self.stop_event.is_set():
                    break
            print(self.adjOrdis, self.id, 'quit')

    threshold = 10  # 队列大小阈值
    adj_queues = {node: multiprocessing.Queue() for node in range(num_pois)}  # 创建多个队列
    dis_queues = {node: multiprocessing.Queue() for node in range(num_pois)}  # 创建多个队列
    tasks = split_list([i for i in range(num_pois)],int(args.cpus/2))
    stop_event = multiprocessing.Event()

    for idx, task in enumerate(tasks):
        ap = produceSampleProcess(tasks=task, queues=adj_queues, adj_list=adj, restart_prob=args.restart_prob,
                                  num_walks=args.num_walks,
                                  threshold=threshold, adjOrdis='adj', stop_event=stop_event, id=idx)
        ap.start()
        dp = produceSampleProcess(tasks=task, queues=dis_queues, adj_list=dis, restart_prob=args.restart_prob,
                                  num_walks=args.num_walks,
                                  threshold=threshold, adjOrdis='dis', stop_event=stop_event, id=idx)
        dp.start()

    # %% ====================== Build Models ======================
    # Model1: POI embedding model
    if isinstance(X, np.ndarray):
        X = torch.from_numpy(X)
        A = torch.from_numpy(A)
    X = X.to(device=args.device, dtype=torch.float)
    A = A.to(device=args.device, dtype=torch.float)

    poi_embed_model = GraphSage(X=X,  embed_dim=args.poi_embed_dim, adj=adj, dis=dis,
                                device=args.device, restart_prob=args.restart_prob, num_walks=args.num_walks,
                                dropout=args.dropout, adj_queues=adj_queues, dis_queues=dis_queues)

    # %% Model2: User embedding model, nn.embedding
    num_users = len(user_id2idx_dict)
    user_embed_model = UserEmbeddings(num_users, args.user_embed_dim)

    # %% Model3: Time Model
    time_embed_model = Time2Vec('sin', out_dim=args.time_embed_dim)

    # %% Model4: Category embedding model
    cat_embed_model = CategoryEmbeddings(num_cats, args.cat_embed_dim)

    # %% Model5: Embedding fusion models
    embed_fuse_model1 = FuseEmbeddings(args.user_embed_dim, args.poi_embed_dim)
    embed_fuse_model2 = FuseEmbeddings(args.time_embed_dim, args.cat_embed_dim)

    # %% Model6: Sequence model
    args.seq_input_embed = args.poi_embed_dim + args.user_embed_dim + args.time_embed_dim + args.cat_embed_dim
    seq_model = TransformerModel(num_pois,
                                 num_cats,
                                 args.seq_input_embed,
                                 args.transformer_nhead,
                                 args.transformer_nhid,
                                 args.transformer_nlayers,
                                 dropout=args.transformer_dropout)

    # Define overall loss and optimizer
    optimizer = optim.Adam(params=list(poi_embed_model.parameters()) +
                                  list(user_embed_model.parameters()) +
                                  list(time_embed_model.parameters()) +
                                  list(cat_embed_model.parameters()) +
                                  list(embed_fuse_model1.parameters()) +
                                  list(embed_fuse_model2.parameters()) +
                                  list(seq_model.parameters()),
                           lr=args.lr,
                           weight_decay=args.weight_decay)

    criterion_poi = nn.CrossEntropyLoss(ignore_index=-1)  # -1 is padding
    criterion_cat = nn.CrossEntropyLoss(ignore_index=-1)  # -1 is padding
    criterion_time = maksed_mse_loss

    lr_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
        optimizer, 'min', verbose=True, factor=args.lr_scheduler_factor)

    # %% Tool functions for training
    def input_traj_to_embeddings(sample, poi_embeddings, embedding_index):
        # Parse sample
        traj_id = sample[0]
        input_seq = [each[0] for each in sample[1]]
        input_seq_time = [each[1] for each in sample[1]]
        input_seq_cat = [poi_idx2cat_idx_dict[each] for each in input_seq]

        # User to embedding
        user_id = traj_id.split('_')[0]
        user_idx = user_id2idx_dict[user_id]
        input = torch.LongTensor([user_idx]).to(device=args.device)
        user_embedding = user_embed_model(input)
        user_embedding = torch.squeeze(user_embedding)

        poi_idxs=[embedding_index+idx for idx in range(len(input_seq))]
        sample_poi_embedding=poi_embeddings[poi_idxs].squeeze()
        sample_time_embedding=time_embed_model(torch.tensor(input_seq_time,dtype=torch.float).to(device=args.device)).squeeze()
        sample_cat_embedding=cat_embed_model(torch.tensor(input_seq_cat,dtype=torch.long).to(device=args.device)).squeeze()
        sample_fused_embedding1=embed_fuse_model1(user_embedding.expand(len(input_seq),-1),sample_poi_embedding)
        sample_fused_embedding2=embed_fuse_model2(sample_time_embedding,sample_cat_embedding)
        sample_concat_embedding=torch.cat((sample_fused_embedding1,sample_fused_embedding2),dim=-1)

        # POI to embedding and fuse embeddings
        '''
        input_seq_embed = []
        for idx in range(len(input_seq)):
            poi_embedding = poi_embeddings[embedding_index+idx]
            poi_embedding = torch.squeeze(poi_embedding).to(device=args.device)

            # Time to vector
            time_embedding = time_embed_model(
                torch.tensor([input_seq_time[idx]], dtype=torch.float).to(device=args.device))
            time_embedding = torch.squeeze(time_embedding).to(device=args.device)

            # Categroy to embedding
            cat_idx = torch.LongTensor([input_seq_cat[idx]]).to(device=args.device)
            cat_embedding = cat_embed_model(cat_idx)
            cat_embedding = torch.squeeze(cat_embedding)

            # Fuse user+poi embeds
            fused_embedding1 = embed_fuse_model1(user_embedding, poi_embedding)
            fused_embedding2 = embed_fuse_model2(time_embedding, cat_embedding)

            # Concat time, cat after user+poi
            concat_embedding = torch.cat((fused_embedding1, fused_embedding2), dim=-1)

            # Save final embed
            input_seq_embed.append(concat_embedding)
        '''
        return sample_concat_embedding

    # %% ====================== Train ======================
    poi_embed_model = poi_embed_model.to(device=args.device)
    user_embed_model = user_embed_model.to(device=args.device)
    time_embed_model = time_embed_model.to(device=args.device)
    cat_embed_model = cat_embed_model.to(device=args.device)
    embed_fuse_model1 = embed_fuse_model1.to(device=args.device)
    embed_fuse_model2 = embed_fuse_model2.to(device=args.device)
    seq_model = seq_model.to(device=args.device)

    # %% Loop epoch
    # For plotting
    train_epochs_top1_acc_list = []
    train_epochs_top5_acc_list = []
    train_epochs_top10_acc_list = []
    train_epochs_top20_acc_list = []
    train_epochs_mAP20_list = []
    train_epochs_mrr_list = []
    train_epochs_loss_list = []
    train_epochs_poi_loss_list = []
    train_epochs_time_loss_list = []
    train_epochs_cat_loss_list = []
    val_epochs_top1_acc_list = []
    val_epochs_top5_acc_list = []
    val_epochs_top10_acc_list = []
    val_epochs_top20_acc_list = []
    val_epochs_mAP20_list = []
    val_epochs_mrr_list = []
    val_epochs_loss_list = []
    val_epochs_poi_loss_list = []
    val_epochs_time_loss_list = []
    val_epochs_cat_loss_list = []
    # For saving ckpt
    max_val_score = -np.inf

    for epoch in range(args.epochs):
        logging.info(f"{'*' * 50}Epoch:{epoch:03d}{'*' * 50}\n")
        poi_embed_model.train()
        user_embed_model.train()
        time_embed_model.train()
        cat_embed_model.train()
        embed_fuse_model1.train()
        embed_fuse_model2.train()
        seq_model.train()

        train_batches_top1_acc_list = []
        train_batches_top5_acc_list = []
        train_batches_top10_acc_list = []
        train_batches_top20_acc_list = []
        train_batches_mAP20_list = []
        train_batches_mrr_list = []
        train_batches_loss_list = []
        train_batches_poi_loss_list = []
        train_batches_time_loss_list = []
        train_batches_cat_loss_list = []
        #src_mask = seq_model.generate_square_subsequent_mask(args.batch).to(args.device)
        # Loop batch
        for b_idx, batch in enumerate(train_loader):
            #if len(batch) != args.batch:
                #src_mask = seq_model.generate_square_subsequent_mask(len(batch)).to(args.device)

            # For padding
            batch_input_seqs = []
            batch_seq_lens = []
            batch_seq_embeds = []
            batch_seq_labels_poi = []
            batch_seq_labels_time = []
            batch_seq_labels_cat = []

            pois = [each[0] for sample in batch for each in sample[1]]
            poi_embeddings = poi_embed_model(torch.tensor(pois).to(args.device))
            # Convert input seq to embeddings

            embedding_index=0
            for sample in batch:
                # sample[0]: traj_id, sample[1]: input_seq, sample[2]: label_seq
                traj_id = sample[0]
                input_seq = [each[0] for each in sample[1]]
                label_seq = [each[0] for each in sample[2]]
                input_seq_time = [each[1] for each in sample[1]]
                label_seq_time = [each[1] for each in sample[2]]
                label_seq_cats = [poi_idx2cat_idx_dict[each] for each in label_seq]
                input_seq_embed = input_traj_to_embeddings(sample, poi_embeddings,embedding_index)
                batch_seq_embeds.append(input_seq_embed)
                batch_seq_lens.append(len(input_seq))
                batch_input_seqs.append(input_seq)
                batch_seq_labels_poi.append(torch.LongTensor(label_seq))
                batch_seq_labels_time.append(torch.FloatTensor(label_seq_time))
                batch_seq_labels_cat.append(torch.LongTensor(label_seq_cats))
                embedding_index+=len(input_seq)

            # Pad seqs for batch training
            batch_padded = pad_sequence(batch_seq_embeds, batch_first=True, padding_value=-1)
            label_padded_poi = pad_sequence(batch_seq_labels_poi, batch_first=True, padding_value=-1)
            label_padded_time = pad_sequence(batch_seq_labels_time, batch_first=True, padding_value=-1)
            label_padded_cat = pad_sequence(batch_seq_labels_cat, batch_first=True, padding_value=-1)

            # Feedforward
            x = batch_padded.to(device=args.device, dtype=torch.float)
            y_poi = label_padded_poi.to(device=args.device, dtype=torch.long)
            y_time = label_padded_time.to(device=args.device, dtype=torch.float)
            y_cat = label_padded_cat.to(device=args.device, dtype=torch.long)
            y_pred_poi, y_pred_time, y_pred_cat = seq_model(x)

            loss_poi = criterion_poi(y_pred_poi.transpose(1, 2), y_poi)
            loss_time = criterion_time(torch.squeeze(y_pred_time), y_time)
            loss_cat = criterion_cat(y_pred_cat.transpose(1, 2), y_cat)

            # Final loss
            loss = loss_poi + loss_time * args.time_loss_weight + loss_cat
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            # Performance measurement
            top1_acc = 0
            top5_acc = 0
            top10_acc = 0
            top20_acc = 0
            mAP20 = 0
            mrr = 0
            batch_label_pois = y_poi.detach().cpu().numpy()
            batch_pred_pois = y_pred_poi.detach().cpu().numpy()
            batch_pred_times = y_pred_time.detach().cpu().numpy()
            batch_pred_cats = y_pred_cat.detach().cpu().numpy()
            for label_pois, pred_pois, seq_len in zip(batch_label_pois, batch_pred_pois, batch_seq_lens):
                label_pois = label_pois[:seq_len]  # shape: (seq_len, )
                pred_pois = pred_pois[:seq_len, :]  # shape: (seq_len, num_poi)
                top1_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=1)
                top5_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=5)
                top10_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=10)
                top20_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=20)
                mAP20 += mAP_metric_last_timestep(label_pois, pred_pois, k=20)
                mrr += MRR_metric_last_timestep(label_pois, pred_pois)
            train_batches_top1_acc_list.append(top1_acc / len(batch_label_pois))
            train_batches_top5_acc_list.append(top5_acc / len(batch_label_pois))
            train_batches_top10_acc_list.append(top10_acc / len(batch_label_pois))
            train_batches_top20_acc_list.append(top20_acc / len(batch_label_pois))
            train_batches_mAP20_list.append(mAP20 / len(batch_label_pois))
            train_batches_mrr_list.append(mrr / len(batch_label_pois))
            train_batches_loss_list.append(loss.detach().cpu().numpy())
            train_batches_poi_loss_list.append(loss_poi.detach().cpu().numpy())
            train_batches_time_loss_list.append(loss_time.detach().cpu().numpy())
            train_batches_cat_loss_list.append(loss_cat.detach().cpu().numpy())

            # Report training progress
            if (b_idx % (40)) == 0:
                sample_idx = 0
                logging.info(f'Epoch:{epoch}, batch:{b_idx}, '
                             f'train_batch_loss:{loss.item():.2f}, '
                             f'train_batch_top1_acc:{top1_acc / len(batch_label_pois):.2f}, '
                             f'train_move_loss:{np.mean(train_batches_loss_list):.2f}\n'
                             f'train_move_poi_loss:{np.mean(train_batches_poi_loss_list):.2f}\n'
                             f'train_move_time_loss:{np.mean(train_batches_time_loss_list):.2f}\n'
                             f'train_move_top1_acc:{np.mean(train_batches_top1_acc_list):.4f}\n'
                             f'train_move_top5_acc:{np.mean(train_batches_top5_acc_list):.4f}\n'
                             f'train_move_top10_acc:{np.mean(train_batches_top10_acc_list):.4f}\n'
                             f'train_move_top20_acc:{np.mean(train_batches_top20_acc_list):.4f}\n'
                             f'train_move_mAP20:{np.mean(train_batches_mAP20_list):.4f}\n'
                             f'train_move_MRR:{np.mean(train_batches_mrr_list):.4f}\n'
                             f'traj_id:{batch[sample_idx][0]}\n'
                             f'input_seq: {batch[sample_idx][1]}\n'
                             f'label_seq:{batch[sample_idx][2]}\n'
                             f'pred_seq_poi:{list(np.argmax(batch_pred_pois, axis=2)[sample_idx][:batch_seq_lens[sample_idx]])} \n'
                             f'label_seq_cat:{[poi_idx2cat_idx_dict[each[0]] for each in batch[sample_idx][2]]}\n'
                             f'pred_seq_cat:{list(np.argmax(batch_pred_cats, axis=2)[sample_idx][:batch_seq_lens[sample_idx]])} \n'
                             f'label_seq_time:{list(batch_seq_labels_time[sample_idx].numpy()[:batch_seq_lens[sample_idx]])}\n'
                             f'pred_seq_time:{list(np.squeeze(batch_pred_times)[sample_idx][:batch_seq_lens[sample_idx]])} \n' +
                             '=' * 100)

        # train end --------------------------------------------------------------------------------------------------------
        poi_embed_model.eval()
        user_embed_model.eval()
        time_embed_model.eval()
        cat_embed_model.eval()
        embed_fuse_model1.eval()
        embed_fuse_model2.eval()
        seq_model.eval()
        val_batches_top1_acc_list = []
        val_batches_top5_acc_list = []
        val_batches_top10_acc_list = []
        val_batches_top20_acc_list = []
        val_batches_mAP20_list = []
        val_batches_mrr_list = []
        val_batches_loss_list = []
        val_batches_poi_loss_list = []
        val_batches_time_loss_list = []
        val_batches_cat_loss_list = []
        #src_mask = seq_model.generate_square_subsequent_mask(args.batch).to(args.device)
        for vb_idx, batch in enumerate(val_loader):
            #if len(batch) != args.batch:
                #src_mask = seq_model.generate_square_subsequent_mask(len(batch)).to(args.device)

            # For padding
            batch_input_seqs = []
            batch_seq_lens = []
            batch_seq_embeds = []
            batch_seq_labels_poi = []
            batch_seq_labels_time = []
            batch_seq_labels_cat = []

            pois = [each[0] for sample in batch for each in sample[1]]
            poi_embeddings = poi_embed_model(torch.tensor(pois).to(args.device))
            embedding_index=0
            # Convert input seq to embeddings
            for sample in batch:
                traj_id = sample[0]
                input_seq = [each[0] for each in sample[1]]
                label_seq = [each[0] for each in sample[2]]
                input_seq_time = [each[1] for each in sample[1]]
                label_seq_time = [each[1] for each in sample[2]]
                label_seq_cats = [poi_idx2cat_idx_dict[each] for each in label_seq]
                input_seq_embed = input_traj_to_embeddings(sample, poi_embeddings,embedding_index)
                batch_seq_embeds.append(input_seq_embed)
                batch_seq_lens.append(len(input_seq))
                batch_input_seqs.append(input_seq)
                batch_seq_labels_poi.append(torch.LongTensor(label_seq))
                batch_seq_labels_time.append(torch.FloatTensor(label_seq_time))
                batch_seq_labels_cat.append(torch.LongTensor(label_seq_cats))
                embedding_index+=len(input_seq)

            # Pad seqs for batch training
            batch_padded = pad_sequence(batch_seq_embeds, batch_first=True, padding_value=-1)
            label_padded_poi = pad_sequence(batch_seq_labels_poi, batch_first=True, padding_value=-1)
            label_padded_time = pad_sequence(batch_seq_labels_time, batch_first=True, padding_value=-1)
            label_padded_cat = pad_sequence(batch_seq_labels_cat, batch_first=True, padding_value=-1)

            # Feedforward
            x = batch_padded.to(device=args.device, dtype=torch.float)
            y_poi = label_padded_poi.to(device=args.device, dtype=torch.long)
            y_time = label_padded_time.to(device=args.device, dtype=torch.float)
            y_cat = label_padded_cat.to(device=args.device, dtype=torch.long)
            y_pred_poi, y_pred_time, y_pred_cat = seq_model(x)

            # Calculate loss
            loss_poi = criterion_poi(y_pred_poi.transpose(1, 2), y_poi)
            loss_time = criterion_time(torch.squeeze(y_pred_time), y_time)
            loss_cat = criterion_cat(y_pred_cat.transpose(1, 2), y_cat)
            loss = loss_poi + loss_time * args.time_loss_weight + loss_cat

            # Performance measurement
            top1_acc = 0
            top5_acc = 0
            top10_acc = 0
            top20_acc = 0
            mAP20 = 0
            mrr = 0
            batch_label_pois = y_poi.detach().cpu().numpy()
            batch_pred_pois = y_pred_poi.detach().cpu().numpy()
            batch_pred_times = y_pred_time.detach().cpu().numpy()
            batch_pred_cats = y_pred_cat.detach().cpu().numpy()
            for label_pois, pred_pois, seq_len in zip(batch_label_pois, batch_pred_pois, batch_seq_lens):
                label_pois = label_pois[:seq_len]  # shape: (seq_len, )
                pred_pois = pred_pois[:seq_len, :]  # shape: (seq_len, num_poi)
                top1_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=1)
                top5_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=5)
                top10_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=10)
                top20_acc += top_k_acc_last_timestep(label_pois, pred_pois, k=20)
                mAP20 += mAP_metric_last_timestep(label_pois, pred_pois, k=20)
                mrr += MRR_metric_last_timestep(label_pois, pred_pois)
            val_batches_top1_acc_list.append(top1_acc / len(batch_label_pois))
            val_batches_top5_acc_list.append(top5_acc / len(batch_label_pois))
            val_batches_top10_acc_list.append(top10_acc / len(batch_label_pois))
            val_batches_top20_acc_list.append(top20_acc / len(batch_label_pois))
            val_batches_mAP20_list.append(mAP20 / len(batch_label_pois))
            val_batches_mrr_list.append(mrr / len(batch_label_pois))
            val_batches_loss_list.append(loss.detach().cpu().numpy())
            val_batches_poi_loss_list.append(loss_poi.detach().cpu().numpy())
            val_batches_time_loss_list.append(loss_time.detach().cpu().numpy())
            val_batches_cat_loss_list.append(loss_cat.detach().cpu().numpy())

            # Report validation progress
            if (vb_idx % (20)) == 0:
                sample_idx = 0
                logging.info(f'Epoch:{epoch}, batch:{vb_idx}, '
                             f'val_batch_loss:{loss.item():.2f}, '
                             f'val_batch_top1_acc:{top1_acc / len(batch_label_pois):.2f}, '
                             f'val_move_loss:{np.mean(val_batches_loss_list):.2f} \n'
                             f'val_move_poi_loss:{np.mean(val_batches_poi_loss_list):.2f} \n'
                             f'val_move_time_loss:{np.mean(val_batches_time_loss_list):.2f} \n'
                             f'val_move_top1_acc:{np.mean(val_batches_top1_acc_list):.4f} \n'
                             f'val_move_top5_acc:{np.mean(val_batches_top5_acc_list):.4f} \n'
                             f'val_move_top10_acc:{np.mean(val_batches_top10_acc_list):.4f} \n'
                             f'val_move_top20_acc:{np.mean(val_batches_top20_acc_list):.4f} \n'
                             f'val_move_mAP20:{np.mean(val_batches_mAP20_list):.4f} \n'
                             f'val_move_MRR:{np.mean(val_batches_mrr_list):.4f} \n'
                             f'traj_id:{batch[sample_idx][0]}\n'
                             f'input_seq:{batch[sample_idx][1]}\n'
                             f'label_seq:{batch[sample_idx][2]}\n'
                             f'pred_seq_poi:{list(np.argmax(batch_pred_pois, axis=2)[sample_idx][:batch_seq_lens[sample_idx]])} \n'
                             f'label_seq_cat:{[poi_idx2cat_idx_dict[each[0]] for each in batch[sample_idx][2]]}\n'
                             f'pred_seq_cat:{list(np.argmax(batch_pred_cats, axis=2)[sample_idx][:batch_seq_lens[sample_idx]])} \n'
                             f'label_seq_time:{list(batch_seq_labels_time[sample_idx].numpy()[:batch_seq_lens[sample_idx]])}\n'
                             f'pred_seq_time:{list(np.squeeze(batch_pred_times)[sample_idx][:batch_seq_lens[sample_idx]])} \n' +
                             '=' * 100)
        # valid end --------------------------------------------------------------------------------------------------------

        # Calculate epoch metrics
        epoch_train_top1_acc = np.mean(train_batches_top1_acc_list)
        epoch_train_top5_acc = np.mean(train_batches_top5_acc_list)
        epoch_train_top10_acc = np.mean(train_batches_top10_acc_list)
        epoch_train_top20_acc = np.mean(train_batches_top20_acc_list)
        epoch_train_mAP20 = np.mean(train_batches_mAP20_list)
        epoch_train_mrr = np.mean(train_batches_mrr_list)
        epoch_train_loss = np.mean(train_batches_loss_list)
        epoch_train_poi_loss = np.mean(train_batches_poi_loss_list)
        epoch_train_time_loss = np.mean(train_batches_time_loss_list)
        epoch_train_cat_loss = np.mean(train_batches_cat_loss_list)
        epoch_val_top1_acc = np.mean(val_batches_top1_acc_list)
        epoch_val_top5_acc = np.mean(val_batches_top5_acc_list)
        epoch_val_top10_acc = np.mean(val_batches_top10_acc_list)
        epoch_val_top20_acc = np.mean(val_batches_top20_acc_list)
        epoch_val_mAP20 = np.mean(val_batches_mAP20_list)
        epoch_val_mrr = np.mean(val_batches_mrr_list)
        epoch_val_loss = np.mean(val_batches_loss_list)
        epoch_val_poi_loss = np.mean(val_batches_poi_loss_list)
        epoch_val_time_loss = np.mean(val_batches_time_loss_list)
        epoch_val_cat_loss = np.mean(val_batches_cat_loss_list)

        # Save metrics to list
        train_epochs_loss_list.append(epoch_train_loss)
        train_epochs_poi_loss_list.append(epoch_train_poi_loss)
        train_epochs_time_loss_list.append(epoch_train_time_loss)
        train_epochs_cat_loss_list.append(epoch_train_cat_loss)
        train_epochs_top1_acc_list.append(epoch_train_top1_acc)
        train_epochs_top5_acc_list.append(epoch_train_top5_acc)
        train_epochs_top10_acc_list.append(epoch_train_top10_acc)
        train_epochs_top20_acc_list.append(epoch_train_top20_acc)
        train_epochs_mAP20_list.append(epoch_train_mAP20)
        train_epochs_mrr_list.append(epoch_train_mrr)
        val_epochs_loss_list.append(epoch_val_loss)
        val_epochs_poi_loss_list.append(epoch_val_poi_loss)
        val_epochs_time_loss_list.append(epoch_val_time_loss)
        val_epochs_cat_loss_list.append(epoch_val_cat_loss)
        val_epochs_top1_acc_list.append(epoch_val_top1_acc)
        val_epochs_top5_acc_list.append(epoch_val_top5_acc)
        val_epochs_top10_acc_list.append(epoch_val_top10_acc)
        val_epochs_top20_acc_list.append(epoch_val_top20_acc)
        val_epochs_mAP20_list.append(epoch_val_mAP20)
        val_epochs_mrr_list.append(epoch_val_mrr)

        # Monitor loss and score
        monitor_loss = epoch_val_loss
        monitor_score = np.mean(epoch_val_top1_acc * 4 + epoch_val_top20_acc)

        # Learning rate schuduler
        lr_scheduler.step(monitor_loss)

        # Print epoch results
        logging.info(f"Epoch {epoch}/{args.epochs}\n"
                     f"train_loss:{epoch_train_loss:.4f}, "
                     f"train_poi_loss:{epoch_train_poi_loss:.4f}, "
                     f"train_time_loss:{epoch_train_time_loss:.4f}, "
                     f"train_cat_loss:{epoch_train_cat_loss:.4f}, "
                     f"train_top1_acc:{epoch_train_top1_acc:.4f}, "
                     f"train_top5_acc:{epoch_train_top5_acc:.4f}, "
                     f"train_top10_acc:{epoch_train_top10_acc:.4f}, "
                     f"train_top20_acc:{epoch_train_top20_acc:.4f}, "
                     f"train_mAP20:{epoch_train_mAP20:.4f}, "
                     f"train_mrr:{epoch_train_mrr:.4f}\n"
                     f"val_loss: {epoch_val_loss:.4f}, "
                     f"val_poi_loss: {epoch_val_poi_loss:.4f}, "
                     f"val_time_loss: {epoch_val_time_loss:.4f}, "
                     f"val_cat_loss: {epoch_val_cat_loss:.4f}, "
                     f"val_top1_acc:{epoch_val_top1_acc:.4f}, "
                     f"val_top5_acc:{epoch_val_top5_acc:.4f}, "
                     f"val_top10_acc:{epoch_val_top10_acc:.4f}, "
                     f"val_top20_acc:{epoch_val_top20_acc:.4f}, "
                     f"val_mAP20:{epoch_val_mAP20:.4f}, "
                     f"val_mrr:{epoch_val_mrr:.4f}")

        # Save train/val metrics for plotting purpose
        with open(os.path.join(args.save_dir, 'metrics-train.txt'), "w") as f:
            print(f'train_epochs_loss_list={[float(f"{each:.4f}") for each in train_epochs_loss_list]}', file=f)
            print(f'train_epochs_poi_loss_list={[float(f"{each:.4f}") for each in train_epochs_poi_loss_list]}', file=f)
            print(f'train_epochs_time_loss_list={[float(f"{each:.4f}") for each in train_epochs_time_loss_list]}',
                  file=f)
            print(f'train_epochs_cat_loss_list={[float(f"{each:.4f}") for each in train_epochs_cat_loss_list]}', file=f)
            print(f'train_epochs_top1_acc_list={[float(f"{each:.4f}") for each in train_epochs_top1_acc_list]}', file=f)
            print(f'train_epochs_top5_acc_list={[float(f"{each:.4f}") for each in train_epochs_top5_acc_list]}', file=f)
            print(f'train_epochs_top10_acc_list={[float(f"{each:.4f}") for each in train_epochs_top10_acc_list]}',
                  file=f)
            print(f'train_epochs_top20_acc_list={[float(f"{each:.4f}") for each in train_epochs_top20_acc_list]}',
                  file=f)
            print(f'train_epochs_mAP20_list={[float(f"{each:.4f}") for each in train_epochs_mAP20_list]}', file=f)
            print(f'train_epochs_mrr_list={[float(f"{each:.4f}") for each in train_epochs_mrr_list]}', file=f)
        with open(os.path.join(args.save_dir, 'metrics-val.txt'), "w") as f:
            print(f'val_epochs_loss_list={[float(f"{each:.4f}") for each in val_epochs_loss_list]}', file=f)
            print(f'val_epochs_poi_loss_list={[float(f"{each:.4f}") for each in val_epochs_poi_loss_list]}', file=f)
            print(f'val_epochs_time_loss_list={[float(f"{each:.4f}") for each in val_epochs_time_loss_list]}', file=f)
            print(f'val_epochs_cat_loss_list={[float(f"{each:.4f}") for each in val_epochs_cat_loss_list]}', file=f)
            print(f'val_epochs_top1_acc_list={[float(f"{each:.4f}") for each in val_epochs_top1_acc_list]}', file=f)
            print(f'val_epochs_top5_acc_list={[float(f"{each:.4f}") for each in val_epochs_top5_acc_list]}', file=f)
            print(f'val_epochs_top10_acc_list={[float(f"{each:.4f}") for each in val_epochs_top10_acc_list]}', file=f)
            print(f'val_epochs_top20_acc_list={[float(f"{each:.4f}") for each in val_epochs_top20_acc_list]}', file=f)
            print(f'val_epochs_mAP20_list={[float(f"{each:.4f}") for each in val_epochs_mAP20_list]}', file=f)
            print(f'val_epochs_mrr_list={[float(f"{each:.4f}") for each in val_epochs_mrr_list]}', file=f)

if __name__ == '__main__':
    args = parameter_parser()
    # The name of node features in NYC/graph_X.csv
    args.feature1 = 'checkin_cnt'
    args.feature2 = 'poi_catid'
    args.feature3 = 'latitude'
    args.feature4 = 'longitude'
    train(args)


"""Glues numpy arrays together
Usage:
    glue.py <out> dir <dir>
    glue.py <out> files <file>...
"""
import os

import numpy as np
from docopt import docopt

def glue(result, inputs):
    arrays = [np.load(x) for x in inputs]
    np.save(result, np.array(arrays))

if __name__ == '__main__':
    arguments = docopt(__doc__)

    if arguments['dir'] is True:
        files = os.listdir(arguments['<dir>'])
        glue(result=arguments['<out>'], inputs=files)

    else:
        glue(result=arguments['<out>'], inputs=arguments['<file>'])


import pytest
import main
# import os
import logging

logger = logging.getLogger(__name__)

@pytest.fixture(autouse=True)
def set_env_vars(monkeypatch):
    with open('./tests/mocks/mock-creds.json', 'r') as f:
        fake_credentials = f.read()
    monkeypatch.setenv('GOOGLE_CREDS', fake_credentials)
    monkeypatch.setenv('GCP_PROJECT_ID', "fake-gcp-project")
    monkeypatch.setenv('INSTANCE_INTERVAL', '600')

# def test_create_costs_report(mocker, monkeypatch, tmp_path):

#     test_file = "platform-costs.pytest.md"

#     monkeypatch.setenv('OUTPUT_DIR', str(tmp_path))
#     monkeypatch.setenv('REPORT_FILE', test_file)

#     test_data = [
#         ['project-1-flex', 201905, 1.64],
#         ['project-1-flex', 201906, 0.37],
#         ['project-1-prod', 201905, 1.65],
#         ['project-1-prod', 201906, 0.37],
#         ['project-2-test', 201805, 2.51],
#         ['project-2-test', 201806, 4.96],
#         ['project-2-prod', 201807, 4.98],
#         ['project-2-prod', 201808, 4.77]
#     ]

#     df = pd.DataFrame(test_data)
#     df.columns = (['project', 'month', 'spend'])

#     stub_project_list = mocker.patch('main.list_projects')
#     stub_project_list.return_value = ['project-1-flex', 'project-1-prod']

#     main.create_costs_report(df)

#     f = open(tmp_path / test_file, "r")
#     result = f.read()
#     f.close()

#     assert "title: " in result
#     assert "Last Generated" in result
#     assert "weight: " in result

#     # these tests may be brittle if wording changes a lot - consider removing
#     assert "JLDP v1 Costs" in result
#     assert "version 1 platform runs" in result
#     assert "JLDP v2 Tenant Costs" in result
#     assert "GCP services outside" in result
#     assert "JLDP v2 Platform Costs" in result
#     assert "includes costs" in result
#     assert "Other JL Commerce Projects" in result
#     assert "not treated as JLDP projects" in result

# def test_create_cost_charts(mocker, monkeypatch, tmp_path):

#     monkeypatch.setenv('OUTPUT_DIR', str(tmp_path))

#     stub_project_list = mocker.patch('main.list_projects')
#     stub_project_list.return_value = ['project-1-flex', 'project-1-prod']

#     test_data = "./tests/mocks/raw_df.csv"
#     df = pd.read_csv(test_data, index_col=0)

#     main.create_cost_charts(df)

#     # Note that with this test we are not checking the content of the png is valid!
#     num_png_files = len([f for f in os.listdir(tmp_path)
#                          if f.endswith('.png') and os.path.isfile(os.path.join(tmp_path, f))])
#     # could turn out to be brittle - 4 sections in the SECTIONS static in main.py
#     assert num_png_files == 4

# def test_main_no_args(mocker):
#     mocker.patch('main.list_projects')
#     mocker.patch('main.query_monthly_spend')
#     mocker.patch('main.create_cost_charts')
#     mocker.patch('main.create_costs_report')

#     runner = CliRunner()
#     result = runner.invoke(main.main)

#     assert result.output == 'No project specified - reporting on all projects\n'

# def test_main_with_project(mocker):
#     mocker.patch('main.list_projects')
#     mocker.patch('main.query_monthly_spend')
#     mocker.patch('main.create_cost_charts')
#     mocker.patch('main.create_costs_report')

#     runner = CliRunner()
#     result = runner.invoke(main.main, ['--project', 'jl-platform-k8s-verify'])

#     assert result.output == 'Building report for jl-platform-k8s-verify project\n'

def test_init(mocker):
    # run wrapper validity: https://medium.com/opsops/how-to-test-if-name-main-1928367290cb
    mocker.patch.object(main, "main", return_value=42)
    mocker.patch.object(main, "__name__", "__main__")
    mocker.patch.object(main.sys, 'exit')
    main.init()
    assert main.sys.exit.call_args[0][0] == 42


# -*- coding: utf-8 -*-
"""
Created on Sat Jan  2 18:15:05 2021

@author: D-RI
"""
from mpl_toolkits.mplot3d import Axes3D
import math
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
import pandas as pd
import matplotlib.cm as cmx
data = pd.read_csv("iris.csv ")

data.head()
specific_data=data[["SepalLengthCm","SepalWidthCm","PetalLengthCm","PetalWidthCm"]]
setosa=np.transpose(specific_data[0:50].to_numpy())
versicolor=np.transpose(specific_data[50:100].to_numpy())
virginica=np.transpose(specific_data[100:150].to_numpy())
input_array=np.concatenate((versicolor,setosa,virginica),axis=1)

class Som_kohonen:
    def hjfunction(self,weight,j,iteration,iteration_number):
        d=[]
        for i in range(len(weight)):
            d.append(np.linalg.norm(weight[i,:]-weight[j,:]))
        sigma_0=0.305
        sigma=sigma_0*math.exp(-1*(iteration+1)/iteration_number)
        h_ji=[]

        for x in range(len(d)):
            h_ji.append(math.exp(-1*(math.pow(d[x], 2))/2*math.pow(sigma,2)))

        return h_ji

    def c_iteration(self,c,iteration,iteration_number):
        sigma_0=0.305
        sigma=sigma_0*math.exp(-1*(iteration+1)/iteration_number)

        c_iter=c*math.exp(-1*(iteration+1)/sigma)
        return c_iter

    def neuron_win(self,weight,arrays):
        d=[]

        for i in range(len(weight)):
            d.append(np.matmul(weight[i,:],arrays.reshape(4,1)))
        d_np=np.array(d)
        max_index=np.argmax(d_np)
        # max_index = d.index(max(d))
        return max_index

    def update(self,weight,win,array,c,iteration,iteration_number):
        hj=self.hjfunction(weight,win,iteration,iteration_number)
        for i in range(len(weight)):
            for j in range(4):
                weight[i,j]=weight[i,j]+self.c_iteration(c,iteration,iteration_number)*hj[i]*(array[j]-weight[i,j])

        return weight

    def start_som(self,weight,arrays,c,iteration):

        for i in range(iteration):
            for j in range(np.size(arrays,1)):
                win_neuron=self.neuron_win(weight,arrays[:,j])
                #w_list.append(self.update(w_list[a],win_neuron,arrays[:,j],c,i,iteration))

                self.update(weight,win_neuron,arrays[:,j],c,i,iteration)

# a=np.random.rand(6,4)*40

# np.save('W_6noron', a)
W= np.load('W_6noron.npy')

def scatter3d(x,y,z, cs,f, colorsMap='jet'):
    cm = plt.get_cmap(colorsMap)
    cNorm = matplotlib.colors.Normalize(vmin=min(cs), vmax=max(cs))
    scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
    fig = plt.figure()
    ax = Axes3D(fig)
    for i in range(150):

        ax.scatter(x[i], y[i], z[i], c=scalarMap.to_rgba(cs[i]),marker=f[i])
    scalarMap.set_array(cs)
    fig.colorbar(scalarMap,label='4.boyut')
    plt.show()

c=0.5         #0.60
iteration=1000
som=Som_kohonen()
d=[]
som.start_som(W,input_array,c,iteration)

for i in range(150):
    d.append(som.neuron_win(W,input_array[:,i]))

x=input_array[0,:]
y=input_array[1,:]
z=input_array[2,:]
t=input_array[3,:]

f=[]
# for i in range(150):
#     if d[i]==3 or d[i]==0:
#         f.append("o")
#     elif d[i]==4:
#         f.append("x")
#     elif d[i]==1 or d[i]==2:
#         f.append("v")
for i in range(150):
    if d[i]==5:
        f.append("o")
    elif d[i]==2:
        f.append("x")
    elif d[i]==0 or d[i]==4:
        f.append("v")
scatter3d(x,y,z,t,f)


from flask import Flask, request, jsonify

app = Flask(__name__)

from filterLib.curse_detector import CurseDetector

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/text', methods=["POST"])
def check_text():
    curse = CurseDetector()
    body = request.json
    text = body['text']

    result = curse.predict(text)
    returnArr = []
    cnt = 0

    for i in result:
        if i[1] > 0.9:
            returnArr.append('true')
            cnt += 1
            continue

        returnArr.append('false')
        cnt += 1

    return jsonify(
        data=returnArr
    )

if __name__ == '__main__':
    app.run(host='0.0.0.0', port='8085', debug=True)


#! -*- coding: utf-8 -*-

def keeptags(value, tags):
    """
    Strips all [X]HTML tags except the space seperated list of tags
    from the output.

    Usage example: keeptags(html, "strong em ul li")
    """
    import re
    from django.utils.html import strip_tags, escape
    tags = [re.escape(tag) for tag in tags.split()]
    tags_re = '(%s)' % '|'.join(tags)
    singletag_re = re.compile(r'<(%s\s*/?)>' % tags_re)
    starttag_re = re.compile(r'<(%s)(\s+[^>]+)>' % tags_re)
    endtag_re = re.compile(r'<(/%s)>' % tags_re)
    value = singletag_re.sub('##~~~\g<1>~~~##', value)
    value = starttag_re.sub('##~~~\g<1>\g<3>~~~##', value)
    value = endtag_re.sub('##~~~\g<1>~~~##', value)
    value = strip_tags(value)
    recreate_re = re.compile('##~~~([^~]+)~~~##')
    value = recreate_re.sub('<\g<1>>', value)
    return value


import requests
import base64
import json
import sys
from csv import reader

if len(sys.argv) != 3:
    print("incorrect command format. Should be:\n" + sys.argv[0] + " <csv file location> <name of target kafka topic>")
    exit(1)

topic = sys.argv[2]
url = "http://localhost:8082/topics/" + str(topic)

headers = {
'Content-Type': 'application/vnd.kafka.json.v2+json',
'Accept': 'application/vnd.kafka.v2+json',
}

file_location = sys.argv[1]

with open(file_location, 'rt') as sourceFile:

    res = reader(sourceFile, delimiter=',', quotechar='"')

    csv_headers = next(res, None)

    row_values = {}

    for line in res:

        for i in range(len(csv_headers)):
            header = csv_headers[i]
            row_values[header] = line[i]

        payload = {"records":
               [{
                   "value":row_values
               }]
        }

        # Send the message
        r = requests.post(url, headers=headers, data=json.dumps(payload))
        if r.status_code != 200:
           print("An error ocurred")
           print("Status Code: " + str(r.status_code))
           print(r.text)

print("Finished uploading to kafka topic")


import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Activation
from keras.layers import Conv2D, MaxPooling2D
from keras.utils.vis_utils import plot_model
from keras.utils import np_utils
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('../data')

X_train, Y_train = mnist.train.images, mnist.train.labels
X_test, Y_test = mnist.test.images, mnist.test.labels

Y_train = np_utils.to_categorical(Y_train,num_classes=10)
Y_test = np_utils.to_categorical(Y_test,num_classes=10)

X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1)

# Build LeNet-5
model = Sequential()
model.add(Conv2D(filters=6, kernel_size=(5, 5), padding='valid', input_shape=(28, 28, 1), activation='tanh')) # C1
model.add(MaxPooling2D(pool_size=(2, 2))) # S2
model.add(Conv2D(filters=16, kernel_size=(5, 5), padding='valid', activation='tanh')) # C3
model.add(MaxPooling2D(pool_size=(2, 2))) # S4
model.add(Flatten())
model.add(Dense(120, activation='tanh')) # C5
model.add(Dense(84, activation='tanh')) # F6
model.add(Dense(10, activation='softmax')) # output
model.summary()

model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
model.fit(X_train, Y_train, batch_size=500, epochs=10, verbose=1, validation_data=(X_test, Y_test))
model.save('cnn_fashion_mnist.h5')

loss, accuracy = model.evaluate(X_test, Y_test, verbose=0)
print('loss:', loss)
print('accuracy:', accuracy)


# coding: utf-8
from typing import List, Dict
from ...dataclass.area import Area
from ...dataclass.area_info import AreaInfo
from .i_rules_area import IRulesArea
from .rule_area_base import RuleAreaBase

class RuleAreaVertical(RuleAreaBase):
    """Matches when there is a vertical parent"""

    def __init__(self, rules: IRulesArea) -> None:
        """constructor"""
        super().__init__(rules=rules)
    # region IRuleArea Methods

    def get_is_match(self, ai: AreaInfo, alst: List[Area]) -> bool:
        """
        Gets if rule is a match

        Args:
            alst (List[Area]): Areas to match
        """
        # vertical matches are when all areas have the sam x1 value:
        # see: https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1ucb_1_1ContentResultSet.html
        if len(alst) < 2:
            return False
        first = self._get_first_y1(ai=ai, alst=alst)
        if ai.shape:
            # vertical are ofset left or right on x1, Usually right
            # more likley this is a single
            if first.x1 == ai.shape.x1:
                return False
        is_vert = True
        d_lst: Dict[int, List[Area]] = self._list_dict_x1(
            lst=alst)  # grouped by y1
        for area in d_lst[first.x1]:
            if area.x1 != first.x1:
                is_vert = False
                break

        return is_vert

    def get_area(self, ai: AreaInfo, alst: List[Area]) -> List[Area]:
        """
        Gets filtered Area list

        Args:
            alst (List[Area]): Areas to filter

         Returns:
            List[Area]: Filtered Area List
        """
        # remove any duplicates and return list.
        # is it unlikely there would ever be duplicates, but just in case.
        first = self._get_first_y1(ai=ai, alst=alst)
        d_lst: Dict[int, List[Area]] = self._list_dict_x1(
            lst=alst)  # grouped by y1
        # filtering upper by shape or first is a bug fix.
        # in cases such as https://tinyurl.com/yaqul3gs
        # some of child classes have the exact same y1 as the parrent classes
        if ai.shape:
            upper: List[Area] = [
                a for a in d_lst[first.x1] if a.y1 < ai.shape.y1]
        else:
            upper: List[Area] = [
                a for a in d_lst[first.x1] if a.y1 <= first.y1]
        sorted_u = sorted(upper, key=lambda a: a.y1)
        if self.rules.remove_parent_inherited:
            self._remove_duplicates_lst(sorted_u)
        return sorted_u


# -*- coding: utf-8 -*-

from __future__ import division

import numpy as np
import pytest

from FTRLprox.models import FTRLprox
from FTRLprox.models import OGDLR
from FTRLprox.models import SEED
from FTRLprox.utils import logloss
from tutils import ogdlr_before
from tutils import ogdlr_after
from tutils import ftrl_before
from tutils import ftrl_after
from tutils import hash_before
from tutils import hash_after
from tutils import nn_before
from tutils import nn_after
from tutils import X
from tutils import y

def test_FTRL_learns():
    # test that this model learns something
    y_pred = ftrl_before.predict_proba(X)
    ll_before = logloss(y, y_pred)

    y_pred = ftrl_after.predict_proba(X)
    ll_after = logloss(y, y_pred)

    assert ll_before > ll_after

def test_ogdlr_learns():
    # test that this model learns something
    y_pred = ogdlr_before.predict_proba(X)
    ll_before = logloss(y, y_pred)

    y_pred = ogdlr_after.predict_proba(X)
    ll_after = logloss(y, y_pred)
    assert ll_before > ll_after

def test_ogdlr_with_hash_learns():
    # test that this model learns something
    y_pred = hash_before.predict_proba(X)
    ll_before = logloss(y, y_pred)

    y_pred = hash_after.predict_proba(X)
    ll_after = logloss(y, y_pred)

    assert ll_before > ll_after

def test_nn_learns():
    # test that this model learns something
    y_pred = nn_before.predict_proba(X)
    ll_before = logloss(y, y_pred)

    y_pred = nn_after.predict_proba(X)
    ll_after = logloss(y, y_pred)

    assert ll_before > ll_after

def test_models_same_predictions():
    # for lambda1, lambda2 = 0, OGDLR and FTRLprox should generate the
    # same result. The same goes if hashing is used (except for the
    # rare case of hash collisions. A neural net does not necessarily
    # predict exactly the same outcome.
    y_f = ftrl_after.predict_proba(X)
    y_o = ogdlr_after.predict_proba(X)
    y_h = hash_after.predict_proba(X)
    assert np.allclose(y_f, y_o, atol=1e-15)
    assert np.allclose(y_f, y_h, atol=1e-15)

def test_effect_of_alpha():
    # higher alpha should lead to faster learning, thus higher weights
    mean_abs_weights = []
    for alpha in [0, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 1e1]:
        clf = OGDLR(alpha=alpha)
        clf.fit(X[:100], y[:100])
        mean_abs_weights.append(np.abs(clf.weights()).mean())
    assert mean_abs_weights[0] == 0.
    assert all(np.diff(mean_abs_weights) > 0)

def test_effect_of_beta():
    # higher beta should lead to slower learning, thus lower weights
    mean_abs_weights = []
    for beta in [10 ** n for n in range(7)]:
        clf = OGDLR(beta=beta)
        clf.fit(X[:100], y[:100])
        mean_abs_weights.append(np.abs(clf.weights()).mean())
    assert np.allclose(mean_abs_weights[-1], 0, atol=1e-6)
    assert all(np.diff(mean_abs_weights) < 0)

@pytest.mark.parametrize('lambda1', [1 / lam for lam in range(1, 6)])
def test_effect_of_lambda1(lambda1):
    # gradients should be the same regardless of magnitude of weights
    weights = range(-5, 0) + range(1, 6)
    clf = OGDLR(lambda1=lambda1)
    grads = clf._get_grads(0, 0, weights)
    # gradient only depends on sign of weight
    abso = [gr * np.sign(w) for gr, w in zip(grads, weights)]
    assert np.allclose(abso[0], abso)

    # contingency test: should fail
    frac = [gr / w for gr, w in zip(grads, weights)]
    with pytest.raises(AssertionError):
        assert np.allclose(frac[0], frac)

@pytest.mark.parametrize('lambda2', [1 / lam for lam in range(1, 6)])
def test_effect_of_lambda2(lambda2):
    # relative difference in gradients should be the same
    weights = range(-5, 0) + range(1, 6)
    clf = OGDLR(lambda2=lambda2)
    grads = clf._get_grads(0, 0, weights)
    # gradient is proportional to weights
    frac = [gr / w for gr, w in zip(grads, weights)]
    assert np.allclose(frac[0], frac)

    # contingencey test: should fail
    abso = [gr * np.sign(w) for gr, w in zip(grads, weights)]
    with pytest.raises(AssertionError):
        assert np.allclose(abso[0], abso)


import urllib.request, json
from bs4 import BeautifulSoup

user_id = list()

def get_id():

    username = str(input('Enter username: '))

    data = urllib.request.urlopen(f'https://users.roblox.com/v1/users/search?keyword={username}&limit=10')
    data_load = json.loads(data.read().decode())

    for dic in data_load['data']:
        user_id.append(dic['id'])

def get_info():

    data = urllib.request.urlopen(f'https://users.roblox.com/v1/users/{user_id[0]}')
    data_load = json.loads(data.read().decode())