# write your code here
def convertir_coords(x, y):
    return int(x) - 1 + (3 - int(y)) * 3

def compteur_cases(cells):
    x_counter = 0
    o_counter = 0
    for char in cells:
        if char == 'X':
            x_counter += 1
        if char == 'O':
            o_counter += 1
    if abs(x_counter - o_counter) >= 2:
        return "trop de XO"
    if x_counter + o_counter == 9:
        return "complet"

endgame = False
winner = '-'
two_winners = False
cells = '_________'
tour_X = True

while not endgame:
    case_valide = False
    case_x = -1
    case_y = -1

    while not case_valide:
        case_x, case_y = input("Enter the coordinates: ").split()
        if not case_x.isdigit() or not case_y.isdigit():
            print("You should enter numbers!")
        elif not 0 <= int(case_x) <= 3 or not 0 <= int(case_y) <= 3:
            print("Coordinates should be from 1 to 3!")
        elif cells[convertir_coords(int(case_x), int(case_y))] != '_':
            print("This cell is occupied! Choose another one!")

        else:
            case_valide = True

    if tour_X:
        cells = cells[:convertir_coords(case_x, case_y)] + 'X' + cells[convertir_coords(case_x, case_y) + 1:]
    elif not tour_X:
        cells = cells[:convertir_coords(case_x, case_y)] + 'O' + cells[convertir_coords(case_x, case_y) + 1:]
    print("---------")
    print("| " + cells[0] + " " + cells[1] + " " + cells[2] + " |")
    print("| " + cells[3] + " " + cells[4] + " " + cells[5] + " |")
    print("| " + cells[6] + " " + cells[7] + " " + cells[8] + " |")
    print("---------")

    if cells[0] == cells[1] and cells[1] == cells[2]:
        if winner != '-':
            two_winners = True
        if cells[0] == 'X':
            endgame = True
            winner = 'X'
        elif cells[0] == 'O':
            endgame = True
            winner = 'O'
    if cells[3] == cells[4] and cells[4] == cells[5]:
        if winner != '-':
            two_winners = True
        if cells[3] == 'X':
            endgame = True
            winner = 'X'
        elif cells[3] == 'O':
            endgame = True
            winner = 'O'
    if cells[6] == cells[7] and cells[7] == cells[8]:
        if winner != '-':
            two_winners = True
        if cells[6] == 'X':
            endgame = True
            winner = 'X'
        elif cells[6] == 'O':
            endgame = True
            winner = 'O'
    if cells[0] == cells[3] and cells[3] == cells[6]:
        if winner != '-':
            two_winners = True
        if cells[0] == 'X':
            endgame = True
            winner = 'X'
        elif cells[0] == 'O':
            endgame = True
            winner = 'O'
    if cells[1] == cells[4] and cells[4] == cells[7]:
        if winner != '-':
            two_winners = True
        if cells[1] == 'X':
            endgame = True
            winner = 'X'
        elif cells[1] == 'O':
            endgame = True
            winner = 'O'
    if cells[2] == cells[5] and cells[5] == cells[8]:
        if winner != '-':
            two_winners = True
        if cells[2] == 'X':
            endgame = True
            winner = 'X'
        elif cells[2] == 'O':
            endgame = True
            winner = 'O'
    if cells[0] == cells[4] and cells[4] == cells[8]:
        if winner != '-':
            two_winners = True
        if cells[0] == 'X':
            endgame = True
            winner = 'X'
        elif cells[0] == 'O':
            endgame = True
            winner = 'O'
    if cells[2] == cells[4] and cells[4] == cells[6]:
        if winner != '-':
            two_winners = True
        if cells[2] == 'X':
            endgame = True
            winner = 'X'
        elif cells[2] == 'O':
            endgame = True
            winner = 'O'

    if compteur_cases(cells) == "trop de XO" or two_winners:
        print('Impossible')
    elif compteur_cases(cells) == "complet" and winner == '-':
        endgame = True
        print('Draw')
    elif winner == 'X':
        print('X wins')
    elif winner == 'O':
        print('O wins')
    elif winner == '-':
        print('Game not finished')

    tour_X = not tour_X


class Solution:
    def solve(self, board):
        """
        Do not return anything, modify board in-place instead.
        """
        readed = set()

        def search(i, j):
            if i == -1 or i == len(board) or j == -1 or j == len(board[0]):
                return False
            if board[i][j] == "X":
                return True
            board[i][j] = "X"
            candi = [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]
            flg = []
            for ix, iy in candi:
                if f"{ix}-{iy}" in readed:
                    continue
                rs = search(ix, iy)
                flg.append(rs)
            # print(board)
                readed.add(f"{i}-{j}")

            print(i, j, flg, sum(flg))

            if sum(flg) != 4:
                board[i][j] = "O"
                return False
            return True

        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] == "O" and f"{i}-{j}" not in readed:
                    search(i, j)
                    readed.add(f"{i}-{j}")
        # search(0, 0)
        for i in board:
            print(i)

s = Solution()
board = [
     ["X","O","X","X", "O"],
     ["X","X","O","X", "X"],
     ["X","O","X","O", "X"],
     ["O","X","X","X", "X"]
         ]
# board = [["X"]]
board = [["O","O","O"],
         ["O","O","O"],
         ["O","O","O"]
         ]
board = [["X","X","X","X"],
         ["X","O","O","X"],
         ["X","X","O","X"],
         ["X","O","X","X"]]
s.solve(board)


from tkinter import *

root=Tk()
root.geometry("500x500")
root.title("Hey This Is Title")

Pizza = [
    "Choice The Correct Sentence",
    "Disha Computer Is The World's Best Institute",
    "Anu Is The Best Programmer In The World",
    "Lenovo Is A Laptop Company",
    "Python Is A Worst Language"
]

clicked = StringVar()
clicked.set("Choice The Correct Sentence")

Drop = OptionMenu(root, clicked, *Pizza)
Drop.place(x=150, y=50)

root.mainloop()


'''
Miscellaneous utility functions.
'''

import os
import yaml
import numpy as np
import matplotlib.pyplot as plt
import gif
import warnings
from typing import List

import torch
import torch.nn as nn

from pytorch_lightning.loggers import TensorBoardLogger
from pytorch_lightning.utilities import rank_zero_only

from pathlib import Path
from importlib import import_module

'''
Generates a side-by-side GIF of the raw data and the model reconstruction for the
test dataset; logs the result.

Input:
    trainer: lightning trainer
    datamodule: data module
    model: model to use or none to use best checkpoint
'''
def make_gif(trainer, datamodule, model):
    #run on test data
    if model == None:
        results = trainer.predict(ckpt_path='best', datamodule=datamodule)
    else:
        results = trainer.predict(model=model, datamodule=datamodule)

    #agglomerate the data if necessary (if tiling was used)
    data = datamodule.agglomerate(results)

    print(data.shape)

    #if multichannel then just take first channel
    if data.shape[-1] > 1:
        data = data[...,0]

    data = data.squeeze()

    #get plotting function
    plot_func = datamodule.get_plot_func()

    if plot_func == None:
        return

    #gif frame closure
    @gif.frame
    def plot(i):
        fig, ax = plt.subplots(1, 2)

        plot_func(datamodule.get_sample(i), ax[0])
        ax[0].set_title("Uncompressed")

        im = plot_func(data[i,...], ax[1])
        ax[1].set_title("Reconstructed")

        if datamodule.spatial_dim == 2:
            # mappable = cm.ScalarMappable(norm=norm, cmap=cmap)
            fig.colorbar(im, ax=ax.ravel().tolist(), location='bottom')

    #build frames
    frames = [plot(i) for i in range(data.shape[0])]

    #save gif
    gif.save(frames, f'{trainer.logger.log_dir}/{"last" if model else "best"}.gif', duration=50)

    return

'''
Custom Tensorboard logger; does not log hparams.yaml or the epoch metric.
'''
class Logger(TensorBoardLogger):

    def __init__(self,
            **kwargs
        ):
        super().__init__(**kwargs)

    @rank_zero_only
    def log_metrics(self, metrics, step):
        metrics.pop('epoch', None)
        return super().log_metrics(metrics, step)

    @rank_zero_only
    def save(self):
        pass

    @rank_zero_only
    def log_config(self, config):

        filename = os.path.join(self.log_dir, 'config.yaml')
        os.makedirs(os.path.dirname(filename), exist_ok=True)

        with open(filename, "w") as file:
            yaml.dump(config, file)

        return

'''
Package conv parameters.

Input:
    kwargs: keyword arguments
'''
def package_args(stages, kwargs, mirror=False):

    for key, value in kwargs.items():
        if len(value) == 1:
            kwargs[key] = value*(stages)
        elif mirror:
            value.reverse() #inplace

    arg_stack = [{ key : value[i] for key, value in kwargs.items() } for i in range(stages)]

    return arg_stack

'''
Swap input and output points and channels
'''
def swap(conv_params):
    swapped_params = conv_params.copy()

    try:
        temp = swapped_params["in_points"]
        swapped_params["in_points"] = swapped_params["out_points"]
        swapped_params["out_points"] = temp
    except:
        pass

    try:
        temp = swapped_params["in_channels"]
        swapped_params["in_channels"] = swapped_params["out_channels"]
        swapped_params["out_channels"] = temp
    except:
        pass

    return swapped_params

'''
Load in the data and model associated with a given checkpoint
'''

def load_checkpoint(path_to_checkpoint, data_path):

    #### Change the entries here to analyze a new model / dataset
    model_checkpoint_path = Path(path_to_checkpoint)
    data_path = Path(data_path)
    ###################

    model_yml = list(model_checkpoint_path.glob('config.yaml'))

    with model_yml[0].open() as file:
        config = yaml.safe_load(file)

    #extract args
    #trainer_args = config['train']
    model_args = config['model']
    data_args = config['data']
    data_args['data_dir'] = data_path
    #misc_args = config['misc']

    checkpoint = list(model_checkpoint_path.rglob('epoch=*.ckpt'))

    checkpoint_dict = torch.load(checkpoint[0])

    state_dict = checkpoint_dict['state_dict']

    #setup datamodule
    module = import_module('core.' + data_args.pop('module'))
    datamodule = module.DataModule(**data_args)
    datamodule.setup(stage='analyze')
    dataset, points = datamodule.analyze_data()

    #build model
    module = import_module('core.' + model_args.pop('type') + '.model')
    model = module.Model(**model_args, data_info = datamodule.get_data_info())

    del_list = []
    for key in state_dict:
        if 'eval_indices' in key:
            del_list.append(key)

    for key in del_list:
        del state_dict[key]

    model.load_state_dict(state_dict, strict=False)
    model.eval()
    model.to('cpu')

    return model, dataset, points


from graph_from_txt import read_graph

def clustering_coefficient(network, node): # book's from in-text
    """Compute the local clustering coefficient for a node.

    Args:
        network (dict): a graph represented by a dictionary
        node: a node in the network

    Returns:
        (float): the local clustering coefficient of node.
    """
    neighbors = network[node]
    num_neighbors = len(neighbors)
    if num_neighbors <= 1:
        return 0
    num_links = 0
    for index1 in range(len(neighbors) - 1):
        for index2 in range(index1 + 1, len(neighbors)):
            neighbor1 = neighbors[index1]
            neighbor2 = neighbors[index2]
            if neighbor1 != neighbor2 and neighbor1 in network[neighbor2]:
                num_links += 1
    return num_links / (num_neighbors * (num_neighbors - 1) / 2)

def average_clustering_coefficient(network):
    """Returns the average local clustering coefficient for a network."""
    coefficients = 0
    for key in network:
        coefficients += clustering_coefficient(network, key)
    return coefficients / len(network)

network = read_graph('grid.txt')
print(average_clustering_coefficient(network))

network = read_graph('clusters.txt')
print(average_clustering_coefficient(network))


import numpy as np
import mne
import argparse
import pickle
from statsmodels.regression.mixed_linear_model import MixedLM
import pandas as pd
import warnings
from os.path import isdir
warnings.filterwarnings("ignore")

def load_sparse(filename,convert=True,full=False,nump_type="float32"):
    with open(filename,"rb") as f:
        result = pickle.load(f)
    if convert:
        full_mat = np.zeros(result["mat_sparse"].shape[:-1] + \
          (result["mat_res"],result["mat_res"])).astype(nump_type)
        full_mat[...,result["mat_inds"][0],result["mat_inds"][1]] = \
          result["mat_sparse"]
        result = full_mat
    return result

def phi(mat, k=0):
    if len(mat.shape)>2:
        triu_inds = np.triu_indices(mat.shape[1],k=k)
        return mat[...,triu_inds[0],triu_inds[1]]
    else:
        triu_inds = np.triu_indices(mat.shape[0],k=k)
        return mat[triu_inds[0],triu_inds[1]]

'''
this function fits a model for each possible point of observation (e.g. vertex, voxel)
formula is the formula parameter which gets passed on to statsmodels MixedLM,
data is a pandas dataframe which contains the independent variables
uv_data is a 2d numpy array where the first dimension is the number of observations
 and the 2nd is the number of points of observations - the length of the 1st dimension
 must match the number of rows in the data variable
group_id is a 1d numpy array with length number of observations
'''
def mass_uv_mixedlmm(formula, data, uv_data, group_id):
    mods = []
    for d_idx in range(uv_data.shape[1]):
        print("{} of {}".format(d_idx, uv_data.shape[1]),
                                flush=True)
        data_temp = data.copy()
        data_temp["Brain"] = uv_data[:,d_idx]
        model = MixedLM.from_formula(formula, data_temp, groups=group_id)
        try:
            mod_fit = model.fit(reml=False)
        except:
            mods.append(None)
            continue
        mods.append(mod_fit)
    return mods

# get command line parameters
parser = argparse.ArgumentParser()
parser.add_argument('--band', type=str, required=True)
parser.add_argument('--noZ', action="store_true")
opt = parser.parse_args()

subjs = ["ATT_10", "ATT_11", "ATT_12", "ATT_13", "ATT_14", "ATT_15", "ATT_16",
         "ATT_17", "ATT_18", "ATT_19", "ATT_20", "ATT_21", "ATT_22", "ATT_23",
         "ATT_24", "ATT_25", "ATT_26", "ATT_28", "ATT_31", "ATT_33", "ATT_34",
         "ATT_35", "ATT_36", "ATT_37"]

if isdir("/home/jev"):
    root_dir = "/home/jev/ATT_dat/"
elif isdir("/home/jeffhanna/"):
    root_dir = "/scratch/jeffhanna/ATT_dat/"
proc_dir = root_dir+"proc/"

# parameters and setup
proc_dir = root_dir + "proc/"
out_dir = root_dir + "lmm/"
conds = ["rest","audio","visual","visselten","zaehlen"]
z_name = {}
band = opt.band
no_Z = opt.noZ
z_name = ""
if no_Z:
    conds = ["rest","audio","visual","visselten"]
    z_name = "no_Z"

'''
build up the dataframes and group_id which will eventually be passed to
mass_uv_lmm. We will build two models here. "Simple" will make only one contrast:
resting state and task. "Cond" makes distinctions for the different conditions.
'''

data = []
predictor_vars = ("Subj","Block")
dm_simple = pd.DataFrame(columns=predictor_vars)
dm_cond = dm_simple.copy()
group_id = []
for sub_idx,sub in enumerate(subjs):
    for cond_idx,cond in enumerate(conds):
        # we actually only need the dPTE to get the number of trials
        data_temp = load_sparse("{}nc_{}_{}_dPTE_{}.sps".format(proc_dir, sub,
                                                                cond, band))
        for epo_idx in range(data_temp.shape[0]):
            c = cond if cond == "rest" else "task"
            dm_simple = dm_simple.append({"Subj":sub, "Block":c}, ignore_index=True)
            dm_cond = dm_cond.append({"Subj":sub, "Block":cond}, ignore_index=True)
            data.append(phi(data_temp[epo_idx,], k=1)) # flatten upper diagonal of connectivity matrix, add it to the list
            group_id.append(sub_idx)
data = np.array(data)
group_id = np.array(group_id)

'''
Finally, pass the variables along to mass_uv_lmm, for null, simple, and cond.
The function returns a list of fitted LMM; each list member is a model fitted
at a point of observation (e.g. vertex, voxel). Then save each member of the list.
'''

formula = "Brain ~ 1"
mods_null = mass_uv_mixedlmm(formula, dm_simple, data, group_id)
for mod_idx,mod in enumerate(mods_null):
    if mod == None:
        continue
    mod.save("{}{}/null_reg70_lmm_{}{}.pickle".format(out_dir,opt.band,mod_idx,
                                                      z_name))

formula = "Brain ~ C(Block, Treatment('rest'))"
mods_simple = mass_uv_mixedlmm(formula, dm_simple, data, group_id)
for mod_idx,mod in enumerate(mods_simple):
    if mod == None:
        continue
    mod.save("{}{}/simple_reg70_lmm_{}{}.pickle".format(out_dir,opt.band,mod_idx,
                                                        z_name))

formula = "Brain ~ C(Block, Treatment('rest'))"
mods_cond = mass_uv_mixedlmm(formula, dm_cond, data, group_id)
for mod_idx,mod in enumerate(mods_cond):
    if mod == None:
        continue
    mod.save("{}{}/cond_reg70_lmm_{}{}.pickle".format(out_dir,opt.band,mod_idx,
                                                      z_name))


# -*- coding: utf-8 -*-
import unittest
import tempfile
import math
import numpy as np
from numpy import dtype

from pupynere import netcdf_file, nc_generator

VAR_NAME = 'temp'
VAR_TYPE = 'f4'
VAR_VAL = math.pi

n1dim = 4
n2dim = 10
n3dim = 8
ranarr = 100.*np.zeros(shape=(n1dim,n2dim,n3dim))

class TestGeneratorNonrecvars(unittest.TestCase):

    def runTest(self):
        f = netcdf_file(None, 'w')
        temp = f.createVariable(VAR_NAME, dtype(VAR_TYPE))
        temp.assignValue(VAR_VAL)

        # Test filesize property of a virtual file with nonrecvars
        assert f.filesize == 68

        # Test generator
        pipeline = nc_generator(f, iter(np.array([temp.data])))
        with tempfile.NamedTemporaryFile(suffix=".nc") as fn:
            for block in pipeline:
                fn.write(block)

            fn.flush()
            nc = netcdf_file(fn.name, 'r')
            assert VAR_NAME in nc.variables.keys()
            assert nc.variables[VAR_NAME].data == np.float32(VAR_VAL)
            assert nc.variables[VAR_NAME].dtype == dtype('>f4')

            nc.close()

        f.close()

class TestGeneratorRecvars(unittest.TestCase):

    def runTest(self):
        keys = ('n1','n2','n3')
        dims = [None, n2dim, n3dim]

        f = netcdf_file(None, 'w')
        for i in range(len(keys)):
            f.createDimension(keys[i], dims[i])
        foo = f.createVariable('data1', ranarr.dtype, keys)

        # write some data to it.
        foo[:] = ranarr
        foo[n1dim:,:,:] = 2.*ranarr

        with self.assertRaises(ValueError):
            f.filesize

        # Test generator
        pipeline = nc_generator(f, iter(foo.data))
        with tempfile.NamedTemporaryFile(suffix=".nc") as fn:
            for block in pipeline:
                fn.write(block)

            fn.flush()
            nc = netcdf_file(fn.name, 'r')
            assert 'data1' in nc.variables.keys()
            for i, n in enumerate(keys):
                assert n in nc.dimensions.keys()
                assert nc.dimensions[n] == dims[i]
                assert nc.filesize == 5236
            nc.close()

        f.close()


from collections import Counter
from typing import List

class LinkedListNode:
    def __init__(self, val):
        self.next = None
        self.val = val

class BinaryTreeNode:
    def __init__(self, val):
        self.left = None
        self.right = None
        self.val = val
        self.elements = Counter()  # number of people to the left by height
        self.elements_total = 0  # total number of people to the left
        self.person = None

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        def construct_binary_tree(node, left_interval, right_interval):
            left, right = left_interval
            if left < right:
                middle = (left + right) // 2

                node.left = BinaryTreeNode(middle)
                construct_binary_tree(node.left, (left, middle), (middle + 1, right))

            left, right = right_interval
            if left < right:
                middle = (left + right) // 2

                node.right = BinaryTreeNode(middle)
                construct_binary_tree(node.right, (left, middle), (middle + 1, right))

        def tree_insert(node, person, less):
            equal_or_missing = node.elements[person[0]] + (
                node.val - node.elements_total - less
            )
            if equal_or_missing > person[1]:
                node.elements[person[0]] += 1
                node.elements_total += 1
                tree_insert(node.left, person, less)
            elif equal_or_missing < person[1]:
                tree_insert(
                    node.right,
                    person,
                    node.val
                    - equal_or_missing
                    + (1 if node.person and node.person[0] != person[0] else 0),
                )
            else:
                if node.person:
                    tree_insert(node.right, person, node.val - equal_or_missing + 1)
                else:
                    node.person = person

        def inorder_walk(node):
            if node.left:
                yield from inorder_walk(node.left)
            yield node.person
            if node.right:
                yield from inorder_walk(node.right)

        if not people:
            return []

        middle = len(people) // 2
        root = BinaryTreeNode(middle)

        construct_binary_tree(root, (0, middle), (middle + 1, len(people)))

        people.sort()

        for person in people:
            tree_insert(root, person, 0)

        return list(inorder_walk(root))

    def reconstructQueue1(self, people: List[List[int]]) -> List[List[int]]:
        people.sort()

        result = [None] * len(people)

        for person in people:
            equal_or_missing = 0
            for pos in range(len(result)):
                if result[pos] is None and equal_or_missing == person[1]:
                    result[pos] = person
                    break
                if result[pos] is None or result[pos][0] == person[0]:
                    equal_or_missing += 1

        return result

    def reconstructQueue2(self, people: List[List[int]]) -> List[List[int]]:
        people.sort(key=lambda x: x[1])
        linked_list = LinkedListNode(None)

        for person in people:
            count = 0
            node = linked_list

            while node.next is not None:
                if node.next.val[0] >= person[0]:
                    count += 1

                if count <= person[1]:
                    node = node.next
                else:
                    break

            next_node = node.next
            node.next = LinkedListNode(person)
            node.next.next = next_node

        result = []

        node = linked_list.next
        while node:
            result.append(node.val)
            node = node.next

        return result

class TestSolution:
    def setup(self):
        self.sol = Solution()

    def test_empty(self):
        assert self.sol.reconstructQueue([]) == []

    def test_case1(self):
        assert self.sol.reconstructQueue(
            [[7, 0], [4, 4], [7, 1], [5, 0], [6, 1], [5, 2]]
        ) == [[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]]

    def test_case2(self):
        assert self.sol.reconstructQueue(
            [
                [0, 0],
                [6, 2],
                [5, 5],
                [4, 3],
                [5, 2],
                [1, 1],
                [6, 0],
                [6, 3],
                [7, 0],
                [5, 1],
            ]
        ) == [
            [0, 0],
            [6, 0],
            [1, 1],
            [5, 1],
            [5, 2],
            [4, 3],
            [7, 0],
            [6, 2],
            [5, 5],
            [6, 3],
        ]


# -*- coding: utf-8 -*-
"""
Created on Thu Aug 25 13:43:57 2022

@author: ADMIN
"""
import pygame
import colors
import sys
from catalyze_coop_brain import vec2,writetext,drawhunter,hunter

class basemovebar:
    def __init__(self,pos1,pos2,width,mrange,bg = colors.BLACK,color = colors.WHITE):
        assert pos2.y == pos1.y
        assert pos1.x < pos2.x
        self.pos1 = pos1
        self.pos2 = pos2
        self.width = width
        self.mrange = mrange
        self.mousepos = pos1 - vec2(0,0) # Somehow this nonsense is needed to decouple self.pos1 from self.mousepos
        self.color = color
        self.bg = bg
        self.rect = pygame.Rect(pos1.x, pos1.y - (width/2), pos2.x - pos1.x, width)

    def draw(self,screen,font,text):
        radius2 = self.width/2
        place = self.mousepos
        #Draw the rect
        gap1 = 20
        gap2 = 20
        myval = self.getval("int")

        if isinstance(myval,type(1.2)):
            myval = "{:.10f}".format(myval)
        else:
            myval = str(myval)

        mloc = vec2(((self.pos2.x - self.pos1.x)/2.) + self.pos1.x,self.pos1.y - gap2)

        pygame.draw.rect(screen,
                        colors.GRAY,
                        self.rect)
        #Draw circle on top of rect
        pygame.draw.circle(screen, colors.WHITE, [place.x,self.pos1.y], radius2)
        writetext(font, self.mrange[0], screen, (self.pos1 - vec2(gap1,0)).elems(), self.color, self.bg)
        writetext(font, self.mrange[1], screen, (self.pos2 + vec2(gap1,0)).elems(), self.color, self.bg)
        writetext(font,text,screen, mloc.elems(),self.color,self.bg)
        writetext(font,myval,screen,(self.mousepos + vec2(0,gap2 - self.mousepos.y + self.pos2.y)).elems(),self.color,self.bg)

    def update(self,click):
        cur = vec2(*pygame.mouse.get_pos())
        iscollide = self.rect.collidepoint(cur.x, cur.y)
        if click and iscollide:
            #currently_occupied.add(self)
            self.mousepos = cur

    def getval(self,mtype):
        posn = (self.mousepos.x - self.pos1.x)/(self.pos2.x - self.pos1.x)
        fin = posn*(self.mrange[1] - self.mrange[0]) + self.mrange[0]
        if mtype == "int":
            return int(fin)
        elif mtype == "float":
            return fin

class mutnbar(basemovebar):

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)

    def getval(self,throwaway):
        posn = (self.mousepos.x - self.pos1.x)/(self.pos2.x - self.pos1.x)
        if posn <= 0.01:
            return self.mrange[0]
        elif posn >= 0.99:
            return self.mrange[1]
        fin = 10**(posn*10 - 10)
        return fin

class movebar:
    def __init__(self,pos1,pos2,width,mrange,hunter,radius,bg = colors.BLACK,color = colors.WHITE):
        assert pos2.y == pos1.y
        assert pos1.x < pos2.x
        self.pos1 = pos1
        self.pos2 = pos2
        self.hunter = hunter
        self.radiush = radius
        self.width = width
        self.mrange = mrange
        self.mousepos = pos1 - vec2(0,0) # Somehow this nonsense is needed to decouple self.pos1 from self.mousepos
        self.color = color
        self.bg = bg
        self.rect = pygame.Rect(pos1.x, pos1.y - (width/2), pos2.x - pos1.x, width)

    def draw(self,screen,font):
        radius2 = self.width/2
        place = self.mousepos
        #Draw the rect
        gap1 = 10
        gap2 = 10
        pygame.draw.rect(screen,
                        colors.GRAY,
                        self.rect)
        #Draw circle on top of rect
        pygame.draw.circle(screen, colors.WHITE, [place.x,self.pos1.y], radius2)
        writetext(font, self.mrange[0], screen, (self.pos1 - vec2(gap1,0)).elems(), self.color, self.bg)
        writetext(font, self.mrange[1], screen, (self.pos2 + vec2(gap1,0)).elems(), self.color, self.bg)

        mloc = vec2(((self.pos2.x - self.pos1.x)/2.) + self.pos1.x,self.pos1.y - (self.radiush*2.0) - gap2)
        writetext(font, self.hunter, screen, (mloc - vec2(0,(self.radiush*3.) - gap2)).elems(), self.color, self.bg)
        drawhunter(screen, mloc.elems(), self.radiush, self.hunter)

    def update(self,click):
        cur = vec2(*pygame.mouse.get_pos())
        iscollide = self.rect.collidepoint(cur.x, cur.y)
        if click and iscollide:
            #currently_occupied.add(self)
            self.mousepos = cur

    def getval(self):
        posn = (self.mousepos.x - self.pos1.x)/(self.pos2.x - self.pos1.x)
        if posn <= 0.01:
            return self.mrange[0]
        elif posn >= 0.99:
            return self.mrange[1]
        fin = posn*(self.mrange[1] - self.mrange[0]) + self.mrange[0]
        return fin

    def changeposn(self,click,newval):
        #THIS WILL NOT WORK FOR ALL RANGES! ONLY 0-1 RANGES
        cur = vec2(*pygame.mouse.get_pos())
        iscollide = self.rect.collidepoint(cur.x, cur.y)
        if click and iscollide:
            pass
        elif self.mrange[0] != 0 or self.mrange[1] != 1:
            pass
        else:
            #fin = (self.mousepos.x - self.pos1.x)/(self.pos2.x - self.pos1.x)
            self.mousepos.x = newval*(self.pos2.x - self.pos1.x) + self.pos1.x # For 0-1 range only

def create_spaced_bars(screensize,myy,mrange,barwidth,hunters,radius,edge = 40):

    lenary = len(hunters)
    scr_ary = edge,screensize[0] - edge
    gaplen = 100
    #An array of x's containing the starts of each bar is ideal

    #lenary*barlength + (lenary-1)*gaplen = scr_ary[1] - scr_ary[0]
    barlength = ((scr_ary[1] - scr_ary[0]) - ((lenary - 1)*gaplen))/lenary
    pos1s = [((barlength + gaplen)*j) + edge for j in range(lenary)]
    pos2s = [item + barlength for item in pos1s]
    ys = [myy]*lenary

    pos1s = [vec2(item,y) for item,y in zip(pos1s,ys)]
    pos2s = [vec2(item,y) for item,y in zip(pos2s,ys)]
    final = []
    for pos1,pos2,mhunter in zip(pos1s,pos2s,hunters):
        mbar = movebar(pos1, pos2, barwidth, [0,1], mhunter, radius)
        final.append(mbar)

    return final

def process_values(barvals):
    if sum(barvals) <= 0:
        return [1/len(barvals)]*len(barvals)
    elif sum(barvals) == 1:
        return barvals
    elif sum(barvals) < 1:
        #again, normalize the non-zero values
        missing = 1 - sum(barvals)
        proportions = [item/sum(barvals) for item in barvals]
        toadd = [missing*proportion for proportion in proportions]
        final = [item + plus for item,plus in zip(barvals,toadd)]
        return final
    elif sum(barvals) > 1:
        #we need to normalize the non-zero values
        excess = sum(barvals) - 1
        proportions = [item/sum(barvals) for item in barvals]
        toremove = [excess*proportion for proportion in proportions]
        final = [item - torm for item,torm in zip(barvals,toremove)]
        return final

if __name__ == "__main__":
    pygame.init()
    myfont = font = pygame.font.Font('freesansbold.ttf', 10)
    clock = pygame.time.Clock()
    screensize = pygame.display.Info().current_w,pygame.display.Info().current_h
    mysurfacesize = width, height =screensize[0] - 100,screensize[1] - 200
    screen = pygame.display.set_mode(mysurfacesize)
    strategies = [
    ("H","H",1),
    ("H","H",2),
    ("H","S",1),
    ("H","S",2),
    ("S","H",1),
    ("S","H",2),
    ("S","S",1),
    ("S","S",2)
    ]

    hunters = [hunter(*item) for item in strategies]

    allbars = create_spaced_bars(mysurfacesize, height/2 - 150 , [0,1], 20, hunters[:4], 10)
    allbars += create_spaced_bars(mysurfacesize, height/2 + 150 , [0,1], 20, hunters[4:], 10)
    print(height)
    totalbar = basemovebar(vec2((width/2) - 100,height - 100), vec2((width/2) + 100,height - 100), 20, [100,1000])
    mutn = mutnbar(vec2((width/2) - 100,100), vec2((width/2) + 100,100), 20, [0,1])
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            else:
                pass

        click = pygame.mouse.get_pressed()[0]
        change = process_values([item.getval() for item in allbars])

        i = 0

        totalbar.update(click)
        mutn.update(click)
        for bar in allbars:
            bar.update(click)
            bar.changeposn(click, change[i])
            i += 1

        screen.fill(colors.BLACK)

        totalbar.draw(screen, myfont, "TOTAL")
        mutn.draw(screen, myfont, "MUTATION PROBABILITY")
        for bar in allbars:
            bar.draw(screen,myfont)

        pygame.display.flip()


import re

from cgm.lib.zoo.zooPy.misc import removeDupes
from cgm.lib.zoo.zooPy.names import camelCaseToNice

from triggered import Trigger
from control import getNiceName
from apiExtensions import asMObject, cleanShortName
from maya.cmds import *

import maya.cmds as cmd

import apiExtensions
import triggered
import rigUtils
import control

attrState = control.attrState
AXES = rigUtils.Axis.BASE_AXES

class ChangeSpaceCmd(unicode):
	'''
	contains a bunch of higher level tools to querying the space changing command string
	'''

	_THE_LINES = 'zooFlags;', 'zooUtils;', 'zooChangeSpace \"-attr parent %d\" %%%d;'

	@classmethod
	def Create( cls, parentIdx, parentConnectIdx ):
		return cls( '\n'.join( cls._THE_LINES ) % (parentIdx, parentConnectIdx) )
	@classmethod
	def IsChangeSpaceCmd( cls, theStr ):
		return '\nzooChangeSpace "' in theStr

	def getInterestingLine( self ):
		for line in self.split( '\n' ):
			if line.startswith( 'zooChangeSpace ' ):
				return line
	def getIndex( self ):
		interestingLine = self.getInterestingLine()
		indexStr = interestingLine.split( ' ' )[ -2 ].replace( '"', '' )

		return int( indexStr )
	def setIndex( self, index ):
		lines = self.split( '\n' )
		for n, line in enumerate( lines ):
			if line.startswith( 'zooChangeSpace ' ):
				toks = line.split( ' ' )
				toks[ -2 ] = '%d"' % index

				lines[ n ] = ' '.join( toks )

		return ChangeSpaceCmd( '\n'.join( lines ) )
	def getConnectToken( self ):
		interestingLine = self.getInterestingLine()
		lastToken = interestingLine.split( ' ' )[ -1 ].replace( ';', '' )

		return lastToken

def build( src, tgts, names=None, space=None, **kw ):
	'''
	'''
	if names is None:
		names = [ None for t in tgts ]

	conditions = []
	for tgt, name in zip( tgts, names ):
		cond = add( src, tgt, name, space, **kw )
		conditions.append( cond )

	return conditions

CONSTRAINT_TYPES = CONSTRAINT_PARENT, CONSTRAINT_POINT, CONSTRAINT_ORIENT = 'parentConstraint', 'pointConstraint', 'orientConstraint'
CONSTRAINT_CHANNELS = { CONSTRAINT_PARENT: (['t', 'r'], ['ct', 'cr']),
                        CONSTRAINT_POINT: (['t'], ['ct']),
                        CONSTRAINT_ORIENT: (['r'], ['cr']) }

NO_TRANSLATION = { 'skipTranslationAxes': ('x', 'y', 'z') }
NO_ROTATION = { 'skipRotationAxes': ('x', 'y', 'z') }

def add( src, tgt,
         name=None,
         space=None,
         maintainOffset=True,
         nodeWithParentAttr=None,
         skipTranslationAxes=(),
         skipRotationAxes=(),
         constraintType=CONSTRAINT_PARENT ):

	global AXES
	AXES = list( AXES )

	if space is None:
		space = listRelatives( src, p=True, pa=True )[ 0 ]

	if nodeWithParentAttr is None:
		nodeWithParentAttr = src

	if not name:
		name = getNiceName( tgt )
		if name is None:
			name = camelCaseToNice( str( tgt ) )

	#if there is an existing constraint, check to see if the target already exists in its target list - if it does, return the condition used it uses
	attrState( space, ('t', 'r'), lock=False )
	existingConstraint = findConstraint( src )
	if existingConstraint:
		constraintType = nodeType( existingConstraint )
		constraintFunc = getattr( cmd, constraintType )
		targetsOnConstraint = constraintFunc( existingConstraint, q=True, tl=True )
		if tgt in targetsOnConstraint:
			idx = targetsOnConstraint.index( tgt )
			aliases = constraintFunc( existingConstraint, q=True, weightAliasList=True )
			cons = listConnections( '%s.%s' % (existingConstraint, aliases[ idx ]), type='condition', d=False )

			return cons[ 0 ]

	#when skip axes are specified maya doesn't handle things properly - so make sure
	#ALL transform channels are connected, and remove unwanted channels at the end...
	preT, preR = getAttr( '%s.t' % space )[0], getAttr( '%s.r' % space )[0]
	if existingConstraint:
		chans = CONSTRAINT_CHANNELS[ constraintType ]
		for channel, constraintAttr in zip( *chans ):
			for axis in AXES:
				spaceAttr = '%s.%s%s' %( space, channel, axis)
				conAttr = '%s.%s%s' % (existingConstraint, constraintAttr, axis)
				if not isConnected( conAttr, spaceAttr ):
					connectAttr( conAttr, spaceAttr )

	#get the names for the parents from the parent enum attribute
	cmdOptionKw = { 'mo': True } if maintainOffset else {}
	if objExists( '%s.parent' % nodeWithParentAttr ):
		srcs, names = getSpaceTargetsNames( src )
		addAttr( '%s.parent' % nodeWithParentAttr, e=True, enumName=':'.join( names + [name] ) )

		#if we're building a pointConstraint instead of a parent constraint AND we already
		#have spaces on the object, we need to turn the -mo flag off regardless of what the
		#user set it to, as the pointConstraint maintain offset has different behaviour to
		#the parent constraint
		if constraintType in ( CONSTRAINT_POINT, CONSTRAINT_ORIENT ):
			cmdOptionKw = {}
	else:
		addAttr( nodeWithParentAttr, ln='parent', at="enum", en=name )
		setAttr( '%s.parent' % nodeWithParentAttr, keyable=True )

	#now build the constraint
	constraintFunction = getattr( cmd, constraintType )
	constraint = constraintFunction( tgt, space, **cmdOptionKw )[ 0 ]

	weightAliasList = constraintFunction( constraint, q=True, weightAliasList=True )
	targetCount = len( weightAliasList )
	constraintAttr = weightAliasList[ -1 ]
	condition = shadingNode( 'condition', asUtility=True )
	condition = rename( condition, '%s_to_space_%s#' % (cleanShortName( src ), cleanShortName( tgt )) )

	setAttr( '%s.secondTerm' % condition, targetCount-1 )
	setAttr( '%s.colorIfTrue' % condition, 1, 1, 1 )
	setAttr( '%s.colorIfFalse' % condition, 0, 0, 0 )
	connectAttr( '%s.parent' % nodeWithParentAttr, '%s.firstTerm' % condition )
	connectAttr( '%s.outColorR' % condition, '%s.%s' % (constraint, constraintAttr) )

	#find out what symbol to use to find the parent attribute
	parentAttrIdx = 0
	if not apiExtensions.cmpNodes( space, src ):
		srcTrigger = triggered.Trigger( src )
		parentAttrIdx = srcTrigger.connect( nodeWithParentAttr )

	#add the zooObjMenu commands to the object for easy space switching
	Trigger.CreateMenu( src,
	                    "parent to %s" % name,
	                    ChangeSpaceCmd.Create( targetCount-1, parentAttrIdx ) )

	#when skip axes are specified maya doesn't handle things properly - so make sure
	#ALL transform channels are connected, and remove unwanted channels at the end...
	for axis, value in zip( AXES, preT ):
		if axis in skipTranslationAxes:
			attr = '%s.t%s' % (space, axis)
			delete( attr, icn=True )
			setAttr( attr, value )

	for axis, value in zip( AXES, preR ):
		if axis in skipRotationAxes:
			attr = '%s.r%s' % (space, axis)
			delete( attr, icn=True )
			setAttr( attr, value )

	#make the space node non-keyable and lock visibility
	attrState( space, [ 't', 'r', 's' ], lock=True )
	attrState( space, 'v', *control.HIDE )

	return condition

def removeSpace( src, tgt ):
	'''
	removes a target (or space) from a "space switching" object
	'''

	tgts, names = getSpaceTargetsNames( src )
	tgt_mobject = asMObject( tgt )

	name = None
	for index, (aTgt, aName) in enumerate( zip( tgts, names ) ):
		aTgt = asMObject( aTgt )
		if aTgt == tgt_mobject:
			name = aName
			break

	if name is None:
		raise AttributeError( "no such target" )

	delete = False
	if len( tgts ) == 1:
		delete = True

	constraint = findConstraint( src )

	parentAttrOn = findSpaceAttrNode( src )
	space = findSpace( src )

	srcTrigger = Trigger( src )
	cmds = srcTrigger.iterMenus()

	if delete:
		delete( constraint )
		deleteAttr( '%s.parent' % src )
	else:
		constraintType = nodeType( constraint )
		constraintFunc = getattr( cmd, constraintType )
		constraintFunc( tgt, constraint, rm=True )

	for slot, cmdName, cmdStr in srcTrigger.iterMenus():
		if cmdName == ( "parent to %s" % name ):
			srcTrigger.removeMenu( slot )

		#rebuild the parent attribute
		newNames = names[:]
		newNames.pop( index )
		addAttr( '%s.parent' % parentAttrOn, e=True, enumName=':'.join( newNames ) )

	#now we need to update the indicies in the right click command - all targets that were beyond the one we
	#just removed need to have their indices decremented
	for slot, cmdName, cmdStr in srcTrigger.iterMenus():
		if not cmdName.startswith( 'parent to ' ):
			continue

		cmdStrObj = ChangeSpaceCmd( cmdStr )
		cmdIndex = cmdStrObj.getIndex()
		if cmdIndex < index:
			continue

		cmdStrObj = cmdStrObj.setIndex( cmdIndex-1 )
		srcTrigger.setMenuCmd( slot, cmdStrObj )

def getSpaceName( src, theTgt ):
	'''
	will return the user specified name given to a particular target object
	'''
	tgts, names = getSpaceTargetsNames( src )
	for tgt, name in zip( tgts, names ):
		if tgt == theTgt:
			return name

def getSpaceTargetsNames( src ):
	'''
	this procedure returns a 2-tuple: a list of all targets, and a list of user
	specified names - for the right click menus
	'''
	constraint = findConstraint( src )
	if constraint is None:
		return [], []

	space = findSpace( src, constraint )
	if space is None:
		return [], []

	constraintType = nodeType( constraint )
	constraintFunc = getattr( cmd, constraintType )

	targetsOnConstraint = constraintFunc( constraint, q=True, tl=True )
	trigger = Trigger( src )

	SPECIAL_STRING = 'parent to '
	LEN_SPECIAL_STRING = len( SPECIAL_STRING )

	tgts, names = [], []
	for slotIdx, slotName, slotCmd in trigger.iterMenus():
		if slotName.startswith( SPECIAL_STRING ):
			names.append( slotName[ LEN_SPECIAL_STRING: ] )

			cmdStrObj = ChangeSpaceCmd( slotCmd )
			cmdIndex = cmdStrObj.getIndex()
			tgts.append( targetsOnConstraint[ cmdIndex ] )

	return tgts, names

def findSpace( obj, constraint=None ):
	'''
	will return the node being used as the "space node" for any given space switching object
	'''
	if constraint is None:
		constraint = findConstraint( obj )
		if constraint is None:
			return None

	cAttr = '%s.constraintParentInverseMatrix' % constraint
	spaces = listConnections( cAttr, type='transform', d=False )
	if spaces:
		future = ls( listHistory( cAttr, f=True ), type='transform' )
		if future:
			return future[ -1 ]

def findConstraint( obj ):
	'''
	will return the name of the constraint node thats controlling the "space node" for any given
	space switching object
	'''
	parentAttrOn = findSpaceAttrNode( obj )
	if parentAttrOn is None:
		return None

	pAttr = '%s.parent' % parentAttrOn
	if not objExists( pAttr ):
		return None

	conditions = listConnections( pAttr, type='condition', s=False ) or []
	for condition in conditions:
		constraints = listConnections( '%s.outColorR' % condition, type='constraint', s=False )
		if constraints:
			return constraints[ 0 ]

	return None

def findSpaceAttrNode( obj ):
	'''
	returns the node that contains the parent attribute for the space switch
	'''
	parentAttrOn = "";
	trigger = Trigger( obj )

	for slotIdx, slotName, slotCmd in trigger.iterMenus():
		if slotName.startswith( 'parent to ' ):
			cmdStrObj = ChangeSpaceCmd( slotCmd )
			connectToken = cmdStrObj.getConnectToken()

			return trigger.resolve( connectToken )

#end


from ctg_benchmark.utils.utils import get_basic_loader_config
from ctg_benchmark.utils.io import load_yaml
from plantcelltype.graphnn.trainer import train

template_config_paths = ('./lengths_all_directions/gcn.yaml',
                         './lengths_all_directions/deeper_gcn.yaml',
                         )

perturbation = {'name': 'proj_length_unit_sphere',
                'pre_transform': [{'name': 'Zscore'},
                                  {'name': 'ToTorchTensor'}]}
name = '_All_Lengths'
for template_config_path in template_config_paths:
    template_config = load_yaml(template_config_path)
    train(config=template_config)  # perturbed training

    dataset_config = get_basic_loader_config('dataset')
    dataset_config['node_features'].append(perturbation)
    for dataset in ['train_dataset', 'test_dataset', 'val_dataset']:
        if dataset in template_config['loader']:
            template_config['loader'][dataset]['raw_transform_config'] = dataset_config

    template_config['logs']['name'] += name
    train(config=template_config)  # perturbed training


import numpy as np
import heapq
import pickle

def change_in_margin_for_node_set_constructive(G, C, node_list, votes, nodes, optimal_candidate):
    changes_in_margin = []
    for candidate in range(0, C):
        g = 0
        #if candidate != optimal_candidate:
        for n in nodes:
            if G.nodes[node_list[n]]["voting_preference"][0] == candidate and G.nodes[node_list[n]]["voting_preference"][1] == optimal_candidate:
                g += 2
            elif G.nodes[node_list[n]]["voting_preference"][1] == optimal_candidate:
                g += 1
        changes_in_margin.append(g + np.max(votes) - votes[candidate])
    return min(changes_in_margin)

def change_in_margin_for_node_set_destructive(G, C, node_list, votes, nodes, optimal_candidate):
    changes_in_margin = []
    for candidate in range(0, C):
        g = 0
        for n in nodes:
            if G.nodes[node_list[n]]["voting_preference"][1] == candidate and \
                    G.nodes[node_list[n]]["voting_preference"][0] == optimal_candidate:
                g += 2
            elif G.nodes[node_list[n]]["voting_preference"][0] == optimal_candidate:
                g += 1
        changes_in_margin.append(g + votes[candidate])
    return max(changes_in_margin) - np.max(votes)

def compute_influence_for_node_set(G, C, node_list, votes, nodes, samples, is_constructive, optimal_candidate):
    vals = []
    for s in samples:
        reachable_nodes = []
        for node in nodes:
            reachable_nodes = np.union1d(reachable_nodes, s[node]["influenced_descendants"]).astype(int)
        val = change_in_margin_for_node_set_constructive(G, C, node_list, votes, reachable_nodes, optimal_candidate) if is_constructive else change_in_margin_for_node_set_destructive(G, C, node_list, votes, reachable_nodes, optimal_candidate)
        vals.append(val)
        # vals.append(len(reachable_nodes))
    return np.mean(vals)

def compute_influence_for_node(G, C, node_list, votes, node, samples, is_constructive, optimal_candidate):
    vals = []
    for s in samples:
        #vals.append(len(s[node]["influenced_descendants"]))
        val = change_in_margin_for_node_set_constructive(G, C, node_list, votes, s[node]["influenced_descendants"], optimal_candidate) if is_constructive else change_in_margin_for_node_set_destructive(G, C, node_list, votes, s[node]["influenced_descendants"], optimal_candidate)
        vals.append(val)
    return np.mean(vals)

def greedy_once(G, C, node_list, votes, nodes, samples, is_constructive, optimal_candidate):
    heap = []
    influences = []
    for n in nodes:
        influence = compute_influence_for_node(G, C, node_list, votes, n, samples, is_constructive, optimal_candidate)
        influences.append(influence)
        heapq.heappush(heap, (-influence, n))

    return heap, influences

def lazy_greedy(network, num_mc_samples, C, is_constructive, num_seed_nodes, instance, optimal_candidate):
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/compressed_mc_samples_' + str(C) + '_' + str(instance) +'.pkl', 'rb') as f:
        samples = pickle.load(f)
    samples = samples[0:num_mc_samples]

    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/graph_' + str(C) + '_' + str(instance) +'.pkl', 'rb') as f:
        G = pickle.load(f)

    votes = []
    for candidate in range(0, C):
        votes.append(len([node for node in G.nodes if G.nodes[node]["voting_preference"][0] == candidate]))
    node_list = list(G.nodes)
    marginal_influences = []
    print("RUNNING LAZY GREEDY")
    heap, influences = greedy_once(G, C, node_list, votes, list(np.arange(0, len(G.nodes))), samples, is_constructive, optimal_candidate)
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/influences_' + str(C) + '_' + str(instance) + '.pkl', 'wb') as f:
        pickle.dump(influences, f)
    influence, node = heapq.heappop(heap)
    prev_influence = -influence
    marginal_influences.append(prev_influence)
    seed_nodes = {node}
    seed_nodes_list = [node]
    while len(seed_nodes) < num_seed_nodes:
        print(seed_nodes)
        max_found = False
        while not max_found:
            influence, node = heapq.heappop(heap)
            influence = compute_influence_for_node_set(G, C, node_list, votes, (seed_nodes | {node}), samples, is_constructive, optimal_candidate)
            marginal_influence = influence - prev_influence
            heapq.heappush(heap, (-marginal_influence, node))
            max_found = heap[0][1] == node
        marginal_influence, node = heapq.heappop(heap)
        marginal_influences.append(-marginal_influence)
        prev_influence = prev_influence + (-marginal_influence)
        seed_nodes.add(node)
        seed_nodes_list.append(node)
    print(seed_nodes_list)
    print(prev_influence)
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/seed_nodes_' + str(C) + '_' + str(instance) + '.pkl', 'wb') as f:
        pickle.dump(seed_nodes_list, f)
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/marginal_influences_' + str(C) + '_' + str(instance) + '.pkl', 'wb') as f:
        pickle.dump(marginal_influences, f)
    return prev_influence

def analysis(network, num_mc_samples, C, is_constructive, num_seed_nodes, instance, optimal_candidate):
    seed_nodes = []
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/seed_nodes_' + str(C) + '_' + str(instance) +'.pkl', 'rb') as f:
        seed_nodes = pickle.load(f)
    influences = []
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/influences_' + str(C) + '_' + str(instance) + '.pkl', 'rb') as f:
        influences = pickle.load(f)
    with open('544tFinalProjectData/' + network + '/' + ('constructive' if is_constructive else 'destructive') + '/C_' + str(C) + '/marginal_influences_' + str(C) + '_' + str(instance) + '.pkl', 'rb') as f:
        marginal_influences = pickle.load(f)
    avg_influence = sum(influences) / len(influences)
    print(marginal_influences)
    seed_node_influences = []
    print(seed_nodes)
    for s in seed_nodes:
        seed_node_influences.append(influences[s])
    return seed_node_influences, avg_influence

'''
SET PARAMETERS
'''
#k = 25
#C = 10
#optimal_candidate = 0

'''
LOAD GRAPH
'''
# with open('polblogs_graph_trimmed_' + str(C) + '.pkl', 'rb') as f:
#    G = pickle.load(f)
# with open('./544tFinalProjectData/netscience/constructive/C_' + str(C) + '/netscience_graph_' + str(C) + '.pkl', 'rb') as f:
#    G = pickle.load(f)
# votes = []
# for candidate in range(0, C):
#     votes.append(len([node for node in G.nodes if G.nodes[node]["voting_preference"][0] == candidate]))
# node_list = list(G.nodes)
# '''
# LOAD MC SAMPLES
# '''
# # with open('compressed_mc_samples_trimmed_' + str(C) + '.pkl', 'rb') as f:
# #    samples = pickle.load(f)
# with open('./544tFinalProjectData/netscience/constructive/C_' + str(C) + '/compressed_mc_samples_' + str(C) + '.pkl', 'rb') as f:
#    samples = pickle.load(f)
#
# #samples = samples[0:100]
#
# '''
# GREEDY
# Run greedy algorithm
# '''
# lazy_greedy(k)


#!/usr/bin/env python
# This example script was ported from Perl Spreadsheet::WriteExcel module.
# The author of the Spreadsheet::WriteExcel module is John McNamara
# <jmcnamara@cpan.org>

__revision__ = """$Id: images.py,v 1.9 2004/01/31 18:56:07 fufff Exp $"""

#######################################################################
#
# Example of how to insert images into an Excel worksheet using the
# Spreadsheet::WriteExcel insert_bitmap() method.
#
# reverse('(c)'), October 2001, John McNamara, jmcnamara@cpan.org
#

import pyXLWriter as xl

# Create a new workbook called simple.xls and add a worksheet
workbook   = xl.Writer("images.xls")
worksheet1 = workbook.add_worksheet('Image 1')
worksheet2 = workbook.add_worksheet('Image 2')
worksheet3 = workbook.add_worksheet('Image 3')
worksheet4 = workbook.add_worksheet('Image 4')

# Insert a basic image
worksheet1.write('A10', "Image inserted into worksheet.")
worksheet1.insert_bitmap('A1', 'republic.bmp')

# Insert an image with an offset
worksheet2.write('A10', "Image inserted with an offset.")
worksheet2.insert_bitmap('A1', 'republic.bmp', 32, 10)

# Insert a scaled image
worksheet3.write('A10', "Image scaled: width x 2, height x 0.8.")
worksheet3.insert_bitmap('A1', 'republic.bmp', 0, 0, 2, 0.8)

# Insert an image over varied column and row sizes
# This does not require any additional work

# Set the cols and row sizes
# NOTE: you must do this before you call insert_bitmap()
worksheet4.set_column('A:A', 5)
worksheet4.set_column('B:B', hidden=True)
worksheet4.set_column('C:D', 10)
worksheet4.set_row(0, 30)
worksheet4.set_row(3, 5)

worksheet4.write('A10', "Image inserted over scaled rows and columns.")
worksheet4.insert_bitmap('A1', 'republic.bmp')

workbook.close()


"""
Lambdas are one line functions.
They are also known as anonymous functions in some other languages.
You might want to use lambdas when you don’t want to use a function twice in a program.
They are just like normal functions and even behave like them.
"""

# lambda argument: manipulate(argument)

add = lambda x, y: x + y

print(add(3, 5))

# list sorting
a = [(1, 2, 3), (4, 1, 4), (9, 10, 5), (13, -3, 6)]
a.sort(key=lambda x: x[2])  # sorts by 3rd key in tuple
# key= Optional. A function to specify the sorting criteria(s)

'''
# A function that returns the length of the value:
def myFunc(e):
  return len(e)
cars = ['Ford', 'Mitsubishi', 'BMW', 'VW']
cars.sort(key=myFunc)
'''

print(a)

asd = lambda x: x[2]
print(asd(a))

#Parallel sorting of lists
list1 = [(5, 2, 3), (1, 2, 4), (9, 2, 5), (13, -3, 6)]
list2 = [(5, 2, 3), (4, 1, 4), (9, 10, 5), (13, -3, 6)]

data = zip(list1, list2)
list1, list2 = map(lambda t: list(t), zip(*data))
print(list1)
print(list2)


import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt

# veri kumesini oku
kolon_adlari = ['duration','protocol_type','service','flag','src_bytes','dst_bytes','land','wrong_fragment','urgent',
'hot','num_failed_logins','logged_in','num_compromised','root_shell','su_attempted','num_root','num_file_creations',
'num_shells','num_access_files','num_outbound_cmds','is_host_login','is_guest_login','count','srv_count',
'serror_rate','srv_serror_rate','rerror_rate','srv_rerror_rate','same_srv_rate','diff_srv_rate','srv_diff_host_rate',
'dst_host_count','dst_host_srv_count','dst_host_same_srv_rate','dst_host_diff_srv_rate','dst_host_same_src_port_rate',
'dst_host_srv_diff_host_rate','dst_host_serror_rate','dst_host_srv_serror_rate','dst_host_rerror_rate',
'dst_host_srv_rerror_rate','label']

verikumesi = pd.read_csv("kddcup99.tar.gz",compression="gzip", names=kolon_adlari,
low_memory=False, skiprows=1)

secilecek_kolonlar = ['serror_rate','srv_serror_rate',
'rerror_rate','srv_rerror_rate','same_srv_rate','diff_srv_rate','srv_diff_host_rate','dst_host_count',
'dst_host_srv_count','dst_host_same_srv_rate','dst_host_diff_srv_rate','dst_host_same_src_port_rate',
'dst_host_srv_diff_host_rate','dst_host_serror_rate','dst_host_srv_serror_rate','dst_host_rerror_rate',
'dst_host_srv_rerror_rate']

X = verikumesi[secilecek_kolonlar].as_matrix()
y = verikumesi['label'].apply(lambda d:0 if d == 'normal.' else 1).as_matrix()

# lambda degerleri
lambdas=[x  for x in range(1, 1000, 50)]

# agirliklar icin zero matris tanimla
coefs_ridge = np.zeros((len(lambdas),X.shape[1]))
print(coefs_ridge.shape)

i = 0
for l in lambdas:
   print(datetime.now(),i)
   clf = LogisticRegression(verbose=0, C=1/l)
   clf.fit(X,y)
   coefs_ridge[i,:] = clf.coef_
   i += 1
plt.figure(1)
ax = plt.gca()

for i in range(X.shape[1]):
    coef_l = coefs_ridge[:,i]
    print('*'*100)
    print(coef_l.shape)
    l1 = plt.plot(lambdas, coef_l, label= secilecek_kolonlar[i])
plt.legend()
plt.show()

'''
plt.figure(1)
ax = plt.gca()

colors = cycle(['b', 'r', 'g', 'c', 'k'])
neg_log_alphas_lasso = -np.log10(alphas_lasso)
for coef_l, c in zip(coefs_lasso, colors):
    l1 = plt.plot(alphas_lasso, coef_l, c=c)

plt.axis('tight')
plt.show()
'''


import scipy.integrate as spi
import numpy as np
import pylab as pl

beta=1.4247
gamma=0.14286
p=0.1
l=0.1
b=0.1
e=0.1
I0=0.01
ND=48
TS=1.0
INPUT = (1.0-I0, I0,0,0)

def diff_eqs(INP,t):
	'''The main set of equations'''
	Y=np.zeros((4))
	S=INP[0]
	E=INP[1]
	I=INP[2]
	Z=INP[2]
	N=S+I+E+Z
	Y[0] = - beta * S * I/N -b * S * Z/N
	Y[1] = (1-p)*beta * S * I/N +(1-l)*b * S * Z/N-p*E*I/N-e*E
	Y[2] = - p*beta * S * I/N +p * E * I/N+e*E
	Y[3] = l*b** S * Z/N
	return Y   # For odeint

# t_start = 0.0; t_end = ND; t_inc = TS
# t_range = np.arange(t_start, t_end+t_inc, t_inc)
# RES = spi.odeint(diff_eqs,INPUT,t_range)
#
# print (RES)

#Ploting
# pl.subplot(211)
# pl.plot(RES[:,0], '-g', label='Susceptibles')
# pl.title('Program_2_5.py')
# pl.xlabel('Time')
# pl.ylabel('Susceptibles')
# pl.subplot(212)
# pl.plot(RES[:,2], '-r', label='Infectious')
# pl.xlabel('Time')
# pl.ylabel('Infectious')
# pl.show()
print()


from itertools import product, permutations

k = 0
coll = permutations('мстилав', r=5)
for i in coll:
    s = ''.join(i)
    s2 = ''
    for w in s:
        if w in 'мстлв':
            s2 += 's'
        else:
            s2 += 'g'
    if s2.count('s') > s2.count('g') and 'gg' not in s2:
        k += 1

print(k)


import numpy as np

class IEEE754:
    def __init__(self, x, precision=2):
        self.precision = precision
        length_list = [16, 32, 64, 128, 256]
        exponent_list = [5, 8, 11, 15, 19]
        mantissa_list = [10, 23, 52, 112, 236]
        bias_list = [15, 127, 1023, 16383, 262143]
        self.length = length_list[precision]
        self.exponent = exponent_list[precision]
        self.mantissa = mantissa_list[precision]
        self.bias = bias_list[precision]
        self.s = 0 if x >= 0 else 1
        x = abs(x)
        self.x = x
        self.i = self.integer2binary(int(x))
        self.d = self.decimal2binary(x-int(x))
        self.e = self.integer2binary((self.i.size-1)+self.bias)
        self.m = np.append(self.i[1::], self.d)
        self.h = ''

    def __str__(self):
        r = np.zeros(self.length, dtype=int)
        i_d = np.append(self.i[1::], self.d)
        r[0] = self.s
        r[1+(self.exponent - self.e.size):(self.exponent + 1):] = self.e
        r[(1 + self.exponent):(1 + self.exponent + i_d.size):] = i_d[0:self.mantissa]
        s = np.array2string(r, separator='')
        return s[1:-1].replace("\n", "").replace(" ", "")

    @staticmethod
    def integer2binary(x):
        b = np.empty((0,), dtype=int)
        while x > 1:
            b = np.append(b, np.array([x % 2]))
            x = int(x/2)
        b = np.append(b, np.array([x]))
        b = b[::-1]
        return b

    def decimal2binary(self, x):
        b = np.empty((0,), dtype=int)
        i = 0
        while x > 0 and i < self.mantissa:
            x = x * 2
            b = np.append(b, np.array([int(x)]))
            x -= int(x)
            i += 1
        return b

    def str2hex(self):
        s = str(self)
        for i in range(0, len(s), 4):
            ss = s[i:i+4]
            si = 0
            for j in range(4):
                si += int(ss[j]) * (2**(3-j))
            sh = hex(si)
            self.h += sh[2]
        return self.h

if __name__ == "__main__":
    for p in range(5):
        a = IEEE754(13.375, p)
        print("x = %f | b = %s | h = %s" % (13.375, a, a.str2hex()))


class circularqueue(object):

    def __init__(self,capacity):
        self.capacity = capacity
        self.queue = [None] * capacity
        self.front = 0
        self.end = -1

    def add(self, value):
        #resize and straigten queue
        if self.size() == self.capacity:
            temp = [None] * 2 * self.capacity
            i = 0
            j = self.front
            while i < self.capacity:
                temp[i] = self.queue[j]
                j = (j + 1) % self.capacity
                i += 1
            self.queue = temp
            self.front = 0
            self.end = self.capacity - 1
            self.capacity *= 2
        self.end = (self.end + 1) % self.capacity
        self.queue[self.end] = value

    def remove(self):
        if self.isEmpty():
            return None
        removedElement = self.queue[self.front]
        self.queue[self.front] = None
        self.front = (self.front + 1) % self.capacity
        if self.isEmpty():
            self.front = 0
            self.end = -1
        return removedElement

    def peak(self):
        if self.isEmpty():
            return None
        return self.queue[self.front]

    def isEmpty(self):
        return self.size() == 0

    def size(self):
        if self.end == -1:
            return 0
        if self.end > self.front:
            return self.end - self.front + 1
        else:
            return self.end - self.front + self.capacity + 1

    def print(self):
        i = self.front
        count = 0
        size = self.size()
        while count < size:
            print(self.queue[i], end = " ")
            i = (i + 1) % self.capacity
            count += 1

queue = circularqueue(5)
queue.add(5)
queue.add(4)
queue.add(3)
queue.add(2)
queue.add(3)
queue.remove()
queue.add(1)
queue.add(6)
queue.print()


def test_generator(x):
    while x < 100:
        yield x
        x += 10
    yield x

def cut_down(x):
    while x >= 1:
        yield x
        x -= 1

def cut_down2(x):
    if x > 0:
        yield x
        yield from yield_2()

def yield_2():
    yield 'first'
    yield 'second'

# t = test_generator(3)
#
# print(list(cut_down(9)))
# print(list(cut_down2(7)))
# print(yield_2())

class LettersIter:
    def __init__(self, start='a', end='e'):
        self.next_letter = start
        self.end = end

    def __next__(self):
        if self.next_letter == self.end:
            raise StopIteration
        letter = self.next_letter
        self.next_letter = chr(ord(letter) + 1)
        return letter

    def __iter__(self):
        start = self.next_letter
        while start < self.end:
            yield start
            start = chr(ord(start) + 1)

class Letters:
    def __init__(self, start='a', end='b'):
        self.start = start
        self.end = end

    def __iter__(self):
        return LettersIter(self.start, self.end)

letter_iter = Letters('d', 'r')
first_iterator = iter(letter_iter)
t1 = iter(first_iterator)
t2 = iter(first_iterator)
print(iter(first_iterator) == iter(first_iterator))  # False
print(t1)  # <generator object LettersIter.__iter__ at 0x00000238211D9938>
print(t2)  # <generator object LettersIter.__iter__ at 0x00000238211D9938>
print(next(first_iterator))  # d
print(next(iter(first_iterator)))  # e

# y2 = yield_2()
# y2_it = iter(y2)
# print(y2 == y2_it)
# print(next(first_iterator))
# print(iter(first_iterator))
# print([k for k in first_iterator])

def add_this_many(x, el, s):
    """ Adds el to the end of s the number of times x occurs in s.
    >>> s = [1, 2, 4, 2, 1]
    >>> add_this_many(1, 5, s)
    >>> s
    [1, 2, 4, 2, 1, 5, 5]
    >>> add_this_many(2, 2, s)
    >>> s
    [1, 2, 4, 2, 1, 5, 5, 2, 2]
    """
    "*** YOUR CODE HERE ***"
    s_len = len(s)
    cnt = 0
    for i in range(s_len):
        if s[i] == x:
            cnt += 1
    s.extend([el for i in range(cnt)])


import json

def main():
    f = open('student_data.json', 'r')
    json_data = f.read()
    f.close()

    students = json.loads(json_data)
    #print(json.dumps(students, indent=2))
    for id,student_data in students.items():
        assert 'name' in student_data
        first_name = student_data['name'][0]
        last_name = student_data['name'][1]
        assert 'scores' in student_data
        assignments = student_data['scores']['assignments']
        exams = student_data['scores']['exams']
        asgn_avg = sum(assignments) / len(assignments)
        exams_avg = sum(exams) / len(exams)
        print(f'{id} {first_name} {last_name} {asgn_avg} {exams_avg}')

    # for id in students:
    #     print(id)
    # id = input("Select a student: ")
    # assert id in students
    # print(students[id])

if __name__ == "__main__":
    main()


import speech_recognition as sr
r = sr.Recognizer()

harvard = sr.AudioFile('jackhammer.wav')
with harvard as source:
    r.adjust_for_ambient_noise(source,duration=0.5)
    audio = r.record(source)

recognized_sentence=r.recognize_google(audio,show_all=True)

print('Sentence: ',recognized_sentence)


from django import forms
from vehicles.models import Vehicle, VechiclePublication

class VehicleRegisterForm(forms.ModelForm):
    class Meta:
        model = Vehicle
        fields = ['carRegistration', 'brand', 'carModel', 'year', 'seatsNumber']
        widgets = {
            'carRegistration': forms.TextInput(
                attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '15'}),
            'brand': forms.TextInput(attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '15'}),
            'carModel': forms.TextInput(
                attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '15'}),
            'year': forms.NumberInput(attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '15'}),
            'seatsNumber': forms.NumberInput(
                attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '15'})
        }

    def save_model(self, request, obj, form, change):
        obj.added_by = request.user
        super().save_model(request, obj, form, change)

class VehiclePublicationForm(forms.ModelForm):
    class Meta:
        model = VechiclePublication
        fields = ['price', 'description', 'published']
        widgets = {
            'price': forms.NumberInput(attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '15'}),
            'description': forms.TextInput( attrs={'class': 'form-control mt-3', 'placeholder': 'Nick', 'max_length': '100'}),
            'published': forms.CheckboxInput(attrs={'class': 'form-control mt-3', 'placeholder': 'Nick'}),
        }

    def save_model(self, request, obj, form, change):
        obj.added_by = request.user
        super().save_model(request, obj, form, change)


import requests as rq
import pandas as pd

urlTGD = 'https://thegameday.com/fantasy/football/rankings/dynasty/'

def ScrapingPlayersTGD():
    playerDict = {}
    df = pd.read_html(urlTGD)

    # This returns the first table which is our targetted table
    dfRanks = df[0]
    # Assigns values into player dict in the form 'Player': [RK, POSRK]
    for i in range(300):
        # NameEditor ensures each dict has the same str for each player's name
        name = NameEditor(dfRanks['Player'][i])
        ovrRank = dfRanks['RK'][i]
        posRank = dfRanks['POSRK'][i]
        # Stores in the structure of 'PlayerName': ('ovrRank','posRank')
        playerDict[name] = [str(ovrRank), posRank]

    return playerDict

urlPFF = 'https://www.pff.com/news/fantasy-football-2023-post-nfl-draft-dynasty-rankings'

def ScrapingPlayersPFF():
    playerDict = {}

    # Additional request code necessary for avoiding gateway error
    url = rq.get(urlPFF)
    df = pd.read_html(url.text)

    # This returns the first table which is our targetted table
    dfRanks = df[0]

    # Each of the cols are the playerName, overRank, and posRank respectively
    for i in range(299):
        # NameEditor ensures each dict has the same str for each player's name
        name = NameEditor(dfRanks[2][i+1])
        ovrRank = dfRanks[0][i+1]
        posRank = dfRanks[4][i+1]
        # Stores in the structure of 'PlayerName': ('ovrRank','posRank')
        playerDict[name] = [ovrRank, posRank]

    return playerDict

# Used to standarize particular names that are different between the two dicts
def NameEditor(name):
    if ' Jr.' in name:
        return(name.replace(' Jr.', ''))
    elif ' II' in name:
        return(name.replace(' II', ''))
    elif 'D.K.' in name:
        return(name.replace('D.K.', 'DK'))
    elif 'Gabriel' in name:
        return(name.replace('Gabriel', 'Gabe'))
    elif 'Josh' in name:
        return(name.replace('Josh', 'Joshua'))
    elif 'K.J.' in name:
        return(name.replace('K.J.', 'KJ'))
    # If the names do not apply to any of the if statements keep it the same
    else:
        return name

# Used to troubleshoot and see the names not in both of the dicts respectively
def NameDictChecker(dict1, dict2):
    notFoundNames1 = []
    notFoundNames2 = []

    # If the name is not in the other dict put it into the notFoundNames arr
    for key in dict2:
        if key not in dict1:
            notFoundNames1.append(key)

    # If the name is not in the other dict put it into the notFoundNames arr
    for key in dict1:
        if key not in dict2:
            notFoundNames2.append(key)

    # Lengths of the two arrays extra names arr
    print(len(notFoundNames1), len(notFoundNames2))

    # Printing the two arrays to find which names are not in both dicts
    print(sorted(notFoundNames1))
    print(sorted(notFoundNames2))

# Used to put the players into one dict, if they both have the same player append the rank they have
def CombineFunction(dict1, dict2, newDict):
    # Goes through each element of the dict
    for (key1, val1), (key2, val2) in zip(dict1.items(), dict2.items()):
        # std placeholder value, allows for you to append each of the new rankings easier
        std = [[], []]
        # val will be in the form (ovrRank, posRank)

        # create new dict if the player is not in dict1
        if key1 not in newDict:
            newDict[key1] = std
            newDict[key1] = std[0].append(val1[0])
            newDict[key1] = std[1].append(val1[1])
            newDict[key1] = std
            std = [[], []]
        else:
            # appends if player is already in from dict2
            std = newDict[key1]
            newDict[key1] = std[0].append(val1[0])
            newDict[key1] = std[1].append(val1[1])
            newDict[key1] = std
            std = [[], []]

        # create new dict if the player is not in dict2
        if key2 not in newDict:
            newDict[key2] = std
            newDict[key2] = std[0].append(val2[0])
            newDict[key2] = std[1].append(val2[1])
            newDict[key2] = std
            std = [[], []]
        else:
            # appends if player is already in from dict1
            std = newDict[key2]
            newDict[key2] = std[0].append(val2[0])
            newDict[key2] = std[1].append(val2[1])
            newDict[key2] = std
            std = [[], []]
    return newDict

# Takes the elements of the dicts and averages out their rankings in the same dict
def RankCombinerFunction(combDict):
    for player, (ovrRank, posRank) in combDict.items():
        # player = playername, ovrRank = [rank1, rank2], posRank = [posRank1, posRank2]
        # Checks if there are two elements in the item meaning both sites had data on the player
        if len(ovrRank) == 2:
            temp1 = (int(ovrRank[0]) + int(ovrRank[1])) / 2
        else:
            temp1 = int(ovrRank[0])
        if len(posRank) == 2:
            # Each of these are used to ensure that the appropriate chars are taken from the pos rankings ignoring
            # the position that goes along with the rankings
            if len(posRank[0]) == 3:
                tempPosRank1 = int(posRank[0][-1])
            elif len(posRank[0]) == 4:
                tempPosRank1 = int(posRank[0][-2:])
            elif len(posRank[0]) == 5:
                tempPosRank1 = int(posRank[0][-3:])
            if len(posRank[1]) == 3:
                tempPosRank2 = int(posRank[1][-1])
            elif len(posRank[1]) == 4:
                tempPosRank2 = int(posRank[1][-2:])
            elif len(posRank[1]) == 5:
                tempPosRank2 = int(posRank[1][-3:])
            temp2 = (tempPosRank1+tempPosRank2) / 2
            tempPosRank2, tempPosRank1 = 0,0
            temp2 = posRank[0][0:2] + str(temp2)
        else:
            temp2 = posRank[0]
        combDict[player] = [temp1, temp2]


import torch
from sklearn.metrics import classification_report
from torch.autograd import Variable
import numpy as np
import discriminator as d
import generator as g
import params
import torchvision.transforms as transforms
from torchvision.utils import save_image
from torch.utils.data import DataLoader, ConcatDataset
from torchvision import datasets
import os

cuda = True if torch.cuda.is_available() else False
FloatTensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor
opt = params.opt
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

def get_transform():
    return transforms.Compose(
        [transforms.Resize(params.opt.img_size), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])]
    )

def weights_init_normal(m):
    classname = m.__class__.__name__
    if classname.find("Conv") != -1:
        torch.nn.init.normal_(m.weight.data, 0.0, 0.02)
    elif classname.find("BatchNorm") != -1:
        torch.nn.init.normal_(m.weight.data, 1.0, 0.02)
        torch.nn.init.constant_(m.bias.data, 0.0)

def to_categorical(y, num_columns):
    """Returns one-hot encoded Variable"""
    y_cat = np.zeros((y.shape[0], num_columns))
    y_cat[range(y.shape[0]), y] = 1.0

    return Variable(FloatTensor(y_cat))

def init_GAN():
    generator = g.Generator()
    discriminator = d.Discriminator()
    adversarial_loss = torch.nn.MSELoss()
    categorical_loss = torch.nn.CrossEntropyLoss()
    continuous_loss = torch.nn.MSELoss()

    if cuda:
        generator.cuda()
        discriminator.cuda()
        adversarial_loss.cuda()
        categorical_loss.cuda()
        continuous_loss.cuda()

    generator.apply(weights_init_normal)
    discriminator.apply(weights_init_normal)
    return generator, discriminator, adversarial_loss, categorical_loss, continuous_loss

def get_MNIST_train_loader():
    os.makedirs(opt.data_dir, exist_ok=True)
    train_set = datasets.MNIST(root=opt.data_dir, download=True, train=True, transform=get_transform())
    train_loader = torch.utils.data.DataLoader(train_set, batch_size=params.opt.batch_size, shuffle=True)
    return train_loader

def get_MNIST_test_loader():
    test_set = datasets.MNIST(opt.data_dir, download=True, train=False, transform=get_transform())
    test_loader = torch.utils.data.DataLoader(test_set, batch_size=params.opt.batch_size, shuffle=True)
    return test_loader

def get_Fashion_test_loader():
    test_set = datasets.FashionMNIST(opt.fashion_data_dir, download=True, train=False, transform=get_transform())
    test_loader = torch.utils.data.DataLoader(test_set, batch_size=params.opt.batch_size, shuffle=True)
    return test_loader

def get_static_gen_input():
    static_z = Variable(FloatTensor(np.zeros((opt.n_classes ** 2, opt.latent_dim))))
    static_label = to_categorical(
        np.array([num for _ in range(opt.n_classes) for num in range(opt.n_classes)]), num_columns=opt.n_classes
    )
    static_code = Variable(FloatTensor(np.zeros((opt.n_classes ** 2, opt.code_dim))))
    return static_z, static_label, static_code

def sample_image(generator, n_row, batches_done, folder_im):
    static_z, static_label, static_code = get_static_gen_input()
    z = Variable(FloatTensor(np.random.normal(0, 1, (n_row ** 2, opt.latent_dim))))
    static_sample = generator(z, static_label, static_code)
    save_image(static_sample.data, folder_im + "/static/%d.png" % batches_done, nrow=n_row, normalize=True)
    zeros = np.zeros((n_row ** 2, 1))
    c_varied = np.repeat(np.linspace(-1, 1, n_row)[:, np.newaxis], n_row, 0)
    c1 = Variable(FloatTensor(np.concatenate((c_varied, zeros), -1)))
    c2 = Variable(FloatTensor(np.concatenate((zeros, c_varied), -1)))
    sample1 = generator(static_z, static_label, c1)
    sample2 = generator(static_z, static_label, c2)
    save_image(sample1.data, folder_im + "/varying_c1/%d.png" % batches_done, nrow=n_row, normalize=True)
    save_image(sample2.data, folder_im + "/varying_c2/%d.png" % batches_done, nrow=n_row, normalize=True)

def sample_image2(generator, n_row, batches_done, folder_im):
    static_z, static_label, static_code = get_static_gen_input()
    z = Variable(FloatTensor(np.random.normal(0, 1, (n_row ** 2, opt.latent_dim))))
    static_sample = generator(z, static_label, static_code)
    save_image(static_sample.data, folder_im + "/static/%d.png" % batches_done, nrow=n_row, normalize=True)
    zeros = np.zeros((n_row ** 2, 1))
    c_varied = np.repeat(np.linspace(-1, 1, n_row)[:, np.newaxis], n_row, 0)
    for i in range(opt.code_dim):
        l = [zeros] * opt.code_dim
        l[i] = c_varied
        c = Variable(FloatTensor(np.concatenate(tuple(l), -1)))
        sample = generator(static_z, static_label, c)
        name = folder_im + '/varying_c' + str(i + 1) + '/%d.png' % batches_done
        save_image(sample.data, name, nrow=n_row, normalize=True)

def get_structure_loss(loss_function, code_input, pred_code, negative_edges, positive_edges):
    loss = 0
    losses = []
    gains = []
    gains2 = []
    for edge in positive_edges:
        losses.append(loss_function(pred_code[:, edge[1]], code_input[:, edge[0]]))

    for edge in negative_edges:
        gains.append(loss_function(pred_code[:, edge[1]], code_input[:, edge[0]]))

    for i in range(pred_code.size()[1]):
        for j in range(i, pred_code.size()[1]):
            gains2.append(loss_function(pred_code[:, i], code_input[:, j]))

    if sum(gains) + sum(gains2) > sum(losses):
        return loss
    else:
        return sum(losses) - sum(gains) - sum(gains2)

def get_imbalance_dataloader(labels, sizes):
    """ Returns imbalanced train loader """

    dataset_list = []
    for i in range(0, len(labels)):
        label = labels[i]
        size = sizes[i]
        temp_dataset = get_imbalanced_dataset(label, size)
        dataset_list.append(temp_dataset)

    dataset = ConcatDataset(dataset_list)
    return DataLoader(dataset, batch_size=opt.batch_size, shuffle=True)

def get_imbalanced_dataset(label, num):
    """ Returns specific number of label """

    os.makedirs(opt.data_dir, exist_ok=True)
    dataset = datasets.MNIST(opt.data_dir, train=True, download=True, transform=get_transform())
    index = (dataset.targets == label)
    dataset.targets = dataset.targets[index]
    dataset.data = dataset.data[index]

    indices = torch.randperm(len(dataset.targets))[:num]
    dataset.targets = dataset.targets[indices]
    dataset.data = dataset.data[indices]
    return dataset

def initial_mnist_imbalanced_data(labels, nums, gene_indexes, gene_nums):
    """ Returns imbalanced data for CNNs """

    images = torch.empty(0).to(device)
    targets = torch.empty(0, dtype=int).to(device)
    length = len(labels)
    for i in range(length):
        label = labels[i]
        num = nums[i]
        generate_index = gene_indexes[i]
        gene_size = gene_nums[i]

        temp_images, temp_labels = get_specific_label(label, num)
        temp_images, temp_labels = temp_images.to(device), temp_labels.to(device)
        temp_gene_images, temp_gene_labels = generate_sample(label, generate_index, gene_size=gene_size)

        images = torch.cat([images, temp_images, temp_gene_images], dim=0)
        targets = torch.cat([targets, temp_labels, temp_gene_labels], dim=0)

    if cuda:
        images, targets = images.cpu(), targets.cpu()
    x, y = shuffle(images.detach().numpy(), targets.detach().numpy())
    return torch.from_numpy(x), torch.from_numpy(y)

def generate_sample(label, index, gene_size=100):
    """ Generates images and targets via GAN """

    path = opt.gan_dir + '/GAN_MNIST.pt'
    generator, _ = get_trained_generator_discriminator(path)
    if cuda:
        generator.cuda()

    data = torch.empty(0).to(device)
    targets = torch.empty(0, dtype=int).to(device)
    repeat = int(gene_size / 100)
    for i in range(repeat):
        gene_data = generate_img(generator, label, index)
        data = torch.cat([data, gene_data], dim=0)

        targets = torch.cat([targets, torch.from_numpy(np.ones(100, dtype=int) * label).to(device)], dim=0)
    return data, targets

def get_trained_generator_discriminator(path):
    generator = g.Generator()
    checkpoint = torch.load(path, map_location=torch.device('cpu'))
    generator.load_state_dict(checkpoint['generator'])
    generator.eval()

    discriminator = d.Discriminator()
    discriminator.load_state_dict(checkpoint['discriminator'])
    discriminator.eval()
    return generator, discriminator

def generate_img(generator, label, label_index, n_row=10):
    """ Returns generative result """

    static_z, static_label, static_code = get_specific_label_gen_input(label_index)
    z = Variable(torch.FloatTensor(np.random.normal(0, 0.5, (n_row ** 2, opt.latent_dim))))
    z = z.to(device)
    sample = generator(z, static_label, static_code)

    img_dir = opt.gene_img_dir
    os.makedirs(img_dir, exist_ok=True)
    name = opt.gene_img_dir + '/gene_label_{}_index_{}.png'.format(label, label_index)
    save_image(sample.data, name, nrow=n_row, normalize=True)

    return sample

def get_specific_label_gen_input(label_index):
    """ Returns specific static label """

    static_z = Variable(FloatTensor(np.zeros((opt.n_classes ** 2, opt.latent_dim))))
    static_label = to_categorical(
        np.ones(100, dtype=int).dot(label_index), num_columns=opt.n_classes
    )
    static_code = Variable(FloatTensor(np.zeros((opt.n_classes ** 2, opt.code_dim))))
    return static_z, static_label, static_code

def get_specific_label(label, size):
    """ Returns specific label with specific number """

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

    os.makedirs(opt.data_dir, exist_ok=True)
    train_set = datasets.MNIST(root=opt.data_dir, download=True, train=True, transform=transforms.Compose(
        [transforms.Resize(32), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])]
    ))

    idx = (train_set.targets == label)
    train_set.targets = train_set.targets[idx]
    train_set.data = train_set.data[idx]

    # randomly select data
    indices = torch.randperm(len(train_set.targets))[:size]
    train_set.targets = train_set.targets[indices]
    train_set.data = train_set.data[indices]

    data_loader = torch.utils.data.DataLoader(train_set, batch_size=len(train_set.targets))

    dataiter = iter(data_loader)
    images, labels = next(dataiter)
    return images, labels

def shuffle(data, targets, seed=32):
    np.random.seed(seed)
    np.random.shuffle(data)
    np.random.seed(seed)
    np.random.shuffle(targets)
    return data, targets

def print_report(model, test_loader, report_labels=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]):
    """ Print classification report """

    pred_labels = []
    true_labels = []
    for images, labels in test_loader:
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        pred_labels = pred_labels + predicted.numpy().tolist()
        true_labels = true_labels + labels.numpy().tolist()

    report = classification_report(true_labels, pred_labels, labels=report_labels)
    print(report)

def initial_parameters(dataset):
    """ Initial parameters
    Args:
        dataset: name of dataset

    Returns:
        labels: classes in dataset
        nums: number of each class
        gene_indexes: relationship between generative label and index
        gene_nums: number of each class that will generate
    """

    if dataset == 'fashion-mnist':
        labels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        nums = [4000, 2000, 1000, 750, 500, 350, 200, 100, 60, 40]
        gene_indexes = [7, 6, 9, 8, 0, 4, 5, 3, 1, 2]
        gene_nums = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]

        return labels, nums, gene_indexes, gene_nums
    else:
        # mnist
        labels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        nums = [4000, 2000, 1000, 750, 500, 350, 200, 100, 60, 40]

        gene_indexes = [6, 1, 4, 9, 0, 8, 5, 2, 7, 3]
        gene_nums = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]

        return labels, nums, gene_indexes, gene_nums

def initial_fashion_imbalanced_data(labels, nums, gene_indexes, gene_nums):

    images = torch.empty(0).to(device)
    targets = torch.empty(0, dtype=int).to(device)
    length = len(labels)
    for i in range(length):
        label = labels[i]
        size = nums[i]
        gene_index = gene_indexes[i]
        gene_num = gene_nums[i]

        temp_images, temp_labels = get_fashion_specific_label(label, size)
        temp_gene_images, temp_gene_labels = generate_fashion_sample(label, gene_index, gene_num)

        images = torch.cat([images, temp_images, temp_gene_images], dim=0)
        targets = torch.cat([targets, temp_labels, temp_gene_labels], dim=0)

    if cuda:
        images, targets = images.cpu(), targets.cpu()
    x, y = shuffle(images.detach().numpy(), targets.detach().numpy())
    return torch.from_numpy(x), torch.from_numpy(y)

def get_fashion_specific_label(label, size):
    train_set = datasets.FashionMNIST(root=opt.fashion_data_dir, download=True, train=True, transform=transforms.Compose(
        [transforms.Resize(32), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])]
    ))

    idx = (train_set.targets == label)
    train_set.targets = train_set.targets[idx]
    train_set.data = train_set.data[idx]

    indices = torch.randperm(len(train_set.targets))[:size]
    train_set.targets = train_set.targets[indices]
    train_set.data = train_set.data[indices]

    data_loader = torch.utils.data.DataLoader(train_set, batch_size=len(train_set.targets))

    dataiter = iter(data_loader)
    images, labels = next(dataiter)
    return images.to(device), labels.to(device)

def generate_fashion_sample(label, index, gene_num=100):
    """
    generate images, labels via GAN
    """

    # set code_dim
    opt.code_dim = 3

    generator, _ = get_trained_generator_discriminator(opt.gan_dir + '/GAN_Fashion_MNIST.pt')
    if cuda:
        generator.cuda()

    data = torch.empty(0).to(device)
    targets = torch.empty(0, dtype=int).to(device)
    repeat = int(gene_num / 100)
    for i in range(repeat):
        gene_data = generate_fashion_img(generator, label, index)
        data = torch.cat([data, gene_data], dim=0)

        targets = torch.cat([targets, torch.from_numpy(np.ones(100, dtype=int) * label).to(device)], dim=0)
    return data, targets

def generate_fashion_img(generator, label, label_index, n_row=10, factor=4.9):
    """ Returns generative result """

    static_z, static_label, static_code = get_specific_label_gen_input(label_index)
    z = Variable(torch.FloatTensor(np.random.normal(0, 0.2, (n_row ** 2, opt.latent_dim))))
    z = z.to(device)

    zeros = np.zeros((n_row ** 2, 1))
    c_varied = torch.randn(100, 1) * factor

    # code
    l = [zeros] * opt.code_dim
    l[2] = c_varied
    code = Variable(torch.FloatTensor(np.concatenate(tuple(l), -1)))
    code = code.to(device)

    sample = generator(z, static_label, code)

    # save image
    img_dir = opt.gene_img_dir
    os.makedirs(img_dir, exist_ok=True)
    name = opt.gene_img_dir + '/gene_fashion_label_{}_index_{}.png'.format(label, label_index)
    save_image(sample.data, name, nrow=n_row, normalize=True)

    return sample


from node import Node

class LinkedList:
    def __init__(self):
        self.head = None
        self.last = None
        self._size = 0

    # Inserir elementos no final da lista.
    def append(self, element):
        # Caso exista um elemento já na lista.
        if self.head:
            # Inserção quando a lista já possui elementos
            pointer = self.head
            ls = None
            # Pegar a posição da memória onde não exista nada no próximo next
            while(pointer.next):
                ls = pointer
                pointer = pointer.next
            pointer.next = Node(element)
            pointer.next.ls = pointer
            pointer.ls = ls
            if self.last:
                self.last = pointer.next

        # Se não insira o primeiro elemento na lista.
        else:
            # Primeira inserção
            self.head = Node(element)
            self.last = Node(element)
        self._size = self._size + 1

    def __len__(self):
        # Retorna o tamanho da lista.
        return self._size

    def _get_node(self, index):
        pointer = self.head
        for i in range(index):
            if pointer:
                pointer = pointer.next
            else:
                raise IndexError("list index out of range")
        return pointer

    def set(self, index, element):
        pass

    def __getitem__(self, index):
        # Recuperar o valor a partir de []
        # a = lista[6]
        pointer = self._get_node(index)
        if pointer:
            return pointer.data
        raise IndexError("list index out of range")

    def __setitem__(self, index, element):
        # lista[5] = 9
        pointer = self._get_node(index)
        if pointer:
            pointer.data = element
        else:
            raise IndexError("list index out of range")

    def index(self, element):
        # Retorna o índice do element na lista
        pointer = self.head
        i = 0
        # for diferente de None
        while(pointer):
            if pointer.data == element:
                return i
            pointer = pointer.next
            i = i + 1
        raise ValueError(f'{element} is not in list')

    def insert(self, index, element):
        node = Node(element)
        if index == 0:
            node.next = self.head
            self.head = node
        else:
            pointer = self._get_node(index-1)
            node = Node(element)
            node.next = pointer.next
            pointer.next = node
        self._size = self._size + 1

    def dell(self):
        pass

    # Imprimir a lista.
    def get_lista(self):
        if self.head == None:
            raise IndexError("Empty list")
        else:
            print("Ordem normal, conforme foi inserido os elementos")
            pointer = self.head
            while(pointer):
                print(f'{pointer.data}, ', end="")
                pointer = pointer.next
            print(f'\nTamanho da lista: {self._size}')
            print("--------------------------")

    # Imprimir a lista (inversalmente)
    def get_lista_inversa(self):
        pointer = self.last
        print("Ordem inversa dos elementos inseridos")
        while(pointer):
            print(f'{pointer.data}, ', end="")
            pointer = pointer.ls
        print(f'\nTamanho da lista: {self._size}')
        print("--------------------------")