#Boa:Frame:Frame1

import wx

def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1STATICTEXT1,
] = [wx.NewId() for _init_ctrls in range(3)]

class Frame1(wx.Frame):
    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
              pos=wx.Point(400, 134), size=wx.Size(578, 475),
              style=wx.DEFAULT_FRAME_STYLE, title=u'my frist app')
        self.SetClientSize(wx.Size(578, 475))
        self.SetMaxSize(wx.Size(578, 475))
        self.SetMinSize(wx.Size(578, 475))

        self.button1 = wx.Button(id=wxID_FRAME1BUTTON1, label=u'Click me',
              name='button1', parent=self, pos=wx.Point(0, 0), size=wx.Size(112,
              48), style=0)
        self.button1.SetMinSize(wx.Size(112, 48))
        self.button1.SetMaxSize(wx.Size(112, 48))
        self.button1.Bind(wx.EVT_BUTTON, self.OnButton1Button,
              id=wxID_FRAME1BUTTON1)

        self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
              label=u'Welcome to my first app!', name='staticText1',
              parent=self, pos=wx.Point(192, 88), size=wx.Size(168, 32),
              style=0)
        self.staticText1.SetToolTipString(u'RUCULA')

    def __init__(self, parent):
        self._init_ctrls(parent)

    def OnButton1Button(self, event):
        dlg = wx.MessageDialog(self, 'This is a simple modal window', 'first app modal', wx.OK)
        dlg.ShowModal()
        dlg.Destroy()
        event.Skip()


from transformers import AutoTokenizer, pipeline, AutoModelForTokenClassification

class FactFixer():
    def __init__(self,
                 model_path):
        """
        Loads NER model at model_path.
        ARGUMENTS:
            model_path: string to path of NER model.
        """
        self.model = pipeline("ner",
                              model=AutoModelForTokenClassification.from_pretrained(model_path),
                              tokenizer=AutoTokenizer.from_pretrained(model_path))

    def infer(self,
              original,
              paraphrase):
        """
        Given input and paraphrased sentence, check if proper nouns are incorrectly modified
        and correct any erroneous misplacements.
        ARGUMENTS:
            original: input sentence string
            paraphrase: paraphrased sentence string
        """
        original_ne = [item["word"] for item in self.model(original)]
        paraphrase_ne = [item["word"] for item in self.model(paraphrase)]

        for index, ne in enumerate(original_ne):
            if paraphrase_ne[index].lower() != ne.lower():
                paraphrase = paraphrase.replace(paraphrase[index], ne)

        return paraphrase


def MAF_counts_distribution(SNP_file):
    '''
    (file) -> list
    Return the list of SNP counts in each MAF bin
    '''

    myfile = open(SNP_file, 'r')
    header = myfile.readline()

    # make a dictionnary with gene as key and list of MAF as value
    genes_MAF = {}
    for line in myfile:
        line = line.rstrip()
        if line != '':
            line = line.split()
            gene = line[0]
            genes_MAF[gene] = []
            if ';' in line[10]:
                strains = line[10].split(';')
                snps = line[11].split(';')
                for i in range(len(strains)):
                    MAF = (int(snps[i]) / int(strains[i])) * 100
                    genes_MAF[gene].append(MAF)
            else:
                genes_MAF[gene].append((int(line[11]) / int(line[10])) * 100)

    # make a list with all the MAF
    all_MAF = []
    for gene in genes_MAF:
        for MAF in genes_MAF[gene]:
            all_MAF.append(MAF)

    # make a list to update with MAF counts
    MAF_counts = [0] * 5

    # determine the index in the list where the MAF should be added
    # count the number of times a position appear within the window
    for MAF in all_MAF:
        which_range = int(MAF) // 20
        MAF_counts[which_range] += 1

    return MAF_counts

def compare_MAF_distribution(PTC_file, SNP_file):
    '''
    (file, file) -> tuple
    Performs a chi-square to compare the distribution of PTCs and other SNPs, and return a tuple with the chi-square, the p-value, and the degree of freedom
    '''
    from scipy import stats

    PTC = MAF_counts_distribution(PTC_file)
    SNP = MAF_counts_distribution(SNP_file)

    diff = stats.chi2_contingency([PTC, SNP])

    return(diff[0], diff[1], diff[2])

def histogram_MAF_distribution(SNP_file):
    '''
    (file) -> list
    Return a lit with frequencies of SNPs in each MAF bin to plot the histogram
    '''

    SNP = MAF_counts_distribution(SNP_file)
    total = 0
    for count in SNP:
        total += count

    MAF_freq = []
    for count in SNP:
        MAF_freq.append(count / total)

    return MAF_freq

def average_MAF_along_CDS(PTC_file, window):
    '''
    (file, int) -> list of list
    Return a list of lists, with each inner list containing the MAF value of PTC in bins of size window
    Precondition: only the most 5' PTC is considered
    '''

    from tool_box import compute_mean_std_error

    stops = open(PTC_file, 'r')
    header = stops.readline()

    # make a list of empty lists to be updated with the MAF values
    i = 100 // window
    PTC = []
    while i != 0:
        PTC.append([])
        i -= 1

    # add the MAF of the most 5' PTC to each bin
    for line in stops:
        line = line.rstrip()
        if line != '':
            line = line.split()
            position = int(line[8]) / int(line[3]) * 100
            if ';' in line[10]:
                strains = line[10].split(';')
                snps = line[11].split(';')
                MAF = (int(snps[0]) / int(strains[0])) * 100
            else:
                MAF = int(line[11]) / int(line[10]) * 100
            which_range = int(position) // window
            PTC[which_range].append(MAF)

    # compte MAF mean and std err for each bin
    average_MAF = []
    for i in range(len(PTC)):
        average = compute_mean_std_error(PTC[i])
        average_MAF.append(average)

    stops.close()
    return average_MAF


# budget program, where I can enter in my expenses and it will store results
# perhaps I can also incorperate some graphs or something

import sqlite3
import random

# might want to change the database name, if I want this to be a budget program
EXPENSE_DATABASE = "expenses.db"
EXPENSE_TYPES = ("FOOD", "RENT", "UTILITIES", "ENTERTAINMENT", "MISC")

# Perhaps I need an income table
def create_database():
    db = sqlite3.connect(EXPENSE_DATABASE)
    cursor = db.cursor()
    cursor.execute('''DROP TABLE expenses''')
    db.commit()
    cursor.execute("CREATE TABLE expenses(uid INTEGER PRIMARY KEY, type TEXT, cost INTEGER)")
    db.commit()
    db.close()

def get_expenses(expense_type):
    db = sqlite3.connect(EXPENSE_DATABASE)
    cursor = db.cursor()
    cursor.execute("SELECT cost, type FROM expenses WHERE type=?", (expense_type,))

    values = [row for row in cursor]

    for row in values:
        print('{0} : {1}'.format(row[0], row[1]))

    print(expense_type + " Total: " + str(sum([row[0] for row in values])))

    db.close()

def add_expense(uid, expense_type, cost):
    db = sqlite3.connect(EXPENSE_DATABASE)
    cursor = db.cursor()

    if expense_type in EXPENSE_TYPES:
        cursor.execute("INSERT INTO expenses(uid, type, cost) \
                            VALUES(?,?,?)", (uid, expense_type, cost))

    db.commit()
    db.close()

#create_database()

#for i in range(100):
    #add_expense(i, random.choice(EXPENSE_TYPES), random.randrange(1000))

get_expenses("FOOD")
print()
get_expenses("RENT")
print()
get_expenses("MISC")


from energy_models.core.stream_type.carbon_models.carbon_capture import CarbonCapture
from energy_models.core.techno_type.techno_disc import TechnoDiscipline
from sostrades_core.tools.post_processing.charts.chart_filter import ChartFilter
from sostrades_core.tools.post_processing.charts.two_axes_instanciated_chart \
    import InstanciatedSeries, TwoAxesInstanciatedChart

import numpy as np

class CCTechnoDiscipline(TechnoDiscipline):

    # ontology information
    _ontology_data = {
        'label': 'Carbon Capture Techology Model',
        'type': 'Research',
        'source': 'SoSTrades Project',
        'validated': '',
        'validated_by': 'SoSTrades Project',
        'last_modification_date': '',
        'category': '',
        'definition': '',
        'icon': 'fas fa-air-freshener fa-fw',
        'version': '',
    }
    DESC_IN = {'transport_cost': {'type': 'dataframe', 'unit': '$/t', 'visibility': TechnoDiscipline.SHARED_VISIBILITY,
                                  'namespace': 'ns_carbon_capture',
                                  'dataframe_descriptor': {'years': ('int',  [1900, 2100], False),
                                                           'transport': ('float',  None, True)},
                                  'dataframe_edition_locked': False},
               'transport_margin': {'type': 'dataframe', 'unit': '%', 'visibility': TechnoDiscipline.SHARED_VISIBILITY,
                                    'namespace': 'ns_carbon_capture',
                                    'dataframe_descriptor': {'years': ('int',  [1900, 2100], False),
                                                             'margin': ('float',  None, True)},
                                    'dataframe_edition_locked': False},
               'fg_ratio_effect': {'type': 'bool', 'visibility': TechnoDiscipline.SHARED_VISIBILITY,
                                   'namespace': 'ns_carbon_capture', 'default': True},
               'data_fuel_dict': {'type': 'dict', 'visibility': TechnoDiscipline.SHARED_VISIBILITY,
                                  'namespace': 'ns_carbon_capture', 'default': CarbonCapture.data_energy_dict,
                                  'unit': 'defined in dict'},

               }
    DESC_IN.update(TechnoDiscipline.DESC_IN)

    _maturity = 'Research'

    energy_name = CarbonCapture.name

    def set_partial_derivatives_flue_gas(self, energy_name='electricity'):

        inputs_dict = self.get_sosdisc_inputs()
        scaling_factor_invest_level = inputs_dict['scaling_factor_invest_level']
        scaling_factor_techno_consumption = self.get_sosdisc_inputs(
            'scaling_factor_techno_consumption')
        scaling_factor_techno_production = self.get_sosdisc_inputs(
            'scaling_factor_techno_production')
        dcapex_dfluegas = self.techno_model.compute_dcapex_dfg_ratio(
            inputs_dict['flue_gas_mean']['flue_gas_mean'].values,
            inputs_dict['invest_level'].loc[inputs_dict['invest_level']['years'] <=
                                            inputs_dict['year_end']]['invest'].values,
            inputs_dict['techno_infos_dict'], inputs_dict['fg_ratio_effect'])

        crf = self.techno_model.compute_crf(inputs_dict['techno_infos_dict'])
        dfactory_dfluegas = dcapex_dfluegas * \
            (crf + inputs_dict['techno_infos_dict']['Opex_percentage'])

        delec_dflue_gas = self.techno_model.compute_delec_dfg_ratio(
            inputs_dict['flue_gas_mean']['flue_gas_mean'].values, inputs_dict['fg_ratio_effect'], energy_name)

        margin = inputs_dict['margin'].loc[inputs_dict['margin']['years']
                                           <= inputs_dict['year_end']]['margin'].values

        dprice_dfluegas = (dfactory_dfluegas + delec_dflue_gas) * np.split(margin, len(margin)) / \
            100.0

        self.set_partial_derivative_for_other_types(
            ('techno_prices', f'{self.techno_name}'), ('flue_gas_mean', 'flue_gas_mean'), dprice_dfluegas)

        self.set_partial_derivative_for_other_types(
            ('techno_prices', f'{self.techno_name}_wotaxes'), ('flue_gas_mean', 'flue_gas_mean'), dprice_dfluegas)

        capex = self.get_sosdisc_outputs('techno_detailed_prices')[
            f'Capex_{self.techno_name}'].values

        dprod_dfluegas = self.techno_model.compute_dprod_dfluegas(
            capex, inputs_dict['invest_level']['invest'].values,
            inputs_dict['invest_before_ystart']['invest'].values,
            inputs_dict['techno_infos_dict'], dcapex_dfluegas)

        self.set_partial_derivative_for_other_types(
            ('techno_production', f'{self.energy_name} ({self.techno_model.product_energy_unit})'), (
                'flue_gas_mean', 'flue_gas_mean'),
            dprod_dfluegas * self.techno_model.applied_ratio['applied_ratio'].values[:, np.newaxis] * scaling_factor_invest_level / scaling_factor_techno_production)

        production, consumption = self.get_sosdisc_outputs(
            ['techno_production', 'techno_consumption'])
        for column in consumption:
            dprod_column_dfluegas = dprod_dfluegas.copy()
            if column not in ['years']:
                var_cons = (consumption[column] /
                            production[f'{self.energy_name} ({self.techno_model.product_energy_unit})']).fillna(
                    0)
                for line in range(len(consumption[column].values)):
                    dprod_column_dfluegas[line, :] = dprod_dfluegas[line,
                                                                    :] * var_cons[line]
                self.set_partial_derivative_for_other_types(
                    ('techno_consumption', column), ('flue_gas_mean', 'flue_gas_mean'),
                    dprod_column_dfluegas * self.techno_model.applied_ratio['applied_ratio'].values[:, np.newaxis] * scaling_factor_invest_level / scaling_factor_techno_production)
                self.set_partial_derivative_for_other_types(
                    ('techno_consumption_woratio',
                     column), ('flue_gas_mean', 'flue_gas_mean'),
                    dprod_column_dfluegas * scaling_factor_invest_level / scaling_factor_techno_production)

        dnon_use_capital_dflue_gas_mean, dtechnocapital_dflue_gas_mean = self.techno_model.compute_dnon_usecapital_dfluegas(
            dcapex_dfluegas, dprod_dfluegas)

        self.set_partial_derivative_for_other_types(
            ('non_use_capital', self.techno_model.name), ('flue_gas_mean', 'flue_gas_mean'), dnon_use_capital_dflue_gas_mean)
        self.set_partial_derivative_for_other_types(
            ('techno_capital', self.techno_model.name), ('flue_gas_mean', 'flue_gas_mean'), dtechnocapital_dflue_gas_mean)

    def get_chart_filter_list(self):

        chart_filters = []
        chart_list = ['Detailed prices',
                      'Consumption and production',
                      'Initial Production']
        if self.get_sosdisc_inputs('is_apply_ratio'):
            chart_list.extend(['Applied Ratio'])
        chart_filters.append(ChartFilter(
            'Charts', chart_list, chart_list, 'charts'))

        price_unit_list = ['$/tCO2']
        chart_filters.append(ChartFilter(
            'Price unit', price_unit_list, price_unit_list, 'price_unit'))
        return chart_filters

    def get_post_processing_list(self, filters=None):

        # For the outputs, making a graph for block fuel vs range and blocktime vs
        # range

        instanciated_charts = []
        charts = []
        price_unit_list = ['$/tCO2']
        # Overload default value with chart filter
        if filters is not None:
            for chart_filter in filters:
                if chart_filter.filter_key == 'charts':
                    charts = chart_filter.selected_values
                if chart_filter.filter_key == 'price_unit':
                    price_unit_list = chart_filter.selected_values

        if 'Detailed prices' in charts and '$/tCO2' in price_unit_list:
            new_chart = self.get_chart_detailed_price_in_dollar_tCO2()
            if new_chart is not None:
                instanciated_charts.append(new_chart)

        if 'Consumption and production' in charts:
            new_chart = self.get_chart_investments()
            if new_chart is not None:
                instanciated_charts.append(new_chart)

            new_charts = self.get_charts_consumption_and_production()
            for new_chart in new_charts:
                if new_chart is not None:
                    instanciated_charts.append(new_chart)

            new_charts = self.get_charts_consumption_and_production_energy()
            for new_chart in new_charts:
                if new_chart is not None:
                    instanciated_charts.append(new_chart)

        if 'Applied Ratio' in charts:
            new_chart = self.get_chart_applied_ratio()
            if new_chart is not None:
                instanciated_charts.append(new_chart)

        if 'Initial Production' in charts:
            if 'initial_production' in self.get_data_in():
                new_chart = self.get_chart_initial_production()
                if new_chart is not None:
                    instanciated_charts.append(new_chart)

        return instanciated_charts

    def get_chart_detailed_price_in_dollar_tCO2(self):

        techno_detailed_prices = self.get_sosdisc_outputs(
            'techno_detailed_prices')

        chart_name = f'Detailed prices of {self.techno_name} technology over the years'
        year_start = min(techno_detailed_prices['years'].values.tolist())
        year_end = max(techno_detailed_prices['years'].values.tolist())
        minimum = 0
        maximum = max(
            (techno_detailed_prices[self.techno_name].values).tolist()) * 1.2

        new_chart = TwoAxesInstanciatedChart('years', 'Prices [$/tCO2]', [year_start, year_end], [minimum, maximum],
                                             chart_name=chart_name)

        if 'percentage_resource' in self.get_data_in():
            percentage_resource = self.get_sosdisc_inputs(
                'percentage_resource')
            new_chart.annotation_upper_left = {
                'Percentage of total price at starting year': f'{percentage_resource[self.energy_name][0]} %'}
            tot_price = (techno_detailed_prices[self.techno_name].values) / \
                (percentage_resource[self.energy_name] / 100.)
            serie = InstanciatedSeries(
                techno_detailed_prices['years'].values.tolist(),
                tot_price.tolist(), 'Total price without percentage', 'lines')
            new_chart.series.append(serie)
        # Add total price
        serie = InstanciatedSeries(
            techno_detailed_prices['years'].values.tolist(),
            (techno_detailed_prices[self.techno_name].values).tolist(), 'Total price with margin', 'lines')

        new_chart.series.append(serie)

        # Factory price
        serie = InstanciatedSeries(
            techno_detailed_prices['years'].values.tolist(),
            (techno_detailed_prices[f'{self.techno_name}_factory'].values).tolist(), 'Factory', 'lines')

        new_chart.series.append(serie)

        if 'energy_costs' in techno_detailed_prices:
            # energy_costs
            serie = InstanciatedSeries(
                techno_detailed_prices['years'].values.tolist(),
                (techno_detailed_prices['energy_costs'].values).tolist(), 'Energy costs', 'lines')

            new_chart.series.append(serie)

        # Transport price
        serie = InstanciatedSeries(
            techno_detailed_prices['years'].values.tolist(),
            (techno_detailed_prices['transport'].values).tolist(), 'Transport', 'lines')

        new_chart.series.append(serie)
        # CO2 taxes
        serie = InstanciatedSeries(
            techno_detailed_prices['years'].values.tolist(),
            (techno_detailed_prices['CO2_taxes_factory'].values).tolist(), 'CO2 taxes due to production', 'lines')
        new_chart.series.append(serie)

        return new_chart

    def get_chart_investments(self):
        # Chart for input investments
        input_investments = self.get_sosdisc_inputs('invest_level')

        chart_name = f'Input investments over the years'

        new_chart = TwoAxesInstanciatedChart('years', 'Investments [G$]',
                                             chart_name=chart_name, stacked_bar=True)
        invest = input_investments['invest'].values
        serie = InstanciatedSeries(
            input_investments['years'].values.tolist(),
            invest.tolist(), '', 'bar')

        new_chart.series.append(serie)

        return new_chart

    def get_charts_consumption_and_production(self):
        instanciated_charts = []
        # Charts for consumption and prod
        techno_consumption = self.get_sosdisc_outputs(
            'techno_detailed_consumption')
        techno_production = self.get_sosdisc_outputs(
            'techno_detailed_production')
        chart_name = f'{self.techno_name} resources production & consumption
with input investments'

        new_chart = TwoAxesInstanciatedChart('years', 'Mass [Mt]',
                                             chart_name=chart_name, stacked_bar=True)

        for reactant in techno_consumption.columns:
            if reactant != 'years' and reactant.endswith('(Mt)'):
                energy_twh = -techno_consumption[reactant].values
                legend_title = f'{reactant} consumption'.replace(
                    "(Mt)", "")
                serie = InstanciatedSeries(
                    techno_consumption['years'].values.tolist(),
                    energy_twh.tolist(), legend_title, 'bar')

                new_chart.series.append(serie)

        for products in techno_production.columns:
            if products != 'years' and products.endswith('(Mt)'):
                energy_twh = techno_production[products].values
                legend_title = f'{products} product'.replace(
                    "(Mt)", "")
                serie = InstanciatedSeries(
                    techno_production['years'].values.tolist(),
                    energy_twh.tolist(), legend_title, 'bar')

                new_chart.series.append(serie)
        instanciated_charts.append(new_chart)

        return instanciated_charts

    def get_charts_consumption_and_production_energy(self):
        instanciated_charts = []
        # Charts for consumption and prod
        techno_consumption = self.get_sosdisc_outputs(
            'techno_detailed_consumption')
        techno_production = self.get_sosdisc_outputs(
            'techno_detailed_production')
        chart_name = f'{self.techno_name} energy production & consumption
with input investments'

        new_chart = TwoAxesInstanciatedChart('years', 'Energy [TWh]',
                                             chart_name=chart_name, stacked_bar=True)

        for reactant in techno_consumption.columns:
            if reactant != 'years' and reactant.endswith('(TWh)'):
                energy_twh = -techno_consumption[reactant].values
                legend_title = f'{reactant} consumption'.replace(
                    "(TWh)", "")
                serie = InstanciatedSeries(
                    techno_consumption['years'].values.tolist(),
                    energy_twh.tolist(), legend_title, 'bar')

                new_chart.series.append(serie)

        for products in techno_production.columns:
            if products != 'years' and products.endswith('(TWh)'):
                energy_twh = techno_production[products].values
                legend_title = f'{products}'.replace(
                    "(TWh)", "")
                serie = InstanciatedSeries(
                    techno_production['years'].values.tolist(),
                    energy_twh.tolist(), legend_title, 'bar')

                new_chart.series.append(serie)
        instanciated_charts.append(new_chart)

        return instanciated_charts

    def get_chart_initial_production(self):

        year_start = self.get_sosdisc_inputs(
            'year_start')
        initial_production = self.get_sosdisc_inputs(
            'initial_production')
        initial_age_distrib = self.get_sosdisc_inputs(
            'initial_age_distrib')
        initial_prod = initial_age_distrib.copy(deep=True)
        initial_prod['CO2 (Mt)'] = initial_prod['distrib'] / \
            100.0 * initial_production
        initial_prod['years'] = year_start - initial_prod['age']
        initial_prod.sort_values('years', inplace=True)
        initial_prod['cum CO2 (Mt)'] = initial_prod['CO2 (Mt)'].cumsum()

        study_production = self.get_sosdisc_outputs(
            'techno_detailed_production')
        chart_name = f'World CO2 capture via {self.techno_name}
with 2020 factories distribution'

        new_chart = TwoAxesInstanciatedChart('years', f'{self.energy_name} (Mt)',
                                             chart_name=chart_name)

        serie = InstanciatedSeries(
            initial_prod['years'].values.tolist(),
            initial_prod[f'cum CO2 (Mt)'].values.tolist(), 'Initial carbon capture by 2020 factories', 'lines')
        study_prod = study_production[f'{self.energy_name} (Mt)'].values
        new_chart.series.append(serie)
        years_study = study_production['years'].values.tolist()
        years_study.insert(0, year_start - 1)
        study_prod_l = study_prod.tolist()
        study_prod_l.insert(
            0, initial_prod[f'cum CO2 (Mt)'].values.tolist()[-1])
        serie = InstanciatedSeries(
            years_study,
            study_prod_l, 'Predicted carbon capture', 'lines')
        new_chart.series.append(serie)

        return new_chart


import os
from dotenv import load_dotenv
from modules.download import get, download
from modules.set_filename import set_filename

def fetch_nasa_epic(api_key, path_download, prefix_filename):
    params = {"api_key": api_key}
    url = f"https://api.nasa.gov/EPIC/api/natural/all"
    all_date = get(url, params=params)
    last_date = all_date.json()[0]['date']
    url = f"https://api.nasa.gov/EPIC/api/natural/date/{last_date}"
    fotos_last_day = get(url, params=params)

    for index, snapshot_data in enumerate(fotos_last_day.json()):
        last_date = last_date.replace("-", "/")
        snapshot = f"https://api.nasa.gov/EPIC/archive/natural/{last_date}/png/{snapshot_data['image']}.png"
        file_name = set_filename(snapshot, prefix_filename, "_", str(index))

        download(snapshot, path_download, file_name, params)
    else:
        return "Complate!"

def main():
    load_dotenv()
    NASA_KEY = os.getenv("NASA")
    fetch_nasa_epic(NASA_KEY, "Nasa_Epic", "epic")

if __name__ == "__main__":
    main()


from collections import deque
class Edge:
    def __init__(self,src,nbr):
        self.src = src
        self.nbr = nbr
class pair:
    def __init__(self,v):
        self.v=v
def main():
    vtces = int(input())
    edges = int(input())
    graph = {}
    for i in range(vtces):
        graph[i] = []

    for i in range(edges):
        lines = input().split(" ")
        v1=int(lines[0])
        v2=int(lines[1])
        e1 = Edge(v1 ,v2 )
        e2 = Edge(v2 ,v1 )
        graph[e1.src].append(e1)
        graph[e2.src].append(e2)
    visited=[False]*vtces
    flag=False
    for v in range(vtces):
        if visited[v]==False:
            if isCyclic(graph,v,visited):
                flag=True
                break
    if flag==True:
        print("true")
    else:
        print("false")

def isCyclic(graph,src,visited):
    q=deque()
    q.append(pair(src))
    while len(q)>0:
        r=q.popleft()
        if visited[r.v]==True:
            return True
        visited[r.v]=True
        for e in graph[r.v]:
            if visited[e.nbr]==False:
                q.append(pair(e.nbr))
    return False
    #write your code here

if __name__ == "__main__":
    main()


#!/bin/python3
# Easy
# https://www.hackerrank.com/challenges/time-conversion/problem

# accept the time as string
time = input().strip()
# first ignore AM/PM and store time in variables.
h, m, s = map(int, time[:-2].split(':'))
# the last to letters stored in this variable.
p = time[-2:]

# (p.upper() == 'PM') * 12 is meant to add 12 hours if time after 12 PM to be displayed in 24h format.
h = h % 12 + (p.upper() == 'PM') * 12
# print the time in 00:00:00 format
print(('%02d:%02d:%02d') % (h, m, s))


import os
import time
import datetime
from glob import glob
import numpy as np
from collections import namedtuple
import tensorflow as tf

from tensorflow.keras.optimizers import Adam

from stargan_module import build_generator, build_discriminator, abs_criterion, mae_criterion, discriminator_loss, \
    generator_loss, classification_loss, L1_loss
from tf2_utils import get_now_datetime, ImagePool, to_binary, load_npy_data_starGAN, save_midis, tf_shuffle_axis, concat_with_label

class StarGAN(object):

    def __init__(self, args):

        self.batch_size = args.batch_size
        self.time_step = args.time_step  # number of time steps
        self.pitch_range = args.pitch_range  # number of pitches
        self.input_c_dim = args.input_nc  # number of input image channels
        self.output_c_dim = args.output_nc  # number of output image channels
        self.lr = args.lr
        self.L1_lambda = args.L1_lambda
        self.gamma = args.gamma
        self.sigma_d = args.sigma_d
        self.dataset_A_dir = args.dataset_A_dir
        self.dataset_B_dir = args.dataset_B_dir
        self.dataset_C_dir = args.dataset_C_dir
        self.sample_dir = args.sample_dir

        self.adv_weight = args.adv_weight
        self.rec_weight = args.rec_weight
        self.cls_weight = args.cls_weight
        self.diff_weight = args.diff_weight
        self.gan_type = args.gan_type

        self.model = args.model
        self.discriminator = build_discriminator
        self.generator = build_generator
        self.number_of_domains = args.number_of_domains
        self.ld = args.ld

        self.note_threshold = args.note_threshold

        self.criterionGAN = mae_criterion

        OPTIONS = namedtuple('OPTIONS', 'batch_size '
                                        'time_step '
                                        'input_nc '
                                        'output_nc '
                                        'pitch_range '
                                        'gf_dim '
                                        'df_dim '
                                        'is_training '
                                        'number_of_domains ')
        self.options = OPTIONS._make((args.batch_size,
                                      args.time_step,
                                      args.input_nc,
                                      args.output_nc,
                                      args.pitch_range,
                                      args.ngf,
                                      args.ndf,
                                      args.phase == 'train',
                                      args.number_of_domains
                                      ))
        print(self.options)

        self.now_datetime = get_now_datetime()
        self.pool = ImagePool(args.max_size)

        self._build_model(args)

        print("initialize model...")

    def _build_model(self, args):
        # Generator
        self.generator_star = self.generator(self.options,
                                             name='Generator_star')
        # Discriminator
        self.discriminator_star = self.discriminator(self.options,
                                                     name='Discriminator_star')

        # Discriminator and Generator Optimizer
        self.D_optimizer = Adam(self.lr,
                                beta_1=args.beta1)
        self.G_optimizer = Adam(self.lr,
                                beta_1=args.beta1)

        # Checkpoints
        model_name = "stargan.model"
        model_dir = "stargan_{}2{}_{}_{}_{}".format(self.dataset_A_dir,
                                                    self.dataset_B_dir,
                                                    self.now_datetime,
                                                    self.model,
                                                    self.sigma_d)
        self.checkpoint_dir = os.path.join(args.checkpoint_dir,
                                           model_dir,
                                           model_name)
        if not os.path.exists(self.checkpoint_dir):
            os.makedirs(self.checkpoint_dir)

        if self.model == 'base':
            self.checkpoint = tf.train.Checkpoint(
                generator_optimizer=self.G_optimizer,
                discriminator_optimizer=self.D_optimizer,
                generator=self.generator_star,
                discriminator=self.discriminator_star
            )
        else:
            self.checkpoint = tf.train.Checkpoint(generator_optimizer=self.G_optimizer,
                                                  discriminator_optimizer=self.D_optimizer,
                                                  discriminator_all_optimizer=self.D_all_optimizer,
                                                  generator=self.generator_star,
                                                  discriminator=self.discriminator_star,
                                                  discriminator_all=self.discriminator_all)

        self.checkpoint_manager = tf.train.CheckpointManager(self.checkpoint,
                                                             self.checkpoint_dir,
                                                             max_to_keep=25)

        # if self.checkpoint_manager.latest_checkpoint:
        #     self.checkpoint.restore(self.checkpoint_manager.latest_checkpoint)
        #     print('Latest checkpoint restored!!')

    def train(self, args):
        # Data from domain A and B, and mixed dataset for partial and full models.
        data_1 = np.array(glob('./datasets/{}/train/*.*'.format(self.dataset_A_dir)))
        data_2 = np.array(glob('./datasets/{}/train/*.*'.format(self.dataset_B_dir)))
        data_3 = np.array(glob('./datasets/{}/train/*.*'.format(self.dataset_C_dir)))

        label_1 = 0
        label_2 = 1
        label_3 = 2

        labels_1 = np.full((data_1.shape[0]), label_1)
        labels_2 = np.full((data_2.shape[0]), label_2)
        labels_3 = np.full((data_3.shape[0]), label_3)

        combined_data_1 = list(zip(data_1, labels_1))
        combined_data_2 = list(zip(data_2, labels_2))
        combined_data_3 = list(zip(data_2, labels_3))

        data_all = np.concatenate((combined_data_1, combined_data_2, combined_data_3))

        if args.continue_train:
            if self.checkpoint.restore(self.checkpoint_manager.latest_checkpoint):
                print(" [*] Load checkpoint succeeded!")
            else:
                print(" [!] Load checkpoint failed...")

        counter = 0
        start_time = time.time()

        # tensorboard
        g_loss_metric = tf.keras.metrics.Mean('g_loss', dtype=tf.float32)
        d_loss_metric = tf.keras.metrics.Mean('d_loss', dtype=tf.float32)

        g_adv_loss_metric = tf.keras.metrics.Mean('g_adv_loss', dtype=tf.float32)
        g_cls_loss_metric = tf.keras.metrics.Mean('g_cls_loss', dtype=tf.float32)
        g_rec_loss_metric = tf.keras.metrics.Mean('g_rec_loss', dtype=tf.float32)
        d_adv_loss_metric = tf.keras.metrics.Mean('d_adv_loss', dtype=tf.float32)
        adv_loss_metric = tf.keras.metrics.Mean('adv_loss', dtype=tf.float32)
        d_cls_loss_metric = tf.keras.metrics.Mean('d_cls_loss', dtype=tf.float32)
        number_of_notes_metric = tf.keras.metrics.Mean('number_of_notes', dtype=tf.float32)

        current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
        train_log_dir = 'tb_logs/gradient_tape/' + current_time + '/train'
        train_summary_writer = tf.summary.create_file_writer(train_log_dir)
        # end tensorboard

        for epoch in range(args.epoch):

            # Shuffle training data
            np.random.shuffle(data_all)

            # Get the proper number of batches
            batch_idxs = len(data_all) // self.batch_size

            # learning rate starts to decay when reaching the threshold
            self.lr = self.lr if epoch < args.epoch_step else self.lr * (args.epoch - epoch) / (
                        args.epoch - args.epoch_step)

            for idx in range(batch_idxs):

                # To feed real_data
                batch_data = data_all[idx * self.batch_size:(idx + 1) * self.batch_size]

                batch_samples = [load_npy_data_starGAN(batch_file) for batch_file in batch_data[:,0]]
                batch_samples = np.array(batch_samples).astype(np.float32)  # batch_size * 64 * 84 * 1
                x_real = batch_samples[:, :, :, 0]
                x_real = tf.expand_dims(x_real, -1)

                # generate gaussian noise for robustness improvement
                gaussian_noise = np.abs(np.random.normal(0,
                                                         self.sigma_d,
                                                         [self.batch_size,
                                                          self.time_step,
                                                          self.pitch_range,
                                                          self.input_c_dim])).astype(np.float32)

                with tf.GradientTape(persistent=True) as gen_tape, tf.GradientTape(persistent=True) as disc_tape:

                    labels_orig = tf.convert_to_tensor(batch_data[:, 1].astype(int))
                    labels_orig = tf.one_hot(labels_orig, depth= self.number_of_domains)
                    labels_target = tf_shuffle_axis(labels_orig, axis=1)
                    real_x_with_target_label = concat_with_label(x_real, labels_target)

                    """ Define Generator, Discriminator """

                    x_fake = self.generator_star(real_x_with_target_label, training=True)
                    fake_x_with_orig_label = concat_with_label(x_fake, labels_orig)
                    x_recon = self.generator_star(fake_x_with_orig_label, training=True)

                    real_cls = self.discriminator_star(x_real)
                    fake_cls = self.discriminator_star(x_fake)

                    """ Define Loss """
                    if self.gan_type.__contains__('wgan') or self.gan_type == 'dragan':
                        gp = self.gradient_penalty(real=x_real, fake=x_fake)
                    else:
                        gp = 0

                    sum_difference = tf.abs(tf.reduce_sum(x_fake)-325*self.batch_size)
                    #print("sd {}".format(sum_difference.numpy()))

                    #g_adv_loss = generator_loss(loss_func=self.gan_type, fake=fake_logit)
                    #g_adv_loss = generator_loss(loss_func=self.gan_type, fake=fake_cls)
                    g_cls_loss = classification_loss(logit=fake_cls, label=labels_target)
                    g_rec_loss = L1_loss(x_real, x_recon)

                    #d_adv_loss = discriminator_loss(loss_func=self.gan_type, real=real_cls, fake=fake_cls) + gp
                    adv_loss = discriminator_loss(loss_func=self.gan_type, real=real_cls, fake=fake_cls) + gp
                    d_cls_loss = classification_loss(logit=real_cls, label=labels_orig)

                    d_loss = -self.adv_weight * adv_loss + self.cls_weight * d_cls_loss
                    g_loss = self.adv_weight * adv_loss + self.cls_weight * g_cls_loss + self.rec_weight * g_rec_loss + self.diff_weight * sum_difference

                # Calculate the gradients for generator and discriminator
                generator_gradients = gen_tape.gradient(target=g_loss,
                                                        sources=self.generator_star.trainable_variables)
                discriminator_gradients = disc_tape.gradient(target=d_loss,
                                                             sources=self.discriminator_star.trainable_variables)

                # Apply the gradients to the optimizer
                self.G_optimizer.apply_gradients(zip(generator_gradients,
                                                     self.generator_star.trainable_variables))
                self.D_optimizer.apply_gradients(zip(discriminator_gradients,
                                                     self.discriminator_star.trainable_variables))

                # tensorboard
                g_loss_metric(g_loss)
                d_loss_metric(d_loss)
                #g_adv_loss_metric(g_adv_loss)
                g_cls_loss_metric(g_cls_loss)
                g_rec_loss_metric(g_rec_loss)
                #d_adv_loss_metric(d_adv_loss)
                adv_loss_metric(adv_loss)
                d_cls_loss_metric(d_cls_loss)
                number_of_notes_metric( len([1 for v in x_fake.numpy().flatten() if v > self.note_threshold]) / self.batch_size  )
                # end tensorboard
                print('=================================================================')
                print(("Epoch: [%2d] [%4d/%4d] time: %4.4f D_loss: %6.2f, G_loss: %6.2f" %
                       (epoch, idx, batch_idxs, time.time() - start_time, d_loss, g_loss)))

                counter += 1

                print("real {:6.2f}, fake {:6.2f}, recon {:6.2f}".format( tf.reduce_sum(x_real).numpy(), tf.reduce_sum(x_fake).numpy(), tf.reduce_sum(x_recon).numpy()))

                # save tensorboard data
                if np.mod(counter, args.tb_print_freq) == 0:
                    with train_summary_writer.as_default():
                        tf.summary.scalar('d_loss', d_loss_metric.result(), step=counter)
                        tf.summary.scalar('g_loss', g_loss_metric.result(), step=counter)
                        #tf.summary.scalar('g_adv_loss', g_adv_loss_metric.result(), step=counter)
                        tf.summary.scalar('g_cls_loss', g_cls_loss_metric.result(), step=counter)
                        tf.summary.scalar('g_rec_loss', g_rec_loss_metric.result(), step=counter)
                        #tf.summary.scalar('d_adv_loss', d_adv_loss_metric.result(), step=counter)
                        tf.summary.scalar('adv_loss', adv_loss_metric.result(), step=counter)
                        tf.summary.scalar('d_cls_loss', d_cls_loss_metric.result(), step=counter)
                        tf.summary.scalar('number_of_notes', number_of_notes_metric.result(), step=counter)

                    d_loss_metric.reset_states()
                    g_loss_metric.reset_states()
                    g_adv_loss_metric.reset_states()
                    g_cls_loss_metric.reset_states()
                    g_rec_loss_metric.reset_states()
                    d_adv_loss_metric.reset_states()
                    d_cls_loss_metric.reset_states()
                    adv_loss_metric.reset_states()
                    number_of_notes_metric.reset_states()

                # generate samples during training to track the learning process
                if np.mod(counter, args.print_freq) == 0:
                    sample_dir = os.path.join(self.sample_dir,
                                              '{}2{}_{}_{}_{}'.format(self.dataset_A_dir,
                                                                      self.dataset_B_dir,
                                                                      self.now_datetime,
                                                                      self.model,
                                                                      self.sigma_d))
                    if not os.path.exists(sample_dir):
                        os.makedirs(sample_dir)

                    # to binary, 0 denotes note off, 1 denotes note on
                    samples = [to_binary(x_real,  self.note_threshold),
                               to_binary(x_fake,  self.note_threshold),
                               to_binary(x_recon,  self.note_threshold)]

                    self.sample_model(samples=samples,
                                      labels_orig = labels_orig,
                                      labels_target = labels_target,
                                      sample_dir=sample_dir,
                                      epoch=epoch,
                                      idx=idx)

                if np.mod(counter, args.save_freq) == 0:
                    self.checkpoint_manager.save(counter)

    def sample_model(self, samples, labels_orig, labels_target, sample_dir, epoch, idx):
        print('generating samples during learning......')

        index_orig = tf.argmax(labels_orig, axis=1)
        index_target = tf.argmax(labels_target, axis=1)

        for rec_num in range(samples[0].shape[0]):

            save_midis(tf.reshape(samples[0][rec_num],(1,64,84,1)), './{}/{:02d}_{:04d}_{:04d}_{}to{}_real.mid'.format(sample_dir, epoch, idx, rec_num, index_orig[rec_num], index_target[rec_num]))
            save_midis(tf.reshape(samples[1][rec_num],(1,64,84,1)), './{}/{:02d}_{:04d}_{:04d}_{}to{}_generated.mid'.format(sample_dir, epoch, idx, rec_num, index_orig[rec_num], index_target[rec_num], rec_num))
            save_midis(tf.reshape(samples[2][rec_num],(1,64,84,1)), './{}/{:02d}_{:04d}_{:04d}_{}to{}_reconstructed.mid'.format(sample_dir, epoch, idx, rec_num, index_orig[rec_num], index_target[rec_num], rec_num))
            np.save(('./{}/{:02d}_{:04d}_{:04d}_{}to{}_generated.npy'.format(sample_dir, epoch, idx, rec_num, index_orig[rec_num], index_target[rec_num], rec_num)),tf.reshape(samples[1][rec_num], (1, 64, 84, 1)).numpy())

    def gradient_penalty(self, real, fake, scope="discriminator"):
        if self.gan_type == 'dragan' :
            shape = tf.shape(real)
            eps = tf.random.uniform(shape=shape, minval=0., maxval=1.)
            x_mean, x_var = tf.nn.moments(real, axes=[0, 1, 2, 3])
            x_std = tf.sqrt(x_var)  # magnitude of noise decides the size of local region
            noise = 0.5 * x_std * eps  # delta in paper

            # Author suggested U[0,1] in original paper, but he admitted it is bug in github
            # (https://github.com/kodalinaveen3/DRAGAN). It should be two-sided.

            alpha = tf.random.uniform(shape=[shape[0], 1, 1, 1], minval=-1., maxval=1.)
            interpolated = tf.clip_by_value(real + alpha * noise, -1., 1.)  # x_hat should be in the space of X

        else :
            alpha = tf.random.uniform(shape=[self.batch_size, 1, 1, 1], minval=0., maxval=1.)
            interpolated = alpha*real + (1. - alpha)*fake

        GP = 0

        #grad = tf.gradients(logit, interpolated)[0]  # gradient of D(interpolated)
        #grad_norm = tf.norm(flatten(grad), axis=1)  # l2 norm
        interpolated = tf.Variable(interpolated)

        with tf.GradientTape(persistent=True) as grad_tape:
            grad_tape.watch(interpolated)
            logit, _ = self.discriminator_star(interpolated)

        grad = grad_tape.gradient(logit,interpolated)[0]

        grad_norm = tf.norm(grad, axis=1)  # l2 norm

        # WGAN - LP
        if self.gan_type == 'wgan-lp' :
            GP = self.ld * tf.reduce_mean(tf.square(tf.maximum(0.0, grad_norm - 1.)))

        elif self.gan_type == 'wgan-gp' or self.gan_type == 'dragan':
            GP = self.ld * tf.reduce_mean(tf.square(grad_norm - 1.))

        return GP


import numpy as np
import matplotlib.pyplot as plt
import csv

file_name = './results/performance_removing.csv'
case_array = []
accuracy_rate = []
miss_rate = []

with open(file_name, 'r') as csvFile:
    reader = csv.reader(csvFile)
    next(reader)
    for row in reader:
        case_array.append(int(row[0]))
        accuracy_rate.append(float(row[8]))
        miss_rate.append(float(row[9]))
csvFile.close()

case_array = np.array(case_array)
accuracy_rate = np.array(accuracy_rate)
miss_rate = np.array(miss_rate)

find_1 = np.where(case_array == 1)
find_2 = np.where(case_array == 2)
find_3 = np.where(case_array == 3)
find_4 = np.where(case_array == 4)
find_5 = np.where(case_array == 5)
find_6 = np.where(case_array == 6)
find_7 = np.where(case_array == 7)
find_8 = np.where(case_array == 8)
find_9 = np.where(case_array == 9)
find_10 = np.where(case_array == 10)
find_11 = np.where(case_array == 11)

box1 = np.column_stack((accuracy_rate[find_1], accuracy_rate[find_2], accuracy_rate[find_3], accuracy_rate[find_4], accuracy_rate[find_5], accuracy_rate[find_6], accuracy_rate[find_7], accuracy_rate[find_8], accuracy_rate[find_9],accuracy_rate[find_10],accuracy_rate[find_11]))
box2 = np.column_stack((miss_rate[find_1], miss_rate[find_2], miss_rate[find_3], miss_rate[find_4], miss_rate[find_5], miss_rate[find_6], miss_rate[find_7], miss_rate[find_8], miss_rate[find_9], miss_rate[find_10], miss_rate[find_11]))

labelList =['All', 'All-A','All-HD', 'All-AG', 'All-HT','All-M', 'All-W', 'All-SS', 'All-G', 'All-BMI', 'All-RT']

fig, ax = plt.subplots(1, figsize=(9, 5))
bp1 = ax.boxplot(box1, positions=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], widths=0.2)
print(bp1.keys())
plt.setp(bp1['boxes'], color='red')
plt.setp(bp1['fliers'], color='red')
plt.setp(bp1['caps'], color='red')
plt.setp(bp1['medians'], color='red')
plt.setp(bp1['whiskers'], color='red')

ax2 = ax.twinx()
bp2 = ax2.boxplot(box2, positions=[1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3, 8.3, 9.3, 10.3, 11.3], widths=0.2)
plt.setp(bp2['boxes'], color='blue')
plt.setp(bp2['fliers'], color='blue')
plt.setp(bp2['caps'], color='blue')
plt.setp(bp2['medians'], color='blue')
plt.setp(bp2['whiskers'], color='blue')

ax.set_xticklabels(labelList)
ax.set_xticks([1.15, 2.15, 3.15, 4.15, 5.15, 6.15, 7.15, 8.15, 9.15, 10.15, 11.15])

ax.set_ylabel('Accuracy rate', fontsize=13, color='r')
ax.set_xlabel('Features combination', fontsize=14)
ax2.set_ylabel('Miss rate', fontsize=13, color='b')

ax.grid(True)
plt.savefig('./results/feature-removal.pdf', format='pdf')
plt.show()


import glob
import re
import json
import yaml
import pandas as pd

def process_keel_results(root: str):
    result_files = glob.glob(f'{root}/*/results/*/metrics.csv')
    pattern = re.compile('\./Keel1/(?P<data_name>.*?)/results/(?P<experiment_name>.*?)/metrics\.csv')
    records = []
    result_df = None
    for path in result_files:
        m = re.match(pattern, path)
        assert m is not None, f"No matching result in {path}"
        data_name = m.group('data_name')
        exper_name = m.group('experiment_name')
        print(data_name, " ", exper_name)
        df = pd.read_csv(path)
        index = pd.MultiIndex.from_tuples([(data_name, exper_name)], names=["dataset", "experiment"])
        df1 = pd.DataFrame(df.to_numpy(), index=index, columns=df.columns)
        if result_df is None:
            result_df = df1
        else:
            result_df = pd.concat([result_df, df1])
    return result_df
    #     with open(path) as f:
    #         res = json.load(f)
    #         records.append((data_name, exper_name, res['average_precision']))
    #
    # df = pd.DataFrame.from_records(records, columns=['dataset', 'experiment', 'ap'])
    # df = df.pivot(index='dataset', columns='experiment', values='ap')
    # ir = get_ir_in_configs(root)
    # df["ir"] = pd.Series(ir)
    # return df

def get_ir_in_configs(root: str):
    files = glob.glob(f'{root}/*/config.yml')
    pattern = re.compile('\./Keel1/(?P<data_name>.*?)/config\.yml')
    d = dict()
    for file in files:
        m = re.match(pattern, file)
        data_name = m.group('data_name')
        with open(file) as f:
            config = yaml.load(f, Loader=yaml.FullLoader)
        d[data_name] = config['ir']
    return d

if __name__ == "__main__":
    root = './Keel1'
    df = process_keel_results(root)
    # df.to_csv('./results_last.csv')


#LOAD
def ilangin_enter(data):
    for i in range(len(data)):
        data[i] = data[i].replace("\n", "")
    return data

def pisah(baris, pemisah):
    baris_baru =[""]
    j = 0
    for i in range(len(baris)):
        if baris[i] == pemisah:
            baris_baru.append("")
            j = j+1
        else :
            baris_baru[j] = baris_baru[j] + baris[i]
    return baris_baru

def ubah_string_ke_data(baris, pemisah):
    baris_baru1 = pisah(baris, pemisah)
    baris_baru2 = [data.strip() for data in baris_baru1]
    return baris_baru2

def ubah_tipe(datamentah, indeks_integer):
    data_baru = datamentah[:]
    for i in range(7):
        if i in indeks_integer and not (data_baru[i]==""):
            data_baru[i] = int(data_baru[i])
    return data_baru

def gabung_baris(datamentah):
    data = []
    for i in range(len(datamentah)):
        data.append(datamentah[i])
    return data

def load(file, pemisah, indeks_integer):
    f = open(file, "r")
    lines_mentah = f.readlines()
    f.close()
    lines = ilangin_enter(lines_mentah)
    header1 = lines.pop(0)
    header = ubah_string_ke_data(header1, pemisah)
    for i in range(len(lines)):
        lines[i] = ubah_string_ke_data(lines[i], pemisah)
        lines[i] = ubah_tipe(lines[i], indeks_integer)
    data = gabung_baris(lines)
    return (header, data)


from django.http.response import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse, reverse_lazy
from django.views.generic import View, CreateView, DetailView
from datetime import datetime
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

from django.views.generic.edit import UpdateView, DeleteView
from .calendar import Calendar
from .models import Diary
from .forms import DiaryCreationForm, DiaryUpdateForm

# Create your views here.
@method_decorator(login_required, 'get')
class HomeView(View):
    def get(self, request):
        now = datetime.now()
        cal = Calendar(now.year, now.month, request.user)
        html_cal = cal.formatmonth(withyear=True)
        return render(request, 'diaryapp/home.html', {'calendar':html_cal})

class DiaryCreate(View):
    def get(self, request, year, month, day):
        c_year, c_month, c_day = year, month, day
        return render(request, 'diaryapp/create.html', {'year':c_year, 'month':c_month, 'day':c_day})

class DiaryCreateCommon(CreateView):
    model = Diary
    context_object_name = 'target_diary'
    template_name = 'diaryapp/create_common.html'
    form_class = DiaryCreationForm

    def form_valid(self, form):
        temp_diary = form.save(commit=False)
        temp_diary.user = self.request.user
        temp_diary.date = datetime.strptime(f"{self.kwargs['year']}-{self.kwargs['month']}-{self.kwargs['day']}", "%Y-%m-%d")
        temp_diary.save()
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        value = super(DiaryCreateCommon, self).get_context_data(**kwargs)
        value['year'] = self.kwargs['year']
        value['month'] = self.kwargs['month']
        value['day'] = self.kwargs['day']
        return value

    def get_success_url(self):
        return reverse('diaryapp:read', kwargs={'pk':self.object.pk})

class DiarySelectFeeling(View):
    def get(self, request, year, month, day):
        c_year, c_month, c_day = year, month, day
        return render(request, 'diaryapp/select_feeling.html', {'year':c_year, 'month': c_month, 'day':c_day})

    def post(self, request, year, month, day):
        print('post까지 들어옴')
        if 'joy' in self.request.POST:
            print('joy')
            temp_diary = Diary(user=self.request.user)
            temp_diary.title = f'{month}월 {day}일 일기'
            temp_diary.date = datetime.strptime(f"{year}-{month}-{day}", "%Y-%m-%d")
            temp_diary.feeling = 'joy'
            temp_diary.save()
        elif 'sad' in self.request.POST:
            print('sad')
            temp_diary = Diary(user=self.request.user)
            temp_diary.title = f'{month}월 {day}일 일기'
            temp_diary.date = datetime.strptime(f"{year}-{month}-{day}", "%Y-%m-%d")
            temp_diary.feeling = 'sad'
            temp_diary.save()
        elif 'angry' in self.request.POST:
            print('angry')
            temp_diary = Diary(user=self.request.user)
            temp_diary.title = f'{month}월 {day}일 일기'
            temp_diary.date = datetime.strptime(f"{year}-{month}-{day}", "%Y-%m-%d")
            temp_diary.feeling = 'angry'
            temp_diary.save()
        else:
            print('fear')
            temp_diary = Diary(user=self.request.user)
            temp_diary.title = f'{month}월 {day}일 일기'
            temp_diary.date = datetime.strptime(f"{year}-{month}-{day}", "%Y-%m-%d")
            temp_diary.feeling = 'fear'
            temp_diary.save()
        print('리턴 바로앞!')
        return HttpResponseRedirect(reverse('diaryapp:select_who', kwargs={'pk':temp_diary.pk}))

class DiarySelectWho(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_who.html', {'pk':pk})

    def post(self, request, pk):
        target_diary = Diary.objects.get(pk=pk)
        if target_diary.content:
            if 'me' in self.request.POST:
                target_diary.content += '
내가'
                target_diary.save()
            elif 'friend' in self.request.POST:
                target_diary.content += '
친구가'
                target_diary.save()
            elif 'father' in self.request.POST:
                target_diary.content += '
아빠가'
                target_diary.save()
            elif 'mother' in self.request.POST:
                target_diary.content += '
엄마가'
                target_diary.save()
            elif 'girlfriend' in self.request.POST:
                target_diary.content += '
여친이'
                target_diary.save()
            elif 'boyfriend' in self.request.POST:
                target_diary.content += '
남친이'
                target_diary.save()
            elif 'etc' in self.request.POST:
                target_diary.content += '
' + self.request.POST['self_input']
                target_diary.save()
        else:
            if 'me' in self.request.POST:
                target_diary.content = '내가'
                target_diary.save()
            elif 'friend' in self.request.POST:
                target_diary.content = '친구가'
                target_diary.save()
            elif 'father' in self.request.POST:
                target_diary.content = '아빠가'
                target_diary.save()
            elif 'mother' in self.request.POST:
                target_diary.content = '엄마가'
                target_diary.save()
            elif 'girlfriend' in self.request.POST:
                target_diary.content = '여친이'
                target_diary.save()
            elif 'boyfriend' in self.request.POST:
                target_diary.content = '남친이'
                target_diary.save()
            elif 'etc' in self.request.POST:
                target_diary.content = self.request.POST['self_input']
                target_diary.save()
        return HttpResponseRedirect(reverse('diaryapp:select_when', kwargs={'pk':pk}))

class DiarySelectWhen(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_when.html', {'pk':pk})

    def post(self, request, pk):
        target_diary = Diary.objects.get(pk=pk)
        if 'before_noon' in self.request.POST:
            target_diary.content += ' 오전에'
            target_diary.save()
        elif 'after_noon' in self.request.POST:
            target_diary.content += ' 오후에'
            target_diary.save()
        elif 'morning' in self.request.POST:
            target_diary.content += ' 아침에'
            target_diary.save()
        elif 'noon' in self.request.POST:
            target_diary.content += ' 점심에'
            target_diary.save()
        elif 'evening' in self.request.POST:
            target_diary.content += ' 저녁에'
            target_diary.save()
        elif 'night' in self.request.POST:
            target_diary.content += ' 밤에'
            target_diary.save()
        elif 'etc' in self.request.POST:
            target_diary.content += ' ' + self.request.POST['self_input']
            target_diary.save()
        return HttpResponseRedirect(reverse('diaryapp:select_where', kwargs={'pk':pk}))

class DiarySelectWhere(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_where.html', {'pk':pk})

    def post(self, request, pk):
        target_diary = Diary.objects.get(pk=pk)
        if 'home' in self.request.POST:
            target_diary.content += ' 집에서'
            target_diary.save()
        elif 'school' in self.request.POST:
            target_diary.content += ' 학교에서'
            target_diary.save()
        elif 'company' in self.request.POST:
            target_diary.content += ' 직장에서'
            target_diary.save()
        elif 'park' in self.request.POST:
            target_diary.content += ' 공원에서'
            target_diary.save()
        elif 'restaurant' in self.request.POST:
            target_diary.content += ' 식당에서'
            target_diary.save()
        elif 'cafe' in self.request.POST:
            target_diary.content += ' 카페에서'
            target_diary.save()
        elif 'etc' in self.request.POST:
            target_diary.content += ' ' + self.request.POST['self_input']
            target_diary.save()
        return HttpResponseRedirect(reverse('diaryapp:select_what', kwargs={'pk':pk}))

class DiarySelectWhat(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_what.html', {'pk':pk})

    def post(self, request, pk):
        target_diary = Diary.objects.get(pk=pk)
        target_diary.content += ' ' + self.request.POST['self_input']
        target_diary.save()
        return HttpResponseRedirect(reverse('diaryapp:select_how', kwargs={'pk':pk}))

class DiarySelectHow(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_how.html', {'pk':pk})

    def post(self, request, pk):
        target_diary = Diary.objects.get(pk=pk)
        target_diary.content += ' ' + self.request.POST['self_input']
        target_diary.save()
        return HttpResponseRedirect(reverse('diaryapp:select_why', kwargs={'pk':pk}))

class DiarySelectWhy(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_why.html', {'pk':pk})

    def post(self, request, pk):
        target_diary = Diary.objects.get(pk=pk)
        target_diary.content += ' ' + self.request.POST['self_input']
        target_diary.save()
        return HttpResponseRedirect(reverse('diaryapp:select_continue', kwargs={'pk':pk}))

class DiarySelectContinue(View):
    def get(self, request, pk):
        return render(request, 'diaryapp/select_continue.html', {'pk':pk})

class DiaryRead(DetailView):
    model = Diary
    context_object_name = 'target_diary'
    template_name = 'diaryapp/detail.html'

class DiaryUpdateView(UpdateView):
    model = Diary
    context_object_name = 'target_diary'
    form_class = DiaryUpdateForm
    template_name = 'diaryapp/update.html'

    def get_success_url(self):
        return reverse('diaryapp:read', kwargs={'pk': self.object.pk})

class DiaryDeleteView(DeleteView):
    model = Diary
    success_url = reverse_lazy('diaryapp:home')
    template_name = 'diaryapp/delete.html'
    context_object_name = 'target_diary'


# import sys
class readdb():

    def __init__(self, textfile):
        self.textfile=textfile

    def readdb(self):
        with  open(self.textfile) as _text:
            lines=_text.readlines()
        _string=''.join(lines)
        lines=[]
        for lin in _string.split("\n"):
            lines.append(lin.split(" "))
        return lines

# if __name__=='__main__':
#         read = readdb("/home/saurabh/Desktop/MIRAGE_version1/sample_data/input_new.txt")
#         read.readdb()


# -*- coding: UTF-8 -*-
"""
title：买卖股票的最佳时机 IV
You are given an integer array prices where prices[i] is the price of a given stock on the ith day, and an integer k.
Find the maximum profit you can achieve. You may complete at most k transactions.
Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).

Example 1:
Input: k = 2, prices = [2,4,1]
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.

Example 2:
Input: k = 2, prices = [3,2,6,5,0,3]
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4. Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.

Constraints:
0 <= k <= 100
0 <= prices.length <= 1000
0 <= prices[i] <= 1000
"""
from typing import List

class Solution:
    """
    有效的交易由买入和卖出构成，至少需要两天；反之，当天买入当天卖出则视为一次无效交易。若给定的最大交易次数 k <= n/2，
    则这个 k 可以有效约束交易次数；若给定的 k > n/2 ，则这个 k 实际上起不到约束作用，此时的k等价于正无穷，问题退化为不限交易次数。
    动态规划。
    """

    def maxProfit(self, k: int, prices: List[int]) -> int:
        def maxProfit_k_inf(prices):
            res = 0
            for i in range(1, n):
                if prices[i] > prices[i - 1]:
                    res += prices[i] - prices[i - 1]
            return res

        def maxProfit_k_others(prices, k):
            dp = [[[0, 0] for _ in range(k + 1)] for _ in range(n)]
            for i in range(n):
                for j in range(1, k + 1):
                    if i == 0:
                        # 0 - 第i天执行第j笔交易(买入)的最大利润；1 - 第i天执行第j笔交易(卖出)的最大利润
                        dp[i][j][0] = -prices[i]
                    else:
                        dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j - 1][1] - prices[i])
                        dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j][0] + prices[i])
            # return dp[n - 1][k][1]
            return dp[-1][-1][1]

        n = len(prices)
        if n < 2 or k < 1:
            return 0
        # k > n // 2 时，其实可将k看作是n // 2，然后代入maxProfit_k_others。不过使用maxProfit_k_inf计算，时空复杂度都可以更低
        if k > n // 2:
            # 不限制交易次数
            return maxProfit_k_inf(prices)
        else:
            return maxProfit_k_others(prices, k)

if __name__ == '__main__':
    print(Solution().maxProfit(k = 2, prices = [3,2,6,5,0,3]))


# Used cars kicks classification - Sensitivity analysis
# Data source:
# https://www.openml.org/search?type=data&sort=runs&id=41162&status=active
# https://www.kaggle.com/competitions/DontGetKicked/overview

# Source previous script
exec(open("./Scripts/04_Preprocessing.py").read())

import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.utils.class_weight import compute_class_weight
from sklearn.dummy import DummyClassifier
from sklearn.linear_model import SGDClassifier
from sklearn.kernel_approximation import RBFSampler
from sklearn.calibration import CalibratedClassifierCV
from xgboost import XGBClassifier

import torch, torchvision
import lightning.pytorch as pl
from XX_LightningClasses import TrainDataset, TestDataset, SeluDropoutModel

from itertools import product

# Set plotting options
plt.rcParams['figure.dpi'] = 300
plt.rcParams['savefig.dpi'] = 300
plt.rcParams["figure.autolayout"] = True
sns.set_style("darkgrid")

# Set Torch settings
torch.set_default_dtype(torch.float32)
torch.set_float32_matmul_precision('high')
pl.seed_everything(1923, workers = True)

# Compute class weight
classes = list(set(y_train))
class_weight = compute_class_weight("balanced", classes = classes, y = y_train)
sample_weight = np.where(y_train == 1, class_weight[1], class_weight[0])

# Create dummy classifier which predicts the prior class probabilities
model_dummy = DummyClassifier(strategy = "prior")

# Train & predict with dummy classifier
model_dummy.fit(x_train, y_train)
preds_dummy = model_dummy.predict_proba(x_test)
preds_dummy = [x[1] for x in preds_dummy]

# Create logistic regression pipeline with optimal hyperparameters
best_trial_logistic = pd.read_csv("./ModifiedData/trials_logistic.csv").iloc[0,]
pipe_logistic = Pipeline(steps = [
  ("preprocessing", pipe_process),
  ("Logistic", SGDClassifier(
      loss = "log_loss",
      penalty = "elasticnet",
      alpha = best_trial_logistic["params_reg_strength"],
      l1_ratio = best_trial_logistic["params_l1_ratio"],
      max_iter = 26,
      n_iter_no_change = 1000, # Ensure model doesn't early stop based on train loss
      verbose = 1,
      random_state = 1923
    )
  )
])

# Train & predict with logistic regression
pipe_logistic.fit(x_train, y_train, Logistic__sample_weight = sample_weight)
preds_logistic = pipe_logistic.predict_proba(x_test)
preds_logistic = [x[1] for x in preds_logistic]

# Create SVM pipeline with optimal hyperparameters
best_trial_svm = pd.read_csv("./ModifiedData/trials_svm.csv").iloc[0,]
pipe_svm = Pipeline(steps = [
  ("preprocessing", pipe_process),
  ("KernelTrick", RBFSampler(
      gamma = "scale",
      n_components = 100,
      random_state = 1923
    )
  ),
  ("SVM", CalibratedClassifierCV(
    estimator = SGDClassifier(
      loss = "hinge",
      penalty = "elasticnet",
      alpha = best_trial_svm["params_reg_strength"],
      l1_ratio = best_trial_svm["params_l1_ratio"],
      max_iter = 13,
      n_iter_no_change = 1000, # Ensure model doesn't early stop based on train loss
      verbose = 1,
      random_state = 1923
      ),
    method = "isotonic"
    )
  )
])

# Train & predict with SVM
pipe_svm.fit(x_train, y_train, SVM__sample_weight = sample_weight)
preds_svm = pipe_svm.predict_proba(x_test)
preds_svm = [x[1] for x in preds_svm]

# Create XGBoost pipeline with optimal hyperparameters
best_trial_xgb = pd.read_csv("./ModifiedData/trials_xgb.csv").iloc[0,]
pipe_xgb = Pipeline(steps = [
  ("preprocessing", pipe_process),
  ("XGBoost", XGBClassifier(
      objective = "binary:logistic",
      n_estimators = 20,
      eval_metric = "logloss",
      tree_method = "gpu_hist",
      gpu_id = 0,
      verbosity = 1,
      random_state = 1923,
      learning_rate = best_trial_xgb["params_learning_rate"],
      max_depth = best_trial_xgb["params_max_depth"],
      min_child_weight = best_trial_xgb["params_min_child_weight"],
      gamma = best_trial_xgb["params_gamma"],
      reg_alpha = best_trial_xgb["params_l1_reg"],
      reg_lambda = best_trial_xgb["params_l2_reg"],
      subsample = best_trial_xgb["params_subsample"],
      colsample_bytree = best_trial_xgb["params_colsample_bytree"]
    )
  )
])

# Train & predict with XGBoost
pipe_xgb.fit(x_train, y_train, XGBoost__sample_weight = sample_weight)
preds_xgb = pipe_xgb.predict_proba(x_test)
preds_xgb = [x[1] for x in preds_xgb]

# Define & train NN model with best parameters
best_trial_nn = pd.read_csv("./ModifiedData/trials_nn.csv").iloc[0,]
hyperparams_dict = {
      "input_size": 90,
      "n_hidden_layers": best_trial_nn["params_n_hidden_layers"],
      "hidden_size": 2 ** best_trial_nn["params_hidden_size"],
      "learning_rate": best_trial_nn["params_learning_rate"],
      "l2": best_trial_nn["params_l2"],
      "dropout": best_trial_nn["params_dropout"],
      "loss_alpha": best_trial_nn["params_loss_alpha"],
      "loss_gamma": best_trial_nn["params_loss_gamma"]
    }
model_nn = SeluDropoutModel(hyperparams_dict)

# Apply scikit preprocessing pipeline
x_tr = pipe_process.fit_transform(x_train, y_train)
x_test1 = pipe_process.transform(x_test)

# Create train & test Datasets, dataloaders
train_data = TrainDataset(x_tr, y_train)
test_data = TestDataset(x_test1)

train_loader = torch.utils.data.DataLoader(
  train_data, batch_size = 1024, num_workers = 0, shuffle = True)
test_loader = torch.utils.data.DataLoader(
  test_data, batch_size = len(test_data), num_workers = 0, shuffle = False)

# Create trainer
trainer = pl.Trainer(
      max_epochs = 9, # Best epoch from ModelingNN
      log_every_n_steps = 5, # The default is 50, but there are less training batches
      # than 50
      accelerator = "gpu", devices = "auto", precision = "16-mixed",
      logger = True,
      enable_progress_bar = True,
      enable_checkpointing = False
    )

# Train NN model
trainer.fit(model_nn, train_loader)

# Predict with NN model
y_prob = trainer.predict(model_nn, test_loader)

# Convert list of float16 Torch tensors to single float32 np.array
preds_nn = np.float32(y_prob[0].numpy().reshape(1, -1)[0])

# Retrieve prob. predictions, target labels, purchase prices in dataframes, sort in
# descending order according to prob. predictions
df_dummy = pd.DataFrame({
  "Price": x_test["VehBCost"],
  "Kick": y_test,
  "ProbKick": preds_dummy
})
df_dummy = df_dummy.sort_values("ProbKick", ascending = True)

df_logistic = pd.DataFrame({
  "Price": x_test["VehBCost"],
  "Kick": y_test,
  "ProbKick": preds_logistic
})
df_logistic = df_logistic.sort_values("ProbKick", ascending = True)

df_svm = pd.DataFrame({
  "Price": x_test["VehBCost"],
  "Kick": y_test,
  "ProbKick": preds_svm
})
df_svm = df_svm.sort_values("ProbKick", ascending = True)

df_xgb = pd.DataFrame({
  "Price": x_test["VehBCost"],
  "Kick": y_test,
  "ProbKick": preds_xgb
})
df_xgb = df_xgb.sort_values("ProbKick", ascending = True)

df_nn = pd.DataFrame({
  "Price": x_test["VehBCost"],
  "Kick": y_test,
  "ProbKick": preds_nn
})
df_nn = df_nn.sort_values("ProbKick", ascending = True)

# Define function to calculate profit-loss at given threshold prob. and number of
# cars to purchase
def calc_profit(threshold, num_purchases, df_probs):

  # Retrieve arrays of prices, labels, predicted probs
  price = df_probs["Price"].values
  kick = df_probs["Kick"].values
  prob = df_probs["ProbKick"].values

  # Retrieve n. of cars to purchase (if available at threshold)
  n = num_purchases

  # Get vector of purchase decision for the top N cars at threshold prob.
  decision = (prob[0:n] < threshold).astype(int)

  # Calculate profit/loss for each car, purchased or not
  profit = [((0.1 * price[i]) - (0.9 * price[i] * kick[i])) * decision[i] for i in range(n)]

  # Return n. of cars actually purchased, total profit / loss
  return sum(decision), sum(profit)

# Get combinations of thresholds - n. of cars to purchase
thresholds = np.arange(0, 1, 0.01)
num_buys = np.arange(0, len(y_test), 100)
thresholds_buys = list(product(thresholds, num_buys))

# Calculate n. of cars actually bought and profit at each threshold / buy combination
output_dummy = [calc_profit(x, y, df_dummy) for x, y in thresholds_buys]
decisions_dummy = [x[0] for x in output_dummy]
profits_dummy= [x[1] for x in output_dummy]

output_logistic = [calc_profit(x, y, df_logistic) for x, y in thresholds_buys]
decisions_logistic = [x[0] for x in output_logistic]
profits_logistic = [x[1] for x in output_logistic]

output_svm = [calc_profit(x, y, df_svm) for x, y in thresholds_buys]
decisions_svm = [x[0] for x in output_svm]
profits_svm = [x[1] for x in output_svm]

output_xgb = [calc_profit(x, y, df_xgb) for x, y in thresholds_buys]
decisions_xgb = [x[0] for x in output_xgb]
profits_xgb = [x[1] for x in output_xgb]

output_nn = [calc_profit(x, y, df_nn) for x, y in thresholds_buys]
decisions_nn = [x[0] for x in output_nn]
profits_nn = [x[1] for x in output_nn]

# Make long dataframes of threshold-purchase-profit values
df_long_dummy = pd.DataFrame({
  "Threshold": [x[0] for x in thresholds_buys],
  "Purchases": decisions_dummy,
  "Profits": profits_dummy,
  "Model": "Dummy"
})

df_long_logistic = pd.DataFrame({
  "Threshold": [x[0] for x in thresholds_buys],
  "Purchases": decisions_logistic,
  "Profits": profits_logistic,
  "Model": "Logistic"
})

df_long_svm = pd.DataFrame({
  "Threshold": [x[0] for x in thresholds_buys],
  "Purchases": decisions_svm,
  "Profits": profits_svm,
  "Model": "SVM"
})

df_long_xgb = pd.DataFrame({
  "Threshold": [x[0] for x in thresholds_buys],
  "Purchases": decisions_xgb,
  "Profits": profits_xgb,
  "Model": "XGBoost"
})

df_long_nn = pd.DataFrame({
  "Threshold": [x[0] for x in thresholds_buys],
  "Purchases": decisions_nn,
  "Profits": profits_nn,
  "Model": "Neural net"
})

# Combine long dataframes into one
df_long = pd.concat([df_long_dummy, df_long_logistic, df_long_svm, df_long_xgb, df_long_nn])

# Drop rows with duplicates of purchase-profit-model columns (cases where a
# probability t results in buying n number of cars, and a higher t doesn't result
# in more cars bought or a different profit value)
df_long = df_long.drop_duplicates(["Purchases", "Profits", "Model"])

# 2D lineplots of thresholds-purchases-profits
fig, ax = plt.subplots(3)
_ = fig.suptitle("Relationships between classifier threshold probability, number of cars purchased and profit")

_ = sns.lineplot(
  ax = ax[0],
  data = df_long, x = "Threshold", y = "Profits", hue = "Model")
_ = ax[0].set_xlabel("Threshold probability")
_ = ax[0].set_ylabel("Profits, $mil")

_ = sns.lineplot(
  ax = ax[1],
  data = df_long, x = "Threshold", y = "Purchases", hue = "Model", legend = False)
_ = ax[1].set_xlabel("Threshold probability (lowest value that results in N. cars purchased)")
_ = ax[1].set_ylabel("N. cars purchased")

_ = sns.lineplot(
  ax = ax[2],
  data = df_long, x = "Purchases", y = "Profits", hue = "Model", legend = False)
_ = ax[2].set_xlabel("N. cars purchased")
_ = ax[2].set_ylabel("Profits, $mil")

plt.show()
plt.savefig("./Plots/sensitivity.png", dpi = 300)
plt.close("all")

# Quasi-optimal combinations of threshold prob - n. purchases
optimal_dummy = df_long_dummy.loc[np.argmax(df_long_dummy["Profits"])]
optimal_logistic = df_long_logistic.loc[np.argmax(df_long_logistic["Profits"])]
optimal_svm = df_long_svm.loc[np.argmax(df_long_svm["Profits"])]
optimal_xgb = df_long_xgb.loc[np.argmax(df_long_xgb["Profits"])]
optimal_nn =df_long_nn.loc[np.argmax(df_long_nn["Profits"])]

df_optimal = pd.concat([
  optimal_dummy, optimal_logistic, optimal_svm, optimal_xgb, optimal_nn],
  axis = 1).transpose()

df_optimal["Profits"] = df_optimal["Profits"] / 1e6

df_optimal = df_optimal.rename({
  "Threshold": "Threshold prob.",
  "Purchases": "N. cars purchased",
  "Profits": "Profits, $mil"
}, axis = 1)

df_optimal


#!/usr/bin/env/python
#Merges all fastq_files from all samples into one file.

import re
import os
import glob
import shutil
def merge_files(dest_dir, fastq_files):
    #sample_pattern=re.compile("^(.+)_S[0-9]+_.+_R([1-2])_")
    #Below is used for BCBP above for Irma style projects.
    sample_pattern=re.compile("^[0-9]_[0-9]+_[A-Z0-9]+_(P[0-9]+_[0-9]+)_([1-2])")
    while fastq_files:
        tomerge=[]
        first=fastq_files[0]
        fq_bn=os.path.basename(first)
        sample_name=sample_pattern.match(fq_bn).group(1)
        read_nb=sample_pattern.match(fq_bn).group(2)
        for fq in fastq_files:
            if sample_name in os.path.basename(fq) and "_{}.".format(read_nb) in os.path.basename(fq):
                tomerge.append(fq)
        for fq in tomerge:
            fastq_files.remove(fq)

        outfile=os.path.join(dest_dir, "{}_R{}.fastq.gz".format(sample_name, read_nb))
        with open(outfile, 'wb') as wfp:
            for fn in tomerge:
                with open(fn, 'rb') as rfp:
                    shutil.copyfileobj(rfp, wfp)

def main():
    destination_dir = str(raw_input("Destiantion dir:"))
    #all fastq.gz files in CWD
    fastq_files=glob.glob('*.fastq.gz')
    merge_files(destination_dir,fastq_files)

if __name__ == "__main__":
    main()


import random as rd

class Empresa:
    _instance = None

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        self.camiones = []
        self.conductores = []
        self.asistentes = []
        self.turnosDelDia = []
        self.turnosTotales = 0

    def __iter__(self):
        return IteradorTurnos(self.turnosDelDia)

    # Función que agrega un camión
    def agregarCamion(self):
        if len(self.conductores) < 1:
            print("XXXX Error: Se requiere al menos 1 conductor registrado XXXX")
            return

        if len(self.asistentes) < 2:
            print("XXXX Error: Se requieren al menos 2 asistentes registrados XXXX")
            return

        print("----- Conductores disponibles -----")
        # Elegir un conductor
        conductoresDisponibles = []
        for i, conductor in enumerate(self.conductores):
            if not conductor.ocupado:
                conductoresDisponibles.append(conductor)
                print(f"{i}. {conductor}")
        conductor = None
        while conductor is None:
            indice = input("Seleccione el número de conductor que desea asignar: ")
            try:
                indice = int(indice)
                if 0 <= indice < len(conductoresDisponibles):
                    conductor = conductoresDisponibles[indice]
                    break
                else:
                    print("Error: Seleccione un número válido de conductor disponible.")
            except ValueError:
                print("Error: Ingrese un número válido.")

        # Cambiar a no disponible
        for i in self.conductores:
            if i.ident == conductor.ident:
                i.ocupado = True

        print("----- Asistentes disponibles -----")
        asistentes_disponibles = []
        for i, asistente in enumerate(self.asistentes):
            if not asistente.ocupado:
                asistentes_disponibles.append(asistente)
                print(f"{i}. {asistente}")

        # Solicitar al usuario que elija dos asistentes
        seleccionados_asistentes = []
        while len(seleccionados_asistentes) < 2:
            indice = input(f"Seleccione el número de asistente {len(seleccionados_asistentes) + 1}: ")
            try:
                indice = int(indice)
                if 0 <= indice < len(asistentes_disponibles):
                    seleccionado_asistente = asistentes_disponibles[indice]
                    seleccionados_asistentes.append(seleccionado_asistente)
                    asistentes_disponibles.pop(indice)
                    print(f"Asistente {len(seleccionados_asistentes)} seleccionado: {seleccionado_asistente}")
                else:
                    print("Error: Seleccione un número válido de asistente disponible.")
            except ValueError:
                print("Error: Ingrese un número válido.")

        asistente1, asistente2 = seleccionados_asistentes
        # Cambiar a no disponible
        for i in self.asistentes:
            if i.ident == asistente1.ident or i.ident == asistente2.ident:
                i.ocupado = True

        id = int(input("Ingrese el código del camión: "))

        # Validar si el camión ya existe en la lista de camiones
        for camion in self.camiones:
            if camion.id == id:
                print("XXXXX Error: El camión ya existe en la empresa XXXXX")
                return
        # Añadirlo a la lista de camiones
        self.camiones.append(Camion(conductor, asistente1, asistente2, id))
        print("----- Camión agregado correctamente -----")

    def agregarConductor(self):
        nombre = input("Ingrese el nombre del conductor: ")
        ident = None

        while not ident:
            try:
                ident = int(input("Ingrese la identificación del conductor: "))
            except ValueError or TypeError:
                print("Error: El identificador debe ser un número entero. Intente nuevamente.")

        # Validar si el conductor ya existe en la lista de conductores
        for conductor in self.conductores:
            if conductor.ident == ident and conductor.id == ident:
                print("XXXXX Error: El conductor ya existe en la empresa XXXXX")
                return

        # Añadirlo a la lista de conductores
        self.conductores.append(Conductor(nombre, ident))
        print("------- Conductor agregado correctamente -------")

    def agregarAsistente(self):
        nombre = input("Ingrese el nombre del asistente: ")
        ident = None
        while not ident:
            try:
                ident = int(input("Ingrese la identificación del asistente: "))
            except ValueError or TypeError:
                print("Error: El identificador debe ser un número entero. Intente nuevamente.")

        # Validar si el asistente ya existe en la lista de conductores
        for asistente in self.asistentes:
            if asistente.ident == ident:
                print("XXXXX Error: El asistente ya existe en la empresa XXXXX")
                return

        # Añadirlo a la lista de asistentes
        self.asistentes.append(Asistente(nombre, ident))
        print("------- Asistente agregado correctamente -------")

    def registrarTurno(self):
        if len(self.camiones) < 1:
            print("XXXX Error: Se requiere al menos 1 camion registrado XXXX")
            return
        elif(self.turnosTotales == len(self.camiones)):
            print("XXXX Error: No hay camiones disponibles para más turnos XXXX")
            return

        print("----- Camiones disponibles -----")
        # Elegir un camion
        camionesDisponibles = []
        for i, camion in enumerate(self.camiones):
            if not camion.ocupado:
                camionesDisponibles.append(camion)
                print(f"{i}. Camión ID: {camion.id}")
        camion = None
        while camion is None:
            indice = input("Seleccione el número de camion que desea asignar: ")
            try:
                indice = int(indice)
                if 0 <= indice < len(camionesDisponibles):
                    camion = camionesDisponibles[indice]
                    break
                else:
                    print("Error: Seleccione un número válido de camion disponible.")
            except ValueError or TypeError:
                print("Error: Ingrese un número válido.")

        # Cambiar a no disponible
        for i in self.camiones:
            if i.id == camion.id:
                i.ocupado = True
        turno = Turno(camion)
        turno.clasificar()
        turno.mostrarResumen()
        respuesta = input("¿Estás seguro de que deseas ingresar el turno? (S/N): ")
        if respuesta.upper() == "S":
            self.turnosDelDia.append(turno)
            self.turnosTotales += 1
            print("------- Turno ingresado correctamente -------")
        else:
            print("----- Turno no registrado -----")

    def calcularVidrio(self) -> float:
        totalVidrio = 0
        iterador = iter(self.turnosDelDia)
        while True:
            try:
                turno = next(iterador)
                totalVidrio += turno.clasificacion["vidrio"]
            except StopIteration:
                break
        return totalVidrio

    def finalizarDia(self):
        print("----- Finalizar día -----")
        respuesta = input("¿Estás seguro de que deseas finalizar el día? (S/N): ")
        if respuesta.upper() == "S":
            # Calcular vidrio total recogido
            totalVidrio = self.calcularVidrio()
            print("----- Vidrio total recogio en el día en el centro de acopio -----")
            print(f"Vidrio total: {totalVidrio}")
            print("-----------------------------------------------------------------")
            print("------------------------- DÍA FINALIZADO ------------------------")
        else:
            print("...Continuando el día...")

class IteradorTurnos:
    def __init__(self, turnos):
        self.turnos = turnos
        self.indice_actual = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.indice_actual < len(self.turnos):
            turno = self.turnos[self.indice_actual]
            self.indice_actual += 1
            return turno
        raise StopIteration()

class PuntoGeografico:
    def __init__(self, latitud: int, longitud: int):
        self.latitud = latitud
        self.longitud = longitud

class Camion:
    def __init__(self, conductor, asistente1, asistente2, id: int):
        self.conductor = conductor
        self.asistentes = [asistente1, asistente2]
        self.id = id
        self.ocupado = False

    def __repr__(self):
        return f"Camión ID: {self.id}\nConductor: {self.conductor}\nAsistentes: {self.asistentes}"

# La clase Persona almacena informacion de la persona (nombre e identificacíón)
class Persona:
    def __init__(self, nombre: str, ident: int):
        self.nombre = nombre
        self.ident = ident

# La clase Conductor hereda de persona nombre e ident(indentificación) y almacena su cargo
class Conductor(Persona):
    def __init__(self, nombre: str, ident: int):
        super().__init__(nombre, ident)
        self.cargo = "Conductor"
        self.ocupado = False

    def __repr__(self):
        estado = "disponible" if not self.ocupado else "no disponible"
        return f"{self.nombre} ({self.ident}), Estado: {estado}"

# La clase Asistente hereda de persona nombre e ident(indentificación) y almacena su cargo
class Asistente(Persona):
    def __init__(self, nombre: str, ident: int):
        super().__init__(nombre, ident)
        self.cargo = "Asistente de recolección"
        self.ocupado = False

    def __repr__(self):
        estado = "disponible" if not self.ocupado else "no disponible"
        return f"{self.nombre} ({self.ident}), Estado: {estado}"

class Turno:
    def __init__(self, camion: Camion):
        self.ruta = []
        self.generarRuta()
        self.camion = camion
        self.conductor = self.camion.conductor
        self.asistentes = self.camion.asistentes
        self.clasificacion = {"vidrio": 0.0, "papel": 0.0, "metal": 0.0, "residuos": 0.0}

    def generarRuta(self) -> None:
        for _ in range(5):
            latitud = rd.randint(-90, 90)  # Generar latitud aleatoria entre -90 y 90
            longitud = rd.randint(-180, 180)  # Generar longitud aleatoria entre -180 y 180
            self.ruta.append(PuntoGeografico(latitud, longitud))

    def clasificar(self) -> None:
        vidrio = float(input("¿Cuánto vidrio se recogió en el turno?: "))
        papel = float(input("¿Cuánto papel se recogió en el turno?: "))
        metal = float(input("¿Cuánto metal se recogió en el turno?: "))
        residuos = float(input("¿Cuánto residuos se recogió en el turno?: "))
        self.clasificacion.update({"vidrio":vidrio, "papel":papel, "metal": metal, "residuos":residuos})

    def mostrarResumen(self) -> None:
        print("---------------- Resumen de turno ingresado -------------------")
        print(self.camion)
        print("Cantidad de vidrio: ", self.clasificacion["vidrio"])
        print("Cantidad de papel: ", self.clasificacion["vidrio"])
        print("Cantidad de metal: ", self.clasificacion["vidrio"])
        print("Cantidad de residuos organicos: ", self.clasificacion["vidrio"])
        print("---------------------------------------------------------------")


class Server(object):
    def __init__(self, client, binding=None):
        self.wsdl = client.wsdl
        self.factory = client.factory

        def get_binding(obj):
            return self.wsdl.bindings_def['%s/literal' % obj.soap.style] # assume literal use

        if binding:
            for (name, ns), binding_obj in self.wsdl.bindings.iteritems():
                if name == binding:
                    self.binding  = get_binding(binding_obj)
                    break
            else:
                raise ValueError('Binding `%s` not found' % binding)
        else:
            if len(self.wsdl.bindings) == 1:
                self.binding = get_binding(self.wsdl.bindings.values()[0])
            else:
                raise ValueError('Binding name required')

    def handle_request(self, content):
        replyroot = self.binding.parser.parse(string=content)

        soapenv = replyroot.getChild('Envelope')
        soapenv.promotePrefixes()

        soapbody = soapenv.getChild('Body')
        soapbody = self.binding.multiref.process(soapbody)

        nodes = soapbody.getChildren()

        unmarshaller = self.binding.unmarshaller()
        result = [unmarshaller.process(node, None) for node in nodes]
        return len(result) == 1 and result[0] or result

    def handle_response(self, *content):
        message = self.binding.get_message(*content)
        return str(message)