text:
# -*- coding: utf-8 -*-
"""
Created in 07/2021

@author: Eyal Cohen
"""

if __name__ == "__main__":
    import os
    from matplotlib.figure import Figure
    import matplotlib.pyplot as plt
    import matplotlib
    matplotlib.use("TkAgg")
    import sys
    import tkinter as tk
    from tkinter import DISABLED, NORMAL
    from tkinter import BOTTOM, TOP, LEFT, RIGHT
    from tkinter import ttk
    import networkx as nx
    from networkx import NetworkXException
    import TkinterDnD2 as tkd
    import PAFtoAF as paf
    import platform
    from PAFtoAF import UnsupportedFormatException, FormatSyntaxException,  PreferenceException, FormatException, CommandLineException, FindingSolverException, UnsupportedOSException
    from datetime import (date, datetime)

    system = platform.system()
    if system not in ["Windows", "Linux", "Darwin"]:
        root = tk.Tk()
        root.withdraw()
        msg = tk.messagebox.showinfo("Error", "It looks like you system is not supported.\nSupported systems : Windows, Linux, Darwin(MacOS)\nYour system : {}".format(system))
        while msg != "ok":
            continue
        sys.exit()

    inputfile = ''
    fileformat = ''
    query_bool = False
    tempFile = []
    solverPath = ''
    reduction = 0
    fig = Figure()

    if os.path.exists("temp"):
        if not (os.path.isdir("temp")):
            os.remove("temp")
        else:
            for file in os.scandir("temp"):
                os.remove(file)
            os.rmdir("temp")
    os.mkdir("temp")

    a = open("temp/reloading_text.ptgf", "w+")
    a.close()

    a = open("temp/reloading_text.papx", "w+")
    a.close()

    def reset_values():
        global reduction
        global query_bool
        global solverpath
        query_bool = False
        task_label.grid(row = 0, column = 1)
        queryframe.grid_remove()
        renew_query_frame()
        solverpath = ''
        reduction = 0
        textarea.delete("1.0","end")
        textareaReduc["state"] = NORMAL
        textareaReduc.delete("1.0","end")
        textareaReduc["state"] = DISABLED
        button0["bg"] = "red"
        button0["state"] = DISABLED
        button1["bg"] = "white"
        button1["state"] = NORMAL
        button2["bg"] = "white"
        button2["state"] = NORMAL
        button3["bg"] = "white"
        button3["state"] = NORMAL
        button4["bg"] = "white"
        button4["state"] = NORMAL
        problem_box.set("")
        problem_value.set("")
        semantic_box.set("")
        semantic_value.set("")
        problem_box["state"] = DISABLED
        semantic_box["state"] = DISABLED
        solver.delete(0, tk.END)
        solver_value.set("")
        solver["state"] = DISABLED
        solver_select_button["state"] = DISABLED
        solver_find_button["state"] = DISABLED
        download_button["state"] = DISABLED
        textareaReduc.configure(state = "disabled")

    def try_toPaf(file, fileformat = ''):
        """
        This method is just a toPaf that can manage the different possible Exceptions.
        It is invoked every time we want to convert something to the PAF format in PAFtoAF : (set, dict, dict).
        str * str -> None
        """

        assert type(file) is str, "The first argument must be the name of the file. (type String)"
        assert type(fileformat) is str, "The second argument must be the format of the file. (type String)"

        if fileformat == '':
            try:
                paf.toPaf(file, "ptgf" if file.endswith(".ptgf") or file.endswith(".tgf") else "papx")
            except FileNotFoundError:
                print("It seems that the file you used as input can not be found anymore.")
                textarea.delete("1.0", "end")
                textarea.insert("end", "It seems that the file you used as input can not be found anymore.")
            except (IOError, OSError) as e:
                print("System Error")

                def fatal_closing():
                    fatal_window.destroy()
                    on_closing()

                fatal_window = tk.Tk()
                fatal_window.title("System Error")
                fatal_frame = tk.Frame(fatal_window)
                fatal_frame.pack(side = tk.CENTER)
                fatal_label = tk.Label(fatal_frame, text = "System Error :\n{}".format(e))
                fatal_label.pack(side = TOP)
                fatal_button = tk.Button(fatal_frame, text = "Ok", command = fatal_closing)
                fatal_button.pack(side = BOTTOM)
                fatal_window.protocol("WM_DELETE_WINDOW", fatal_closing)

            except FormatSyntaxException as e:
                textareaReduc["state"] = NORMAL
                textareaReduc.delete("1.0", "end")
                textareaReduc.insert("end", "Format syntax error :\n"+str(e))
                textareaReduc["state"] = DISABLED
                problem_box.set("")
                semantic_box.set("")
                problem_box["state"] = DISABLED
                semantic_box["state"] = DISABLED
                solver.delete(0, tk.END)
                solver["state"] = DISABLED
                solver_select_button["state"] = DISABLED
                solver_find_button["state"] = DISABLED
                button0["state"] = DISABLED
                button1["state"] = DISABLED
                button2["state"] = DISABLED
                button3["state"] = DISABLED
                button4["state"] = DISABLED
                graph_check["state"] = DISABLED
            except PreferenceException as e:
                textareaReduc["state"] = NORMAL
                textareaReduc.delete("1.0", "end")
                textareaReduc.insert("end", "Preferences error :\n"+str(e))
                textareaReduc["state"] = DISABLED
                problem_box.set("")
                semantic_box.set("")
                problem_box["state"] = DISABLED
                semantic_box["state"] = DISABLED
                solver.delete(0, tk.END)
                solver["state"] = DISABLED
                solver_select_button["state"] = DISABLED
                solver_find_button["state"] = DISABLED
                button0["state"] = DISABLED
                button1["state"] = DISABLED
                button2["state"] = DISABLED
                button3["state"] = DISABLED
                button4["state"] = DISABLED
                graph_check["state"] = DISABLED
            except UnsupportedFormatException as e:
                textarea.delete("1.0", "end")
                textarea.insert("end", "Unsupported format exception :\n", str(e))
                problem_box.set("")
                semantic_box.set("")
                problem_box["state"] = DISABLED
                semantic_box["state"] = DISABLED
                solver.delete(0, tk.END)
                solver["state"] = DISABLED
                solver_select_button["state"] = DISABLED
                solver_find_button["state"] = DISABLED
                button0["state"] = DISABLED
                button1["state"] = DISABLED
                button2["state"] = DISABLED
                button3["state"] = DISABLED
                button4["state"] = DISABLED
                graph_check["state"] = DISABLED
        else:
            try:
                paf.toPaf(file, "ptgf" if fileformat in ["ptgf", "tgf"] else "papx")
            except FileNotFoundError:
                print("It seems that the file you used as input can not be found anymore.")
                textarea.delete("1.0", "end")
                textarea.insert("end", "It seems that the file you used as input can not be found anymore.")
                problem_box.set("")
                semantic_box.set("")
                problem_box["state"] = DISABLED
                semantic_box["state"] = DISABLED
                solver.delete(0, tk.END)
                solver["state"] = DISABLED
                solver_select_button["state"] = DISABLED
                solver_find_button["state"] = DISABLED
                button0["state"] = DISABLED
                button1["state"] = DISABLED
                button2["state"] = DISABLED
                button3["state"] = DISABLED
                button4["state"] = DISABLED
                graph_check["state"] = DISABLED
            except (IOError, OSError) as e:
                print("System Error")

                def fatal_closing():
                    fatal_window.destroy()
                    on_closing()

                fatal_window = tk.Tk()
                fatal_window.title("System Error")
                fatal_frame = tk.Frame(fatal_window)
                fatal_frame.pack(side = tk.CENTER)
                fatal_label = tk.Label(fatal_frame, text = "System Error :\n{}".format(e))
                fatal_label.pack(side = TOP)
                fatal_button = tk.Button(fatal_frame, text = "Ok", command = fatal_closing)
                fatal_button.pack(side = BOTTOM)
                fatal_window.protocol("WM_DELETE_WINDOW", fatal_closing)

            except FormatSyntaxException as e:
                textareaReduc["state"] = NORMAL
                textareaReduc.delete("1.0", "end")
                textareaReduc.insert("end", "Format syntax error :\n"+str(e))
                textareaReduc["state"] = DISABLED
                problem_box.set("")
                semantic_box.set("")
                problem_box["state"] = DISABLED
                semantic_box["state"] = DISABLED
                solver.delete(0, tk.END)
                solver["state"] = DISABLED
                solver_select_button["state"] = DISABLED
                solver_find_button["state"] = DISABLED
                button0["state"] = DISABLED
                button1["state"] = DISABLED
                button2["state"] = DISABLED
                button3["state"] = DISABLED
                button4["state"] = DISABLED
                graph_check["state"] = DISABLED
            except PreferenceException as e:
                textareaReduc["state"] = NORMAL
                textareaReduc.delete("1.0", "end")
                textareaReduc.insert("end", "Preferences error :\n"+str(e))
                textareaReduc["state"] = DISABLED
                problem_box.set("")
                semantic_box.set("")
                problem_box["state"] = DISABLED
                semantic_box["state"] = DISABLED
                solver.delete(0, tk.END)
                solver["state"] = DISABLED
                solver_select_button["state"] = DISABLED
                solver_find_button["state"] = DISABLED
                button0["state"] = DISABLED
                button1["state"] = DISABLED
                button2["state"] = DISABLED
                button3["state"] = DISABLED
                button4["state"] = DISABLED
                graph_check["state"] = DISABLED

    def load_text(event):
        """
        This method is binded to the drag and drop text area, it is invoked when someone drop a file,
        and just load the text inside the file if the format is right and write an error message in the area if the format is not accepted.
        Event -> None
        """

        textarea.delete("1.0","end")
        textareaReduc["state"] = NORMAL
        textareaReduc.delete("1.0","end")
        textareaReduc["state"] = DISABLED
        button0["bg"] = "white"
        button1["bg"] = "white"
        button2["bg"] = "white"
        button3["bg"] = "white"
        button4["bg"] = "white"
        reset_values()
        global inputfile
        global fileformat
        if event.data.endswith(".ptgf") or event.data.endswith(".papx"):
            inputfile = event.data
            fileformat = "ptgf" if event.data.endswith(".ptgf") else "papx"
            with open(event.data, "r") as file:
                for line in file:
                    line=line.strip()
                    textarea.insert("end",f"{line}\n")
            button0["bg"] = "red"
            button0["state"] = DISABLED
            button1["state"] = NORMAL
            button2["state"] = NORMAL
            button3["state"] = NORMAL
            button4["state"] = NORMAL
            graph_check["state"] = NORMAL
            try_toPaf(event.data)
        elif event.data.endswith(".tgf") or event.data.endswith(".apx"):
            inputfile = event.data
            fileformat = "tgf" if event.data.endswith(".tgf") else "apx"
            with open(event.data, "r") as file:
                for line in file:
                    line=line.strip()
                    textarea.insert("end",f"{line}\n")
            button0["bg"] = "red"
            button0["state"] = DISABLED
            button1["state"] = NORMAL
            button2["state"] = NORMAL
            button3["state"] = NORMAL
            button4["state"] = NORMAL
            graph_check["state"] = NORMAL
            try_toPaf(event.data)
        else:
            button0["state"] = DISABLED
            button1["state"] = DISABLED
            button2["state"] = DISABLED
            button3["state"] = DISABLED
            button4["state"] = DISABLED
            graph_check["state"] = DISABLED
            paf.args.clear()
            paf.attacksFrom.clear()
            paf.preferences.clear()
            textarea.insert("end","Sorry this document format is not\naccepted.\nPlease use .ptgf .papx .tgf or .apx\nformats.\n\nFor help please click on the help button and to see the available formats click onthe formats button.")
        global graph_check_value
        if graph_check_value.get() == 1:
            show_graph()

    def load_text_selection():
        """
        This method is the one used by the button open (for the files) on the GUI.
        It opens a window allowing the user to browse its file and then reads and load the selected file.
        """

        typeslist = [("PTFG file", ".ptgf"), ("PAPX file", ".papx"), ("TGF file", ".tgf"), ("APX file", ".apx")]
        Sfile = tk.filedialog.askopenfilename(title = "Sélectionnez un fichier ..." , filetypes = typeslist)
        load_text_file(Sfile)

    def select_solver():
        """
        This method is the one used by the button open (for the solver) on the GUI.
        It opens a window allowing the user to browse its file and select the solver.
        """
        global solverPath
        typeslist = [("Executable", ".exe"), ("Python", ".py"), ("Java", ".jar"), ("Other", ".*")]
        Sfile = tk.filedialog.askopenfilename(title = "Sélectionnez un fichier ..." , filetypes = typeslist)
        solverPath = Sfile
        solver.delete(0, tk.END)
        solver.insert(tk.END, Sfile)

    def find_solver():
        """
        This method is linked to the find button (under the solver entry).
        It scans the current directory and see if it can find the solver, if it can it will write its path in the entry, if not it will write 'not found'.
        """
        global solverPath
        found = True
        solver_name = solver_value.get()
        if os.path.exists(solver_name):
            if os.path.isdir(solver_name):
                found = False
                for file in os.scandir(solver_name):
                    if os.fsdecode(file) in ["mu-toksia", "mu-toksia.exe", "JargSemSAT.jar"]:
                        solverPath = os.path.abspath(solver_name + os.fsdecode(file))
                        found = True
            else:
                solverPath = os.path.abspath(solver_name)
        else:
            found = False
        if not found:
            solver.delete(0,tk.END)
            solver.insert(tk.END, "Not found")
        else:
            solver.delete(0,tk.END)
            solver.insert(tk.END, solverPath)

    def load_text_file(Sfile):
        """
        This method is the same as load_text but works without an event,
        it just reads the file that the load_text_selection gave it and loads the text inside the same way, load_text does.
        """

        assert type(Sfile) is str, "The argument of this method is the name of the file it has to load. (type String)"

        reset_values()

        global inputfile
        global fileformat
        global reduction

        if Sfile.endswith(".ptgf") or Sfile.endswith(".papx"):
            inputfile = Sfile
            fileformat = "ptgf" if Sfile.endswith(".ptgf") else "papx"
            with open(Sfile, "r") as file:
                for line in file:
                    line=line.strip()
                    textarea.insert("end",f"{line}\n")
            try_toPaf(Sfile, fileformat)
            button0["bg"] = "red"
            button0["state"] = DISABLED
            button1["state"] = NORMAL
            button2["state"] = NORMAL
            button3["state"] = NORMAL
            button4["state"] = NORMAL
            graph_check["state"] = NORMAL
        elif Sfile.endswith(".tgf") or Sfile.endswith(".apx"):
            inputfile = Sfile
            fileformat = "tgf" if Sfile.endswith(".tgf") else "apx"
            with open(Sfile, "r") as file:
                for line in file:
                    line=line.strip()
                    textarea.insert("end",f"{line}\n")
            try_toPaf(Sfile, fileformat)
            button0["bg"] = "red"
            button0["state"] = DISABLED
            button1["state"] = NORMAL
            button2["state"] = NORMAL
            button3["state"] = NORMAL
            button4["state"] = NORMAL
            graph_check["state"] = NORMAL
        else:
            button0["state"] = DISABLED
            button1["state"] = DISABLED
            button2["state"] = DISABLED
            button3["state"] = DISABLED
            button4["state"] = DISABLED
            graph_check["state"] = DISABLED
            paf.args.clear()
            paf.attacksFrom.clear()
            paf.preferences.clear()
            textarea.insert("end","Sorry this document format is not\naccepted.\nPlease use .ptgf .papx .tgf or .apx\nformats.\n\nFor help please click on the help button and to see the available formats click onthe formats button.")
        global graph_check_value
        if graph_check_value.get() == 1:
            show_graph()

    def reload_text():
        """
        This method reads the text area and reload the text.
        It means that the user can now modify the text inside the area to modify the PAF they want to generate.
        """
        global inuptfile
        global fileformat
        if fileformat == '':
            textarea.get("1.0", "2.0")
            if line_is_int(textarea.get("1.0", "1.1")):
                fileformat = "ptgf"
            elif(textarea.get("1.0", "2.0")[0:3] == "arg"):
                fileformat = "papx"
            else:
                textareaReduc["state"] = NORMAL
                textareaReduc.delete("1.0","end")
                textareaReduc.insert("end", "\nThe text written in the box next to this one does not follow an accepted format.\nPlease consult the format option button for more information.\n")
                textareaReduc["state"] = DISABLED
                return 0
        inputfile = "temp/reloading_text.{}".format(fileformat)
        with open(inputfile, "w+") as openfile:
            openfile.write(textarea.get("1.0", "end"))

        load_text_file(inputfile)

    def line_is_int(line):
        """
        This method verify if the line it receives is an int, it is used to get the format if the user writes the file or writes directly on the text area.
        Object -> bool
        """
        if type(line) is int:
            return(True)
        elif type(line) is str:
            try:
                int(line)
            except:
                return(False)
            return(True)
        elif type(line) is float:
            if line%1==0:
                return(True)
        return(False)

    window = tkd.TkinterDnD.Tk()
    window.title('PAFtoAF')
    window.geometry('750x800')
    window.config(bg='#554356')

    ws = tk.Frame(window)
    ws.pack(side = TOP)

    frame = tk.Frame(ws, height = 60, width = 82)
    frame.pack()

    optionframe = tk.Frame(frame, height = 10, width = 40)
    optionframe.pack(side = TOP)

    frameDnD = tk.Frame(frame, height = 23, width = 41)
    frameDnD.pack(side = LEFT)

    frameReduction = tk.Frame(frame, height = 23, width = 41)
    frameReduction.pack(side = RIGHT)

    compute_frame = tk.Frame(ws)
    compute_frame.pack(side = BOTTOM)

    taskframe = tk.Frame(ws)
    taskframe.pack(side = BOTTOM)

    solverframe = tk.Frame(ws)
    solverframe.pack(side = BOTTOM)

    buttonframe = tk.Frame(ws, height = 5, width = 40)
    buttonframe.pack(side = BOTTOM)

    queryframe = tk.Frame(taskframe)

    def show_help():
        """
        The method linked to the help button (in the option frame), it creates a new window with nothing but a text area explaining the GUI.
        """
        help_window = tk.Tk()
        help_window.title("HELP")
        help_window.geometry("696x590")
        help_window.config(bg = "#dddddd")
        help_frame = tk.Frame(help_window, height = 38, width = 86)
        help_frame.pack()
        help_text = tk.Text(help_frame, height = 36, width = 84)
        help_text.grid(column = 0, row = 0, columnspan = 10, rowspan = 10)

        sbv_help = tk.Scrollbar(help_frame, orient = tk.VERTICAL)
        sbv_help.grid(row = 0, column = 10, rowspan = 10, columnspan = 1, sticky = tk.NS)
        help_text.configure(yscrollcommand = sbv_help.set)
        sbv_help.config(command = help_text.yview)

        help_text.insert("end", "This is the GUI version of PAFtoAF Version 1.0, created by Eyal Cohen.\n")
        help_text.insert("end", "\nThis application allows you to use a Preference-based Argumentation Framework\n(PAF) and transform it into an Extension-based Argumentation Framework (AF).\n")
        help_text.insert("end", "\nTo do so, please choose a file in the ptgf, papx, tgf or apx format\n(for more information please click on the formats button in the main window).\n")
        help_text.insert("end", "\nDrag you file in the area specifying so or use the 'open' button to select one.\n(Don't forget to specify the format in the list or extensions)\nThe text in the file should now appear.\n")
        help_text.insert("end", "\nIf you want to modify the PAF (or even write one on the fly) you can just modify\nthe text in the area and then click on the reload button. The PAF will be written\non a file in the temp directory.\nThere should be multiple files in the directory but the one you are looking for\nhere is named 'reloading_text.ptgf' or 'reloading_text.papx', depending on the\nformat you chose to write it in.\nIf you want to get it please copy the file and let the original in the directory.\nIf you move the original the software could not be able to find it and\ngenerate errors.\n")
        help_text.insert("end", "\nYou can generate the graph described in the file by checking the box under the\ntext area.\nNote that self-attacks will not be shown because the API used considers edges as\nlines between nodes so a self attacks is a line with a length of 0.\n")
        help_text.insert("end", "\nThen select the reduction you wish to apply, the resulting AF should\nappear in a tgf or apx format. The graph is dynamically modified to represent\nthe current AF.\n")
        help_text.insert("end", "\nIf you want to use a solver, please enter it's name in the specified line,\nor use the open button to find it, its path will automatically be written\nin the box.\nIn abscence of a name or path mu-toksia will be selected under Linux and\nJArgSemSAT under Windows.\n")
        help_text.insert("end", "After indicating or selecting your solver, click on the Find button, the path\nto the solver should now appear in the box.\n")
        help_text.insert("end", "\nFinally you can select the task you would like to carry out.\nAnd all the options that you want to apply, using the buttons under\n'Solver Options :'.\n")
        help_text.insert("end", "\nThen you can click the COMPUTE button.\nThe result should appear in the figure down below.\nIf you click the COMPUTE button while everything is empty it\nshould write the information about the author and the version in the box.\n")
        help_text.insert("end", "\nPlease do not alter the 'temp' directory. You can copy a file if needed, but\nremoving/deleting one could cause an error, maybe even crashing the application.\nAnd putting a new file in could rewrite it, and would delete it on the closing\nof the application.\n")
        help_text["state"] = DISABLED

    def show_formats():
        """
        The method linked to the formats button (in the option frame).
        It creates a new window with a text and 2 buttons explaining the formats and a button per format to see what each one means.
        """
        def show_ptgf():
            formats_text["state"] = NORMAL
            formats_text.delete("1.0", "end")
            formats_text.insert("end", "\nThe tgf (Trivial Graph Format) is a usualformat for files\ndescipting an AF.\n")
            formats_text.insert("end", "Here we add the preference side of a Preference-base AF (PAF).\n")
            formats_text.insert("end", "\nTo do so, we add on the tgf format a second # delimiting\na third area, where the prefernces are written as attacks.\n")
            formats_text.insert("end", "So arguments are written as their names, then a # is placed,\nfollowed by the attacks where 1 2 means that 1 attacks 2.\n")
            formats_text.insert("end", "Then a second # is placed and finally the preferences\nwhere 1 2 means 1 is prefered over 2.\n")
            formats_text.insert("end", "Here is an exemple :\n1\n2\n3\n#\n1 2\n2 1\n2 3\n#\n1 2\n\nMeans that 1 and 2 attack each other, 2 attack 3, 1 is preffered\nover 2.")
            p_tgfButton["bg"] = "red"
            p_tgfButton["state"] = DISABLED
            p_apxButton["bg"] = "white"
            p_apxButton["state"] = NORMAL
            formats_text["state"] = DISABLED
        def show_papx():
            formats_text["state"] = NORMAL
            formats_text.delete("1.0", "end")
            formats_text.insert("end", "\nThe apx (Aspartix) is a usualformat for files\ndescipting an AF.\n")
            formats_text.insert("end", "Here we add the preference side of a Preference-base AF (PAF).\n")
            formats_text.insert("end", "\nTo do so, we add on the apx format a new keyword\nfor the prefernces : pref.\n")
            formats_text.insert("end", "So arguments are written as arg(name) followed by\nthe attacks where att(1,2) means that 1 attacks 2.\n")
            formats_text.insert("end", "Finally the preferences written pref(1,2) if 1 is prefered\nover 2.\n")
            formats_text.insert("end", "\nAt the end of each line must appear a dot.\n")
            formats_text.insert("end", "Here is an exemple :\narg(1).\narg(2).\narg(3).\natt(1,2).\natt(2,1).\natt(2,3).\npref(1,2).\n\nMeans that 1 and 2 attack each other, 2 attack 3, 1 is preffered\nover 2.")
            p_apxButton["bg"] = "red"
            p_apxButton["state"] = DISABLED
            p_tgfButton["bg"] = "white"
            p_tgfButton["state"] = NORMAL
            formats_text["state"] = DISABLED
        formats_window = tk.Tk()
        formats_window.title("FORMATS")
        formats_window.geometry("686x480")
        formats_window.config(bg = "#dddddd")
        formats_frame = tk.Frame(formats_window, height = 30, width = 86)
        formats_frame.pack()
        accepted_formats_text = tk.Text(formats_frame, height = 4, width = 84)
        accepted_formats_text.pack(side = TOP)
        formats_text = tk.Text(formats_frame, height = 28, width = 84, state = DISABLED)
        buttonsframe = tk.Frame(formats_frame, height = 5, width = 84)
        buttonsframe.pack(side = TOP)
        p_tgfButton = tk.Button(buttonsframe, text = "tgf and ptgf", bg = "white", activebackground = "red", command = show_ptgf)
        p_apxButton = tk.Button(buttonsframe, text = "apx and papx", bg = "white", activebackground = "red", command = show_papx)
        p_tgfButton.pack(side = LEFT)
        p_apxButton.pack(side = LEFT)
        formats_text.pack(side = TOP)
        accepted_formats_text.insert("end", "The formats accepted are ptgf, papx, tgf, and apx.\n")

    def show_problems():
        """
        This method is linked to the 'problems' button (in the option frame).
        It creates a window with a small text and 2 comboBox exaplaining every semantic and every task.
        """
        def CO():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Complete :\nS is in CO(F) iff :\n-S is in ADM(F)\n-for every a in A that is defended by S, a is in S.\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following sets are complete :\n{1,4,6}, {1, 3} or {1}.\n{1,3,4,6} is not in CO(F) because it\nis not in CF(F) so not in ADM(F).\n(3 and 4 attack each other)")
            sem_text["state"] = DISABLED
        def PR():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Prefered :\nS is in PR(F) iff :\n-S is a maximal admissible set.\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following sets are preferred :\n{1,4,6}, {1,3}.\n{1} is not prefered since it is\nincluded in {1,4,6} (and in {1,3}) so\nit is not maximal.")
            sem_text["state"] = DISABLED
        def ST():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Stable :\nS is in ST(F) iff :\n-S is in CF(F)\n-S attacks every a in A\\S\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following set is stable :\n{1,4,6}.\n{1,3} is not stable because 5, 6 and 7 are not\nattacked and not in S.")
            sem_text["state"] = DISABLED
        def SST():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Semi-Stable :\nS is in SST(F) iff :\n-S is in CO(F)\n-S# is maximal, there is no S2 such that S# is included in S2#\nEvery S in ST(F) is in SST(F), but the\nconverse is not true.\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following set is semi-stable :\n{1,4,6} since it is stable.\nBut in this AF :\nA\nB\nC\nD\nA A\nA C\nB C\nC D\nThe following set is semi-stable\nbut not stable : {B,D}")
            sem_text["state"] = DISABLED
        def STG():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Staged :\nS is in STG(F) iff :\n-S is in CF(F)\n-S# is maximal, there is no S2 such that S# is included in S2#\nEvery S in ST(F) S is in STG(F), if\nF has at least one stable extension,\nthen every S in STG(F) is also in ST(F).\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following set is staged :\n{1,4,6} since it is stable.\nBut in this AF :\nA\nB\nA A\nA B\n{B} is staged and not stable,\nbecause there is not stable extension\nin this AF.")
            sem_text["state"] = DISABLED
        def GR():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Grounded :\nS is in GR(F) iff :\n-S is a minimal complete extension\nThere is no S2 in CO(F) such that S2 is\nincluded in (or equal to) S.\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following set is grounded :\n{1}.\n{1,3} is not grounded, because {1} is complete and included in it.\n")
            sem_text["state"] = DISABLED
        def ID():
            sem_text["state"] = NORMAL
            sem_text.delete("1.0", "end")
            sem_text.insert("end", "Ideal :\nS is in ID(F) iff :\n-S is in ADM(F)\n-S is included the intersection of\nevery S_i in PR(F)\n-S is maximal in term of inclusion\nthere is no S2 in ADM(F) and in\nthe intersection of every S_i in PR(f)\nsuch that S is included in S2.\n\nThere is only one set in ID(F).\n")
            sem_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nThe following set is ideal :\n{1}.")
            sem_text["state"] = DISABLED
        def DC():
            task_text["state"] = NORMAL
            task_text.delete("1.0", "end")
            task_text.insert("end", "Decide Credulously :\nGiven an AF F, an argument (query) a in\nA and a semantic sem,\nsees if the argument is in the union of\nevery S in sem(F).\nFor ID(F) DC and DS are the same task\nsince there is a single ideal extension.\n")
            task_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nCO-DC would answer :\nYES for every a in {1,3,4,6}\nNO for a in {2,5,7}.")
            task_text["state"] = DISABLED
        def DS():
            task_text["state"] = NORMAL
            task_text.delete("1.0", "end")
            task_text.insert("end", "Decide Skeptically :\nGiven an AF F, an argument (query) a in\nA and a semantic sem,\nsees if the argument is in the intersection of\nevery S in sem(F).\nFor ID(F) DC and DS are the same task\nsince there is a single ideal\nextension.\n")
            task_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nCO-DS would answer :\nYES for every a in {1}\nNO for a in {2,3,4,5,6,7}.")
            task_text["state"] = DISABLED
        def CE():
            task_text["state"] = NORMAL
            task_text.delete("1.0", "end")
            task_text.insert("end", "Count Extension :\nGiven an AF F and a semantic sem, give the number\nof extensions in sem(F).\nThere is always only one ideal extension.\nSo CE-ID has always 1 for answer.\n")
            task_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nPR-CE would answer 2.")
            task_text["state"] = DISABLED
        def SE():
            task_text["state"] = NORMAL
            task_text.delete("1.0", "end")
            task_text.insert("end", "Some Extension :\nGiven and AF F and a smenatic sem, give\none extension in sem(F).\nFor ID(F) EE and CE are the same thing since there\n is only one extension in ID(F).\n")
            task_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nSTG-SE would answer {1,4,6}.")
            task_text["state"] = DISABLED
        def EE():
            task_text["state"] = NORMAL
            task_text.delete("1.0", "end")
            task_text.insert("end", "Enumerate Extensions :\nGiven and AF F and a smenatic sem, enumerate\nevery extension in sem(F).\nFor ID(F) EE and CE are the same thing since there\n is only one extension in ID(F).\n")
            task_text.insert("end", "\nFor exemple in the following AF :\n1\n2\n3\n4\n5\n6\n7\n1 2\n2 3\n3 4\n4 3\n4 5\n5 6\n6 7\n7 5\nCO-SE would answer :\n{1,4,6}, {1, 3}, {1}.")
            task_text["state"] = DISABLED
        switcher_semantics = {
            "" : print,
            "CO" : CO,
            "PR" : PR,
            "ST" : ST,
            "SST" : SST,
            "STG" : STG,
            "GR" : GR,
            "ID" : ID
            }
        switcher_tasks = {
            "" : print,
            "DC" : DC,
            "DS" : DS,
            "CE" : CE,
            "SE" : SE,
            "EE" : EE
            }
        def sem_select(event):
            switcher_semantics[sem_box.get()]()
        def task_select(event):
            switcher_tasks[task_box.get()]()
        #I know it is weird to get from the box instead of from the StringVar()
        #But the sem_val and task_val are empty when I do a .get() and I don't know why
        #I even tried making the variable global but it does not change anything

        problems_window = tk.Tk()
        problems_window.title("PROBLEMS")
        problems_window.geometry("696x480")
        problems_window.config(bg = "#dddddd")

        problems_frame = tk.Frame(problems_window, height = 30, width = 86)
        problems_frame.pack()

        top_frame = tk.Frame(problems_frame)
        top_frame.grid(row = 0, column = 0, columnspan = 12, rowspan = 6)
        explication_text = tk.Text(top_frame, height = 12, width = 84)
        explication_text.grid(row = 0, column = 0, columnspan = 10, rowspan = 6)
        explication_text.delete("1.0","end")
        explication_text.insert("end", "'Problems' are the computational problems that you want to submit to the program.\nA problem is composed of :\n-a semantic : a meaning, a logic\n-a task : that will be resolved with respect to the semantic.\n")
        explication_text.insert("end", "Now we must introduce some notions.\nGiven an AF F = <A,R>. With A the arguments and R (included in A x A) the attacks.\nS a set or arguments in A is :\n")
        explication_text.insert("end", "\n-Conflict-Free (CF) : iff for every a,b in S, (a,b) is not in R.\n")
        explication_text.insert("end", "\n-Admissible (ADM) : iff S is CF and for every a in S, S defends a from any b\n(not in S) attacking a.\n")
        explication_text.insert("end", "\n-The range of S is S and every argument it attacks, let us note it S# \n(formally it is a small circled + in the top right corner of the letter)\n")
        explication_text["state"] = DISABLED

        sbv_explication = tk.Scrollbar(top_frame, orient = tk.VERTICAL)
        sbv_explication.grid(row = 0, column = 12, rowspan = 6, columnspan = 1, sticky = tk.NS)
        explication_text.configure(yscrollcommand = sbv_explication.set)
        sbv_explication.config(command = explication_text.yview)

        boxframe = tk.Frame(problems_frame, width = 84)
        boxframe.grid(row = 6, column = 0, columnspan = 10)

        sem_val = tk.StringVar()
        sem_box = ttk.Combobox(boxframe, values = ["CO","PR","ST","SST","STG","GR","ID"], textvariable = sem_val, state = "readonly")
        sem_box.bind("<<ComboboxSelected>>", sem_select)
        sem_box.pack(side = LEFT)

        task_val = tk.StringVar()
        task_box = ttk.Combobox(boxframe, values = ["DC","DS","CE","SE","EE"], textvariable = task_val, state = "readonly")
        task_box.bind("<<ComboboxSelected>>", task_select)
        task_box.pack(side = RIGHT)

        explicationframe = tk.Frame(problems_frame, height = 16, width = 84)
        explicationframe.grid(row = 7, column = 0, rowspan = 7, columnspan = 10)

        sem_frame = tk.Frame(explicationframe)

        sem_text = tk.Text(sem_frame, height = 14, width = 40, state = DISABLED)
        sem_text.grid(row = 0, column = 0, rowspan = 7, columnspan = 4)
        sem_frame.grid(row = 0, column = 0, rowspan = 7, columnspan = 5)

        sbv_sem = tk.Scrollbar(sem_frame, orient=tk.VERTICAL)
        sbv_sem.grid(row = 0, column = 4, rowspan = 6, columnspan = 1, sticky = tk.NS)
        sem_text.configure(yscrollcommand = sbv_sem.set)
        sbv_sem.config(command = sem_text.yview)

        task_frame = tk.Frame(explicationframe)

        task_text = tk.Text(task_frame, height = 14, width = 40, state = DISABLED)
        task_text.grid(row = 0, column = 0, rowspan = 7, columnspan = 4)
        task_frame.grid(row = 0, column = 5, rowspan = 7, columnspan = 5)

        sbv_task = tk.Scrollbar(task_frame, orient=tk.VERTICAL)
        sbv_task.grid(row = 0, column = 4, rowspan = 6, columnspan = 1, sticky = tk.NS)
        task_text.configure(yscrollcommand = sbv_task.set)
        sbv_task.config(command = task_text.yview)

        expli_empty_label = tk.Label(explicationframe, text = "", height = 1, width = 80)
        expli_empty_label.grid(row = 7, column = 0, rowspan = 1, columnspan = 10)

    def ClickReduc0():
        """
        Linked to the 'no reduction' button. It clears the reduction text area and change the graph (if the checkbox is active) to the PAF graph.
        """
        global reduction
        global inputfile
        global fileformat
        global graph_check_value
        reduction = 0
        try_toPaf(inputfile, fileformat)
        textareaReduc.configure(state = "normal")
        textareaReduc.delete("1.0","end")
        if graph_check_value.get() == 1:
            show_graph()
        reset_values()

    def ClickReduc1():
        """
        Linked to the 'reduction 1' button. It overwrite the reduction text area with the reduction 1.
        If the graph checkbox is active, it overwrites the graph with the resulting AF.
        """
        global reduction
        global inputfile
        global tempFile
        global fileformat
        reduction = 1
        try_toPaf(inputfile, fileformat)
        textareaReduc.configure(state = "normal")
        file = "temp/Reduction1-AF-tmp.{}".format("tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        paf.reduction1([file], "tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        with open(file,"r") as openfile:
            textareaReduc.delete("1.0", "end")
            for line in openfile:
                line = line.strip()
                textareaReduc.insert("end", f"{line}\n")
        if file not in tempFile:
            tempFile.append(file)
        try_toPaf(file, fileformat)
        if graph_check_value.get() == 1:
            show_graph()
        button1["bg"] = "red"
        button1["state"] = DISABLED
        button0["bg"] = "white"
        button0["state"] = NORMAL
        button2["bg"] = "white"
        button2["state"] = NORMAL
        button3["bg"] = "white"
        button3["state"] = NORMAL
        button4["bg"] = "white"
        button4["state"] = NORMAL
        problem_box["state"] = "readonly"
        semantic_box["state"] = "readonly"
        solver["state"] = NORMAL
        solver_select_button["state"] = NORMAL
        solver_find_button["state"] = NORMAL
        download_button["state"] = NORMAL
        textareaReduc.configure(state = "disabled")

    def ClickReduc2():
        """
        Linked to the 'reduction 2' button. It overwrite the reduction text area with the reduction 2.
        If the graph checkbox is active, it overwrites the graph with the resulting AF.
        """
        global reduction
        global inputfile
        global tempFile
        global fileformat
        reduction = 2
        try_toPaf(inputfile, fileformat)
        textareaReduc.configure(state = "normal")
        file = "temp/Reduction2-AF-tmp.{}".format("tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        paf.reduction2([file], "tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        with open(file,"r") as openfile:
            textareaReduc.delete("1.0", "end")
            for line in openfile:
                line = line.strip()
                textareaReduc.insert("end", f"{line}\n")
        if file not in tempFile:
            tempFile.append(file)
        try_toPaf(file, fileformat)
        if graph_check_value.get() == 1:
            show_graph()
        button2["bg"] = "red"
        button2["state"] = DISABLED
        button0["bg"] = "white"
        button0["state"] = NORMAL
        button1["bg"] = "white"
        button1["state"] = NORMAL
        button3["bg"] = "white"
        button3["state"] = NORMAL
        button4["bg"] = "white"
        button4["state"] = NORMAL
        problem_box["state"] = "readonly"
        semantic_box["state"] = "readonly"
        solver["state"] = NORMAL
        solver_select_button["state"] = NORMAL
        solver_find_button["state"] = NORMAL
        download_button["state"] = NORMAL
        textareaReduc.configure(state = "disabled")

    def ClickReduc3():
        """
        Linked to the 'reduction 3' button. It overwrite the reduction text area with the reduction 3.
        If the graph checkbox is active, it overwrites the graph with the resulting AF.
        """
        global reduction
        global inputfile
        global tempFile
        global fileformat
        reduction = 3
        try_toPaf(inputfile, fileformat)
        textareaReduc.configure(state = "normal")
        file = "temp/Reduction3-AF-tmp.{}".format("tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        paf.reduction3([file], "tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        with open(file,"r") as openfile:
            textareaReduc.delete("1.0", "end")
            for line in openfile:
                line = line.strip()
                textareaReduc.insert("end", f"{line}\n")
        if file not in tempFile:
            tempFile.append(file)
        try_toPaf(file, fileformat)
        if graph_check_value.get() == 1:
            show_graph()
        button3["bg"] = "red"
        button3["state"] = DISABLED
        button0["bg"] = "white"
        button0["state"] = NORMAL
        button1["bg"] = "white"
        button1["state"] = NORMAL
        button2["bg"] = "white"
        button2["state"] = NORMAL
        button4["bg"] = "white"
        button4["state"] = NORMAL
        problem_box["state"] = "readonly"
        semantic_box["state"] = "readonly"
        solver["state"] = NORMAL
        solver_select_button["state"] = NORMAL
        solver_find_button["state"] = NORMAL
        download_button["state"] = NORMAL
        textareaReduc.configure(state = "disabled")

    def ClickReduc4():
        """
        Linked to the 'reduction 4' button. It overwrite the reduction text area with the reduction 4.
        If the graph checkbox is active, it overwrites the graph with the resulting AF.
        """
        global reduction
        global inputfile
        global tempFile
        global fileformat
        reduction = 4
        try_toPaf(inputfile, fileformat)
        file = "temp/Reduction4-AF-tmp.{}".format("tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        textareaReduc.configure(state = "normal")
        paf.reduction4([file], "tgf" if (fileformat == "ptgf" or fileformat == "tgf") else "apx")
        with open(file,"r") as openfile:
            textareaReduc.delete("1.0", "end")
            for line in openfile:
                line = line.strip()
                textareaReduc.insert("end", f"{line}\n")
        if file not in tempFile:
            tempFile.append(file)
        try_toPaf(file, fileformat)
        if graph_check_value.get() == 1:
            show_graph()
        button4["bg"] = "red"
        button4["state"] = DISABLED
        button0["bg"] = "white"
        button0["state"] = NORMAL
        button1["bg"] = "white"
        button1["state"] = NORMAL
        button2["bg"] = "white"
        button2["state"] = NORMAL
        button3["bg"] = "white"
        button3["state"] = NORMAL
        problem_box["state"] = "readonly"
        semantic_box["state"] = "readonly"
        solver["state"] = NORMAL
        solver_select_button["state"] = NORMAL
        solver_find_button["state"] = NORMAL
        download_button["state"] = NORMAL
        textareaReduc.configure(state = "disabled")

    def download_reduc():
        """
        This method is binded to the 'download' button (above the reduction text area).
        It writes the reduction in a new file.
        """
        global inputfile
        today = date.today()
        now_time = datetime.now().strftime("%d-%m-%Y~%H_%M_%S")
        directory = f"PAFtoAF_downloads_{today}"
        if not os.path.exists(directory):
            os.mkdir(directory)
        else:
            if not os.path.isdir(directory):
                directory = directory+"_dir"
                os.mkdir(directory)
        if inputfile.find("\\") != -1:
            filename = inputfile[inputfile.rfind("\\")+1:inputfile.rfind("".join([".", fileformat]))]
        elif inputfile.find("/") != -1:
            filename = inputfile[inputfile.rfind("/")+1:inputfile.rfind("".join([".", fileformat]))]
        else :
             filename = inputfile[:inputfile.rfind("".join([".", fileformat]))]
        with open(f"{directory}/reduction{reduction}_{filename}_{now_time}.{('tgf', 'apx')[fileformat == 'papx']}", "w+") as openfile:
            openfile.write(textareaReduc.get("1.0", "end"))

    def renew_query_frame():
        """
        This method is invoked to reset the query frame, it happens when the user select a new task that is not relative to an argument.
        """
        queryframe = tk.Frame(taskframe)

        query_label = tk.Label(queryframe, text = "query : ")
        query_label.grid(row = 0, column = 0)

        query_value= tk.StringVar()
        query_entry = tk.Entry(queryframe, textvariable = query_value)
        query_entry.grid(row = 0, column = 1)

    def problem_selection(event):
        """
        Linked to the problem selection combo box, this method check the selected value in the box and manages the other box according to what was chosen.
        """
        global query_bool
        global queryframe
        if problem_value.get() in ["CE", "EE", "DC"]:
            semantic_box["values"] = ["CO","PR","ST","SST","STG","GR"]
        else:
            semantic_box["values"] = ["CO","PR","ST","SST","STG","GR", "ID"]
        if problem_value.get() in ["DC", "DS"] and not query_bool:
            query_bool = True
            task_label.grid(row = 0, column = 2)
            queryframe.grid(row = 1, column = 3)
        elif problem_value.get() in ["CE", "EE", "SE"] and query_bool:
            query_bool = False
            task_label.grid(row = 0, column = 1)
            queryframe.grid_remove()
            renew_query_frame()

    def semantic_selection(event):
        """
        Linked to the semantic selection combo box, this method check the selected value in the box and manages the other box according to what was chosen.
        """
        if semantic_value.get() == "ID":
            problem_box["values"] = ["DS","SE"]
        else:
            problem_box["values"] = ["DC","DS","CE","SE","EE"]

    def show_graph():
        """
        Linked to the 'show graph' checkbox, this method creates a figure in which it draws the graph of the current reudction (PAF in case no reduction has been applied).
        """
        global fig
        global inputfile

        if graph_check_value.get() == 1:
            if fig == Figure():
                fig = plt.figure(dpi = 100)

            plt.clf()

            edgeList = []

            ax = plt.subplot(111)
            ax.set_title('Graph - {}'.format(inputfile), fontsize=10)
            graph = nx.DiGraph()

            for arg1 in paf.attacksFrom.keys():
                for arg2 in paf.attacksFrom[arg1]:
                    edgeList.append((arg1,arg2))

            graph.add_edges_from(edgeList, color = "k", weight = 2)
            critical_edges = []

            for arg1 in paf.preferences.keys():
                for arg2 in paf.preferences[arg1]:
                    if (arg2, arg1) in edgeList:
                        critical_edges.append((arg2,arg1))

            graph.add_edges_from(critical_edges, color = "r", weight = 3)

            graph.graph["edge"] = {"arrowsize" : "3", "splines" : "curved"}

            colors = nx.get_edge_attributes(graph,'color').values()
            weights = nx.get_edge_attributes(graph,'weight').values()
            try:
                pos = nx.planar_layout(graph)
            except(NetworkXException):
                pos = nx.spring_layout(graph)
            nx.draw(graph, pos, node_size=700, node_color='yellow', font_size=8, font_weight='bold', edge_color = colors, width = list(weights), arrowsize = 30, arrowstyle = "->", with_labels = True)

            plt.tight_layout()

            plt.rcParams["figure.figsize"] = (10,9)

            plt.savefig("temp/Graph.png", format="PNG")

        else:
            os.remove("temp/Graph.png")
            plt.close()

    def compute():
        """
        This method is linked to the COMPUTE button.
        It takes every information given by the user and runs the PAFtoAF.py file.
        It then writes what is returned in the text area below.
        """
        com = command_line("compute").split()
        return_text["state"] = NORMAL
        return_text.delete("1.0", "end")
        try:
            ret = paf.main(len(com), com, True)
            if (ret is not None):
                for w in ret:
                    return_text.insert("end", w)
                return_text["state"] = DISABLED
            else:
                return_text.insert("end", "No output.")
                return_text["state"] = DISABLED
        except (UnsupportedFormatException, FormatSyntaxException,  PreferenceException, FormatException, CommandLineException, FindingSolverException, UnsupportedOSException) as e:
            return_text.insert("end", e.name)
            return_text.insert("end", ":")
            return_text.insert("end", str(e))
            return_text["state"] = DISABLED
        except Exception as e:
            return_text.insert("end", e.name)
            return_text.insert("end", ":")
            return_text.insert("end", str(e))
            return_text["state"] = DISABLED

    def save():
        """
        This method is binded to the save button (in the option frame).
        On activation it reads every useful information in the user's choices and writes the corresponding command line.
        """
        global inputfile
        global fileformat
        global reduction
        global solver
        global solverPath
        today = date.today()
        directory = f"PAFtoAF_downloads_{today}"
        if not os.path.exists(directory):
            os.mkdir(directory)
        else:
            if not os.path.isdir(directory):
                directory = directory+"_dir"
                os.mkdir(directory)
        with open("{}/PAFtoAFGUI-saved-{}-{}-{}.txt".format(directory, os.path.basename(inputfile).replace(".{}".format(fileformat),""), reduction, datetime.now().strftime("%d_%m_%Y_%H-%M-%S")), "w+") as file:
            file.write(command_line("save"))

    def command_line(mode):
        """
        This method is used by the method save and by compute.
        It reads the information the user provided in the GUI and return a command line correspoonding to what the user wants to do.
        """
        global inputfile
        global fileformat
        global reduction
        global solver
        global solverPath
        if mode == "save":
            com = "python3 PAFtoAF "
        if mode == "compute":
            if os.path.exists("PAFtoAF.py"):
                com = os.getcwd() + "\\PAFtoAF.py "
            else:
                return_text["state"] = NORMAL
                return_text.insert("end", "For this application to work proprely, please put the PAFtoAF.py file\nin the same folder as this one (PAFtoAFGUI.py)\n")
                return_text["state"] = DISABLED
        if inputfile != '':
            com += "-f {} -fo {} ".format(inputfile, fileformat)
        if reduction != 0:
            com += "-r {} ".format(reduction)
        if semantic_value.get() != '' and problem_value.get() != '':
            com += "-p {}-{} ".format(problem_value.get(), semantic_value.get())
            if query.get() != '':
                com += "-a {} ".format(query.get())
        if solver_value.get() != '':
            com += "-s {} ".format(solver.get())
        if solverPath != '':
            com += "-sp {} ".format(solverPath)
        return(com)

    def on_closing():
        """
        This is the closing protocol, it is activated on the closing of the main window.
        Its purpose is to delete every temporary file that has been created during the session and then to destroy the window.
        """
        global graph_value
        if graph_check_value.get() == 1:
            graph_check.toggle()
        if tempFile != []:
            for i in range(len(tempFile)):
                os.remove(tempFile[i])
            tempFile.clear()
        for file in os.scandir("temp"):
            os.remove(file)
        os.rmdir("temp")
        window.destroy()
        window.quit()

    textarea = tk.Text(frameDnD, height=18, width=41)
    textarea.grid(row = 1, column = 0, rowspan = 6, columnspan = 6)
    textarea.drop_target_register(tkd.DND_FILES)
    textarea.dnd_bind('<<Drop>>', load_text)
    textarea.insert("end", "\n\nPlease drag a file here.\n\nOr click the 'open' button under this\nbox to select a file.\n\nAccepted formats are ptgf, papx,\ntgf or apx.")

    sbv = tk.Scrollbar(frameDnD, orient=tk.VERTICAL)
    sbv.grid(row = 1, column = 7, rowspan = 6, columnspan = 6, sticky = tk.NS)

    textarea.configure(yscrollcommand=sbv.set)
    sbv.config(command=textarea.yview)

    open_button = tk.Button(frameDnD, activebackground = "blue", bg = "white", text = "open", command = load_text_selection)
    open_button.grid(row = 7, column = 0, columnspan = 6)

    reload_button= tk.Button(frameDnD, activebackground = "red", bg = "white", text = "reload", command = reload_text, width = 46)
    reload_button.grid(row = 0, column = 0, columnspan = 6)

    graph_check_value = tk.IntVar()
    graph_check = tk.Checkbutton(frameDnD, disabledforeground = "yellow", text = "generate the graph", variable = graph_check_value, command = show_graph, onvalue = 1, state = DISABLED)
    graph_check.grid(row = 7, column = 0)

    help_option = tk.Button(optionframe, activebackground = "red", bg = "white", text = "Help", command = show_help)
    help_option.pack(side = LEFT)

    formats_option = tk.Button(optionframe, activebackground = "red", bg = "white", text = "Formats", command = show_formats)
    formats_option.pack(side = LEFT)

    problems_option = tk.Button(optionframe, activebackground = "red", bg = "white", text = "Problems", command = show_problems)
    problems_option.pack(side = LEFT)

    save_option = tk.Button(optionframe, activebackground = "blue", bg = "white", text = "save", command = save)
    save_option.pack(side = LEFT)

    task_label = tk.Label(taskframe, text = "Tasks :", justify = tk.CENTER)
    task_label.grid(row = 0, column = 1)

    problem_value = tk.StringVar()
    problem_box = ttk.Combobox(taskframe, values = ["DC","DS","CE","SE","EE"], state = DISABLED, textvariable = problem_value)
    problem_box.bind("<<ComboboxSelected>>", problem_selection)
    problem_box.grid(row = 1, column = 0)

    query_label = tk.Label(queryframe, text = "query : ")
    query_label.grid(row = 0, column = 0)

    query= tk.StringVar()
    query_entry = tk.Entry(queryframe, textvariable = query)
    query_entry.grid(row = 0, column = 1)

    semantic_value = tk.StringVar()
    semantic_box = ttk.Combobox(taskframe, values = ["CO","PR","ST","SST","STG","GR","ID"], state = DISABLED, textvariable = semantic_value)
    semantic_box.bind("<<ComboboxSelected>>", semantic_selection)
    semantic_box.grid(row = 1, column = 2)

    empty_task_label = tk.Label(taskframe, text = "")
    empty_task_label.grid(row = 2, column = 0, columnspan = 3, rowspan = 2)

    solver_label = tk.Label(solverframe, text = "solver : ")
    solver_label.grid(row = 0, column = 0)

    solver_value = tk.StringVar()
    solver = tk.Entry(solverframe, textvariable = solver_value)
    solver.grid(row = 0, column = 1)

    solver_select_button = tk.Button(solverframe, activebackground = "blue", bg = "white", text = "open", state = DISABLED, command = select_solver)
    solver_select_button.grid(row = 0, column = 2)

    solver_find_button = tk.Button(solverframe, activebackground = "red", bg = "white", text = "find", state = DISABLED, command = find_solver)
    solver_find_button.grid(row = 1, column = 1)

    button0 = tk.Button(buttonframe, activebackground = "red", bg = "white", text = "no reduction", state = DISABLED, command = ClickReduc0)
    button0.pack(side = LEFT)

    button1 = tk.Button(buttonframe, activebackground = "red", bg = "white", text = "reduction 1", state = DISABLED, command = ClickReduc1)
    button1.pack(side = LEFT)

    button2 = tk.Button(buttonframe, activebackground = "red", bg = "white", text = "reduction 2", state = DISABLED, command = ClickReduc2)
    button2.pack(side = LEFT)

    button3 = tk.Button(buttonframe, activebackground = "red", bg = "white", text = "reduction 3", state = DISABLED, command = ClickReduc3)
    button3.pack(side = LEFT,)

    button4 = tk.Button(buttonframe, activebackground = "red", bg = "white", text = "reduction 4", state = DISABLED, command = ClickReduc4)
    button4.pack(side = LEFT)

    textareaReduc = tk.Text(frameReduction, height=18, width=41)
    textareaReduc.grid(row = 1, column = 0, rowspan = 6, columnspan = 6)
    textareaReduc.configure(state = "disabled")

    sbvR = tk.Scrollbar(frameReduction, orient=tk.VERTICAL)
    sbvR.grid(row = 1, column = 7, rowspan = 6, columnspan = 6, sticky = tk.NS)

    download_button= tk.Button(frameReduction, activebackground = "red", bg = "white", text = "download", command = download_reduc, width = 46, state = DISABLED)
    download_button.grid(row = 0, column = 0, columnspan = 6)

    empty_reduc_label = tk.Label(frameReduction, text = " ")
    empty_reduc_label.grid(row = 7, column = 0)

    textareaReduc.configure(yscrollcommand = sbvR.set)
    sbvR.config(command = textareaReduc.yview)

    compute_button = tk.Button(compute_frame, height = 8, width = 68, text = "COMPUTE", activebackground = "yellow", bg = "blue", command = compute)
    compute_button.pack(side = TOP)

    empty_compute_label = tk.Label(compute_frame, height = 2, width = 68)
    empty_compute_label.pack(side = TOP)

    return_text = tk.Text(compute_frame, height = 4, width = 68)
    return_text.pack(side = TOP)
    return_text.configure(state = "disabled")

    empty_compute_label2 = tk.Label(compute_frame, height = 2, width = 68)
    empty_compute_label2.pack(side = TOP)

    window.protocol("WM_DELETE_WINDOW", on_closing)

    window.mainloop()

max_stars_repo_name: UnHommeLambda/PAFtoAF

max_issues_repo_name: UnHommeLambda/PAFtoAF

max_forks_repo_name: UnHommeLambda/PAFtoAF

reason: import networkx,from networkx


text:
import pandas as pd
from scipy import stats
import os, sys

def choose_multiple_values_in_column(df, colName, values):
    '''
    Return the dataframe (df) with selected string (values) in colName
    @param df: pandas dataframe
    @param colName: which column
    @param values: what are the values of intrest
    @return: dataframe (df) with selected string (values) in colName
    '''
    return df[df[colName].str.contains('|'.join(values))]

def sclmns(df, s, not_in=False):
    '''
    Return all the columns that (not) contain the names in s.
    :param df: pandas dataframe.
    :param s: string(s) the column(s) contains.
    :param not_in: all columns except the ones selected.
    :return: list of columns.
    '''
    clmns = []
    if not_in:
        # all_clmns = list(df.columns)
        all_clmns = df.columns
        for i in s:
            # all_clmns.remove(i)
            # all_clmns = [x for x in all_clmns if not x.__contains__(i)]
            all_clmns = all_clmns[~all_clmns.str.contains(i)]
        clmns = list(all_clmns)
        # clmns = all_clmns.copy()
    else:
        for i in s:
            clmns = clmns + list(df.columns[df.columns.str.contains(i)])
    return clmns

def calculate_corr_with_pvalues(df, method = 'pearsonr'):
    '''
    Calculate the correlation between the columns of dataframe and return values with stars.
    :param df: dataframe
    :param method: pearsonr/ spearman
    :return: pvalues, corr_with_stars
    '''
    df = df.dropna()._get_numeric_data()
    dfcols = pd.DataFrame(columns=df.columns)
    pvalues = dfcols.transpose().join(dfcols, how='outer')

    rho = df.corr()

    for r in df.columns:
        for c in df.columns:
            if method == 'pearsonr':
                pvalues[r][c] = round(stats.pearsonr(df[r], df[c])[1], 4)
            elif method == 'spearman':
                pvalues[r][c] = round(stats.spearmanr(df[r], df[c])[1], 4)
            elif method == 'reg':
                slope, intercept, rho[r][c], pvalues[r][c], std_err = stats.linregress(x=df[r],y= df[c])

    rho = rho.round(2)
    pval = pvalues
    # create three masks
    r1 = rho.applymap(lambda x: '{}*'.format(x))
    r2 = rho.applymap(lambda x: '{}**'.format(x))
    r3 = rho.applymap(lambda x: '{}***'.format(x))
    # apply them where appropriate
    rho = rho.mask(pval <= 0.05, r1)
    rho = rho.mask(pval <= 0.01, r2)
    rho = rho.mask(pval <= 0.001, r3)

    return pvalues, rho

def save_latex(data_path, df, fn, ix = True):
    '''
    Save dataframe with latex file
    :param data_path: were to open the .tex file
    :param df: pandas dataframe
    :param fn: filename
    :param ix: save index
    :return:
    '''
    with open(data_path + '%s.tex' %fn, 'w') as tf:
        if type(df) != pd.core.frame.DataFrame:
            df = pd.DataFrame(df)
        tf.write(df.to_latex(float_format=lambda x: '%.3f' % x, index=ix))
        df.to_csv(data_path + '%s.csv' % fn)

def ttest_or_mannwhitney(y1,y2):
    '''
    Check if y1 and y2 stand the assumptions for ttest and if not preform mannwhitney
    :param y1: 1st sample
    :param y2: 2nd sample
    :return: s, pvalue, ttest - True/False
    '''
    ttest = False

    # assumptions for t-test
    # https://pythonfordatascience.org/independent-t-test-python/#t_test-assumptions
    ns1, np1 = stats.shapiro(y1)  # test normality of the data
    ns2, np2 = stats.shapiro(y2)  # test noramlity of the data
    ls, lp = stats.levene(y1, y2)  # test that the variance behave the same
    if (lp > .05) & (np1 > .05) & (np2 > .05):
        ttest = True
        s, p = stats.ttest_ind(y1, y2)
    else:
        s, p = stats.mannwhitneyu(y1, y2)

    return s, p, ttest

def new_dir(dirPath):
    if not os.path.isdir(dirPath):
        os.mkdir(dirPath)

def progress(i, N, text = None):
    '''
    Update progress in the same line
    :param i: current progress
    :param N: total count
    :param text: description text
    :return:
    '''
    sys.stdout.write('/r')
    if text is None:
        sys.stdout.write('Frame {0}/{1} added to video'.format(i, N))
    else:
        sys.stdout.write(text + '{0}/{1}'.format(i, N))
    sys.stdout.flush()

ext: py

reason: from scipy


text:
import numpy as np

from sfsimodels.models import time

def test_time_series():
    values = np.linspace(0, 10, 101)
    dt = 0.5
    ts = time.TimeSeries(values, dt)
    assert ts.npts == 101
    assert ts.dt == 0.5
    assert len(ts.time) == len(values)
    assert np.isclose(ts.time[4], 2.0)
    assert np.isclose(ts.time[-1], 50.0)

def test_time_indices():
    npts = 1000
    dt = 0.5
    start = 0
    end = 10
    index = False
    s_index, e_index = time.time_indices(npts, dt, start, end, index)
    assert s_index == 0
    assert e_index == 21

    start = 2
    s_index, e_index = time.time_indices(npts, dt, start, end, index)
    assert s_index == 4
    assert e_index == 21

    index = True
    s_index, e_index = time.time_indices(npts, dt, start, end, index)
    assert s_index == 2
    assert e_index == 10

if __name__ == '__main__':
    test_time_series()

max_stars_repo_name: eng-tools/sfsimodels

max_issues_repo_name: eng-tools/sfsimodels

max_forks_repo_name: eng-tools/sfsimodels

reason: import numpy


text:
"""Genetic Algorithm for Problem Solving."""

# Author: Lucas David -- <ld492@drexel.edu>
# License: MIT (c) 2016
import logging
import math
import multiprocessing
import threading
import time

import numpy as np
from scipy.spatial import distance

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

from .base import SearchBase
from ..agents import UtilityBasedAgent
from ..base import GeneticState

logger = logging.getLogger('artificial')

class GeneticAlgorithm(SearchBase):
    """Genetic Algorithm Search.

    Parameters
    ----------
    agent: inherited

    population_size: [int|'auto'], default='auto'
        The size of the population to be kept in memory.

    max_evolution_cycles: [int, np.inf], default=np.inf
        The upper bound for evolution cycles, in cycle count.
        If infinity, no bound is set and evolution cycles won't
        be directly a factor for the evolution process stop.

    max_evolution_duration: float, default=np.inf
        The upper bound for evolution duration, in seconds.
        If infinity, no bound is set and evolution will continue
        regardless the amount of time spent on the process.

    min_genetic_similarity: float, default=0
        The lower bound for individuals' genetic similarity, in percentage.
        If 0, no bound is set and evolution continues regardless the
        individuals genetic similarity.

    breeding_selection: ['random'|'tournament'|'roulette'|'gattaca'],
        default='roulette'
        The method employed when selecting individuals for breeding.

        Options are:
            --- 'random'
                Individuals are selected at random.

            --- 'tournament'
                `k` tournaments are made to decide which individuals should be
                chosen for breeding. In every one of them, `n_selected`
                individuals are chosen from the population and the best of them
                is selected for breeding.

            --- 'roulette'
                Each individual `i` has an associated rate
               :math:`\frac{U_i}{\sum_{k=0}{|population|} U_k}`

                It's worth mentioning that "windowing" is performed if any
                negative utilities happen to appear: every individual has added
                to their utility the value:math:`\min_k U_k` and utilities
                that assume negative values are then fixed, entailing a correct
                probability distribution.

            --- 'gattaca'
                Individuals are paired up accordingly to their "rank" (fitness)
                in the population.

                Note: this option is just a joke. Don't expect great results
                from this method.

    n_selected: [int|float], default=1.0
        Number of individuals selected for breeding. If `int`, exactly
        `n_selected` individuals are selected. If `float`,
        `int(n_selected * self.population_size_)` individuals are
        considered instead.

        This parameter is ignored and automatically assumes the value
        `population_size_ -1` when `natural_selection` chosen is 'elitism',
        as this procedure must always keep only the fittest of every iteration.

    tournament_size: [int|float], default=.5
        Number of individuals fighting in a single tournament. If `int`,
        exactly `tournament_size` individuals are selected. If `float`,
        `int(n_selected * self.population_size_)` individuals are
        considered instead.

        This parameter is ignored when `breeding_selection != 'tournament'`.

    mutation_factor: float, default=.05
        If the problem at hand accepts many different values for genes, and
        said values are enumerable, `mutation_factor` describes how strongly
        a gene is affected by mutation.

        For instance, a gene is "completely" affected if `mutation_factor == 1`,
        or "loosely" or "slightly" affected for factors closest to 0.

    mutation_probability: float, default=.05
        The probability of a given gene of a individual to mutate.

    natural_selection: ['steady-state', 'elitism'], default='steady-state'
        The method employed when selecting which individuals will survive the
        evolution process.

        Options are:
            --- 'random'
                `population_size_` individuals are randomly selected from all
                individuals in population and the offspring.

            --- 'steady-state'
                `M` individuals in the current generation are selected to
                replace the `M` worse individuals from the previous generation.

            --- 'elitism'
                All individuals from the previous generation are killed, except
                for the fittest, which replaces the worse in the current one.

    n_jobs: int, default=1
        Number of jobs to be executed in parallel. If `-1`, execute exactly
        `cpu_count` jobs.

    debug: bool, default=False
        Signals if current execution is in debugging mode. If True, statistics
        such as average utility or variability are kept, requiring
        :math:`O(cycle_)` of memory.

    random_state: RandomState object, default=None
        RandomState object used to control randomness of the process.
        If None, no seed is passed and the default is used.

    Attributes
    ----------
    cycle_: int
        The number of evolution cycles that the search went through.

    average_utility_: float
        The average utilities in every single generation.

    highest_utility_: float
        The highest utilities in every single generation.

    lowest_utility_: float
        The lowest utilities in every single generation.

    n_selected_: int
        Real number of individuals selected for breeding.

    offspring_: GeneticState's list
        Individuals created on this generation.
        This option is cleared after every generation's natural selection
        process.

    population_: GeneticState's list
        Current set of individuals.

    population_size_: int
        Real population size.

    solution_candidate_: State-like object
        Fittest individual from all iterations. Additionally, we ought to
        mention that `fittest_` isn't necessarily contained in the last
        `population_` batch, although this is true for
        `breeding_selection == 'elitism'` option.

    selected_: GeneticState's list
        Individuals selected for breeding in the current generation.
        This option is cleared after every generation's natural selection
        process.

    tournament_size_: int
        Real tournament size. Assumes value `None` when
        `breeding_selection != 'tournament'`,

    variability_: float
        The variability of the last evolved population.

    """

    class _Worker(threading.Thread):
        """Genetic search process inner worker.

        Parameters
        ----------
        worker_id: int
            The id of the current worker. This will later be used
            to automatically perform data division.

        manager: GeneticAlgorithm object-like
            The `GeneticAlgorithm` instance to which this worker belong.

        """

        def __init__(self, worker_id, manager):
            # Use daemon option, as we want to
            # make the disposing process async.
            super(GeneticAlgorithm._Worker, self).__init__()

            self.id = worker_id
            self.manager = manager
            self.daemon = True

        def run(self):
            while True:
                task = self.manager.tasks.get()

                if task is None:
                    # `None` is our safe word. Shutting down...
                    break

                # Task is a method in _Worker class. How convenient!
                # Simply execute the method.
                try:
                    getattr(self, task)()
                finally:
                    self.manager.tasks.task_done()

        def divide_load(self, collection_size):
            """Divide the workload and return probe share.

            The workload is equality divided between the probes, except by the
            last which might receive a smaller load if the `collection_size`
            isn't divisible by the `manager.n_jobs_`.

            Example
            -------
            If `GeneticAlgorithm(population_size=503, n_jobs=4)` were created,
            workload division would happen as follows:

            * _Worker #0: 126
            * _Worker #1: 126
            * _Worker #3: 126
            * _Worker #4: 125

            """
            group_size = math.ceil(collection_size / self.manager.n_jobs_)

            if self.id == self.manager.n_jobs_ - 1:
                # If last worker, reduce the remaining individuals, as they
                # were added by ceiling the division above.
                group_size -= collection_size % self.manager.n_jobs_

            return int(group_size)

        def generate_population(self):
            state_c = self.manager.agent.environment.state_class_

            # Divide the load and find how many individuals should it spawn.
            group_size = self.divide_load(self.manager.population_size_)

            # Generate population randomly.
            group = [state_c.random() for _ in range(group_size)]

            with self.manager.lock:
                self.manager.population_ += group

        def breed(self):
            i, size = self.id, self.divide_load(self.manager.n_selected_)

            selected = self.manager.selected_
            selected = iter(selected[i * size:(i + 1) * size])

            group = []

            try:
                while True:
                    a, b = next(selected), next(selected)
                    cs = a.cross(b)

                    if isinstance(cs, GeneticState):
                        cs = [cs]

                    group += [c.mutate(self.manager.mutation_factor,
                                       self.manager.mutation_probability)
                              for c in cs]

            except StopIteration:
                # We're finished!
                pass
            finally:
                with self.manager.lock:
                    self.manager.offspring_ += group

    def __init__(self, agent,
                 population_size='auto',
                 max_evolution_cycles=np.inf,
                 max_evolution_duration=np.inf,
                 min_genetic_similarity=0,
                 breeding_selection='roulette',
                 n_selected=1.0,
                 tournament_size=.5,
                 mutation_factor=.05,
                 mutation_probability=.05,
                 natural_selection='steady-state',
                 n_jobs=1,
                 debug=False,
                 random_state=None):
        super(GeneticAlgorithm, self).__init__(agent=agent)

        assert isinstance(agent, UtilityBasedAgent), \
            'Genetic searches require an utility based agent.'

        self.population_size = population_size
        self.max_evolution_cycles = max_evolution_cycles
        self.max_evolution_duration = max_evolution_duration
        self.min_genetic_similarity = min_genetic_similarity
        self.breeding_selection = breeding_selection
        self.n_selected = n_selected
        self.tournament_size = tournament_size
        self.mutation_factor = mutation_factor
        self.mutation_probability = mutation_probability
        self.natural_selection = natural_selection
        self.n_jobs = n_jobs
        self.debug = debug
        self.random_state = random_state or np.random.RandomState()

        # Interns.
        self.workers = None
        self.tasks = None
        self.lock = threading.Lock()

        # Properties.
        self.population_size_ = self.population_ = self.tournament_size_ = \
            self.selected_ = self.n_selected_ = self.offspring_ = \
            self.started_at_ = self.n_jobs_ = None

        # Statistics.
        self.generations_variability_ = self.avg_utility_ = \
            self.highest_utility_ = self.lowest_utility_ = None
        self.variability_ = self.cycle_ = 0

    def search(self):
        """Evolve generations while the `continue_evolving` condition is
        satisfied.

        In its default form, `continue_evolving` involves satisfying three
        conditions: (1) the time spent on evolution isn't greater than the
        limit imposed by the user; (2) the number of evolution cycles doesn't
        overflow the limit imposed by the user; (3) the goal hasn't been
        reached (i.e., a `GeneticState` s.t. its `is_goal` property is `True`).

        The fittest individual from all generations is stored in
        `solution_candidate_` attribute.

        Returns
        -------
        self

        """
        self.cycle_ = 0
        self.started_at_ = time.time()
        self.solution_candidate_ = None

        self.search_start().generate_population()

        while self.continue_evolving():
            self.cycle_ += 1
            logger.info('cycle %i of %f.0', self.cycle_,
                        self.max_evolution_cycles)
            self.evolve()
        self.search_dispose()
        return self

    def search_start(self):
        self.n_jobs_ = (self.n_jobs
                        if self.n_jobs > 0
                        else multiprocessing.cpu_count())

        if isinstance(self.population_size, int):
            self.population_size_ = self.population_size

        elif self.population_size == 'auto':
            # default population size.
            self.population_size_ = 1000

            cycles = self.max_evolution_cycles
            duration = self.max_evolution_duration

            if cycles != np.inf and duration != np.inf:
                # Both cycles count and evolution duration were defined, let's
                # choose the population size that optimizes these constraints.
                # Fist, estimates the time for evaluating a individual.
                individual = self.agent.environment.state_class_.random()
                utility_elapsed = time.time()
                self.agent.utility(individual)
                utility_elapsed = time.time() - utility_elapsed
                del individual

                # Finally, lower bound value by 100.
                self.population_size_ = int(2 * self.n_jobs_ * duration /
                                            utility_elapsed / cycles)
                self.population_size_ = max(100, self.population_size_)
        else:
            raise ValueError('Illegal value for population size {%i}.'
                             % self.population_size)

        if self.natural_selection == 'elitism':
            # On elitist natural selection, every individual is replaced by the
            # offspring, saved by the fittest. We therefore must select
            # `2 * (population_size_ - 1)` individuals, which will generate an
            # offspring of exactly `population_size_ - 1` new samples.
            self.n_selected_ = 2 * (self.population_size_ - 1)
        elif isinstance(self.n_selected, int):
            self.n_selected_ = self.n_selected
        elif isinstance(self.n_selected, float):
            self.n_selected_ = int(self.n_selected * self.population_size_)
        else:
            raise ValueError('Illegal value for n_selected {%s}'
                             % str(self.n_selected))

        if self.breeding_selection not in ('random', 'tournament', 'roulette',
                                           'gattaca'):
            raise ValueError('Illegal value for breeding selection method '
                             '{%s}.' % self.breeding_selection)

        if self.natural_selection not in ('random', 'steady-state', 'elitism'):
            raise ValueError('Illegal value for natural selection method {%s}'
                             % self.natural_selection)

        if self.breeding_selection == 'tournament':
            self.tournament_size_ = (self.tournament_size
                                     if isinstance(self.tournament_size, int)
                                     else int(self.tournament_size *
                                              self.population_size_))

            if self.tournament_size_ > self.population_size_:
                raise ValueError('Illegal value for tournament size {%i}.'
                                 % self.tournament_size_)

        if self.debug:
            self.average_utility_ = []
            self.highest_utility_ = []
            self.lowest_utility_ = []
            self.generations_variability_ = []

        self.workers = []
        self.tasks = Queue()

        for i in range(self.n_jobs_):
            self.workers.append(self._Worker(worker_id=i, manager=self))
            self.workers[-1].start()

        return self

    def search_dispose(self):
        self.population_ = None

        for _ in range(self.n_jobs_):
            # Signal workers to stop, but don't wait for
            # it to actually happen. No point on doing that.
            self.tasks.put_nowait(None)

        self.workers = None
        self.tasks = None

        return self

    def cycle_start(self):
        if self.debug:
            utilities = [self.agent.utility(i) for i in self.population_]

            _min, _avg, _max = (min(utilities),
                                sum(utilities) / len(utilities),
                                max(utilities))

            self.lowest_utility_.append(_min)
            self.average_utility_.append(_avg)
            self.highest_utility_.append(_max)

            logger.info('fitting: [%.2f, %.2f, %.2f]', _min, _avg, _max)

        return self

    def cycle_dispose(self):
        self.selected_ = self.offspring_ = None
        return self

    def generate_population(self):
        """Generate initial random population.

        The generation's size is defined by the `self.population_size`
        parameter. If its value is 'auto', a value that best fits the
        constrains is chosen.

        Notes
        -----
        This method assumes the agent is in an environment capable of
        generating random states.

        """

        self.population_ = []

        for _ in range(self.n_jobs_):
            self.tasks.put_nowait('generate_population')
        self.tasks.join()

        # Find who is the fittest.
        self.solution_candidate_ = max(self.population_,
                                       key=lambda i: self.agent.utility(i))
        return self

    def evolve(self):
        """Evolve a generation of individuals."""
        return (self
                .cycle_start()
                .select_for_breeding()
                .breed()
                .naturally_select()
                .cycle_dispose())

    def continue_evolving(self):
        """Checks if evolution process should continue.

        Returns
        -------
        True, if evolution should continue, False otherwise.

        """
        return (time.time() - self.started_at_ < self.max_evolution_duration and
                self.cycle_ < self.max_evolution_cycles and
                not self.solution_candidate_.is_goal and
                (self.min_genetic_similarity == 0 or
                 self.min_genetic_similarity <= self.genetic_similarity()))

    def select_for_breeding(self):
        """Breeding Selection.

        Select individuals for breeding by adding them to the `selected_`
        array. The order in which the individuals are in the array determines
        the breeding pairs (`2i-th` and `(2i+1)-th` are breeding partners, for
        every:math:`i \in [0, n_selected_ / 2)`).

        """
        random = self.random_state

        if self.breeding_selection == 'random':
            self.selected_ = random.choice(self.population_,
                                           size=self.n_selected_)

        elif self.breeding_selection == 'tournament':
            self.selected_ = [max(random.choice(self.population_,
                                                size=self.tournament_size_),
                                  key=lambda i: self.agent.utility(i))
                              for _ in range(self.n_selected_)]

        elif self.breeding_selection == 'roulette':
            # Roulette requires probabilities. Soft-max p!
            p = np.array([self.agent.utility(i)
                          for i in self.population_], dtype=float)
            p = np.exp(p)
            p /= p.sum()

            self.selected_ = random.choice(self.population_,
                                           size=self.n_selected_, p=p)

        elif self.breeding_selection == 'gattaca':
            self.population_.sort(key=lambda i: -self.agent.utility(i))
            self.selected_ = self.population_[:self.n_selected_]

        return self

    def breed(self):
        """Breed previously selected individuals."""
        self.offspring_ = []

        for _ in range(self.n_jobs_):
            self.tasks.put_nowait('breed')
        self.tasks.join()

        return self

    def naturally_select(self):
        if not self.offspring_:
            raise RuntimeError('No offspring generated. Cannot naturally '
                               'select from empty set.')

        self.offspring_.sort(key=lambda i: -self.agent.utility(i))
        self.population_.sort(key=lambda i: -self.agent.utility(i))

        self.solution_candidate_ = max(self.offspring_[0],
                                       self.solution_candidate_,
                                       key=lambda i: self.agent.utility(i))

        if self.natural_selection == 'random':
            self.population_ += self.offspring_
            self.random_state.shuffle(self.population_)
            self.population_ = self.population_[:self.population_size_]

        elif self.natural_selection == 'steady-state':
            self.population_ = (self.population_[:-len(self.offspring_)] +
                                self.offspring_)

        elif self.natural_selection == 'elitism':
            self.population_ = self.population_[:1] + self.offspring_

        return self

    def genetic_similarity(self):
        if not self.population_:
            raise RuntimeError('Cannot compute genetic similarity of empty '
                               'population. Are you calling genetic_similarity '
                               'method before searching?')

        individuals = np.array([i.data for i in self.population_])

        centroid = (np.sum(individuals, axis=0).astype(float) /
                    individuals.shape[0])

        # Average distance from the centroid, relative to the maximum variance
        # (all genes being different).
        # This assumes that genes assume integer values in {0, 1} set,
        # and it should be improved.:-(
        self.variability_ = np.mean(
            distance.cdist(individuals, np.array([centroid])) /
            np.sqrt(individuals.shape[1]))

        if self.debug:
            self.generations_variability_.append(self.variability_)

        return self.variability_

max_stars_repo_name: lucasdavid/artificial

max_issues_repo_name: lucasdavid/artificial

max_forks_repo_name: lucasdavid/artificial

reason: import numpy,from scipy


text:
# -*- coding: utf-8 -*-

import os
import shutil

import torch

import numpy as np

from ..dim_processor import DimProcessorBase
from ..feature_enhancer import EnhanceBase
from ..metric import MetricBase
from ..re_ranker import ReRankerBase
from ..utils import feature_loader

import matplotlib.pyplot as plt

from typing import Dict, List

class IndexHelper:
    """
    A helper class to index features.
    """
    def __init__(
            self,
            dim_processors: List[DimProcessorBase],
            feature_enhancer: EnhanceBase,
            metric: MetricBase,
            re_ranker: ReRankerBase,
    ):
        """
        Args:
            dim_processors (list):
            feature_enhancer (EnhanceBase):
            metric (MetricBase):
            re_ranker (ReRankerBase):
        """
        self.dim_procs = dim_processors
        self.feature_enhance = feature_enhancer
        self.metric = metric
        self.re_rank = re_ranker

    def show_topk_retrieved_images(self, single_query_info: Dict, topk: int, gallery_info: List[Dict]) -> None:
        """
        Show the top-k retrieved images of one query.

        Args:
            single_query_info (dict): a dict of single query information.
            topk (int): number of the nearest images to be showed.
            gallery_info (list): a list of gallery set information.
        """
        query_idx = single_query_info["ranked_neighbors_idx"]
        query_topk_idx = query_idx[:topk]

        for idx in query_topk_idx:
            img_path = gallery_info[idx]["path"]
            plt.figure()
            plt.imshow(img_path)
            plt.show()

    def save_topk_retrieved_images(self, save_path: str, single_query_info: Dict, topk: int, gallery_info: List[Dict]) -> None:
        """
        Save the top-k retrieved images of one query.

        Args:
            save_path (str): the path to save the retrieved images.
            single_query_info (dict): a dict of single query information.
            topk (int): number of the nearest images to be saved.
            gallery_info (list): a list of gallery set information.
        """
        query_idx = single_query_info["ranked_neighbors_idx"]
        query_topk_idx = query_idx[:topk]

        for idx in query_topk_idx:
            img_path = gallery_info[idx]["path"]
            shutil.copy(img_path, os.path.join(save_path, str(idx)+'.png'))

    def do_index(self, query_fea: np.ndarray, query_info: List, gallery_fea: np.ndarray) -> (List, np.ndarray, np.ndarray):
        """
        Index the query features.

        Args:
            query_fea (np.ndarray): query set features.
            query_info (list): a list of gallery set information.
            gallery_fea (np.ndarray): gallery set features.

        Returns:
            tuple(List, np.ndarray, np.ndarray): query feature information, query features and gallery features after process.
        """
        for dim_proc in self.dim_procs:
            query_fea, gallery_fea = dim_proc(query_fea), dim_proc(gallery_fea)

        query_fea, gallery_fea = torch.Tensor(query_fea), torch.Tensor(gallery_fea)
        # if torch.cuda.is_available():
        #     query_fea = query_fea.cuda()
        #     gallery_fea = gallery_fea.cuda()

        gallery_fea = self.feature_enhance(gallery_fea)

        dis, sorted_index = self.metric(query_fea, gallery_fea)

        sorted_index = self.re_rank(query_fea, gallery_fea, dis=dis, sorted_index=sorted_index)
        for i, info in enumerate(query_info):
            info["ranked_neighbors_idx"] = sorted_index[i].tolist()

        return query_info, query_fea, gallery_fea

max_stars_repo_name: dongan-beta/PyRetri

max_issues_repo_name: dongan-beta/PyRetri

max_forks_repo_name: dongan-beta/PyRetri