import math
import matplotlib.pyplot as plt
import numpy as np
import random

def f(x):
    f = 94 * (np.cos(x) ** 3) - 24 * np.cos(x) + 177 * (np.sin(x) ** 2) - 108 * (np.sin(x) ** 4) - 72 * (
            np.cos(x) ** 3) * (np.sin(x) ** 2) - 65
    return f

def fder1(x):
    f = -6 * ((2*np.cos(x) - 1) ** 2) * (15*np.cos(x)**2 - 3*np.cos(x) - 4) * np.sin(x)
    return f

def fder2(x):
    f = (1728 - 1800*np.cos(x))*np.sin(x)**4 + (2358*np.cos(x) - 2004)*np.sin(x)**2 - 402*np.cos(x) + 354
    return f

def bisection_method(a, b, tolerance):
    print(f"\nChecking in [{a}, {b}]")
    if f(a) == 0:
        print(f"Root is {a}, initial lower boundary!\n")
        return a
    elif f(b) == 0:
        print(f"Root is {b}, initial upper boundary!\n")
        return b
    elif f(a) * f(b) >= 0:
        print(f"No or multiple roots in [{a},{b}], bisection does not work!\n")
        return "0"
    error = abs(b - a)
    N = math.ceil((math.log(abs(b - a)) - math.log((1 / 2) * (1 / pow(10, tolerance)))) / math.log(2))
    for i in range(N):

        xi = random.uniform(a, b)

        try:
            if f(a) * f(xi) < 0:
                b = xi
                error = abs(b - a)
            elif f(b) * f(xi) < 0:
                a = xi
                error = abs(b - a)
            else:
                print("Good guess.")
                print(f"Lower boundary a is: {a} and upper b is: {b}, approximate root: {xi}, rounded to: "
                      f"{round(xi, tolerance)}"
                      f" after {i + 1} iterations.\n")
                return [round(xi, tolerance), i + 1]
        except Exception as e:
            print(type(e))
            print("Something went wrong\n")
            return [round(xi, tolerance), i + 1]

    print(f"Error is: {error}")
    print(f"Lower boundary a is: {a} and upper b is: {b}, approximate root: {xi}, rounded to: {round(xi, tolerance)}"
          f" after {i + 1} iterations.\n")
    return [round(xi, tolerance), i + 1]

def newton_raphson_method(a, b, tolerance):
    print(f"\nChecking in [{a}, {b}]")
    if f(a) == 0:
        print(f"Root is {a}, initial lower boundary!\n")
        return a
    elif f(b) == 0:
        print(f"Root is {b}, initial upper boundary!\n")
        return b

    x = random.uniform(a, b)
    counter = 0
    while f(x) * fder2(x) <= 0 or fder1(x) == 0 or f(x) == 0:
        if f(x) == 0:
            print(f"Nice guess! Root is {x}\n")
            return [round(x, tolerance), 0.0, 0]
        x = random.uniform(a, b)
        counter += 1
        if counter > 50:
            return "Couldn't find appropriate guess"

    print(f"Guess is: {x}")

    try:
        for i in range(100):

            xi = x - (1 / ((fder1(x) / f(x)) - (1 / 2) * (fder2(x) / fder1(x))))

            error = abs(xi - x)
            if error < (1 / 2) * (1 / pow(10, tolerance)):
                print(
                    f"Error is: {error}\nApproximate root: {xi}, rounded to: {round(xi, tolerance)} after {i+1} iterations\n")
                return [round(xi, tolerance), error, i + 1]
            x = xi
    except Exception as e:
        print(type(e))
        print(f"Something went wrong after {i} iterations.\n")

    print(f"Maximum iterations reached, failed to find root in [{a},{b}]")

    return [round(xi, tolerance), error, i + 1]

def secant_method(x0, x1, tolerance):

    print(f"\nChecking in [{x0}, {x1}]")

    if f(x0) == f(x1):
        return "Line is parallel to x axis! Secant doesn't work!"

    if f(x0) == 0:
        print(f"Root at lower boundary. Root is {x0}\n")
        return x0
    if f(x1) == 0:
        print(f"Root at upper boundary. Root is {x1}\n")
        return x1

    def q():
        return f(x0) / f(x1)

    def r():
        return f(x2) / f(x1)

    def s():
        return f(x2) / f(x0)

    x2 = (x0 + x1) / 2
    error = abs(x2 - x1)
    counter = 0
    while s() == 1 or r() == 1 or q() == 1:
        x2 = random.uniform(x0, x1)
        if f(x2) == 0:
            print(f"Nice guess! Root is {round(x2, tolerance)}\n")
            return [round(x2, tolerance), 0.0, 0]
        counter += 1
        if counter > 50:
            return "Couldn't find appropriate x2"

    for i in range(1, 100):

        try:
            xi = x2 - ((r() * (r() - q()) * (x2 - x1) + (1 - r()) * s() * (x2 - x0)) /
                       ((q() - 1) * (r() - 1) * (s() - 1)))
        except Exception as e:
            print(type(e))
            print(f"Oh no, division by zero after {i + 1} iterations!")
            print(f"x={x2}, rounded to: {round(x2, tolerance)}\nf(x)={f(x2)}\nf'(x)={fder1(x2)}\n")
            return [round(xi, tolerance), error, i + 1]
        x0 = x1
        x1 = x2
        x2 = xi
        error = abs(x2 - x1)
        if error < (1/2)*(1/pow(10, tolerance)):
            print(f"Error is: {error}\nApproximate root: {xi}, rounded to: {round(xi, tolerance)} "
                  f"after {i + 1} iterations\n")
            return [round(xi, tolerance), error, i + 1]
        if f(x0) == f(x1):
            print("Line is parallel to x axis!")
            print(f"Error is: {error}\nApproximate root: {xi}, rounded to: {round(xi, tolerance)} "
                  f"after {i + 1} iterations\n")
            return [round(xi, tolerance), error, i + 1]

    print(f"Maximum iterations reached. Approximation: {xi}, rounded to: {round(xi, tolerance)} "
          f"after {i + 1} iterations\n")
    return [round(xi, tolerance), error, i + 1]

def main():
    # 1
    tolerance = 5
    print("\n\nA \n\n")

    print("Bisection")
    for j in range(3):
        print(bisection_method(j, j + 1, tolerance))

    print("\nNewton-Raphson")
    for j in range(3):
        print(newton_raphson_method(j, j + 1, tolerance))

    print("\nSecant")
    for j in range(3):
        print(secant_method(j, j + 1, tolerance))

    # 2

    print("\n\nB\n\n")

    for i in range(10):
        for j in range(3):
            print(bisection_method(j, j + 1, tolerance))

    x = np.linspace(0, 3, 100)
    fig = plt.figure(figsize=(10, 5))
    plt.plot(x, f(x))
    plt.grid()
    plt.axis()
    plt.title("Ex 2")
    plt.show()

    print(f(0), fder1(0), fder2(0))
    return 0

main()


import json
import time
import pygame, sys
import math

from time import sleep
from decimal import Decimal
from tkinter import filedialog
from controller.VerifyController import VerifyController
from model.MoreBodiesSimulation import  MoreBodiesSimulation
from controller.Utilities import Utilities
from controller.JsonController import JsonController
from model.Body import Body
from vendor.Checkbox import Checkbox
from vendor.chart.FramePerTimeChart import FramePerTimeChart
from vendor.chart.PrecisionChart import PrecisionChart
from model.BarnesHutSimulation import BarnesHutSimulation
import numpy as np

class ViewTestPygame():
    def __init__(self):
        pygame.init()
        self.jsonController = JsonController("./data/statistics.json")
        self.nbSim = 0
        # Fonts
        pygame.font.init()
        self.poppins_font_15 = pygame.font.Font("assets/font/Poppins-Regular.ttf", 15)
        self.poppins_font_30 = pygame.font.Font("assets/font/Poppins-Regular.ttf", 30)
        self.poppins_font_35 = pygame.font.Font("assets/font/Poppins-Regular.ttf", 35)
        self.poppins_font_80 = pygame.font.Font("assets/font/Poppins-Regular.ttf", 80)
        pygame.font.get_fonts()

        # Windows parameters
        self.width = 1200
        self.height = 800

        self.nb_simulations = 0

        pygame.display.set_caption('Ncorps')
        self.window_surface = pygame.display.set_mode((self.width, self.height))
        self.background = pygame.Surface((1200, 800))
        self.background.fill(pygame.Color('#E6E6E6'))

        # Screens loops
        self.run_menu = True
        self.run_simulation = False
        self.run_notice = False
        self.run_configurator = False
        self.run_statistic = False

        # Data to store
        self.numSimulations = 0
        self.nbCorps = 0
        self.algo = None
        self.temps = None
        self.precision = None

        self.data = [self.numSimulations, self.nbCorps, self.algo, self.temps, self.precision]

        self.nbInteract = 0
        self.averageInteract = 0

        # Buttons
        self.button_dim = (456,118)
        self.box_idle = pygame.transform.scale(pygame.image.load("./assets/picture/button.jpg"),(self.button_dim[0],self.button_dim[1]))
        self.box_pressed = pygame.transform.scale(pygame.image.load("./assets/picture/button_down.jpg"),(self.button_dim[0], self.button_dim[1]))
        self.box_idle_correct = pygame.transform.scale(pygame.image.load("./assets/picture/button_correct.jpg"),(self.button_dim[0],self.button_dim[1]))
        self.box_pressed_correct = pygame.transform.scale(pygame.image.load("./assets/picture/button_down_correct.jpg"),(self.button_dim[0],self.button_dim[1]))
        self.box_idle_incorrect = pygame.transform.scale(pygame.image.load("./assets/picture/button_incorrect.jpg"),(self.button_dim[0],self.button_dim[1]))
        self.box_pressed_incorrect = pygame.transform.scale(pygame.image.load("./assets/picture/button_down_incorrect.jpg"),(self.button_dim[0],self.button_dim[1]))

        # Icons
        self.icons_size = 512//11
        self.icon_return = pygame.transform.scale(pygame.image.load("./assets/picture/return.png"),(self.icons_size,self.icons_size))
        self.icon_play = pygame.transform.scale(pygame.image.load("./assets/picture/bouton-jouer.png"),(self.icons_size,self.icons_size))
        self.icon_notice = pygame.transform.scale(pygame.image.load("./assets/picture/livre.png"),(self.icons_size,self.icons_size))
        self.icon_exit = pygame.transform.scale(pygame.image.load("./assets/picture/se-deconnecter2.png"),(self.icons_size,self.icons_size))
        self.icon_import = pygame.transform.scale(pygame.image.load("./assets/picture/import.png"),(self.icons_size,self.icons_size))
        self.icon_import_correct = pygame.transform.scale(pygame.image.load("./assets/picture/import_correct.png"),(self.icons_size,self.icons_size))
        self.icon_import_incorrect = pygame.transform.scale(pygame.image.load("./assets/picture/import_incorrect.png"),(self.icons_size,self.icons_size))
        self.icon_trash = pygame.transform.scale(pygame.image.load("./assets/picture/poubelle.png"),(self.icons_size,self.icons_size))
        self.icon_next = pygame.transform.scale(pygame.image.load("./assets/picture/next.png"),(self.icons_size,self.icons_size))
        self.icon_cache = pygame.transform.scale(pygame.image.load("./assets/picture/cache.png"),(self.icons_size,self.icons_size))

        # Rects
        self.rect_next = pygame.Rect(self.icons_size, 800-self.icons_size-25, self.icons_size, self.icons_size)
        self.rect_return = pygame.Rect(1200-self.icons_size-25, 800-self.icons_size-25, self.icons_size, self.icons_size)

    def menu(self):
        # Reinitialize json file
        while self.run_menu:
            # Get mouse position
            mouseX, mouseY = pygame.mouse.get_pos()

            # Display the text
            self.window_surface.blit(self.background,(0,0))

            # Collision areas
            button_posX = (self.width/2)-(self.button_dim[0]/2)
            button_posY = 225
            decalage_Y = 150
            rect_jouer = pygame.Rect(button_posX, button_posY, self.button_dim[0], self.button_dim[1])
            rect_notice = pygame.Rect(button_posX, button_posY + decalage_Y, self.button_dim[0], self.button_dim[1])
            rect_quitter = pygame.Rect(button_posX, button_posY + decalage_Y*2, self.button_dim[0], self.button_dim[1])
            rect_cache = pygame.Rect(self.width-60, self.height-60, self.button_dim[0], self.button_dim[1])

            # Draw title
            Utilities().display_text(self.window_surface, 'N-Corps', (450,50), self.poppins_font_80, '#007AB5')

            # Animation when mouse hover a button
            # Play button
            if not rect_jouer.collidepoint(mouseX, mouseY):
                self.window_surface.blit(self.box_idle, (button_posX, button_posY))
            else:
                self.window_surface.blit(self.box_pressed, (button_posX, button_posY))

            # Notice button
            if not rect_notice.collidepoint(mouseX, mouseY):
                self.window_surface.blit(self.box_idle, (button_posX, button_posY + decalage_Y))
            else:
                self.window_surface.blit(self.box_pressed, (button_posX, button_posY + decalage_Y))

            # Quit Button
            if not rect_quitter.collidepoint(mouseX, mouseY):
                self.window_surface.blit(self.box_idle, (button_posX, button_posY + decalage_Y*2))
            else:
                self.window_surface.blit(self.box_pressed, (button_posX, button_posY + decalage_Y*2))
            # Reset statistics.json cache
            if not rect_cache.collidepoint(mouseX, mouseY):
                self.window_surface.blit(self.icon_cache, (self.width-60, self.height-60))
            else:
                self.window_surface.blit(self.icon_cache, (self.width-58, self.height-58))

            # Draw icons
            self.window_surface.blit(self.icon_play, (button_posX + 45, button_posY + 35))
            self.window_surface.blit(self.icon_notice, (button_posX + 45, button_posY + decalage_Y + 35))
            self.window_surface.blit(self.icon_exit, (button_posX + 45, button_posY + decalage_Y*2 + 35))

            # Draw Buttons texts
            Utilities().display_text(self.window_surface, 'Jouer', (600, button_posY + 35), self.poppins_font_35, '#007AB5')
            Utilities().display_text(self.window_surface, 'Notice', (600, button_posY + decalage_Y + 35), self.poppins_font_35, '#007AB5')
            Utilities().display_text(self.window_surface, 'Quitter', (595, button_posY + decalage_Y*2 + 35), self.poppins_font_35, '#007AB5')

            for event in pygame.event.get():
                # Exit
                if event.type == pygame.QUIT:
                    self.run_notice = False
                    pygame.quit()
                    sys.exit()

                # Event when click
                if event.type == pygame.MOUSEBUTTONDOWN:
                    # Click on Play
                    if rect_jouer.collidepoint((mouseX,mouseY)):
                        # Run the screen
                        self.run_menu = False
                        self.run_configurator = True
                        self.configuration()
                    #Click on Cache
                    if rect_cache.collidepoint((mouseX,mouseY)):
                        # Reset statistics.json
                        self.jsonController.deleteJsonFile()
                    # Click on Notice
                    if rect_notice.collidepoint((mouseX,mouseY)):
                        # Run the screen
                        self.run_menu = False
                        self.run_notice = True
                        self.Notice()

                    # Click on Quit
                    if rect_quitter.collidepoint((mouseX,mouseY)):
                        sys.exit()

            pygame.display.flip()

    def Notice(self):
        text = ("Enoncé : \n" +
                "Le problème à N corps est un problème de mécanique newtonienne où plusieurs corps se déplacent dans l'espace en étant soumis à leur propre inertie et l'attraction des autres corps.\n" +
                "Configuration : \n" +
                "- Nombres de corps \n" +
                "- Masses minimums et maximums \n" +
                "- Algorithmes : Vous pouvez sélectionner l'algorithme désiré en cochant la checkbox correspondante. \n" +
                "- Import : vous pouvez importer directement des corps avec des caractéristiques précises par le biais d'un tableau excel. Pour ce faire il vous suffit de modifier le modèle de fichier excel fournit sur le menu de configuration, le remplir avec vos informations puis le redonner en cliquant sur le bouton import.")

        while self.run_notice:
            # Get mouse position
            mouseX, mouseY = pygame.mouse.get_pos()

            # Draw background
            self.window_surface.blit(self.background, (0, 0))

            # Draw text
            Utilities().display_text(self.window_surface, text, (50,50), self.poppins_font_30, 'black')

            # Draw icon return
            self.window_surface.blit(self.icon_return, ((1200-self.icons_size-25, 800-self.icons_size-25)))

            for event in pygame.event.get():
                # Exit
                if event.type == pygame.QUIT:
                    self.run_notice = False
                    pygame.quit()
                    sys.exit()

                # Events when click
                if event.type == pygame.MOUSEBUTTONDOWN:
                    # Click on return
                    if self.rect_return.collidepoint((mouseX,mouseY)):
                        # Run the screen
                        self.run_menu = True
                        self.run_notice = False
                        self.menu()

            pygame.display.flip()

    def simulation(self, file=None, nbBodies = 50, mass_min = 6, mass_max = 12, algo="classic"):
        # Use a specific simulation
        sim = None
        precList = None
        self.algo = algo
        def importBodies(file):
            bodies = []
            for _ in range(len(file)):
                body = Body(file[_][0],file[_][1],float(file[_][2]))
                if len(file[_]) > 3:
                    body.spd = np.array([float(file[_][3]),float(file[_][4])])
                bodies.append(body)

            return bodies

        if file == None:
            bodies = []
        else:
            #File is simply the name of the file, the second element is the bodies over each frame (similar to dataTime), the third is the list of the bodies at the 20th frame of the simulation
            precList = [file, [[],None], None]
            bodies = importBodies(file)
            nbBodies = len(bodies)
            self.nbCorps = nbBodies

        if algo == "classic":
            sim = MoreBodiesSimulation(bodyCount=nbBodies, mass_min=mass_min, mass_max=mass_max, width=self.width, height=self.height, bodies=bodies)
        elif algo == "barnesHut":
            sim = BarnesHutSimulation(bodyCount=nbBodies,mass_min=mass_min, mass_max=mass_max, width=self.width, height=self.height, bodies=bodies)
        elif algo == "FMM":
            sim = MoreBodiesSimulation(bodyCount=nbBodies, mass_min=mass_min, mass_max=mass_max, width=self.width, height=self.height, bodies=bodies)

        cmpt = 0
        dataTime = [[],[]]
        initTime = time.time()

        while self.run_simulation:
            # Get mouse position
            cmpt += 1
            dataTime[0].append(round(time.time() - initTime, 3))
            dataTime[1].append(cmpt)
            if file != None: precList[1][0].append(tuple(sim.bodies[0].pos))
            mouseX, mouseY = pygame.mouse.get_pos()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.run_simulation = False
                    precList[1][1] = dataTime[1]
                    self.data = [self.numSimulations, self.nbCorps, self.algo, dataTime, precList]
                    self.jsonController.storeDataJson(self.data)
                    pygame.quit()
                    sys.exit()

                # Events when click
                if event.type == pygame.MOUSEBUTTONDOWN:
                    # Click on return
                    if cmpt > 200 :
                        if self.rect_return.collidepoint((mouseX,mouseY)):

                            # Save simulation
                            self.temps = dataTime[0]
                            if file != None : precList[1][1] = dataTime[1]
                            self.data = [self.numSimulations, self.nbCorps, self.algo, dataTime, precList]
                            self.jsonController.storeDataJson(self.data)

                            self.run_statistic = True
                            self.run_simulation = False
                            self.statistic()

                    if self.rect_next.collidepoint((mouseX,mouseY)):
                        # Save simulation
                        self.temps = dataTime[0]
                        if file != None : precList[1][1] = dataTime[1]
                        self.data = [self.numSimulations, self.nbCorps, self.algo, dataTime, precList]
                        self.jsonController.storeDataJson(self.data)

                        # Run screen
                        self.run_configurator = True
                        self.run_simulation = False
                        sim = None
                        self.configuration()

            # Draw background
            self.window_surface.blit(self.background, (0, 0))

            # Get base values for min and max exponential
            mass_min_r = math.floor(math.log(sim.bodies[0].mass, 10))
            mass_max_r = math.floor(math.log(sim.bodies[0].mass, 10))
            # Values for the size in pixels of the bodies
            minp = 3
            maxp = 10

            # Get min and max exp values for all bodies
            for body in sim.bodies:
                exp = math.floor(math.log(body.mass, 10))
                if(exp < mass_min_r):
                    mass_min_r = exp
                if(exp > mass_max_r):
                    mass_max_r = exp

            # Draw bodies
            for body in sim.bodies:
                # if mass max equal to min max set a pixel size for all
                if mass_max_r == mass_min_r :
                    pygame.draw.circle(self.window_surface,body.getBodyColor(7),(body.pos[0],body.pos[1]), 7)
                # Scale the size of the bodies
                else :
                    nombreSortie = ((maxp - minp) / (mass_max_r - mass_min_r)) * (math.floor(math.log(body.mass, 10)) - mass_min_r) + minp
                    pygame.draw.circle(self.window_surface,body.getBodyColor(int(nombreSortie)),(body.pos[0],body.pos[1]), int(nombreSortie))

            self.window_surface.blit(self.icon_return, ((self.icons_size, 800-self.icons_size-25)))

            # Store Bodies For Precision at 20 frames
            if cmpt == 20:
                if file != None and precList[2] == None: precList[2] = tuple(map(lambda x : tuple(x.pos), sim.bodies))

            # Draw next icon
            if cmpt > 200 :
                self.window_surface.blit(self.icon_next, ((1200-self.icons_size-25, 800-self.icons_size-25)))

            sim.advance()

            self.nbInteract += sim.nbInteract
            self.averageInteract= self.nbInteract/cmpt

            pygame.display.update()

    def statistic(self,):
        # Load data from json file
        with open("./data/statistics.json", 'r') as file:
            data = json.load(file)

        # Define here Chart from vendor\Chart
        # FramePerTimeChart

        FPT = FramePerTimeChart(data)
        printFPT = FPT.printChart()
        FPTraw_data = printFPT[0]
        FPTcanvas = printFPT[1]

        Prec = PrecisionChart(data)
        printPrec = Prec.printChart()
        print(printPrec[1])
        if printPrec[0] == None:
            drawPrecision = False
            errMessPrec = printPrec[1]
        else:
            drawPrecision = True
            PrecRawData = printPrec[0]
            PrecCanvas = printPrec[1]
            averagePrec20 = printPrec[2]
        # END FramePerTimeChart
        # END CHART

        while self.run_statistic:
            # Get mouse position
            mouseX, mouseY = pygame.mouse.get_pos()

            self.window_surface.blit(self.background, (0, 0))
            self.window_surface.blit(self.icon_return, ((self.icons_size, 800-self.icons_size-25)))

            # PRINT FPT
            FPTsize = FPTcanvas.get_width_height()
            FPTsurf = pygame.image.fromstring(FPTraw_data, FPTsize, "RGB")
            self.window_surface.blit(FPTsurf, (20,30))

            if drawPrecision:
                PrecSize = PrecCanvas.get_width_height()
                PrecSurf = pygame.image.fromstring(PrecRawData, PrecSize, "RGB")
                self.window_surface.blit(PrecSurf, (500,30))
                Utilities().display_text(self.window_surface, "L'erreur moyenne au bout de 20 frames etait de " + str(averagePrec20), (600,500), self.poppins_font_15, '#007AB5')
            else:
                Utilities().display_text(self.window_surface, errMessPrec, (750,250), self.poppins_font_15, '#007AB5')

            # Display title
            Utilities().display_text(self.window_surface, 'Statistiques', (self.width//2 - 150, -20), self.poppins_font_80, '#007AB5')
            Utilities().display_text(self.window_surface, "La simulation contenait " + str(self.nbCorps) + " corps pour un total de " + str(self.averageInteract) + "calcul de force par frame", (100, 600 ), self.poppins_font_15, '#007AB5')

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.run_statistic = False
                    pygame.quit()
                    sys.exit()

                # Evenements lors du clique
                if event.type == pygame.MOUSEBUTTONDOWN:
                    # Si clique sur bouton Retour
                    if self.rect_next.collidepoint((mouseX,mouseY)):
                        self.run_menu = True
                        self.run_statistic = False
                        self.menu()

            pygame.display.update()

    def configuration(self):
        # Variables
        active_nb = False
        active_mass_min = False
        active_mass_max = False
        error = None
        can_run = False
        color_active = pygame.Color(180, 180, 180)
        color_passive = pygame.Color(230, 230, 230)
        color_nb = color_passive
        color_mass_min = color_passive
        color_mass_max = color_passive

        # Input Value
        input_number = '50'
        input_mass_min = '5.9722*10**6'
        input_mass_max = '5.9722*10**12'

        self.button_posX = (self.width/2)-(self.button_dim[0]/2)

        # Rectangles for collisions
        rect_jouer = pygame.Rect(self.width//3.5, 700, 1000, 100)
        rect_input = pygame.Rect(400,125,300,40)
        rect_input_outline = pygame.Rect(395,120,310,50)
        rect_mass_min = pygame.Rect(400,250,300,40)
        rect_mass_min_outline = pygame.Rect(395,245,310,50)
        rect_mass_max = pygame.Rect(400,375,300,40)
        rect_mass_max_outline = pygame.Rect(395,370,310,50)
        rect_import = pygame.Rect(self.button_posX,500,556,118)
        rect_trash = pygame.Rect(self.button_posX + self.button_dim[0] + 25, 500 + 35, self.icons_size, self.icons_size)

        file = None

        # Checkbox algorithm selector*
        # Boxe for multiple check
        boxes = []
        #checkbox
        classic = Checkbox(surface=self.window_surface,x=350,y=450,caption="Algorithme quadratique", idnum=1,font_color='#007AB5',checked=True, algo="classic")
        barnersHutt = Checkbox(surface=self.window_surface,x=570,y=450,caption="Barners Hutt", idnum=2,font_color='#007AB5', algo="barnesHut")
        FMM = Checkbox(surface=self.window_surface,x=720,y=450,caption="FMM", idnum=3,font_color='#007AB5',algo="FMM")
        #Append into the boxes
        boxes.append(classic)
        boxes.append(barnersHutt)
        boxes.append(FMM)

        while self.run_configurator:
            # Get mouse position
            mouseX, mouseY = pygame.mouse.get_pos()

            controller = VerifyController((800,1200))
            # Draw background
            self.window_surface.blit(self.background, (0, 0))
            #checkbox update
            for checkbox in boxes:
                checkbox.render_checkbox()
            # Verify inputs
            if(controller.verifyInput(input_number, input_mass_min, input_mass_max) == False or controller.verifyNb(input_number) == False):
                can_run = False
            else:
                can_run = True

            # Check state input
            if(active_nb):
                color_nb = color_active
                color_mass_min = color_passive
                color_mass_max = color_passive
            elif(active_mass_min):
                color_mass_min = color_active
                color_nb = color_passive
                color_mass_max = color_passive
            elif(active_mass_max):
                color_mass_max = color_active
                color_mass_min = color_passive
                color_nb = color_passive

            # EVENT
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.run_configurator = False
                    self.jsonController.storeDataJson(self.data)
                    pygame.quit()
                    sys.exit()
                # CLICK EVENT
                if event.type == pygame.MOUSEBUTTONDOWN:
                    for box in boxes:
                        box.update_checkbox(event)
                        if box.checked is True:
                            for b in boxes:
                                if b != box:
                                    b.checked = False
                    # Return
                    if self.rect_return.collidepoint((mouseX,mouseY)):
                        self.run_menu = True
                        self.run_configurator = False
                        self.menu()

                    # Start simulation
                    if rect_jouer.collidepoint((mouseX,mouseY)):
                        if(can_run):
                            # Actualize data to store
                            self.numSimulations += 1
                            self.nbCorps = int(input_number)
                            self.algo = box.algo

                            self.run_simulation = True
                            self.run_configurator = False

                            if(file == None):
                                for box in boxes:
                                    if box.checked == True:
                                        self.simulation(nbBodies = int(input_number), mass_min = Utilities().bodyMassExp(input_mass_min), mass_max = Utilities().bodyMassExp(input_mass_max),algo=box.algo)
                            else:
                                for box in boxes:
                                    if box.checked == True:
                                        self.simulation(file, nbBodies = int(input_number), mass_min = Utilities().bodyMassExp(input_mass_min), mass_max = Utilities().bodyMassExp(input_mass_max), algo=box.algo)

                    # Type text input nb
                    if rect_input.collidepoint((mouseX,mouseY)):
                        if(active_mass_min == True):
                            active_mass_min = not active_mass_min
                        elif(active_mass_max == True):
                            active_mass_max = not active_mass_max
                        active_nb = not active_nb

                    # Type text input mass_min
                    if rect_mass_min.collidepoint((mouseX,mouseY)):
                        if(active_nb == True):
                            active_nb = not active_nb
                        elif(active_mass_max == True):
                            active_mass_max = not active_mass_max
                        active_mass_min = not active_mass_min

                    # Type text input mass_max
                    if rect_mass_max.collidepoint((mouseX,mouseY)):
                        if(active_mass_min == True):
                            active_mass_min = not active_mass_min
                        elif(active_nb == True):
                            active_nb = not active_nb
                        active_mass_max = not active_mass_max

                    Utilities().display_text(self.window_surface, "Fichier incorrect", (self.button_posX, 410), self.poppins_font_30, '#D10000')

                    if rect_trash.collidepoint((mouseX,mouseY)):
                        file = None
                        error = None

                    # Import file
                    if rect_import.collidepoint((mouseX, mouseY)):

                        file = filedialog.askopenfile(mode = "r",initialdir="./data", title="selectionner", filetypes=(("Fichier CSV","*.csv"),("Fichier PDF","*.pdf"))).name

                        if file != None:
                            file = controller.getBodyFromCSV(file)
                            print(*file)
                        else :
                            error = True

                if event.type == pygame.KEYDOWN:
                    # Check for backspace
                    if event.key == pygame.K_BACKSPACE:
                        # get text input from 0 to -1 i.e. end.
                        if(active_nb):
                            input_number = input_number[:-1]
                        elif(active_mass_min):
                            input_mass_min = input_mass_min[:-1]
                        elif(active_mass_max):
                            input_mass_max = input_mass_max[:-1]

                    # Unicode standard is used for string
                    # formation
                    else:
                        if event.unicode.isdigit():
                            if(active_nb):
                                input_number += event.unicode
                            elif(active_mass_min):
                                input_mass_min += event.unicode
                            elif(active_mass_max):
                                input_mass_max += event.unicode
            # Draw icon return
            self.window_surface.blit(self.icon_return, ((1200-self.icons_size-25, 800-self.icons_size-25)))

            # Draw play
            self.window_surface.blit(self.icon_play, (self.width//1.8, 700))

            # Display text on inputs
            Utilities().display_text(self.window_surface, "Lancer la simulation", (self.width//3.3,700), self.poppins_font_30, '#007AB5')
            Utilities().display_text(self.window_surface,"Nombre de corps ? (2 - 100)", (400,75),self.poppins_font_30,'#007AB5')
            Utilities().display_text(self.window_surface,"Masse des corps minimum ? (x * (10**11 - 10**24) )", (400,200),self.poppins_font_30,'#007AB5')
            Utilities().display_text(self.window_surface,"Masse des corps maximum ? (x * (10**11 - 10**24) )", (400,325),self.poppins_font_30,'#007AB5')

            # Draw the rectangles
            pygame.draw.rect(self.window_surface,"#007AB5", rect_input_outline)
            pygame.draw.rect(self.window_surface, color_nb, rect_input)
            pygame.draw.rect(self.window_surface, "#007AB5", rect_mass_min_outline)
            pygame.draw.rect(self.window_surface, color_mass_min, rect_mass_min)
            pygame.draw.rect(self.window_surface, "#007AB5", rect_mass_max_outline)
            pygame.draw.rect(self.window_surface, color_mass_max, rect_mass_max)

            # Apply text surface
            Utilities().display_text(self.window_surface, input_number, (rect_input.x, rect_input.y), self.poppins_font_30, 'black')
            Utilities().display_text(self.window_surface, input_mass_min, (rect_mass_min.x, rect_mass_min.y), self.poppins_font_30, 'black')
            Utilities().display_text(self.window_surface, input_mass_max, (rect_mass_max.x, rect_mass_max.y), self.poppins_font_30, 'black')

            # Animation hover import button
            if not rect_import.collidepoint(mouseX, mouseY):
                if(error == True):
                    self.window_surface.blit(self.box_idle_incorrect, (self.button_posX,500))
                elif(error == False):
                    self.window_surface.blit(self.box_idle_correct, (self.button_posX,500))
                else:
                    self.window_surface.blit(self.box_idle, (self.button_posX,500))
            else:
                if(error == True):
                    self.window_surface.blit(self.box_pressed_incorrect, (self.button_posX,500))
                elif(error == False):
                    self.window_surface.blit(self.box_pressed_correct, (self.button_posX,500))
                else:
                    self.window_surface.blit(self.box_pressed, (self.button_posX,500))

            # Graphics for import error
            if(error == True):
                Utilities().display_text(self.window_surface, "Fichier incorrect", (self.button_posX + 125, 450), self.poppins_font_30, '#D10000')
                self.window_surface.blit(self.icon_import_incorrect, (self.button_posX + 45, 500 + 35))
                Utilities().display_text(self.window_surface, "Import", (self.button_posX + 225, 535), self.poppins_font_35, '#D10000')
            elif(error == False):
                Utilities().display_text(self.window_surface, "Fichier importé", (self.button_posX + 125, 450), self.poppins_font_30, '#10CA00')
                self.window_surface.blit(self.icon_import_correct, (self.button_posX + 45, 500 + 35))
                self.window_surface.blit(self.icon_trash, (self.button_posX + self.button_dim[0] + 25, 500 + 35))
                Utilities().display_text(self.window_surface, "Import", (self.button_posX + 225, 535), self.poppins_font_35, '#10CA00')
            else:
                self.window_surface.blit(self.icon_import, (self.button_posX + 45, 500 + 35))
                Utilities().display_text(self.window_surface, "Import", (self.button_posX + 225, 535), self.poppins_font_35, '#007AB5')
            # Update the screen
            pygame.display.update()


import argparse
import hashlib
import logging
import os
import subprocess
import sys
import tempfile
from datetime import datetime
from os.path import join
from typing import Optional, List

fastr_default_testdir = 'test.fastr'
gnur_default_testdir = 'test.gnur'

_opts = argparse.Namespace()
_common_arg_parser = argparse.ArgumentParser()
_common_arg_parser.add_argument('--fastr-home', metavar='FASTR_HOME', dest="fastr_home", type=str, default=None,
                                required=True,
                                help='The FastR standalone repo home directory (required).')
_common_arg_parser.add_argument('--gnur-home', metavar="GNUR_HOME", dest="gnur_home", default=None, required=True,
                                help='The GnuR home directory (required).')
_common_arg_parser.add_argument('--graalvm-home', metavar="GRAALVM_HOME", dest="graalvm_home", default=None,
                    help='The GraalVM root directory (optional). If provided, FastR binaries are taken from this directory')
_common_arg_parser.add_argument('--repos', metavar='REPO_NAME=URL', dest="repos", type=str, default=None,
                    help='Repos to install packages from. Can be set by "FASTR_REPOS" env var. '
                         'Example: "--repos FASTR=file://$HOME/fastr_repo,CRAN=file://$HOME/minicran"')
_common_arg_parser.add_argument('-v', '--verbose', dest="verbose", action="store_const", const=1, default=0,
                    help='Do verbose logging.')
_common_arg_parser.add_argument('-V', '--very-verbose', dest="verbose", action="store_const", const=2,
                    help='Do very verbose logging.')
_common_arg_parser.add_argument('--dump-preprocessed', dest="dump_preprocessed", action="store_true",
                    help='Dump processed output files where replacement filters have been applied.')
_common_arg_parser.add_argument('-q', '--quiet', dest="quiet", action="store_true",
                    help="Don't log anything")
_common_arg_parser.add_argument('--fastr-testdir', metavar="FASTR_TESTDIR", dest="fastr_testdir", default=fastr_default_testdir,
                    help='FastR test result directory (default: "test.fastr").')
_common_arg_parser.add_argument('--gnur-testdir', metavar="GNUR_TESTDIR", dest="gnur_testdir", default=gnur_default_testdir,
                    help='GnuR test result directory (default: "test.gnur").')
_common_arg_parser.add_argument('-l', '--log-file', dest="log_file", default="pkgtest.log",
                    help='Log file name (default: "FASTR_TESTDIR/pkgtest.log").')
pkg_spec_group = _common_arg_parser.add_mutually_exclusive_group()
pkg_spec_group.add_argument('--pkg-pattern', metavar='PATTERN', dest='pattern', type=str, default=None,
                            help='Pattern of packages to install and potentially test')
pkg_spec_group.add_argument('--pkg-filelist', metavar='FILE', dest='filelist', type=str, default=None,
                            help='File containing a list of packages to install and potentially test')

def get_opts() -> argparse.Namespace:
    return _opts

def get_common_arg_parser() -> argparse.ArgumentParser:
    return _common_arg_parser

def get_fastr_repo_dir() -> str:
    return _opts.fastr_home

def get_gnur_home() -> str:
    '''
    Returns path to GnuR home dir, e.g., gnur/gnur/R-3.4.0/.
    '''
    return _opts.gnur_home

def get_gnur_rscript() -> str:
    '''
    returns path to Rscript in sibling gnur directory
    '''
    # return _mx_gnur().extensions._gnur_rscript_path()
    return join(get_gnur_home(), "bin", "Rscript")

def get_gnur_include_path() -> str:
    # if graalvm():
    #     return join(_mx_gnur().dir, 'gnur', _mx_gnur().extensions.r_version(), 'include')
    # return join(mx_fastr._gnur_path(), "include")
    return join(get_gnur_home(), 'include')

def get_fastr_home() -> str:
    if get_graalvm_home():
        fastr_home = join(get_graalvm_home(), "languages", "R")
        if os.path.exists(fastr_home):
            return fastr_home
        else:
            logging.error(f"Could not find FastR home at {fastr_home}")
    return get_fastr_repo_dir()

def get_fastr_include_path() -> str:
    return join(get_fastr_home(), 'include')

def graalvm_rscript() -> str:
    assert get_graalvm_home() is not None
    return join(get_graalvm_home(), 'bin', 'Rscript')

def get_fastr_rscript() -> str:
    graalvm_dir = get_graalvm_home()
    if graalvm_dir is not None:
        return join(graalvm_dir, "bin", "Rscript")
    return join(get_fastr_repo_dir(), 'bin', 'Rscript')

def get_default_cran_mirror() -> str:
    default_cran_mirror_file = join(get_fastr_home(), 'etc', 'DEFAULT_CRAN_MIRROR')
    url = None
    try:
        f = open(default_cran_mirror_file, "r")
        url = f.readline()
        if url:
            url = url.strip()
        if 'FASTR_MRAN_MIRROR' in os.environ:
            overlay = os.environ['FASTR_MRAN_MIRROR'].strip()
            overlay += '' if overlay.endswith('/') else '/'
            date = url[-len('2000-00-00'):]
            url = overlay + 'snapshot/' + date
            logging.info("Using '{0}' instead of the default MRAN mirror.".format(url))
    except IOError as e:
        logging.error("Could not read %s: %s" % (default_cran_mirror_file, e))
    finally:
        f.close()
    return url

def get_r_version(rscript_binary: str, tmp_dir: str) -> str:
    r_version_file = join(tmp_dir, "R.version")
    args = [rscript_binary, "--verbose", "-e", "cat(R.Version()[['major']], '.', R.Version()[['minor']], file='%s', sep='')" % r_version_file]
    if not os.path.exists(rscript_binary):
        abort(1, "Rscript binary '%s' does not exist.", rscript_binary)
    try:
        logging.debug("Running command: %s", args)
        output = subprocess.check_output(args, stderr=subprocess.STDOUT, universal_newlines=True)

        with open(r_version_file, "r") as f:
            lines = f.readlines()
        return lines[-1].strip()
    finally:
        os.unlink(r_version_file)

def get_graalvm_home() -> Optional[str]:
    return _opts.graalvm_home

def abort(status: int, *args) -> None:
    if args:
        logging.fatal(*args)
    quit(status)

def warn(*args) -> None:
    logging.warning(*args)

def log_step(state: str, step: str, rvariant: str) -> None:
    if not _opts.quiet:
        logging.info("{0} {1} with {2}".format(state, step, rvariant))
        log_timestamp()

def log_timestamp() -> None:
    if not _opts.quiet:
        logging.info("timestamp: {0}".format(str(datetime.now())))

def check_r_versions() -> None:
    '''
    Checks that FastR and GnuR have the same version.
    '''
    tmp_dir = tempfile.mkdtemp()
    gnur_version = get_r_version(get_gnur_rscript(), tmp_dir)
    fastr_version = get_r_version(get_fastr_rscript(), tmp_dir)
    logging.info("Using FastR version = %r ; GnuR version = %r: " % (fastr_version, gnur_version))
    if gnur_version != fastr_version:
        abort(1, 'GraalVM R version does not match GnuR version: %r (FastR) vs. %r (GnuR)' % (fastr_version, gnur_version))

VERY_VERBOSE = logging.DEBUG - 5

def parse_arguments(argv: List[str], r_version_check=True) -> List[str]:
    """
    Parses the given argument vector and stores the values of the arguments known by this script to appropriate globals.
    This represents the common arguments for both pkgtest and pkgcache.
    The unknown arguments are returned for further processing.
    """
    global _opts
    _opts, r_args = _common_arg_parser.parse_known_args(args=argv)

    if not _opts.repos and os.environ.get('FASTR_REPOS'):
        _opts.repos = os.environ['FASTR_REPOS']
    elif _opts.repos and os.environ.get('FASTR_REPOS'):
        warn('Both --repos option and FASTR_REPOS env var set, using value from command-line argument.')

    # ensure that first arg is neither the name of this package nor a py file
    if r_args and (r_args[0] == __package__ or r_args[0].endswith(".py")):
        r_args = r_args[1:]

    log_format = '%(message)s'
    if _opts.verbose == 1:
        log_level = logging.DEBUG
    elif _opts.verbose == 2:
        log_level = VERY_VERBOSE
    else:
        log_level = logging.INFO
    logging.basicConfig(filename=_opts.log_file, filemode="w", level=log_level, format=log_format)

    logger = logging.getLogger("")
    if len(logger.handlers) < 2:
        # We want to have 2 handlers in total - one that logs in _opts.log_file and one that logs
        # to console.
        console_handler = logging.StreamHandler(stream=sys.stdout)
        console_handler.setLevel(log_level)
        console_handler.setFormatter(logging.Formatter(log_format))
        logger.addHandler(console_handler)

    logging.log(VERY_VERBOSE, "known_args: %s" % _opts)

    # print info if _opts.graalvm is used
    if get_graalvm_home():
        logging.info("Using GraalVM at %r" % get_graalvm_home())

    # ensure that FastR and GnuR have the same version
    if r_version_check:
        check_r_versions()

    return r_args

def computeApiChecksum(includeDir: str) -> str:
    """
    Computes a checksum of the header files found in the provided directory (recursively).
    The result is a SHA256 checksum (as string with hex digits) of all header files.
    """
    m = hashlib.sha256()
    rootDir = includeDir
    fileList = list()
    for root, _, files in os.walk(rootDir):
        for f in files:
            fileName = join(root, f)
            if fileName.endswith('.h'):
                fileList.append(fileName)

    # sorting makes the checksum independent of the FS traversal order
    fileList.sort()
    for fileName in fileList:
        try:
            with open(fileName) as f:
                fileContent = f.read().encode()
                m.update(fileContent)
        except IOError as e:
            # Ignore errors on broken symlinks
            if not os.path.islink(fileName) or os.path.exists(fileName):
                raise e

    hxdigest = str(m.hexdigest())
    logging.debug("Computed API version checksum {0}".format(hxdigest))
    return hxdigest

def ensure_dir(path):
    if not os.path.exists(path):
        os.makedirs(path)
    return path


import csv
import itertools
import operator
import re

i = 0
contacts_dict = []
with open('phonebook_raw.csv', encoding="utf8") as f:
    reader = csv.reader(f, delimiter=",")
    contacts_list = list(reader)
    for items in contacts_list:
        pattern_phone = r'(\+7|8)?\s*\(?(\d{3})\)?[\s*-]?(\d{3})[\s*-]?(\d{2})[\s*-]?(\d{2})(\s*)\(?(доб\.?)?\s*(\d*)?\)?'
        fixed_phone = re.sub(pattern_phone, r'+7(\2)\3-\4-\5\6\7\8', items[5])
        contacts_list[i][5] = fixed_phone
        try:
            i += 1
        except IndexError:
            break

    keys = contacts_list[0]
    values = contacts_list[1:]
    for num, vals in enumerate(values):
        contacts_dict.append({})
        for key, val in zip(keys, vals):
            contacts_dict[num].update({key: val})
    for v in contacts_dict:
        splt = v['lastname'].split(' ')
        if len(splt) > 1:
            v['lastname'] = splt[0]
            v['firstname'] = splt[1]
            if len(splt) > 2:
                v['surname'] = splt[2]

        splt = v['firstname'].split(' ')
        if len(splt) > 1:
            v['firstname'] = splt[0]
            v['surname'] = splt[1]
    all_keys = set(contacts_dict[0].keys())
    group_list = ['firstname', 'lastname']
    group = operator.itemgetter(*group_list)
    cols = operator.itemgetter(*(all_keys ^ set(group_list)))
    contacts_dict.sort(key=group)
    grouped = itertools.groupby(contacts_dict, group)

    merge_data = []
    for (firstname, lastname), g in grouped:
        merge_data.append({'lastname': lastname, 'firstname': firstname})
        for gr in g:
            d1 = merge_data[-1]
            for k, v in gr.items():
                if k not in d1 or d1[k] == '':
                    d1[k] = v
keys = list(merge_data[0].keys())
with open('phonebook.csv', "w", encoding="utf8") as f:
    datawriter = csv.writer(f, delimiter=',')
    datawriter.writerow(keys)
    for d in merge_data:
        datawriter.writerow(d.values())

print('Data updated.')


#
# @lc app=leetcode.cn id=220 lang=python3
#
# [220] 存在重复元素 III
#

# @lc code=start
# from sortedcontainers import SortedSet

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
    #     buckets = {}
    #     for i, num in enumerate(nums):
    #         id = self.bucketId(num, t+1)
    #         if id in buckets or \
    #             (buckets.get(id+1) and buckets[id+1]<=num+t) or \
    #                 (buckets.get(id-1) and buckets[id-1]>=num-t):
    #             return True
    #         buckets[id] = num
    #         if i >= k:
    #             buckets.pop(self.bucketId(nums[i-k], t+1))
    #     return False

    # def bucketId(self, num, size):
    #     return num//size if num >= 0 else (num+1)//size-1
        sst = SortedSet()
        for i, num in enumerate(nums):
            lower = sst.bisect_right(num) -1
            if lower >= 0 and sst[lower] >= num - t:
                return True
            upper = sst.bisect_right(num)
            if upper < len(sst) and sst[upper] <= num + t:
                return True
            sst.add(num)
            if len(sst) > k:
                sst.remove(nums[i-k])
        return False
# @lc code=end


# write your code here
class Person:
    #name = 'alia'
    #age = 33

    def __init__(self,name,age):
        self.name= name
        self.age= age

    def is_adult(self):
        if self.age > 18:
             print("You have too much responsibilities")
        elif self.age < 18:
            print("Lucky you")
    def __str__(self):
        return f"My name is {self.name} and I am {self.age} years old "
first_person = Person('alia',33)
print(first_person.name , first_person.age)
first_person.is_adult()
print(first_person)


import torch
from helper import load_data
from solution import PCA, AE, frobeniu_norm_error
import numpy as np
import os

def test_pca(A, p):
    pca = PCA(A, p)
    Ap, G = pca.get_reduced()
    A_re = pca.reconstruction(Ap)
    error = frobeniu_norm_error(A, A_re)
    print('PCA-Reconstruction error for {k} components is'.format(k=p), error)
    return G

def test_ae(A, p):
    model = AE(d_hidden_rep=p)
    model.train(A, A, 128, 300)
    A_re = model.reconstruction(A)
    final_w = model.get_params()
    error = frobeniu_norm_error(A, A_re)
    print('AE-Reconstruction error for {k}-dimensional hidden representation is'.format(k=p), error)
    return final_w

if __name__ == '__main__':
    dataloc = "../data/USPS.mat"
    A = load_data(dataloc)
    A = A.T
    ## Normalize A
    A = A/A.max()

    ### YOUR CODE HERE
    # Note: You are free to modify your code here for debugging and justifying your ideas for 5(f)

    #we need to normalize A by subtracting mean for PCA for minimum recontruction error as per notes, we can use same A_norm
    #for both AE and PCA for proper comparision
    size = A.shape[1]
    A_norm = (A - ((1/size)*A@np.ones((size,1)))@np.ones((1,size)))

    ps = [32, 64, 128]
    #ps = [64]
    for p in ps:
        G = test_pca(A_norm, p)
        final_w = test_ae(A_norm, p)

    #for relation between W and G
    ps = [32, 64, 128]
    for p in ps:
        G = test_pca(A_norm, p)
        W = test_ae(A_norm, p)
        print("G-W", frobeniu_norm_error(G, W))
        M = G.T @ W
        U, S, V = np.linalg.svd(M, full_matrices=True)
        Mp = U @ np.eye(U.shape[0], V.shape[0]) @ V
        Gp = G @ Mp
        print("Gp-W", frobeniu_norm_error(Gp, W))
        print('M-Mp', frobeniu_norm_error(M, Mp))
        A_re = Gp @ Gp.T @ A_norm
        print("A -A_Re:", frobeniu_norm_error(A_norm, A_re))

    ### END YOUR CODE


import ssl
import smtplib

from email.message import EmailMessage

# email the error if there has happened something faulty
def email_error(website, error, huis):
    message = EmailMessage()
    message.set_content(str(error)+'\n'+str(huis))
    message['FROM'] = "huizzoeker@outlook.com"
    message['TO'] = ["rensevdzee@hotmail.com"]
    message['SUBJECT'] = "Error bij "+website
    context = ssl.create_default_context()
    # set up SMTP server
    with smtplib.SMTP('smtp-mail.outlook.com', 587) as smtp:
        smtp.starttls(context=context)
        smtp.login(message['FROM'], "Ludosanders")
        smtp.send_message(message)
        smtp.quit()

# email the results if there has been new houses spotted
def email_new(results, alert):
    #print(products, new_products, updated_products)
    message = EmailMessage()
    message.set_content(results)
    message['FROM'] = "huizzoeker@outlook.com"
    message['TO'] = ["rensevdzee@hotmail.com"]
    if alert == 1:
        message['SUBJECT'] = "1 nieuwe osso gevonden"
    if alert > 1:
        message['SUBJECT'] = str(alert)+" nieuwe ossos gevonden"
    context = ssl.create_default_context()
    # set up SMTP server
    with smtplib.SMTP('smtp-mail.outlook.com', 587) as smtp:
        smtp.starttls(context=context)
        smtp.login(message['FROM'], "Ludosanders")
        smtp.send_message(message)
        smtp.quit()

# combine the data of the house into an appropiate sentence for the email
def write_msg(new,old):
    str_list = []
    for item in new:
        str_list.append("(**Nieuw**) Potentieel huis gevonden op de {} met {} m2 voor {} {}!  {}".format(item[1],item[3], item[5], item[6], item[8]))
    for item in old:
        str_list.append("Potentieel huis gevonden op de {} met {} m2 voor {} {}!  {}".format(item[1],item[3], item[5], item[6], item[8]))
        # if item[0] == "(Nieuw)":
        #     str_list.append("{}Potentieel huis gevonden met {} m2 voor {} {}!  {}".format(
        #         item[0], item[1], item[2], item[3], item[4]))
        # else:
        #     str_list.append("Potentieel huis gevonden met {} m2 voor {} {}!  {}".format(
        #         item[1], item[2], item[3], item[4]))
    return "\n".join(str_list)


import sys, os
from sklearn.datasets import load_files
from sklearn.datasets import fetch_20newsgroups
import settings

data_path = settings.data_path
def load(path):
	if path=="newsgroups":
		categories=['alt.atheism', 'soc.religion.christian']
		data=fetch_20newsgroups(subset='all',categories=categories)
	else:
		data_container_path = data_path + 'corpora/raw/' + path
		print("Loading files dataset")
		data = load_files(data_container_path, load_content=True, shuffle=True, encoding='utf8', charset='utf8', charset_error='', decode_error='strict', random_state=42)

	rawdata, classes = data.data, data.target
	print("classes: %s" % data.target_names)
	print('data loaded')
	return rawdata, classes, data.target_names
def load_dataset(dataset_name):
    """Load and return dataset (classification).

    The dataset is a classic and very easy multi-class classification
    dataset.

    Returns
    -------
    data : Bunch
        Dictionary-like object, the interesting attributes are:
        'data', the data to learn, 'target', the classification labels,
        'target_names', the meaning of the labels, 'feature_names', the
        meaning of the features

    Examples
    --------
    Let's say you are interested in the samples 10, 25, and 50, and want to
    know their class name.

    >>> data = load_dataset("en_room_facebook")
    >>> data.target[[10, 25, 50]]
    array([0, 0, 1])
    >>> list(data.target_names)
    ['room', 'rent', 'amsterdam']
    """
    data_file = csv.reader(open(join(data_path, 'datasets', dataset_name + '.csv')))
    first_line = next(data_file)
    n_samples = int(first_line[0])
    n_features = int(first_line[1])
    target_names = np.array(first_line[2:])
    second_line = next(data_file)
    feature_names = second_line
    data = np.empty((n_samples, n_features))
    target = np.empty((n_samples,), dtype=np.int)

    for i, line in enumerate(data_file):
        data[i] = np.asarray(line[:-1], dtype=np.float)
        target[i] = np.asarray(line[-1], dtype=np.int)

    return Bunch(data=data, target=target, target_names=target_names, feature_names=feature_names)
def save_dataset():
	return None


import socket

import threading

import json

import copy

import socket_protocol as sp

class PeerBroadcast(threading.Thread):

    def __init__(self, peer, message, broadcast_list, node_info):
        threading.Thread.__init__(self)
        self.peer = peer
        self.message = message
        self.broadcast_list = broadcast_list
        self.node_info = node_info

    def run(self):
        print ("broadcasting message")

        peer = self.peer
        message = self.message
        broadcast_list = self.broadcast_list
        node_info = self.node_info

        PEER_IP = peer["address"]
        PORT = peer["port"]

        peer_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        peer_conn.settimeout(2.0)

        try:
            peer_conn.connect((peer["address"], peer["port"]))
        except ConnectionRefusedError:
            print ("peer not online")

            print (peer["address"])
            print (peer["port"])

            return

        new_broadcast_list = copy.copy(broadcast_list)
        new_broadcast_list.append(node_info)

        broadcast_json = {
            "message_type": "broadcast",
            "message": message,
            "broadcast_sent_to": new_broadcast_list
        }

        broadcast_string = json.dumps(broadcast_json)

        try:

            try:

                sp.send_msg(peer_conn, broadcast_string.encode('utf-8'))

                response_data = sp.recv_msg(peer_conn).decode('utf-8')

                response_data_json = json.loads(response_data)

                if (response_data_json["message_type"] == "success"):

                    print ("BROADCAST SUCCESS")

                else:
                    print ("BROADCAST FAILURE")

                peer_conn.close()
                return

            except Exception as err:
                print ("unable to send broadcast")
                return
        except ConnectionRefusedError:
            print ("connection refused")


"""
File Name: gol.py
Create Time: 2022.05.30
生命游戏轮子
"""
from manim import *
from rle_decode import *

class CellBoard(VGroup):
    def __init__(self,
            side_length = 0.5, dimension = (10, 10),
            colors = {'live': WHITE, 'dead': GREY, 'empty': GREY},
            rule = 'B3/S23',
            **kwargs):
        """
        Purpose: Initialise the cell board (by default all are empty cells)
        @param side_length: side_length of one single cell
        @param dimension: (height, width)
            width: number of cells in one row
            height: number of cells in one column
        @param color: default color of the cell
        @param rule: the Game of life rule, now only accept Bxx/Sxx format
        """
        super().__init__(**kwargs)
        self.side_length = side_length
        self.dimension = dimension
        self.live_color = colors['live'] # 1
        self.dead_color = colors['dead'] # -1
        self.empty_color = colors['empty'] # 0
        self.rule = rule
        self.board_arr = np.zeros(dimension)

        for i in range(self.dimension[0] * self.dimension[1]):
            self.add(Square(side_length = self.side_length, color = self.empty_color, fill_color = self.empty_color, fill_opacity = 1))

        # this custom_buff may be changed if the visual effect is not satisfactory
        #custom_buff = 0

        if dimension[0] * dimension[1] < 100:
            custom_buff = side_length / 5.0
        else: #dimension[0] * dimension[1] <= 225:
            custom_buff = side_length / 4.0

        # height, width
        self.arrange_in_grid(self.dimension[0], self.dimension[1], buff = custom_buff)

    def get_cell(self, row, column):
        """
        Purpose: get the cell
        @param row: beginning index is 1
        @param column: beginning index is 1
        """
        if row < 1 or row > self.dimension[0]:
            raise RuntimeError('Out of range!')
        if column < 1 or column > self.dimension[1]:
            raise RuntimeError('Out of range!')
        index = (row - 1) * self.dimension[1] + column - 1
        return self[index]

    def get_cell_center(self, row, column):
        """
        Purpose: get the center of the cell
        @param row: beginning index is 1
        @param column: beginning index is 1
        """
        return self.get_cell(row, column).get_center()

    def set_stageboard(self, arr):
        """
        Purpose: Initialize the board
        @param arr 2D array, 1 means live, 0 means empty,
        -1 means there existed dead cell be4
        """
        self.board_arr = arr

        for i in range(arr.shape[0]):
            for j in range(arr.shape[1]):
                if arr[i][j] == 0:
                    self.get_cell(i + 1, j + 1).set_color(self.empty_color).set_style(fill_color = self.empty_color)
                elif arr[i][j] == 1:
                    self.get_cell(i + 1, j + 1).set_color(self.live_color).set_style(fill_color = self.live_color)
                elif arr[i][j] == -1:
                    self.get_cell(i + 1, j + 1).set_color(self.dead_color).set_style(fill_color = self.dead_color)

    def set_stageboard_by_rle(self, file_path):
        """
        Purpose: configure the setting of the board using rtf file
        @param file_path The path to the rle file

        Reminders: x is the width and y is the height
        """
        self.set_stageboard( expand_rle(file_path) )

    def count_live_neighbour(self, x, y):
        """
        Purpose: count the number of live neighbours
        @param x begin with 0
        @param y begin with 0
        """
        cnt = 0
        loc = np.array([x, y, 0])
        directions = np.array([UP, UL, LEFT, DL, DOWN, DR, RIGHT, UR])
        for direction in directions:
            des = loc + direction
            #print(des)
            if des[0] < 0 or des[0] >= self.dimension[0]:
                continue
            if des[1] < 0 or des[1] >= self.dimension[1]:
                continue
            dx = int(des[0])
            dy = int(des[1])
            if self.board_arr[dx][dy] == 1:
                cnt += 1

        return int(cnt)

    def next_status(self, x, y, cnt):
        """
        Purpose: obtain the next status of the current cell
        @param x begin with 0
        @param y begin with 0
        """
        Birth, Survival = self.rule.split('/')
        Birth = Birth[1:]
        Survival = Survival[1:]
        """
        print("############")
        print(Birth)
        print(Survival)
        print(cnt)
        print("###########")
        """

        if self.board_arr[x][y] == 1: # live
            if str(cnt) not in Survival:
                self.board_arr[x][y] = -1
                self.get_cell(x + 1, y + 1).set_color(self.dead_color).set_style(fill_color = self.dead_color)
        else: # otherwise
            if str(cnt) in Birth:
                self.board_arr[x][y] = 1
                self.get_cell(x + 1, y + 1).set_color(self.live_color).set_style(fill_color = self.live_color)

    def step(self):
        #print(np.count_nonzero(self.board_arr == 1))
        """
        Purpose: simulate the next step based on the rule
        """
        cnt_arr = np.zeros(self.board_arr.shape, dtype = "int64")
        for x in range(self.board_arr.shape[0]):
            for y in range(self.board_arr.shape[1]):
                cnt_arr[x][y] = self.count_live_neighbour(x, y)

                #print(cnt_arr[x][y])
        #print(np.count_nonzero(cnt_arr == 1))

        for x in range(self.board_arr.shape[0]):
            for y in range(self.board_arr.shape[1]):
                self.next_status(x, y, cnt_arr[x][y])

        #self.set_stageboard(self.board_arr)


class Node:
	def __init__(self, data):
		self.data = data
		self.next = None
class LinkedList:
	def __init__(self):
		self.head = None
	def push(self, new_data):
		new_node = Node(new_data)
		new_node.next = self.head
		self.head = new_node
	def getCount(self):
		temp = self.head
		count = 0
		while (temp):
			count += 1
			temp = temp.next
		return count
if __name__ == '__main__':
	llist = LinkedList()
	llist.push("c")
	llist.push("python")
	llist.push("c++")
	llist.push("java")
	llist.push("html")
	print("Count of nodes is :", llist.getCount())


from tensorflow.keras.preprocessing.image import load_img, img_to_array
from os import path, listdir
from numpy import zeros
from ocr_libs.mapping import string_to_array

class ImageSet:
    def __init__(self, training, test, input_size, output_size):
        self.__TRAINING_PATH = path.abspath(training)
        self.__TEST_PATH = path.abspath(test)
        self.__count_inputs = 0
        self.__num_trainings = len([name for name in listdir(self.__TRAINING_PATH)])
        self.__num_tests = len([name for name in listdir(self.__TEST_PATH)])
        self.__training_shape = (self.__num_trainings,) + input_size
        self.__test_shape = (self.__num_tests,) + input_size
        self.__training_imgs_array = zeros(shape=self.__training_shape)
        self.__test_imgs_array = zeros(shape=self.__test_shape)
        self.__training_labels_array = zeros(shape=(self.__num_trainings, output_size))
        self.__test_labels_array = zeros(shape=(self.__num_tests, output_size))

    def load_training(self):
        for filename in listdir(self.__TRAINING_PATH):
            self.__training_imgs_array[self.__count_inputs] = img_to_array(
                load_img(self.__TRAINING_PATH + "/" + filename)
            )
            char = filename[int(filename[6])]
            self.__training_labels_array[self.__count_inputs] = string_to_array(char)
            self.__count_inputs += 1
            if self.__count_inputs >= self.__num_trainings:
                break
        self.__count_inputs = 0
        return (self.__training_imgs_array, self.__training_labels_array)

    def load_test(self):
        for filename in listdir(self.__TEST_PATH):
            self.__test_imgs_array[self.__count_inputs] = img_to_array(
                load_img(self.__TEST_PATH + "/" + filename)
            )
            char = filename[int(filename[6])]
            self.__test_labels_array[self.__count_inputs] = string_to_array(char)
            self.__count_inputs += 1
            if self.__count_inputs >= self.__num_tests:
                break
        self.__count_inputs = 0
        return (self.__test_imgs_array, self.__test_labels_array)


import re

def extract_text_snippets(wiki_md, wiki_title, nlp):
    """
    Extract text snippets from the given
    Markdown text.
    """
    if not wiki_md or not wiki_md.get("extract"):
        return []

    # load content
    content = wiki_md["extract"]

    # remove noise and load doc
    clean_content = _filter_noise(content)
    doc = nlp(clean_content)

    # split the given document into sentences
    evidences = list()
    for sent in doc.sents:
        # drop empty sentences
        if not sent.text.strip():
            continue

        # wiki_title will be prepended later to avoid noisy matches
        evidence_text = sent.text.strip()

        # create evidence object
        evidence = {
            # entities are added later by EvidenceAnnotator
            "evidence_text": evidence_text,
            "source": "text",
        }
        evidences.append(evidence)
    return evidences

def _filter_noise(wiki_content):
    """
    Filter headings and whitespaces from the document.
    """
    # remove sections
    content = wiki_content.split("== Citations ==")[0]
    content = wiki_content.split("== Footnotes ==")[0]
    content = wiki_content.split("== References ==")[0]
    content = wiki_content.split("== Further reading ==")[0]
    # clean text
    content = re.sub(r"==.*?==+", "", content)
    content = content.replace("\n", " ")
    while "  " in content:
        content = content.replace("  ", " ")
    return content


import numpy as np
import pandas as pd

grades = {

    'Student1' : [10,10,10],
    'Student2' : [9,7,9],
    'Student3' : [9,6,6]

}

df = pd.DataFrame(grades, index = ('Homework', 'Activity', 'Attendance'))
df.index.name = 'Grades'

midterm1 = pd.DataFrame({

    'Student1':10,
    'Student2':10,
    'Student3':10
}, index=['Midterm 1'])

# df = pd.concat([df, midterm1])
# print(df)

student4 = [9,7,8,8]
df.insert(3, 'Student4', student4)
# print(df)

# df.drop(columns = ['Student1'], inplace=True)
# df.drop(['Midterm 1'], inplace = True)
# print(df)

print(df['Student2'])
print(df.loc[['Attendance'], ['Student3', 'Student4']])


import torch
import numpy as np
import matplotlib.pyplot as plt
from torchvision import transforms
import pandas as pd
from torch.utils.data import Dataset , DataLoader
from roboflow import Roboflow

rf = Roboflow(api_key="TJJkQCgCgKoIpfHHTeRT")
project = rf.workspace("erushiki").project("side-ktyou")
dataset = project.version(5).download("multiclass")

csv_or = pd.read_csv('/content/Side-5/train/_classes.csv')

csv_or.keys()

csv_bottom = csv_or[' Bottom']
csv_left = csv_or[' Left']

csv_right = csv_or[' Right']
csv_top = csv_or[' Top']

csv_file = csv_or['filename']

DEFAULT_PATH_TRAIN = '/content/Side-5/train'
DEFAULT_PATH_TEST = '/content/Side-5/test'

def test(fname, b, l, r, t):
    img = plt.imread(f"{DEFAULT_PATH_TRAIN}/{fname}")

    plt.imshow(img)
    # plt.legend()

    print(f"{b, l, r, t}")

    if b == 1:
        print("Show Bottom")
    if l == 1:
        print("Show Left")
    if r == 1:
        print("Show Right")
    if t == 1:
        print("Show Top")

class dset(Dataset):

    def __init__(self, csv, root, transforms=None):

        super().__init__()

        self.csv = csv
        self.root = root
        self.transforms = transforms

    def __len__(self):

        return len(self.csv)

    def __getitem__(self, idx):

        if torch.is_tensor(idx):
            idx = idx.tolist()

        readed = pd.read_csv(self.csv)

        csv_bottom = readed[' Bottom']
        csv_left = readed[' Left']
        csv_right = readed[' Right']
        csv_top = readed[' Top']
        csv_file = readed['filename']

        img_name = f'{self.root}/{csv_file[idx]}'
        label = np.array((csv_bottom[idx], csv_left[idx], csv_right[idx], csv_top[idx]))
        img = plt.imread(img_name)
        # img = torch.from_numpy(np.float32(img))
        # label = torch.from_numpy(np.float32(label))
        sample = {'image': img, 'label': label}

        if self.transforms != None:
            img = self.transforms(img)

        return img, label

transform = transforms.Compose([

    transforms.ToTensor(),
    transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
])

Datas = dset('/content/Side-5/train/_classes.csv', '/content/Side-5/train', transform)

DataL = DataLoader(Datas, 1, True)


import rhinoscriptsyntax as rs
import trkRhinoPy as trp

objs = rs.GetObjects('select objects', preselect=True)

def setUID(objs):
    for idx, obj in enumerate(objs, start=1):
        rs.SetUserText(obj, 'uid', 'uid-{}'.format(idx))

setUID(objs)

# def setQuickTag(obj, tagVal):
#     rs.SetUserText(obj, 'tag', tagVal)

# def getQuickTag(tagVal):
#     rs.Command('_SelKeyValue tag {}'.format(tagVal))

# def objsSetQuickTag():
#     objs = rs.GetObjects('select objects to tag', preselect=True)
#     tagVal = rs.GetString('Tag Value')
#     map(lambda x: setQuickTag(x, tagVal), objs)

# def objsGetQuickTag():
#     tagVal = rs.GetString('Tag Value')
#     rs.Command('_SelKeyValue tag {}'.format(tagVal))


from modules.playogo_db import PlayogoDb, Venue
from modules.venue_search import VenueSearch
from bs4 import BeautifulSoup
import os, urllib, requests, json, logging

class Controller():
    pass

class VenuesController(Controller):

    def search_results(search_query):

        db = PlayogoDb()

        lat, lng, err = VenueSearch.get_lat_lng(search_query)

        if err:
            logging.error("VenueSearch::get_lat_lng failed.")
            return {
                'closest_venues': [],
                'search_query': search_query,
                'error': "Sorry but there was a problem processing your request. If this problem persists please report it to playogosports@gmail.com."
            }

        closest_venues = VenueSearch.get_closest_venues(lat, lng)

        return {
            'closest_venues': closest_venues,
            'search_query': search_query,
            'encoded_search_query': urllib.parse.quote_plus(search_query)
        }

    def venue(slug):

        db = PlayogoDb()

        venue = db.session.query(Venue).filter_by(id=slug).first();

        return {
            'venue_name': venue.name,
            'venue_formatted_address': venue.formatted_address,
            'venue_street_number': str(venue.street_number),
            'venue_route_short': venue.route_short,
            'venue_city': venue.city_long,
            'venue_province_short': venue.admin_area_level_1_short,
            'venue_country': venue.country_short,
            'venue_postal_code': venue.postal_code,
            'venue_lat': venue.lat,
            'venue_lng': venue.lng,
            'venue_phone_number': venue.phone_number,
            'venue_website': venue.website,
            'google_encoded_location': urllib.parse.quote_plus(venue.formatted_address),
            'google_encoded_timhortons': urllib.parse.quote_plus('Tim Horton\'s near ' + venue.formatted_address),
            'google_encoded_hotels': urllib.parse.quote_plus('Hotels near ' + venue.formatted_address),
            'google_api_key': os.environ['PLAYOGO_GMAPS_API_KEY']
        }

    def home_page():
        return {}


import torch as th

def _get_first_singular_vectors_power_method(X, Y, max_iter=500, tol=1e-06):
    eps = th.finfo(th.float64).eps
    try:
        y_score = next(col for col in Y.T if th.any(th.abs(col) > eps))
    except StopIteration as e:
        raise StopIteration("Y residual is constant") from e

    x_weights_old = 100
    for i in range(max_iter):
        x_weights = th.matmul(X.T, y_score) / th.matmul(y_score, y_score)
        x_weights /= th.sqrt(th.matmul(x_weights, x_weights)) + eps
        x_score = th.matmul(X, x_weights)
        y_weights = th.matmul(Y.T, x_score) / th.matmul(x_score.T, x_score)
        y_score = th.matmul(Y, y_weights) / (th.matmul(y_weights, y_weights) + eps)
        x_weights_diff = x_weights - x_weights_old
        if th.matmul(x_weights_diff, x_weights_diff) < tol or Y.shape[1] == 1:
            break
        x_weights_old = x_weights
    n_iter = i + 1
    return x_weights, y_weights, n_iter

def _get_first_singular_vectors_svd(X, Y):
    C = th.matmul(X.T, Y)
    U, _, Vt = th.linalg.svd(C)
    return U[:, 0], Vt[0, :]

def _svd_flip_1d(u, v):
    biggest_abs_val_idx = th.argmax(th.abs(u))
    sign = th.sign(u[biggest_abs_val_idx])
    u *= sign
    v *= sign


def sys_bgcolor(pyplot):
    """Reads system preference and sets plt background accordingly"""
    from winreg import ConnectRegistry, HKEY_CURRENT_USER, OpenKeyEx, QueryValueEx
    root = ConnectRegistry(None, HKEY_CURRENT_USER)
    policy_key = OpenKeyEx(root, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize")
    light, _ = QueryValueEx(policy_key, "AppsUseLightTheme")
    if light:
        pyplot.style.use('default')
    else:
        pyplot.style.use('dark_background')

def winplay(data, rate, *, width=3, offset=0, seconds=15):
    """Plays a numpy array as a sound on Windows (and is unstoppable)"""
    import winsound
    data = data[rate*offset:rate*(offset + seconds)]
    r = bytearray()
    r += b'\x52\x49\x46\x46' # RIFF
    r += (width*len(data) + 36).to_bytes(4, 'little') # bytes until EOF
    r += b'\x57\x41\x56\x45' # WAVE
    r += b'\x66\x6D\x74\x20' # fmt_
    r += b'\x10\x00\x00\x00' # 16 bytes for the chunk
    r += b'\x01\x00' # PCM = 1
    r += b'\x01\x00' # number of channels
    r += (rate).to_bytes(4, 'little') # number of channels
    r += (rate*width).to_bytes(4, 'little') # bytes per sec
    r += (width).to_bytes(2, 'little') # bytes per block
    r += (width*8).to_bytes(2, 'little') # bits per sample
    r += b'\x64\x61\x74\x61' # data
    r += (width*len(data)).to_bytes(4, 'little') # bytes until EOF
    max_value = max(abs(data))
    max_number = 2**(width*8 - 1) - 1
    for e in data:
        r += int(e*max_number/max_value).to_bytes(width, 'little', signed=True)
    winsound.PlaySound(r, winsound.SND_MEMORY)

def fin():
    """To play a sound after execution"""
    from IPython.display import Audio
    return Audio('https://www.soundboard.com/mediafiles/23/230637-88d7c1eb-fd29-4c12-9775-f8dff855374b.mp3',
                 autoplay=True)

def toggle_color_mode():
    """Toggles system color scheme preference."""
    from winreg import ConnectRegistry, HKEY_CURRENT_USER, REG_SZ, KEY_ALL_ACCESS, OpenKeyEx, QueryValueEx, SetValueEx, CloseKey
    root = ConnectRegistry(None, HKEY_CURRENT_USER)
    policy_key = OpenKeyEx(root, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize", access=KEY_ALL_ACCESS)
    light, _ = QueryValueEx(policy_key, "AppsUseLightTheme")
    SetValueEx(policy_key, "AppsUseLightTheme", 0, REG_SZ, str(1-int(light)))
    SetValueEx(policy_key, "SystemUsesLightTheme", 0, REG_SZ, str(1-int(light)))
    CloseKey(policy_key)


"""
This script is watching a specific file for the presence of 2D points,
    and plots them in a live fashion.
"""
import csv
import os
import random
import tkinter as tk

import matplotlib
import matplotlib.animation as animation
from matplotlib import style
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

matplotlib.use("TkAgg")

matplotlib.style.use("ggplot")

file_location = "data.txt"

f = Figure(figsize=(5, 5), dpi=100)
a = f.add_subplot(111)

def create_a_file_and_input_random_data_to_it():
    with open(file_location, "w") as data_file:
        x_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        y_values = [random.randint(0, 10) for _ in range(10)]
        for x, y in zip(x_values, y_values):
            line = "{},{}\n".format(x, y)
            data_file.write(line)

def animate(i):
    with open(file_location, "r") as data_file:
        csvReader = csv.reader(data_file)

        x_list = []
        y_list = []
        for row in csvReader:
            if row:
                x_list.append(float(row[0]))
                y_list.append(float(row[1]))

        a.clear()
        a.plot(x_list, y_list)

main_window = tk.Tk()
main_window.state("zoomed")
main_window.title("File point watcher")

f = Figure(figsize=(5, 5), dpi=100)
a = f.add_subplot(111)

a.clear()
x_list, y_list = [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]
a.plot(x_list, y_list)

canvas = FigureCanvasTkAgg(f, main_window)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

# Creates the file if it does not exist
if not os.path.isfile(file_location):
    create_a_file_and_input_random_data_to_it()

ani = animation.FuncAnimation(f, animate, interval=500)
main_window.mainloop()


import json
import csv
import os
from flask import (
    Blueprint,  send_file, flash, g, redirect, render_template, request, session, url_for, current_app
)
from app.db import get_mongo
from app.db import get_db

admin_blueprint = Blueprint('admin', __name__, url_prefix='/admin')

data_dir = os.path.join(admin_blueprint.root_path, 'data')

print("root path", admin_blueprint.root_path)

@admin_blueprint.route('/', methods=['GET', 'POST'])
def admin():
    db = get_db()

    if ('admin' not in session):
        # session['admin'] = False;
        return redirect(url_for('index'))

    data = {}

    exams_in_db = db.execute(
        "SELECT count(*) as count from exam").fetchone()['count']

    users_in_db = db.execute(
        "SELECT count(*) as count from user").fetchone()['count']

    tests_in_db = db.execute(
        "SELECT count(*) as count from test").fetchone()['count']

    data['exams_in_db'] = exams_in_db
    data['users_in_db'] = users_in_db - 1
    data['tests_in_db'] = tests_in_db

    users = []
    user_details_in_db = db.execute(
        "SELECT * FROM user WHERE configured=1"
    ).fetchall()

    for user in user_details_in_db:
        print(user['name'])
        users.append({
            "id": user['id'],
            "email": user['email'],
            "name": user['name']
        })

    return render_template("admin/dashboard.html", data=data, users=users)

@admin_blueprint.route('/plan/<email>', methods=['GET', 'POST'])
def admin_user_plan_progress(email):
    db = get_db()

    if ("admin" not in session):
        return redirect(url_for('index'))

    plan_in_db = db.execute(
        "SELECT * FROM plan\
            WHERE email=?", (email,)
    ).fetchone()

    plan_id = plan_in_db["id"]
    start_date = plan_in_db["start_date"]
    end_date = plan_in_db["end_date"]

    dates = {
        "start_date": start_date.strftime("%m/%d/%Y"),
        "end_date": end_date.strftime("%m/%d/%Y")
    }

    uncompleted_topics_in_db = db.execute(
        "SELECT * FROM plan_details WHERE completed = 0 AND plan_id=?", (
            plan_id,)
    ).fetchall()

    completed_topics_in_db = db.execute(
        "SELECT * FROM plan_details WHERE completed = 1 AND plan_id=?", (
            plan_id,)
    ).fetchall()

    topic_number_data = {
        "completed": len(completed_topics_in_db),
        "uncompleted": len(uncompleted_topics_in_db),
    }
    print(topic_number_data)

    subject_data = {}

    for topic_row in completed_topics_in_db:
        if topic_row["subject_name"] in subject_data:
            subject_data[topic_row["subject_name"]] += 1
        else:
            subject_data[topic_row["subject_name"]] = 1

    subject_data["Uncompleted"] = len(uncompleted_topics_in_db)

    print(subject_data)

    return render_template('admin/plan_progress.html', email=email, topic_number_data=json.dumps(topic_number_data), start_end=dates, dates=json.dumps(dates), subject_data=json.dumps(subject_data))

@admin_blueprint.route('/syllabus', methods=['GET', 'POST'])
def admin_syllabus():
    db = get_db()

    if ('admin' not in session):
        # session['admin'] = False;
        return redirect(url_for('index'))

    exams_in_db = db.execute(
        "SELECT * FROM exam"
    ).fetchall()

    exams = []

    for exam in exams_in_db:
        exams.append({"id": exam["id"], "exam_name": exam["exam_name"]})
    print(exams)

    return render_template("admin/syllabus.html", exams=exams)

@admin_blueprint.route('/questions', methods=['GET', 'POST'])
def admin_question():
    db = get_db()

    if ('admin' not in session):
        # session['admin'] = False;
        return redirect(url_for('index'))

    topics_in_db = db.execute(
        "SELECT * FROM exam_details"
    ).fetchall()

    topics = []

    for topic in topics_in_db:
        topics.append({"id": topic["id"], "topic_name": topic["topic_name"]})

    return render_template("admin/questions.html", topics=topics)

@admin_blueprint.route('/download/questions', methods=['GET', 'POST'])
def download_questions():
    db = get_db()
    if request.method == "POST":
        topic_id = request.form['topic_id']
        questions_in_db = db.execute(
            "SELECT * FROM questions \
            WHERE topic_id = ?", (topic_id,)
        ).fetchall()
        column_names = [
            "id",
            "topic_id",
            "question_statement",
            "a",
            "b",
            "c",
            "d",
            "answer"
        ]
        topic_name = db.execute(
            "SELECT * FROM exam_details WHERE id = ?", (topic_id,)
        ).fetchone()["topic_name"]

        file_name = f"{topic_id}_{topic_name}.csv"
        file_path = os.path.join(data_dir, file_name)
        fp = open(file_path, 'w+')
        # use lineterminator for windows
        myFile = csv.writer(fp, lineterminator='\n')
        myFile.writerow(column_names)

        for row in questions_in_db:
            question = [
                row["id"],
                row["topic_id"],
                row["question_statement"],
                row["a"],
                row["b"],
                row["c"],
                row["d"],
                row["answer"]
            ]
            myFile.writerow(question)

        fp.close()
        return send_file(file_path, as_attachment=True)

@admin_blueprint.route('/upload/questions', methods=['GET', 'POST'])
def upload_questions():
    db = get_db()
    if request.method == "POST":

        if 'file' not in request.files:
            flash('No files')
            return redirect(url_for('admin.admin'))
        file = request.files['file']
        if file.filename == '':
            flash('No selected file')
            return redirect(url_for('admin.admin'))
        file_name = file.filename

        topic_id, topic_name = file_name.split('_')
        file_path = os.path.join(data_dir, file_name)

        file.save(file_path)

        update_rows = []
        new_rows = []
        delete_rows = []

        with open(file_path, mode='r')as file:

            # reading the CSV file
            csvFile = csv.reader(file)

            # displaying the contents of the CSV file
            for lines in csvFile:
                print(lines)
                if (lines[0] == ''):
                    new_rows.append(lines)
                elif (lines[1] == '' and lines[2] == '' and lines[3] == ''):
                    delete_rows.append(lines[0])
                else:
                    update_rows.append(lines)

        update_rows.pop(0)

        print("update", update_rows)
        print("new", new_rows)
        print("delete", delete_rows)

        for id in delete_rows:
            db.execute(
                "DELETE FROM questions where id=?", (id,)
            )
        for lines in update_rows:
            db.execute(
                "UPDATE questions SET question_statement=?, a=?, b=?, c=?, d=?, answer=? WHERE id=?", (
                    lines[2], lines[3], lines[4], lines[5], lines[6], lines[7], lines[0])
            )

        for lines in new_rows:
            db.execute(
                "INSERT INTO questions (topic_id, question_statement, a, b, c, d, answer) VALUES(?,?,?,?,?,?,?)",
                (topic_id, lines[2], lines[3],
                 lines[4], lines[5], lines[6], lines[7])
            )
        db.commit()
        error = "updated questions for " + topic_name
        flash(error)
        return redirect(url_for('admin.admin_question'))

@admin_blueprint.route('/download/syllabus', methods=['GET', 'POST'])
def download_syllabus():
    db = get_db()
    if request.method == "POST":
        exam_id = request.form['exam']
        topics_in_db = db.execute(
            "SELECT * FROM exam_details \
            WHERE exam_id = ?", (exam_id,)
        ).fetchall()
        exam_name = db.execute(
            "SELECT * FROM exam WHERE id = ?", (exam_id,)
        ).fetchone()["exam_name"]

        column_names = [
            "id",
            "topic_name",
            "subject_name",
            "required_hours"
        ]
        file_name = f"{exam_id}_{exam_name}.csv"
        file_path = os.path.join(data_dir, file_name)
        fp = open(file_path, 'w+')
        # use lineterminator for windows
        myFile = csv.writer(fp, lineterminator='\n')
        myFile.writerow(column_names)
        for row in topics_in_db:
            topic = [
                row['id'],
                row['topic_name'],
                row['subject_name'],
                row['required_hours']
            ]
            myFile.writerow(topic)
        fp.close()
        return send_file(file_path, as_attachment=True)

@admin_blueprint.route('/upload/syllabus', methods=['GET', 'POST'])
def upload_syllabus():
    db = get_db()
    if request.method == "POST":

        if 'file' not in request.files:
            flash('No files')
            return redirect(url_for('admin.admin'))
        file = request.files['file']
        if file.filename == '':
            flash('No selected file')
            return redirect(url_for('admin.admin'))
        file_name = file.filename

        exam_id, exam_name = file_name.split('_')
        file_path = os.path.join(data_dir, file_name)

        file.save(file_path)

        update_rows = []
        new_rows = []
        delete_rows = []

        with open(file_path, mode='r')as file:

            # reading the CSV file
            csvFile = csv.reader(file)

            # displaying the contents of the CSV file
            for lines in csvFile:
                print(lines)
                if (lines[0] == ''):
                    new_rows.append(lines)
                elif (lines[1] == '' and lines[2] == '' and lines[3] == ''):
                    delete_rows.append(lines[0])
                else:
                    update_rows.append(lines)

        update_rows.pop(0)

        print("update", update_rows)
        print("new", new_rows)
        print("delete", delete_rows)

        for id in delete_rows:
            db.execute(
                "DELETE FROM exam_details where id=?", (id,)
            )

        for lines in update_rows:
            db.execute(
                "UPDATE exam_details SET topic_name=?, subject_name=?, required_hours=? WHERE id=?", (
                    lines[1], lines[2], lines[3], lines[0],)
            )

        for lines in new_rows:
            db.execute(
                "INSERT INTO exam_details (exam_id, topic_name, subject_name, required_hours) VALUES(?,?,?,?)",
                (exam_id, lines[1], lines[2], lines[3])
            )
        db.commit()

        os.remove(file_path)

        error = "updated syllabus"
        flash(error)
        return redirect(url_for('admin.admin_syllabus'))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Attempt of recreating the 1D example from L. Boninsegna and C. Clementi,
“Sparse learning of stochastic dynamical equations,”
J. Chem. Phys., vol. 148, p. 241723, 2018, doi: 10.1063/1.5018409.
"""
import numpy as np
import matplotlib.pyplot as plt
from dataprep import *
from stochastic_sindy import *

plt.rcParams.update({
    "text.usetex": True,
    "font.family": "serif",
    "font.serif": ["Computer Modern"],
    "pgf.texsystem": "pdflatex",
    'pgf.rcfonts': False
})
#%% Defining the force function
y = lambda x : 3 - 18*x  + 12*x**2 - 2*x**3
u = lambda x : x**4/2-4*x**3+9*x**2-3*x
# y = lambda x : 0*x
x = np.linspace(-1,5,100)

fig, (ax1, ax2) = plt.subplots(1,2,dpi=200, figsize = (10,4))

ax1.plot(x,y(x), 'k')
ax1.set_xlabel("$x$")
ax1.set_ylabel("$F(x)$")
ax1.set_ylim([-35,30])
ax1.axhline(0, alpha = 0.2, c = 'k')
ax2.plot(x,u(x), 'k')
ax2.set_xlabel("$x$")
ax2.set_ylabel("$U(x)$")
ax2.set_ylim([-1,16])
plt.show()

#%% Generating time series of multiple trajectories
import multiprocessing as mp
import time

x_multiple = []
dt = 5e-3
n = int(1e3)
n_traj = 5
diffusion = 1
sigma_y = 0
sigma = sigma_y*dt/np.sqrt(2)
# x0s = np.full(4,2)
x0s = np.linspace(-0.606,4.27,n_traj)
t = time.time()

def mp_ts(x0):
    np.random.seed()
    return time_series(y,x0,dt,n,diffusion)

pool = mp.Pool()
x_multiple = pool.map(mp_ts, x0s)
pool.close()
pool.join()

# for x0 in np.linspace(-1,5,n_traj):
#     x_multiple.append(time_series(y, x0, dt, n, diffusion))

x_multiple = np.array(x_multiple)

print(time.time() - t)

fig, (ax1,ax2,ax3) = plt.subplots(1,3, figsize = (6,4), dpi = 200)
plt.rcParams['axes.facecolor'] = 'w'

for i in range(n_traj):
    plt.plot(np.linspace(0,n*dt,n+1),x_multiple[i], linewidth = 0.3)
plt.xlabel("$t$")
plt.ylabel("$x$")

# x_multiple = add_noise(x_multiple, sigma)

# for i in range(n_traj):
#     plt.scatter(x_multiple[i],np.linspace(0,n*dt,n+1), c='r', s=4)
# plt.xlabel("x")
# plt.ylabel("t")
# plt.show()

x_multiple = np.array(x_multiple).T

# x_multiple = add_noise(x_multiple, .05)

#%% Trajectory plot

import multiprocessing as mp
import time

fig, axs = plt.subplots(1,3, figsize = (6,4), dpi = 200, sharey=True)
plt.rcParams['axes.facecolor'] = 'w'

Ds = [0.2,1,5]

for di in range(3):
    diffusion = Ds[di]
    x_multiple = []
    dt = 5e-3
    n = int(1e3)
    n_traj = 5
    sigma_y = 0
    sigma = sigma_y*dt/np.sqrt(2)
    # x0s = np.full(4,2)
    x0s = np.linspace(-0.606,4.27,n_traj)
    t = time.time()

    def mp_ts(x0):
        np.random.seed()
        return time_series(y,x0,dt,n,diffusion)

    pool = mp.Pool()
    x_multiple = pool.map(mp_ts, x0s)
    pool.close()
    pool.join()

    # for x0 in np.linspace(-1,5,n_traj):
    #     x_multiple.append(time_series(y, x0, dt, n, diffusion))

    x_multiple = np.array(x_multiple)

    print(time.time() - t)

    for i in range(n_traj):
        axs[di].plot(x_multiple[i], np.linspace(0,n*dt,n+1),linewidth = 0.3)
    axs[di].set_xlabel("$x$")
    axs[di].set_xlim([-3,7])

# x_multiple = add_noise(x_multiple, sigma)

# for i in range(n_traj):
#     plt.scatter(x_multiple[i],np.linspace(0,n*dt,n+1), c='r', s=4)
# plt.xlabel("x")
# plt.ylabel("t")
# plt.show()
fig.tight_layout()
axs[0].set_ylabel("$t$")

plt.show()
x_multiple = np.array(x_multiple).T

# x_multiple = add_noise(x_multiple, .05)
#%% Computing the matrices X and Y
Y_multiple = ps.differentiation.FiniteDifference(order = 1)._differentiate(
    x_multiple, dt
)

# Stack the data into one column
Y_single = Y_multiple.reshape(-1, 1, order = 'F')
x_single = x_multiple.reshape(-1, 1, order = 'F')

basis = ps.feature_library.polynomial_library.PolynomialLibrary(degree=15)
basis.fit(x_single)
X_single = basis.transform(x_single)

n_pos = X_single.shape[1]*Y_single.shape[1]
n_features = X_single.shape[1]

#%% Bin the data and use it to infer the force
x_binned, Y_binned, weights = bin_data(x_single, Y_single, 90,
                                       width_type = 'equal')
basis.fit(x_binned)
X_binned = basis.transform(x_binned)
W = np.diag(weights)

plt.scatter(x_binned.squeeze(), Y_binned.squeeze(), s = 40*(weights/np.max(weights)),
            marker = 'o', facecolor = 'b', alpha = 0.3)
plt.plot(x,y(x), 'k')

mask = np.zeros((n_features,1), dtype = 'bool')
mask[0:4] = True
# mask = np.ones([True, True, True, True, False, False,
#                  False, False, False, False, False]).reshape(-1,1)
C, mask = SSR_step(np.matmul(W,X_binned), np.matmul(W,Y_binned), mask)
print(C)

y_pred = lambda x : C[0] + C[1]*x + C[2]*x**2 + C[3]*x**3 + C[4]*x**4
plt.plot(x, y_pred(x), 'r--')
plt.show()

#%%
errors = CV_scores(np.matmul(W,X_binned), np.matmul(W,Y_binned), K=5)
plt.semilogy(np.arange(1, X_single.shape[1] * Y_single.shape[1] + 1, 1), errors, '-o')
plt.xticks(np.arange(1,X_single.shape[1]+1,1))
plt.xlabel("Total number of nonzero terms")
plt.ylabel("Cross-validation score $\delta$")
plt.show()

opt_n = opt_term_n(errors)
print(opt_n)

#%%
Cs, masks, errors = SSR(np.matmul(W,X_binned), np.matmul(W,Y_binned))
coeffs = np.abs(Cs.squeeze())
coeffs[~masks.squeeze()] = None
# for i in range(coeffs.shape[0]):
#     coeffs[i,:] -= np.nanmin(coeffs[i,:])*.99
#     coeffs[i,:] /= np.nanmax(coeffs[i,:])
coeffs = np.log10(coeffs)

###
idxs = np.arange(0.5,n_features+1.5,1)
pos = np.arange(0.5,n_pos+1.5,1)

X_mesh, Y_mesh = np.meshgrid(idxs, pos)

plt.rcParams['axes.facecolor'] = [.65]*3

fig = plt.figure(dpi = 200)
ax = fig.add_subplot(1,1,1)

cmap = pl.cm.Reds.copy()
cmap.set_bad(alpha = 0)

plt.rc('axes', axisbelow=False)

im = plt.pcolor(X_mesh, Y_mesh, coeffs[:,:], cmap = cmap,
                  shading = "flat", alpha = 0.95)
plt.gca().invert_yaxis()

# x-axis
def insert(source_str, insert_str, pos):
    return source_str[:pos]+insert_str+source_str[pos:]

f_names = basis.get_feature_names(["x","y"])
f_names = np.ravel(f_names)
f_names = np.array(["$"+insert(s,"{",s.find("^")+1)+"}$" for s in f_names])
plt.xticks(np.arange(1,n_pos+1,1),
           f_names,
           rotation='vertical')
ax.set_xticks(np.arange(0.5,n_pos+1,1), minor=True)

# y-axis
y_labels = np.arange(1,n_pos+1,1).astype('str')
y_labels = np.array(["$"+s+"$" for s in y_labels])
plt.yticks(np.arange(1,n_pos+1,1), y_labels)
ax.set_yticks(np.arange(0.5,n_pos+1,1), minor=True)
plt.ylim([n_pos+0.5,0])
plt.xlim([0.5, n_pos+0.5])
for i in range(n_pos):
    if true_mask.ravel(order="F")[i]:
        pass
        # plt.axvline(i+0.5, zorder = 1, c = 'k')
        # plt.axvline(i+1.5, zorder = 1, c = 'k')
        # f_name = basis.get_feature_names(["x","y"])[np.mod(i, X.shape[1])]
        # plt.text(i+.75,-.4,"$"+f_name+"$")

# Optimal functions
# plt.axhline(opt_n-.5, c="k", zorder = 10)
# plt.axhline(opt_n+.5, c="k", zorder = 10)
opt_x, opt_y = np.meshgrid([0.5, n_pos+0.5], [opt_n-.5, opt_n+.5])
plt.pcolor(opt_x, opt_y, np.full((1,1),1), alpha = 0.5, shading = 'flat',
           cmap = 'binary', zorder = -1)

plt.xlabel("Function")
plt.ylabel("Survival position")
plt.grid(True, which = "minor", linewidth = 1, c = 'w')
ax.tick_params(length = 0, which = 'both')
ax.set_aspect("equal")

# plt.scatter(np.arange(1, n_pos+1,1)[true_mask.ravel(order = "F")],
#             [5]*true_mask.sum(), c = "w")
# plt.grid()
plt.show()