def check_tail(y_head, x_head, y_tail, x_tail):
    global grid_tail
    global grid

    same_col = False
    same_row = False
    if x_head == x_tail:
        same_col = True
    if y_head == y_tail:
        same_row = True

    # straight
    if same_row and x_head - 1 > x_tail:
        x_tail += 1
    if same_row and x_head + 1 < x_tail:
        x_tail -= 1
    if same_col and y_head - 1 > y_tail:
        y_tail += 1
    if same_col and y_head + 1 < y_tail:
        y_tail -= 1

    # corners
    if x_head - 1 > x_tail and y_head - 1 > y_tail:
        x_tail += 1
        y_tail += 1
    if x_head - 1 > x_tail and y_head + 1 < y_tail:
        x_tail += 1
        y_tail -= 1
    if x_head + 1 < x_tail and y_head - 1 > y_tail:
        x_tail -= 1
        y_tail += 1
    if x_head + 1 < x_tail and y_head + 1 < y_tail:
        x_tail -= 1
        y_tail -= 1

    # edges but not straight
    if not same_row and x_head - 1 > x_tail:
        x_tail += 1
        y_tail = y_head
    if not same_row and x_head + 1 < x_tail:
        x_tail -= 1
        y_tail = y_head
    if not same_col and y_head - 1 > y_tail:
        y_tail += 1
        x_tail = x_head
    if not same_col and y_head + 1 < y_tail:
        y_tail -= 1
        x_tail = x_head

    return [y_tail, x_tail]

def simulate_tail():
    global tail_pos
    global grid
    for i in range(1, len(tail_pos)):
        new_pos = check_tail(tail_pos[i - 1][0], tail_pos[i - 1][1], tail_pos[i][0], tail_pos[i][1])
        tail_pos[i][0] = new_pos[0]
        tail_pos[i][1] = new_pos[1]

    last_tail = tail_pos[len(tail_pos) - 1]
    grid_tail[last_tail[0]][last_tail[1]] = '#'

def execute_step(step):
    global tail_pos
    s = step[0]
    n = step[1]
    if s == "R":
        for i in range(0, n):
            tail_pos[0][1] += 1
            simulate_tail()
    if s == "U":
        for i in range(0, n):
            tail_pos[0][0] -= 1
            simulate_tail()

    if s == "D":
        for i in range(0, n):
            tail_pos[0][0] += 1
            simulate_tail()
    if s == "L":
        for i in range(0, n):
            tail_pos[0][1] -= 1
            simulate_tail()

def print_grid(grid):
    print("")
    for i in range(0, len(grid[0])):
        print(grid[i])

def clear_gird(grid) -> list:
    global grid_mid
    grid.clear()
    for i in range(0, grid_mid * 2):
        r = []
        for j in range(0, grid_mid * 2):
            r.append('_')
        grid.append(r)
    return grid

def update_grid():
    global grid
    global x_pos
    global y_pos
    global tail_pos
    clear_gird(grid)
    grid[y_pos][x_pos] = 's'
    for i in range(0, len(tail_pos)):
        grid[tail_pos[i][0]][tail_pos[i][1]] = str(i)

grid = []
grid_tail = []
tail_pos = []
# (1) Head + Tails
tail_count = 1 + 9

grid_mid = 1000
x_pos = int(grid_mid / 2)
y_pos = int(grid_mid / 2)

with open("input.txt") as f:
    txt = f.read().split('\n')
    steps = []
    for line in txt:
        s = line.split(" ")
        steps.append([s[0], int(s[1])])

    for i in range(0, grid_mid * 2):
        r = []
        r_t = []
        for j in range(0, grid_mid * 2):
            r_t.append('_')
            r.append('_')
        grid.append(r)
        grid_tail.append(r_t)

    for i in range(0, tail_count):
        tail_pos.append([y_pos, x_pos])

    grid[y_pos][x_pos] = 's'

    print(f'last step {steps[len(steps) - 1]}')
    for s in steps:
        # print(f'Step: {s}')
        execute_step(s)
        # update_grid()
        # print_grid(grid)

    # print_grid(grid_tail)

    count = 0
    for i in range(0, len(grid_tail)):
        for j in range(0, len(grid_tail[0])):
            if grid_tail[i][j] == '#':
                count += 1
    print(count)


import os
import torch

def create_model_save_dir(save_dir):
    """ """
    model_save_dir=''
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)

    folder_list = os.listdir(save_dir)
    if len(folder_list) > 0:
        folder_list = list(folder_list)
        folder_list = list(map(int, folder_list))
        folder_list.sort()
        last_folder = folder_list[-1]
        last_number = int(last_folder)
        new_folder = str(last_number + 1)
    else:
        new_folder = '1'
    model_save_dir = os.path.join(save_dir, new_folder)
    os.makedirs(model_save_dir)

    return model_save_dir


import pandas as pd
import numpy as np
import cv2
import math
from matplotlib import pyplot as plt
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from skimage import feature
import os

'''
Ici on importe le fichier csv en fonction de s'il s'agit du test ou du train
'''

class importcsv:
    def __init__(self,train):
        self.train=train
        if train :
            self.path="./Dataset/trainset/"
            df=pd.read_csv(self.path+"trainset.csv", sep=',',header=0)
            self.target = df.iloc[:,-1:]
        else:
            self.path="./Dataset/testset/"
            df=pd.read_csv(self.path+"testset.csv", sep=',',header=0)

        self.filename=df["filename"].astype(str).values.tolist()
        self.size=len(df)
        self.landmarks=np.empty([self.size,68,2],dtype=np.longdouble)
        for i in range(self.size):
            for j in range(0,68):
                self.landmarks[i,j,0] = df.iloc[i,j+1]
                self.landmarks[i,j,1] = df.iloc[i,j+69]

class normalization:
    def __init__(self,data):
        self.landmarks=np.empty([data.size,68,2],dtype=np.longdouble)
        self.normFactor=[]
        reference=np.max(distance(data,39,42))                   #On utilise la plus grande distance entre les yeux parmis toutes les images comme référence pour le facteur de normalisation
                                               #cela nous permet de conserver le maximum d'informations dans chaque image, puisque aucune image ne sera réduite(mais elle seront toutes multipliées).
        for i in range(data.size):
            factor=reference/distance(data,39,42,i)  #On calcule le facteur de normalisation
            self.normFactor.append(factor)           #On sauvegarde ce facteur afin de pour voir le réutiliser plus tard lors de la normalisation des images
            for j in range(0,68):
                self.landmarks[i,j,0] = data.landmarks[i,j,0]*factor
                self.landmarks[i,j,1] = data.landmarks[i,j,1]*factor  #On normalise tout les landmarks

'''
Cette fonction nous permet d'obtenir l'angle entre le vecteur de landmarks 39 et 42 càd le vecteur qui passe par les deux yeux
Cet angle nous permettra de tourner l'image afin que le visage soit parfaitement droit
'''
def getHeadTilt(data,img):
    return  math.degrees(math.atan2(data.landmarks[img,42,1] - data.landmarks[img,39,1], data.landmarks[img,42,0] - data.landmarks[img,39,0]))

'''
Cette fonction nous permet de faire une rotation de l'image
'''
def rotateImage(img, angle, origin):
    rotationMatrix = cv2.getRotationMatrix2D(origin, angle, 1.0)
    return cv2.warpAffine(img, rotationMatrix, img.shape[1::-1], flags=cv2.INTER_LINEAR)

'''
Cette fonction nous permet de faire une rotation des coordonnées des landmarks
'''

def rotateLandmarks(origin, point, angle):
    ox, oy = origin
    px, py = point
    return ( ox+math.cos(angle)*(px-ox)-math.sin(angle)*(py-oy) ),( oy+math.sin(angle)*(px-ox)+math.cos(angle)*(py-oy) )

'''
Cette fonction nous permet d'obtenir la distance euclidienne entre deux landmarks
ou selon le paramètre de renvoyer la distance euclidienne entre de landmarks de toutes les images
'''

def distance(data,A,B,specific=-1):
    if specific>=0 :
        a=np.array((data.landmarks[specific,A,0],data.landmarks[specific,A,1]))
        b=np.array((data.landmarks[specific,B,0],data.landmarks[specific,B,1]))
        return np.linalg.norm(a-b) # calcul distance euclidienne
    else:
        dist=[]
        for i in range(originalData.size):
            a=np.array((data.landmarks[i,A,0],data.landmarks[i,A,1]))
            b=np.array((data.landmarks[i,B,0],data.landmarks[i,B,1]))
            dist.append(np.linalg.norm(a-b))
        return np.array(dist)

'''
Cette fonction nous permet d'extraire les Features de textures et de normaliser toutes les images
'''

def extractTextureFeatures():
    #On prépare le dataframe
    columns = ['texInterSourcil1', 'texInterSourcil2','texCoinBoucheD1', 'texCoinBoucheD2', 'texCoinBoucheG1', 'texCoinBoucheG2', 'texPaupiereG1', 'texPaupiereG2', 'texPaupiereD1', 'texPaupiereD2']

    df = pd.DataFrame(index=range(originalData.size),columns=columns)

    maxHeight= int ( np.max(distance(normalizedData,33,8)) +3 ) # Ici on calcule la distance maximale parmis toutes les images entre le nez et les bords du visages
    maxWidth= int ( np.max(distance(normalizedData,33,16)) +3 ) # afin que toutes les images ait les même dimension après normalisation et ce sans perte d'informations

    for file in range(originalData.size):
        headTilt=getHeadTilt(normalizedData,file) #On obtient ici l'angle du visage pour corriger sa rotation

        factor=normalizedData.normFactor[file] #On récupère notre facteur de normalisation utilisé pour la normalisation des landmarks

        img = cv2.imread(originalData.path+originalData.filename[file]+".png", cv2.IMREAD_UNCHANGED)
        img = cv2.resize(img, (int(img.shape[1] * factor), int(img.shape[0] * factor)), interpolation = cv2.INTER_AREA) # On redimmensionne l'image

        origin=tuple(np.array(img.shape[1::-1]) / 2)
        img = rotateImage(img,headTilt,origin) #On peut maintenant tourner l'image avec l'angle et l'origine de l'image calculée
        img = img[int(round(normalizedData.landmarks[file,33,1]))-maxHeight:int(round(normalizedData.landmarks[file,33,1]))+maxHeight,
                  int(round(normalizedData.landmarks[file,33,0]))-maxWidth:int(round(normalizedData.landmarks[file,33,0]))+maxWidth] # Ici on extrait seulement le visage de toute l'image en utlisant les valeurs maximum autour du visage

        noseX,noseY=normalizedData.landmarks[file,33,0],normalizedData.landmarks[file,33,1] # On stock les valeurs des lanmarks du nez pour les utiliser plus simplement

        for i in range(len(normalizedData.landmarks[file,:,:])):
            rotatedX,rotatedY = rotateLandmarks(origin,(normalizedData.landmarks[file,i,0],normalizedData.landmarks[file,i,1]),-(math.radians(headTilt)))
            normalizedData.landmarks[file,i,0]=rotatedX-noseX+maxWidth           # Enfin ici on calcule les nouveaux landmarks qui correspondent au image normalisé(rognées et tournées)
            normalizedData.landmarks[file,i,1]=rotatedY-noseY+maxHeight
            # plt.scatter(np.round(normalizedData.landmarks[file,i,0]),np.round(normalizedData.landmarks[file,i,1]),c="red",s=1)

        '''
        Ici on va maintenant extraire toutes les zones intéressantes du visage et y appliquer un Local Binary Patern

        ZONE ENTRE LES SOURCILS
        '''
        height=int((normalizedData.landmarks[file,27,1]-normalizedData.landmarks[file,21,1])/2)
        centerY=int(normalizedData.landmarks[file,27,1]-height)
        centerX=int(normalizedData.landmarks[file,27,0])
        df.iloc[file,0], df.iloc[file,1] = LBP(img[centerY-50:centerY+50,centerX-50:centerX+50])

        '''
        ZONE COIN DROIT DE LA BOUCHE
        '''
        centerY=int(normalizedData.landmarks[file,48,1])
        centerX=int(normalizedData.landmarks[file,48,0])

        df.iloc[file,2], df.iloc[file,3] = LBP(img[centerY-25:centerY+25,centerX-25:centerX+25])

        '''
        ZONE COIN GAUCHE DE LA BOUCHE
        '''

        centerY=int(normalizedData.landmarks[file,54,1])
        centerX=int(normalizedData.landmarks[file,54,0])

        df.iloc[file,4], df.iloc[file,5] = LBP(img[centerY-25:centerY+25,centerX-25:centerX+25])

        '''
        ZONE PAUPIERE GAUCHE
        '''

        height=int((normalizedData.landmarks[file,1,1]-normalizedData.landmarks[file,36,1])/2)
        width=int((normalizedData.landmarks[file,39,0]-normalizedData.landmarks[file,36,0])/2)
        centerY=int(normalizedData.landmarks[file,41,1]+height)
        centerX=int(normalizedData.landmarks[file,36,0]+width)

        df.iloc[file,6], df.iloc[file,7] = LBP(img[centerY-75:centerY+75,centerX-75:centerX+75])

        '''
        ZONE PAUPIERE DROITE
        '''

        height=int((normalizedData.landmarks[file,1,1]-normalizedData.landmarks[file,42,1])/2)
        width=int((normalizedData.landmarks[file,45,0]-normalizedData.landmarks[file,42,0])/2)
        centerY=int(normalizedData.landmarks[file,47,1]+height)
        centerX=int(normalizedData.landmarks[file,42,0]+width)
        df.iloc[file,8], df.iloc[file,9] = LBP(img[centerY-75:centerY+75,centerX-75:centerX+75])

    return df

'''
Cette fonction applique un Local Binary Patern à l'image reçue
'''
def LBP(img):

    ret_s, th_s = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
    th_s=feature.local_binary_pattern(th_s, 24,8, method="uniform")
    th_s[th_s==24]=0
    rate_nblack_pix = (th_s[th_s!=0].size) / th_s.size
    rate_nblack_on_bl = (th_s[th_s!=0].size)/(th_s[th_s==0].size)

    return rate_nblack_pix, rate_nblack_on_bl

'''
Puisque nos landmarks sont normalisées on peut les ajouter en temps que features on créer donc un dataframe
'''
def landmarksDataFrame():

    dfx = pd.DataFrame(normalizedData.landmarks[:,:,0], columns = ['x_0', 'x_1', 'x_2', 'x_3', 'x_4', 'x_5', 'x_6', 'x_7', 'x_8', 'x_9', 'x_10', 'x_11', 'x_12', 'x_13', 'x_14', 'x_15', 'x_16', 'x_17', 'x_18', 'x_19', 'x_20', 'x_21', 'x_22', 'x_23', 'x_24', 'x_25', 'x_26', 'x_27', 'x_28', 'x_29', 'x_30', 'x_31', 'x_32', 'x_33', 'x_34', 'x_35', 'x_36', 'x_37', 'x_38', 'x_39', 'x_40', 'x_41', 'x_42', 'x_43', 'x_44', 'x_45', 'x_46', 'x_47', 'x_48', 'x_49', 'x_50', 'x_51', 'x_52', 'x_53', 'x_54', 'x_55', 'x_56', 'x_57', 'x_58', 'x_59', 'x_60', 'x_61', 'x_62', 'x_63', 'x_64', 'x_65', 'x_66', 'x_67'])
    dfy = pd.DataFrame(normalizedData.landmarks[:,:,1], columns = ['y_0', 'y_1', 'y_2', 'y_3', 'y_4', 'y_5', 'y_6', 'y_7', 'y_8', 'y_9', 'y_10', 'y_11', 'y_12', 'y_13', 'y_14', 'y_15', 'y_16', 'y_17', 'y_18', 'y_19', 'y_20', 'y_21', 'y_22', 'y_23', 'y_24', 'y_25', 'y_26', 'y_27', 'y_28', 'y_29', 'y_30', 'y_31', 'y_32', 'y_33', 'y_34', 'y_35', 'y_36', 'y_37', 'y_38', 'y_39', 'y_40', 'y_41', 'y_42', 'y_43', 'y_44', 'y_45', 'y_46', 'y_47', 'y_48', 'y_49', 'y_50', 'y_51', 'y_52', 'y_53', 'y_54', 'y_55', 'y_56', 'y_57', 'y_58', 'y_59', 'y_60', 'y_61', 'y_62', 'y_63', 'y_64', 'y_65', 'y_66', 'y_67'])
    return pd.concat([dfx, dfy], axis=1)

'''
Ici on cree notre dataframe pour les features de géométrie celle-ci vont calculé des relations entre les landmarks
'''

def extractGeoFeatures():

    columns = ['h_nez_ment','h_bouche_int', 'oeil_d_sourcil', 'oeil_g_sourcil', 'inter_sourcil', 'relat_oeil_d_1',
           'relat_oeil_d_2', 'relat_oeil_g_1', 'relat_oeil_g_2', 'relat_bouche_int',

           'labels']
    df = pd.DataFrame(index=range(originalData.size),columns=columns)
    df["h_nez_ment"]=distance(normalizedData,8,33)
    df["h_bouche_int"]=distance(normalizedData,62,66)
    df["oeil_d_sourcil"]=distance(normalizedData,19,37)
    df["oeil_g_sourcil"]=distance(normalizedData,24,44)
    df["inter_sourcil"]=distance(normalizedData,21,22)
    df["relat_oeil_d_1"]=(distance(normalizedData,42,45)/distance(normalizedData,43,47))
    df["relat_oeil_d_2"]=(distance(normalizedData,42,45)/distance(normalizedData,44,46))
    df["relat_oeil_g_1"]=(distance(normalizedData,36,39)/distance(normalizedData,37,41))
    df["relat_oeil_g_2"]=(distance(normalizedData,36,39)/distance(normalizedData,38,40))
    df["relat_bouche_int"]= (distance(normalizedData,62,66)/distance(normalizedData,60,64))

    if originalData.train :
        df["labels"]=originalData.target
    return df

'''
On utilise une Random Forest pour effuctuer une features selection
'''

def index_features_select(X,Y,c=1):
    rf = RandomForestClassifier(n_estimators=130,criterion='gini',max_depth=50,random_state=42)
    rf.fit(X, Y)
    len_feat = X.values.shape[1]
    return np.where(rf.feature_importances_>=(c/len_feat))[0]

'''
On va d'abord générer notre features_train.csv et selectionné les features les plus pertinentes
'''
originalData = importcsv(1)

normalizedData = normalization(originalData)

texFeatures=extractTextureFeatures()
landFeatures=landmarksDataFrame()
geoFeatures=extractGeoFeatures()
labels = geoFeatures.iloc[:,-1]

fullFeaturesTrain = pd.concat([landFeatures,texFeatures,geoFeatures], axis=1)

selectedFeatures = index_features_select(fullFeaturesTrain.iloc[:,:-1],fullFeaturesTrain.iloc[:,-1])

finalFeatures = fullFeaturesTrain.iloc[:,index_features_select(fullFeaturesTrain.iloc[:,:-1],fullFeaturesTrain.iloc[:,-1],c=1)]
finalFeatures = pd.concat([finalFeatures,labels],axis=1)

finalFeatures.to_csv("features_train.csv",index=False)
'''
Maintenant on créer notre features_test.csv en ne prenant que les features qui on été selectionné lors de la features selection du train
'''
originalData = importcsv(0)

normalizedData = normalization(originalData)

texFeatures=extractTextureFeatures()
landFeatures=landmarksDataFrame()
geoFeatures=extractGeoFeatures()

fullFeaturesTest = pd.concat([landFeatures,texFeatures,geoFeatures], axis=1)
fullFeaturesTest = fullFeaturesTest.iloc[:,selectedFeatures]
fullFeaturesTest.to_csv("features_test.csv",index=False)


import os
from flask import Flask, redirect, url_for, request, render_template, session, jsonify
import flask
import arrow
import acp_times
import requests
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')

@app.route('/')
def index():

    return render_template('calc.html'), 200

# @app.route("/listAll", methods=["POST", "GET"])
@app.route("/<path:url>", methods=["POST", "GET"])
@app.route("/<path:url>/<path:file_type>/", methods=["POST", "GET"])
def list_all(url, file_type=None, limit=str(0)):

    if file_type is not None:  # if we specify json or csv format
        """
        This will parse the url correctly if we specify the file type
        and / or a top query.
        http://localhost:5000/listClosedOnly/json/?top=4
        """
        if request.args.get("top"):
            limit = request.args.get("top")
        resp = requests.get("http://api-service/" + url + "/" + file_type + "?top=" + limit)
        return resp.content, resp.status_code, resp.headers.items()

    # if we only do listAll, listClosedOnly, etc
    resp = requests.get("http://api-service/" + url)
    return resp.content, resp.status_code, resp.headers.items()

def remove_empty(lst):
    temp = []
    for i in lst:
        if i != "":
            temp.append(i)
    return temp

def build_dict(km: list, open: list, close: list):
    return_dict = []
    for i in range(len(km)):
        # return_dict.append("KM": km[i]) = [open[i], close[i]]
        temp = {
            "km": km[i],
            "open": open[i],
            "close": close[i]
        }
        return_dict.append(temp)
    print(f"return dict: {return_dict}")
    return return_dict

@app.route('/new', methods=['POST', "GET"])
def new():
    # get form data as list
    open_time = request.form.getlist("open")
    close_time = request.form.getlist("close")
    km = request.form.getlist("km")

    # remove empty strings in each list
    km = remove_empty(km)
    close_time = remove_empty(close_time)
    open_time = remove_empty(open_time)

    controls = build_dict(km, open_time, close_time)

    if len(request.form['name']) == 0:
        return render_template('error.html'), "Form not filled out"

    item_doc = {
        'BrevetName': request.form['name'],  # name of the race
        "Distance": str(session["Distance"]),
        "StartDate": session["start_date"],
        "StartTime": session["start_time"],
        "Controls": controls

    }

    # print(item_doc)
    headers = {'Content-type': 'application/json'}
    resp = requests.post("http://api-service/new", json=item_doc)

    return redirect(url_for('index'))

@app.route("/_calc_times")
def _calc_times():
    """
    Calculates open/close times from miles, using rules
    described at https://rusa.org/octime_alg.html.
    Expects one URL-encoded argument, the number of miles.
    """

    # app.logger.debug("Got a JSON request")
    km = request.args.get('km', 999, type=float)
    # app.logger.debug("km={}".format(km))
    # app.logger.debug("request.args: {}".format(request.args))
    distance = request.args.get("distance", 200, int)
    date = request.args.get("start_date")
    time = request.args.get("start_time")
    t = arrow.get(str(date) + " " + str(time),
                  "YYYY-MM-DD HH:mm")  # create str of date to convert
    open_time = acp_times.open_time(km, distance, t)
    close_time = acp_times.close_time(km, distance, t)
    result = {"open": open_time, "close": close_time}
    session["Distance"] = distance
    session["start_time"] = time
    session["start_date"] = date
    return flask.jsonify(result=result)

if __name__ == "__main__":
    app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
    app.run(host='0.0.0.0', debug=True)


import sklearn
from sklearn.utils import shuffle
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
import numpy as np
from sklearn import linear_model, preprocessing

data = pd.read_csv("car.data")
print(data.head())

le = preprocessing.LabelEncoder()
buying = le.fit_transform(list(data["buying"]))
maint = le.fit_transform(list(data["maint"]))
door = le.fit_transform(list(data["door"]))
persons = le.fit_transform(list(data["persons"]))
lug_boot = le.fit_transform(list(data["lug_boot"]))
safety = le.fit_transform(list(data["safety"]))
clss = le.fit_transform(list(data["class"]))
print(buying)

predict = "class"

X = list(zip(buying, maint, door, persons, lug_boot, safety))
Y = list(clss)

x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(X, Y, test_size = 0.1)

model = KNeighborsClassifier(n_neighbors=9)

acc = model.fit(x_train, y_train)
print(acc)

predicted = model.predict(x_test)
names = ["unacc","acc","good","vgood"]

for x in range(len(predicted)):
    print("Predicted: ", names[predicted[x]], " | Data: ", x_test[x], " | Actual: ", names[y_test[x]])


import pandas as pd

df = pd.read_csv("en.csv")
print(df.head())

train_file = open("train.txt", "a")
test_file = open("test.txt","a")

for i in range(len(df)):
    label = df.loc[i]['Label']
    if i <= int(0.8 * len(df)):
        train_file.write("__label__" + str(label) + " , " + df.loc[i]['Text']
                         + "\n")
    else:
        test_file.write("__label__" + str(label) + " , " + df.loc[i]['Text']
                         + "\n")

train_file.close()
test_file.close()


class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        firstRowVal, R, C =1,  len(matrix), len(matrix[0])
        for i in range(R):
            for j in range(C):
                if matrix[i][j] == 0:
                    matrix[0][j] = 0
                    if i != 0:
                        matrix[i][0] = 0
                    else:
                        firstRowVal = 0
        for i in reversed(range(R)):
            for j in reversed(range(C)):
                if i == 0:
                    matrix[i][j] *= firstRowVal
                elif matrix[0][j] == 0 or matrix[i][0] == 0:
                    matrix[i][j] = 0

LeetCode/Python3/Medium/73. Set Matrix Zeroes/0073-set-matrix-zeroes.py


import os
from flask import Blueprint, make_response, g, request, jsonify
from werkzeug.utils import secure_filename
from flask_executor import Executor
from ipr_service.database.actions import db_update_queue_status
from ipr_service.loggers import logger
from ..forms.vector import VectorEmbedForm, VectorDetectForm
from ..context import get_session, clean_working_path
from ..async_ import vector_embed_process, vector_detect_process, async_callback
from ..helpers import parse_read_options, copy_to_output

def _before_requests():
    """Executed before each request for this blueprint.

    Get the request form and session details.

    Returns:
        None|Response: In case of validation error, returns a Flask response, None otherwise.
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    form = VectorEmbedForm() if request.endpoint[7:12] == 'embed' else VectorDetectForm()
    if not form.validate_on_submit():
        return make_response(form.errors, 400)

    session = get_session()

    src_file = os.path.join(os.environ['INPUT_DIR'], form.original.data)

    g.src_file = src_file
    g.form = form
    g.session = session

    g.params = parse_read_options(form)
    if request.endpoint[7:12] != 'embed':
        g.test_file = os.path.join(os.environ['INPUT_DIR'], form.test.data)
        g.test_params = parse_read_options(form, prefix='test_')

def _vector_embed(action, **kwargs):
    """Embed a watermark in vector.

    Arguments:
        action (str): How to embed the watermark; one of 'fictitious', 'geometries'.
        **kwargs: Vector specific read parameters.

    Returns:
        (flask.response): Flask response.
    """
    if g.form.response.data == 'prompt':
        session, export, success, error_msg = vector_embed_process(action, g.session, g.src_file, g.form.uuid.data, **kwargs)
        if not success:
            db_update_queue_status(g.session['ticket'], completed=True, success=False, error_msg=error_msg)
            return make_response({'error': error_msg}, 500)
        path = copy_to_output(export, session['ticket'])
        db_update_queue_status(session['ticket'], completed=True, success=True, result=path)
        return make_response({'type': 'prompt', 'path': path}, 200)

    future = executor.submit(vector_embed_process, action, g.session, g.src_file, g.form.uuid.data, **kwargs)
    future.add_done_callback(async_callback)
    ticket = g.session['ticket']
    return make_response({'type': 'deferred', 'ticket': ticket, 'statusUri': "/jobs/status?ticket={ticket}".format(ticket=ticket)}, 202)

def _vector_detect(action, **kwargs):
    """Check a vector dataset for embedded uuids.

    Arguments:
        action (str): How the watermark was embedded; one of 'fictitious', 'geometries'.
        **kwargs: Vector specific read parameters.

    Returns:
        (flask.response): Flask response.
    """
    if g.form.response.data == 'prompt':
        session, uuid, success, error_msg = vector_detect_process(action, g.session, g.src_file, g.test_file, g.form.uuids.data, **kwargs)
        if not success:
            db_update_queue_status(g.session['ticket'], completed=True, success=False, error_msg=error_msg)
            return make_response({'error': error_msg}, 500)
        db_update_queue_status(session['ticket'], completed=True, success=True, result=uuid)
        return make_response({'type': 'prompt', 'key': uuid}, 200)

    future = executor.submit(vector_detect_process, action, g.session, g.src_file, g.test_file, g.form.uuids.data, **kwargs)
    future.add_done_callback(async_callback)
    ticket = g.session['ticket']
    return make_response({'type': 'deferred', 'ticket': ticket, 'statusUri': "/jobs/status?ticket={ticket}".format(ticket=ticket)}, 202)

# FLASK ROUTES

executor = Executor()
bp = Blueprint('vector', __name__, url_prefix='/vector')
bp.before_request(_before_requests)
bp.teardown_request(clean_working_path)

@bp.route('/embed/fictitious', methods=['POST'])
def embed_fictitious():
    """**Flask POST rule**.

    Embed fictitious entries in the dataset.
    ---
    post:
        summary: Embed fictitious entries.
        description: Embed fictitious entries in the dataset, according to the given unique key.
        tags:
            - Vector
            - Tabular
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: vectorEmbedForm
        responses:
            200: promptEmbedResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    return _vector_embed('fictitious', **g.params)

@bp.route('/embed/geometries', methods=['POST'])
def embed_geoms():
    """**Flask POST rule**.

    Embed collinear points in selected geometries of the dataset.
    ---
    post:
        summary: Embed collinear points in selected geometries.
        description: Embed collinear points in selected geometries of the dataset, according to the given unique key.
        tags:
            - Vector
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: vectorEmbedForm
        responses:
            200: promptEmbedResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    return _vector_embed('geometries', **g.params)

@bp.route('/detect/fictitious', methods=['POST'])
def detect_fictitious():
    """**Flask POST rule**.

    Detect fictitious entries in the dataset, applying the given keys.
    ---
    post:
        summary: Detect fictitious entries.
        description: Detect fictitious entries in the dataset, applying the given keys.
        tags:
            - Vector
            - Tabular
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: vectorDetectForm
        responses:
            200: promptDetectResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    return _vector_detect('fictitious', original_params=g.params, test_params=g.test_params)

@bp.route('/detect/geometries', methods=['POST'])
def detect_geoms():
    """**Flask POST rule**.

    Detect embedded collinear points in selected geometries of the dataset, applying the given keys.
    ---
    post:
        summary: Detect embedded collinear points in selected geometries.
        description: Detect embedded collinear points in selected geometries of the dataset, applying the given keys.
        tags:
            - Vector
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: vectorDetectForm
        responses:
            200: promptDetectResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    return _vector_detect('geometries', original_params=g.params, test_params=g.test_params)


"""
FPMC
"""

import numpy as np
import tensorflow.compat.v1 as tf
import tensorflow
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

class FPMC():
    def __init__(self, args,data_config):
        self.model_type='FPMC'

        self.n_items=data_config['n_items']
        self.n_users=data_config['n_users']
        self.max_len=args.max_len
        self.gru_layers=eval(args.gru_layers)

        self.emb_dim=args.embed_size

        self.lr=args.lr

        self.batch_size=args.batch_size
        self.regs=eval(args.regs)
        self.pairwise_loss=False

        # 定义输入placeholder
        self.users=tf.placeholder(tf.int32,shape=[None,None],name='users') # [N,1]
        self.hist=tf.placeholder(tf.int32,shape=[None,None],name='hist') # [N,max_len] max_len为MC中的阶数
        self.pos_items=tf.placeholder(tf.int32,shape=[None,None],name='pos_items') # [N,1]
        self.neg_items=tf.placeholder(tf.int32,shape=[None,None],name='neg_items') # [N,1]
        self.drop_rate=tf.placeholder(tf.float32,name='dropout_rate') # 丢弃的比例

        # 初始化模型参数
        self.weights=self._init_weights()

        # 构造模型
        self._forward()

    # 初始化参数
    def _init_weights(self):
        all_weights=dict()
        initializer=tensorflow.contrib.layers.xavier_initializer()
        # 分别是 UI HI IU IH R=<UI,IU>+<HI,IH>
        all_weights['user_embedding']=tf.Variable(initializer([self.n_users,self.emb_dim]),name='user_embedding')
        all_weights['history_hi_embedding']=tf.Variable(initializer([self.n_items+1,self.emb_dim]),name='history_hi_embedding')
        all_weights['target_iu_embedding']=tf.Variable(initializer([self.n_items+1,self.emb_dim]),name='target_iu_embedding')
        all_weights['target_ih_embedding']=tf.Variable(initializer([self.n_items+1,self.emb_dim]),name='target_ih_embedding')

        print('using xavier initialization')
        # 位置嵌入
        all_weights['position_embedding']=tf.Variable(initializer([self.max_len,self.emb_dim]),name='position_embedding')

        return all_weights

    # 构造模型
    def _forward(self):
        # 1 得到四种嵌入
        u_embeddings_ui=tf.nn.embedding_lookup(self.weights['user_embedding'],self.users) # [N,1,k]
        his_embeddings_hi=self._get_mask_emb(self.weights['history_hi_embedding'],self.hist,self.n_items) # [N,max_len,k]

        pos_embeddings_iu=self._get_mask_emb(self.weights['target_iu_embedding'],self.pos_items,self.n_items) # [N,1,k]
        pos_embeddings_ih=self._get_mask_emb(self.weights['target_ih_embedding'],self.pos_items,self.n_items) # [N,1,k]

        neg_embeddings_iu=self._get_mask_emb(self.weights['target_iu_embedding'],self.neg_items,self.n_items) # [N,1,k]
        neg_embeddings_ih=self._get_mask_emb(self.weights['target_ih_embedding'],self.neg_items,self.n_items) # [N,1,k]

        #print(u_embeddings_ui.shape)
        #print(his_embeddings_hi.shape)

        # 2 计算对pos neg的预测评分
        pos_preidct_scores=self._get_predict_score(u_embeddings_ui,his_embeddings_hi,pos_embeddings_iu,pos_embeddings_ih)
        neg_preidct_scores=self._get_predict_score(u_embeddings_ui,his_embeddings_hi,neg_embeddings_iu,neg_embeddings_ih)
        self.batch_ratings=pos_preidct_scores

        # 4 构造损失函数
        if(self.pairwise_loss):
            cf_loss=tf.log(tf.nn.sigmoid(pos_preidct_scores-neg_preidct_scores)+1e-24)
            cf_loss=-(tf.reduce_mean(cf_loss)) # [N,target_num] -> 1
        else:
            pos_preidct_scores=tf.nn.sigmoid(pos_preidct_scores) # [N,1]
            neg_preidct_scores=tf.nn.sigmoid(neg_preidct_scores) # [N,neg_num]
            cf_loss_list=[-tf.math.log(pos_preidct_scores+1e-24),-tf.math.log(1-neg_preidct_scores+1e-24)]
            cf_loss=tf.reduce_mean(tf.concat(cf_loss_list,axis=1))

        reg_loss=tf.nn.l2_loss(u_embeddings_ui)+tf.nn.l2_loss(his_embeddings_hi)+\
        tf.nn.l2_loss(pos_embeddings_iu)+tf.nn.l2_loss(pos_embeddings_ih)+\
        tf.nn.l2_loss(neg_embeddings_iu)+tf.nn.l2_loss(neg_embeddings_ih)

        reg_loss=reg_loss*self.regs[0]

        self.loss=cf_loss+reg_loss
        # 5 优化
        self.opt=tf.train.AdamOptimizer(learning_rate=self.lr).minimize(self.loss)

    # 获取ids的嵌入 其中等于pad_id的位置返回0
    def _get_mask_emb(self,embeddings,ids,pad_id):
        outputs=tf.nn.embedding_lookup(embeddings,ids) # [N,max_len,k]
        mask=tf.cast(tf.not_equal(ids,pad_id),tf.float32) # [N,max_len]
        mask=tf.expand_dims(mask,axis=-1) # [N,max_len,1]
        return tf.multiply(outputs,mask) # [N,max_len,k]

    # 根据hist表示和target表示预测评分
    def _get_predict_score(self,ui,hi,iu,ih):
        # [N,1,k],[N,s_len,k] [N,neg_num,k] [N,neg_num,k]
        #print(hist_e.get_shape())
        logit_ui=tf.matmul(ui,tf.transpose(iu,perm=[0,2,1])) # [N,1,k]*[N,k,neg_num] -> [N,1,neg_num]
        logit_ui=tf.reduce_sum(logit_ui,axis=1,keepdims=False) # [N,1,neg_num] -> [N,neg_num]

        logit_hi=tf.matmul(hi,tf.transpose(ih,perm=[0,2,1])) # [N,s_len,k]*[N,k,neg_num] -> [N,s_len,neg_num]
        logit_hi=tf.reduce_sum(logit_hi,axis=1,keepdims=False) # [N,s_len,neg_num] -> [N,neg_num]

        #logit_ui=tf.multiply(ui,iu) # [N,1,k]
        #logit_ui=tf.reduce_sum(logit_ui,axis=2,keepdims=False) # [N,1,k] -> [N,1]

        #logit_hi=tf.multiply(hi,ih) # [N,len,k]
        #logit_hi=tf.reduce_sum(logit_hi,axis=2,keepdims=False) # [N,len,k] -> [N,len]
        #logit_hi=tf.reduce_sum(logit_hi,axis=1,keepdims=True) # [N,len] -> [N,1]

        return logit_ui+logit_hi # [N,target_num]

    # 训练
    def train(self,sess,feed_dict):
        return sess.run([self.opt,self.loss],feed_dict=feed_dict)

    # 预测
    def predict(self,sess,feed_dict):
        return sess.run(self.batch_ratings,feed_dict=feed_dict)


from datetime import (
    datetime,
    timezone,
)
import json
from typing import (
    Optional,
    Union,
)

from google.auth.transport.urllib3 import (
    AuthorizedHttp,
)
from google.cloud.bigquery_reservation_v1 import (
    Assignment,
    CapacityCommitment,
    Reservation,
    ReservationServiceClient,
)
from google.cloud.bigquery_reservation_v1.services.reservation_service.pagers import (
    ListAssignmentsPager,
    ListCapacityCommitmentsPager,
    ListReservationsPager,
)
from google.oauth2.service_account import (
    Credentials,
)
import urllib3

from azul import (
    cached_property,
    config,
    logging,
    require,
)
from azul.deployment import (
    aws,
)
from azul.http import (
    http_client,
)

log = logging.getLogger(__name__)

# FIXME: BigQuery slot management assumes all slots are in the same region
#        https://github.com/DataBiosphere/azul/issues/3454
class BigQueryReservation:
    slots = config.bigquery_reserved_slots

    _reservation_id = 'default'

    _rest_api_url = 'https://content-bigqueryreservation.googleapis.com/v1/'

    _http_scopes = ['https://www.googleapis.com/auth/bigquery']

    _path_suffixes = {
        'capacity_commitment': '',
        'reservation': '',
        'assignment': '/reservations/-'
    }

    capacity_commitment_name: Optional[str]
    reservation_name: Optional[str]
    assignment_name: Optional[str]

    def __init__(self, *, dry_run: bool = False):
        """
        :param dry_run: If true, methods will not create/update/destroy any
                        cloud resources.
        """
        self.dry_run = dry_run
        self.refresh()

    def refresh(self):
        for resource_type, path_suffix in self._path_suffixes.items():
            self._refresh(resource_type)

    def _refresh(self, resource_type):
        pager_method = getattr(self._client, f'list_{resource_type}s')
        path_suffix = self._path_suffixes[resource_type]
        pager = pager_method(parent=self._reservation_parent_path + path_suffix)
        setattr(self, f'{resource_type}_name', self._single_resource_name(pager))

    @cached_property
    def credentials(self) -> Credentials:
        with aws.service_account_credentials() as file_name:
            credentials = Credentials.from_service_account_file(file_name)
        return credentials.with_scopes(self._http_scopes)

    @cached_property
    def _client(self) -> ReservationServiceClient:
        return ReservationServiceClient(credentials=self.credentials)

    @cached_property
    def _http_client(self) -> urllib3.PoolManager:
        return AuthorizedHttp(self.credentials, http_client())

    @property
    def _project(self) -> str:
        return self.credentials.project_id

    @property
    def _reservation_parent_path(self) -> str:
        return self._client.common_location_path(project=self._project,
                                                 location=config.tdr_source_location)

    @property
    def is_active(self) -> Optional[bool]:
        resources = {
            self.capacity_commitment_name,
            self.reservation_name,
            self.assignment_name
        }
        if resources == {None}:
            return False
        elif None not in resources:
            return True
        else:
            return None

    @property
    def update_time(self) -> Optional[float]:
        """
        The time at which the current Reservation was updated as a Unix
        timestamp, or None if is there is no Reservation.
        """
        if self.reservation_name is None:
            return None
        else:
            # The `Reservation` class used elsewhere does not expose the
            # `creationTime` or `updateTime` fields.
            # FIXME: Remove workaround for missing creation_time in BQ
            #        Reservation
            #        https://github.com/DataBiosphere/azul/issues/3360
            response = self._http_client.request('GET',
                                                 self._rest_api_url + self.reservation_name)
            require(response.status == 200, response.status, response.data)
            response = json.loads(response.data)
            update_time = response['updateTime']
            update_time = datetime.strptime(update_time, '%Y-%m-%dT%H:%M:%S.%fZ')
            assert update_time.tzinfo is None
            return update_time.replace(tzinfo=timezone.utc).timestamp()

    def activate(self) -> None:
        self._purchase_capacity_commitment()
        self._create_reservation()
        self._assign_slots()
        self.refresh()
        if not self.dry_run and not self.is_active:
            raise RuntimeError('Failed to activate slots')

    def _purchase_capacity_commitment(self) -> None:
        """
        Idempotently purchase capacity commitment.
        """
        self._refresh('capacity_commitment')
        if self.capacity_commitment_name is not None:
            log.info('Slot commitment already purchased')
        else:
            commitment = CapacityCommitment(dict(slot_count=self.slots,
                                                 plan=CapacityCommitment.CommitmentPlan.FLEX))
            if self.dry_run:
                log.info('Would purchase %d BigQuery slots', commitment.slot_count)
            else:
                log.info('Purchasing %d BigQuery slots', commitment.slot_count)
                commitment = self._client.create_capacity_commitment(capacity_commitment=commitment,
                                                                     parent=self._reservation_parent_path)
                log.info('Purchased %d BigQuery slots, commitment name: %r',
                         commitment.slot_count, commitment.name)
                self.capacity_commitment_name = commitment.name

    def _create_reservation(self) -> None:
        """
        Idempotently create reservation.
        """
        self._refresh('reservation')
        if self.reservation_name is not None:
            log.info('Reservation already created')
        else:
            reservation = Reservation(dict(slot_capacity=self.slots,
                                           ignore_idle_slots=False))
            if self.dry_run:
                log.info('Would reserve %d BigQuery slots, reservation ID: %r',
                         reservation.slot_capacity, self._reservation_id)
            else:
                log.info('Reserving %d BigQuery slots, reservation ID: %r',
                         reservation.slot_capacity, self._reservation_id)
                reservation = self._client.create_reservation(reservation=reservation,
                                                              reservation_id=self._reservation_id,
                                                              parent=self._reservation_parent_path)
                log.info('Reserved %d BigQuery slots, reservation name: %r',
                         reservation.slot_capacity, reservation.name)
                self.reservation_name = reservation.name

    def _assign_slots(self) -> None:
        """
        Idempotently assign capacity commitment to a reservation.
        """
        self._refresh('assignment')
        if self.assignment_name is not None:
            log.info('Slots already assigned')
        else:
            assignment = Assignment(dict(assignee=f'projects/{self._project}',
                                         job_type=Assignment.JobType.QUERY))
            if self.dry_run:
                log.info('Would assign slots to reservation %r', self.reservation_name)
            else:
                require(self.reservation_name is not None)
                log.info('Assigning slots to reservation %r', self.reservation_name)
                assignment = self._client.create_assignment(parent=self.reservation_name,
                                                            assignment=assignment)
                log.info('Assigned slots, assignment name: %r', assignment.name)
                self.assignment_name = assignment.name

    def deactivate(self) -> None:
        """
        Idempotently delete all resources.
        """
        for resource_type in ('assignment', 'reservation', 'capacity_commitment'):
            attr_name = resource_type + '_name'
            resource_name = getattr(self, attr_name)
            if resource_name is None:
                log.info('%r does not exist', resource_type)
            else:
                resource_str = f'{resource_type}:{resource_name}'
                if self.dry_run:
                    log.info('Would delete resource %r', resource_str)
                else:
                    delete_method = getattr(self._client, 'delete_' + resource_type)
                    delete_method(name=resource_name)
                    log.info('Deleted resource %r', resource_str)
        self.refresh()
        if not self.dry_run and self.is_active is not False:
            raise RuntimeError('Failed to delete slots')

    ResourcePager = Union[ListCapacityCommitmentsPager,
                          ListReservationsPager,
                          ListAssignmentsPager]

    def _single_resource_name(self, resources: ResourcePager) -> Optional[str]:
        resources = [resource.name for resource in resources]
        try:
            resource_name, *extras = resources
        except ValueError:
            return None
        else:
            require(not extras,
                    'Too many resources in path (should be 0 or 1)',
                    self._reservation_parent_path, resources)
            return resource_name


## yapCAD poly() intersecton and drawing examples

from yapcad.geom import *
from yapcad.poly import *
import examples.example10 as example10
import random

def drawLegend(d):
    ## Put some documentary text on the drawing
    d.layer = 'DOCUMENTATION'

    att = {'style': 'OpenSans-Bold',
           'height': 2.5}

    d.draw_text("yapCAD", point(5,15), attr = att)

    d.draw_text("example8.py", point(5,11), attr=att)
    d.draw_text("Polygon() flowers, mirrored geometry",
                point(5,7),attr=att)
    d.layer = False # back to default layer

def flower(center = point(0,0),
           petals = 10,
           minDiam=5.0,
           maxDiam=15,
           minRadius=20,
           maxRadius=40,
           insideRad = 5, returnPoly = False):

    glist= []
    for i in range(petals):
        angle = i*360/petals
        anrad = angle*pi2/360.0

        an2 = (((i+0.5)/petals)%1.0)*360
        an2rad = an2*pi2/360.0

        radius = (maxRadius-minRadius)*random.random()+minRadius
        diam = (maxDiam-minDiam)*random.random()+minDiam
        pnt = add(point(cos(anrad)*radius,sin(anrad)*radius),
                  center)
        pnt2 = add(point(cos(an2rad)*insideRad,sin(an2rad)*insideRad),
                   center)
        a = arc(pnt,diam/2)
        glist.append(a)
        glist.append(pnt2)

    p = Polygon(glist)
    #p.makeoutline()
    if returnPoly:
        return p
    else:
        return p.geom()

def mirrorArray(pnt=point(-45,45)):
    flwr = flower(pnt,returnPoly=True)
    glist = flwr.geom()
    bb = bbox(glist)
    flwr2 = deepcopy(flwr)
    flwr2.grow(1.0)
    glist.append(flwr2.geom())

    ranp = example10.randomPoints(bb,500)

    for p in ranp:
        if flwr.isinside(p):
            glist.append(arc(p,0.4))

    ply = [point(bb[0]), point(bb[1][0],bb[0][1]),
           point(bb[1]), point(bb[0][0],bb[1][1])]
    glist = glist + ply
    glist = glist + mirror(glist,'yz')
    glist = glist + mirror(glist,'xz')
    return glist

if __name__ == "__main__":

    from yapcad.ezdxf_drawable import *
    #set up DXF rendering

    print("example8.py -- yapCAD computational geometry and DXF drawing example")
    print("""
This is a demo of the Polygon() and mirror capabilities of yapCAD,
making and then mirroring random "flowers."
    """)
    dd=ezdxfDraw()
    filename="example8-out"
    print("Output file name is {}.dxf".format(filename))
    dd.filename = filename

    glist = mirrorArray()

    def mydrawer(gl):
        g1=[]
        g2=[]
        for g in gl:
            if iscircle(g):
                g1.append(g)
            else:
                g2.append(g)
        dd.linecolor = 'white'
        dd.draw(g2)
        dd.linecolor = 'aqua'
        dd.draw(g1)

    drawLegend(dd)
    mydrawer(glist)
    dd.display()


import os
import pprint
import random
import numpy as np
import torch
import torch.nn.parallel
import torch.optim
import itertools
import argparse

import torch.utils.data
import torch.utils.data.distributed
import torch.distributed as dist
from torch.cuda.amp import autocast as autocast

from config.config import config, update_config

from model.corr_clip_spatial_transformer2_anchor_2heads_hnm import ClipMatcher
from utils import exp_utils, train_utils, dist_utils
from dataset import dataset_utils
from func.train_anchor import train_epoch, validate

import transformers
import wandb

def parse_args():
    parser = argparse.ArgumentParser(description='Train hand reconstruction network')
    parser.add_argument(
        '--cfg', help='experiment configure file name', required=True, type=str)
    parser.add_argument(
        "--eval", dest="eval", action="store_true",help="evaluate model")
    parser.add_argument(
        '--local_rank', default=-1, type=int, help='node rank for distributed training')
    args, rest = parser.parse_known_args()
    update_config(args.cfg)
    return args

def main():
    # Get args and config
    args = parse_args()
    logger, output_dir, tb_log_dir = exp_utils.create_logger(config, args.cfg, phase='train')
    logger.info(pprint.pformat(args))
    logger.info(pprint.pformat(config))

    # set random seeds
    torch.cuda.manual_seed_all(config.seed)
    torch.manual_seed(config.seed)
    np.random.seed(config.seed)
    random.seed(config.seed)

    # set device
    gpus = range(torch.cuda.device_count())
    distributed = torch.cuda.device_count() > 1
    device = torch.device('cuda') if len(gpus) > 0 else torch.device('cpu')
    if "LOCAL_RANK" in os.environ:
        dist_utils.dist_init(int(os.environ["LOCAL_RANK"]))
    local_rank = dist.get_rank()
    torch.cuda.set_device(local_rank)

    if local_rank == 0:
        wandb_name = config.exp_name
        wandb_proj_name = config.exp_group
        wandb_run = wandb.init(project=wandb_proj_name, group=wandb_name)#, name='smooth-puddle-94', resume=True)
        wandb.config.update({
            "exp_name": config.exp_name,
            "batch_size": config.train.batch_size,
            "total_iteration": config.train.total_iteration,
            "lr": config.train.lr,
            "weight_decay": config.train.weight_decay,
            "loss_weight_bbox_giou": config.loss.weight_bbox_giou,
            "loss_prob_bce_weight": config.loss.prob_bce_weight,
            "model_num_transformer": config.model.num_transformer,
            "model_resolution_transformer": config.model.resolution_transformer,
            "model_window_transformer": config.model.window_transformer,
        })
    else:
        wandb_run = None

    # get model
    model = ClipMatcher(config).to(device)
    #model = torch.compile(model)

    # get optimizer
    optimizer = train_utils.get_optimizer(config, model)
    # schedular = train_utils.get_schedular(config, optimizer)
    schedular = transformers.get_linear_schedule_with_warmup(optimizer,
                                                             num_warmup_steps=config.train.schedular_warmup_iter,
                                                             num_training_steps=config.train.total_iteration)
    scaler = torch.cuda.amp.GradScaler()

    best_iou, best_prob = 0.0, 0.0
    ep_resume = None
    if config.train.resume:
        try:
            model, optimizer, schedular, scaler, ep_resume, best_iou, best_prob = train_utils.resume_training(
                                                                                model, optimizer, schedular, scaler,
                                                                                output_dir,
                                                                                cpt_name='cpt_last.pth.tar')
            print('LR after resume {}'.format(optimizer.param_groups[0]['lr']))
        except:
            print('Resume failed')

    # distributed training
    ddp = False
    model =  torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)
    if device == torch.device("cuda"):
        torch.backends.cudnn.benchmark = True
        device_ids = range(torch.cuda.device_count())
        print("using {} cuda".format(len(device_ids)))
        model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[local_rank], find_unused_parameters=True)
        device_num = len(device_ids)
        ddp = True

    # get dataset and dataloader
    train_data = dataset_utils.get_dataset(config, split='train')
    train_sampler = torch.utils.data.distributed.DistributedSampler(train_data)
    train_loader = torch.utils.data.DataLoader(train_data,
                                               batch_size=config.train.batch_size,
                                               shuffle=False,
                                               num_workers=int(config.workers),
                                               pin_memory=True,
                                               drop_last=True,
                                               sampler=train_sampler)
    val_data = dataset_utils.get_dataset(config, split='val')
    val_loader = torch.utils.data.DataLoader(val_data,
                                               batch_size=config.test.batch_size,
                                               shuffle=False,
                                               num_workers=int(config.workers),
                                               pin_memory=True,
                                               drop_last=False)

    start_ep = ep_resume if ep_resume is not None else 0
    end_ep = 100000000 #int(config.train.total_iteration / len(train_loader)) + 1

    # train
    for epoch in range(start_ep, end_ep):
        train_sampler.set_epoch(epoch)
        train_epoch(config,
                    loader=train_loader,
                    model=model,
                    optimizer=optimizer,
                    schedular=schedular,
                    scaler=scaler,
                    epoch=epoch,
                    output_dir=output_dir,
                    device=device,
                    rank=local_rank,
                    ddp=ddp,
                    wandb_run=wandb_run
                    )
        torch.cuda.empty_cache()

        if local_rank == 0:
            train_utils.save_checkpoint(
                    {
                        'epoch': epoch + 1,
                        'state_dict': model.module.state_dict(),
                        'optimizer': optimizer.state_dict(),
                        'schedular': schedular.state_dict(),
                        'scaler': scaler.state_dict(),
                    },
                    checkpoint=output_dir, filename="cpt_last.pth.tar")

        if epoch % 5 == 0:
            print('Doing validation...')
            iou, prob = validate(config,
                                loader=val_loader,
                                model=model,
                                epoch=epoch,
                                output_dir=output_dir,
                                device=device,
                                rank=local_rank,
                                ddp=ddp,
                                wandb_run=wandb_run
                                )
            torch.cuda.empty_cache()
            if iou > best_iou:
                best_iou = iou
                if local_rank == 0:
                    train_utils.save_checkpoint(
                    {
                        'epoch': epoch + 1,
                        'state_dict': model.module.state_dict(),
                        'optimizer': optimizer.state_dict(),
                        'schedular': schedular.state_dict(),
                        'scaler': scaler.state_dict(),
                        'best_iou': best_iou,
                    },
                    checkpoint=output_dir, filename="cpt_best_iou.pth.tar")

            if prob > best_prob:
                best_prob = prob
                if local_rank == 0:
                    train_utils.save_checkpoint(
                    {
                        'epoch': epoch + 1,
                        'state_dict': model.module.state_dict(),
                        'optimizer': optimizer.state_dict(),
                        'schedular': schedular.state_dict(),
                        'scaler': scaler.state_dict(),
                        'best_prob': best_prob,
                    },
                    checkpoint=output_dir, filename="cpt_best_prob.pth.tar")

            logger.info('Rank {}, best iou: {} (current {}), best probability accuracy: {} (current {})'.format(local_rank, best_iou, iou, best_prob, prob))
        dist.barrier()
        torch.cuda.empty_cache()

if __name__ == '__main__':
    main()


#%%
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
     ----- MNSD with LIF-SL-I -----
Multi-Neuron Spike Detector with Leaky and Integrate-Fire
with Spike Latency and Intrinsic Plasticity

@author: Alejandro Santos-Mayo // Complutense University of Madrid (UCM)
"""

import nest
import nest.raster_plot
import numpy as np
import matplotlib.pyplot as plt
if not 'lifl_psc_exp_ie' in nest.Models():
    nest.Install('LIFL_IEmodule')

nest.ResetKernel()
nest.SetKernelStatus({'resolution' : 0.1})  # Time resolution set at 0.1 ms

# First of all, we create the dc generator for ordered inputs
E1 = nest.Create("dc_generator"); E2 = nest.Create("dc_generator"); E3 = nest.Create("dc_generator"); E4 = nest.Create("dc_generator")
# Neurons which send the initial supra-threshold input. Connections between Generator-Neuron.
N1 = nest.Create('iaf_psc_alpha'); N2 = nest.Create('iaf_psc_alpha'); N3 = nest.Create('iaf_psc_alpha'); N4 = nest.Create('iaf_psc_alpha')
nest.Connect(E1,N1, {"rule": "one_to_one"}, {"weight": 725.5});
nest.Connect(E2,N2, {"rule": "one_to_one"}, {"weight": 725.5});
nest.Connect(E3,N3, {"rule": "one_to_one"}, {"weight": 725.5});
nest.Connect(E4,N4, {"rule": "one_to_one"}, {"weight": 725.5});

# Main leaky integrate and fire with spike latency and intrinsic plasticity.
D1 = nest.Create('lifl_psc_exp_ie', 1, { 'lambda': 0.0005 }) # plasticity parameter lambda
D2 = nest.Create('lifl_psc_exp_ie', 1, { 'lambda': 0.0005 }) # Tau parameter is 12.5 as default
D3 = nest.Create('lifl_psc_exp_ie', 1, { 'lambda': 0.0005 })
D4 = nest.Create('lifl_psc_exp_ie', 1, { 'lambda': 0.0005 })
nest.Connect(N1, D1, {"rule": "one_to_one"}, {"weight": 3700.0}) # Connections Source Neuron <-> Detector (LIF_SL_IP)
nest.Connect(N2, D2, {"rule": "one_to_one"}, {"weight": 3700.0})
nest.Connect(N3, D3, {"rule": "one_to_one"}, {"weight": 3700.0})
nest.Connect(N4, D4, {"rule": "one_to_one"}, {"weight": 3700.0})

# We set the GID of neurons which modulate the Intrinsic Plasticity of the neuron.
nest.SetStatus(D1, {'stimulator': [D2[0]]});
nest.SetStatus(D2, {'stimulator': [D3[0], D1[0]]});
nest.SetStatus(D3, {'stimulator': [D2[0], D4[0]]});
nest.SetStatus(D4, {'stimulator': [D3[0]]});

# Target neuron. Connections are set in order to produce a target spike only in pattern detection.
Target = nest.Create('lifl_psc_exp_ie', 1, {'I_e' : 0.0, "tau_minus": 10.0})
nest.Connect(D1,Target, {"rule": "one_to_one"}, {"weight": 410.0});
nest.Connect(D2,Target, {"rule": "one_to_one"}, {"weight": 410.0});
nest.Connect(D3,Target, {"rule": "one_to_one"}, {"weight": 410.0});
nest.Connect(D4,Target, {"rule": "one_to_one"}, {"weight": 410.0});

# Connections between
nest.Connect(D1,D2, {"rule": "one_to_one"}, { "model": "stdp_synapse", 'delay': 0.1});
nest.Connect(D2,D1, {"rule": "one_to_one"}, { "model": "stdp_synapse", 'delay': 0.1});
nest.Connect(D2,D3, {"rule": "one_to_one"}, { "model": "stdp_synapse", 'delay': 0.1});
nest.Connect(D3,D2, {"rule": "one_to_one"}, { "model": "stdp_synapse", 'delay': 0.1});
nest.Connect(D3,D4, {"rule": "one_to_one"}, { "model": "stdp_synapse", 'delay': 0.1});
nest.Connect(D4,D3, {"rule": "one_to_one"}, { "model": "stdp_synapse", 'delay': 0.1});

# We create a Detector so that we can get spike times and raster plot
detector = nest.Create('spike_detector');
nest.Connect(D1,detector); nest.Connect(D2, detector); nest.Connect(D3, detector); nest.Connect(D4, detector); nest.Connect(Target, detector);
nest.Connect(N1, detector); nest.Connect(N2, detector); nest.Connect(N3, detector); nest.Connect(N4, detector);
# We create a multim to record the Voltage potential of the membrane (V_m)
# and the excitability parameter of Intrinsic Plasticity (soma_exc)
multim = nest.Create('multimeter', params = {'withtime': True, 'record_from': ['V_m', 'soma_exc'], 'interval': 0.1})
nest.Connect(multim, Target); nest.Connect(multim, D1); nest.Connect(multim, D2); nest.Connect(multim, D3); nest.Connect(multim, D4) #Target

# We create a matrix to save the spike times of each trial
iterations = 300
times = np.zeros((iterations+1, 6)); times[:,4]=range(0,iterations+1)

for i in range(1,iterations): #450
      # First, we set the amplitude to the generator and create a pattern (order) of spikes
    nest.SetStatus(E1, {"amplitude": 0.6575, 'start': (i*1000)-1000+30.0, 'stop': (i*1000)-1000+55.0}) #30 55   0.5635
    nest.SetStatus(E2, {"amplitude": 0.6575, 'start': (i*1000)-1000+33.3, 'stop': (i*1000)-1000+58.3}) #40 65
    nest.SetStatus(E3, {"amplitude": 0.6575, 'start': (i*1000)-1000+36.6, 'stop': (i*1000)-1000+61.6}) #50 75
    nest.SetStatus(E4, {"amplitude": 0.6575, 'start': (i * 1000) - 1000 + 40.0, 'stop': (i * 1000) - 1000 + 65.0})  # 50 75
    nest.SetStatus(D1, {"V_m": -70.0}); nest.SetStatus(D2, {"V_m": -70.0}); nest.SetStatus(D3, {"V_m": -70.0}); nest.SetStatus(D4, {"V_m": -70.0}); nest.SetStatus(Target, {"V_m": -70.0})

    nest.Simulate(1000) # Simulate 1000 ms per trial

    # We get the status of the detector in order to get the spike times and save them
    spikes = nest.GetStatus(detector)[0]['events']
    t_spikes = spikes['times'][spikes['times']>(1000*i)-1000]; sends_spikes = spikes['senders'][len(spikes['senders'])-len(t_spikes):];
    times1 = t_spikes[sends_spikes == 9]; times2 = t_spikes[sends_spikes == 10]; times3 = t_spikes[sends_spikes == 11]; times4 = t_spikes[sends_spikes == 12]
    if len(times1)==1: times[i,0] = times1-(1000*i)+1000; times[i,4] = times[i,4]+1
    if len(times2)==1: times[i,1] = times2-(1000*i)+1000; times[i,4] = times[i,4]+1
    if len(times3)==1: times[i,2] = times3-(1000*i)+1000; times[i,4] = times[i,4]+1
    if len(times4) == 1: times[i, 3] = times4 - (1000 * i) + 1000; times[i, 4] = times[i, 4] + 1

# Raster plot
nest.raster_plot.from_device(detector)

# We get events of multimeter (V_m and Soma_exc)
events = nest.GetStatus(multim)[0]['events']
t = np.linspace(int(min(events['times'])), int(max(events['times']))+1, (int(max(events['times']))+1)*10-1);
v_1 = events['V_m'][events['senders']==9];v_2 = events['V_m'][events['senders']==10];v_3 = events['V_m'][events['senders']==11];v_4 = events['V_m'][events['senders']==12]; v_5 = events['V_m'][events['senders']==13];
se1 = events['soma_exc'][events['senders']==9]-1;se2 = events['soma_exc'][events['senders']==10]-1;se3 = events['soma_exc'][events['senders']==11]-1; se4 = events['soma_exc'][events['senders']==12]-1;
plt.figure(); plt.plot(t, v_1); plt.plot(t, v_2); plt.plot(t, v_3); plt.plot(t, v_4); plt.plot(t, v_5); plt.ylabel('Membrane potential [mV]')

from mpl_toolkits.mplot3d import Axes3D

delta1 = times[:,0]- times[:,1]
delta2 = times[:,0]- times[:,2]
delta3 = times[:,0]- times[:,3]
delta4 = times[:,1]- times[:,2]
delta5 = times[:,1]- times[:,3]
delta6 = times[:,2]- times[:,3]

fig = plt.figure();
ax = Axes3D(fig);
ax.plot(delta1, delta2, delta3)
ax.scatter(delta1, delta2, delta3)
ax.set_xlabel('Time between D1-D2'); ax.set_ylabel('Time between D2-D3'); ax.set_zlabel('Time between D1-D3')

# 3D plot of Intrinsic Plasticity  excitability parameter for each neuron
import matplotlib.pyplot as plt
fig = plt.figure()
#ax = Axes3D(fig)
ax = fig.add_subplot(111, projection='3d')
ax.plot(se1, se2, se3)
ax.scatter(se1, se2, se3, c = se4, cmap = plt.hot(), s= 0.5)
ax.set_xlabel('Intrinsic Excitability D1'); ax.set_ylabel('Intrinsic Excitability D2'); ax.set_zlabel('Intrinsic Excitability D3')
ax.locator_params(axis='y', nbins=6)
ax.locator_params(axis='x', nbins=6)
ax.locator_params(axis='z', nbins=6)

plt.figure();    #  PLOT IE in time
plt.plot(se1)
plt.plot(se2)
plt.plot(se3)
plt.plot(se4)
plt.xticks([0, 1000000, 2000000, 3000000], [0, 100, 200, 300]); plt.xlabel('Training trials'); plt.ylabel('Intrinsic Excitability (IE)')

plt.figure();    #  PLOT DELAY deltas
plt.plot(delta1)
plt.plot(delta2)
plt.plot(delta3)
plt.plot(delta4)
plt.plot(delta5)
plt.plot(delta6)
plt.xlim([1,300]); plt.xticks([1, 100, 200, 300], [0, 100, 200, 300]); plt.xlabel('Training trials'); plt.ylabel('Spike time difference between neurons')

################################################################################
################   TEST new Patterns   #########################################

# In order to test other possible patterns, we swich off the Intrinsic Plasticity mode (std_mod: synaptic time dependent modificator)
nest.SetStatus(D1, {'std_mod': False})
nest.SetStatus(D2, {'std_mod': False})
nest.SetStatus(D3, {'std_mod': False})
nest.SetStatus(D4, {'std_mod': False})

i = iterations + 2; #453
nest.SetStatus(E1, {"amplitude": 0.6575, 'start': (i*1000)-1000+30.0, 'stop': (i*1000)-1000+55.0}) #30 55
nest.SetStatus(E2, {"amplitude": 0.6575, 'start': (i*1000)-1000+33.3, 'stop': (i*1000)-1000+58.3}) #40 65
nest.SetStatus(E3, {"amplitude": 0.6575, 'start': (i*1000)-1000+40.0, 'stop': (i*1000)-1000+65.0}) #50 75
nest.SetStatus(E4, {"amplitude": 0.6575, 'start': (i*1000)-1000+36.6, 'stop': (i*1000)-1000+61.6}) #50 75
nest.SetStatus(D1, {"V_m": -70.0}); nest.SetStatus(D2, {"V_m": -70.0}); nest.SetStatus(D3, {"V_m": -70.0}); nest.SetStatus(Target, {"V_m": -70.0})
nest.Simulate(3000)

i = i+1; #453
nest.SetStatus(E1, {"amplitude": 0.6575, 'start': (i*1000)-1000+40.0, 'stop': (i*1000)-1000+65.0}) #30 55
nest.SetStatus(E2, {"amplitude": 0.6575, 'start': (i*1000)-1000+36.6, 'stop': (i*1000)-1000+61.6}) #40 65
nest.SetStatus(E3, {"amplitude": 0.6575, 'start': (i*1000)-1000+33.3, 'stop': (i*1000)-1000+58.3}) #50 75
nest.SetStatus(E4, {"amplitude": 0.6575, 'start': (i*1000)-1000+30.0, 'stop': (i*1000)-1000+55.0}) #50 75
nest.SetStatus(D1, {"V_m": -70.0}); nest.SetStatus(D2, {"V_m": -70.0}); nest.SetStatus(D3, {"V_m": -70.0}); nest.SetStatus(Target, {"V_m": -70.0})
nest.Simulate(1000)
i = i+1; #453
nest.SetStatus(E3, {"amplitude": 0.6575, 'start': (i*1000)-1000+35.0, 'stop': (i*1000)-1000+60.0}) #30 55
nest.SetStatus(E2, {"amplitude": 0.6575, 'start': (i*1000)-1000+30.0, 'stop': (i*1000)-1000+55.0}) #40 65
nest.SetStatus(E1, {"amplitude": 0.6575, 'start': (i*1000)-1000+40.0, 'stop': (i*1000)-1000+65.0}) #50 75
nest.SetStatus(D1, {"V_m": -70.0}); nest.SetStatus(D2, {"V_m": -70.0}); nest.SetStatus(D3, {"V_m": -70.0}); nest.SetStatus(Target, {"V_m": -70.0})
nest.Simulate(1000)
i = i+1; #453
nest.SetStatus(E1, {"amplitude": 0.6575, 'start': (i*1000)-1000+35.0, 'stop': (i*1000)-1000+60.0}) #30 55
nest.SetStatus(E3, {"amplitude": 0.6575, 'start': (i*1000)-1000+30.0, 'stop': (i*1000)-1000+55.0}) #40 65
nest.SetStatus(E2, {"amplitude": 0.6575, 'start': (i*1000)-1000+40.0, 'stop': (i*1000)-1000+65.0}) #50 75
nest.SetStatus(D1, {"V_m": -70.0}); nest.SetStatus(D2, {"V_m": -70.0}); nest.SetStatus(D3, {"V_m": -70.0}); nest.SetStatus(Target, {"V_m": -70.0})
nest.Simulate(1000)
i = i+1; #453
nest.SetStatus(E2, {"amplitude": 0.6575, 'start': (i*1000)-1000+35.0, 'stop': (i*1000)-1000+60.0}) #30 55
nest.SetStatus(E3, {"amplitude": 0.6575, 'start': (i*1000)-1000+30.0, 'stop': (i*1000)-1000+55.0}) #40 65
nest.SetStatus(E1, {"amplitude": 0.6575, 'start': (i*1000)-1000+40.0, 'stop': (i*1000)-1000+65.0}) #50 75
nest.SetStatus(D1, {"V_m": -70.0}); nest.SetStatus(D2, {"V_m": -70.0}); nest.SetStatus(D3, {"V_m": -70.0}); nest.SetStatus(Target, {"V_m": -70.0})
nest.Simulate(1000)

# We get events of multimeter (V_m and Soma_exc)
events = nest.GetStatus(multim)[0]['events']
t = np.linspace(int(min(events['times'])), int(max(events['times']))+1, (int(max(events['times']))+1)*10-1);
v_1 = events['V_m'][events['senders']==9];v_2 = events['V_m'][events['senders']==10];v_3 = events['V_m'][events['senders']==11];v_4 = events['V_m'][events['senders']==12]; v_5 = events['V_m'][events['senders']==13];
se1 = events['soma_exc'][events['senders']==9]-1;se2 = events['soma_exc'][events['senders']==10]-1;se3 = events['soma_exc'][events['senders']==11]-1; se4 = events['soma_exc'][events['senders']==12]-1;
plt.figure(); plt.plot(t, v_1); plt.plot(t, v_2); plt.plot(t, v_3); plt.plot(t, v_4); plt.plot(t, v_5); plt.ylabel('Membrane potential [mV]')

plt.figure()
ax = plt.subplot2grid((3, 2), (2, 0), )
ax.plot(t, v_1); ax.plot(t, v_2); ax.plot(t, v_3); ax.plot(t, v_4); ax.plot(t, v_5);
ax.set_xlim([303040,303100])
plt.xticks([303040, 303060, 303080, 303100], [0, 20, 40, 60])

ax1 = plt.subplot2grid((3, 2), (2, 1), sharey  = ax)
ax1.plot(t, v_1); ax1.plot(t, v_2); ax1.plot(t, v_3); ax1.plot(t, v_4); ax1.plot(t, v_5);
ax1.set_xlim([304040,304100])
plt.setp(ax1.get_yticklabels(), visible=False)
plt.xticks([304040, 304060, 304080, 304100], [0, 20, 40, 60])

ax2 = plt.subplot2grid((3, 2), (1, 0))
ax2.plot(t, v_1); ax2.plot(t, v_2); ax2.plot(t, v_3); ax2.plot(t, v_4); ax2.plot(t, v_5); plt.ylabel('Membrane potential [mV]')
ax2.set_xlim([302040,302100])
plt.setp(ax2.get_xticklabels(), visible=False)

ax3 = plt.subplot2grid((3, 2), (1, 1), sharey = ax2)
ax3.plot(t, v_1); ax3.plot(t, v_2); ax3.plot(t, v_3); ax3.plot(t, v_4); ax3.plot(t, v_5);
ax3.set_xlim([305040,305100])
plt.setp(ax3.get_xticklabels(), visible=False)
plt.setp(ax3.get_yticklabels(), visible=False)

ax4 = plt.subplot2grid((3, 2), (0, 0))
ax4.plot(t, v_1); ax4.plot(t, v_2); ax4.plot(t, v_3); ax4.plot(t, v_4); ax4.plot(t, v_5);
ax4.set_xlim([298040,298100])
plt.setp(ax4.get_xticklabels(), visible=False)

ax5 = plt.subplot2grid((3, 2), (0, 1), sharey = ax4)
ax5.plot(t, v_1); ax5.plot(t, v_2); ax5.plot(t, v_3); ax5.plot(t, v_4);ax5.plot(t, v_5);
ax5.set_xlim([301040,301100])
plt.setp(ax5.get_xticklabels(), visible=False)
plt.setp(ax5.get_yticklabels(), visible=False)

plt.show()


from enum import Enum

from idgames.engine import Engine
from idgames.game import Game

class KeyType(Enum):
    TEXT = 'text'
    BOOL = 'bool'
    GAME = 'game'
    DIFFICULTY = 'difficulty'
    MAP_NUMBER = 'map_number'
    DATETIME = 'datetime'
    INTEGER = 'integer'
    GAME_STYLE = 'game_style'
    ENGINE = 'engine'

TEXT_KEYS = {
    'authors': {
        'type': KeyType.TEXT,
        'keys': {'author', 'authors', 'author(s)', 'autor', 'original author'},
        'array': True,
    },
    'title': {
        'type': KeyType.TEXT,
        'keys': {'title', 'level name', 'name'},
        'single_line': True,
    },
    'game_style_singleplayer': {
        'type': KeyType.BOOL,
        'keys': {'single player', 'singleplayer'},
    },
    'based_on': {
        'type': KeyType.TEXT,
        'keys': {'base', 'idea base'},
    },
    'description': {
        'type': KeyType.TEXT,
        'keys': {'description', 'instructions', 'play information', 'wad description', 'log entry'},
    },
    'difficulty_levels': {
        'type': KeyType.DIFFICULTY,
        'keys': {'difficulty settings', 'difficulty'},
    },
    'game_style_cooperative': {
        'type': KeyType.BOOL,
        'keys': {'cooperative 2-4 player', 'cooperative', 'cooperative 2-8 player', 'co-op', 'coop 2-4 player', 'coop'},
    },
    'game_style_deathmatch': {
        'type': KeyType.BOOL,
        'keys': {'deathmatch 2-4 player', 'deathmatch', 'deathmatch 2-8 player'},
    },
    'tools_used': {
        'type': KeyType.TEXT,
        'keys': {
            'editor(s) used', 'editors used', 'editor used', 'tools used', 'editors', 'utilities used', 'editor',
            'main editor(s) used', 'tools(s) used',
        },
    },
    'email': {
        'type': KeyType.TEXT,
        'keys': {'email address', 'e-mail', 'e-mail address', 'email'},
    },
    'known_bugs': {
        'type': KeyType.TEXT,
        'keys': {'known bugs', 'bugs', 'unknown bugs'},
    },
    'copyright': {
        'type': KeyType.TEXT,
        'keys': {'copyright / permissions'},
    },
    'filename': {
        'type': KeyType.TEXT,
        'keys': {'filename'},
    },
    'credits': {
        'type': KeyType.TEXT,
        'keys': {
            'additional credits to', 'additional credits', 'credits', 'credits to', 'special thanks to', 'thanks to',
            'big thanks to', 'special thanks', 'additional credit to',
        },
    },
    'build_time': {
        'type': KeyType.TEXT,
        'keys': {'build time', 'time taken', 'construction time', 'time', 'building time'},
    },
    'author_info': {
        'type': KeyType.TEXT,
        'keys': {'misc. author info', 'misc author info', 'author info', 'misc. developer info'},
    },
    'other': {
        'type': KeyType.TEXT,
        'keys': {'other'},
    },
    'game': {
        'type': KeyType.GAME,
        'keys': {'game', 'required game', 'game version required', 'iwad needed', 'doom version', 'game and version used'},
    },
    'content_graphics': {
        'type': KeyType.BOOL,
        'keys': {
            'new graphics', 'graphics', 'graphic addon only', 'sprites', 'textures', 'sprite edit', 'new sprites',
            'new textures',
        },
    },
    'content_sounds': {
        'type': KeyType.BOOL,
        'keys': {'new sounds', 'sounds', 'sound pwad only'},
    },
    'music': {
        'type': KeyType.TEXT,
        'keys': {'music', 'music track'},
    },
    'map_number': {
        'type': KeyType.MAP_NUMBER,
        'keys': {'map #', 'episode and level #', 'level #', 'level', 'map', 'map number'},
    },
    'content_demos': {
        'type': KeyType.BOOL,
        'keys': {'demos replaced', 'demos', '.lmp only', 'new demos'},
    },
    'content_music': {
        'type': KeyType.BOOL,
        'keys': {'new music', 'music pwad only', 'midi', 'new musics'},
    },
    'date_released': {
        'type': KeyType.DATETIME,
        'keys': {'release date', 'date', 'date released', 'date of release'},
    },
    'content_dehacked': {
        'type': KeyType.BOOL,
        'keys': {'dehacked/bex patch', 'dehack patch only'},
    },
    'game_style_primary': {
        'type': KeyType.GAME_STYLE,
        'keys': {'primary purpose'},
    },
    'game_style_other': {
        'type': KeyType.GAME_STYLE,
        'keys': {'other game styles'},
    },
    'other_files_required': {
        'type': KeyType.TEXT,
        'keys': {'other files required', 'required to have in dir'},
    },
    'author_other_files': {
        'type': KeyType.TEXT,
        'keys': {'other files by author'},
    },
    'engine': {
        'type': KeyType.ENGINE,
        'keys': {'advanced engine needed', 'source port', 'engine', 'port'},
    },
    'links': {
        'type': KeyType.TEXT,
        'keys': {
            'the usual', 'ftp sites', 'web sites', 'bbs numbers', 'homepage', 'web page', 'ftp', 'website',
            'web site', 'home page', 'www', 'bbs', 'internet', 'web', 'www sites'
        },
    },
    'do_not_run_with': {
        'type': KeyType.TEXT,
        'keys': {'may not run with...', 'may not run with', 'will not run with...'},
    },
    'archive_maintainer': {
        'type': KeyType.TEXT,
        'keys': {'archive maintainer'},
    },
    'tested_with': {
        'type': KeyType.TEXT,
        'keys': {'tested with'},
    },
    'update_to': {
        'type': KeyType.TEXT,
        'keys': {'update to'},
    },
    'where_to_get': {
        'type': KeyType.TEXT,
        'keys': {'where to get this wad'},
    },
    'date_completed': {
        'type': KeyType.DATETIME,
        'keys': {'date finished', 'date completed', 'completion date'},
    },
    'content_levels': {
        'type': KeyType.BOOL,
        'keys': {'new level wad', 'new levels', 'levels', 'levels replaced'},
    },
    'review': {
        'type': KeyType.TEXT,
        'keys': {'review'},
    },
    'story': {
        'type': KeyType.TEXT,
        'keys': {'story', 'the story', 'story line'},
    },
    'theme': {
        'type': KeyType.TEXT,
        'keys': {'theme', 'themes'},
    },
    'inspiration': {
        'type': KeyType.TEXT,
        'keys': {'inspiration'},
    },
    'comments': {
        'type': KeyType.TEXT,
        'keys': {
            'comments', 'author\'s comment', 'info', 'author\'s comments', 'note', 'notes', 'additional notes',
            'uploader\'s note', 'important notes', 'play notes', 'misc. info', 'things to look out for',
            'additional info', 'comment', 'misc game info', 'misc notes', 'author comments', 'authors comments',
            'important',
        },
    },
    'hints': {
        'type': KeyType.TEXT,
        'keys': {'hints', 'tips', 'hint'},
    },
    'content_decorate': {
        'type': KeyType.TEXT,
        'keys': {'decorate'},
    },
    'content_weapons': {
        'type': KeyType.TEXT,
        'keys': {'weapons', 'new weapons'},
    },
}

TEXT_GAMES = {
    Game.DOOM2: {
        'keys': {
            'doom 2', 'doom2', 'doom ii', 'doomii', 'doom 2 ver 1.9', 'doom ][', 'doom / doom2', 'doom/doom2',
            'any doom', '- doom2', '2', 'any', 'both', 'freedoom',' freedm', 'ii', 'any iwad', 'freedoom: phase 2',
        },
        're': ['any doom.*', '^doom 2.*', '.*doom2.*', r'.*doom2\.wad.*', '.*doom ii.*', r'\bdoom\b', '^any game'],
    },
    Game.DOOM: {
        'keys': {'doom', 'doom1', '(ultimate) doom', 'the ultimate doom', 'freedoom1'},
        're': ['^doom.*', '.* ultimate .*', r'doom\.wad', '.*ultimate doom.*', '.*doom i.*'],
    },
    Game.PLUTONIA: {
        'keys': {'final doom', 'the plutonia experiment'},
        're': ['^final doom.*', '^plutonia.*'],
    },
    Game.TNT: {
        're': ['^tnt.*'],
    },
    Game.HERETIC: {
        're': ['.*heretic.*'],
    },
    Game.HEXEN: {
        're': ['.*hexen.*'],
    },
    Game.STRIFE: {
        're': ['.*strife.*'],
    },
    Game.CHEX: {
        'keys': {'chex', 'chex quest', 'chex quest 3'},
    },
    Game.HACX: {
        're': ['^hacx.*'],
    }
}

TEXT_DIFFICULTY = {
    'true': {
        'keys': {'yes', 'y', 'supported', 'possibly', 'of course', 'any', 'all', 'full implementation', 'fully functional.', 'fully supported', 'some'},
        're': ['^yes', '^yup', '^yep', '^yeah', r'^skills\s', r'^skill\s', '^only', '^implemented', r'^all\b', '^definitely', '^fully implemented', r'^some\b']
    },
    'false': {
        'keys': {'not implented', 'no', 'not implimented', '-', 'n\\a', 'unknown', 'n', 'not really', 'na', 'not applicable'},
        're': ['^not implemented', '^nope', '^none', r'^no\b', '^nah', '^n/a', r'^not\b']
    },
}

TEXT_BOOLEAN = {
    'true': {
        'keys': {'designed for', 'all', 'any', 'yeah!', 'yeah', 'affirmative', 'certainly', 'some', 'y', '- yes',
                 'one'},
        're': ['^yea.*', '^oh yeah.*', '^oh yes.*', '^supported.*', '^starts.*', '^yes.*', '^sure.*', '^probably.*',
               '^absolutely.*', '^definitely.*', '^some .*', '^duh.*', '^hell (yes|yeah).*', '^i guess.*',
               '^implemented.*', '^of course.*', '^yep.*', '^yup.*', '^a .*', '^all .*', '^designed.*', '^fully .*',
               '^full .*', '^you bet.*', r'.*\(yes\).*', '^aye.*'],
    },
    'false': {
        'keys': {'n/a', '-', '- no', '0', 'nah'},
        're': ['^no.*'],
    },
}

TEXT_ENGINE = {
    Engine.ZDOOM: {
        're': [r'zdoom'],
    },
    Engine.DOOM: {
        'keys': {
            'none', 'no', 'none.', 'doom2', 'vanilla', '-', 'doom 2', 'nope', 'any', 'n/a', 'vanilla compatible',
            'doom2.exe', 'vanilla-compatible', 'vanilla doom', 'none required',
        },
    },
    Engine.BOOM: {
        're': [r'boom', 'prboom+', 'prboom-plus -complevel 2'],
    },
    Engine.GZDOOM: {
        're': [r'gzdoom'],
    },
    Engine.SKULLTAG: {
        'keys': {'skulltag'},
    },
    Engine.NOLIMITS: {
        'keys': {'limit removing', 'limit-removing', 'limit removing port', 'yes', 'limit-removing port'},
    },
    Engine.MBF: {
        'keys': {'mbf', 'marine\'s best friend'},
    },
    Engine.LEGACY: {
        'keys': {'legacy', 'doom legacy'},
    },
    Engine.ZANDRONUM: {
        'keys': {'zandronum'},
    },
    Engine.ZDAEMON: {
        'keys': {'zdaemon'},
    },
    Engine.ETERNITY: {
        'keys': {'eternity'},
    },
}


import math
import operator as op
import os
from collections import ChainMap
from types import MappingProxyType

from .symbol import Symbol
from PIL import Image, ImageDraw, ImageFont

def eval(x, env=None):
    """
    Avalia expressão no ambiente de execução dado.
    """

    # Cria ambiente padrão, caso o usuário não passe o argumento opcional "env"
    if env is None:
        env = ChainMap({}, global_env)

    # Avalia tipos atômicos
    if isinstance(x, Symbol):
        return env[x]
    elif isinstance(x, (int, float, bool, str)):
        return x

    # Avalia formas especiais e listas
    head, *args = x

    if head == Symbol.DEFINE:
        variable, path_or_operation = args
        path_or_operation = eval(path_or_operation,env)
        if isinstance(path_or_operation,str): # é o caminho para uma imagem
            path_or_operation =str(os.getcwd() +'/'+ path_or_operation[1:-1])
            image = Image.open(path_or_operation)
            draw = ImageDraw.Draw(image)
            env[Symbol(variable)] = (image,draw)
        else: # é uma operação
            env[Symbol(variable)] = path_or_operation

    elif head == Symbol.SETTEXT:
        variable,position,text = args
        variable = eval(variable,env)
        try:
            font = env[Symbol('font')]
        except KeyError:
            font = None
        variable[1].text(position,text,fill='rgb(0,204,0)',font=font)

    elif head == Symbol.SAVE:
        variable, name = args
        variable = eval(variable,env)
        name = eval(name,env)[1:-1]
        variable[0].save(os.getcwd()+"/"+name)

    elif head == Symbol.SETFONT:
        fontfamily_path, size = args
        fontfamily_path =str(os.getcwd() +'/'+ fontfamily_path[1:-1])
        env[Symbol('font')] = ImageFont.truetype(fontfamily_path,size=size)
#
# Cria ambiente de execução.
#
def env(*args, **kwargs):
    """
    Retorna um ambiente de execução que pode ser aproveitado pela função
    eval().

    Aceita um dicionário como argumento posicional opcional. Argumentos nomeados
    são salvos como atribuições de variáveis.

    Ambiente padrão
    >>> env()
    {...}

    Acrescenta algumas variáveis explicitamente
    >>> env(x=1, y=2)
    {x: 1, y: 2, ...}

    Passa um dicionário com variáveis adicionais
    >>> d = {Symbol('x'): 1, Symbol('y'): 2}
    >>> env(d)
    {x: 1, y: 2, ...}
    """

    kwargs = {Symbol(k): v for k, v in kwargs.items()}
    if len(args) > 1:
        raise TypeError('accepts zero or one positional arguments')
    elif len(args):
        if any(not isinstance(x, Symbol) for x in args[0]):
            raise ValueError('keys in a environment must be Symbols')
        args[0].update(kwargs)
        return ChainMap(args[0], global_env)
    return ChainMap(kwargs, global_env)

def _make_global_env():
    """
    Retorna dicionário fechado para escrita relacionando o nome das variáveis aos
    respectivos valores.
    """

    dic = {
        **vars(math), # sin, cos, sqrt, pi, ...
        '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv,
        '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
        'abs':     abs,
        'append':  op.add,
        'apply':   lambda proc, args: proc(*args),
        'begin':   lambda *x: x[-1],
        'car':     lambda x: head,
        'cdr':     lambda x: x[1:],
        'cons':    lambda x,y: [x] + y,
        'eq?':     op.is_,
        'expt':    pow,
        'equal?':  op.eq,
        'even?':   lambda x: x % 2 == 0,
        'length':  len,
        'list':    lambda *x: list(x),
        'list?':   lambda x: isinstance(x, list),
        'map':     map,
        'max':     max,
        'min':     min,
        'not':     op.not_,
        'null?':   lambda x: x == [],
        'number?': lambda x: isinstance(x, (float, int)),
		'odd?':   lambda x: x % 2 == 1,
        'print':   print,
        'procedure?': callable,
        'quotient': op.floordiv,
        'round':   round,
        'symbol?': lambda x: isinstance(x, Symbol),
    }
    return MappingProxyType({Symbol(k): v for k, v in dic.items()})

global_env = _make_global_env()


from dados import produtos, pessoas, lista

def main():
    # Com map
    nova_lista_map = map(lambda x: x * 2, lista)

    # Com list comprehension
    nova_lista = [x * 2 for x in lista]

    print(list(nova_lista_map))
    print(nova_lista)

    # ----

    precos = map(lambda p: p['preco'], produtos)
    print(list(precos))

    precos_aumento = map(aumenta_preco, produtos)
    print(list(precos_aumento))

def aumenta_preco(p):
    p['preco'] = round(p['preco'] * 1.05, 2)
    return p

if __name__ == "__main__":
    main()


# https://www.geeksforgeeks.org/find-the-missing-number/
arr = list(map(eval , input().split(', ')))

# we will find the missing number using => [sum of numbers upto size numberi + 1] -  sum(arr)

# Solution will be in O(N) time and O(1) constant space

sum_of_arr = 0
for val in arr:
    sum_of_arr += val

num = len(arr) + 1
sum_upto_size = ( num * (num + 1) ) // 2

print("Missing number is :" , sum_upto_size - sum_of_arr)


import os
import streamlit as st
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain, SequentialChain
from dotenv import load_dotenv

load_dotenv()  # take environment variables from .env.

apikey = os.getenv('OPENAI_KEY')

os.environ['OPENAI_API_KEY'] = apikey

# app framework
st.title("LangChain, GPT creator")
prompt = st.text_input("Plug in your prompt here")

# prompt templates
title_template = PromptTemplate(
    input_variables=['topic'],
    template='give me a function name for {topic}'
)

code_template = PromptTemplate(
    input_variables=['topic'],
    template="""
        write me a theoretical solution and actual code implementation for this problem,
          explain why you did certain things and how you solved it, add comments to each line of the code implementation,
          code it in node.js/javascript,
          after you're done with the initial solution,
          provide some information about faster solutions and why they're faster, and same thing with slower solutions
          PROBLEM: {topic}
    """
)

#  llms (large language model): https://en.wikipedia.org/wiki/Large_language_model
llm = OpenAI(temperature=0.9)
title_chain = LLMChain(llm=llm, prompt=title_template,
                       verbose=True, output_key='title')
code_chain = LLMChain(llm=llm, prompt=code_template,
                      verbose=True, output_key='problem')
sequential_chain = SequentialChain(
    chains=[title_chain, code_chain],
    input_variables=['topic'],
    output_variables=['title', 'problem'],
    verbose=True
)

# show stuff to the screen if prompt provided.
if prompt:
    response = sequential_chain({'topic': prompt})
    st.write(response['title'])
    st.write(response['problem'])


from urllib.request import Request, urlopen
from bs4 import BeautifulSoup as soup
import urllib
import requests
import os.path
from os import path
import DBManager
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String
import env

engine = create_engine('postgresql://'+env.db_user+':'+env.db_pass+'@'+env.db_url+':'+env.db_port+'/'+env.db_name)\

conn = engine.connect()

def iterate():
    with open("tradeables.txt", "r") as a_file:
      for line in a_file:
        stripped_line = line.strip()
        start = stripped_line.find("")
        end = stripped_line.find(":")
        id = stripped_line[start:end]
        start = stripped_line.find(":")+1
        name = stripped_line[start:]
        print(name + " " + id)
        s = DBManager.itemIds.insert().values(id = id, Name = name)
        result = conn.execute(s)

def listOffers():
    #searches for item matching itemID inside items table
    s = DBManager.itemIds.select()
    results = conn.execute(s)
    for result in results:
        print(result)
    return results

listOffers()

iterate()


import matplotlib.pyplot as plt
import pandas as pd

# from matplotlib import rc
from matplotlib import rcParams
from os.path import abspath, dirname, join

# directories
WD = dirname(abspath(__file__))
RES_DIR = join(WD, *['..', '..', 'results'])
OUT_DIR = dirname(abspath(__file__))

# kernels and scenarios
kernels = ['linear', 'poly', 'rbf']
scenarios = ['G', 'cw']

# plot params
# rc('text', usetex=True)
# rc('text.latex', preamble=r'\usepackage{amsmath}')
rcParams["mathtext.fontset"] = 'cm'
constrained_layout = True # use tight layout if False

if __name__ == '__main__':
    ## Coverage Comparison ##

    fig, axs = plt.subplots(1, 3, figsize=(6.5, 4.333), sharey=True,
                            constrained_layout=constrained_layout)
    if not constrained_layout: fig.subplots_adjust(wspace=0.1)

    for i in range(3):
        # read in data and get vectors
        res = pd.read_csv(join(RES_DIR, 'validation_%s.csv' % kernels[i]),
                          index_col=0)

        C = res.index.to_numpy()
        coverage = res.coverage

        # scatter plot
        axs[i].scatter(C, coverage, label=r'SVM', s=15, alpha=0.3, zorder=10)

        # add y-label for left plot
        if i == 0:
            axs[i].set_ylabel(r'Coverage', fontsize=12)

        # set axis
        axs[i].set_ylim(-0.05, 1.05)
        axs[i].set_xscale('log')
        axs[i].set_xlabel(r'$\lambda^{-1}$', fontsize=12)
        axs[i].tick_params(labelsize=10)
        axs[i].tick_params(axis='x', which='minor', bottom=False)
        if i == 0: axs[i].set_xticks([0.01, 0.1, 1])
        axs[i].set_aspect(1 / axs[i].get_data_ratio())
        axs[i].grid(True)

    # layout and save
    if not constrained_layout: fig.tight_layout()
    plt.savefig(join(OUT_DIR,'fig2.pdf'), dpi=200, bbox_inches='tight')


#Função para o tamanho
def f_tam(n):
    cont = 0
    while (n > 0):
        cont += 1
        n = n//10
    return cont

#Função para inverter
def f_inversor(n):
    inv = 0
    tam = f_tam(n) - 1
    while(n > 0):
        a = n % 10
        inv += a * 10**tam
        tam = tam - 1
        n = n // 10
    return inv

# Função para verificar o quadrado perfeito
def f_quad(n):
    d = n
    while (d >= 1):
        if( d * d == n):
            return True
        d = d - 1
    return False

#Função para verificar capicua
def f_cap(n):
    inv = f_inversor(n)
    if (n == inv):
        return True
    else:
        return False

#Função Principal
def main():
    for i in range(1,5001):
        if(f_cap(i) and f_quad(i)):
            print(f'{i} É CAPICUA E QUADRADO PERFEITO ')
        elif(f_cap(i)):
            print(f'{i} É CAPICUA')
        elif(f_quad(i)):
            print(f'{i} É QUADRADO PERFEITO')

    return 0
if __name__ == "__main__":
    main()


from menu_and_input.input_parser import parse_input
from database.dbsession import Container, Session

def submenu_3_worker():
    while True:
        _parsed_input = parse_input()
        _prefix = _parsed_input[0]
        _code = _parsed_input[1]

        if _code == 'q':
            return 'quit'
        if _prefix == 'digits':
            print_container_last_places(_code, '3 days')
            return
        if _prefix == 'hm':
            print_courier_last_containers(_code,'3 days')
            return
    return

def query_container_all_last_places(container_code, data):
    session = Session()
    query = session.query(Container).filter(Container.container_id == container_code)
    print(query)

def print_container_last_places(container_code, data):
    query = query_container_all_last_places(container_code, data)
    print(query)
    return

def query_courier_all_last_containers(courier_code, data):
    session = Session()
    query = session.query(Container).filter(Container.container_id == courier_code)
    print(query)

def print_courier_last_containers(courier_code, data):
    return


'''
#
# MGI_PhenoGeno.py
#
# Report:
#       Phenotype/Genotype MP Annotations
#
#	Tab-delimited report where a row in the report
#	represents a Genotype annotation to a MP term
#	and all of the references (J:) used to annotate that term.
#
#	field 1: Allelic Composition
#	field 2: pipe-delimited list of Alleles
#	field 3: Genetic Background
#	field 4: Mammalian Phenotype ID
#	field 5: PubMed ID
#	field 6: MGI Marker Accession ID (comma-delimited)
#
# Usage:
#       MGI_PhenoGenoMP.py
#
# History:
#
# lec	08/24/2011
#	- TR10829/check if mpMarker contains null (no marker)
#
# lec	05/20/2010
#	- TR10179/add field 2/pipe-delimited list of Alleles
#
# lec	10/04/2005
#	- TR 5188; GO Qualifier
#
# lec	06/03/2005
#	- created
#
'''

import sys
import os
import string
import reportlib
import db

db.setTrace()

CRT = reportlib.CRT
SPACE = reportlib.SPACE
TAB = reportlib.TAB
PAGE = reportlib.PAGE

#
# Main
#

fp = reportlib.init(sys.argv[0], outputdir = os.environ['REPORTOUTPUTDIR'], printHeading = None)

#
# select all MP annotations
#

db.sql('''
        select distinct a._Object_key, a._Term_key, e._Refs_key
        into temporary table mp
        from VOC_Annot a, VOC_Evidence e, VOC_Term t
        where a._AnnotType_key = 1002
        and a._Qualifier_key = t._Term_key
        and t.term is null
        and a._Annot_key = e._Annot_key
        ''', None)
db.sql('create index idx1 on mp(_Object_key)', None)
db.sql('create index idx2 on mp(_Term_key)', None)
db.sql('create index idx3 on mp(_Refs_key)', None)

#
# resolve MP ids
#
results = db.sql('''
        select distinct m._Term_key, a.accID
        from mp m, ACC_Accession a
        where m._Term_key = a._Object_key
        and a._MGIType_key = 13
        and a.preferred = 1
        ''', 'auto')
mpID = {}
for r in results:
    key = r['_Term_key']
    value = r['accID']
    mpID[key] = value

#
# resolve References
#
results = db.sql('''
        select distinct m._Object_key, m._Term_key, a.accID
        from mp m, ACC_Accession a
        where m._Refs_key = a._Object_key
        and a._LogicalDB_key = 29
        ''', 'auto')
mpRef = {}
for r in results:
    key = repr(r['_Object_key']) + repr(r['_Term_key'])
    value = r['accID']
    if key not in mpRef:
        mpRef[key] = []
    mpRef[key].append(value)

#
# resolve Genotype Strains
#
results = db.sql('''
        select distinct m._Object_key, s.strain
        from mp m, GXD_Genotype g, PRB_Strain s
        where m._Object_key = g._Genotype_key
        and g._Strain_key = s._Strain_key
        ''', 'auto')
mpStrain = {}
for r in results:
    key = r['_Object_key']
    value = r['strain']
    mpStrain[key] = value

#
# resolve Allele Combination display
#
results = db.sql('''
        select distinct m._Object_key, n.note
        from mp m, MGI_Note n
        where m._Object_key = n._Object_key
        and n._NoteType_key = 1016
        ''', 'auto')
mpDisplay = {}
for r in results:
    key = r['_Object_key']
    value = str.replace(str.strip(r['note']), '\n', ',')
    mpDisplay[key] = value

#
# resolve Alleles
#
results = db.sql('''
        select distinct m._Object_key, a.symbol
        from mp m, GXD_AlleleGenotype ag, ALL_Allele a
        where m._Object_key = ag._Genotype_key
        and ag._Allele_key = a._Allele_key
        ''', 'auto')
mpAlleles = {}
for r in results:
    key = r['_Object_key']
    value = r['symbol']
    if key not in mpAlleles:
        mpAlleles[key] = []
    mpAlleles[key].append(value)

#
#
# resolve Marker ID
#
results = db.sql('''
        select distinct m._Object_key, a.accID
        from mp m, GXD_AlleleGenotype g, ACC_Accession a
        where m._Object_key = g._Genotype_key
        and g._Marker_key = a._Object_key
        and a._MGIType_key = 2
        and a._LogicalDB_key = 1
        and a.prefixPart = 'MGI:'
        and a.preferred = 1
        ''', 'auto')
mpMarker = {}
for r in results:
    key = r['_Object_key']
    value = r['accID']
    if key not in mpMarker:
        mpMarker[key] = []
    mpMarker[key].append(value)

#
# process results
#
results = db.sql('''
        select distinct _Object_key, _Term_key
        from mp order by _Object_key, _Term_key
        ''', 'auto')

for r in results:

    genotype = r['_Object_key']
    term = r['_Term_key']
    refKey = repr(genotype) + repr(term)

    # we only want to list the Genotypes that have Allele Pairs
    if genotype in mpDisplay:

        fp.write(mpDisplay[genotype] + TAB)
        fp.write('|'.join(mpAlleles[genotype]) + TAB)
        fp.write(mpStrain[genotype] + TAB)
        fp.write(mpID[term] + TAB)

        if refKey in mpRef:
            fp.write('|'.join(mpRef[refKey]) + TAB)
        else:
            fp.write(TAB)

        if genotype in mpMarker:
            fp.write('|'.join(mpMarker[genotype]) + CRT)
        else:
            fp.write(TAB + CRT)

reportlib.finish_nonps(fp)	# non-postscript file


# A1.3d Training a Model
def calc_rmse(y_true, y_pred):
    # this function calculates the RMSE from given y-values
    rmse_t = np.power(y_true-y_pred,2)
    return np.sqrt(np.mean(rmse_t))

nlist = np.array(range(1,10))
rmse_train = []

for i in nlist:
    # calc the rmse for n=1...9
    theta = calc_theta(i,x_train,y_train)
    y_pred = calc_y(x_train,i,theta)

    rmse_train.append(calc_rmse(Y_train,y_pred))


'''
Given a list, sort it using this method: reverse(lst, i, j), which reverses lst from i to j.
'''
# Pancake Sorting
def pancake_sort(list):
    size = len(list)
    for i in reversed(range(size)):
        maxinx = get_maxinx(list[:i+1])
        reverse(list, 0, maxinx)
        reverse(list, 0, i)
    return list

def get_maxinx(list):
    return list.index(max(list))

def reverse(list, i, j):
    while (i<j):
        list[i], list[j] = list[j], list[i]
        i += 1
        j -= 1

a = [5,3,3]
print(pancake_sort(a))