import asyncio
import random
import time
from math import floor
from typing import List
import argparse

import torch
from axon import client, config, discovery
from torchvision import transforms
from torchvision.datasets import MNIST

import numpy as np

import common
from common import TwoNN, get_accuracy, set_parameters
from data_assignment.assign_heuristic import assign_work_heuristic
from data_assignment.error import (
    AssignmentError,
    InfeasibleWorkerCapacityError,
    InsufficientCapacityError,
    InsufficientDataError,
    InsufficientWorkersError,
)
from data_assignment.model import Worker
from environment import (
    get_env_batch_size,
    get_env_beta,
    get_env_default_fee,
    get_env_device,
    get_env_fee_type,
    get_env_fees,
    get_env_max_time,
    get_env_num_benchmark,
    get_env_num_global_cycles,
    get_env_s_min,
    get_env_weight_type,
)
from log import dump_logs

nb_ip = None

device = get_env_device()

# importing data
test_transform = train_transform = transforms.Compose([transforms.ToTensor()])
train_set = MNIST("./data", train=True, download=True, transform=train_transform)
test_set = MNIST("./data", train=False, download=True, transform=test_transform)

x_train_raw, y_train_raw = map(list, zip(*train_set))
x_test_raw, y_test_raw = map(list, zip(*test_set))

# formatting data
x_train = torch.cat(x_train_raw).reshape([-1, 784])
x_test = torch.cat(x_test_raw).reshape([-1, 784])

y_train = torch.tensor(y_train_raw, dtype=torch.long)
y_test = torch.tensor(y_test_raw, dtype=torch.long)

# defines the central model, as well as the criterion
net = TwoNN().to(device)
criterion = torch.nn.CrossEntropyLoss()

# this function aggregates parameters from workers
def aggregate_parameters(param_list, weights):

    num_clients = len(param_list)
    avg_params = []

    for i, params in enumerate(param_list):

        if i == 0:
            for p in params:
                avg_params.append(p.clone() * weights[i])

        else:
            for j, p in enumerate(params):
                avg_params[j].data += p.data * weights[i]

    return avg_params

# gets the accuracy and loss of a neural net on testing data
def val_evaluation(net, x_test, y_test, params):
    BATCH_SIZE = params.get("BATCH_SIZE", get_env_batch_size())

    num_test_batches = x_test.shape[0] // BATCH_SIZE

    loss = 0
    acc = 0

    net = net.to(device)
    for batch_number in range(num_test_batches):
        x_batch = x_test[
            BATCH_SIZE * batch_number : BATCH_SIZE * (batch_number + 1)
        ].to(device)
        y_batch = y_test[
            BATCH_SIZE * batch_number : BATCH_SIZE * (batch_number + 1)
        ].to(device)
        y_hat = net.forward(x_batch)

        loss += criterion(y_hat, y_batch).item()
        acc += get_accuracy(y_hat, y_batch).item()

    # normalizing the loss and accuracy
    loss = loss / num_test_batches
    acc = acc / num_test_batches

    return loss, acc

def get_fees(n, params):
    FEE_TYPE = params.get("FEE_TYPE", get_env_fee_type())
    DEFAULT_FEE = params.get("DEFAULT_FEE", get_env_default_fee())

    print("Using {} fee type".format(FEE_TYPE))

    if FEE_TYPE == "random":
        return [random.randint(1, 20) for _ in range(n)]
    elif FEE_TYPE == "linear":
        return [i + 1 for i in range(n)]
    elif FEE_TYPE == "specific":
        return params.get("FEES", get_env_fees(n))
    else:
        # default to constant
        return [DEFAULT_FEE] * n

def get_weight_type(params):
    WEIGHT_TYPE = params.get("WEIGHT_TYPE", get_env_weight_type())

    print("Using {} weight type".format(WEIGHT_TYPE))

    if WEIGHT_TYPE == "xavier":
        return common.init_weights_xavier
    elif WEIGHT_TYPE == "kaiming":
        return common.init_weights_kaiming
    else:
        # default to orthogonal
        return common.init_weights_orthogonal

async def main(arg_nb_ip=None, params=None):
    global nb_ip

    if params is None:
        params = {}

    # Set nb_ip from args (if provided) or broadcast IP otherwise
    if arg_nb_ip:
        nb_ip = arg_nb_ip
    else:
        # grabs notice board ip for discovery use
        axon_local_ips = await discovery.broadcast_discovery(
            num_hosts=1, port=config.comms_config.notice_board_port
        )

        nb_ip = axon_local_ips.pop()

    log_dict = {}

    # ML-related params
    BATCH_SIZE = params.get("BATCH_SIZE", get_env_batch_size())
    NUM_GLOBAL_CYCLES = params.get("NUM_GLOBAL_CYCLES", get_env_num_global_cycles())
    NUM_BENCHMARK = params.get("NUM_BENCHMARK", get_env_num_benchmark())
    # Data-assignment-related params
    BETA = params.get("BETA", get_env_beta())
    S_MIN = params.get("S_MIN", get_env_s_min())
    MAX_TIME = params.get("MAX_TIME", get_env_max_time())
    max_time_per_cycle = MAX_TIME / NUM_GLOBAL_CYCLES
    # Fees
    FEE_TYPE = params.get("FEE_TYPE", get_env_fee_type())
    WEIGHT_TYPE = params.get("WEIGHT_TYPE", get_env_weight_type())

    print("*** System Parameters ***")
    print(
        "BATCH_SIZE={} NUM_GLOBAL_CYCLES={} NUM_BENCHMARK={}".format(
            BATCH_SIZE, NUM_GLOBAL_CYCLES, NUM_BENCHMARK
        )
    )
    print(
        "BETA={} S_MIN={} MAX_TIME={} FEE_TYPE={}".format(
            BETA, S_MIN, MAX_TIME, FEE_TYPE
        )
    )

    log_dict["BATCH_SIZE"] = BATCH_SIZE
    log_dict["NUM_GLOBAL_CYCLES"] = NUM_GLOBAL_CYCLES
    log_dict["NUM_BENCHMARK"] = NUM_BENCHMARK
    log_dict["BETA"] = BETA
    log_dict["S_MIN"] = S_MIN
    log_dict["MAX_TIME"] = MAX_TIME
    log_dict["max_time_per_cycle"] = max_time_per_cycle
    log_dict["FEE_TYPE"] = FEE_TYPE
    log_dict["WEIGHT_TYPE"] = WEIGHT_TYPE

    print("\n*** Reinitialize net ***")
    reinit_weights_fcn = get_weight_type(params)
    net.apply(reinit_weights_fcn)

    # find and connect to workers
    worker_ips = discovery.get_ips(ip=nb_ip)

    # instantiates remote worker objects, with which we can call rpcs on each worker
    axon_workers = [client.RemoteWorker(ip) for ip in worker_ips]

    print("\n*** Benchmarking Workers ***")
    # start benchmarks in each worker
    benchmark_coros = []
    for w in axon_workers:
        benchmark_coros.append(w.rpcs.benchmark(NUM_BENCHMARK))

    # wait for each worker to finish their benchmark
    benchmark_scores = await asyncio.gather(*benchmark_coros)
    log_dict["benchmark_scores"] = {
        x[0]: x[1] for x in zip(worker_ips, benchmark_scores)
    }
    # calculates the number of batches each worker should be assigned
    s_max_batches = [floor(max_time_per_cycle * b) for b in benchmark_scores]

    # calc total number of batches
    total_batches = x_train.shape[0] // BATCH_SIZE
    log_dict["total_batches"] = total_batches

    fees = get_fees(len(axon_workers), params)

    workers: List[Worker] = []
    for i, w in enumerate(axon_workers):
        ip = worker_ips[i]
        s_max = s_max_batches[i]
        wage = fees[i]
        new_worker = Worker(s_max, wage, ip, w)
        workers.append(new_worker)

    log_dict["workers"] = workers

    print("\n*** Setting Worker Fees ***")

    # set wages in each worker
    minwage_coros = []
    for w in workers:
        print("Worker {} fee: {}".format(w.id, w.c))
        minwage_coros.append(w.axon_worker_ref.rpcs.set_minimum_wage(w.c))

    await asyncio.gather(*minwage_coros)

    print("\n*** Sending Data to Workers ***")
    send_data_start = time.time()

    # The Worker model assumes we partition the set of batches
    dataset = [x for x in range(total_batches)]
    allocations_pending = []
    try:
        [employed_workers, assignment_timing_stats] = assign_work_heuristic(
            workers, dataset, BETA, S_MIN
        )
        print(
            "Assigning data to {} / {} workers".format(
                len(employed_workers), len(workers)
            )
        )
        for w in workers:
            if w.id in employed_workers:
                # Extract the dataset here
                # idxs = torch.randperm(x_train.shape[0])[0 : BATCH_SIZE * w.num_assigned]
                # w.assigned_work will be a List of indexes of batches, samples_indices is a 2D list
                batch_samples = list(
                    map(
                        lambda batch_idx: list(
                            range(batch_idx * BATCH_SIZE, (batch_idx + 1) * BATCH_SIZE)
                        ),
                        w.assigned_work,
                    )
                )
                sample_indices = np.array(batch_samples).flatten()
                num_samples = sample_indices.shape[0]
                x_data = x_train[sample_indices]
                y_data = y_train[sample_indices]

                print(
                    "Assigning worker {} {} batches ({} samples)".format(
                        w.id, num_samples // BATCH_SIZE, num_samples
                    )
                )

                allocations_pending.append(
                    w.axon_worker_ref.rpcs.set_training_data(x_data, y_data)
                )
    except (
        InsufficientWorkersError,
        InsufficientCapacityError,
        InsufficientDataError,
        InfeasibleWorkerCapacityError,
        AssignmentError,
        ValueError,
    ) as e:
        print("Infeasible")
        raise (e)

    await asyncio.gather(*allocations_pending)

    send_data_duration = time.time() - send_data_start
    log_dict["send_data_duration"] = send_data_duration

    # Calculate how many batches were actually assigned
    total_batches_assigned = sum(map(lambda w: w.num_assigned, workers))
    log_dict["total_batches_assigned"] = total_batches_assigned
    # determine which workers were actually assigned data
    assigned_workers = list(filter(lambda w: w.num_assigned > 0, workers))

    print("\n*** Training ***")

    model_stats = {}
    log_dict["model_stats"] = model_stats
    # evaluate parameters
    loss, acc = val_evaluation(net, x_test, y_test, params)
    print("Network loss, accuracy prior to training: {}, {}".format(loss, acc))
    model_stats["0"] = {"loss": loss, "acc": acc}
    log_dict["model_pre_train_loss"] = loss
    log_dict["model_pre_train_acc"] = acc

    training_start = time.time()

    for i in range(NUM_GLOBAL_CYCLES):
        # some workers don't have a GPU and the device that a tensor is on will be serialized, so we've gotta move the network to CPU before transmitting parameters to worker
        net.to("cpu")

        # local updates
        local_update_coros = []
        for w in assigned_workers:
            local_update_coros.append(
                w.axon_worker_ref.rpcs.local_update(list(net.parameters()))
            )

        # waits for local updates to complete
        worker_params = await asyncio.gather(*local_update_coros)

        net.to(device)

        # aggregates parameters
        weights = [w.num_assigned / total_batches_assigned for w in workers]
        new_params = aggregate_parameters(worker_params, weights)

        # sets the central model to the new parameters
        set_parameters(net, new_params)

        # evaluate new parameters
        loss, acc = val_evaluation(net, x_test, y_test, params)
        print(
            "({}/{}) Network loss, accuracy: {}, {}".format(
                i + 1, NUM_GLOBAL_CYCLES, loss, acc
            )
        )
        model_stats[str(i + 1)] = {"loss": loss, "acc": acc}

    log_dict["model_post_train_loss"] = loss
    log_dict["model_post_train_acc"] = acc

    training_duration = time.time() - training_start
    log_dict["training_duration"] = training_duration

    timing_logs_coros = []
    for w in assigned_workers:
        timing_logs_coros.append(w.axon_worker_ref.rpcs.return_and_clear_timing_logs())

    # wait for timing logs to be returned from each worker
    timing_logs = await asyncio.gather(*timing_logs_coros)
    timing_logs = {x[0].id: x[1] for x in zip(assigned_workers, timing_logs)}
    log_dict["timing_logs"] = timing_logs

    print("\n*** Results ***")

    # Worker model computes total cost as w.cost = ceil(w.num_assigned / w.batch_size) * w.c
    total_cost_per_cycle = sum(map(lambda w: w.cost, workers))
    log_dict["total_cost_per_cycle"] = total_cost_per_cycle
    total_cost = total_cost_per_cycle * NUM_GLOBAL_CYCLES
    log_dict["total_cost"] = total_cost

    for w in workers:
        template = "Worker {} assigned {} batches (= {} samples); fee per cycle: {}; total fee: {}"
        msg = template.format(
            w.id,
            w.num_assigned,
            w.num_assigned * BATCH_SIZE,
            w.cost,
            w.cost * NUM_GLOBAL_CYCLES,
        )
        print(msg)
    print("Total fee per cycle:", total_cost_per_cycle)
    print("Total fee ({} cycles): {}".format(NUM_GLOBAL_CYCLES, total_cost))
    print("Data assignment duration:", send_data_duration)
    print("Training duration:", training_duration)

    # Dump log_dict to CSVs
    print("\n*** Writing Logs ***")
    try:
        dump_logs(log_dict, params)
        print("Success!")
    except Exception as e:
        print("Failed!")
        print(e)

    return log_dict

# Instantiate the parser
parser = argparse.ArgumentParser(description="Optional app description")
parser.add_argument("--nb-ip", type=str, help="Notice board host IP")

if __name__ == "__main__":
    args = parser.parse_args()
    asyncio.run(main(arg_nb_ip=args.nb_ip))


"""Exercise 11.1. Write a function that reads the words in words.txt and stores them as keys in a
dictionary. It doesn’t matter what the values are. Then you can use the in operator as a fast way to
check whether a string is in the dictionary."""

def make_word_list() :
    file_object = open('words.txt')
    word_list = []
    for line in file_object :
        word = line.strip()
        word_list.append(word)
    return word_list

def make_dictionary (word_list) :
    the_dictionary = dict()
    for word in word_list :
        the_dictionary[word] = 'null'
    return the_dictionary

thelist = make_word_list()
result = make_dictionary(thelist)
if 'aaa' in result :
    print('True')
else :
    print('False')


def nan_dropper(data, treshold=.9):

    '''
    Drops nans in a specific column or a range of
    columns, using np.isnull() through pandas.

    The treshold sets the % at which the whole column
    is droped (nan % of all values in the column).

    '''

    import wrangle as wr

    temp = wr.df_find_nan(data)
    temp = temp.transpose()

    for col in temp:
        if temp[col][1] < treshold:
            data = data.drop(col, axis=1)
            nan_rate = ((1 - temp[col][1]) * 100)
            print("DROPPED (%.2f%% nans): %s" % (nan_rate, col))

    data.dropna(inplace=True)

    return data


import os
import cv2
import matplotlib.pyplot as plt
import numpy as np
from calc.SinglePiece import SinglePiece
from calc.PieceCompare import box_compare, type_compare, icp_compare
# from scalene import scalene_profiler
from plot_helper.plot_helper import PlotPieces
from calibration.calibration import calibrate, calibrateImages, croppImages
from data_management.DataManager import DataManager
from data_management.ClusterManager import ClusterManager
from calc.ErrorCalculator import calc_error_and_rot_mat
import pickle

# def calibrate(path):
#     chessboardSize = (19,19)
#     frameSize = (2332,2403)

#     # termination criteria
#     criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

#     # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
#     objp = np.zeros((chessboardSize[0] * chessboardSize[1], 3), np.float32)
#     objp[:,:2] = np.mgrid[0:chessboardSize[0],0:chessboardSize[1]].T.reshape(-1,2)

#     size_of_chessboard_squares_mm = 6
#     objp = objp * size_of_chessboard_squares_mm

#     # Arrays to store object points and image points from all the images.
#     objpoints = [] # 3d point in real world space
#     imgpoints = [] # 2d points in image plane.

#     img = cv2.imread(path)
#     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#     # Find the chess board corners
#     ret, corners = cv2.findChessboardCorners(gray, chessboardSize, None)

#     # If found, add object points, image points (after refining them)
#     if ret == True:
#         objpoints.append(objp)
#         corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
#         imgpoints.append(corners)

#         ret, cameraMatrix, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, frameSize, None, None)
#         newCameraMatrix, roi = cv2.getOptimalNewCameraMatrix(cameraMatrix, dist, frameSize, 1, frameSize)
#         return cameraMatrix, dist, newCameraMatrix, roi
def main():
    path = os.path.join("..","..","puzzle_bilder","With Calibration Pattern","pieces_cut.jpg")
    calibPath = os.path.join("..","..","puzzle_bilder","With Calibration Pattern","chessboard_cut.jpg")

    cameraMatrix, dist, newCameraMatrix, roi = calibrate(calibPath)

    minArea = 50000
    maxArea = 250000
    im = cv2.imread(path)
    # Undistort
    dst = cv2.undistort(im, cameraMatrix, dist, None, newCameraMatrix)

    # crop the image
    x, y, w, h = roi
    im = dst[y:y+h, x:x+w]

    np.set_printoptions(linewidth=300,precision=0)

    gray = cv2.cvtColor(cv2.cvtColor(im, cv2.COLOR_BGR2RGB), cv2.COLOR_RGB2GRAY)
    _,binary = cv2.threshold(cv2.GaussianBlur(gray,(15,15),0),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    contours, _ = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    pieces = []
    for c in contours:
        pieces.append(SinglePiece(c,minArea=minArea,maxArea=maxArea))

    pieces = [p for p in pieces if p.valid]
    area = np.array([p.area for p in pieces])

    # idx = area.argsort()[::-1]
    # pieces = [pieces[i] for i in idx]

    error = np.zeros((len(pieces)*4,len(pieces)*4))
    error[:] = np.inf
    rotMat = np.zeros((len(pieces)*4,len(pieces)*4,3,3))
    for i in range(len(pieces)):
        for j in range(i+1,len(pieces)):
            error[4*i:4*i+4,4*j:4*j+4] = 0
            error[4*i:4*i+4,4*j:4*j+4] = type_compare(pieces[i],pieces[j])
            error[4*i:4*i+4,4*j:4*j+4] = box_compare(pieces[i],pieces[j],maxPixelDelta=18*2,matrix=error[4*i:4*i+4,4*j:4*j+4])#18 pixel is about 1mm
            error[4*i:4*i+4,4*j:4*j+4],rotMat[4*i:4*i+4,4*j:4*j+4,:,:] = icp_compare(pieces[i],pieces[j], maxError = 20,matrix=error[4*i:4*i+4,4*j:4*j+4])#18 pixel is about 1mm

    i_lower = np.tril_indices(error.shape[0], -1)
    error[i_lower] = error.T[i_lower]
    tmp = np.transpose(rotMat,(1,0,2,3))
    for i1,i2 in zip(i_lower[0],i_lower[1]):
        if tmp[i1,i2,2,2] == 1:
            rotMat[i1,i2,:,:] = np.linalg.inv(tmp[i1,i2,:,:])
            rotMat[i1,i2,2,:] = np.array([0,0,1])

    # plot some pieces
    e_ = error
    rotHist = []
    plotter = PlotPieces()
    tmp = np.unravel_index(np.argmin(e_, axis=None), e_.shape)
    idx = np.floor(np.array(tmp)/4).astype(int)
    # clear these two peaces
    e_[4*idx[0]:4*idx[0]+4,4*idx[1]:4*idx[1]+4] = np.inf
    e_[4*idx[1]:4*idx[1]+4,4*idx[0]:4*idx[0]+4] = np.inf

    rotHist.append(tmp)
    plt.figure()
    plotter.plot_piece(pieces[idx[0]],idx[0])
    plotter.rotate_and_plot(rotMat,rotHist,pieces[idx[1]],idx[1])
    print(f"Match {idx[0]} with {idx[1]}")

    for ii in range(3):
        tmp = np.unravel_index(np.argmin(e_[4*idx[1]:4*idx[1]+4,:], axis=None)+4*idx[1]*e_.shape[1], e_.shape)
        rotHist.append(tmp)
        idx = np.floor(np.array(tmp)/4).astype(int)
        # clear these two peaces
        e_[4*idx[0]:4*idx[0]+4,4*idx[1]:4*idx[1]+4] = np.inf
        e_[4*idx[1]:4*idx[1]+4,4*idx[0]:4*idx[0]+4] = np.inf

        print(f"Match {idx[0]} with {idx[1]}")
        plotter.rotate_and_plot(rotMat,rotHist,pieces[idx[1]], idx[1])

    plt.figure()
    plt.subplot(121)
    plt.imshow(im)
    axs=plt.subplot(122)
    axs.set_aspect('equal', 'box')
    colors = ["r","b"]
    for p,i in zip(pieces,range(len(pieces))):
        for t,s in zip(p.edgeType,p.sides):
            plt.plot(s[:,0,0],s[:,0,1],colors[int((t+1)/2)])
        for e in p.edgeIdx:
            plt.plot(p.points[e,0,0],p.points[e,0,1],'rx', markersize=12)

        plt.text(np.mean(p.points[:,0,0]),np.mean(p.points[:,0,1]),f'{i}, A= {area[i]}')
    # plt.gca().invert_yaxis()
    plt.show()
    pass

def main2():
    path = os.path.join("..","..","puzzle_bilder","Run_1")

    cameraMatrix, dist, newCameraMatrix, roi = calibrate(path)
    calibrateImages(path,cameraMatrix, dist, newCameraMatrix, roi)

def main3():
    path = os.path.join("..","..","puzzle_bilder","Run_1")
    croppImages(path,600,300,3400,2700)

def main4():
    path = os.path.join("..","..","puzzle_bilder","Run_1","CalibratedPictures")
    piecesListPath = os.path.join(path,"pieces.pickle")
    errorDictPath = os.path.join(path,"error_dict.pickle")
    m = DataManager()
    plotter = PlotPieces()
    if os.path.exists(piecesListPath):
        pieces = m.loadPieces(piecesListPath)
    else:
        pieces = m.generatePieces(path)
        m.storePieces(piecesListPath, pieces)
    plotter.plot_all(pieces)
    # plt.show()

    if os.path.exists(errorDictPath):
        with open(errorDictPath,"rb") as f:
            obj = pickle.load(f)
        error = obj["error"]
        transformMat = obj["transformMat"]
    else:
        error,transformMat = calc_error_and_rot_mat(pieces)
        obj = {"error":error,"transformMat":transformMat}
        with open(errorDictPath,"wb") as f:
            pickle.dump(obj,f)

    solvePuzzle(pieces,error,transformMat)

    # clusterList = []
    # clusterMatrix = []

    # e_ = error
    # rotHist = []
    # plotter = PlotPieces()

    # tmp = np.unravel_index(np.argmin(e_, axis=None), e_.shape)
    # idx = np.floor(np.array(tmp)/4).astype(int)

    # # get clusters
    # cluster = [None,None]
    # for c in clusterList:
    #     for i in range(2):
    #         if cluster[i] == None:
    #             if idx[i] in c:
    #                 cluster[i] = c

    # # check all cases
    # if cluster == [None,None]:
    #     # no cluster exists, create new
    #     clusterList.append(idx)

    # # remove these two side, since they are used now
    # e_[tmp[0],:]= np.inf
    # e_[:,tmp[1]]= np.inf
    # # clear these two peaces
    # e_[4*idx[0]:4*idx[0]+4,4*idx[1]:4*idx[1]+4] = np.inf
    # e_[4*idx[1]:4*idx[1]+4,4*idx[0]:4*idx[0]+4] = np.inf

    # rotHist.append(tmp)
    # plt.figure()
    # plotter.plot_piece(pieces[idx[0]])
    # plotter.rotate_and_plot(transformMat,rotHist,pieces[idx[1]])
    # print(f"Match {idx[0]} with {idx[1]}")

    # for ii in range(1):
    #     tmp = np.unravel_index(np.argmin(e_[4*idx[1]:4*idx[1]+4,:], axis=None)+4*idx[1]*e_.shape[1], e_.shape)
    #     rotHist.append(tmp)
    #     idx = np.floor(np.array(tmp)/4).astype(int)

    #     # remove these two side, since they are used now
    #     e_[tmp[0],:]= np.inf
    #     e_[:,tmp[1]]= np.inf
    #     # clear these two peaces
    #     e_[4*idx[0]:4*idx[0]+4,4*idx[1]:4*idx[1]+4] = np.inf
    #     e_[4*idx[1]:4*idx[1]+4,4*idx[0]:4*idx[0]+4] = np.inf

    #     print(f"Match {idx[0]} with {idx[1]}")
    #     plotter.rotate_and_plot(transformMat,rotHist,pieces[idx[1]])
    # plt.axis('equal')
    # plt.show()
    pass

def solvePuzzle(pieces,error,transformMat,treshold=3):
    np.set_printoptions(linewidth=300,precision=0)

    # init stuff
    clusterList:list[ClusterManager] = []
    e_ = error

    e_values = e_[np.invert(np.isinf(e_))]
    # counts, bins = np.histogram(e_values,100)
    # plt.stairs(counts, bins)
    # idx
    tmp = np.unravel_index(np.argmin(e_, axis=None), e_.shape)
    v = e_[tmp]

    if v > treshold:
        print(f"Error {v} bigger than treshold {treshold}, exit before start solving")
        return
    idx = np.floor(np.array(tmp)/4).astype(int)
    side_idx = np.remainder(tmp,4)

    # remove these two side, since they are used now
    e_[tmp[0],:]= np.inf
    e_[tmp[1],:]= np.inf
    e_[:,tmp[0]]= np.inf
    e_[:,tmp[1]]= np.inf
    # clear these two peaces, these are already togheter
    e_[4*idx[0]:4*idx[0]+4,4*idx[1]:4*idx[1]+4] = np.inf
    e_[4*idx[1]:4*idx[1]+4,4*idx[0]:4*idx[0]+4] = np.inf

    clusterList.append(ClusterManager(idx[0]))
    clusterList[-1].addPiece(dst_piece_idx=idx[0],dst_side_idx=side_idx[0],src_piece_idx=idx[1],src_side_idx=side_idx[1])

    # repeat
    while True:
        tmp = np.unravel_index(np.argmin(e_, axis=None), e_.shape)
        v = e_[tmp]
        if v > treshold:
            break

        idx = np.floor(np.array(tmp)/4).astype(int)
        side_idx = np.remainder(tmp,4)

        # remove these two side, since they are used now
        e_[tmp[0],:]= np.inf
        e_[tmp[1],:]= np.inf
        e_[:,tmp[0]]= np.inf
        e_[:,tmp[1]]= np.inf
        # clear these two peaces, these are already togheter
        e_[4*idx[0]:4*idx[0]+4,4*idx[1]:4*idx[1]+4] = np.inf
        e_[4*idx[1]:4*idx[1]+4,4*idx[0]:4*idx[0]+4] = np.inf

        # check for existing clusters
        cluster = [None,None]
        for c in clusterList:
            for i in range(2):
                if cluster[i] == None:
                    exists,_=c.checkForPiece(idx[i])
                    if exists:
                        cluster[i] = c

        if all([c == None for c in cluster]):
            # no cluster exists, create new
            clusterList.append(ClusterManager(idx[0]))
            clusterList[-1].addPiece(dst_piece_idx=idx[0],dst_side_idx=side_idx[0],src_piece_idx=idx[1],src_side_idx=side_idx[1])
        elif any([c == None for c in cluster]):
            # only one is none
            for i in range(2):
                if not (cluster[i] == None):
                    cluster[i].addPiece(dst_piece_idx=idx[i],dst_side_idx=side_idx[i],src_piece_idx=idx[(i+1)%2],src_side_idx=side_idx[(i+1)%2])
        else:
            # all are not none
            if cluster[0] is cluster[1]:
                print("Error clusters are the same")
            # add cluster to cluster
            cluster[0].addCluster(cluster[1],dst_piece_idx=idx[0],dst_side_idx=side_idx[0],src_piece_idx=idx[1],src_side_idx=side_idx[1])
            # remove cluster 1, it is now in cluster 0
            clusterList.remove(cluster[1])

    # plot the stuff
    plotter = PlotPieces()
    for c in clusterList:
        plt.figure()
        transformInfo = c.generate_transformation_info(transformMat)
        for k,v in transformInfo.items():
            plotter.transform_and_plot(v,pieces[k])

    plt.axis('equal')
    plt.show()

    pass

if __name__ == "__main__":
    # scalene_profiler.start()
    # main()
    # main3()
    # main2()

    main4()
    # scalene_profiler.stop()


import json
from pathlib import Path
from enum import Enum

class Subject(Enum):
    Math = 0
    SocialScience = 1
    Science = 2
    English = 3

def InsertRecord():
    try:
        Record = json.load(open('C:/users/garry/Desktop/StudentRecord/stdRec.txt'))
    except:
        Record = {}
    Name = {}
    Marks = {}
    Percentage = {}
    M = []
    per = 0
    rno = input("\nEnter Student's Roll Number : ")
    Name['Name'] = input("\nEnter Student's Name : ")
    for i in range(4):
        M.append(int(input('\nEnter Marks in ' + str(Subject(i).name) + ' : ')))
    for m in M:
        per += m
    per /= 4
    Marks['Marks'] = M
    Percentage['Percentage'] = per
    Record[rno] = Name, Marks, Percentage
    json.dump(Record, open('C:/users/garry/Desktop/StudentRecord/stdRec.txt', 'w'))
    print('\nRecord Inserted')

def PrintToppersList():
    try:
        rec = json.load(open('C:/users/garry/Desktop/StudentRecord/stdRec.txt'))
        mathTopper = next(iter(rec))
        socialScienceTopper = next(iter(rec))
        scienceTopper = next(iter(rec))
        englishTopper = next(iter(rec))
        for i in rec:
            for j in range(4):
                if j == 0:
                    if rec[i][1]['Marks'][j] > rec[mathTopper][1]['Marks'][j]:
                        mathTopper = i
                elif j == 1:
                    if rec[i][1]['Marks'][j] > rec[socialScienceTopper][1]['Marks'][j]:
                        socialScienceTopper = i
                elif j == 2:
                    if rec[i][1]['Marks'][j] > rec[scienceTopper][1]['Marks'][j]:
                        scienceTopper = i
                elif j == 3:
                    if rec[i][1]['Marks'][j] > rec[englishTopper][1]['Marks'][j]:
                        englishTopper = i
        print('\nMath Topper : ' + rec[mathTopper][0]['Name'])
        print('\nSocial Science Topper : ' + rec[socialScienceTopper][0]['Name'])
        print('\nScience Topper : ' + rec[scienceTopper][0]['Name'])
        print('\nEnglish Topper : ' + rec[englishTopper][0]['Name'])
    except:
        print('\n\nEmpty File. Enter a record first\n\n')

def PrintStudentRecord():
    try:
        rec = json.load(open('C:/users/garry/Desktop/StudentRecord/stdRec.txt'))
        print('\nRollNo    Name        Math    SocialScience    Science    English    Percentage')
        for i in rec:
            r = i
            n = rec[i][0]['Name']
            m = rec[i][1]['Marks']
            p = rec[i][2]['Percentage']
            print(r, '       ', n, '    ', '            '.join([str(ls) for ls in m]), '    ', p)
        print()
    except:
        print('\n\nEmpty File. Enter a record first\n\n')

while True:
    f = Path('C:/users/garry/Desktop/StudentRecord/stdRec.txt')
    if f.is_file():
        uc = int(input('\nPress 1 to veiw existing Student Record\nPress 2 to Add a record\nPress 3 to get the list of Toppers in each Subject\nPress 4 to exit the Program\n\nEnter Your Choice : '))
        if uc == 1:
            PrintStudentRecord()
        elif uc == 2:
            InsertRecord()
        elif uc == 3:
            PrintToppersList()
        elif uc == 4:
            exit()
    else:
        temp = open('C:/users/garry/Desktop/StudentRecord/stdRec.txt', 'w')
        temp.close()


import clip
from datasets.text_label import obj_text_label
import torch

device='cuda'
clip_model = 'ViT-B/32'
clip_model, preprocess = clip.load(clip_model, device=device)
with torch.no_grad():
    obj_text_inputs = torch.cat([clip.tokenize(obj_text[1]) for obj_text in obj_text_label])
    obj_text_embedding = clip_model.encode_text(obj_text_inputs.to(device)).float()
    print('stop')


def get_dns_proxy(
    self,
    ne_id: str,
    cached: bool,
) -> dict:
    """Get DNS Proxy configurations from Edge Connect appliance

    .. list-table::
        :header-rows: 1

        * - Swagger Section
          - Method
          - Endpoint
        * - dnsProxy
          - GET
          - /dnsProxy/config/{neId}?cached={cached}

    :param ne_id: Appliance id in the format of integer.NE e.g. ``3.NE``
    :type ne_id: str
    :param cached: ``True`` retrieves last known value to Orchestrator,
        ``False`` retrieves values directly from Appliance
    :type cached: bool
    :return: Returns dictionary where each key is a segment id that
        contains its associated DNS proxy configuration (profiles,
        domain groups and maps).
    :rtype: dict
    """
    return self._get("/dnsProxy/config/{}?cached={}".format(ne_id, cached))


from django.shortcuts import render, redirect

from newExam.expense_app.forms import ExpenseForm, DeleteExpenseForm
from newExam.expense_app.models import Expense
from newExam.profile_app.models import Profile

def create_expense(request):
    if request.method == 'POST':
        form = ExpenseForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('home')
    else:
        form = ExpenseForm()
    context = {'form': form, 'profile': Profile.objects.first()}
    return render(request, 'expense-create.html', context)

def edit_expense(request, pk):
    expense = Expense.objects.get(pk=pk)
    if request.method == 'POST':
        form = ExpenseForm(request.POST, instance=expense)
        if form.is_valid():
            form.save()
            return redirect('home')
    else:
        form = ExpenseForm(instance=expense)
    context = {'form': form, 'profile': Profile.objects.first()}
    return render(request, 'expense-create.html', context)

def delete_expense(request, pk):
    expense = Expense.objects.get(pk=pk)
    if request.method == 'POST':
        expense.delete()
        return redirect('home')
    else:
        form = DeleteExpenseForm(instance=expense)
    context = {'form': form, 'profile': Profile.objects.first()}
    return render(request, 'expense-delete.html', context)


import numpy as np
from scipy import signal

class EncoderBase:

    def calculate_decoding_rmse(self, data, recon_data):
        data = np.array(data)
        recon_data = np.array(recon_data)
        absolute_error = data-recon_data
        rmse = np.sqrt(np.sum(absolute_error*absolute_error)/absolute_error.size)
        return rmse

class TC(EncoderBase):

    def __init__(self, factor):
        self.factor = factor

    def encode(self, temporal_data):
        temporal_data = np.array(temporal_data)
        num_features, num_time = temporal_data.shape
        spike_train = np.zeros(temporal_data.shape)

        changes = np.diff(temporal_data, n=1, axis=1)
        spike_threshold = np.mean(abs(changes), axis=1) + self.factor*np.std(abs(changes), axis=1)
        changes = np.concatenate((np.zeros((num_features, 1)), changes), axis=1)

        for i in range(0,num_features):
            for j in range(0,num_time):
                if changes[i, j] > spike_threshold[i]:
                    spike_train[i, j] = 1
                elif changes[i, j] < -spike_threshold[i]:
                    spike_train[i, j] = -1

        recon_data = self.decode(spike_train, spike_threshold)
        decoding_rmse = self.calculate_decoding_rmse(temporal_data, recon_data)
        return spike_train.tolist(), spike_threshold.tolist(), decoding_rmse

    def decode(self, spike_train, spike_threshold):
        spike_train = np.array(spike_train)
        num_features, num_time = spike_train.shape
        temporal_data = np.zeros(spike_train.shape)
        for i in range(0,num_features):
            for j in range(1,num_time):
                if spike_train[i, j] > 0:
                    temporal_data[i, j] = temporal_data[i, j-1]+spike_threshold[i]
                elif spike_train[i, j] < 0:
                    temporal_data[i, j] = temporal_data[i, j-1]-spike_threshold[i]
                else:
                    temporal_data[i, j] = temporal_data[i, j-1]

        return temporal_data.tolist()

class BSA(EncoderBase):
    def __init__(self, num_tap, cutoff, bsa_threshold):
        self.num_tap = num_tap
        self.cutoff = cutoff
        self.bsa_threshold = bsa_threshold
        self.filt = signal.firwin(num_tap, cutoff, window='hamming')  # differs from matlab implementation

    def encode(self, temporal_data):
        temporal_data = np.array(temporal_data)
        spike_train = np.zeros(temporal_data.shape)
        filt = np.array(self.filt)
        filt_length = filt.size
        num_features, num_time = temporal_data.shape

        for i in range(0, num_features):
            for j in range(0, (num_time-filt_length+1)):
                error1 = 0
                error2 = 0
                for k in range(0, filt_length):
                    error1 = error1 + np.abs(temporal_data[i, j+k] - filt[k])
                    error2 = error2 + np.abs(temporal_data[i, j+k])

                if error1 <= (error2-self.bsa_threshold):
                    spike_train[i, j] = 1
                    for k in range(0, filt_length):
                        temporal_data[i, j+k] = temporal_data[i, j+k]-filt[k]

        recon_data = self.decode(spike_train)
        decoding_rmse = self.calculate_decoding_rmse(temporal_data, recon_data)
        return spike_train.tolist(), decoding_rmse

    def decode(self, spike_train):
        spike_train = np.array(spike_train)
        temporal_data = np.zeros(spike_train.shape)
        filt = np.array(self.filt)
        filt_length = filt.size
        num_features, num_time = spike_train.shape
        for i in range(0, num_features):
            for j in range(0, num_time-filt_length+1):
                if spike_train[i, j] == 1:
                    for k in range(0, filt_length):
                        temporal_data[i, j+k] = temporal_data[i, j+k] + filt[k]
        return temporal_data.tolist()

my_data = [[1.43, 2.00, 0.53, 7.21], [5.34, 2.87, 1.11,3.21], [1.43, 2.00, 5.33, 2.21]]


import os
os.sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from passlib.hash import sha256_crypt
from flask_restful import reqparse
from functools import wraps
from flask import request, jsonify
from models import models
from flask_jwt_extended import (
    verify_jwt_in_request, get_jwt_claims,
    get_jwt_identity
)

def pw_encrypt(pw):
    return sha256_crypt.hash(pw)

def verify_pw(pw_str, pw_hash):
    return sha256_crypt.verify(pw_str, pw_hash)

def verify_signup_input(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument('name', type=str, required=True, help="Name cannot be blank!")
        parser.add_argument('email', type=str, required=True, help="Email cannot be blank!")
        parser.add_argument('password', type=str, required=True, help="Password cannot be blank!")
        parser.parse_args()

        return f(*args, **kwargs)
    return decorated

def get_role_id(role='regular'):
    role = models.Role.query.filter_by(name=role).first()
    return role.id

def get_request_type_id(type='pending'):
    request_type = models.Request_Type.query.filter_by(name=type).first()
    return request_type.id

def validate_request(*expected_args):
    def validate_input(f):
        @wraps(f)
        def decorated(*args, **kwargs):
            if not request.json:
                return {
                    'status': 'fail',
                    "data": {"message": "Request must be a valid JSON"}
                }, 400

            payload = request.get_json()
            if payload:
                for value in expected_args:
                    if value == 'status' and value not in payload: continue
                    if value not in payload or not payload[value]:
                        return {
                            "status": "fail",
                            "data": {"message": value + " is required"}
                        }, 400
                    if type(payload[value]) != str or not payload[value].strip(' '):
                        return {
                            "status": "fail",
                            "data": {"message": value + " must contain valid strings"}
                        }, 400
            return f(*args, **kwargs)
        return decorated
    return validate_input

# Here is a custom decorator that verifies the JWT is present in
# the request, as well as insuring that this user has a role of
# `admin` in the access token
def admin_required(fn):
    @wraps(fn)
    def authenticated(*args, **kwargs):
        verify_jwt_in_request()
        claims = get_jwt_claims()
        if claims['role'] != 'admin':
            return jsonify(dict(
                status="fail",
                messsage="Access Denied!"
            )), 401
        return fn(*args, **kwargs)
    return authenticated

def validate_user_update_request(fn):
    @wraps(fn)
    def decorated(*args, **kwargs):
        current_user = get_jwt_identity()
        request_id = request.url.rstrip('/').split('/')[-1]
        user_request = models.Request.query.get(request_id)

        if not user_request:
            return {
                "status": "fail",
                "message": "Request not found!"
            }, 404

        if current_user['id'] != str(user_request.owner_id):
            return {
                "status": "fail",
                "message": "Request denied!"
            }, 403

        if user_request.status in ['approved', 'disapproved', 'resolved']:
            return {
                "status": "fail",
                "message": "Request cannot be edited!"
            }, 403

        return fn(*args, **kwargs)
    return decorated


from collections import defaultdict

import torch
import torch.distributed as torch_dist
import torch.nn as nn
import torch.nn.functional as F
import torchvision.models as models
from hirl.utils import dist

class SwAV(nn.Module):
    """
    Re-implementation of Swapping Assignments between Views (SwAV)
    based on https://github.com/facebookresearch/swav.

    Args:
        base arch (str): the base architecture of encoder (default: "resnet50")
        dim (int): feature dimension (default: 128)
        batch_size (int): the number of samples on each GPU (default: 64)
        queue_length (int): size of the queue to supplement mini-batch samples (default: 0)
        T (float): temperature parameter for cluster assignment prediction (default: 0.1)
        epsilon (float): regularization parameter for Sinkhorn-Knopp algorithm (default: 0.05)
        mlp (bool): whether to use mlp projection (default: True)
        num_proto (int): number of prototypes (default: 3000)
        num_sinkhorn (int): number of iterations for Sinkhorn-Knopp algorithm (default: 3).
        multi_crop (bool): whether to use multi-crop augmentation (default: False)
        normalize (bool): whether to apply l2 normalization to output embedding (default: True)
    """
    def __init__(self, base_arch="resnet50", dim=128, batch_size=64, queue_length=0, T=0.1, epsilon=0.05, mlp=True,
                    hidden_mlp=2048, num_proto=3000, num_sinkhorn=3, multi_crop=False, normalize=True, **kwargs):
        super().__init__()

        self.world_size = dist.get_world_size()
        self.batch_size = batch_size
        self.queue_length = queue_length
        self.T = T
        self.epsilon = epsilon
        self.num_proto = num_proto
        self.num_sinkhorn = num_sinkhorn
        self.multi_crop = multi_crop
        self.normalize = normalize

        # create encoder and projection head
        self.encoder = models.__dict__[base_arch](num_classes=dim)
        self.backbone = self.encoder
        dim_mlp = self.encoder.fc.weight.shape[1]
        if mlp:
            ## with a batch norm
            self.encoder.fc = nn.Sequential(
                nn.Linear(dim_mlp, hidden_mlp),
                nn.BatchNorm1d(hidden_mlp),
                nn.ReLU(inplace=True),
                nn.Linear(hidden_mlp, dim)
            )

        # create prototypes and queue
        self.prototypes = nn.Linear(dim, num_proto, bias=False)
        self.queue_length -= self.queue_length % (self.world_size * self.batch_size)
        self.use_queue = self.queue_length >= self.world_size
        if self.use_queue:
            self.register_buffer("queue", torch.zeros(2, self.queue_length // self.world_size, dim))

        # initialize model weights
        self.apply(self._init_weights)

        # create hooks for the embeddings before and after projection
        self.entangled_dim = dim_mlp
        self.inst_dim = dim
        self._embeddings = {}
        def hook_function(module, input_emb, output_emb):
            if isinstance(input_emb, tuple) and len(input_emb) == 1:
                input_emb = input_emb[0]
            if isinstance(output_emb, tuple) and len(output_emb) == 1:
                output_emb = output_emb[0]
            self._embeddings["entangled_emb"] = input_emb
            self._embeddings["inst_emb"] = output_emb
        project_layer = dict([*self.encoder.named_modules()])["fc"]
        project_layer.register_forward_hook(hook_function)

    def _init_weights(self, m):
        if isinstance(m, nn.Conv2d):
            nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu")
        elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
            nn.init.constant_(m.weight, 1)
            nn.init.constant_(m.bias, 0)

    def extract_feat(self, images):
        # extract feature of global views
        im_q, im_k = images[0], images[1]
        q = self.encoder(im_q)
        embedding_dict = defaultdict(list)
        for k,v in self._embeddings.items():
            embedding_dict[k].append(v)

        k = self.encoder(im_k)
        if self.normalize:
            q = F.normalize(q, dim=1)
            k = F.normalize(k, dim=1)

        # extract features of local views
        if self.multi_crop:
            local_views = []
            for im_local in images[2:]:
                local_q = self.encoder(im_local)
                if self.normalize:
                    local_q = F.normalize(local_q, dim=1)
                local_views.append(local_q)
                for key, v in self._embeddings.items():
                    embedding_dict[key].append(v)
            return q, k, local_views, embedding_dict
        else:
            return q, k, None, embedding_dict

    @torch.no_grad()
    def distributed_sinkhorn(self, logit):
        """
        Clustering assignment by iterative Sinkhorn-Knopp algorithm (designed for distributed training).
        """
        Q = torch.exp(logit / self.epsilon).t() # [D, N]
        B = Q.shape[1] * self.world_size
        K = Q.shape[0]

        sum_Q = torch.sum(Q)
        torch_dist.all_reduce(sum_Q)
        Q /= sum_Q

        for it in range(self.num_sinkhorn):
            sum_row = torch.sum(Q, dim=1, keepdim=True)
            torch_dist.all_reduce(sum_row)
            Q /= sum_row
            Q /= K

            Q /= torch.sum(Q, dim=0, keepdim=True)
            Q /= B

        Q *= B
        return Q.t()

    def get_loss(self, q, k, logit_q, logit_k, logit_local):
        loss = torch.tensor(0, dtype=torch.float32, device=q.device)
        _tgt_logits = []
        _src_logits = []
        crops = [(q, logit_q), (k, logit_k)]

        for crop_id, (tgt_crop_id, src_crop_id) in enumerate([(0, 1), (1, 0)]):
            tgt_emb, tgt_logit = crops[tgt_crop_id]
            src_emb, src_logit = crops[src_crop_id]

            # get prediction target
            with torch.no_grad():
                tgt_emb = tgt_emb.detach()
                tgt_logit = tgt_logit.detach()
                if self.use_queue:
                    if not torch.all(self.queue[crop_id, -1, :] == 0):
                        tgt_logit = torch.cat([self.prototypes(self.queue[crop_id]), tgt_logit], dim=0)
                    self.queue[crop_id, self.batch_size:] = self.queue[crop_id, :-self.batch_size].clone()
                    self.queue[crop_id, :self.batch_size] = tgt_emb
                # Sinkhorn iteration
                tgt_assignment = self.distributed_sinkhorn(tgt_logit)[-self.batch_size:]

            # loss of clustering assignment prediction
            all_src_logit = torch.cat([src_logit] + logit_local, dim=0)  # ((N_local + 1) * B, K)
            all_src_logit /= self.T
            all_q = torch.cat([tgt_assignment] * (len(logit_local) + 1), dim=0)  # ((N_local + 1) * B, K)
            loss_ = -torch.mean(torch.sum(all_q * F.log_softmax(all_src_logit, dim=1), dim=1))
            loss += loss_
            _tgt_logits.append(all_q)
            _src_logits.append(all_src_logit)

        loss /= 2 ## average over crops for assignment
        _tgt_logit = torch.cat(_tgt_logits, dim=0)
        _src_logit = torch.cat(_src_logits, dim=0)
        return loss, _tgt_logit, _src_logit

    def forward_feature(self, images):
        return self.encoder(images)

    def forward(self, images, return_hooks=False):
        """
        Given a list of images, compute cross-view cluster assignment prediction loss with sinkhorn
        assignment algorithm.

        Args:
            images (list of torch.Tensor [N,C,H,W]): image tensors. The first two
                elements are global views.
            return_hooks (bool): whether return the hidden output by hook function. (default: False)

        Returns:
            output_dict: dict with the following fields:
                ``loss`` (torch.Tensor [1,]): loss for backward.
                ``target_logits`` (list of torch.Tensor [N,C]) cluster assignment logits for
                    target views.
                ``source_logits`` (list of torch.Tensor [N,C]) cluster assignment logits for
                    source views.
                ``embeddings``: dict used for further loss computation in hirl.
        """
        # normalize prototypes
        if self.normalize:
            with torch.no_grad():
                weight = self.prototypes.weight.data.clone()
                weight = F.normalize(weight, dim=1, p=2)
                self.prototypes.weight.copy_(weight)

        # feature extraction
        q, k, local_views, embedding_dict = self.extract_feat(images)
        image_emb = [q, k] + local_views if self.multi_crop else [q, k]
        logit_q = self.prototypes(q)
        logit_k = self.prototypes(k)
        logit_local = [self.prototypes(local_view) for local_view in local_views] if self.multi_crop else []

        loss, tgt_logit, src_logit = self.get_loss(q, k, logit_q, logit_k, logit_local)

        output_dict = dict(loss=loss,
                           target_logits=tgt_logit,
                           source_logits=src_logit)

        if return_hooks:
            output_dict["embeddings"] = embedding_dict

        return output_dict

def swav_resnet50_single_crop(batch_size=64, queue_length=0, **kwargs):
    model = SwAV(base_arch="resnet50", batch_size=batch_size, queue_length=queue_length,
                    multi_crop=False, **kwargs)
    return model

def swav_resnet50_multi_crop(batch_size=64, queue_length=0, **kwargs):
    model = SwAV(base_arch="resnet50", batch_size=batch_size, queue_length=queue_length,
                    multi_crop=True, **kwargs)
    return model

# set recommended models
swav_single = swav_resnet50_single_crop
swav_multi = swav_resnet50_multi_crop


import tensorflow as tf
import numpy as np

sess = tf.Session()

def t1():
    dataset = tf.data.Dataset.range(100)
    iterator = dataset.make_one_shot_iterator()
    next_element = iterator.get_next()

    with tf.Session() as sess:
        for i in range(10):
            value = sess.run(next_element)
            print(value)

def t2():
    max_value = tf.placeholder(tf.int64, shape=[])
    dataset = tf.data.Dataset.range(max_value)
    iterator = dataset.make_initializable_iterator()
    next_element = iterator.get_next()

    # Initialize an iterator over a dataset with 10 elements.
    sess.run(iterator.initializer, feed_dict={max_value: 10})
    for i in range(10):
        value = sess.run(next_element)
        # print(value)
        # assert i == value

    # Initialize the same iterator over a dataset with 100 elements.
    MAX = 100000
    sess.run(iterator.initializer, feed_dict={max_value: MAX})
    import time
    start = time.time()
    for i in range(MAX):
        value = sess.run(next_element)
        # print(value)
    end = time.time()
    print("speed:", (MAX + 0.0) / (end - start))

def t3():
    # Define training and validation datasets with the same structure.
    training_dataset = tf.data.Dataset.range(100).map(
        lambda x: x + tf.random_uniform([], -10, 10, tf.int64))
    validation_dataset = tf.data.Dataset.range(50)

    # A reinitializable iterator is defined by its structure. We could use the
    # `output_types` and `output_shapes` properties of either `training_dataset`
    # or `validation_dataset` here, because they are compatible.
    iterator = tf.data.Iterator.from_structure(training_dataset.output_types,
                                               training_dataset.output_shapes)
    next_element = iterator.get_next()

    training_init_op = iterator.make_initializer(training_dataset)
    validation_init_op = iterator.make_initializer(validation_dataset)

    # Run 20 epochs in which the training dataset is traversed, followed by the
    # validation dataset.
    for _ in range(20):
        # Initialize an iterator over the training dataset.
        sess.run(training_init_op)
        for _ in range(10):
            print(sess.run(next_element))

        # Initialize an iterator over the validation dataset.
        sess.run(validation_init_op)
        for _ in range(50):
            print(sess.run(next_element))

def t4():
    # Define training and validation datasets with the same structure.
    training_dataset = tf.data.Dataset.range(100).map(
        lambda x: x + tf.random_uniform([], -10, 10, tf.int64)).repeat()
    validation_dataset = tf.data.Dataset.range(50)

    # A feedable iterator is defined by a handle placeholder and its structure. We
    # could use the `output_types` and `output_shapes` properties of either
    # `training_dataset` or `validation_dataset` here, because they have
    # identical structure.
    handle = tf.placeholder(tf.string, shape=[])
    iterator = tf.data.Iterator.from_string_handle(
        handle, training_dataset.output_types, training_dataset.output_shapes)
    next_element = iterator.get_next()

    # You can use feedable iterators with a variety of different kinds of iterator
    # (such as one-shot and initializable iterators).
    training_iterator = training_dataset.make_one_shot_iterator()
    validation_iterator = validation_dataset.make_initializable_iterator()

    # The `Iterator.string_handle()` method returns a tensor that can be evaluated
    # and used to feed the `handle` placeholder.
    training_handle = sess.run(training_iterator.string_handle())
    validation_handle = sess.run(validation_iterator.string_handle())

    # Loop forever, alternating between training and validation.
    while True:
        # Run 200 steps using the training dataset. Note that the training dataset is
        # infinite, and we resume from where we left off in the previous `while` loop
        # iteration.
        for _ in range(200):
            sess.run(next_element, feed_dict={handle: training_handle})

        # Run one pass over the validation dataset.
        sess.run(validation_iterator.initializer)
        for _ in range(50):
            sess.run(next_element, feed_dict={handle: validation_handle})

def t5():
    dataset = tf.data.Dataset.range(5)
    iterator = dataset.make_initializable_iterator()
    next_element = iterator.get_next()
    # Typically `result` will be the output of a model, or an optimizer's
    # training operation.
    result = tf.add(next_element, next_element)  # 将两个元素相加
    sess.run(iterator.initializer)
    print(sess.run(result))  # ==> "0"
    print(sess.run(result))  # ==> "2"
    print(sess.run(result))  # ==> "4"
    print(sess.run(result))  # ==> "6"
    print(sess.run(result))  # ==> "8"
    try:
        sess.run(result)
    except tf.errors.OutOfRangeError:
        print("End of dataset")  # ==> "End of dataset"

def t6():
    dataset1 = tf.data.Dataset.from_tensor_slices(tf.random_uniform([4, 10]))
    dataset2 = tf.data.Dataset.from_tensor_slices((tf.random_uniform([4]), tf.random_uniform([4, 100])))
    dataset3 = tf.data.Dataset.zip((dataset1, dataset2))
    iterator = dataset3.make_initializable_iterator()
    sess.run(iterator.initializer)
    next1, (next2, next3) = iterator.get_next()
    print(sess.run([next1, next2, next3]))

def t7():
    # Define training and validation datasets with the same structure.
    training_dataset = tf.data.Dataset.range(100).map(
        lambda x: x + tf.random_uniform([], -10, 10, tf.int64)).repeat()
    validation_dataset = tf.data.Dataset.range(50)

    # A feedable iterator is defined by a handle placeholder and its structure. We
    # could use the `output_types` and `output_shapes` properties of either
    # `training_dataset` or `validation_dataset` here, because they have
    # identical structure.
    handle = tf.placeholder(tf.string, shape=[])
    iterator = tf.data.Iterator.from_string_handle(
        handle, training_dataset.output_types, training_dataset.output_shapes)
    next_element = iterator.get_next()

    # You can use feedable iterators with a variety of different kinds of iterator
    # (such as one-shot and initializable iterators).
    training_iterator = training_dataset.make_one_shot_iterator()
    validation_iterator = validation_dataset.make_initializable_iterator()

    # The `Iterator.string_handle()` method returns a tensor that can be evaluated
    # and used to feed the `handle` placeholder.
    training_handle = sess.run(training_iterator.string_handle())
    validation_handle = sess.run(validation_iterator.string_handle())

    # Loop forever, alternating between training and validation.
    while True:
        # Run 200 steps using the training dataset. Note that the training dataset is
        # infinite, and we resume from where we left off in the previous `while` loop
        # iteration.
        for _ in range(200):
            sess.run(next_element, feed_dict={handle: training_handle})

        # Run one pass over the validation dataset.
        sess.run(validation_iterator.initializer)
        for _ in range(50):
            sess.run(next_element, feed_dict={handle: validation_handle})

def t8():
    # Load the training data into two NumPy arrays, for example using `np.load()`.
    with np.load("/var/data/training_data.npy") as data:
        features = data["features"]
        labels = data["labels"]

    # Assume that each row of `features` corresponds to the same row as `labels`.
    assert features.shape[0] == labels.shape[0]
    dataset = tf.data.Dataset.from_tensor_slices((features, labels))

def t9():
    # Load the training data into two NumPy arrays, for example using `np.load()`.
    with np.load("/var/data/training_data.npy") as data:
        features = data["features"]
        labels = data["labels"]
    # Assume that each row of `features` corresponds to the same row as `labels`.
    assert features.shape[0] == labels.shape[0]

    features_placeholder = tf.placeholder(features.dtype, features.shape)
    labels_placeholder = tf.placeholder(labels.dtype, labels.shape)

    dataset = tf.data.Dataset.from_tensor_slices((features_placeholder, labels_placeholder))
    # [Other transformations on `dataset`...]
    # dataset = ...
    iterator = dataset.make_initializable_iterator()
    sess.run(iterator.initializer, feed_dict={features_placeholder: features,
                                              labels_placeholder: labels})

def t10():
    filenames = tf.placeholder(tf.string, shape=[None])
    dataset = tf.data.TFRecordDataset(filenames)
    # dataset = dataset.map(...)  # Parse the record into tensors.
    dataset = dataset.repeat()  # Repeat the input indefinitely.
    dataset = dataset.batch(32)
    iterator = dataset.make_initializable_iterator()

    # You can feed the initializer with the appropriate filenames for the current
    # phase of execution, e.g. training vs. validation.

    # Initialize `iterator` with training data.
    training_filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]
    sess.run(iterator.initializer, feed_dict={filenames: training_filenames})

    # Initialize `iterator` with validation data.
    validation_filenames = ["/var/data/validation1.tfrecord", ...]
    sess.run(iterator.initializer, feed_dict={filenames: validation_filenames})

def t11():
    filenames = ["/var/data/file1.txt", "/var/data/file2.txt"]

    dataset = tf.data.Dataset.from_tensor_slices(filenames)

    # Use `Dataset.flat_map()` to transform each file as a separate nested dataset,
    # and then concatenate their contents sequentially into a single "flat" dataset.
    # * Skip the first line (header row).
    # * Filter out lines beginning with "#" (comments).
    dataset = dataset.flat_map(
        lambda filename: (
            tf.data
                .TextLineDataset(filename)
                .skip(1)
                .filter(lambda line: tf.not_equal(tf.substr(line, 0, 1), "#")))
    )

def t12():
    # Transforms a scalar string `example_proto` into a pair of a scalar string and
    # a scalar integer, representing an image and its label, respectively.
    def _parse_function(example_proto):
        features = {"image": tf.FixedLenFeature((), tf.string, default_value=""),
                    "label": tf.FixedLenFeature((), tf.int32, default_value=0)}
        parsed_features = tf.parse_single_example(example_proto, features)
        return parsed_features["image"], parsed_features["label"]

    # Creates a dataset that reads all of the examples from two files, and extracts
    # the image and label features.
    filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]
    dataset = tf.data.TFRecordDataset(filenames)
    dataset = dataset.map(_parse_function)

def t13():
    # Reads an image from a file, decodes it into a dense tensor, and resizes it
    # to a fixed shape.
    def _parse_function(filename, label):
        image_string = tf.read_file(filename)
        image_decoded = tf.image.decode_image(image_string)
        image_resized = tf.image.resize_images(image_decoded, [28, 28])
        return image_resized, label

    # A vector of filenames.
    filenames = tf.constant(["/var/data/image1.jpg", "/var/data/image2.jpg", ...])

    # `labels[i]` is the label for the image in `filenames[i].
    labels = tf.constant([0, 37, ...])

    dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
    dataset = dataset.map(_parse_function)

def use_tf_py_func():
    import cv2
    # Use a custom OpenCV function to read the image, instead of the standard
    # TensorFlow `tf.read_file()` operation.
    def _read_py_function(filename, label):
        image_decoded = cv2.imread(image_string, cv2.IMREAD_GRAYSCALE)
        return image_decoded, label

    # Use standard TensorFlow operations to resize the image to a fixed shape.
    def _resize_function(image_decoded, label):
        image_decoded.set_shape([None, None, None])
        image_resized = tf.image.resize_images(image_decoded, [28, 28])
        return image_resized, label

    filenames = ["/var/data/image1.jpg", "/var/data/image2.jpg", ...]
    labels = [0, 37, 29, 1, ...]

    dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
    dataset = dataset.map(
        lambda filename, label: tuple(tf.py_func(
            _read_py_function, [filename, label], [tf.uint8, label.dtype]))) # py_func的作用是延迟python function的执行
    dataset = dataset.map(_resize_function)

def test_batch():
    inc_dataset = tf.data.Dataset.range(100)
    dec_dataset = tf.data.Dataset.range(0, -100, -1)
    dataset = tf.data.Dataset.zip((inc_dataset, dec_dataset))
    batched_dataset = dataset.batch(4)

    iterator = batched_dataset.make_one_shot_iterator()
    next_element = iterator.get_next()

    print(sess.run(next_element))  # ==> ([0, 1, 2,   3],   [ 0, -1,  -2,  -3])
    print(sess.run(next_element))  # ==> ([4, 5, 6,   7],   [-4, -5,  -6,  -7])
    print(sess.run(next_element))  # ==> ([8, 9, 10, 11],   [-8, -9, -10, -11])

def test_padded_batch():
    dataset = tf.data.Dataset.range(100)
    dataset = dataset.map(lambda x: tf.fill([tf.cast(x, tf.int32)], x))
    dataset = dataset.padded_batch(4, padded_shapes=[None])

    iterator = dataset.make_one_shot_iterator()
    next_element = iterator.get_next()

    print(sess.run(next_element))  # ==> [[0, 0, 0], [1, 0, 0], [2, 2, 0], [3, 3, 3]]
    print("\n")
    print(sess.run(next_element))  # ==> [[4, 4, 4, 4, 0, 0, 0],
                                    #      [5, 5, 5, 5, 5, 0, 0],
                                    #      [6, 6, 6, 6, 6, 6, 0],
                                    #      [7, 7, 7, 7, 7, 7, 7]]

def input_fn():
    def dataset_input_fn():
        filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]
        dataset = tf.data.TFRecordDataset(filenames)

        # Use `tf.parse_single_example()` to extract data from a `tf.Example`
        # protocol buffer, and perform any additional per-record preprocessing.
        def parser(record):
            keys_to_features = {
                "image_data": tf.FixedLenFeature((), tf.string, default_value=""),
                "date_time": tf.FixedLenFeature((), tf.int64, default_value=""),
                "label": tf.FixedLenFeature((), tf.int64,
                                            default_value=tf.zeros([], dtype=tf.int64)),
            }
            parsed = tf.parse_single_example(record, keys_to_features)

            # Perform additional preprocessing on the parsed data.
            image = tf.image.decode_jpeg(parsed["image_data"])
            image = tf.reshape(image, [299, 299, 1])
            label = tf.cast(parsed["label"], tf.int32)
            return {"image_data": image, "date_time": parsed["date_time"]}, label

        # Use `Dataset.map()` to build a pair of a feature dictionary and a label
        # tensor for each example.
        num_epochs =1
        dataset = dataset.map(parser)
        dataset = dataset.shuffle(buffer_size=10000)
        dataset = dataset.batch(32)
        dataset = dataset.repeat(num_epochs)
        iterator = dataset.make_one_shot_iterator()

        # `features` is a dictionary in which each value is a batch of values for
        # that feature; `labels` is a batch of labels.
        features, labels = iterator.get_next()
        return features, labels

def t14():
    dataset = tf.data.Dataset.range(100).map(lambda x: x+1).batch(10)
    iterator = dataset.make_initializable_iterator()
    next_element = iterator.get_next()
    # Typically `result` will be the output of a model, or an optimizer's
    # training operation.
    sess.run(iterator.initializer)
    while True:
        try:
            print(sess.run(next_element))  # ==> "0"
        except tf.errors.OutOfRangeError:
            print("End of dataset")  # ==> "End of dataset"
            break

if __name__ == "__main__":
    # t3()
    # t4()
    # t5()
    # t6()
    #t7()
    #test_batch()
    #test_padded_batch()
    t14()
    sess.close()


class Solution:
    def minimumCost(self, cost: List[int]) -> int:
        # ------------- Approach 1
        '''
        total = 0
        count = 0
        cost = sorted(cost)[::-1]
        for i in range(len(cost)):
            count += 1
            if count % 3 == 0:
                continue
            total += cost[i]
        return total
        '''
        # ------------- Approach 2
        cost.sort(reverse = True)
        total = 0
        for i in range(len(cost)):
            if i % 3 != 2:
                total += cost[i]
        return total


#-*- coding: UTF-8 -*-
from common import MyExcel
import time
from common.SignatureGenerator import *
from common.read_config import read_config
import requests
import configparser
# 1、从excel 表中读取需要算签名数据
filePath = "E:\\PycharmProjects\\python-api\\TestDatas\\TestData.xlsx"
me = MyExcel.MyExcel(filePath)
caseDatas = me.get_all_testDatas()
print(len(caseDatas))
appkey = read_config().read_config("common.conf", "http", "app_key")
for i in range(0,len(caseDatas)):
    params_map =eval(caseDatas[i]["request_data"])
    url = caseDatas[i]["url"]
    signt = str(int(time.time() * 1000))
    params_map.update(signt=signt,appkey=appkey)
    sign = SignatureGenerator.generate(url, params_map)
    params_map.update(sign=sign)
    caseDatas[i]["request_data"] = str(params_map)
    caseDatas[i]["url"] = read_config().read_config("common.conf", "http", "server_ip")+url
print(caseDatas[1]["expected_data"])
# param_map=eval(caseDatas[0]["request_data"])
# url = caseDatas[0]["url"]
# print(param_map)
print(url)
# 2.进行更新param数据中得signt
# signt =str(int(time.time()*1000))
# param_map.update(signt=signt)
# print(param_map)
#
# # 3、进行签名加密
# sign = SignatureGenerator.generate(url, param_map)
# print(sign)
#
# # 4、更新param_map 字典中得参数
#
# param_map.update(sign=sign)
# print(param_map)
# # 5、gei请求
#
# # 读取配置文件中得ip
# config=configparser.ConfigParser()
# config.read("common.conf")
# urls="http://"+config.get("http","server_ip")+"/"+url
# print(urls)
#
#
# request = requests.get(url=urls,params=param_map)
# result =request.content
# print(request.url)
# print(result)


from enum import Enum, unique

class ElementMonthlyRecord:
    def __init__(self, station_id, year, month, element, daily_values):
        self.station_id = station_id
        self.year = year
        self.month = month
        self.element = element
        self.daily_values = daily_values

class ElementDailyRecord:
    def __init__(self, station_id, year, month, date, element, val, m_flag, q_flag, s_flag):
        self.station_id = station_id
        self.year = year
        self.month = month
        self.date = date
        self.element = element
        self.val = val
        self.m_flag = m_flag
        self.q_flag = q_flag
        self.s_flag = s_flag

class DailyValue:
    def __init__(self, val, date, m_flag, q_flag, s_flag):
        self.val = val
        self.date = date
        self.m_flag = m_flag
        self.q_flag = q_flag
        self.s_flag = s_flag

@unique
class ClimateNetwork(Enum):
    NONE = "NONE"
    HCN = "HCN"
    CRN = "CRN"


from collections import deque

MAX = 10 ** 5 + 1

n, k = map(int, input().split())
visited = [[-1, 0] for _ in range(MAX)]

def bfs(x):
    q = deque([x])
    visited[x] = [0, 1]

    while q:
        x = q.popleft()

        for nx in (x - 1, x + 1, 2 * x):
            if 0 <= nx < MAX:
                if visited[nx][0] == -1:
                    q.append(nx)
                    visited[nx] = [visited[x][0] + 1, visited[x][1]]
                elif visited[nx][0] == visited[x][0] + 1:
                    visited[nx][1] += visited[x][1]

    return visited[k]

print(*bfs(n), sep="\n")


# -*- coding: utf-8 -*-
"""
Created on Sat Nov  3 13:54:20 2018
This program builds additional features and targets from the ohlcv data. The
targets built are the times at which extraordinary movements to the up and downside
are present. These times are located by comparing the percentage of returns at each
time step and identifying the overall distribution of these changes. With such a
distribution, arbitrarily significant movements can then be identified and
characterized as the target variable of a binary classifier.
@author: Çağkan Acarbay
"""

import pandas as pd
from sklearn.preprocessing import MinMaxScaler
import feature_eng_TA as ta
import math

def build_targets(prices, target, train_begin, valid_begin, test_begin, test_end = -1):
    """ Computes the percentage change in prices, returns train/test/validation sets
    as a True/False array for the given target variable where:
            - for positive target the output is 1 for values greater than target
            - for negative target the output is 1 for values less than target
    """
    percentage_change = (prices/prices.shift()-1)*100
    percentage_change.fillna(value = 0, inplace = True)
    if target >= 0:
        outliers = percentage_change.map(lambda x: 0 if x <= target else 1)
    else:
        outliers = percentage_change.map(lambda x: 0 if x > target else 1)
    # Split
    Y_train = outliers[train_begin:valid_begin]
    Y_train.index = range(len(Y_train))
    Y_valid = outliers[valid_begin:test_begin]
    Y_valid.index = range(len(Y_valid))
    Y_test = outliers[test_begin:test_end]
    Y_test.index = range(len(Y_test))
    return Y_train, Y_valid, Y_test

def build_targets_full(prices, target):
    """ A basic version of the function build_targets that returns the entire
    target list for the given list of prices as one array."""
    percentage_change = (prices/prices.shift()-1)*100
    percentage_change.fillna(value = 0, inplace = True)
    if target >= 0:
        outliers = percentage_change.map(lambda x: 0 if x <= target else 1)
    else:
        outliers = percentage_change.map(lambda x: 0 if x > target else 1)
    return outliers

def get_features(df, sliding_window_size = 24, ma_size = [10, 20, 50, 200]):
    """ Computes technical indicator values from given ohlcv data. Returns single
    dataframe containing the original dataframe and the computed features.
        Parameters:
            df - ohlcv data
            sliding_window_size - number of lags to add to the dataframe for each
                time point
            ma_size - list of n values for the technical indicators of
            MA, EMA, TRIX, MOM, ROC, Vortex and RSI.
    """
    # Run TA algorithms to prepare features
    n = ma_size
    for i in range(len(n)):
        #df = ta.MA(df,n[i])
        #df = ta.EMA(df,n[i])
        df = ta.TRIX(df,n[i])
        df = ta.MOM(df,n[i])
        df = ta.ROC(df,n[i])
        df = ta.Vortex(df,n[i])
        df = ta.RSI(df,n[i])
    # For these TA algorithms the most commonly used values of parameters are employed
    df = ta.MACD(df)
    df = ta.KST(df)
    df = ta.STOCH_OSC(df,nS = 3*24)

    df1 = df.drop(columns = ['time', 'date', 'open', 'low', 'high'])
    df2 = df1
    # Another feature apart from the TA results are the shifted version of the closing price
    # For this, a sliding window method is used to provide the closing prices for
    # the past 24 hours.
    for i in range(1, sliding_window_size+1):
        temp = df1.shift(i)
        temp = temp.add_suffix('_'+str(i))
        df2 = df2.join(temp)

    # Check if any NANs exist beyond the initial calculations
    if df[2000:].isnull().values.any() == True:
        print('There are NANs in the data. Clean data before proceeding.')
    else:
        print('No NANs in the features')

    return df2

def set_features(X, train_begin, valid_begin, test_begin, test_end = -1):
    """ Takes dataframe with prepared features, beginning index for train, validation
    and test sets and prepares the data by scaling and removing unnecessary ohlcv
    data. Returns seperate X_train, X_valid and X_test data.
    """
    X_train = X[train_begin-1:valid_begin-1]
    X_valid = X[valid_begin-1:test_begin-1]
    X_test = X[test_begin-1:test_end-1]
    # MinMax Scaler built on X_train
    scaler = MinMaxScaler(feature_range = (0,1))
    scaler.fit(X_train)
    X_train = scaler.transform(X_train)
    X_valid = scaler.transform(X_valid)
    X_test = scaler.transform(X_test)
    return X_train, X_valid, X_test

def set_features_basic(X, train_begin = -1, valid_begin = -1):
    """ A basic version of the function set_features that returns the training
    set and the rest of the features as two multi-dimensional arrays. If
    train_begin isn't set, scales according to train_begin, but returns the entire
    set as one.
    """
    if train_begin == -1:
        X_train = X[:valid_begin-1]
        scaler = MinMaxScaler(feature_range = (0,1))
        scaler.fit(X_train)
        X_fit = scaler.transform(X[:-1]) # drop last point
        return X_fit
    else:
        X_train = X[train_begin-1:valid_begin-1]
        X_rest = X[valid_begin-1:-1]
        # MinMax Scaler built on X_train
        scaler = MinMaxScaler(feature_range = (0,1))
        scaler.fit(X_train)
        X_train = scaler.transform(X_train)
        X_rest = scaler.transform(X_rest)
    return X_train, X_rest

def get_splits(df, data_size = [0.3, 0.5, 0.75, 1], train_ratios =
               [0.8, 0.7, 0.6], valid_ratios = [0.05, 0.1, 0.2]):
    """ This function produces a variety of train/validation/test splits of the data
    based on the given ratios of total data size and train/valid set sizes. The
    function returns a list of series denoting the start of each train/valid/test
    split, which may then be used in conjunction with the set_features function to
    get the resulting sets."""
    splits = []
    for data_ratio in data_size:
        begin = round(len(df) - data_ratio*len(df)) + 1
        size = len(df) - begin
        for train_ratio in train_ratios:
            for valid_ratio in valid_ratios:
                if train_ratio + valid_ratio < 1:
                    split = pd.Series(name = 'Size:' + str(size) + ' Ratio:'
                                         + str(train_ratio) + ':' + str(valid_ratio)
                                         + ':' + str(round(1-train_ratio-valid_ratio,2)))
                    split['train_begin'] = begin
                    split['valid_begin'] = round(begin + (len(df) - begin) * train_ratio)
                    split['test_begin'] = round(begin + (len(df) - begin) * (train_ratio + valid_ratio))
                    split['ratio'] = [train_ratio,valid_ratio,round(1-train_ratio-valid_ratio,2)]
                    splits.append(split)
    return splits

def get_rolling_splits(df, start = 2000, delta = 1000, split_size = [10000, 1000, 2000]):
    """ This function produces a rolling train/validation/test splits of the data
    based on the fixed train/validation/test dataset sizes and a fixed delta. The
    list output may then be used with the set_features function to get the resulting
    sets.
    """
    no_of_splits = math.floor((len(df)-sum(split_size)-start)/delta)
    begin = int(start)
    splits = []
    for i in range(no_of_splits):
        split = pd.Series(name = 'Begin:' + str(begin) + ' Sizes:'
                                          + str(int(split_size[0])) + ':'
                                          + str(int(split_size[1])) + ':'
                                          + str(int(split_size[2])))
        split['train_begin'] = begin
        split['valid_begin'] = begin + int(split_size[0])
        split['test_begin'] = split['valid_begin'] + int(split_size[1])
        split['test_end'] = split['test_begin'] + int(split_size[2])
        begin = begin + delta
        splits.append(split)
    return splits

##

#df_org = pd.read_pickle("./btc_hourly")
## Get features
#df = get_features(df_org, sliding_window_size = 72)
#import pickle
#df.to_pickle("./hourly_with_features")


# Anti-"mov" v0.1
import subprocess
import string
import os.path

def mov_argv_brute(target_file:str, charset: str = string.printable, exec: bool = False, sys_type: str = "linux"):
    # File check
    if not os.path.exists(target_file):
        print("Error: File Not Found")
        return

    # Variables
    flag = ''
    command = "perf stat -x : -e instructions:u " + target_file

    # Command Updates
    def update_command(): # With added char
        return command + " " + flag + i + "1>/dev/null"

    def print_flag_command(): # As is
        return target_file + " " + flag

    # Brute force loop
    while True:
        ins_count = 0
        count_chr = ''
        for i in charset:
            if sys_type.lower() == "linux":
                if i == "\'":
                    i = "\\\'"
                else:
                    i = '\'' + i + '\''
            else:
                print("Err: Unsupported OS")
                return
            cmd_updated = update_command()
            target_process = subprocess.Popen(cmd_updated,
                                              stdout=subprocess.PIPE,
                                              stdin=subprocess.PIPE,
                                              stderr=subprocess.STDOUT,
                                              shell=True)

            # Filter out the instruction count
            result = target_process.stdout.read().decode("utf-8")
            result = result.split(":")

            # Pull count and set char if greater
            instructions = int(result[0])
            if instructions > ins_count:
                count_chr = i
                ins_count = instructions
        flag += count_chr
        print(ins_count)
        print(flag)

        # Optional Run Check if exec == true
        if exec:
            exec_process = subprocess.Popen(print_flag_command(),
                                              stdout=subprocess.PIPE,
                                              stdin=subprocess.PIPE,
                                              stderr=subprocess.STDOUT,
                                              shell=True)
            print(exec_process.stdout.read().decode("utf-8"))


# Not even going to bother putting the whole problem statement here...

import os
import math
import collections

# Take list of strings representing a group's customs entries, return unique char count
def CountGroup(group):
    seenChars = set()
    for line in group:
        for char in line:
            seenChars.add(char)

    return len(seenChars)

def SumGroupCounts(groups):
    return sum(list(map(CountGroup, groups)))

def CountGroupPartTwo(group):
    requiredCount = len(group)
    seenChars = collections.defaultdict(int)

    for line in group:
        for char in line:
                seenChars[char] += 1

    result = 0
    for key, value in seenChars.items():
        if value == requiredCount:
            result += 1
    return result

def SumGroupCountsPartTwo(groups):
    results = list(map(CountGroupPartTwo, groups))
    return sum(results)

# Returns a list of lists of strings (i.e. a list of groups)
def ParseInput(filename):
    dataFile = open(filename, "r")
    dataAsString = ""
    for line in dataFile:
        dataAsString += line

    groupLists = []

    for string in dataAsString.split("\n\n"):
        groupLists.append(string.split("\n"))

    print(groupLists[len(groupLists)-1])
    return groupLists

def main():

    os.chdir(os.getcwd() + '\\solutions\\')
    groups = ParseInput("06_input.txt")

    print(SumGroupCounts(groups))
    print(SumGroupCountsPartTwo(groups))

main()


"""pet_service URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls.static import static
from django.conf import settings
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.mainpage),
    path('index/', views.index, name='index'),
    path('get_gu/', views.getGu, name='getGu'),
    path('get_business/', views.getBusiness),
    path('get_info/', views.getInfo),
    path('get_map/',views.Map),
    path('score/', views.score),
    path('getbargraph/', views.getBargraph),
    path('Geo/',views.Geo),
    path("score/get_myloc/",views.my_loc),
    path("media/", views.media),
    path('menu/',views.menu),
    path('menu/get_myloc/',views.my_loc),
    path('get_score/',views.load_score),
    path('get_rank/',views.load_rank),
    path('click_bs/',views.click_bs),
]
urlpatterns += \
    static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


import os
import logging
import time

"""
Set the time you want to rest after the test was
completed to start the test again.
"""
sleeping = 30

logging.basicConfig(filename="connection.log",
                    format='%(levelname)s: %(asctime)s: %(message)s',
                    datefmt='%m/%d/%Y %I:%M:%S %p',
                    level=logging.INFO)
logging.info("Program started")

hostname = "google.com"

def main():
    try:
        response = os.system("ping -c 1 " + hostname)
        if response == 0:
            print(hostname + ' is up!')
            try:
                ping, download, upload = get_speedtest_results()
            except TypeError as err:
                print(hostname + ' is down!')
                logging.info(err)
        else:
            print(hostname + ' is down!')
            # logging.error(hostname + ' is down!')
    except ValueError as err:
        logging.info(err)
    else:
        try:
            logging.info("%5.1f %5.1f %5.1f", ping, download, upload)
            print(ping, download, upload)
        except UnboundLocalError:
            logging.error("The internet is down.")

def get_speedtest_results():
    ping = download = upload = None
    speedtest_output = os.popen('speedtest-cli --simple')

    for line in speedtest_output:
        label, value, unit = line.split()

        if 'Ping' in label:
            ping = float(value)
        elif 'Download' in label:
            download = float(value)
        elif 'Upload' in label:
            upload = float(value)

    if all((ping, download, upload)):  # if all 3 values were parsed
        return ping, download, upload
    else:
        logging.error('internet is down!')

while True:
    main()
    time.sleep(sleeping)

logging.info("Done!")


from typing import Union

from aries_cloudagent.messaging.agent_message import AgentMessage

from .traction_decorator import TractionDecorator

class TractionMessage(AgentMessage):

    def __init__(
        self,
        **kwargs,
    ):

        super().__init__(**kwargs)
        self._decorators["traction"] = TractionDecorator()

    @property
    def _traction(self) -> TractionDecorator:
        return self._decorators.get("traction")

    @_traction.setter
    def _traction(self, val: Union[TractionDecorator, dict]):
        if val is None:
            self._decorators.pop("traction", None)
        else:
            self._decorators["traction"] = val


import lacosmic
import matplotlib.pyplot as plt
from astropy.stats import sigma_clipped_stats

def linear(x, m, c):
    return m * x + c

def clean_cosmic_rays(spectrum2D,
                      mask=None,
                      contrast=3,
                      cr_threshold=5,
                      neighbor_threshold=0.3,
                      effective_gain=1,
                      readnoise=1
                      ):
    if mask is None:
        mask = (spectrum2D == 0)

    cleaned_spectrum2D, _ = lacosmic.lacosmic(spectrum2D,
                                              contrast=contrast,
                                              cr_threshold=cr_threshold,
                                              neighbor_threshold=neighbor_threshold,
                                              mask=mask,
                                              effective_gain=effective_gain,
                                              readnoise=readnoise
                                              )
    return cleaned_spectrum2D

def plot_spec2d(spec2D, ax=None):
    if ax is None:
        fig = plt.figure()
        ax = fig.gca()
    mean, median, std = sigma_clipped_stats(spec2D)
    ax.imshow(spec2D, origin='lower', vmin=median - 3 * std,
               vmax=median + 3 * std, aspect=0.4 * spec2D.shape[1] / spec2D.shape[0])
    return ax


import pytest
import requests

from .. import utils

import verta.dataset
import verta.environment
from verta._internal_utils import _utils

class TestRepository:
    def test_get_by_name(self, client, repository):
        retrieved_repo = client.get_or_create_repository(repository.name)
        assert repository.id == retrieved_repo.id

    def test_get_by_id(self, client, repository):
        retrieved_repo = client.get_or_create_repository(id=repository.id)
        assert repository.id == retrieved_repo.id

    def test_max_one_arg_for_get_commit(self, repository):
        with pytest.raises(ValueError):
            repository.get_commit(branch="banana", tag="coconut")

    def test_master_branch_default(self, repository):
        assert repository.get_commit().branch_name == "master"

class TestCommit:
    def test_add_get_rm(self, commit):
        blob1 = verta.environment.Python(["a==1"])
        blob2 = verta.environment.Python(["b==2"])
        path1 = "path/to/bananas"
        path2 = "path/to/still-bananas"

        commit.update(path1, blob1)
        commit.update(path2, blob2)
        assert commit.get(path1) == blob1
        assert commit.get(path2) == blob2

        commit.remove(path1)
        with pytest.raises(LookupError):
            commit.remove(path1)

        commit.remove(path2)
        assert not commit._blobs

    def test_save(self, commit):
        blob = verta.environment.Python(["a==1"])
        path = "path/to/bananas"

        commit.update(path, blob)

        commit.save(message="banana")

        assert commit.id

    def test_walk(self, commit):
        pytest.importorskip("boto3")

        commit.update("file-1", verta.dataset.S3("s3://verta-starter/census-test.csv"))
        commit.update("a/file-2", verta.dataset.S3("s3://verta-starter/census-train.csv"))
        commit.update("a/file-3", verta.dataset.S3("s3://verta-starter/imdb_master.csv"))
        commit.update("a/b/file-4", verta.dataset.S3("s3://verta-starter/reviews.ann"))
        commit.update("a/c/file-5", verta.dataset.S3("s3://verta-starter/spam.csv"))
        commit.save(message="banana")

        # alphabetical order
        walk = commit.walk()
        assert ("", ["a"], ["file-1"]) == next(walk)
        assert ("a", ["b", "c"], ["file-2", "file-3"]) == next(walk)
        assert ("a/b", [], ["file-4"]) == next(walk)
        assert ("a/c", [], ["file-5"]) == next(walk)

        # mutable `folder_names`
        walk = commit.walk()
        next(walk)  # root
        del next(walk)[1][1]  # remove a/c from a's `folder_names`
        next(walk)  # a/b
        with pytest.raises(StopIteration):
            next(walk)  # a/c removed

    def test_get_commit_by_tag(self, repository):
        blob = verta.environment.Python(["a==1"])
        path = "path/to/bananas"

        commit = repository.get_commit()
        commit.update(path, blob)
        commit.save(message="banana")
        commit.tag("banana")

        assert commit.id == repository.get_commit(tag="banana").id

    def test_get_commit_by_id(self, repository):
        blob = verta.environment.Python(["a==1"])
        path = "path/to/bananas"

        commit = repository.get_commit()
        commit.update(path, blob)
        commit.save(message="banana")

        assert commit.id == repository.get_commit(id=commit.id).id

    def test_become_child(self, commit):
        blob1 = verta.environment.Python(["a==1"])
        blob2 = verta.environment.Python(["b==2"])
        path1 = "path/to/bananas"
        path2 = "path/to/still-bananas"

        commit.update(path1, blob1)
        commit.save(message="banana")
        original_id = commit.id
        commit.update(path2, blob2)

        assert commit.id is None
        assert original_id in commit._parent_ids
        assert commit.get(path1)

        commit.save(message="banana")

        assert commit.id != original_id

    def test_log(self, repository):
        r"""
        Tests the log for this commit tree:

             (master)
              /     \
        (master~) (branch)
              \     /
              (root)

        """
        master = repository.get_commit(branch="master")

        commit_ids = [master.id]

        branch = repository.get_commit(branch="master").new_branch("branch")

        master.update("a", verta.environment.Python(["a==1"]))
        master.save("a")
        commit_ids.append(master.id)

        branch.update("b", verta.environment.Python(["b==2"]))
        branch.save("b")
        commit_ids.append(branch.id)

        master.merge(branch)
        commit_ids.append(master.id)

        for log_commit, expected_id in zip(master.log(), reversed(commit_ids)):
            assert log_commit.id == expected_id

        # use parent of updated-but-unsaved commit
        master.update("c", verta.environment.Python(["c==3"]))
        assert master.id is None  # unsaved
        for log_commit, expected_id in zip(master.log(), reversed(commit_ids)):
            assert log_commit.id == expected_id

    def test_merge_conflict(self, repository):
        branch_a = repository.get_commit(branch="master").new_branch("a")
        branch_a.update("env", verta.environment.Python(["pytest==1"]))
        branch_a.save("a")

        branch_b = repository.get_commit(branch="master").new_branch("b")
        branch_b.update("env", verta.environment.Python(["pytest==2"]))
        branch_b.save("b")

        with pytest.raises(RuntimeError):
            branch_b.merge(branch_a)

    def test_revert(self, repository):
        blob1 = verta.environment.Python(["pytest==1"])
        blob2 = verta.environment.Python(["pytest==2"])
        loc1 = "loc1"
        loc2 = "loc2"

        commit = repository.get_commit(branch="master")

        commit.update(loc1, blob1)
        commit.save("1")
        commit_to_revert_id = commit.id

        commit.update(loc2, blob2)
        commit.save("2")

        commit_to_revert = repository.get_commit(id=commit_to_revert_id)
        commit.revert(commit_to_revert)

        # blob1 removed
        with pytest.raises(LookupError):
            commit.get(loc1)
        # blob2 still present
        assert commit.get(loc2)

    def test_revert_merge_commit(self, repository):
        blob1 = verta.environment.Python(["pytest==1"])
        blob2 = verta.environment.Python(["pytest==2"])
        loc1 = "loc1"
        loc2 = "loc2"

        commit_a = repository.get_commit("master").new_branch("a")
        commit_a.update(loc1, blob1)
        commit_a.save("some message")

        commit_b = repository.get_commit("master").new_branch("b")
        commit_b.update(loc2, blob2)
        commit_b.save("other message")

        commit_a.merge(commit_b)
        commit_a.revert()

        # blob2 removed
        with pytest.raises(LookupError):
            commit_a.get(loc2)

        # blob1 still present
        assert commit_a.get(loc1)

    def test_log_to_run(self, experiment_run, commit):
        blob1 = verta.dataset.Path(__file__)
        reqs = verta.environment.Python.read_pip_environment()
        blob2 = verta.environment.Python(reqs)
        path1 = "data/1"
        path2 = "env/1"

        commit.update(path1, blob1)
        commit.update(path2, blob2)
        commit.save(message="banana")

        key_paths = {'my machine': path1}
        experiment_run.log_commit(commit, key_paths)

        retrieved_commit, retrieved_key_paths = experiment_run.get_commit()
        assert retrieved_commit.id == commit.id
        assert retrieved_key_paths == key_paths

    @pytest.mark.not_oss
    def test_log_to_run_diff_workspaces(self, client, experiment_run, organization):
        repository_name = _utils.generate_default_name()
        repository = client.get_or_create_repository(repository_name, workspace=organization.name)

        # TODO: Uncomment this check when repository.workspace is implemented
        # assert repository.workspace != experiment_run.workspace

        commit = repository.get_commit()
        experiment_run.log_commit(commit)

        retrieved_commit, retrieved_key_paths = experiment_run.get_commit()
        assert retrieved_commit.id == commit.id

        repository.delete()

    def test_log_to_run_diff_workspaces_no_access_error(self, client_2, experiment_run):
        repository_name = _utils.generate_default_name()
        repository = client_2.get_or_create_repository(repository_name)
        commit = repository.get_commit()

        with pytest.raises(requests.HTTPError) as excinfo:
            experiment_run.log_commit(commit)

        excinfo_value = str(excinfo.value).strip()
        assert "403" in excinfo_value
        assert "Access Denied" in excinfo_value

        repository.delete()

class TestBranch:
    def test_set(self, repository):
        branch = "banana"

        blob = verta.environment.Python(["a==1"])
        path = "path/to/bananas"

        commit = repository.get_commit()
        commit.update(path, blob)
        commit.save(message="banana")
        commit = commit.new_branch(branch)

        assert repository.get_commit(branch=branch).id == commit.id

    def test_change(self, repository):
        branch = "banana"

        blob1 = verta.environment.Python(["a==1"])
        blob2 = verta.environment.Python(["b==2"])
        path1 = "path/to/bananas"
        path2 = "path/to/still-bananas"

        commit1 = repository.get_commit()
        root_id = commit1.id
        commit1.update(path1, blob1)
        commit1.save(message="banana")

        commit2 = repository.get_commit(id=root_id)
        commit2.update(path2, blob2)
        commit2.save(message="banana")

        commit1 = commit1.new_branch(branch)
        commit2 = commit2.new_branch(branch)

        assert repository.get_commit(branch=branch).id == commit2.id

    def test_update(self, repository):
        branch = "banana"

        blob1 = verta.environment.Python(["a==1"])
        blob2 = verta.environment.Python(["b==2"])
        path1 = "path/to/bananas"
        path2 = "path/to/still-bananas"

        commit = repository.get_commit()
        commit.update(path1, blob1)
        commit.save(message="banana")
        original_id = commit.id

        commit = commit.new_branch(branch)

        commit.update(path2, blob2)
        commit.save(message="banana")

        assert commit.id != original_id
        assert repository.get_commit(branch=branch).id == commit.id


import torch
import torchvision.models as models
import torch.nn.functional as F

class VFELayer(torch.nn.Module):
    def __init__(self, input_dim, output_dim):
        self.fc = nn.Linear(input_dim, output_dim//2)
        self.bn = nn.BatchNorm1d(output_dim//2)
        self.op = nn.ReLU(inplace=True)

    def forward(self, x):
        output = self.fc(x)
        output = self.bn(output)
        output = self.op(output)
        element_wise_maxpool = torch.max(output,0)[0]
        sz = output.size()
        output = \
            torch.cat(
                (element_wise_maxpool.expand(sz[0],sz[1]), output),
                1
            )
        return output


class element:
	def elenotrep(n):
		n=int(input("enter number of elements in list"))
		for i in range(n):
			lst1.extend(input("Enter input numbers"))
		for num in lst1:
			if num not in lst2:
				lst2.append(num)
		print(lst2)
lst1=[]
lst2=[]
element.elenotrep(3)