import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
from scipy.signal import savgol_filter
import numpy as np
from scipy.signal import argrelextrema
import xlrd
from sklearn.metrics import confusion_matrix
from sklearn.metrics import f1_score

np.set_printoptions(precision=2)
plt.style.use('seaborn')

def filter_local_min(local_max, local_min):
	points_to_be_removed = []
	for i in range(len(local_max)):
		point = local_max[i]
		for j in range(len(local_min)):
			if local_min[j]>= point - 7 and local_min[j]<= point + 7:
				points_to_be_removed.append(local_min[j])

	final_points = []
	for i in range(len(local_min)):
		flag=0
		for j in range(len(points_to_be_removed)):
			if local_min[i] == points_to_be_removed[j]:
				flag=1
				break
		if flag==0:
			final_points.append(local_min[i])

	return final_points

dataset = pd.read_csv('../data_files/envisat.csv')
start_point = 9480
final_point = 9780
X_sma = dataset.iloc[:, [4]].values
X_ = np.ravel(X_sma)
X_sma_smoothed_vals = savgol_filter(X_, 25, 3) # window size 51, polynomial order 3 (31,10)
X_epoch = dataset.iloc[:, [2]].values

derivative = []
maneuver_dates = []
for i in range(len(X_sma)):

	if i == len(X_sma) - 1:
		epoch_date = X_epoch[i][0]
		epoch = datetime.strptime(epoch_date, '%Y-%m-%d %H:%M:%S')

		epoch_date1 = X_epoch[i-1][0]
		epoch1 = datetime.strptime(epoch_date1, '%Y-%m-%d %H:%M:%S')

		d0= datetime(epoch.year, epoch.month, epoch.day,  epoch.hour, epoch.minute,  epoch.second)        # Random date in the past
		d1= datetime(epoch1.year, epoch1.month, epoch1.day,  epoch1.hour, epoch1.minute, epoch1.second)
		duration = d1 - d0                         # For build-in functions
		duration_in_s = duration.total_seconds()
		duration_hours = duration_in_s/3600
		#print(duration_hours)

		num0 = X_sma[i][0]
		num1 = X_sma[i-1][0]

		if num1-num0 == 0:
			derivative.append(0)
		else:
			derivative.append((num1-num0)/(duration_hours))

		break

	epoch_date = X_epoch[i][0]
	epoch = datetime.strptime(epoch_date, '%Y-%m-%d %H:%M:%S')

	epoch_date1 = X_epoch[i+1][0]
	epoch1 = datetime.strptime(epoch_date1, '%Y-%m-%d %H:%M:%S')

	d0= datetime(epoch.year, epoch.month, epoch.day,  epoch.hour, epoch.minute,  epoch.second)        # Random date in the past
	d1= datetime(epoch1.year, epoch1.month, epoch1.day,  epoch1.hour, epoch1.minute, epoch1.second)
	duration = d1 - d0                         # For build-in functions
	duration_in_s = duration.total_seconds()
	duration_hours = duration_in_s/3600

	num0 = X_sma_smoothed_vals[i]
	num1 = X_sma_smoothed_vals[i+1]

	if num1-num0 == 0:
		derivative.append(0)
	else:
		#print(duration_hours)
		if duration_hours == 0:
			duration_hours = 0.02
		derivative.append((num1-num0)/(duration_hours))

	if abs(derivative[i])>2:
		derivative[i] = derivative[i-1]

a = argrelextrema(X_sma_smoothed_vals, np.greater)

# for local minima
b = argrelextrema(X_sma_smoothed_vals, np.less)

filtered_points = filter_local_min(a[0],b[0])
maneuver_dates = []
for i in range(len(filtered_points)):
	if filtered_points[i]+2<len(X_epoch):
		maneuver_dates.append(X_epoch[filtered_points[i]+2][0])
print("Number of maneuver_dates predicted : " + str(len(maneuver_dates)))

#########################################################################################
truth_dataset = pd.read_excel('../data_files/Envisat_Events.xlsx', index_col = None, engine='openpyxl')

book = xlrd.open_workbook("../data_files/Envisat_Events.xlsx")
datemode = book.datemode
first_sheet = book.sheet_by_index(0)
datetime_cnvrted = []
for i in range(1,truth_dataset.shape[0]+1):
	date = first_sheet.cell(i, 0)
	py_date = datetime(*xlrd.xldate_as_tuple(date.value,
												  book.datemode))

	d = py_date.strftime("%Y-%m-%d %H:%M:%S")
	datetime_cnvrted.append(d)

truth_dataset.insert(7, "datetime_cnvrted" , datetime_cnvrted, True)
df_maintenance = truth_dataset[truth_dataset["Column4"] == 'Maintenance']
df_ = df_maintenance.iloc[:,[7]].values
print("No. of maneuver dates in truth data: " + str(df_maintenance.shape[0]))

for i in range(len(maneuver_dates)):
	epoch_date = maneuver_dates[i]
	epoch = datetime.strptime(epoch_date, '%Y-%m-%d %H:%M:%S')
	d0= datetime(epoch.year, epoch.month, epoch.day,  epoch.hour, epoch.minute,  epoch.second)
	for j in range(len(df_)):
		epoch_date1 = df_[j][0]
		epoch1 = datetime.strptime(epoch_date1, '%Y-%m-%d %H:%M:%S')
		d1= datetime(epoch1.year, epoch1.month, epoch1.day,  epoch1.hour, epoch1.minute, epoch1.second)
		duration =  d1 - d0
		duration_in_s = duration.total_seconds()
		duration_in_hours = abs(duration_in_s/3600)
		#print("duration_hours: " + str(duration_in_hours))
		if duration_in_hours < 120:
			maneuver_dates[i] = epoch_date1
			break

y_truth = np.zeros(len(X_epoch))
for i in range(len(df_)):
	flag = 0
	epoch_date = df_[i][0]
	epoch = datetime.strptime(epoch_date, '%Y-%m-%d %H:%M:%S')
	d0= datetime(epoch.year, epoch.month, epoch.day,  epoch.hour, epoch.minute,  epoch.second)
	min_duration = float("inf")

	for j in range(len(X_epoch)):
		epoch_date1 = X_epoch[j][0]
		epoch1 = datetime.strptime(epoch_date1, '%Y-%m-%d %H:%M:%S')
		d1= datetime(epoch1.year, epoch1.month, epoch1.day,  epoch1.hour, epoch1.minute, epoch1.second)
		duration = d1 - d0
		duration_in_s = duration.total_seconds()
		duration_in_hours = abs(duration_in_s/3600)
		#print(duration_in_hours)

		if duration_in_hours < min_duration:
			min_duration = duration_in_hours
		if duration_in_hours > min_duration:
			#print("no")
			flag = 1
			y_truth[j] = 1
			break

#print("len X_epoch " + str(len(X_epoch)))
#print("len y_truth: " + str(len(y_truth)))

sum_y_truth = np.sum(y_truth)
print("No. of labels marked as '1'(maneuver date) when mapping to Tle data from truth data: " + str(sum_y_truth))
#print(y_truth)

y_pred = np.zeros(len(X_epoch))
for i in range(len(maneuver_dates)):
	flag = 0
	epoch_date = maneuver_dates[i]
	epoch = datetime.strptime(epoch_date, '%Y-%m-%d %H:%M:%S')
	d0= datetime(epoch.year, epoch.month, epoch.day,  epoch.hour, epoch.minute,  epoch.second)
	min_duration = float("inf")

	for j in range(len(X_epoch)):
		epoch_date1 = X_epoch[j][0]
		epoch1 = datetime.strptime(epoch_date1, '%Y-%m-%d %H:%M:%S')
		d1= datetime(epoch1.year, epoch1.month, epoch1.day,  epoch1.hour, epoch1.minute, epoch1.second)
		duration = d1 - d0
		duration_in_s = duration.total_seconds()
		duration_in_hours = abs(duration_in_s/3600)
		#print(duration_in_hours)

		if duration_in_hours < min_duration:
			min_duration = duration_in_hours
		if duration_in_hours > min_duration:
			#print("no")
			flag = 1
			y_pred[j] = 1
			break

#print("len X_epoch " + str(len(X_epoch)))
#print("len y_pred: " + str(len(y_pred)))

sum_y_pred = np.sum(y_pred)
print("No. of labels marked as '1'(maneuver date) when mapping to Tle data from predicted data: " + str(sum_y_pred))

no_of_matched = 0
no_of_unmatched = 0
for i in range(len(y_truth)):
	if y_truth[i] == y_pred [i]:
		no_of_matched+=1
	else:
		no_of_unmatched+=1
print("No.of matched labels(both 0 and 1): " +str(no_of_matched))
print("No. of unmatched labels(noth 0 and 1): " + str(no_of_unmatched))
print("confusion matrix : " )
print(confusion_matrix(y_truth, y_pred))
tn, fp, fn, tp = confusion_matrix(y_truth, y_pred).ravel()
#print(tn)
#print(fp)
#print(fn)
#print(tp)
score = f1_score(y_truth, y_pred)
print("F1 score: " + str(score))

print("---------------")
print("Tuned maneuver_dates are as follows: ")
for i in range(len(maneuver_dates)):
	print(maneuver_dates[i])
#################################################
#PLOT
actual_dates = []
actual_dates_sma = []
for i in range(len(X_epoch)):
	if y_truth[i] == 1:
		actual_dates.append(X_epoch[i][0])
		actual_dates_sma.append(X_sma[i])

#print(actual_dates)

predicted_dates = []
predicted_dates_sma = []
for i in range(len(X_epoch)):
	if y_pred[i] == 1:
		predicted_dates.append(X_epoch[i][0])
		predicted_dates_sma.append(X_sma[i])

'''
#print(X_epoch)
#print(X_sma)
X_epoch_ = []
X_sma_ = []
for k in range(len(X_epoch)):
	X_epoch_.append(X_epoch[k][0])

for k in range(len(X_sma)):
	X_sma_.append(X_sma[k][0])

#print(X_epoch_)
#print(X_sma_)

colors=['red', 'blue', 'green']
fig1, (ax1) = plt.subplots(nrows=1, ncols=1)

ax1.plot(X_sma_, X_epoch_, label='TEME' , linestyle='--', marker='o')

ax1.legend()
ax1.set_xlabel('epoch_day')
ax1.set_ylabel('position')
plt.tight_layout()
plt.show()
'''


def pares_e_impares(lista):
    pares = []
    impares = []
    for numero in lista:
        if numero%2 == 0:
            pares.append(numero)
        else:
            impares.append(numero)
    pares.sort()
    impares.sort()
    resultado = []
    resultado.append(pares)
    resultado.append(impares)
    return resultado


import sys

a, b = map(int, sys.stdin.readline().split(' '))

# 최대 공약수 구하기
a_yak = []  # a의 약수
for i in range(1, a + 1):
    if a % i == 0:
        a_yak.append(i)

b_yak = []  # b의 약수
for j in range(1, b + 1):
    if b % j == 0:
        b_yak.append(j)

ab_yak = []  # a,b의 공약수
for i in range(len(a_yak)):
    for j in range(len(b_yak)):
        if a_yak[i] == b_yak[j]:
            ab_yak.append(a_yak[i])

a_mok = a / ab_yak[-1]  # a를 공약수로 나눈수
b_mok = b / ab_yak[-1]  # b를 공약수로 나눈수
ab_bae = ab_yak[-1] * a_mok * b_mok  # ab 최소공배수 = 최대공약수 * 최대공약수로 나눈 a,b의 몫

print(ab_yak[-1])
print(ab_bae)


from mnist import load_mnist
from model import TwoLayerNet
from train import train_model

def main():
    # 读入数据
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

    # 可调超参数
    learning_rate = 0.01
    weight_decay = 0.01
    hidden_size = 256

    # 固定超参数
    input_size = 784
    output_size = 10
    n_epochs = 200
    batch_size = 100
    show_interval = 5

    # 设置模型
    network = TwoLayerNet(input_size=input_size, hidden_size=hidden_size,
                          output_size=output_size, weight_decay_lambda=weight_decay)

    # 模型训练
    train_model(model=network, batch_size=batch_size, n_epochs=n_epochs, learning_rate=learning_rate,
                show_interval=show_interval, train_data=x_train, train_label=t_train, test_data=x_test,
                test_label=t_test)

    # 模型保存
    network.store()

if __name__ == '__main__':
    main()


from typing import List

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        dp = [0] * (n + 1)
        dp[0], dp[1] = cost[0], cost[1]

        for i in range(2, len(cost)):
            dp[i] = min(dp[i - 2], dp[i - 1]) + cost[i]

        return min(dp[n - 2], dp[n - 1])

if __name__ == "__main__":
    s = Solution()
    print(s.minCostClimbingStairs([1, 100, 1, 1, 1, 100, 1, 1, 100, 1]))  # 6


from flask import Flask, send_file

app = Flask(__name__)

@app.route('/downloadCsv')
def downloadCsv():
    try:
        return send_file('/home/rahultarak12345/hashcat/temp.csv',
                         mimetype='text/csv',
                         attachment_filename='temp.csv',
                         as_attachment=True)
    except Exception as e:
        return str(e)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port='80')


class Solution:
    def twoSum(self, nums: list[int], target: int) -> list[int]:
        # curr = 0
        # original = nums
        #
        # def sum_it(nums, target, current=1):
        #     nonlocal curr
        #     curr += current
        #     if len(nums) < 1:
        #         return 1
        #
        #     for i in range(len(nums)-1):
        #         print(f"Adding {nums[0]} to {nums[i+1]} to get {target}")
        #         if nums[0] + nums[i+1] == target:
        #             first = original.index(nums[0])
        #             second = original.index(nums[i+1], first+1)
        #             print(f"target found {target}: at {[original.index(nums[0]), original.index(nums[i+1])]}")
        #             return [first, second]
        #
        #     print(f"Iteration: {current} list: {nums}")
        #
        #     return sum_it(nums[current:], target, 1)
        # return sum_it(nums, target)
        #
        for i in range(len(nums)):
            for j in range(len(nums)-1):
                # if nums[i] + nums[j] == target:
                #     print(f"{nums[i]} + {nums[j]} == target: {target}")
                #     print(f"index of them: {nums.index(nums[i])}, {nums.index(nums[j], nums[i]+1)}")
                #     print('ye')
                #     first = nums.index(nums[j])
                #     second = nums.index(nums[i], first + 1)
                    # return [first, second]
                print(f"i: {i}, j: {j}")
                print(f"e_i: {nums[i]}, e_j: {nums[j+1]}")
        return []

n = Solution()

p = n.twoSum([1, 11, 15, 7, 1, 3, 3, 4, 2], 9)
# p = n.twoSum([3, 3], 6)

print(p)


#-*- coding=utf-8 -*-
import pandas as pd
import matplotlib.pyplot as plt

import sklearn.preprocessing as sp

image_path = r"D:\Project-KOL\Data\\"
train_dataPath = r"D:\Project-KOL\Data\214_train_data.csv"
all_dataPath = r"D:\Project-KOL\Data\feed.csv"

#Read 300+ train Data
name = ['city level','industry','pubmed','WanFang','Trial','Class','BedCount','Pysician#','DailyPatient#','5Yrs','IMS GLP1','IMS Trulicity','HDF Patients','HDF Article','HDF Total']
pd_train_data = pd.read_csv(train_dataPath,usecols=(1,2,3,4,5,8,9,10,11,12,13,14,15,16,17),names=name,header=0)
pd_all_data = pd.read_csv(all_dataPath,usecols=(4,6,7,8,11,12,13,14,15,16,17,18,19,20,21),names=name,header=0,encoding="gb2312")

print(pd_train_data[['industry','pubmed','WanFang']].describe())
print(pd_all_data[['industry','pubmed','WanFang']].describe())

print(pd_train_data[['Score']])

#数据归一化
min_max_scaler = sp.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(pd_train_data)
print(type(pd_train_data))
print(type(X_train_minmax))
print(X_train_minmax.take([1,2,3],axis=1))

#绘制直方图矩阵
pd_train_data.hist( figsize=(10,10),layout=(3,5))
plt.savefig(image_path+'train_bar_chart.png')
plt.show()

plt.close()
pd_all_data.hist(figsize=(10,10),layout=(3,5))
plt.savefig(image_path+'all_bar_chart.png')

plt.show()
plt.close()

# find common features as below
# choose 'industry','pubmed','WanFang' as variable


from dbt.adapters.sql import SQLAdapter as adapter_cls
from dbt.adapters.upsolver import UpsolverConnectionManager
from dbt.events import AdapterLogger
from dbt.adapters.upsolver.relation import UpsolverRelation
from typing import List
from dbt.adapters.base.meta import available
from dbt.adapters.upsolver.options.copy_options import Copy_options
from dbt.adapters.upsolver.options.connection_options import Connection_options
from dbt.adapters.upsolver.options.transformation_options import Transformation_options
from dbt.adapters.upsolver.options.table_options import Table_options
import agate
import datetime
import re

logger = AdapterLogger("Upsolver")
LIST_RELATION_MACRO_NAME = "list_relation_without_caching"

class UpsolverAdapter(adapter_cls):
    """
    Controls actual implmentation of adapter, and ability to override certain methods.
    """

    ConnectionManager = UpsolverConnectionManager
    Relation = UpsolverRelation

    @classmethod
    def date_function(cls):
        """
        Returns canonical date func
        """
        return "datenow()"

    def debug_query(self) -> None:
        self.execute('SELECT * FROM logs.logs.task_executions limit 1;')

    def create_schema(self, relation: UpsolverRelation) -> None:
        pass

    def drop_schema(self, relation: UpsolverRelation) -> None:
        pass

    @available
    def alter_datetime(self):
        datetime_now = datetime.datetime.now()
        return 'Altered: ' + datetime_now.strftime('%Y-%m-%d %H:%M:%S')

    @available
    def get_connection_from_sql(self, sql):
        connection_identifier = re.search('"(.*)"', sql).group().split('.')[2] \
                                  .translate(str.maketrans({'\"':'', '\'':''}))

        return connection_identifier

    @available
    def get_columns_names_with_types(self, list_dict):
        res = []
        for col in list_dict:
            if col.get('type'):
                res.append(f"{col['field']} {col['type']}")
        return ', '.join(set(res))

    @available
    def get_columns_names(self, list_dict):
        res = []
        for col in list_dict:
            res.append(col['field'])
        return ', '.join(set(res))

    @available
    def separate_options(self, config_options, source):
        job_options = self.enrich_options(config_options, source, 'job_options')
        source_options = self.enrich_options(config_options, source, 'source_options')
        return job_options, source_options

    @available
    def enrich_options(self, config_options, source, options_type):
        options = self.get_options(source, options_type)
        enriched_options = {}
        for option, value in config_options.items():
            find_value = options.get(option.lower(), None)
            if find_value:
                if options[option.lower()]['type'] == 'list' and isinstance(value, str):
                    value = f"('{value}')"
                enriched_options[option] = find_value
                enriched_options[option]['value'] = value
            else:
                logger.warning(f"Options not found: {option}")
        return enriched_options

    @available
    def filter_options(self, options, parametr):
        editable = {key:val for key, val in options.items() if val[parametr] == True}
        return editable

    def get_options(self, source, options_type):
        if options_type == 'connection_options':
            options = Connection_options[source.lower()]
        elif options_type == 'transformation_options':
            options = Transformation_options[source.lower()]
        elif options_type == 'table_options':
            options = Table_options
        else:
            options = Copy_options[source.lower()][options_type]
        return options

    def list_relations_without_caching(
        self,
        schema_relation: UpsolverRelation,
        ) -> List[UpsolverRelation]:
        materializations = ["table", "job", "connection", "view"]
        results = agate.Table([],[])
        for type in materializations:
            kwargs = {"schema_relation": schema_relation, "relation_type": type}
            result = self.execute_macro(LIST_RELATION_MACRO_NAME, kwargs=kwargs)
            results = agate.Table.merge([results, result])
        relations = []
        quote_policy = {"database": True, "schema": True, "identifier": True}
        for _database, name, _schema, _type in results:
            try:
                _type = self.Relation.get_relation_type(_type)
            except ValueError:
                _type = self.Relation.External
            relations.append(
                self.Relation.create(
                    database=_database,
                    schema=_schema,
                    identifier=name,
                    quote_policy=quote_policy,
                    type=_type,
                )
            )
        return relations


from rocketpilot.introspection.dbus import DBusIntrospectionObject, is_element
from rocketpilot.introspection._xpathselect import (
    get_classname_from_path,
    get_path_root,
)

from rocketpilot.introspection._search import (
    get_proxy_object_for_existing_process,
    get_proxy_object_for_existing_process_by_name,
)

__all__ = [
    'is_element',
    'get_classname_from_path',
    'get_path_root',
    'ProxyBase',
    'get_proxy_object_for_existing_process',
    'get_proxy_object_for_existing_process_by_name',
]

ProxyBase = DBusIntrospectionObject
ProxyBase.__name__ = 'ProxyBase'


import logging

import zmq

class generic_plugin:

    """
    create instance by passing desired topics and callback function.
    the same callback is called for each topic so it's responsibility
    of the caller to differentiate between them on his own.

    use send_replies() to pass messages to different proxies with
    the zmq_addr field.
    """

    def __init__(
            self,
            logger_name,
            plugin_name,  # eg const.ARTISTINFO_PLUGIN
            subscribe_topics,  # list
            plugin_dispatch,
            command_dispatch_backend_replies,
            zmq_ioloop,
            zmq_ctx):
        self.logger = logging.getLogger(logger_name)
        self.plugin_name = plugin_name

        self.request = zmq_ctx.socket(zmq.SUB)
        self.request.connect(plugin_dispatch)

        for topic in subscribe_topics:
            self.request.setsockopt(zmq.SUBSCRIBE, topic)
            self.logger.info('subscribed to topic ' + str(topic))

        self.push_reply = zmq_ctx.socket(zmq.PUSH)
        self.push_reply.connect(command_dispatch_backend_replies)

        self.ioloop = zmq_ioloop

    async def send_replies(self, replies, zmq_addr, proxy_name):
        self.logger.info('about to send replies %s', replies)
        for reply in replies:
            reply = [zmq_addr, proxy_name, self.plugin_name, reply]
            await self.push_reply.send_multipart(reply)
        self.logger.info('sent!')

    async def read_request(self):
        return await self.request.recv_multipart()


# -*- coding: utf-8 -*-
def fibo_seq(n):
    if n < 2: return n
    a , b = 0, 1
    for i in range(n):
        a, b =b, a+b
    return a

fibo = fibo_seq(10)

print("10까지 피보나치 수열: ", fibo)


import os, argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
from modules.model import Model
from modules.loss import TransformerLoss
import hparams
from text import *
from utils.utils import *
from utils.writer import get_writer

def validate(model, criterion, val_loader, iteration, writer):
    model.eval()
    with torch.no_grad():
        n_data, val_loss = 0, 0
        for i, batch in enumerate(val_loader):
            n_data += len(batch[0])
            text_padded, text_lengths, mel_padded, mel_lengths, gate_padded = [
                x.cuda() for x in batch
            ]

            mel_out, mel_out_post,\
            enc_alignments, dec_alignments, enc_dec_alignments, gate_out = model.module.outputs(text_padded,
                                                                                mel_padded,
                                                                                text_lengths,
                                                                                mel_lengths)

            mel_loss, bce_loss, guide_loss = criterion((mel_out, mel_out_post, gate_out),
                                                       (mel_padded, gate_padded),
                                                       (enc_dec_alignments, text_lengths, mel_lengths))

            loss = torch.mean(mel_loss+bce_loss+guide_loss)
            val_loss += loss.item() * len(batch[0])

        val_loss /= n_data

    writer.add_losses(mel_loss.item(),
                      bce_loss.item(),
                      guide_loss.item(),
                      iteration//hparams.accumulation, 'Validation')

    writer.add_specs(mel_padded.detach().cpu(),
                     mel_out.detach().cpu(),
                     mel_out_post.detach().cpu(),
                     mel_lengths.detach().cpu(),
                     iteration//hparams.accumulation, 'Validation')

    writer.add_alignments(enc_alignments.detach().cpu(),
                          dec_alignments.detach().cpu(),
                          enc_dec_alignments.detach().cpu(),
                          text_padded.detach().cpu(),
                          mel_lengths.detach().cpu(),
                          text_lengths.detach().cpu(),
                          iteration//hparams.accumulation, 'Validation')

    writer.add_gates(gate_out.detach().cpu(),
                    iteration//hparams.accumulation, 'Validation')
    model.train()

def main():
    train_loader, val_loader, collate_fn = prepare_dataloaders(hparams)
    model = nn.DataParallel(Model(hparams)).cuda()
    optimizer = torch.optim.Adam(model.parameters(),
                                 lr=hparams.lr,
                                 betas=(0.9, 0.98),
                                 eps=1e-09)
    criterion = TransformerLoss()
    writer = get_writer(hparams.output_directory, hparams.log_directory)

    iteration, loss = 0, 0
    model.train()
    print("Training Start!!!")
    while iteration < (hparams.train_steps*hparams.accumulation):
        for i, batch in enumerate(train_loader):
            text_padded, text_lengths, mel_padded, mel_lengths, gate_padded = [
                reorder_batch(x, hparams.n_gpus).cuda() for x in batch
            ]

            mel_loss, bce_loss, guide_loss = model(text_padded,
                                                   mel_padded,
                                                   gate_padded,
                                                   text_lengths,
                                                   mel_lengths,
                                                   criterion)

            mel_loss, bce_loss, guide_loss=[
                torch.mean(x) for x in [mel_loss, bce_loss, guide_loss]
            ]
            sub_loss = (mel_loss+bce_loss+guide_loss)/hparams.accumulation
            sub_loss.backward()
            loss = loss+sub_loss.item()

            iteration += 1
            if iteration%hparams.accumulation == 0:
                lr_scheduling(optimizer, iteration//hparams.accumulation)
                nn.utils.clip_grad_norm_(model.parameters(), hparams.grad_clip_thresh)
                optimizer.step()
                model.zero_grad()
                writer.add_losses(mel_loss.item(),
                                  bce_loss.item(),
                                  guide_loss.item(),
                                  iteration//hparams.accumulation, 'Train')
                loss=0

            if iteration%(hparams.iters_per_validation*hparams.accumulation)==0:
                validate(model, criterion, val_loader, iteration, writer)

            if iteration%(hparams.iters_per_checkpoint*hparams.accumulation)==0:
                save_checkpoint(model,
                                optimizer,
                                hparams.lr,
                                iteration//hparams.accumulation,
                                filepath=f'{hparams.output_directory}/{hparams.log_directory}')

            if iteration==(hparams.train_steps*hparams.accumulation):
                break

if __name__ == '__main__':
    p = argparse.ArgumentParser()
    p.add_argument('--gpu', type=str, default='0,1')
    p.add_argument('-v', '--verbose', type=str, default='0')
    args = p.parse_args()

    os.environ["CUDA_VISIBLE_DEVICES"]=args.gpu
    torch.manual_seed(hparams.seed)
    torch.cuda.manual_seed(hparams.seed)

    if args.verbose=='0':
        import warnings
        warnings.filterwarnings("ignore")

    main()


import pandas as pd

def bill_to_type():
    """
    Creates bill_to_type table from bill_sponsors.
    """

    # ----- load -----
    bill_sponsors = pd.read_csv(
        '../data/transformed/bill_sponsors.csv', parse_dates=['date'])
    bill_sponsors = bill_sponsors[['bill_id', 'person_side', 'person_id']]
    bill_sponsors = bill_sponsors[bill_sponsors['bill_id'].notnull()]
    bill_sponsors['person_side'] = bill_sponsors['person_side'].astype(str)
    bill_sponsors['bill_id'] = bill_sponsors['bill_id'].astype('int64')
    bill_sponsors

    # fill-in missing side data here

    # ----- missing side data -----
    missing_side_data = bill_sponsors[bill_sponsors['person_side'] == 'nan']
    missing_side_data
    missing_side_bill_ids = set(missing_side_data['bill_id'])
    missing_side_bill_ids
    missing_side_data = bill_sponsors[bill_sponsors['bill_id'].isin(missing_side_bill_ids)]
    missing_side_data
    missing_side_data = missing_side_data.pivot_table(index='bill_id',
        columns='person_side', values='person_id', aggfunc='nunique').reset_index()
    missing_side_data
    missing_side_data_w_unclear_bill_type = missing_side_data.isnull()
    missing_side_data_w_unclear_bill_type

    missing_side_data_w_unclear_bill_type.to_excel(
        '../data/reports/missing_side_data_w_unclear_bill_type.xlsx',
        sheet_name='missing_side_data_w_unclear_bill_type', index=False)

    # # ----- records to exclude -----
    unclear_bill_type_ids = set(missing_side_data_w_unclear_bill_type['bill_id'])
    unclear_bill_type_ids

    # ----- logic definition -----
    bill_to_type = bill_sponsors[bill_sponsors['bill_id'].isin(unclear_bill_type_ids) == False]
    bill_to_type = bill_to_type.pivot_table(index='bill_id', columns='person_side', values='person_id', aggfunc='nunique').reset_index()
    if 'nan' in bill_to_type.columns:
        bill_to_type.drop(columns='nan', inplace=True)
    bill_to_type['bill_type'] = 'bipartisan'
    bill_to_type['bill_type'][bill_to_type['opposition'].isnull() | bill_to_type['coalition'].isnull()] = 'single-sided'
    bill_to_type

    # ----- save -----
    bill_to_type = bill_to_type[['bill_id', 'bill_type']].drop_duplicates()
    bill_to_type.to_excel(
        '../data/transformed/bill_to_type.xlsx', index=False)
    bill_to_type


'''
This module contains the PyQT5 circutry that runs the GUI. GUI structure is read in from a UI file. DORA parameters are read in a DORA2_settings XML.
'''
import sys
import os
from PyQt5.QtWidgets import *
from PyQt5 import uic
from pathlib import Path
from PyQt5.QtCore import Qt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar

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

import sma_lib.DORA2 as DORA
import sma_lib.MAP_Parameters as params

# xmlname = "DORA2_settings"

# #read in the settings in the .xml file using hazen's Parameter Class
# pars = params.Parameters(xmlname+'.xml') #par is an object of type Parameters, defined in sa_library

xmlname = "DORA2_settings.xml"  # Update the XML filename

# Construct the absolute path to the XML file
directory_path = os.path.dirname(os.path.abspath(__file__))
xml_path = os.path.join(directory_path, xmlname)

# Read in the settings from the XML file using the Parameters class
pars = params.Parameters(xml_path)  # Pass the updated XML file path

class MyGUI(QMainWindow):
    """
    A custom GUI class for handling data visualization and analysis.

    Attributes:
        dir_path (str): The selected directory path.
        selected_csv (str): The currently selected CSV file name.
        raw_data (DataFrame): The raw data loaded from the CSV file.
        data (DataFrame): The processed data after removing invalid readings.
        center (ndarray): The center coordinates of the data.
        center_list (ndarray): A running list of center manipulations.
        frame_increment (int): The number of frames to display in each update.
        start_frame (int): The starting frame index.
        end_frame (int): The ending frame index.
        min_intensity (float): The minimum intensity threshold.
        max_intensity (float): The maximum intensity threshold.
        fig_2 (Figure): The figure object for the Intensity graph.
        canvas_2 (FigureCanvas): The canvas to display the Intensity graph.
        fig_2D (Figure): The figure object for the 2D graph.
        canvas_2D (FigureCanvas): The canvas to display the 2D graph.
        choosen_secondary_graph (str): The currently selected secondary graph option.

    Methods:
        open_dir_dialog(): Opens a file dialog to select a directory.
        load_choosen_csv(): Loads the selected CSV file and performs data processing.
        update_graph_panel(): Updates the graph panel with the latest data.
        update_input_values(): Updates the input values based on the user's inputs.
        update_2D_plot(): Updates the 2D graph based on the frame slider value.
        update_secondary_graph(): Updates the secondary graph based on the selected option.
        clear_csv_list(): Clears the CSV file list.

    """

    def __init__(self):
        """
        Initializes an instance of the MyGUI class.

        This method sets up the GUI elements, connects them to the corresponding functions,
        and initializes default values for certain attributes.

        Note:
            The structure of the GUI is read in from a UI file ("MAP.1.3.ui") in this method.

        Parameters:
            None

        Returns:
            None
        """

        #pull in user data
        super(MyGUI,self).__init__()
        uic.loadUi("MAP.1.3.color.ui",self)
        self.show()

        # Connect the clicked to open folder search
        self.dir_btn.clicked.connect(self.open_dir_dialog) # if button clicked

        # set up list box for displaying CSV file names
        self.csv_list.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.csv_list.setSelectionMode(QListWidget.SingleSelection)

        # Connect the csvclicked in List Box to plotting function
        self.csv_list.itemClicked.connect(self.load_choosen_csv)
        self.csv_list.currentItemChanged.connect(self.load_choosen_csv)

        # Connect the clear selection button with clear csv function
        self.clear_csvs_btn.clicked.connect(self.clear_csv_list)

        # set up figure and canvas for secondary graph
        self.fig_2 = plt.figure()
        self.canvas_2 = FigureCanvas(self.fig_2)
        self.toolbar_2 = NavigationToolbar(self.canvas_2,self.centralwidget)
        self.graphLayout_2.addWidget(self.toolbar_2)
        self.graphLayout_2.addWidget(self.canvas_2)

        # set up figure and canvas for 2D graph
        # self.graphLayout_2D.setMinimumSize(480, 528)
        self.fig_2D = plt.figure()
        self.canvas_2D = FigureCanvas(self.fig_2D)
        self.toolbar_2D = NavigationToolbar(self.canvas_2D,self.centralwidget)
        self.graphLayout_2D.addWidget(self.toolbar_2D)
        self.graphLayout_2D.addWidget(self.canvas_2D)

        # Connect secondary_graph_comboBox to change secondary graph
        self.secondary_graph_comboBox.activated.connect(self.update_secondary_graph)

        # Intialize value of Line Edit:
        self.frame_increment_LineEdit.setText(str(pars.frame_increment))

        # Connect the frame_slider_increment_LineEditor to the LineEdit
        self.update_frames_intensity_PushButton.clicked.connect(self.update_input_values)

        # Connect the frame_slider to update_2D_plot
        self.frame_slider.valueChanged.connect(self.update_2D_plot)

        #set default function values
        self.frame_increment = pars.frame_increment
        secondary_graph_options = ["Continuous Angle vs Time", "Intensity vs Time","SNR vs Time", "SNR2 vs Time"]
        for option in secondary_graph_options:
            self.secondary_graph_comboBox.addItem(option)
        self.choosen_secondary_graph = self.secondary_graph_comboBox.currentText()

    def open_dir_dialog(self):
        """
        Opens a file dialog to select a directory and performs necessary operations based on the selected directory.

        This method prompts the user to select a directory using a file dialog and performs the following tasks:
        - Updates the directory path attribute of the GUI.
        - Updates the directory name in the corresponding text field of the GUI.
        - Populates the CSV list with file names from the selected directory.
        - Prints an information message indicating the selected folder.

        Parameters:
            None

        Returns:
            None
        """
        # Open file dialog and get directory
        dir_path = QFileDialog.getExistingDirectory(self, "Select Directory")
        self.dir_path = dir_path

        if dir_path:
            path = Path(dir_path)

            # Update text field with directory name
            self.dir_name_edit.setText(str(path))

            # Populate CSV list
            csv_files, _ = get_csv_files(str(path))
            for file_name in csv_files:
                self.csv_list.addItem(file_name)

            print(f'[INFO] You selected folder {str(path)}')

    def load_choosen_csv(self):
        """
        Loads the chosen CSV file, performs data processing, and updates the GUI.

        This method retrieves the selected CSV file from the CSV list, runs the necessary data processing steps using the DORA pipeline,
        and updates the GUI with the processed data. It sets up the frame slider and updates the graphs to reflect the loaded data.

        Parameters:
            None

        Returns:
            None
        """
        # Get selected CSV file name and path
        selected_csv = self.csv_list.currentItem().text()
        self.selected_csv = selected_csv
        dir_path = self.dir_path

        # Run DORA pipeline
        self.raw_data = DORA.load_csv(selected_csv, dir_path)
        self.data = self.raw_data.copy()  # Copy data so raw data remains intact
        DORA.remove_invalid_readings(self.data) # NOTE: change name to mask
        DORA.remove_nopass_intensity_filter(self.data)
        self.center, __ = DORA.find_center(self.data)
        self.data["X displacement (pixel)"], self.data["Y displacement (pixel)"] = DORA.generate_centered_data(self.data, self.center)
        self.data['Radius (pixel)'] = DORA.calculate_radius(self.data)
        self.data['z-score Rad'] = DORA.calculate_rad_zscore(self.data)
        self.data["Angle"], self.data["Delta Angle"], self.data["Continuous Angle"] = DORA.calculate_angle(self.data)
        down_sampled_df = DORA.downsample(self.data.dropna())

        # Initialize frame and intensity bounds
        self.start_frame = self.raw_data["index"].min()
        self.end_frame = self.raw_data["index"].max()
        self.min_intensity = self.raw_data["Intensity"].min()
        self.max_intensity = self.raw_data["Intensity"].max()

        # Update the GUI to reflect new frame and intensity bounds
        self.frame_start_LineEdit.setText(str(self.start_frame))
        self.frame_end_LineEdit.setText(str(self.end_frame))
        self.intensity_min_LineEdit.setText(str(self.min_intensity))
        self.intensity_max_LineEdit.setText(str(self.max_intensity))

        # Add first found center into center_list
        self.center_list = np.array(self.center)
        print(f"my starting center is {self.center_list}")

        # Update Center Label
        self.center_x_LineEdit.setText(str(0))
        self.center_y_LineEdit.setText(str(0))

        # Store the data
        self.data = down_sampled_df

        # Change to np format
        self.data_array = self.data.to_numpy()

        # Set minimums and maximums for frame slider values
        data_max = self.data_array.shape[0]
        self.frame_slider.setMaximum(data_max - self.frame_increment)
        self.frame_slider.setMinimum(0)
        self.frame_slider.setValue(self.frame_slider.minimum())

        # Update the graphs
        self.update_graph_panel()

    def update_graph_panel(self):
        """
        Updates the graph panel by clearing the previous plot and generating a new 2D graph based on the loaded data.

        This method clears the previous plot in the graph panel, generates a new 2D graph using the DORA plot_2D_graph function,
        and updates the canvas to display the updated graph. It also calls the update_secondary_graph method to update the secondary graph.

        Parameters:
            None

        Returns:
            None
        """
        # Clear the previous plot
        self.fig_2D.clf()

        # Generate the 2D graph
        DORA.plot_2D_graph(self.data, title=self.selected_csv, fig=self.fig_2D)
        self.fig_2D.tight_layout()

        # Update the canvas to display the updated graph
        self.canvas_2D.draw()

        # Update the secondary graph
        self.update_secondary_graph()

    def update_input_values(self):
        """
        Validates and updates the input values from the line edit fields.

        This method retrieves the values from the line edit fields and performs several checks and actions:

        Checks:
            - Checks if all input values are numeric. If any value is not numeric, an error message is printed, and the
            method returns without updating the values.
            - Checks if the minimum and maximum bounds for frames and intensity values are valid. Uses the `check_bounds`
            function to perform the check.

        Actions:
            - Updates the attribute values in the class corresponding to the line edit fields.
            - Converts the chosen x and y center coordinates from nm to pixels if the unit is "nm".
            - Saves the center coordinates in pixels and checks if the center is redundant. If it's new, adds it to the
            running list of centers.
            - Updates the start frame, end frame, minimum intensity, and maximum intensity attributes.
            - Retrieves the selected CSV file name and path.
            - Loads the CSV file into a data frame, removes invalid readings, and applies intensity filtering.
            - Generates centered data based on the updated center coordinates.
            - Calculates radius, z-score rad, angle, delta angle, and continuous angle for the data.
            - Downsamples the data by removing NaN values.
            - Converts the data frame to a NumPy array.
            - Updates the frame slider's minimum and maximum values based on the data.
            - Updates the graphs by clearing the previous plot and plotting the updated 2D graph.

        Parameters:
            None

        Returns:
            None
        """
        # Create a list of all line edits
        lineEdits = [
            self.frame_increment_LineEdit,
            self.center_x_LineEdit,
            self.center_y_LineEdit,
            self.frame_start_LineEdit,
            self.frame_end_LineEdit,
            self.intensity_min_LineEdit,
            self.intensity_max_LineEdit
        ]

        # Check if inputs are numeric
        for lineEdit in lineEdits:
            value = lineEdit.text()
            try:
                float(value)  # Try converting the value to float
            except ValueError:
                print(f"This value input is not numeric: {value}")
                return

        # Check if minimum and maximum bounds make sense. check_bounds outputs True if it passes
        check_1 = check_bounds(float(self.frame_start_LineEdit.text()), float(self.frame_end_LineEdit.text()), label = "Frames")
        check_2 = check_bounds(float((self.intensity_min_LineEdit.text())), float(self.intensity_max_LineEdit.text()), label = "Intensity")

        if all(value == True for value in [check_1,check_2]):

            #update the attributes values in the class corresponding to the line edits
            update_value(self, self.frame_increment_LineEdit, "frame_increment")
            update_value(self, self.center_x_LineEdit, "center_x")
            update_value(self, self.center_y_LineEdit, "center_y")
            if pars.unit == "nm":
                #convert choosen x (nm) and y (nm) into pixels
                self.center_x = self.center_x / pars.pixel_size
                self.center_y = self.center_y / pars.pixel_size

            # save center in pixels
            self.added_center = [self.center_x, self.center_y]

            # check if the center is redundant
            if self.added_center not in self.center_list:
                # add center if it is new
                self.center_list = np.vstack((self.center_list, self.added_center)) # adds a running list of center manipulations so that all centering opperations are relative to the original data
            self.center = np.sum(self.center_list, axis=0)

            print(f"[INFO] Adjusted Center in pixel space is {self.center}")
            update_value(self, self.frame_start_LineEdit, "start_frame")
            update_value(self, self.frame_end_LineEdit, "end_frame")
            update_value(self, self.intensity_min_LineEdit, "min_intensity")
            update_value(self, self.intensity_max_LineEdit, "max_intensity")

            # get selected CSV file name and path
            selected_csv = self.csv_list.currentItem().text()
            self.selected_csv = selected_csv
            dir_path = self.dir_path

            # Load the csv into a data frame and remove NaN's
            self.raw_data = DORA.load_csv(selected_csv, dir_path, start_frame = self.start_frame, end_frame = self.end_frame)
            self.data = self.raw_data.copy() # Copy data so raw data remains intact
            DORA.remove_invalid_readings(self.data)
            DORA.remove_nopass_intensity_filter(self.data, min_intensity= self.min_intensity, max_intensity=self.max_intensity) #!! Change
            self.data["X displacement (pixel)"], self.data["Y displacement (pixel)"] = DORA.generate_centered_data(self.data, self.center)
            self.data['Radius (pixel)'] = DORA.calculate_radius(self.data)
            self.data['z-score Rad'] = DORA.calculate_rad_zscore(self.data)
            self.data["Angle"], self.data["Delta Angle"], self.data["Continuous Angle"] = DORA.calculate_angle(self.data)
            down_sampled_df = DORA.downsample(self.data.dropna())

            # change to np format
            self.data_array = self.data.to_numpy()

            # update the frame_slider to have new bounds
            frame_slider_index_min = np.min(self.data_array[:, 0])
            frame_slider_index_max = np.max(self.data_array[:,0])
            self.frame_slider.setMinimum(int(frame_slider_index_min))
            self.frame_slider.setMaximum(int(frame_slider_index_max)-self.frame_increment)
            self.frame_slider.setValue(self.frame_slider.minimum())

            # Update the graphs
            self.update_graph_panel()

    def update_2D_plot(self):
        # load slider value INDEXING VALUE
        # NOTE: you need to subtract the minimum value otherwise you will index more than you need to when min ~= 0
        slider_index = self.frame_slider.value() - self.frame_slider.minimum()

        # Index a subset to graph
        subset_array = self.data_array[slider_index : slider_index + self.frame_increment,:]

        # Get the minimum index value from the first column
        min_index = np.min(subset_array[:, 0])
        max_index = np.max(subset_array[:,0])

        # Graph
        # ... perform your 2D graph plotting using subset_array ...
        # ... replace the following code with your actual graph plotting code ...
        DORA.plot_2D_graph(subset_array, column_headers= self.data.columns, start_frame= min_index, endframe = max_index, title= self.selected_csv, fig = self.fig_2D)
        # self.fig_2D.tight_layout()

        # redraw canvas
        self.canvas_2D.draw()

    def update_secondary_graph(self):
        """
        Updates the secondary graph based on the selected option from the combo box.

        This method performs the following actions:

        - Clears the previous plot on the secondary graph canvas.
        - Retrieves the selected option from the secondary graph combo box and updates the label text accordingly.
        - If the selected option is "Continuous Angle vs Time", plots the angular continuous graph using the DORA
        `plot_angular_continuous` function.
        - If the selected option is "Intensity vs Time", plots the intensity vs. time graph using the DORA
        `plot_intensity_time` function.
        - If the selected option is not part of the approved list, raises a ValueError.

        Parameters:
            None

        Returns:
            None
        """

        # Reset Graph Canvas
        self.fig_2.clf()

        # Redefine choosen secondary graph
        self.choosen_secondary_graph = self.secondary_graph_comboBox.currentText()
        self.label_2.setText(self.choosen_secondary_graph)

        # If specific graph is choosen, plot that graph
        if self.choosen_secondary_graph == "Continuous Angle vs Time":
            DORA.plot_angular_continuous(self.data, title = self.selected_csv, fig = self.fig_2)

        elif self.choosen_secondary_graph == "Intensity vs Time":
            DORA.plot_intensity_time(self.data, title = self.selected_csv, fig = self.fig_2)

        elif self.choosen_secondary_graph == "SNR vs Time":
            DORA.plot_snr_time(self.data, title = self.selected_csv, fig = self.fig_2)

        elif self.choosen_secondary_graph == "SNR2 vs Time":
            DORA.plot_intensity_time(self.data, title = self.selected_csv, fig = self.fig_2)

        else:
            ValueError("[ERROR] The choosen secondary graph combo box selection is NOT part of the approved list")

        # Apply tight layout
        self.fig_2.tight_layout()

        # redraw canvas
        self.canvas_2.draw()

    def clear_csv_list(self):
        """
        Clears the CSV list and directory name edit.

        This method performs the following actions:

        - Clears the items in the CSV list widget.
        - Clears the text in the directory name edit widget.
        - Prints a message indicating that the CSVs have been cleared.

        Parameters:
            None

        Returns:
            None
        """
        self.csv_list.clear()
        self.dir_name_edit.clear()
        print("You have cleared the CSV's")

def update_value(self, line_edit, attribute_name):
    """
    Updates the value of the specified attribute based on the input from a line edit.

    Args:
        line_edit (QLineEdit): The line edit containing the new value.
        attribute_name (str): The name of the attribute to be updated.

    Returns:
        value: The updated attribute value.

    Notes:
        - This method takes the input from a line edit and assigns it to the corresponding attribute.
        - The naming convention for the associated line edits is: parameter_LineEdit.
        - The method converts the input value to the appropriate data type (integer or float) based on the attribute.
        - It assumes that these attributes are only numeric.
    """
    value = line_edit.text()
    try:
        if attribute_name == "start_frame" or attribute_name == "end_frame" or attribute_name == "frame_increment":
            setattr(self, attribute_name, int(float(value))) # Convert to integer if necessary
        else:
            setattr(self, attribute_name, float(value))  # Convert to float
        print(f"[INFO] New {attribute_name} is {getattr(self, attribute_name)}")
    except ValueError:
        print(f"[ERROR] Invalid input: {value} for {attribute_name}")

def check_bounds(lower_bound, upper_bound, label):
    """
    Checks the validity of lower and upper bounds for a given label.

    Args:
        lower_bound (float): The lower bound value.
        upper_bound (float): The upper bound value.
        label (str): The label or parameter associated with the bounds.

    Returns:
        bool: True if the bounds are valid, False otherwise.

    Notes:
        - This function is used to check the validity of bounds for a specific parameter.
        - The lower_bound and upper_bound are checked against certain conditions.
        - If the bounds are valid, the function returns True; otherwise, it returns False.
        - It also prints informative messages about the validity of the bounds.
    """
    if upper_bound == -1:
        return True

    if lower_bound < -1 or upper_bound < -1:
        print(f"[INFO] Invalid {label} bounds! Bounds should not be negative, unless -1 is used for the upper bound.")
        return False

    if upper_bound < lower_bound:
        print(f"[INFO] Invalid {label} bounds! The upper bound should be greater than or equal to the lower bound.")
        return False
    elif lower_bound == upper_bound:
        print(f"[INFO] Invalid {label} bounds! The lower bound and upper bound should be different.")
        return False
    else:
        print(f"[INFO] Valid {label} bounds entered.")
        return True

def get_csv_files(folder_path):
    """
    Retrieves CSV files and their file paths from a given folder path.

    Args:
        folder_path (str): The path to the folder containing CSV files.

    Returns:
        tuple: A tuple containing two lists:
            - csv_files: A list of CSV file names in the folder.
            - csv_file_paths: A list of full paths to the CSV files.

    Note:
        - This function uses the `os` module to retrieve the list of files in the folder.
        - It filters the list to include only CSV files based on their file extensions.
        - The function returns two lists, one with the file names and the other with the full paths.
    """
    files = os.listdir(folder_path)
    # Filter the list to only include CSV files
    csv_files = [file for file in files if file.endswith('.csv')]
    csv_file_paths = [os.path.join(folder_path, file) for file in files if file.lower().endswith('.csv')]
    return csv_files, csv_file_paths

def main():
    '''
    The main function represents the entry point of your application. It initializes the application, creates the main GUI window, and starts the event loop.
    '''
    app = QApplication([])
    window = MyGUI()
    app.exec_()
    pass

if __name__ == '__main__':
    main()


#Zero Matrix: If an element in MxN matrix is 0, entire row and column are set to 0

def zero_matrix(matrix):
    zero_i = None
    rows = []
    cols = []
    for i, row in enumerate(matrix):
        if 0 in row:
            rows.append(i)
            cols.append(row.index(0))

    if len(rows) == 0:
        return matrix

    for i, row in enumerate(matrix):
        if i in rows:
            matrix[i] = [0]*len(row)
        else:
            for col in cols:
                matrix[i][col] = 0

    return matrix

if __name__ == "__main__":
    example = [ [1,2,3,4],
                [1,2,0,4],
                [1,0,3,4],
                [1,2,3,4]]

    print(zero_matrix(example))


import os
import yaml
import joblib
from src import clean_data, build_features

def read_params(config_path):
    with open(config_path) as yaml_file:
        config = yaml.safe_load(yaml_file)
    return config

def api_response(request_dict):
    params_path = "params.yaml"
    config = read_params(params_path)

    request_text = request_dict.text

    request_text_clean = clean_data.DataLoader(config_path=params_path)._preprocess_text(request_text)

    request_text_features = build_features.BuildFeatures(config_path=params_path)._build_features_text(request_text_clean, lang="en")

    model_dir = os.path.join(config["model_dir"], "model.joblib")
    model = joblib.load(model_dir)
    prediction = model.predict(request_text_features).tolist()[0]
    prediction_proba = model.predict_proba(request_text_features)[:,1].tolist()[0]

    if prediction == 1:
        toxic = True
    elif prediction == 0:
        toxic = False

    return toxic, prediction_proba

   #!/usr/bin/env python3
# -*- coding: utf-8 -*-

import fasttext

class LanguageIdentification:

    def __init__(self):
        pretrained_lang_model = "/tmp/lid.176.bin"
        self.model = fasttext.load_model(pretrained_lang_model)

    def predict_lang(self, text):
        predictions = self.model.predict(text, k=1) # returns top 2 matching languages
        return predictions

if __name__ == '__main__':
    LANGUAGE = LanguageIdentification()
    lang = LANGUAGE.predict_lang("Hi, how are you?")
    print(lang)


#! /usr/bin/env python3
#

import numpy as np
import matplotlib.pyplot as plt
import platform
import time
import sys
import os
import math
from mpl_toolkits.mplot3d import Axes3D
from sys import exit

sys.path.append(os.path.join("../"))
from base import plot2d, plotocc
from timestamp.timestamp import timestamp

from i4lib.i4_choose import i4_choose
from i4lib.i4vec_sum import i4vec_sum
from i4lib.i4vec_print import i4vec_print
from i4lib.i4mat_print import i4mat_print
from r8lib.r8vec_print import r8vec_print
from r8lib.r8mat_print import r8mat_print, r8mat_print_some
from r8lib.r8mat_write import r8mat_write
from i4lib.i4vec_uniform_ab import i4vec_uniform_ab

def mono_next_grlex(m, x):

    # *****************************************************************************80
    #
    # MONO_NEXT_GRLEX returns the next monomial in grlex order.
    #
    #  Discussion:
    #
    #    Example:
    #
    #    M = 3
    #
    #    #  X(1)  X(2)  X(3)  Degree
    #      +------------------------
    #    1 |  0     0     0        0
    #      |
    #    2 |  0     0     1        1
    #    3 |  0     1     0        1
    #    4 |  1     0     0        1
    #      |
    #    5 |  0     0     2        2
    #    6 |  0     1     1        2
    #    7 |  0     2     0        2
    #    8 |  1     0     1        2
    #    9 |  1     1     0        2
    #   10 |  2     0     0        2
    #      |
    #   11 |  0     0     3        3
    #   12 |  0     1     2        3
    #   13 |  0     2     1        3
    #   14 |  0     3     0        3
    #   15 |  1     0     2        3
    #   16 |  1     1     1        3
    #   17 |  1     2     0        3
    #   18 |  2     0     1        3
    #   19 |  2     1     0        3
    #   20 |  3     0     0        3
    #
    #  Licensing:
    #
    #    This code is distributed under the GNU LGPL license.
    #
    #  Modified:
    #
    #    24 October 2014
    #
    #  Author:
    #
    #    John Burkardt
    #
    #  Parameters:
    #
    #    Input, integer M, the spatial dimension.
    #
    #    Input, integer X[M], the current monomial.
    #    The first element is X = [ 0, 0, ..., 0, 0 ].
    #
    #    Output, integer X[M], the next monomial.
    #

    #
    #  Ensure that 1 <= D.
    #
    if (m < 1):
        print('')
        print('MONO_NEXT_GRLEX - Fatal error!')
        print('  M < 1')
        exit('MONO_NEXT_GRLEX - Fatal error!')
#
#  Ensure that 0 <= X(I).
#
    for i in range(0, m):
        if (x[i] < 0):
            print('')
            print('MONO_NEXT_GRLEX - Fatal error!')
            print('  X[I] < 0')
            exit('MONO_NEXT_GRLEX - Fatal error!')
#
#  Find I, the index of the rightmost nonzero entry of X.
#
    i = 0
    for j in range(m, 0, -1):
        if (0 < x[j - 1]):
            i = j
            break
#
#  set T = X(I)
#  set X(I) to zero,
#  increase X(I-1) by 1,
#  increment X(M) by T-1.
#
    if (i == 0):
        x[m - 1] = 1
        return x
    elif (i == 1):
        t = x[0] + 1
        im1 = m
    elif (1 < i):
        t = x[i - 1]
        im1 = i - 1

    x[i - 1] = 0
    x[im1 - 1] = x[im1 - 1] + 1
    x[m - 1] = x[m - 1] + t - 1

    return x

def mono_next_grlex_test():

    # *****************************************************************************80
    #
    # MONO_NEXT_GRLEX_TEST tests MONO_NEXT_GRLEX.
    #
    #  Licensing:
    #
    #    This code is distributed under the GNU LGPL license.
    #
    #  Modified:
    #
    #    24 October 2014
    #
    #  Author:
    #
    #    John Burkardt
    #

    m = 4

    print('')
    print('MONO_NEXT_GRLEX_TEST')
    print('  Python version: %s' % (platform.python_version()))
    print('  MONO_NEXT_GRLEX computes the next monomial')
    print('  in M variables in grlex order.')
    print('')
    print('  Let M =  %d' % (m))

    a = 0
    b = 3
    seed = 123456789

    for i in range(0, 10):

        x, seed = i4vec_uniform_ab(m, a, b, seed)
        print('')
        print('  ', end='')
        for k in range(0, m):
            print('%2d' % (x[k]), end='')
        print('')

        for j in range(0, 5):
            x = mono_next_grlex(m, x)
            print('  ', end='')
            for k in range(0, m):
                print('%2d' % (x[k]), end='')
            print('')
#
#  Terminate.
#
    print('')
    print('MONO_NEXT_GRLEX_TEST')
    print('  Normal end of execution.')
    return

if (__name__ == '__main__'):
    from timestamp import timestamp
    timestamp()
    mono_next_grlex_test()
    timestamp()