# Creation of Boxes.json for VPD

import profile
from detectron2.config import get_cfg
from detectron2.structures.boxes import pairwise_iou, Boxes
from detectron2.engine import DefaultPredictor
from detectron2 import model_zoo
from mmpose.apis import inference_top_down_pose_model, init_pose_model, vis_pose_result
from queue import Queue
from tqdm import tqdm
import numpy as np
import gzip
import json
import cv2
import os
import torch
from multiprocessing import Pool
from line_profiler import LineProfiler

# Preprocess Bounding Boxes, ie fencers not referees or spectators
pose_checkpnt = '.\pose_estimation\litehrnet30_coco_384x288-a3aef5c4_20210626.pth'
pose_config = '.\pose_estimation\\topdown_heatmap_litehrnet_30_coco_384x288.py'
pose_model = init_pose_model(pose_config, pose_checkpnt)
cfg = get_cfg()
cfg.merge_from_file(
    model_zoo.get_config_file("COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml")
)
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 3

cfg.MODEL.WEIGHTS = ".\\vpd_fencing\\output\\referee_crowd_fencer.pth"
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.8
predictor = DefaultPredictor(cfg)

""" Uses trained detectron2 object detector to detect fencers. Uses max intersection over union of current detections
 againsts previous left or right fencer detection for continuity between frames.
 TODO: extra detection for missed detections.  """

def xyxy_to_xywh(box):
    x1, y1, x2, y2 = box
    w = x2 - x1
    h = y2 - y1
    return torch.Tensor([x1, y1, w, h])

def xywh_to_xyxy(box):
    x, y, w, h = box
    x2 = x + w
    y2 = y + h
    return torch.Tensor([x, y, x2, y2])

def get_area(box):
    x, y, w, h = box
    return w*h

def good_detection(l_box, r_box):
    #TODO: Deal with fencers not being totally in line
    #Currently uses the intersection of the two bounding boxes on the y-axis
    box_list = [l_box, r_box]
    box_list.sort(reverse=True, key=get_area)
    l_box, r_box = box_list
    lx1, ly1, lw, lh = l_box
    rx1, ry1, rw, rh = r_box
    ly2 = ly1 + lh
    ry2 = ry1 + rh
    max_y1 = max(ly1, ry1)
    min_y2 = min(ly2, ry2)
    overlap = min_y2 - max_y1
    if overlap < .3*lh:
        # print("Bad Detect")
        return False
    else:
        # print("Good Detect")
        return True
def bad_iou(iou):
    return True if len(torch.where(iou > .3)[0]) == 0 else False

# def best_boxes(boxes):
#     boxes.sort(reverse = True, key = get_area)
#     return boxes_2[:2]

# TODO: Fix issue with switching left, v. right labels on fencer when they cross
# TODO: Better Solution to bad v good detections(fencers aren't always level from camera perspective)

def create_file(video, output, viz=True):
    if not os.path.exists(output):
        os.mkdir(output)
    cap = cv2.VideoCapture(video)
    total = cap.get(cv2.CAP_PROP_FRAME_COUNT)
    end_frame = (total//2)
    fencer_left = []
    fencer_right = []
    pose_left = []
    pose_right = []
    tracker_left = cv2.TrackerCSRT_create()
    tracker_right = cv2.TrackerCSRT_create()
    left_buffer = Queue(maxsize=1)
    right_buffer = Queue(maxsize=1)
    img_buffer = Queue(maxsize=1)
    initial_detection = False
    begin_tracking = False
    position = 0
    while cap.isOpened() and position < end_frame:
        success, img = cap.read()
        #print(img.shape)
        if not success:

            print(f"Video {os.path.basename(video).replace('.avi', '')} failed to read")
            break
        else:
            position = int(cap.get(cv2.CAP_PROP_POS_FRAMES))

            instances = predictor(img)["instances"]
            boxes_xyxy = instances[instances.pred_classes == 1].get_fields()['pred_boxes'].to("cpu").tensor #get fencer bounding boxes
            boxes = [xyxy_to_xywh(box) for box in boxes_xyxy]
            #print(boxes)
            if not initial_detection:
                # initial detection uses biggest bounding box to determine fencers
                if len(boxes) >= 2:
                    boxes.sort(reverse=True, key= get_area)
                    box1, box2 = boxes[:2]
#BLUE_CIMINI_ITA_vs_FARDZINOV_RUS__16
                    if box1[0] < box2[0]:
                        l_box = box1
                        r_box = box2
                        initial_detection = True
                        left_buffer.put(l_box)
                        right_buffer.put(r_box)
                        img_buffer.put(img)

                    elif box2[0] < box1[0]:
                        r_box = box1
                        l_box = box2
                        initial_detection = True
                        left_buffer.put(l_box)
                        right_buffer.put(r_box)
                        img_buffer.put(img)
                else:
                    print("Poor Initial Detection")

            else:

                left_prev = left_buffer.get()
                right_prev = right_buffer.get()
                prev_img = img_buffer.get()
                left_iou = pairwise_iou(Boxes(xywh_to_xyxy(left_prev).reshape(1, -1)), Boxes(boxes_xyxy))[0]
                right_iou = pairwise_iou(Boxes(xywh_to_xyxy(right_prev).reshape(1, -1)), Boxes(boxes_xyxy))[0]
                #Once a bounding box is lost revert to CSRT tracking with previous bounding boxes

                # print(f"Left IOU {left_iou}")
                # print(f"Right IOU {right_iou}")
                try:
                    left_ind = int((left_iou == max(left_iou)).nonzero()[0,0])
                    right_ind = int((right_iou == max(right_iou)).nonzero()[0,0])

                except ValueError:
                    print("Value Error: Defaulting to CSRT")
                    left_ind, right_ind = 1, 1

                if left_ind != right_ind and not (bad_iou(left_iou) or bad_iou(right_iou)):
                    l_box, r_box = boxes[left_ind], boxes[right_ind]
                    if begin_tracking:
                        begin_tracking = False
                        print("Tracking Stopped")
                    # if not good_detection(l_box.tensor.tolist()[0], r_box.tensor.tolist()[0]):
                    #     if not begin_tracking:
                    #         begin_tracking = True
                    #         print("Tracker Initiated")
                    #         l_init = tuple(int(el) for el in xyxy_to_xywh(left_prev.tensor.numpy().tolist()[0]))
                    #         r_init = tuple(int(el) for el in xyxy_to_xywh(right_prev.tensor.numpy().tolist()[0]))
                    #         tracker_left.init(prev_img, l_init)
                    #         tracker_right.init(prev_img, r_init)

                    #     if begin_tracking:
                    #         _, l_box = tracker_left.update(img)
                    #         _, r_box = tracker_right.update(img)
                else:
                    if not begin_tracking:
                        begin_tracking = True
                        print("Tracker Initiated")
                        l_init = tuple(int(el) for el in left_prev)
                        r_init = tuple(int(el) for el in right_prev)
                        tracker_left.init(prev_img, l_init)
                        tracker_right.init(prev_img, r_init)

                    if begin_tracking:
                        _, l_box = tracker_left.update(img)
                        _, r_box = tracker_right.update(img)
                        r_box = torch.Tensor(r_box)
                        l_box = torch.Tensor(l_box)

                # if type(l_box) == Boxes:
                #     left_buffer.put(l_box)
                #     right_buffer.put(r_box)
                # elif type(l_box != Boxes):
                #     left_buffer.put(Boxes(np.array(xywh_to_xyxy(l_box)).reshape(1, -1)))
                #     right_buffer.put(Boxes(np.array(xywh_to_xyxy(r_box)).reshape(1, -1)))
                left_buffer.put(l_box)
                right_buffer.put(r_box)
                img_buffer.put(img)

            #Run Pose estimation on bounding box

            # TODO more accurate fencer selection from bounding boxes
            if initial_detection:
                box_dict = [{'bbox':l_box.numpy()}, {'bbox':r_box.numpy()}]
                res = inference_top_down_pose_model(pose_model, img, box_dict, format='xywh')[0]
                left_pose, right_pose = res[0]['keypoints'], res[1]['keypoints']
                left_pose_score, right_pose_score = left_pose[:,-1].mean(), right_pose[:,-1].mean()
                if viz:
                    key = cv2.waitKey(1) & 0xFF
                    if key == ord('q'):
                        break
                    # if type(l_box) == Boxes:

                    #     l_box = xyxy_to_xywh(l_box.tensor.numpy().tolist()[0])
                    #     r_box = xyxy_to_xywh(r_box.tensor.numpy().tolist()[0])
                    #     l_box = tuple(int(el) for el in l_box)
                    #     r_box = tuple(int(el) for el in r_box)

                    cv2.rectangle(
                        img,
                        (int(l_box[0]), int(l_box[1])),
                        (int(l_box[0] + l_box[2]), int(l_box[1] + l_box[3])),
                        (255, 0, 0),
                        2,
                    )
                    cv2.rectangle(
                        img,
                        (int(r_box[0]), int(r_box[1])),
                        (int(r_box[0] + r_box[2]), int(r_box[1] + r_box[3])),
                        (0, 255, 0),
                        2,
                    )
                    [[cv2.circle(img, (int(x), int(y)), 2, (0, 255, 255), thickness=2, lineType=cv2.FILLED) for x, y in pose[:,:2]] for pose in (left_pose, right_pose)]
                    cv2.imshow("Main", img)
                    cv2.waitKey(1)
                    # if first_detection:
                    #     tracker_left.init(img, l_box)
                    #     tracker_right.init(img, r_box)
                    #     first_detection = False

                l_box, r_box = l_box.numpy().tolist(), r_box.numpy().tolist()

                fencer_left.append([position, l_box])
                fencer_right.append([position, r_box])
                pose_left.append([position, [[float(left_pose_score), l_box, left_pose.tolist()]]])
                pose_right.append([position, [[float(right_pose_score), r_box, right_pose.tolist()]]])

    left_path = os.path.join(output, "left")
    right_path = os.path.join(output, "right")

    if not os.path.exists(left_path):
        os.mkdir(left_path)

    if not os.path.exists(right_path):
        os.mkdir(right_path)

    with open(os.path.join(left_path, "boxes.json"), "w") as file:
        json.dump(fencer_left, file)
        file.close()

    with open(os.path.join(right_path, "boxes.json"), "w") as file:
        json.dump(fencer_right, file)
        file.close()

    with gzip.open(os.path.join(left_path, "coco_keypoints.json.gz"), 'w') as file:
        file.write(json.dumps(pose_left).encode('utf-8'))

    with gzip.open(os.path.join(right_path, "coco_keypoints.json.gz"), 'w') as file:
        file.write(json.dumps(pose_right).encode('utf-8'))

def main(parent_dir):
    pose_dir = os.path.join(parent_dir, "2d_pose")
    if not os.path.exists(pose_dir):
        os.mkdir(pose_dir)
    dir_list = os.listdir(os.path.join(parent_dir, "clips"))

    index = dir_list.index('BLUE_DI_VEROLI_ITA_vs_SVICHKAR_UKR__11.avi')
    for vid in tqdm(dir_list[index:]):
        basename = os.path.basename(vid).replace(".avi", "")
        print(basename)
        sub_pose_dir = os.path.join(pose_dir, basename)
        if not os.path.exists(sub_pose_dir):
            os.mkdir(sub_pose_dir)
        # lp = LineProfiler()
        # lp_wrapper = lp(create_file)
        # lp_wrapper(os.path.join(parent_dir, "clips", vid), sub_pose_dir)
        # lp.print_stats()
        create_file(os.path.join(parent_dir, "clips", vid), sub_pose_dir)

def worker_func(args):
    return create_file(*args)

def parallel_main(clip_dir, out_dir, viz):
    if not os.path.exists(out_dir):
        os.mkdir(out_dir)
    video_names = [os.path.join(clip_dir,name) for name in os.listdir(clip_dir)]

    worker_args = [(v, os.path.join(out_dir, os.path.basename(v).rstrip('.avi')), viz) for v in video_names]

    if viz:
        parallelism = 1
    else:
        parallelism = 2
    with Pool(parallelism) as p, tqdm(total=len(video_names)) as pbar:
        for video_name in p.imap_unordered(worker_func, worker_args):
            pbar.set_description(video_name, refresh=True)
            pbar.update(1)
    print('Done')

if __name__ == "__main__":
    parallel_main("Bern_2021\clips", "Bern_2021\\2d_pose", False)


"""helper functions for tests and benchmarks."""
import json
import os
import os.path as osp
import pickle

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pytest
import seaborn as sns

from tests.quirks import KNOWN_GYM_RENDER_NOT_IMPLEMENTED

def step_env(env, n=10, render=True):
    """Step env helper."""
    env.reset()
    for _ in range(n):
        _, _, done, _ = env.step(env.action_space.sample())
        if render:
            env.render()
        if done:
            break

def step_env_with_gym_quirks(env, spec, n=10, render=True,
                             serialize_env=False):
    """Step env gym helper."""
    if serialize_env:
        # Roundtrip serialization
        round_trip = pickle.loads(pickle.dumps(env))
        assert round_trip.env.spec == env.env.spec
        env = round_trip

    env.reset()
    for _ in range(n):
        _, _, done, _ = env.step(env.action_space.sample())
        if render:
            if spec.id not in KNOWN_GYM_RENDER_NOT_IMPLEMENTED:
                env.render()
            else:
                with pytest.raises(NotImplementedError):
                    env.render()
        if done:
            break

    env.close()

    if serialize_env:
        # Roundtrip serialization
        round_trip = pickle.loads(pickle.dumps(env))
        assert round_trip.env.spec == env.env.spec

def convolve(_input, filter_weights, filter_bias, strides, filter_sizes,
             in_channels, hidden_nonlinearity):
    """Convolve."""
    # in_width = self.input_width
    # in_height = self.input_height

    batch_size = _input.shape[0]
    in_width = _input.shape[1]
    in_height = _input.shape[2]

    for filter_size, in_shape, filter_weight, _filter_bias, stride in zip(
            filter_sizes, in_channels, filter_weights, filter_bias, strides):
        out_width = int((in_width - filter_size) / stride) + 1
        out_height = int((in_height - filter_size) / stride) + 1
        flatten_filter_size = filter_size * filter_size * in_shape
        reshape_filter = filter_weight.reshape(flatten_filter_size, -1)
        image_vector = np.empty(
            (batch_size, out_width, out_height, flatten_filter_size))
        for batch in range(batch_size):
            for w in range(out_width):
                for h in range(out_height):
                    image_vector[batch][w][h] = _construct_image_vector(
                        _input, batch, w, h, filter_size, filter_size,
                        in_shape)

        _input = np.dot(image_vector, reshape_filter) + _filter_bias
        _input = hidden_nonlinearity(_input).eval()

        in_width = out_width
        in_height = out_height

    return _input

def recurrent_step_lstm(input_val,
                        num_units,
                        step_hidden,
                        step_cell,
                        w_x_init,
                        w_h_init,
                        b_init,
                        nonlinearity,
                        gate_nonlinearity,
                        forget_bias=1.0):
    """
    A LSTM unit implements the following update mechanism:

    Incoming gate:    i(t) = f_i(x(t) @ W_xi + h(t-1) @ W_hi +
                                 w_ci * c(t-1) + b_i)
    Forget gate:      f(t) = f_f(x(t) @ W_xf + h(t-1) @ W_hf +
                                 w_cf * c(t-1) + b_f)
    Cell gate:        c(t) = f(t) * c(t - 1) + i(t) * f_c(x(t) @ W_xc +
                             h(t-1) @ W_hc + b_c)
    Out gate:         o(t) = f_o(x(t) @ W_xo + h(t-1) W_ho + w_co * c(t) + b_o)
    New hidden state: h(t) = o(t) * f_h(c(t))

    Note that the incoming, forget, cell, and out vectors must have the same
    dimension as the hidden state.
    """

    def f(x):
        return x

    if nonlinearity is None:
        nonlinearity = f
    if gate_nonlinearity is None:
        gate_nonlinearity = f

    input_dim = np.prod(input_val.shape[1:])
    # Weights for the input gate
    w_xi = np.full((input_dim, num_units), w_x_init)
    w_hi = np.full((num_units, num_units), w_h_init)
    b_i = np.full((num_units, ), b_init)
    # Weights for the forget gate
    w_xf = np.full((input_dim, num_units), w_x_init)
    w_hf = np.full((num_units, num_units), w_h_init)
    b_f = np.full((num_units, ), b_init)
    # Weights for the cell gate
    w_xc = np.full((input_dim, num_units), w_x_init)
    w_hc = np.full((num_units, num_units), w_h_init)
    b_c = np.full((num_units, ), b_init)
    # Weights for the out gate
    w_xo = np.full((input_dim, num_units), w_x_init)
    w_ho = np.full((num_units, num_units), w_h_init)
    b_o = np.full((num_units, ), b_init)

    w_x_ifco = np.concatenate([w_xi, w_xf, w_xc, w_xo], axis=1)
    w_h_ifco = np.concatenate([w_hi, w_hf, w_hc, w_ho], axis=1)

    x_ifco = np.matmul(input_val, w_x_ifco)
    h_ifco = np.matmul(step_hidden, w_h_ifco)

    x_i = x_ifco[:, :num_units]
    x_f = x_ifco[:, num_units:num_units * 2]
    x_c = x_ifco[:, num_units * 2:num_units * 3]
    x_o = x_ifco[:, num_units * 3:num_units * 4]

    h_i = h_ifco[:, :num_units]
    h_f = h_ifco[:, num_units:num_units * 2]
    h_c = h_ifco[:, num_units * 2:num_units * 3]
    h_o = h_ifco[:, num_units * 3:num_units * 4]

    i = gate_nonlinearity(x_i + h_i + b_i)
    f = gate_nonlinearity(x_f + h_f + b_f + forget_bias)
    o = gate_nonlinearity(x_o + h_o + b_o)

    c = f * step_cell + i * nonlinearity(x_c + h_c + b_c)
    h = o * nonlinearity(c)
    return h, c

def recurrent_step_gru(input_val,
                       num_units,
                       step_hidden,
                       w_x_init,
                       w_h_init,
                       b_init,
                       nonlinearity,
                       gate_nonlinearity,
                       forget_bias=1.0):
    """
    A GRU unit implements the following update mechanism:

    Reset gate:        r(t) = f_r(x(t) @ W_xr + h(t-1) @ W_hr + b_r)
    Update gate:       u(t) = f_u(x(t) @ W_xu + h(t-1) @ W_hu + b_u)
    Cell gate:         c(t) = f_c(x(t) @ W_xc + r(t) * (h(t-1) @ W_hc) + b_c)
    New hidden state:  h(t) = u_t * h(t-1) + (1 - u(t)) * c(t)

    Note that the reset, update, and cell vectors must have the same dimension
    as the hidden state.
    """

    def f(x):
        return x

    if nonlinearity is None:
        nonlinearity = f
    if gate_nonlinearity is None:
        gate_nonlinearity = f

    input_dim = np.prod(input_val.shape[1:])
    # Weights for the update gate
    w_xz = np.full((input_dim, num_units), w_x_init)
    w_hz = np.full((num_units, num_units), w_h_init)
    b_z = np.full((num_units, ), b_init)
    # Weights for the reset gate
    w_xr = np.full((input_dim, num_units), w_x_init)
    w_hr = np.full((num_units, num_units), w_h_init)
    b_r = np.full((num_units, ), b_init)
    # Weights for the hidden gate
    w_xh = np.full((input_dim, num_units), w_x_init)
    w_hh = np.full((num_units, num_units), w_h_init)
    b_h = np.full((num_units, ), b_init)

    w_x_zrh = np.concatenate([w_xz, w_xr, w_xh], axis=1)
    w_h_zrh = np.concatenate([w_hz, w_hr, w_hh], axis=1)

    x_zrh = np.matmul(input_val, w_x_zrh)
    h_zrh = np.matmul(step_hidden, w_h_zrh)

    x_z = x_zrh[:, :num_units]
    x_r = x_zrh[:, num_units:num_units * 2]
    x_h = x_zrh[:, num_units * 2:num_units * 3]

    h_z = h_zrh[:, :num_units]
    h_r = h_zrh[:, num_units:num_units * 2]
    h_h = h_zrh[:, num_units * 2:num_units * 3]

    z = gate_nonlinearity(x_z + h_z + b_z)
    r = gate_nonlinearity(x_r + h_r + b_r)
    hh = nonlinearity(x_h + r * h_h + b_h)
    h = z * step_hidden + (1 - z) * hh

    return h

def _construct_image_vector(_input, batch, w, h, filter_width, filter_height,
                            in_shape):
    """sw is sliding window"""
    sw = np.empty((filter_width, filter_height, in_shape))
    for dw in range(filter_width):
        for dh in range(filter_height):
            for in_c in range(in_shape):
                sw[dw][dh][in_c] = _input[batch][w + dw][h + dh][in_c]
    return sw.flatten()

def max_pooling(_input, pool_shape, pool_stride):
    """Max pooling."""
    batch_size = _input.shape[0]

    # max pooling
    results = np.empty((batch_size, int(_input.shape[1] / pool_shape),
                        int(_input.shape[2] / pool_shape), _input.shape[3]))
    for b in range(batch_size):
        for i, row in enumerate(range(0, _input.shape[1], pool_stride)):
            for j, col in enumerate(range(0, _input.shape[2], pool_stride)):
                for k in range(_input.shape[3]):
                    results[b][i][j][k] = np.max(
                        _input[b, col:col + pool_shape, row:row +  # noqa: W504
                               pool_shape, k])

    return results

def write_file(result_json, algo):
    """Create new progress.json or append to existing one."""
    latest_dir = './latest_results'
    latest_result = latest_dir + '/progress.json'
    res = {}
    if osp.exists(latest_result):
        res = json.loads(open(latest_result, 'r').read())
    elif not osp.exists(latest_dir):
        os.makedirs(latest_dir)
    res[algo] = result_json
    result_file = open(latest_result, 'w')
    result_file.write(json.dumps(res))

def create_json(b_csvs, g_csvs, trails, seeds, b_x, b_y, g_x, g_y, factor_g,
                factor_b):
    """Convert garage and benchmark csv outputs to json format."""
    task_result = {}
    for trail in range(trails):
        g_res, b_res = {}, {}
        trail_seed = 'trail_%d' % (trail + 1)
        task_result['seed'] = seeds[trail]
        task_result[trail_seed] = {}
        df_g = json.loads(pd.read_csv(g_csvs[trail]).to_json())
        df_b = json.loads(pd.read_csv(b_csvs[trail]).to_json())

        g_res['time_steps'] = list(
            map(lambda x: float(x) * factor_g, df_g[g_x].values()))
        g_res['return'] = df_g[g_y]

        b_res['time_steps'] = list(
            map(lambda x: float(x) * factor_b, df_b[b_x].values()))
        b_res['return'] = df_b[b_y]

        task_result[trail_seed]['garage'] = g_res
        task_result[trail_seed]['baselines'] = b_res
    return task_result

def relplot(g_csvs, b_csvs, g_x, g_y, g_z, b_x, b_y, b_z, trials, seeds,
            plt_file, env_id, x_label, y_label):
    """
    Plot benchmark from csv files of garage from multiple trials using Seaborn.

    :param g_csvs: A list contains all csv files in the task.
    :param b_csvs: A list contains all csv files in the task. Pass
        empty list or None if only plotting garage.
    :param g_x: X column names of garage csv.
    :param g_y: Y column names of garage csv.
    :param b_x: X column names of baselines csv.
    :param b_y: Y column names of baselines csv.
    :param trials: Number of trials in the task.
    :param seeds: A list contains all the seeds in the task.
    :param plt_file: Path of the plot png file.
    :param env_id: String contains the id of the environment.
    :return:
    """
    df_g = [pd.read_csv(g) for g in g_csvs]
    df_gs = pd.concat(df_g, axis=0)
    df_gs['Type'] = g_z
    data = df_gs

    if b_csvs:
        assert len(b_csvs) == len(g_csvs)
        df_b = [pd.read_csv(b) for b in b_csvs]
        df_bs = pd.concat(df_b, axis=0)
        df_bs['Type'] = b_z
        df_bs = df_bs.rename(columns={b_x: g_x, b_y: g_y})
        data = pd.concat([df_gs, df_bs])

    ax = sns.relplot(x=g_x, y=g_y, hue='Type', kind='line', data=data)
    ax.axes.flatten()[0].set_title(env_id)

    plt.savefig(plt_file)

    plt.close()

def plot(g_csvs, b_csvs, g_x, g_y, g_z, b_x, b_y, b_z, trials, seeds, plt_file,
         env_id, x_label, y_label):
    """
    Plot benchmark from csv files of garage and baselines.

    :param b_csvs: A list contains all csv files in the task.
    :param g_csvs: A list contains all csv files in the task.
    :param g_x: X column names of garage csv.
    :param g_y: Y column names of garage csv.
    :param b_x: X column names of baselines csv.
    :param b_y: Y column names of baselines csv.
    :param trials: Number of trials in the task.
    :param seeds: A list contains all the seeds in the task.
    :param plt_file: Path of the plot png file.
    :param env_id: String contains the id of the environment.
    :return:
    """
    assert len(b_csvs) == len(g_csvs)
    for trial in range(trials):
        seed = seeds[trial]

        df_g = pd.read_csv(g_csvs[trial])
        df_b = pd.read_csv(b_csvs[trial])

        plt.plot(df_g[g_x],
                 df_g[g_y],
                 label='%s_trial%d_seed%d' % (g_z, trial + 1, seed))
        plt.plot(df_b[b_x],
                 df_b[b_y],
                 label='%s_trial%d_seed%d' % (b_z, trial + 1, seed))

    plt.legend()
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    plt.title(env_id)

    plt.savefig(plt_file)
    plt.close()


from flask import Flask
import pandas as pd
import numpy as np
from flask import request
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity

app = Flask(__name__)

def create_soup(x):
    return x['task_title'] + ' ' + x['difficulty_level'] + ' '+x['task_handler'] + ' ' + x['t1']

def test_deploy(predictionTask):
    task = pd.read_csv('./software_task_updated.csv',
                       encoding="ISO-8859-1", engine='python')
    employees = pd.read_csv(
        './employee.csv',  encoding="ISO-8859-1", engine='python')
    task['soup'] = task.apply(create_soup, axis=1)
    task[['soup']]
    count = CountVectorizer(stop_words='english')
    count_matrix = count.fit_transform(task['soup'])
    cosine_sim2 = cosine_similarity(count_matrix, count_matrix)
    task = task.reset_index()
    indices = pd.Series(task.index, index=task['task_title'])

    def get_recommendations(task_title, cosine_sim=cosine_sim2):
        # Get the index of the movie that matches the title
        #     print(task_title)
        try :
            idx = indices[task_title]

            # Get the pairwsie similarity scores of all movies with that movie
            sim_scores = list(enumerate(cosine_sim[idx]))

            #     # Sort the movies based on the similarity scores
            sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
            #     sim_scores = sorted(sim_scores, reverse=True)

            #     # Get the scores of the 10 most similar movies
            sim_scores = sim_scores[1:11]
            #     # Get the movie indices
            task_indices = [i[0] for i in sim_scores]

            #     # Return the top 10 most similar movies
            return task['task_handler'].iloc[task_indices]

        except:
            return False

    pred_task = predictionTask
    predicted_Category = get_recommendations(pred_task, cosine_sim2)
    if type(predicted_Category) == bool:
        return {'status': 'false', 'message': 'null'}
    # yaha check lagana
    predicted_Category = predicted_Category.values[0]
    # return predicted_Category
    # if predicted Category not found

    def map_function(x):

        if x == 'Advanced':
            return 3
        elif x == 'Intermediate':
            return 2
        elif x == 'Beginner':
            return 1

    employees['expertise_level'] = employees['expertise_level'].apply(
        map_function)

    def getEmployee(taskCategory):
        indexes = []
        for idx, employee in enumerate(employees['employee_type']):
            if taskCategory in employee:
                if employees['available'][idx] == 'Yes':
                    indexes.append(idx)
        return indexes

    filteredDF = employees.filter(
        items=getEmployee(predicted_Category), axis=0)
    sortedDF = filteredDF.sort_values(
        by=['years_of_experience', 'expertise_level'], inplace=False, ascending=False)

    d = dict(enumerate(sortedDF.values[0].flatten(), 1))
    return {'status': 'true', 'message': d}

@app.route("/", methods=['GET'])
def hello_world():
    predictionTask = request.args.get('predictionTask')
    # return result
    return test_deploy(predictionTask)


import yfinance
' some text '.strip

a = "AB"
print(a.lower)

asx_value = 7111.4
date = "2021-01-25"
units = 1
currency = "AUD"
print(f"The closing value of {units} unit of the All Ordinaries on {date} was {asx_value} {currency}.")

# Downloads Qantas share price beginning 1 January 2020

tic = "QAN.AX"
start = '2020-01-01'
end = None
df = yfinance.download(tic, start, end)
print(df)
df.to_csv('qan_stk_prc.csv')


#this is a comment
from collections import Counter

def checkAnagram(num1,num2):
	bin1 = bin(num1)[2:]
	bin2 = bin(num2)[2:]
	zeros = abs(len(bin1)-len(bin2))
	if (len(bin1)>len(bin2)):
		bin2 = zeros * '0' + bin2
	else:
		bin1 = zeros * '0' + bin1
	dict1 = Counter(bin1)
	dict2 = Counter(bin2)
	if dict1 == dict2:
		print('Yes')
	else:
		print('No')

if __name__ == "__main__":
	num1 = int(input('Enter first number'))
	num2 = int(input('Enter second number'))
	checkAnagram(num1,num2)


import pytest
from chalice import UnprocessableEntityError, ChaliceViewError, NotFoundError

from fire_manager.application.firefighter.remove_firefighter.remove_firefighter_error_serializers import \
    RemoveFirefighterErrorSerializers
from fire_manager.domain.firefighter.remove_firefighter.remove_firefighter_usecase import \
    MissingMandatoryId, FirefighterNotFound, CouldNotRemoveFirefighter

class TestRemoveFirefighterErrorSerializers:

    def test_should_return_a_404_http_error_if_firefighter_does_not_exists(self):
        exception = FirefighterNotFound()

        with pytest.raises(NotFoundError) as exception_raised:
            RemoveFirefighterErrorSerializers.to_http_error(exception)

        assert exception_raised.value.STATUS_CODE == 404
        assert str(
            exception_raised.value) == "NotFoundError: Firefighter does not exists"

    def test_should_return_a_422_http_error_if_any_parameter_is_missing(self):
        exception = MissingMandatoryId(MissingMandatoryId.ID_IS_MISSING)

        with pytest.raises(UnprocessableEntityError) as exception_raised:
            RemoveFirefighterErrorSerializers.to_http_error(exception)

        assert exception_raised.value.STATUS_CODE == 422
        assert str(
            exception_raised.value) == 'UnprocessableEntityError: Necessary arguments missing: Field "id" is mandatory'

    def test_should_return_a_500_http_error_if_the_request_fails(self):
        exception = CouldNotRemoveFirefighter()

        with pytest.raises(ChaliceViewError) as exception_raised:
            RemoveFirefighterErrorSerializers.to_http_error(exception)

        assert exception_raised.value.STATUS_CODE == 500
        assert str(
            exception_raised.value) == "ChaliceViewError: Could not remove the firefighter"

    def test_should_return_a_500_http_error_if_any_other_error_is_raised(self):
        exception = StopIteration()

        with pytest.raises(ChaliceViewError) as exception_raised:
            RemoveFirefighterErrorSerializers.to_http_error(exception)

        assert exception_raised.value.STATUS_CODE == 500
        assert str(
            exception_raised.value) == 'ChaliceViewError: An unknown error had happen ¯\_(ツ)_/¯'


"""scrapli_netconf.transport.plugins.system.transport"""
from io import BytesIO

from scrapli.exceptions import ScrapliConnectionNotOpened
from scrapli.transport.base import BaseTransportArgs
from scrapli.transport.plugins.system.transport import PluginTransportArgs, SystemTransport

# imported from base driver
_ = PluginTransportArgs

class NetconfSystemTransport(SystemTransport):
    def __init__(
        self, base_transport_args: BaseTransportArgs, plugin_transport_args: PluginTransportArgs
    ):
        self.write_chunk_size = 65535
        super().__init__(
            base_transport_args=base_transport_args, plugin_transport_args=plugin_transport_args
        )

    def _build_open_cmd(self) -> None:
        super()._build_open_cmd()
        # adding `-tt` forces tty allocation which lets us send a string greater than 1024 chars;
        # without this we are basically capped at 1024 chars and scrapli will/the connection will
        # die. it *may* be possible to alter ptyprocess vendor'd code to add `stty -icanon` which
        # should also have a similar affect, though this seems simpler.
        self.open_cmd.extend(["-tt"])
        self.open_cmd.extend(["-s", "netconf"])
        self.logger.debug(f"final open_cmd: {self.open_cmd}")

    def open_netconf(self) -> None:
        """
        Netconf open method

        Simply calls the "normal" open method, but retaining an explicit "netconf" open for sanity

        Args:
            N/A

        Returns:
            None

        Raises:
            N/A

        """
        self.open()

    def write(self, channel_input: bytes) -> None:
        if not self.session:
            raise ScrapliConnectionNotOpened

        if self.write_chunk_size <= 0:
            self.session.write(channel_input)
        else:
            bytes_to_send_len = len(channel_input)
            bytes_to_send = BytesIO(channel_input)
            bytes_sent = 0

            while bytes_sent < bytes_to_send_len:
                self.session.write(bytes_to_send.read(self.write_chunk_size))
                bytes_sent += self.write_chunk_size


import requests
from bs4 import BeautifulSoup

def get_html(url):
    response = requests.get(url)
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')
    return soup

def get_table_data(table):
    teams = table.find_all('tr')
    for team in teams:
        team_info = dict()
        info = team.find_all('td', {'class' : 'standing-table__cell'})
        #print(info)
        team_info['team'] = info[1]['data-long-name']
        team_info['position'] = int(info[0].text)
        team_info['played'] = int(info[2].text)
        team_info['won'] = int(info[3].text)
        team_info['draw'] = int(info[4].text)
        team_info['lost'] = int(info[5].text)
        team_info['fouls'] = int(info[6].text)
        team_info['assists'] = int(info[7].text)
        team_info['goals'] = int(info[8].text)
        team_info['points'] = int(info[9].text)
        yield team_info
        #break
url = 'https://www.skysports.com/premier-league-table'
table = get_html(url).find('tbody')
data = get_table_data(table)


from torch import nn
import torch

class MyNet(nn.Module):
    def __init__(self):  # 第一个方法，初始化
        super(MyNet, self).__init__()  # 继承父类的方法
        self.layers = nn.Sequential(

            nn.Conv2d(3, 11, 3),  # 输入通道为3，输出通道为11，卷积核为3*3
            nn.LeakyReLU(),  # 激活一下
            nn.MaxPool2d(3),  # 池化一下

            nn.Conv2d(11, 22, 3),
            nn.LeakyReLU(),
            nn.MaxPool2d(2),

            nn.Conv2d(22, 32, 3),
            nn.LeakyReLU(),
            nn.MaxPool2d(2),

            nn.Conv2d(32, 64, 3),
            nn.LeakyReLU(),

            nn.Conv2d(64, 128, 3),
            nn.LeakyReLU()

        )
        self.label_layer = nn.Sequential(  # 对label的卷积
            nn.Conv2d(128, 1, 19),
            nn.ReLU(),
        )
        self.position_layer = nn.Sequential(  # 对position的卷积
            nn.Conv2d(128, 4, 19),
            nn.LeakyReLU(),
        )
        self.sort_layer = nn.Sequential(  # 对sort的卷积
            nn.Conv2d(128, 20, 19),
            nn.LeakyReLU(),
        )

    def forward(self, x):  # 前向计算
        out = self.layers(x)
        label = self.label_layer(out)
        label = torch.squeeze(label, dim=2)  # 对第二个位置进行降维，只输出一个值
        label = torch.squeeze(label, dim=2)
        label = torch.squeeze(label, dim=1)
        position = self.position_layer(out)
        position = torch.squeeze(position, dim=2)
        position = torch.squeeze(position, dim=2)
        sot = self.sort_layer(out)
        sot = torch.squeeze(sot, dim=2)
        sot = torch.squeeze(sot, dim=2)
        return label, position, sot

"""
if __name__=='__main__':
    net=MyNet().cuda()
    x=torch.rand(3,3,300,300).cuda() #参数含义，批次，通道，维度，维度
    print(net(x)[0].shape)
    print(net(x)[1].shape)
    print(net(x)[2].shape)
"""


import base64
import functools
import os

from django.conf import settings
from django.contrib.auth import login, logout
from django.core import signing
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.utils.encoding import force_bytes
from django.utils.http import is_safe_url
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _

from rest_framework import generics
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from waffle.decorators import waffle_switch

import olympia.core.logger
from olympia import amo
from olympia.access.models import GroupUser
from olympia.amo import messages
from olympia.amo.decorators import write
from olympia.api.authentication import (
    JWTKeyAuthentication, WebTokenAuthentication)
from olympia.api.permissions import GroupPermission
from olympia.users.models import UserProfile

from . import verify
from .serializers import AccountSuperCreateSerializer, UserProfileSerializer
from .utils import fxa_login_url, generate_fxa_state

log = olympia.core.logger.getLogger('accounts')

ERROR_AUTHENTICATED = 'authenticated'
ERROR_NO_CODE = 'no-code'
ERROR_NO_PROFILE = 'no-profile'
ERROR_NO_USER = 'no-user'
ERROR_STATE_MISMATCH = 'state-mismatch'
ERROR_STATUSES = {
    ERROR_AUTHENTICATED: 400,
    ERROR_NO_CODE: 422,
    ERROR_NO_PROFILE: 401,
    ERROR_STATE_MISMATCH: 400,
}
LOGIN_ERROR_MESSAGES = {
    ERROR_AUTHENTICATED: _(u'You are already logged in.'),
    ERROR_NO_CODE:
        _(u'Your login attempt could not be parsed. Please try again.'),
    ERROR_NO_PROFILE:
        _(u'Your Firefox Account could not be found. Please try again.'),
    ERROR_STATE_MISMATCH: _(u'You could not be logged in. Please try again.'),
}

API_TOKEN_COOKIE = 'api_auth_token'

def safe_redirect(url, action):
    if not is_safe_url(url):
        url = reverse('home')
    log.info(u'Redirecting after {} to: {}'.format(action, url))
    return HttpResponseRedirect(url)

def find_user(identity):
    """Try to find a user for a Firefox Accounts profile. If the account
    hasn't been migrated we'll need to do the lookup by email but we should
    use the ID after that so check both. If we get multiple users we're in
    some weird state where the accounts need to be merged but that behaviour
    hasn't been defined so let it raise.
    """
    try:
        return UserProfile.objects.get(
            Q(fxa_id=identity['uid']) | Q(email=identity['email']))
    except UserProfile.DoesNotExist:
        return None
    except UserProfile.MultipleObjectsReturned:
        # This shouldn't happen, so let it raise.
        log.error(
            'Found multiple users for {email} and {uid}'.format(**identity))
        raise

def register_user(request, identity):
    user = UserProfile.objects.create_user(
        email=identity['email'], username=None, fxa_id=identity['uid'])
    log.info('Created user {} from FxA'.format(user))
    login(request, user)
    return user

def update_user(user, identity):
    """Update a user's info from FxA if needed, as well as generating the id
    that is used as part of the session/api token generation."""
    if (user.fxa_id != identity['uid'] or
            user.email != identity['email']):
        log.info(
            'Updating user info from FxA for {pk}. Old {old_email} {old_uid} '
            'New {new_email} {new_uid}'.format(
                pk=user.pk, old_email=user.email, old_uid=user.fxa_id,
                new_email=identity['email'], new_uid=identity['uid']))
        user.update(fxa_id=identity['uid'], email=identity['email'])
    if user.auth_id is None:
        # If the user didn't have an auth id (old user account created before
        # we added the field), generate one for them.
        user.update(auth_id=UserProfile._meta.get_field('auth_id').default())

def login_user(request, user, identity):
    update_user(user, identity)
    log.info('Logging in user {} from FxA'.format(user))
    user.log_login_attempt(True)
    login(request, user)

def fxa_error_message(message):
    login_help_url = (
        'https://support.mozilla.org/kb/access-your-add-ons-firefox-accounts')
    return format_html(
        u'{error} {help_text}',
        url=login_help_url, help_text=_(u'Need help?'),
        error=message)

def render_error(request, error, next_path=None, format=None):
    if format == 'json':
        status = ERROR_STATUSES.get(error, 422)
        response = Response({'error': error}, status=status)
    else:
        if not is_safe_url(next_path):
            next_path = None
        messages.error(
            request, fxa_error_message(LOGIN_ERROR_MESSAGES[error]),
            extra_tags='fxa')
        if next_path is None:
            response = HttpResponseRedirect(reverse('users.login'))
        else:
            response = HttpResponseRedirect(next_path)
    return response

def parse_next_path(state_parts):
    next_path = None
    if len(state_parts) == 2:
        # The = signs will be stripped off so we need to add them back
        # but it only cares if there are too few so add 4 of them.
        encoded_path = state_parts[1] + '===='
        try:
            next_path = base64.urlsafe_b64decode(
                force_bytes(encoded_path)).decode('utf-8')
        except TypeError:
            log.info('Error decoding next_path {}'.format(
                encoded_path))
            pass
    if not is_safe_url(next_path):
        next_path = None
    return next_path

def with_user(format, config=None):

    def outer(fn):
        @functools.wraps(fn)
        @write
        def inner(self, request):
            if config is None:
                if hasattr(self, 'get_fxa_config'):
                    fxa_config = self.get_fxa_config(request)
                else:
                    fxa_config = (
                        settings.FXA_CONFIG[settings.DEFAULT_FXA_CONFIG_NAME])
            else:
                fxa_config = config

            if request.method == 'GET':
                data = request.query_params
            else:
                data = request.data

            state_parts = data.get('state', '').split(':', 1)
            state = state_parts[0]
            next_path = parse_next_path(state_parts)
            if not data.get('code'):
                log.info('No code provided.')
                return render_error(
                    request, ERROR_NO_CODE, next_path=next_path, format=format)
            elif (not request.session.get('fxa_state') or
                    request.session['fxa_state'] != state):
                log.info(
                    'State mismatch. URL: {url} Session: {session}'.format(
                        url=data.get('state'),
                        session=request.session.get('fxa_state'),
                    ))
                return render_error(
                    request, ERROR_STATE_MISMATCH, next_path=next_path,
                    format=format)
            elif request.user.is_authenticated():
                response = render_error(
                    request, ERROR_AUTHENTICATED, next_path=next_path,
                    format=format)
                # If the api token cookie is missing but we're still
                # authenticated using the session, add it back.
                if API_TOKEN_COOKIE not in request.COOKIES:
                    log.info('User %s was already authenticated but did not '
                             'have an API token cookie, adding one.',
                             request.user.pk)
                    response = add_api_token_to_response(
                        response, request.user)
                return response
            try:
                identity = verify.fxa_identify(data['code'], config=fxa_config)
            except verify.IdentificationError:
                log.info('Profile not found. Code: {}'.format(data['code']))
                return render_error(
                    request, ERROR_NO_PROFILE, next_path=next_path,
                    format=format)
            else:
                return fn(
                    self, request, user=find_user(identity), identity=identity,
                    next_path=next_path)
        return inner
    return outer

def generate_api_token(user):
    """Generate a new API token for a given user."""
    data = {
        'auth_hash': user.get_session_auth_hash(),
        'user_id': user.pk,
    }
    return signing.dumps(data, salt=WebTokenAuthentication.salt)

def add_api_token_to_response(response, user):
    """Generate API token and add it to the response (both as a `token` key in
    the response if it was json and by setting a cookie named API_TOKEN_COOKIE.
    """
    token = generate_api_token(user)
    if hasattr(response, 'data'):
        response.data['token'] = token
    # Also include the API token in a session cookie, so that it is
    # available for universal frontend apps.
    response.set_cookie(
        API_TOKEN_COOKIE,
        token,
        max_age=settings.SESSION_COOKIE_AGE,
        secure=settings.SESSION_COOKIE_SECURE,
        httponly=settings.SESSION_COOKIE_HTTPONLY)

    return response

def remove_api_token_cookie(response):
    """Delete the api token cookie."""
    response.delete_cookie(API_TOKEN_COOKIE)

class FxAConfigMixin(object):

    def get_config_name(self, request):
        return request.GET.get('config', self.DEFAULT_FXA_CONFIG_NAME)

    def get_allowed_configs(self):
        return getattr(
            self, 'ALLOWED_FXA_CONFIGS', [self.DEFAULT_FXA_CONFIG_NAME])

    def get_fxa_config(self, request):
        config_name = self.get_config_name(request)
        if config_name in self.get_allowed_configs():
            return settings.FXA_CONFIG[config_name]
        log.info('Using default FxA config instead of {}'.format(config_name))
        return settings.FXA_CONFIG[self.DEFAULT_FXA_CONFIG_NAME]

class LoginStartBaseView(FxAConfigMixin, APIView):

    def get(self, request):
        request.session.setdefault('fxa_state', generate_fxa_state())
        return HttpResponseRedirect(
            fxa_login_url(
                config=self.get_fxa_config(request),
                state=request.session['fxa_state'],
                next_path=request.GET.get('to'),
                action=request.GET.get('action', 'signin')))

class LoginStartView(LoginStartBaseView):
    DEFAULT_FXA_CONFIG_NAME = settings.DEFAULT_FXA_CONFIG_NAME
    ALLOWED_FXA_CONFIGS = settings.ALLOWED_FXA_CONFIGS

class LoginBaseView(FxAConfigMixin, APIView):

    @with_user(format='json')
    def post(self, request, user, identity, next_path):
        if user is None:
            return Response({'error': ERROR_NO_USER}, status=422)
        else:
            update_user(user, identity)
            response = Response({'email': identity['email']})
            add_api_token_to_response(response, user)
            log.info('Logging in user {} from FxA'.format(user))
            return response

    def options(self, request):
        return Response()

class LoginView(LoginBaseView):
    DEFAULT_FXA_CONFIG_NAME = settings.DEFAULT_FXA_CONFIG_NAME
    ALLOWED_FXA_CONFIGS = settings.ALLOWED_FXA_CONFIGS

class RegisterView(APIView):
    authentication_classes = (SessionAuthentication,)

    @with_user(format='json')
    def post(self, request, user, identity, next_path):
        if user is not None:
            return Response({'error': 'That account already exists.'},
                            status=422)
        else:
            user = register_user(request, identity)
            response = Response({'email': user.email})
            add_api_token_to_response(response, user)
            return response

class AuthenticateView(FxAConfigMixin, APIView):
    DEFAULT_FXA_CONFIG_NAME = settings.DEFAULT_FXA_CONFIG_NAME
    ALLOWED_FXA_CONFIGS = settings.ALLOWED_FXA_CONFIGS

    authentication_classes = (SessionAuthentication,)

    @with_user(format='html')
    def get(self, request, user, identity, next_path):
        if user is None:
            user = register_user(request, identity)
            fxa_config = self.get_fxa_config(request)
            if fxa_config.get('skip_register_redirect'):
                response = safe_redirect(next_path, 'register')
            else:
                response = safe_redirect(reverse('users.edit'), 'register')
        else:
            login_user(request, user, identity)
            response = safe_redirect(next_path, 'login')
        add_api_token_to_response(response, user)
        return response

def logout_user(request, response):
    logout(request)
    remove_api_token_cookie(response)

class SessionView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, *args, **kwargs):
        response = Response({'ok': True})
        logout_user(request, response)
        return response

class ProfileView(generics.RetrieveAPIView):
    authentication_classes = [JWTKeyAuthentication]
    permission_classes = [IsAuthenticated]
    serializer_class = UserProfileSerializer

    def retrieve(self, request, *args, **kw):
        return Response(self.get_serializer(request.user).data)

class AccountSuperCreate(APIView):
    authentication_classes = [JWTKeyAuthentication]
    permission_classes = [
        IsAuthenticated,
        GroupPermission(amo.permissions.ACCOUNTS_SUPER_CREATE)]

    @waffle_switch('super-create-accounts')
    def post(self, request):
        serializer = AccountSuperCreateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response({'errors': serializer.errors},
                            status=422)

        data = serializer.data

        group = serializer.validated_data.get('group', None)
        user_token = os.urandom(4).encode('hex')
        username = data.get('username', 'super-created-{}'.format(user_token))
        fxa_id = data.get('fxa_id', None)
        email = data.get('email', '{}@addons.mozilla.org'.format(username))

        user = UserProfile.objects.create(
            username=username,
            email=email,
            fxa_id=fxa_id,
            display_name='Super Created {}'.format(user_token),
            is_verified=True,
            notes='auto-generated from API')
        user.save()

        if group:
            GroupUser.objects.create(user=user, group=group)

        login(request, user)
        request.session.save()

        log.info(u'API user {api_user} created and logged in a user from '
                 u'the super-create API: user_id: {user.pk}; '
                 u'user_name: {user.username}; fxa_id: {user.fxa_id}; '
                 u'group: {group}'
                 .format(user=user, api_user=request.user, group=group))

        cookie = {
            'name': settings.SESSION_COOKIE_NAME,
            'value': request.session.session_key,
        }
        cookie['encoded'] = '{name}={value}'.format(**cookie)

        return Response({
            'user_id': user.pk,
            'username': user.username,
            'email': user.email,
            'display_name': user.display_name,
            'groups': list((g.pk, g.name, g.rules) for g in user.groups.all()),
            'fxa_id': user.fxa_id,
            'session_cookie': cookie,
        }, status=201)


import os
import sys

sys.path.insert(0, os.path.realpath(os.getcwd()))

import importlib
import os
import sys
import time
from fabric.api import local
from fabric.decorators import task

import version
from secrets import pypi_auth

def fatal(msg):
    print("Fatal error: {}; exiting.".format(msg))
    sys.exit(1)

def docker_exec(cmdline):
    """
    Execute command in running docker container
    :param cmdline: command to be executed
    """
    local('docker exec -ti hmm_filter {}'.format(cmdline))

def inc_version():
    """
    Increment micro release version (in 'major.minor.micro') in version.py and re-import it.
    Major and minor versions must be incremented manually in version.py.

    :return: list with current version numbers, e.g., [0,1,23].
    """

    new_version = version.__version__

    values = list(map(lambda x: int(x), new_version.split('.')))
    values[2] += 1

    with open('version.py', 'w') as f:
        f.write('__version__ = "{}.{}.{}"\n'.format(values[0], values[1], values[2]))
    with open('hmm_filter/version.py', 'w') as f:
        f.write('__version__ = "{}.{}.{}"\n'.format(values[0], values[1], values[2]))

    importlib.reload(version)

    print('Current version: {}'.format(version.__version__))

    return values

@task
def git_check():
    """
    Check that all changes , besides versioning files, are committed
    :return:
    """

    # check that changes staged for commit are pushed to origin
    output = local('git diff --name-only | egrep -v "^(hmm_filter/version.py)|(version.py)$" | tr "\\n" " "',
                   capture=True).strip()
    if output:
        fatal('Stage for commit and commit all changes first: {}'.format(output))

    output = local('git diff --cached --name-only | egrep -v "^(hmm_filter/version.py)|(version.py)$" | tr "\\n" " "',
                   capture=True).strip()
    if output:
        fatal('Commit all changes first: {}'.format(output))

def git_push():
    """
    Push new version and corresponding tag to origin
    :return:
    """

    # get current version
    new_version = version.__version__
    values = list(map(lambda x: int(x), new_version.split('.')))

    # Push to origin new version and corresponding tag:
    # * commit new version
    # * create tag
    # * push version,tag to origin
    local('git add hmm_filter/version.py version.py')

    local('git commit -m "updated version"')
    local('git tag {}.{}.{}'.format(values[0], values[1], values[2]))
    local('git push origin --tags')
    local('git push')

@task
def docker_build(options=''):
    """
    Build docker image
    """
    local('docker build {} -t hmm_filter .'.format(options))

@task
def docker_start(develop=True):
    """
    Start docker container
    """
    curr_dir = os.path.dirname(os.path.realpath(__file__))
    local('docker run --rm --name hmm_filter -d -ti -p 127.0.0.1:8889:8888  -v {}:/code -t hmm_filter'.format(curr_dir))

    if develop:
        # Install package in develop mode: the code in /code is mapped to the installed package.
        docker_exec('python3 setup.py develop')

    print('Jupyter lab available at http://127.0.0.1:8889')

@task
def docker_stop():
    """
    Stop docker container
    """
    local('docker stop hmm_filter 2> /dev/null || true')

@task
def docker_sh():
    """
    Execute command in docker container
    """
    docker_exec('/bin/bash')

@task
def test_pip(cleancontainer=True):
    """
    Run all tests in docker container
    :param params: parameters to py.test
    """

    if cleancontainer:
        docker_stop()
        # sometimes, Docker returns too early and then docker_start fails.
        time.sleep(1)
        docker_start(develop=False)
    # WE have now a fresh container as defined in Dockerfile

    docker_exec('pip install hmm_filter')
    test()

    # restart with develop package install
    docker_stop()
    docker_start()

    print("All tests passed!")

@task
def test(params=''):
    """
    Run all tests in docker container
    :param params: parameters to py.test
    """
    docker_exec('py.test {}'.format(params))

@task
def test_sx(params=''):
    """
    Execute all tests in docker container printing output and terminating tests at first failure
    :param params: parameters to py.test
    """
    docker_exec('py.test -sx {}'.format(params))

@task
def test_pep8():
    """
    Execute  only pep8 test in docker container
    """
    docker_exec('py.test tests/test_pep8.py')

@task
def fix_pep8():
    """
    Fix a few common and easy PEP8 mistakes in docker container
    """
    docker_exec('autopep8 --select E251,E303,W293,W291,W391,W292,W391,E302 --aggressive --in-place --recursive .')

@task
def build():
    """
    Build package in docker container
    :return:
    """
    docker_exec('python3 setup.py sdist bdist_wheel')

@task
def release():
    """
    Release new package version to pypi
    :return:
    """

    # Check that all changes are committed before creating a new version
    git_check()

    # Test package
    test()

    # Increment version
    inc_version()

    # Commit new version, create tag for version and push everything to origin
    git_push()

    # Build and publish package
    build()
    pathname = 'dist/hmm_filter-{}.tar.gz'.format(version.__version__)
    docker_exec('twine upload -u {user} -p {pass} {pathname}'.format(pathname=pathname, **pypi_auth))

    # Remove temporary files
    clean()

@task
def clean():
    """
    Rempove temporary files
    """
    local('rm -rf .cache .eggs build dist')


import numpy as np
from scipy.io import loadmat
import pickle
import random

window_len = 30*256

pid = 1

file_x = r'\Users\Owner\Desktop\chb-mit\data\patient{0}\features_se.mat'.format(pid)
file_y = r'\Users\Owner\Desktop\chb-mit\data\patient{0}\y_data{0}.npy'.format(pid)
interval_file = r'\Users\Owner\Desktop\chb-mit\data\patient{0}\intervals.data'.format(pid)

x = loadmat(file_x)
y = np.load(file_y)
x_data = list()
y_data = list()

with open(interval_file, "rb") as f:
    intervals = pickle.load(f)

for i in range(len(intervals)-1):
    start = intervals[i]
    end = intervals[i+1]

    num_windows = np.int(np.floor((end-start)/window_len))

    # hour data
    x_subset = x[start:end,:]
    y_subset = y[start:end]

    for j in range(num_windows):
        window_x = x_subset[j*self.window_len:(j+1)*self.window_len]
        window_y = y_subset[j*self.window_len:(j+1)*self.window_len]
        x_svm_avg = np.average(window_x, axis=0)
        x_svm_std = np.std(window_x, axis=0)
        x_svm = np.concatenate((x_svm_avg,x_svm_std), axis=1)
        #x_svm = np.reshape(x_svm,(-1,1))
        y_svm =  int(max(window_y))
        x_data.append(x_svm)
        y_data.append(y_svm)

c = list(zip(x_data, y_data))
random.shuffle(c)
x_data, y_data = zip(*c)

x_svm = np.concatenate(x_data,axis=0)
y_svm = np.asarray(y_data)


import discord
import os
import json

from discord.ext import commands, tasks
from itertools import cycle

def get_prefix(client, message):
    with open('prefixes.json', 'r') as f:
        prefixes = json.load(f)

        return prefixes[str(message.guild.id)]

intents = discord.Intents.all()
client = commands.Bot(command_prefix = get_prefix, intents=intents)
status = cycle(['!help for help!', 'Stay tuned for more'])

@client.event
async def on_ready():
    await client.change_presence(activity=discord.Game('ball'))
    change_status.start()
    print('Bot is ready.')

@client.event
async def on_guild_join(guild):

    with open('prefixes.json', 'r') as f:
        prefixes = json.load(f)

    prefixes[str(guild.id)] = '!'

    with open('prefixes.json', 'w') as f:
        json.dump(prefixes, f, indent = 4)

@client.event
async def on_guild_remove(guild):
    with open('prefixes.json', 'r') as f:
        prefixes = json.load(f)

    prefixes.pop(str(guild.id))

    with open('prefixes.json', 'w') as f:
        json.dump(prefixes, f, indent = 4)

@client.command()
async def change_prefix(ctx, prefix):
    with open('prefixes.json', 'r') as f:
        prefixes = json.load(f)

    prefixes[str(ctx.guild.id)] = prefix

    with open('prefixes.json', 'w') as f:
        json.dump(prefixes, f, indent = 4)

    await ctx.send(f'Prefix changed to: {prefix}')

@tasks.loop(seconds=10)
async def change_status():
    await client.change_presence(activity=discord.Game(next(status)))

#def is_it_me(ctx):
#    return ctx.author.id == 992991780062646372

#@client.command()
#@commands.check(is_it_me)
#async def example(ctx):
#    await ctx.send(f'Hi, I\'m {ctx.author}')

@client.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound):
        await ctx.send('Command does not exist, refer to !help for known commands.')
    if isinstance(error, commands.MissingRequiredArgument):
        await ctx.send('Please pass in all requirements')
    if isinstance(error, commands.MissingPermissions):
        await ctx.send("You dont have all the requirements")

@client.command()
async def load(ctx, extension):
    client.load_extension(f'cogs.{extension}')

@client.command()
async def unload(ctx, extension):
    client.unload_extension(f'cogs.{extension}')

@client.command()
async def reload(ctx, extension):
    client.unload_extension(f'cogs.{extension}')
    client.load_extension(f'clogs.{extension}')

for filename in os.listdir('./cogs'):
    if filename.endswith('.py'):
        client.load_extension(f'cogs.{filename[:-3]}')

client.run('token')


from collections import defaultdict
from utils.env import Environment

class JobProcessor():
    def __init__(self, param_dict):
        self.env = Environment()
        self.job_name = 'job_{0}'.format(self.env.get_env())
        self.jobparam_dict = param_dict[self.job_name]
        self.build_table()
        self.done = False

    def build_table(self):
        self.job_table = defaultdict(dict)
        self.index_table = defaultdict(dict)
        for k in self.jobparam_dict:
            tmp = self.rangestr2array(self.jobparam_dict[k])
            if tmp is not None and len(tmp) != 0:
                self.job_table[k] = tmp
                self.index_table[k] = 0

    def init(self):
        for k in self.index_table:
            self.index_table[k] = 0
        self.done = False

    def has_next(self):
        return not self.done

    def cur_params(self):
        params = defaultdict(dict)
        for k in self.index_table:
            params[k] = self.job_table[k][self.index_table[k]]
        return params

    def carry_by_one(self, carry_index):
        keys = list(self.index_table.keys())
        for j in range(carry_index + 1):
            self.index_table[keys[j]] = 0
        if carry_index + 1 == len(keys):
            self.done = True
            return
        j = carry_index + 1
        while j < len(keys) and len(self.job_table[keys[j]]) <= 1:
            j += 1
        if j < len(keys):
            if self.index_table[keys[j]] == len(self.job_table[keys[j]]) - 1:
                # self.carry = True
                self.carry_by_one(j)
            else:
                self.index_table[keys[j]] += 1
        else:
            self.done = True

    def process(self):
        params = self.cur_params()

        # proceed by 1
        # if self.curry:
        #     self.curry = False
        #     return
        keys = list(self.index_table.keys())
        for i in range(len(keys)):
            if self.index_table[keys[i]] < len(self.job_table[keys[i]]):
                if self.index_table[keys[i]] ==\
                        len(self.job_table[keys[i]]) - 1:
                    self.carry_by_one(i)
                    return
                self.index_table[keys[i]] += 1
                return

    def rangestr2array(self, rangestr):
        # if given str is already array then just return it.
        if isinstance(rangestr, list):
            return rangestr
        if type(rangestr) is int:
            return [rangestr]
        if len(rangestr) > 0 and rangestr[0] == '[' and rangestr[len(rangestr) - 1] == ']':
            params = rangestr[1:len(rangestr)-1].split(',')
            if len(params) > 1:
                params = [int(x.replace(' ', '')) for x in params]
                print(params)
                return params
        params = rangestr.split(',')
        if len(params) > 1:
            params = [int(x.replace(' ', '')) for x in params]
            if len(params) == 2:
                return [x for x in range(params[0], params[1]+1)]
            if len(params) == 3:
                return [x for x in range(params[0], params[1]+1, params[2])]
        return [rangestr]


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, OrdinalEncoder
from xgboost import XGBClassifier
from sklearn.metrics import (
    ConfusionMatrixDisplay,
    confusion_matrix,
    classification_report,
    f1_score,
)

from preprocessing import TEST_SIZE
from MLFineTuning import RANDOM_STATE

warnings.simplefilter(action="ignore", category=FutureWarning)
warnings.simplefilter(action="ignore", category=UserWarning)

# Funzione per la stampa a console e la creazione di una confusion matrix dei risultati di un modello
def performance(model_name, y_test, y_pred, type, graph=True):
    print(
        "-----------------",
        model_name,
        "-----------------",
    )

    cm = confusion_matrix(y_pred, y_test)
    disp = ConfusionMatrixDisplay(confusion_matrix=cm)
    disp.plot()
    if graph:
        plt.savefig("./Images/Results/" + model_name + "_" + type + ".png")

    print("----------------------------------------------------------")
    print("Confusion Matrix")
    print(cm)
    print("----------------------------------------------------------")
    print("Classification Report")
    print(classification_report(y_pred, y_test))

# Script che crea, allena e testa gli stessi due modelli prima sul dataset puro, poi sulla sua versione processata
def main():
    df = pd.read_csv("./Datasets/Adult.csv")
    y = df.pop("income")
    X = df

    o = OrdinalEncoder()
    X = o.fit_transform(X)

    l = LabelEncoder()
    y = l.fit_transform(y)

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=TEST_SIZE, stratify=y, random_state=RANDOM_STATE
    )

    XGmodel = XGBClassifier(criterion="gini", max_depth=5, max_features="log2", n_estimators=140)
    RFmodel = RandomForestClassifier(
        bootstrap=True,
        max_depth=20,
        max_features=6,
        min_samples_leaf=1,
        min_samples_split=5,
        n_estimators=120,
    )

    XGmodel.fit(X_train, y_train)
    RFmodel.fit(X_train, y_train)

    y_pred_XG = XGmodel.predict(X_test)
    y_pred_RF = RFmodel.predict(X_test)

    print("\n\nDATASET NON PREPROCESSATO\n\n")

    performance("XGBoost", y_test, y_pred_XG, "noP")
    performance("RandomForest", y_test, y_pred_RF, "noP")

    X_train = pd.read_csv("./Datasets/TrainData.csv")
    y_train = pd.read_csv("./Datasets/TrainLabel.csv")
    X_test = pd.read_csv("./Datasets/TestData.csv")
    y_test = pd.read_csv("./Datasets/TestLabel.csv")

    XGmodel.fit(X_train, y_train)
    RFmodel.fit(X_train, y_train)

    y_pred_XG = XGmodel.predict(X_test)
    y_pred_RF = RFmodel.predict(X_test)

    print("\n\nDATASET PREPROCESSATO\n\n")

    performance("XGBoost", y_test, y_pred_XG, "noP", False)
    performance("RandomForest", y_test, y_pred_RF, "noP", False)

if __name__ == "__main__":
    main()


import random
from typing import List, Tuple, Any

from jass.agents.agent import Agent
from jass.logic.card import Card, Suit
from jass.logic.deck import Deck
from jass.logic.exceptions import GameOver
from jass.logic.player import Player
from jass.logic.trick import Trick

GOAL = 1000

class Team:
    def __init__(self, player1: Player, player2: Player):
        self.player1 = player1
        self.player2 = player2
        self.score = 0

    @property
    def players(self) -> List[Player]:
        return [self.player1, self.player2]

    def __contains__(self, player: Player):
        return self.player1 == player or self.player2 == player

class Game:
    def __init__(self, agents: List[Agent], names: List[str] = None, log_fn=None, goal=GOAL):
        assert len(agents) == 4, 'It is a 4 players game, need 4 agents'
        if names is None:
            names = [f'{a.__class__.__name__}{random.randint(1e6, 1e7 - 1)}' for a in agents]
        assert len(set(names)) == 4, 'It is a 4 players game, need 4 unique names'

        self.__players = [Player(name, agent) for name, agent in zip(names, agents)]
        team1 = Team(
            player1=self.__players[0],
            player2=self.__players[2],
        )
        team2 = Team(
            player1=self.__players[1],
            player2=self.__players[3],
        )
        self.__goal = goal
        self.__teams = (team1, team2)
        self.__log_fn = log_fn
        self.n = 0

    @property
    def players(self) -> Tuple[Player, Player, Player, Player]:
        p1, p2, p3, p4 = self.__players
        return p1, p2, p3, p4

    @property
    def teams(self) -> Tuple[Team, Team]:
        return self.__teams

    def start(self) -> None:

        self.__log('Let\'s start a Jass Game :)')

        trump_chooser: Player = None
        deck = Deck()  # this reuses the same cards object -> slight memory/performance gain

        try:
            while True:

                #########################
                # GIVE CARDS TO PLAYERS #
                #########################

                for player, hand in zip(self.__players, deck.shuffle().give_hands()):
                    player.give(hand)

                ################
                # CHOOSE TRUMP #
                ################

                if trump_chooser is None:
                    for p in self.__players:
                        if p.has_7_diamonds():
                            trump_chooser = p
                            self.__log(f'{p} has the {Card(7, Suit.diamonds)}!')
                            break

                trump = self.choose_trump(
                    trump_chooser=trump_chooser
                )

                #####################
                # PLAY THE 9 TRICKS #
                #####################

                self.play_9_tricks(
                    trump=trump,
                    trump_chooser=trump_chooser,
                )

                ###########
                # RESTART #
                ###########

                trump_chooser = self.__next_player(trump_chooser)
                self.__log_score()

                self.n += 1
                if self.n % 20 == 0:
                    self.n = 0
                    print(f'Score difference: {self.teams[0].score - self.teams[1].score}')

        except GameOver as e:
            self.__log(e)
            self.__log_score()

    def choose_trump(self, trump_chooser: Player) -> Suit:
        trump = trump_chooser.choose_trump(can_chibre=True)
        if trump is None:  # chibre!
            self.__log(f'{trump_chooser} chibre!')
            partner = self.__partner_of(trump_chooser)
            trump = partner.choose_trump(can_chibre=False)
            self.__log(f'{partner} choose trump suit = {trump}')
        else:
            self.__log(f'{trump_chooser} choose trump suit = {trump}')
        return trump

    def play_9_tricks(self, trump: Suit, trump_chooser: Player) -> None:
        next_trick_starter: Player = trump_chooser
        prev_tricks: List[Trick] = []

        trick_7 = None
        for trick_idx in range(9):

            trick, points = self.play_trick(
                trump=trump,
                trump_chooser=trump_chooser,
                starter=next_trick_starter,
                is_last_trick=trick_idx == 8,
                prev_tricks=prev_tricks,
            )
            prev_tricks.append(trick)
            winner = trick.winner

            ##############
            # ADD POINTS #
            ##############

            winning_team = self.__team_of(winner)
            winning_team.score += points
            if trick_idx == 7:
                trick_7 = trick
            else:
                if trick_idx == 8:
                    if trick_7.winner in winning_team:
                        points += trick_7.points
                    else:
                        points -= trick_7.points
                for p in self.__players:
                    if p in winning_team:
                        p.reward(points=points, is_last_trick=trick_idx == 8)
                    else:
                        p.reward(points=-points, is_last_trick=trick_idx == 8)

            next_trick_starter = winner

            if self.__has_won(winning_team):
                raise GameOver(f'{winning_team.player1}-{winning_team.player2} team won')

    def play_trick(self, trump: Suit, trump_chooser: Player, starter: Player, is_last_trick: bool,
                   prev_tricks: List[Trick]):

        trick = Trick(trump)

        ####################
        # PLAY EACH A CARD #
        ####################

        for player in self.__players_order_from(starter):
            if is_last_trick:
                card_played = player.hand_cards[0]
            else:
                card_played = player.play(
                    trump=trump,
                    trump_chooser=trump_chooser,
                    players=self.__players_order_from(player),
                    trick_cards=trick.played_cards,
                    round_tricks=[trick.played_cards for trick in prev_tricks],
                )
            self.__log(f'{player} played {card_played}')
            trick.add_card(card_played, player)

        ####################
        # DETERMINE WINNER #
        ####################

        winner = trick.winner
        points = trick.points
        if is_last_trick:
            points += 5
            if all([self.__team_of(t.winner) == self.__team_of(winner) for t in prev_tricks]):
                points += 100
                self.__log(f'Match!')

        self.__log(f'{winner} wins the trick ({points} points)')

        return trick, points

    def __has_won(self, team: Team) -> bool:
        return team.score >= self.__goal

    def __players_order_from(self, player: Player) -> List[Player]:
        player_idx = self.__players.index(player)
        return self.__players[player_idx:] + self.__players[:player_idx]

    def __next_player(self, player) -> Player:
        return self.__players_order_from(player)[1]

    def __partner_of(self, player: Player) -> Player:
        return self.__players_order_from(player)[2]

    def __team_of(self, player: Player) -> Team:
        return [t for t in self.teams if player in t][0]

    def __log(self, s: Any) -> None:
        if self.__log_fn is not None:
            self.__log_fn(s)

    def __log_score(self):
        for team in self.__teams:
            self.__log(f'{team.player1}-{team.player2} team score: {team.score}')


import sys, os, json
from subprocess import Popen, PIPE

api_url = 'https://api.github.com/repos/tikzit/tikzit'

tok = os.getenv('GITHUB_TOKEN', '')

if tok == '':
	print("Must set GITHUB_TOKEN environment variable.")
	sys.exit(1)

# pretty-print JSON responses
def pr(j): print(json.dumps(j, indent=2))

# call GitHub API with curl
def gh(s, args=[], quiet=True, parse=True, auth=True):
    cmd = (["curl"] +
           (["-s"] if quiet else []) +
           args +
           (["-H", "Authorization: token " + tok] if auth else []) +
           [s if 'https://' in s else api_url + '/' + s])
    # ONLY UN-COMMENT FOR TESTING:
    # print(' '.join(cmd))
    p = Popen(cmd, stdout=PIPE)
    resp = p.stdout.read()
    if parse: return json.loads(resp if resp else '{}')
    else: return resp

def get_release(n):
  rs = [r for r in gh('releases') if r['name'] == n]
  if len(rs) > 0: return rs[0]
  else: return None


import torch

from modules.bnn.modules.linear import BayesLinear
from modules.bnn.modules.emp_linear import EmpBayesLinear
from modules.bnn.modules.ext_emp_linear import ExtEmpBayesLinear
from modules.bnn.modules.mlg_linear import MLGBayesLinear
from modules.bnn.modules.cm_linear import CMBayesLinear
from modules.bnn.modules.cmv_linear import CMVBayesLinear

def _gaussian_kl(mean_q, std_q, mean_p, std_p):
    """
    KL divergence between diagonal Gaussian distribtuions.
    (We can simply calculate the sum of the kl between independent single variate gaussians)
    """
    kl = (-0.5 + torch.log(std_p) - torch.log(std_q) +
          (torch.pow(std_q, 2) + torch.pow(mean_q-mean_p, 2)) /
          (2*torch.pow(std_p, 2)))
    return kl.sum()

def gaussian_kl_loss(model):
    """
    KL divergence between approximate posterior and prior, assuming both are diagonal Gaussian.
    This is the closed form complexity cost in Weight Uncertainty in Neural Networks.
    """
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    kl = torch.Tensor([0]).to(device)
    kl_sum = torch.Tensor([0]).to(device)
    for m in model.modules():
        if (isinstance(m, (BayesLinear))
                or isinstance(m, (EmpBayesLinear))
                or isinstance(m, (ExtEmpBayesLinear))
                or isinstance(m, (MLGBayesLinear))):
            kl = _gaussian_kl(m.weight_mean, m.weight_std, m.prior_weight_mean, m.prior_weight_std)
            kl_sum += kl
            if m.bias:
                kl = _gaussian_kl(m.bias_mean, m.bias_std, m.prior_bias_mean, m.prior_bias_std)
                kl_sum += kl
    return kl_sum

def nelbo(model, loss_args, minibatch_ratio, nll_loss, kl_loss):
    """
    kl divided by number of minibatches
    """
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    nelbo = torch.Tensor([0]).to(device)
    nll = nll_loss(*loss_args)
    kl = kl_loss(model) * minibatch_ratio
    nelbo = nll + kl

    return nelbo, nll, kl

def _cml(post_mean, post_std, alpha, prior_std):
    gamma = prior_std**2
    alpha_reg = gamma / (gamma + alpha)
    cml = ((post_std**2 + alpha_reg*post_mean**2) / gamma + torch.log(gamma)
           - 2*torch.log(post_std) - torch.log(alpha_reg) - 1)
    return cml.sum()/2

def cm_loss(model):
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    cml = torch.Tensor([0]).to(device)
    cml_sum = torch.Tensor([0]).to(device)
    for m in model.modules():
        if (isinstance(m, (CMBayesLinear))):
            cml = _cml(m.weight_mean, m.weight_std, m.prior_mean_hyperstd, m.prior_weight_std)
            cml_sum += cml
            if m.bias:
                cml = _cml(m.bias_mean, m.bias_std, m.prior_mean_hyperstd, m.prior_bias_std)
                cml_sum += cml
    return cml_sum

def _cmvl(post_mean, post_std, alpha, beta, delta):
    cmvl = ((alpha + 1/2)*torch.log(beta + delta*post_mean**2/2 + post_std**2/2)
            - torch.log(post_std) - torch.lgamma(alpha + 1/2) + torch.lgamma(alpha)
            - alpha*torch.log(beta) - torch.log(delta))
    return cmvl.sum()

def cmv_loss(model):
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    cmvl = torch.Tensor([0]).to(device)
    cmvl_sum = torch.Tensor([0]).to(device)
    for m in model.modules():
        if (isinstance(m, (CMVBayesLinear))):
            cmvl = _cmvl(m.weight_mean, m.weight_std, m.hyperprior_alpha, m.hyperprior_beta, m.hyperprior_delta)
            cmvl_sum += cmvl
            if m.bias:
                cmvl = _cmvl(m.bias_mean, m.bias_std, m.hyperprior_alpha, m.hyperprior_beta, m.hyperprior_delta)
                cmvl_sum += cmvl
    return cmvl_sum

def prior_regularisation(model):
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    prior_dif = torch.Tensor([0]).to(device)
    prior_dif_sum = torch.Tensor([0]).to(device)
    for m in model.modules():
        if (isinstance(m, (BayesLinear))
                or isinstance(m, (EmpBayesLinear))
                or isinstance(m, (ExtEmpBayesLinear))
                or isinstance(m, (MLGBayesLinear))):
            prior_dif = _gaussian_kl(m.weight_mean, m.weight_std, m.prior_weight_mean, m.prior_weight_std)
            prior_dif_sum += kl
            if m.bias:
                kl = _gaussian_kl(m.bias_mean, m.bias_std, m.prior_bias_mean, m.prior_bias_std)
                kl_sum += kl
    return kl_sum

def maximum_a_posteriori(model, loss_args, minibatch_ratio, nll_loss):
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    map_loss = torch.Tensor([0]).to(device)
    nll = nll_loss(*loss_args)
    prior_loss = prior_regularisation(model)
    map_loss = nll + prior_loss

    return map_loss, nll, prior_loss

def MLG_gaussian_kl(model):
    """
    KL divergence is between the epsilon posterior and prior (standard normal)
    """
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    kl = torch.Tensor([0]).to(device)
    kl_sum = torch.Tensor([0]).to(device)
    for m in model.modules():
        if isinstance(m, (MLGBayesLinear)):
            kl = _gaussian_kl(m.weight_mean, m.weight_std, torch.tensor(0), torch.tensor(1))
            kl_sum += kl
            if m.bias:
                kl = _gaussian_kl(m.bias_mean, m.bias_std, torch.tensor(0), torch.tensor(1))
                kl_sum += kl
    return kl_sum

def MLG_approximate_scheme(model, loss_args, minibatch_ratio, nll_loss, kl_loss):
    device = torch.device("cuda" if next(model.parameters()).is_cuda else "cpu")
    nelbo = torch.Tensor([0]).to(device)
    nll = nll_loss(*loss_args)
    kl = kl_loss(model) * minibatch_ratio
    nelbo = nll + kl

    return nelbo, nll, kl


from sklearn import svm, metrics
import torch
import numpy as np
from exp_config import ONESHOT_CONFIG
import random

np.random.seed(35813)
torch.manual_seed(35813)

### Direct to working environment
MODEL_OUTPUT_PATH = "/home/jia/Desktop/MSc_Project/imagetemplate/FedLIT/output"
data_path = "/home/jia/Desktop/MSc_Project/imagetemplate/FedLIT/classifier_data"

def cast_train_data(train_data, sample_size, numbers):
    dataset = {}
    for number in numbers:
        data = []
        for x, y in train_data:
            if y == number:
                data.append(x)
        dataset[number] = data
    n_subjects = min([len(data) for _, data in dataset.items()])
    sampled_subjects_id = [random.randint(1, n_subjects) for _ in numbers]

    sampled_dataset = []
    for i in range(sample_size):
        new_dataset = []
        for number, data in dataset.items():
            new_dataset.append((data[sampled_subjects_id[number-1]], number))
        sampled_dataset.append(new_dataset)

    assert len(sampled_dataset) == sample_size

    return sampled_dataset

def linearize_image_data(dataset):
    new_dataset = []
    for image, label in dataset:
        linear_image = image.flatten()
        new_dataset.append((linear_image, label))
    return new_dataset

if __name__ == '__main__':

    for i in range(1,6):
        print('-----------')
        print(f'Client {i}')
        print('-----------')

        # ------------------------ train data ------------------------------
        train_data = np.load(data_path + '/' + f'client{i}' + '/train_data.npy', allow_pickle=True)
        train_data = linearize_image_data(train_data)
        test_data = np.load(data_path + '/' + f'client{i}' + '/mixed_test_data.npy', allow_pickle=True)
        test_data = linearize_image_data(test_data)
        x_test, y_test = zip(*test_data)

        sampled_oneshot_train_data = cast_train_data(train_data, ONESHOT_CONFIG['train_times'], ONESHOT_CONFIG['numbers'])

        one_shot_accs = []
        for one_shot_train_data in sampled_oneshot_train_data:

            x_train, y_train = zip(*one_shot_train_data)

            # instantiate a model
            svm_linear = svm.SVC(kernel='linear')
            # fit
            svm_linear.fit(x_train, y_train)
            # predict
            predictions = svm_linear.predict(x_test)

            acc = metrics.accuracy_score(y_true=y_test, y_pred=predictions)
            one_shot_accs.append(acc)

        avg_one_shot_acc = sum(one_shot_accs)/len(one_shot_accs)
        std_one_shot_acc = np.std(one_shot_accs)
        print(f'average one-shot accuarcy: {avg_one_shot_acc}, std: {std_one_shot_acc}' )
        # ------------------------ LIT ------------------------------
        LIT_set = []
        for number in ONESHOT_CONFIG['numbers']:
            LIT = np.load( MODEL_OUTPUT_PATH + '/' + f'number{number}' + '/' + 'ablated_fed/image_templates/' f'client{i}' + '_image_template.npy')
            LIT_set.append((LIT, number))
        LIT_set = linearize_image_data(LIT_set)
        x_LIT, y_LIT = zip(*LIT_set)
        # instantiate a model
        svm_linear = svm.SVC(kernel='linear')
        # fit
        svm_linear.fit(x_LIT, y_LIT)
        # predict
        predictions = svm_linear.predict(x_test)

        LIT_acc = metrics.accuracy_score(y_true=y_test, y_pred=predictions)

        print(f'LIT accuarcy: {LIT_acc}' )


import shutil
from pathlib import Path
from unittest import TestCase

import numpy as np
import pytest

from geojson_modelica_translator.modelica.modelica_runner import ModelicaRunner

class GMTTestCase(TestCase):
    def setUp(self):
        # extend as needed to run these methods for all inherited test cases
        pass

    def tearDown(self):
        # extend as needed to run these methods for all inherited test cases
        pass

class TestCaseBase(GMTTestCase):
    """Base Test Case Class to handle generic configurations"""

    SHARED_DATA_DIR = Path(__file__).parent / 'data_shared'

    def set_up(self, root_folder, project_name):
        """

        :param root_folder: Folder where the test is to run. This is also the path where the input data are located.
        :param project_name: Name of the project folder to create.
        :return:
        """
        data_dir = Path(root_folder) / 'data'
        output_dir = Path(root_folder) / 'output'

        project_dir = output_dir / project_name
        if project_dir.exists():
            shutil.rmtree(project_dir)

        return data_dir, output_dir

    def compile_and_assert_in_docker(self, file_to_run: str, project_path: Path, project_name: str):
        """Run the compilation test in docker

        :param file_to_run: Full path to the file to run. Typically this is the .mo file of interest (e.g., coupling.mo)
        :param project_path: Full path to the location of the project to run. This is typically the the full path to
        where the directory named with the `project_name` comes come from.
        :param project_name: The name of the project that is running. This is the directory where the root package.mo
        lives.
        :return: None
        """
        mr = ModelicaRunner()
        run_path = Path(project_path).parent.resolve()
        success = mr.run_in_docker('compile', file_to_run, save_path=run_path)
        # on the exit of the docker command it should return a zero exit code, otherwise there was an issue.
        # Look at the stdout.log if this is non-zero.
        self.assertTrue(success)

        # make sure that the results log exist
        self.assertTrue((Path(run_path) / 'stdout.log').exists())

    def run_and_assert_in_docker(self, model_name: str, file_to_load: str, run_path: Path, **kwargs):
        """Wrapper for running and asserting that the simulation completed successfully

        Args:
            model_name (str): Name of the model to run, this is the name in the Modelica file
            file_to_load (str): Name of the file to load, which may or may not contain the model_name
            run_path (Path): Path to the simulation directory where all the files will be copied
        """
        mr = ModelicaRunner()
        success, results_path = mr.run_in_docker(
            'compile_and_run', model_name, file_to_load=file_to_load, run_path=run_path, **kwargs
        )
        # on the exit of the docker command it should return a zero exit code, otherwise there was an issue.
        # Look at the stdout.log if this is non-zero.
        self.assertTrue(success)

        # make sure that the results log exist
        self.assertTrue((Path(results_path) / 'stdout.log').exists())

    @pytest.mark.dymola
    def run_and_assert_in_dymola(self, model_name: str, file_to_load: str, run_path: Path, **kwargs):
        """Wrapper for running and asserting that the simulation completed successfully in dymola

        Args:
            model_name (str): Name of the model to run, this is the name in the Modelica file
            file_to_load (str): Name of the file to load, which may or may not contain the model_name
            run_path (Path): Path to the simulation directory where all the files will be copied
        """
        mr = ModelicaRunner()
        success, results_path = mr.run_in_dymola(
            'simulate', model_name, file_to_load=file_to_load, run_path=run_path, **kwargs
        )
        # on the exit of the docker command it should return a zero exit code, otherwise there was an issue.
        # Look at the stdout.log if this is non-zero.
        self.assertTrue(success)

        # make sure that the results log exist
        self.assertTrue((Path(results_path) / 'stdout.log').exists())

    def cvrmsd(self, measured, simulated):
        """Return CVRMSD between arrays.
        Implementation of ASHRAE Guideline 14 (4-4)

        :param measured: numpy.array
        :param simulated: numpy.array
        :return: float
        """
        def rmsd(a, b):
            p = 1
            n_samples = len(a)
            return np.sqrt(
                np.sum(
                    np.square(
                        a - b
                    )
                ) / (n_samples - p)
            )

        normalization_factor = np.mean(measured)
        return rmsd(measured, simulated) / normalization_factor


import asyncio
import logging
import json

class UDPProtocol(asyncio.DatagramProtocol):
    def __init__(self, queue, request_handler_resolver, loop):
        self.queue = queue
        self.request_handler_resolver = request_handler_resolver
        self.loop = loop
        self.transport = None

    def __call__(self):
        return self

    async def start(self):
        while self.transport and not self.transport.is_closing():
            request = await self.queue.get()
            data = json.dumps(request['data'], ensure_ascii=False)
            # logging.debug('sending %s to %s', data, request['destination'])
            self.transport.sendto(data.encode('utf8'), request['destination'])

    def connection_made(self, transport):
        self.transport = transport
        asyncio.ensure_future(self.start(), loop=self.loop)

    def datagram_received(self, data, sender):
        # logging.debug('received %s from %s', data, sender)
        doc = json.loads(data)
        doc['sender'] = sender
        self.request_handler_resolver()(doc)