import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import VarianceThreshold
from sklearn.metrics import r2_score, mean_squared_error
from rdkit import Chem
from rdkit.Chem import AllChem
import dill
import pymc3 as pm
import arviz as az

## Helper Functions

def variance_threshold_selector(data, threshold=0.00):
	selector = VarianceThreshold(threshold)
	selector.fit(data)
	return data[data.columns[selector.get_support(indices=True)]]

def get_ci_error(model, x, y, pred, error):
    x_dist = model.μ.distribution.predict(np.array(x))
    x_reshape = x_dist.T
    ci = list(az.hdi(np.array(x), hxdi_prob=0.89) for x in x_reshape)
    ci_flat =np.stack(ci)
    ci_errors = (np.abs(ci_flat - pred.reshape(len(pred),1)))

    error_lim = np.log10(10**y+np.array(error).reshape(1,-1))-y

    return x_dist, ci, ci_errors, error_lim

## Load in data

data = pd.read_csv("../data/raw/data.csv")
train = np.where(data.label == "train")[0]
test = np.where(data.label == "test")[0]
val = np.where(data.label == "val")[0]

smiles_full = data.SMILES
mols_full = [Chem.MolFromSmiles(x) for x in smiles_full]
g = data.g
gdbl = data.gdbl

gtrain_error = data.err_g[train]
gtest_error = data.err_g[test]
gval_error = data.err_g[val]
gdbltrain_error = data.err_gdbl[train]
gdbltest_error = data.err_gdbl[test]
gdblval_error = data.err_gdbl[val]

## Get Descriptors

df = pd.DataFrame()
df["num_rings"] = [Chem.rdMolDescriptors.CalcNumRings(x) for x in mols_full]

fcfp = []
for mol in mols_full:
    ar = np.zeros((1,))
    fp = AllChem.GetMorganFingerprintAsBitVect(mol, 2, 2048, useFeatures=True)
    Chem.DataStructs.ConvertToNumpyArray(fp,ar)
    fcfp.append(ar)
fcfp = pd.DataFrame(np.stack(fcfp), columns=["FCFP_"+str(i) for i in range(2048)])
ecfp = []
for mol in mols_full:
    ar = np.zeros((1,))
    fp = AllChem.GetMorganFingerprintAsBitVect(mol, 2, 2048, useFeatures=False)
    Chem.DataStructs.ConvertToNumpyArray(fp,ar)
    ecfp.append(ar)
ecfp = pd.DataFrame(np.stack(ecfp), columns=["ECFP_"+str(i) for i in range(2048)])
df = pd.concat([df,fcfp,ecfp],axis=1)

for col in df.columns:
    df[col] = df[col]*data.conc

## Split into predetermined train, test and validation sets

xtrain = df.iloc[train]
xtest = df.iloc[test].reset_index(drop=True)
xval = df.iloc[val].reset_index(drop=True)

gtrain = g.iloc[train]
gtest = g.iloc[test]
gval = g.iloc[val]

gdbltrain = gdbl.iloc[train]
gdbltest = gdbl.iloc[test]
gdblval = gdbl.iloc[val]

## Remove correlated and zero variance descriptors

xtrain = variance_threshold_selector(xtrain)
corr_matrix = xtrain.corr().abs()
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool))
to_drop = [column for column in upper.columns if any(upper[column] > 0.9)]+["FCFP_0"] ## Added FCFP_0 due to being set in all molecules
xtrain = xtrain.drop(xtrain[to_drop], axis=1)
xtest = xtest[xtrain.columns]
xval = xval[xtrain.columns]

scaler = StandardScaler()
xtrain = pd.DataFrame(scaler.fit_transform(xtrain), columns = xtrain.columns)
xtest = pd.DataFrame(scaler.transform(xtest), columns = xtrain.columns)
xval = pd.DataFrame(scaler.transform(xval), columns = xtrain.columns)

with open("../models/scaler.pkl", "wb") as f:
    dill.dump(scaler, f)

## Save split data

xtrain.to_csv("../data/split/xtrain.csv", index=False)
xtest.to_csv("../data/split/xtest.csv", index=False)
xval.to_csv("../data/split/xval.csv", index=False)

gtrain.to_csv("../data/split/gtrain.csv", index=False)
gtest.to_csv("../data/split/gtest.csv", index=False)
gval.to_csv("../data/split/gval.csv", index=False)

gdbltrain.to_csv("../data/split/gdbltrain.csv", index=False)
gdbltest.to_csv("../data/split/gdbltest.csv", index=False)
gdblval.to_csv("../data/split/gdblval.csv", index=False)

## BART requires y data as np array

gtrain = np.ravel(gtrain)
gtest = np.ravel(gtest)
gval = np.ravel(gval)

gdbltrain = np.ravel(gdbltrain)
gdbltest = np.ravel(gdbltest)
gdblval = np.ravel(gdblval)

## Build and save models

models = []
traces = []
for y,m,alpha in [(gtrain,10,0.9), (gdbltrain,25,0.8)]:
    with pm.Model() as model:
        σ = pm.HalfNormal('σ', 1)
        μ = pm.BART('μ', xtrain, np.array(y), m=m, alpha=alpha)
        y = pm.Normal('y', μ, σ, observed=np.array(y))
        trace = pm.sample(2000, cores=1, tune=1000, return_inferencedata=False, random_seed = 42)

    models.append(model)
    traces.append(trace)

model_g = models[0]
trace_g = traces[0]
model_gdbl = models[1]
trace_gdbl = traces[1]

with open("../models/g.pkl","wb") as f:
    dill.dump(model_g, f)

with open("../models/gdbl.pkl","wb") as f:
    dill.dump(model_gdbl, f)

with open("../models/g_trace.pkl","wb") as f:
    dill.dump(trace_g, f)

with open("../models/gdbl_trace.pkl","wb") as f:
    dill.dump(trace_gdbl, f)

## Get Predictions and produce report

gtrain_pred = model_g.µ.distribution.predict(np.array(xtrain)).mean(axis=0)
gdbltrain_pred = model_gdbl.µ.distribution.predict(np.array(xtrain)).mean(axis=0)
gtest_pred = model_g.µ.distribution.predict(np.array(xtest)).mean(axis=0)
gdbltest_pred = model_gdbl.µ.distribution.predict(np.array(xtest)).mean(axis=0)
gval_pred = model_g.µ.distribution.predict(np.array(xval)).mean(axis=0)
gdblval_pred = model_gdbl.µ.distribution.predict(np.array(xval)).mean(axis=0)

gtrain_pred_res = np.abs(gtrain_pred - gtrain)
gdbltrain_pred_res = np.abs(gdbltrain_pred - gdbltrain)
gtest_pred_res = np.abs(gtest_pred - gtest)
gdbltest_pred_res = np.abs(gdbltest_pred - gdbltest)
gval_pred_res = np.abs(gval_pred - gval)
gdblval_pred_res = np.abs(gdblval_pred - gdblval)

gtrain_dist, gtrain_ci, gtrain_ci_errors, gtrain_exp_errors = get_ci_error(model_g, xtrain, gtrain, gtrain_pred, gtrain_error)
gtest_dist, gtest_ci, gtest_ci_errors, gtest_exp_errors = get_ci_error(model_g, xtest, gtest, gtest_pred, gtest_error)
gval_dist, gval_ci, gval_ci_errors, gval_exp_errors = get_ci_error(model_g, xval, gval, gval_pred, gval_error)
gdbltrain_dist, gdbltrain_ci, gdbltrain_ci_errors, gdbltrain_exp_errors = get_ci_error(model_gdbl, xtrain, gdbltrain, gdbltrain_pred, gdbltrain_error)
gdbltest_dist, gdbltest_ci, gdbltest_ci_errors, gdbltest_exp_errors = get_ci_error(model_gdbl, xtest, gdbltest, gdbltest_pred, gdbltest_error)
gdblval_dist, gdblval_ci, gdblval_ci_errors, gdblval_exp_errors = get_ci_error(model_gdbl, xval, gdblval, gdblval_pred, gdblval_error)

ci_errors_fullg = np.concatenate([gtrain_ci_errors, gtest_ci_errors, gval_ci_errors])
ci_errors_1g = []
ci_errors_2g = []
for i in range(len(ci_errors_fullg)):
    ci_errors_1g.append(ci_errors_fullg[i][0])
    ci_errors_2g.append(ci_errors_fullg[i][1])

ci_errors_fullgdbl = np.concatenate([gdbltrain_ci_errors, gdbltest_ci_errors, gdblval_ci_errors])
ci_errors_1gdbl = []
ci_errors_2gdbl = []
for i in range(len(ci_errors_fullgdbl)):
    ci_errors_1gdbl.append(ci_errors_fullgdbl[i][0])
    ci_errors_2gdbl.append(ci_errors_fullgdbl[i][1])

ci_errors_1g = pd.Series(ci_errors_1g, name="ci1_g")
ci_errors_2g = pd.Series(ci_errors_2g, name="ci2_g")
ci_errors_1gdbl = pd.Series(ci_errors_1g, name="ci1_gdbl")
ci_errors_2gdbl = pd.Series(ci_errors_2g, name="ci2_gdbl")

all_errg = pd.Series(list(gtrain_exp_errors[0]) + list(gtest_exp_errors[0]) + list(gval_exp_errors[0]), name = "err_g")
all_errgdbl = pd.Series(list(gdbltrain_exp_errors[0]) + list(gdbltest_exp_errors[0]) + list(gdblval_exp_errors[0]), name = "err_gdbl")

train_results = pd.DataFrame([gtrain, gtrain_pred, gtrain_pred_res, gdbltrain, gdbltrain_pred, gdbltrain_pred_res], index=["g", "g_pred", "g_pred_res", "gdbl", "gdbl_pred", "gdbl_pred_res"]).T
train_results["label"] = ["train" for x in range(len(train_results))]
test_results = pd.DataFrame([gtest, gtest_pred, gtest_pred_res, gdbltest, gdbltest_pred, gdbltest_pred_res], index=["g", "g_pred", "g_pred_res", "gdbl", "gdbl_pred", "gdbl_pred_res"]).T
test_results["label"] = ["test" for x in range(len(test_results))]
val_results = pd.DataFrame([gval, gval_pred, gval_pred_res, gdblval, gdblval_pred, gdblval_pred_res], index=["g", "g_pred", "g_pred_res", "gdbl", "gdbl_pred", "gdbl_pred_res"]).T
val_results["label"] = ["val" for x in range(len(val_results))]

results = pd.concat([train_results, test_results, val_results], axis=0).reset_index(drop=True)

results = pd.concat([results, all_errg, ci_errors_1g, ci_errors_2g, all_errgdbl, ci_errors_1gdbl, ci_errors_2gdbl, smiles_full],axis=1)
results.to_csv("../reports/predictions.csv", index=False)

prediction_summary = pd.DataFrame()
for ind in [train, test, val]:
    gr2 = r2_score(results.g[ind], results.g_pred[ind])
    grmse = np.sqrt(mean_squared_error(results.g[ind], results.g_pred[ind]))
    gdblr2 = r2_score(results.gdbl[ind], results.gdbl_pred[ind])
    gdblrmse = np.sqrt(mean_squared_error(results.gdbl[ind], results.gdbl_pred[ind]))
    pred_rep = pd.DataFrame([gr2, grmse, gdblr2, gdblrmse],index=["gr2", "grmse", "gdblr2", "gdblrmse"]).T
    prediction_summary = pd.concat([prediction_summary, pred_rep], axis=0).reset_index(drop=True)
prediction_summary.rename({0:"train",1:"test",2:"val"}, axis=0, inplace=True)
prediction_summary.to_csv("../reports/prediction_summary.csv", index=False)


import utils.format_population as fpt
import utils.population as pup
import utils.graphs as graph

def run():
    data = fpt.read_csv('./world_population.csv')
    country = input('Ingresa un país => ')
    result = pup.get_population_by_country(data, country)
    if len(result) > 0:
        keys, values = pup.get_population_year(result[0])
        graph.bar_chart(keys, values)

if __name__=='__main__':
    run()


from plotnine import *
from sklearn.datasets import make_regression

from sklearn.model_selection import TimeSeriesSplit
from sklearn.model_selection import KFold
from src.cv_extensions.blocked_cv import BlockedKFold
from src.cv_extensions.hv_blocked_cv import hvBlockedKFold
from src.cv_extensions.modified_cv import ModifiedKFold
from src.cv_extensions.sliding_tss import SlidingTimeSeriesSplit
from src.cv_extensions.holdout import Holdout
from src.mccv import MonteCarloCV

from src.cv_plot import cv_plot_points, cv_plot_points_blank

N_SPLITS = 5
N = 30
GAP = 3
WIDTH, HEIGHT = 9, 5

X, y = make_regression(n_samples=N)

kfcv = KFold(n_splits=N_SPLITS, shuffle=True)
stss_cv = SlidingTimeSeriesSplit(n_splits=N_SPLITS)
tss_cv = TimeSeriesSplit(n_splits=N_SPLITS)
tssg_cv = TimeSeriesSplit(n_splits=N_SPLITS, gap=GAP)
bcv = BlockedKFold(n_splits=N_SPLITS)
hvbcv = hvBlockedKFold(n_splits=N_SPLITS, gap=GAP)
mcv = ModifiedKFold(n_splits=N_SPLITS, gap=2)
mccv = MonteCarloCV(n_splits=N_SPLITS, train_size=.5, test_size=.1)
ho = Holdout(n=N, test_size=.3)

plot_kfcv, _ = cv_plot_points(kfcv, X, y)
plot_stss_cv, _ = cv_plot_points(stss_cv, X, y)
plot_tss_cv, _ = cv_plot_points(tss_cv, X, y)
plot_tssg_cv, _ = cv_plot_points(tssg_cv, X, y)
plot_bcv, _ = cv_plot_points(bcv, X, y)
plot_hvbcv, _ = cv_plot_points(hvbcv, X, y)
plot_mcv, _ = cv_plot_points(mcv, X, y)
plot_mccv, _ = cv_plot_points(mccv, X, y)
plot_mccv2, _ = cv_plot_points_blank(mccv, X, y)
plot_ho, _ = cv_plot_points(ho, X, y)
plot_ho += ylim(1, 1)

plot_kfcv.save('kfcv.pdf', width=WIDTH, height=HEIGHT)
plot_stss_cv.save('stss.pdf', width=WIDTH, height=HEIGHT)
plot_tss_cv.save('tss.pdf', width=WIDTH, height=HEIGHT)
plot_tssg_cv.save('tssg.pdf', width=WIDTH, height=HEIGHT)
plot_bcv.save('bcv.pdf', width=WIDTH, height=HEIGHT)
plot_hvbcv.save('hvbcv.pdf', width=WIDTH, height=HEIGHT)
plot_mcv.save('mcv.pdf', width=WIDTH, height=HEIGHT)
plot_mccv.save('mccv.pdf', width=WIDTH, height=HEIGHT)
plot_mccv2.save('mccv_blank.pdf', width=WIDTH, height=HEIGHT)
plot_ho.save('ho.pdf', width=WIDTH, height=HEIGHT)


import argparse
import subprocess
import time

parser = argparse.ArgumentParser(description=None);
parser.add_argument("-p", "--parties", action="store", required=True, type=int, help="number of parties");
args = parser.parse_args();

num_parties = args.parties
port = 8888

print("Generating config.ini file...")
subprocess.Popen(["sudo", "python3", "generate.py", "-p{}".format(num_parties)]).wait()
print("Finished creating config.ini file")

active_parties = []
print("Starting all nodes\n")
timer = time.time()
for i in range(num_parties):

    active_parties.append(subprocess.Popen(["sudo", "python3", "summation.py", "-P{}".format(port)]))
    port += 1

print(f"It took {time.time() - timer} seconds to start {num_parties} parties")

#Wait for parties to finish
for i in active_parties:
    i.wait()

print("Done")


S = input()

S = set(S)
if 1 not in [len(S&set(t)) for t in ["NS", "WE"]]:
    print("Yes")
else:
    print("No")

################################

# # s=set(input());print("YNeos"[1 in[(len(s&set(t)))for t in["NS","WE"]]::2])
# # s=set;print("NYoe s"[s(input())in map(s,["NS","EW","NSEW"])::2])
# print("NYoe s"[set(input())in map(set,["NS","EW","NSEW"])::2])


import pprint
import time
import  pandas as pd
import requests
from config import *
from concurrent.futures import ThreadPoolExecutor
import  logging

# 灵活配置日志级别,日志格式,输出位置
logging.basicConfig(level=logging.DEBUG,  # 日志类型为DEBUG或者比DEBUG级别更高的类型保存在日志文件中;
                   format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                   datefmt='%a, %d %b %Y %H:%M:%S',
                   filename='lagou.log',
                   filemode='w')

def getPositionIDPage(url_start, url_parse, page=1, kd='python'):
    """

 获取PositionId列表所在页面, 返回的时json数据;
   :param url_start:   图形界面拉勾网职位信息的url地址;为了获取随机的session;
   :param url_parse: 真实返回json格式的url地址
   :param page: 访问的页数
   :param kd: 搜索的关键字
   :return: json数据格式的文本信息;
   """
    # 构造请求头(headers)
    headers = {'User-Agent': ua.random,
               'Host': Host,
               'Origin': Origin,
               'Referer': Referer,
               'Connection': Connection,
               'Accept': Accept

               }

    # 构造表单
    data = {
        'first': False,
        'pn': str(page),
        'kd': kd

    }

    try:
        # requests库的session对象能够帮我们跨请求保持某些参数,
        # 也会在同一个session实例发出的所有请求之间保持cookies。
        # 创建一个session对象
        session = requests.Session()
        # 用session对象发出get请求,设置cookies
        session.get(url_start, headers=headers, timeout=3)  # 请求首页获取cookies
        cookie = session.cookies  # 为此次获取的cookies
        # 用session对象发出另外一个post请求,获取cookies , 返回响应信息
        response = session.post(url=url_parse,
                                headers=headers,
                                data=data,

                                )
        time.sleep(1)
        # 响应状态码为4xx客户端错误,或者5xx服务器错误响应,来抛出异常:
        response.raise_for_status()
        response.encoding = response.apparent_encoding
    except Exception as e:
        logging.error("页面" + url_parse + "爬取失败:", e)
    else:
        logging.info("页面" + url_parse + "爬取成功" + str(response.status_code))
        return response.json()

def analyse_PositionID(html):
   """
  根据获取的页面解析每一个招聘页面详情都有一个所属的ID索引
  :param html:
  :return:
  """
   # tag = 'positionId'
   positions = html['content']['positionResult']['result']
   df = pd.DataFrame(positions)
   return df

def task(page):
    # 拉勾网页面
    url_start = 'https://www.lagou.com/jobs/list_%s' %(keyword)
    # 真实的拉勾网url地址
    url_parse = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult = false'
    # 获取指定页拉勾网的职位信息, 返回的是json反序列化的结果
    html = getPositionIDPage(url_start, url_parse, page=page, kd=keyword)
    # pprint.pprint(content)
    # 解析页面, 返回DataFrame格式的数据;
    df = analyse_PositionID(html)
    return df
if __name__ == '__main__':
    with ThreadPoolExecutor(ThreadCount) as pool:
        results = pool.map(task, range(1, pages+1))
    total_df = pd.concat(results, axis=0)
    total_df.to_csv(csvFileName, index=False,sep=',', header=True )


from openerp import models, fields, api, _
from openerp.exceptions import Warning

class HrAppraisalInput(models.Model):
    _name = 'hr.appraisal.input'
    _inherit = ['mail.thread']
    _description = "Appraisal input"

    name = fields.Char(
        compute='_get_name_hr_appraisal_input', string='Name',
        size=128, store=True)
    appraisal_id = fields.Many2one(
        "hr.appraisal", string="Appraisal", readonly=True, ondelete='restrict')
    author_id = fields.Many2one(
        "hr.employee", string="Author", required=True, readonly=True)
    input_line_ids = fields.One2many(
        'hr.appraisal.input.line', 'input_id', string="Input Lines",
        required=True, readonly=True,
        states={'requested': [('readonly', False)]})
    extra_comments = fields.Text(string="Extra Comments")
    state = fields.Selection(
        [('requested', 'Requested'),
         ('done', 'Done'),
         ('cancel', 'Cancelled')],
        readonly=True, track_visibility='onchange', default='requested')

    @api.multi
    def write(self, vals):
        """
        Security on appraisal input:
        - Manual update: only author can update his input
        - Auto update state from appraisal:
            HR manager can change input state to requested, cancelled
            User must change the state of appraisal input to `done` by himself
        """
        context = self._context or {}
        current_user_id = self._uid
        for appraisal in self:
            author_user_id = appraisal.author_id.user_id and \
                appraisal.author_id.user_id.id or False
            auto_update = context.get('auto_update_from_appraisal')
            if not auto_update and vals and author_user_id != current_user_id:
                raise Warning(_("Only author can update his appraisal input."))
        return super(HrAppraisalInput, self).write(vals)

    @api.multi
    def button_done(self):
        """
        Change state to done
        """
        self.write({'state': 'done'})
        self.send_email()

    @api.multi
    def button_reopen(self):
        """
        Button Done appraisal input:
        - Set state to requested
        - For a done appraisal, do not allow to reopen its inputs
        """
        for line in self:
            if line.appraisal_id.state == 'done':
                raise Warning(
                    _('You cannot reopen this appraisal input'
                      ' because the appraisal has been done already.'))
            line.state = 'requested'

    @api.multi
    def get_url(self):
        """
        Calculate the URL of current appraisal input.
        """
        ParamObj = self.env["ir.config_parameter"]
        link_template = u"{0}#id={1}&view_type=form&model=hr.appraisal.input"
        conf_val = ParamObj.get_param(
            key="web.base.url",
            default=self.get_value_from_param('tms_url_appraisal')
        )
        if not conf_val:
            conf_val = self.get_value_from_param('tms_url_appraisal')
        base_url = conf_val + '/web?db=%s' % self._cr.dbname
        link = link_template.format(base_url, self[0].id)
        return link

    @api.model
    def get_subject(self):
        self.ensure_one()
        res = '[Appraisal Input][Done]: %s by %s' % (
            self.appraisal_id.name, self.author_id.name)
        return res

    @api.model
    def get_value_from_param(self, key):
        ParamObj = self.env["ir.config_parameter"]
        res = ParamObj.get_param(key, 'False')
        return res

    @api.model
    def get_notification_mail_content(self):
        self.ensure_one()
        mail_body = '''
            Dear  HR,

            Employee %s has completed the appraisal "%s"

         ''' % (self.author_id.name, self.appraisal_id.name)
        return mail_body

    @api.multi
    def send_email(self):

        email_template = self.env.ref(
            'trobz_hr_simple_appraisal.'
            'email_template_notification_appraisal_input_done'
        )
        if email_template:
            for appr_input in self:
                email_template.send_mail(
                    appr_input.id, force_send=True, raise_exception=False
                )
        return True

    @api.depends('appraisal_id', 'author_id',
                 'appraisal_id.name', 'author_id.login')
    def _get_name_hr_appraisal_input(self):
        for appraisal_input in self:
            appraisal_input.name = '%s by %s' % (
                appraisal_input.appraisal_id.name,
                appraisal_input.author_id.login)


#!/usr/bin/python3
"""
Solution for N Queens problem
"""

import sys

n = int(sys.argv[1])

for z in range(1, n - 1):
    step = z + 1
    tstep = step
    new_list = [list([0, 0]) for i in range(0, n)]
    for x in range(0, n):
        new_list[x] = [x, tstep - 1]
        tstep += step
        if (tstep > n and n % 2 == 0):
            tstep -= n + 1
        elif (tstep > n and n % 2 == 1):
            tstep -= n
    print(new_list)


import numpy as np
from sklearn.model_selection import KFold

from sklearn.utils import indexable, check_random_state
from sklearn.utils.validation import _num_samples

class ModifiedKFold(KFold):

    def __init__(self,
                 n_splits: int,
                 gap: int = 1,
                 random_state: int = None):
        super().__init__(n_splits=n_splits,
                         shuffle=True,
                         random_state=random_state)

        self.gap = gap

    def split(self, X, y=None, groups=None):

        X, y, groups = indexable(X, y, groups)
        n_samples = _num_samples(X)
        if self.n_splits > n_samples:
            raise ValueError(
                (
                    "Cannot have number of splits n_splits={0} greater"
                    " than the number of samples: n_samples={1}."
                ).format(self.n_splits, n_samples)
            )

        X, y, groups = indexable(X, y, groups)
        indices = np.arange(_num_samples(X))
        for test_index in self._iter_test_masks(X, y, groups):
            train_index = indices[np.logical_not(test_index)]
            test_index = indices[test_index]

            if self.gap > 0:
                dependent_obs = [np.arange(x - self.gap, x + self.gap + 1, 1) for x in test_index]
                gap_zone = np.unique(np.concatenate(dependent_obs))

                train_index = np.setdiff1d(train_index, gap_zone)

            yield train_index, test_index

    def _iter_test_indices(self, X, y=None, groups=None):
        n_samples = _num_samples(X)
        indices = np.arange(n_samples)
        if self.shuffle:
            check_random_state(self.random_state).shuffle(indices)

        n_splits = self.n_splits
        fold_sizes = np.full(n_splits, n_samples // n_splits, dtype=int)
        fold_sizes[: n_samples % n_splits] += 1
        current = 0
        for fold_size in fold_sizes:
            start, stop = current, current + fold_size
            yield indices[start:stop]
            current = stop


# ---
# Created by aitirga at 09/10/2019
# Description: This module contains the gradient descent class
# ---
import os
import time

import matplotlib.pyplot as plt
import numpy as np

from ann_solver.ann_core import ANN
from ann_solver.constants import *

class GradientDescent(ANN):
    def initialize(self, alpha=1e-4, ATOL=ATOL, RTOL=RTOL, always_decrease=False,
                   n=100, plotting=True, n_plot=False, NMAX=NMAX, lambda0=0.0, input_set_type="full",
                   momentum_g=0.8, norm=False, n_batch=25, plot_contour=False, n_contour=(100, 100),
                   momentum=False, avoid_cf=False):
        """

        :param always_decrease:
        :param norm:
        :param n_batch:
        :param alpha: initial learning rate
        :param ATOL: absolute tolerance, if the change in cost function between consecutive steps is less than ATOL,
        the algorithm converges
        :param RTOL: relative tolerance, if the change in costa function compared to the initial one is less than RTOL,
        the algorithm converges
        not do that, an error is raised
        :param n: parameter that controls the number of steps before updating the plots
        :param plotting:
        :param n_plot:
        :param NMAX: maximum number of timesteps, if the algorithm performs more timesteps, it raises an error
        :param lambda0: regularization parameter
        :param input_set_type: sets the criteria to use the input file in the calculation of the gradient descent:
        "full" to use the whole dataset, "batch" to do batches of n_batch elements and "stochastic" to use one
        input every step
        :param momentum_g: sets the momentum constant
        :param plot_contour: Set it True to dinamically plot a contour plot of the results
        :param n_contour: number of elements on the contour plot
        :param momentum: Set it True to use momentum and "Nesterov" to use the Nesterov momentum
        :param avoid_cf: Set it True to only compute the cost function at the plotting timesteps set by n
        :return:
        """
        # Perform gradient descent minimization algorithm using the provided learning rate.
        # It uses a fixed number of learning steps
        # Parameters for live plotting
        self.input_set_type = input_set_type
        self.n_batch = n_batch
        self.plotting = plotting
        self.time_start = time.time()
        self.time_0 = self.time_start
        self.lambda0 = lambda0  # Regularization term
        self.gamma = momentum_g  # The momentum term
        self.alpha = alpha  # Step size
        self.alpha0 = alpha  # Initial step size (default)
        self.ATOL = ATOL
        self.RTOL = RTOL
        self.NMAX = NMAX
        self.momentum = momentum
        self.tol["AlwaysDecrease"]["Value"] = always_decrease
        self.x_backup = self.x
        self.avoid_CF = avoid_cf
        self.plotting = plotting
        self.plot_contour = plot_contour
        self.n_contour = n_contour
        self.n = n

        if not n_plot:
            self.n_plot = self.n
        else:
            self.n_plot = n_plot
        self.Time = []
        self.CF = []

        # Automatic tolerance stop (ATOL)
        self.nsim = 0
        # Velocities matrix for the momentum implementation

        if norm:  # Specifies if the input X vector should be normalized
            if not self.normalized:
                ANN.normalize_x_stdmean(self)

    def run_gradient_descent(self):
        line1 = []
        io.print_gradient_descent_intro(self)
        self.n_plot_list = []
        self.CF_plot_list = []
        # First timestep cf calculation
        temp_CF = ANN.cost_function(self)
        self.n_plot_list.append(self.nsim)
        self.CF_plot_list.append(temp_CF)
        line1 = ANN.plot_CF(self, line1)
        contour = []
        while 1:
            if self.adaptive_learning_rate:
                self.alpha = GradientDescent.adaptive_learning_rate(self)
            GradientDescent.compute_gradient_and_update_weights(self)
            # ANN.update_weights(self)
            if GradientDescent.evaluate_tolerances(self, self.ATOL, self.RTOL, self.NMAX):
                break
            if self.avoid_CF:
                pass
            else:
                temp_CF = ANN.cost_function(self)
                self.CF.append(temp_CF)
            GradientDescent.evaluate_tolerances(self, self.ATOL, self.RTOL, self.NMAX)
            if float(self.nsim) % self.n == 0.0:
                if self.avoid_CF:
                    temp_CF = ANN.cost_function(self)
                    self.CF.append(temp_CF)
                print("Learning step %s, cost function value: %s" % (self.nsim, temp_CF))
                ANN.print_tolerances(self)
                if self.plot_contour:
                    contour = ANN.live_plotter_contour(self, contour, self.n_contour)
                # ANN.check_gradient(self)
            self.nsim += 1
            if self.plotting:
                if float(self.nsim) % self.n == 0:
                    self.n_plot_list.append(self.nsim)
                    self.CF_plot_list.append(temp_CF)
                    line1 = ANN.plot_CF(self, line1)
        io.sim_status(self)
        plt.ioff()

    def adaptive_learning_rate(self):
        return self.dict_learning_rate[self.adaptive_learning_rate_type](self, **self.adaptive_learning_rate_args)

    def compute_gradient_and_update_weights(self):
        if not self.momentum == "nesterov":
            ANN.compute_gradient(self)
        if self.momentum == "nesterov":
            self.Theta += np.multiply(self.alpha, self.v_momentum)
            ANN.compute_gradient(self)
        if self.momentum == True or self.momentum == "yes":
            self.v_momentum = np.multiply(self.gamma, self.v_momentum) - np.multiply(self.alpha, self.D)
            self.Theta += self.v_momentum
        if self.momentum == "nesterov":
            self.v_momentum = np.multiply(self.gamma, self.v_momentum) - np.multiply(self.alpha, self.D)
            self.Theta += self.v_momentum
        if not self.momentum:
            self.Theta -= np.multiply(self.alpha, self.D)

    def evaluate_tolerances(self, ATOL=1E-2, RTOL=1E-4, NMAX=100000, AlwaysDecrease=False):
        if len(self.CF) > 1:
            self.tol["ATOL"]["Value"] = abs(self.CF[-2] - self.CF[-1])
            self.tol["RTOL"]["Value"] = abs(self.CF[-2] - self.CF[-1]) / (abs(self.CF[-1] - self.CF[0] + self.eps))
            self.tol["NMAX"]["Value"] = self.nsim
            if (self.tol["AlwaysDecrease"]["Value"] == 1.0) and (self.CF[-1] - self.CF[-2] > 0.0):
                self.tol["AlwaysDecrease"]["Status"] = True
            if self.tol["ATOL"]["Value"] < ATOL:
                self.tol["ATOL"]["Status"] = True
            if self.tol["RTOL"]["Value"] < RTOL:
                self.tol["RTOL"]["Status"] = True
            if self.tol["NMAX"]["Value"] > NMAX:
                self.tol["NMAX"]["Status"] = True
        for i in self.tol:
            if self.tol[i]["Status"]:
                return True

class io(GradientDescent):
    """Input/output control class for GradientDescent
    This class contains the functions to print output data regarding the evolution of the GradientDescent algorithm
    """

    def sim_status(self):
        reason = {}
        for i in self.tol:
            if self.tol[i]["Status"]:
                reason[i] = self.tol[i]
        print("************ Training finished ************\n")
        print("*******************************************")
        print("********** ANN training status ************")
        print("*******************************************")
        print("The training of the neural network has finished")
        print("Total training time: %s s" % (time.time() - self.time_start))
        print("Simulation steps: %s" % self.nsim)
        print("Value of the minimized Cost Function %s" % self.CF[-1])
        print("Reason for termination: %s" % reason)
        print("****************** END ********************\n")
        os.system('pause')

    def print_gradient_descent_intro(self):
        print("*******************************************")
        print("**** Gradient descent training utility ****")
        print("*******************************************")
        print("Gradient descent utility properties:")
        print("\tLearning rate: %s" % self.alpha)
        if self.plotting:
            print("\tPlotting CF evolution")
        print("Regularization term: %s" % self.lambda0)
        print("Input set for gradient calculation: %s" % self.input_set_type)
        if self.input_set_type == "batch":
            print("Batch elements: %s" % self.n_batch)
        print("Gradient acceleration: %s" % self.momentum)
        print("\tTolerances:")
        print("\t\tATOL: %s" % self.ATOL)
        print("\t\tRTOL: %s" % self.RTOL)
        print("\t\tNMAX: %s" % self.NMAX)
        print("************ Training started *************")


criptograma = "UJ PDNAAJ MN ERNCWJV ODNDWLXWOURLCXKNURLXYJAJRVYNMRAUJANDWRORLJLRXWMNERNCWJVKJSXDWPXKRNAWXLXVDWRBCJNWM"
print("Criptograma: " + criptograma)

for d in range(0,26):
    mensaje = ""
    for c in range(len(criptograma)):
        letra = criptograma[c]
        mensaje += chr((ord(letra) + d - 65) % 26 + 65)

    print("Desplazamiento {}\t: {}".format(str(d), mensaje))


"""Write a Python program to SORT and print the result data of the above table.
User must have option to choose the Sorting parameter
[1. Sort by P_ID, 2. Sort by Start Time, 3. Sort by Priority]"""
flight_Table = [
    {'P_ID': 'P1', 'Process':  'VSCode', 'Start Time': 100, 'Priority':  'MID'},
{'P_ID': 'P23', 'Process': 'Eclipse', 'Start Time': 234 , 'Priority': 'MID'},
{'P_ID': 'P93', 'Process': 'Chrome', 'Start Time': 189 , 'Priority': 'High'},
{'P_ID': 'P42', 'Process': 'JDK', 'Start Time': 9, 'Priority':  'High'},
{'P_ID': 'P9', 'Process': 'CMD', 'Start Time': 7, 'Priority':  'High'},
{'P_ID': 'P87', 'Process': 'NotePad', 'Start Time': 23, 'Priority':  'Low'}
]

def sort_data(data, sort_by):
    if sort_by == 'P_ID':
        return sorted(data, key=lambda x: x['P_ID'])
    elif sort_by == 'Start Time':
        return sorted(data, key=lambda x: x['Start Time'])
    elif sort_by == 'Priority':
        return sorted(data, key=lambda x: x['Priority'])
    else:
        return data

sort_by = input("Enter the sorting parameter (P_ID, Start Time, Priority): ")

sorted_data = sort_data(flight_Table, sort_by)

for item in sorted_data:
    print(item)


import os
import numpy as np

from dataclasses import dataclass
from typing import Dict, Union, NamedTuple

import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, RandomSampler, SequentialSampler, DataLoader
from torch.utils.data.distributed import DistributedSampler

from pyutils.display import maybe_tqdm
import pyutils.io as io

from nlpr.tasks.core import BatchMixin
from nlpr.shared.pycore import ExtendedDataClassMixin
from nlpr.shared.model_setup import OptimizerScheduler
from nlpr.shared.modeling.models import forward_batch_delegate, compute_loss_from_model_output
import nlpr.tasks.evaluate as evaluate

class BaseRunner:
    pass

@dataclass
class TrainGlobalState(ExtendedDataClassMixin):
    epoch: int = 0
    epoch_step: int = 0
    global_step: int = 0

    def step(self):
        self.global_step += 1
        self.epoch_step += 1

    def step_epoch(self):
        self.epoch += 1
        self.epoch_step = 0

    def __str__(self):
        return f"TGS({self.epoch} / {self.epoch_step} ({self.global_step}))"

@dataclass
class DatasetWithMetadata:
    dataset: TensorDataset
    metadata: Dict

    def get_descriptor_dict(self):
        return {
            descriptor.name: descriptor
            for descriptor in self.metadata["descriptors"]
        }

@dataclass
class DataDescriptor:
    category: str
    # category=dataset: Tensor
    # category=other: metadata to carry around be batch
    # category=none: don't propagate
    name: str
    pos: Union[int, None]
    # Tensor position. Only use if category=dataset

def convert_examples_to_dataset(examples, tokenizer, feat_spec, task, verbose=False):
    data_rows = [
        example.tokenize(tokenizer).featurize(tokenizer, feat_spec)
        for example in maybe_tqdm(examples, desc="Tokenizing", verbose=verbose)
    ]
    full_batch = task.Batch.from_data_rows(data_rows)
    dataset_with_metadata = full_batch_to_dataset(full_batch)
    dataset_with_metadata.metadata["descriptors"].append(
        DataDescriptor("other_metadata", "example_id", None)
    )
    dataset_with_metadata.metadata["other"]["example_id"] = list(range(len(examples)))
    return dataset_with_metadata

def full_batch_to_dataset(full_batch):
    dataset_ls = []
    others_dict = {}
    descriptors = []
    for i, (k, v) in enumerate(full_batch.asdict().items()):
        if isinstance(v, torch.Tensor):
            descriptors.append(DataDescriptor("dataset", k, len(dataset_ls)))
            dataset_ls.append(v)
        elif v is None:
            descriptors.append(DataDescriptor("none", k, None))
        else:
            descriptors.append(DataDescriptor("other_data", k, None))
            others_dict[k] = v
    dataset_ls.append(torch.arange(len(full_batch)))
    return DatasetWithMetadata(
        dataset=TensorDataset(*dataset_ls),
        metadata={
            "descriptors": descriptors,
            "other": others_dict,
        }
    )

class BatchTuple(NamedTuple):
    batch: BatchMixin
    metadata: dict

    def to(self, device):
        return BatchTuple(
            batch=self.batch.to(device),
            metadata=self.metadata,
        )

class HybridLoader:
    def __init__(self, dataloader, metadata, task):
        self.dataloader = dataloader
        self.metadata = metadata
        self.task = task

    @property
    def dataset_with_metadata(self):
        return DatasetWithMetadata(
            dataset=self.dataloader.dataset,
            metadata=self.metadata,
        )

    def __iter__(self):
        for batch in self.dataloader:
            example_ids = batch[-1]
            batch_dict = {}
            batch_metadata_dict = {"example_id": example_ids}
            for descriptor in self.metadata["descriptors"]:
                if descriptor.category == "dataset":
                    batch_dict[descriptor.name] = batch[descriptor.pos]
                elif descriptor.category == "none":
                    batch_dict[descriptor.name] = None
                elif descriptor.category == "other_data":
                    batch_dict[descriptor.name] = [
                        self.metadata["other"][descriptor.name][i]
                        for i in example_ids
                    ]
                elif descriptor.category == "other_metadata":
                    batch_metadata_dict[descriptor.name] = [
                        self.metadata["other"][descriptor.name][i]
                        for i in example_ids
                    ]
                else:
                    raise KeyError(descriptor.category)
            yield BatchTuple(
                batch=self.task.Batch(**batch_dict),
                metadata=batch_metadata_dict,
            )

    def __len__(self):
        return len(self.dataloader)

def get_sampler(dataset, local_rank, force_sequential=False):
    if force_sequential:
        return SequentialSampler(dataset)
    if local_rank == -1:
        return RandomSampler(dataset)
    else:
        return DistributedSampler(dataset)

def run_val(val_examples, val_dataloader,
            model, task, loss_criterion,
            device, local_rank, verbose):
    if not local_rank == -1:
        return
    model.eval()
    total_eval_loss = 0
    nb_eval_steps, nb_eval_examples = 0, 0
    all_logits = []
    for step, (batch, batch_metadata) in enumerate(
            maybe_tqdm(val_dataloader, desc="Evaluating (Val)", verbose=verbose)):
        batch = batch.to(device)

        with torch.no_grad():
            logits = forward_batch_delegate(
                model=model,
                batch=batch,
                omit_label_ids=True,
                task_type=task.TASK_TYPE,
            )[0]
            tmp_eval_loss = compute_loss_from_model_output(
                logits=logits,
                loss_criterion=loss_criterion,
                batch=batch,
                task_type=task.TASK_TYPE,
            )

        logits = logits.detach().cpu().numpy()
        total_eval_loss += tmp_eval_loss.mean().item()

        nb_eval_examples += len(batch)
        nb_eval_steps += 1
        all_logits.append(logits)
    eval_loss = total_eval_loss / nb_eval_steps
    all_logits = np.concatenate(all_logits, axis=0)

    return {
        "logits": all_logits,
        "loss": eval_loss,
        "metrics": evaluate.compute_task_metrics(task, all_logits, val_examples),
    }

def get_train_dataloader(train_examples, task,
                         tokenizer, feat_spec, local_rank, train_batch_size, verbose=True):
    dataset_with_metadata = convert_examples_to_dataset(
        examples=train_examples,
        feat_spec=feat_spec,
        tokenizer=tokenizer,
        task=task,
        verbose=verbose,
    )
    train_sampler = get_sampler(
        dataset=dataset_with_metadata.dataset,
        local_rank=local_rank,
    )
    train_dataloader = DataLoader(
        dataset=dataset_with_metadata.dataset,
        sampler=train_sampler,
        batch_size=train_batch_size,
    )
    return HybridLoader(
        dataloader=train_dataloader,
        metadata=dataset_with_metadata.metadata,
        task=task,
    )

def get_eval_dataloader(eval_examples, task,
                        tokenizer, feat_spec, eval_batch_size):
    dataset_with_metadata = convert_examples_to_dataset(
        examples=eval_examples,
        feat_spec=feat_spec,
        tokenizer=tokenizer,
        task=task,
    )
    eval_sampler = SequentialSampler(dataset_with_metadata.dataset)
    eval_dataloader = DataLoader(
        dataset=dataset_with_metadata.dataset,
        sampler=eval_sampler,
        batch_size=eval_batch_size,
    )
    return HybridLoader(
        dataloader=eval_dataloader,
        metadata=dataset_with_metadata.metadata,
        task=task,
    )

def complex_backpropagate(loss, optimizer, model,
                          fp16, n_gpu, gradient_accumulation_steps, max_grad_norm):
    if n_gpu > 1:
        loss = loss.mean()  # mean() to average on multi-gpu.
    if gradient_accumulation_steps > 1:
        loss = loss / gradient_accumulation_steps
    if fp16:
        # noinspection PyUnresolvedReferences
        from apex import amp
        with amp.scale_loss(loss, optimizer) as scaled_loss:
            scaled_loss.backward()
        torch.nn.utils.clip_grad_norm_(amp.master_params(optimizer), max_grad_norm)
    else:
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_grad_norm)
    return loss

def optim_step_grad_accum(optimizer_scheduler: OptimizerScheduler,
                          train_global_state: TrainGlobalState,
                          gradient_accumulation_steps: int):
    if (train_global_state.epoch_step + 1) % gradient_accumulation_steps == 0:
        optimizer_scheduler.step()
        optimizer_scheduler.optimizer.zero_grad()
        train_global_state.global_step += 1

def save_model_with_metadata(model: nn.Module, metadata: dict, output_dir: str, file_name="model"):
    torch.save(
        model.state_dict(),
        os.path.join(output_dir, f"{file_name}.p")
    )
    io.write_json(
        metadata,
        os.path.join(output_dir, f"{file_name}.metadata.json")
    )

def compare_steps_max_steps(step, max_steps):
    return (
        max_steps is not None
        and max_steps != -1
        and step >= max_steps
    )


class BinarySearchTree:
    # left: BinarySearchTree
    # right: BinarySearchTree
    # key: int
    # item: int
    # size: int
    def __init__(self, debugger = None):
        self.left = None
        self.right = None
        self.key = None
        self.item = None
        self._size = 1
        self.debugger = debugger

    @property
    def size(self):
         return self._size

     # a setter function
    @size.setter
    def size(self, a):
        debugger = self.debugger
        if debugger:
            debugger.inc_size_counter()
        self._size = a

    ####### Part a #######
    '''
    Calculates the size of the tree
    returns the size at a given node
    '''
    def calculate_sizes(self, debugger = None):
        # Debugging code
        # No need to modify
        # Provides counts
        if debugger is None:
            debugger = self.debugger
        if debugger:
            debugger.inc()

        # Implementation
        self.size = 1
        if self.right is not None:
            self.size += self.right.calculate_sizes(debugger)
        if self.left is not None:
            self.size += self.left.calculate_sizes(debugger)
        return self.size

    '''
    Select the ind-th key in the tree

    ind: a number between 0 and n-1 (the number of nodes/objects)
    returns BinarySearchTree/Node or None
    '''
    def select(self, ind):
        left_size = 0
        if self.left is not None:
            left_size =self.left.size
        if ind == left_size:
            return self
        if left_size > ind and self.left is not None:
            return self.left.select(ind)
        if left_size < ind and self.right is not None:
            """ Changed code to account for the size of the left-hand tree
            and number of nodes above it
            """
            return self.right.select(ind - left_size - 1)
        return None

    '''
    Searches for a given key
    returns a pointer to the object with target key or None (Roughgarden)
    '''
    def search(self, key):
        if self is None:
            return None
        elif self.key == key:
            return self
        elif self.key < key and self.right is not None:
            return self.right.search(key)
        elif self.left is not None:
            return self.left.search(key)
        return None

    '''
    Inserts a key into the tree
    key: the key for the new node;
        ... this is NOT a BinarySearchTree/Node, the function creates one

    returns the original (top level) tree - allows for easy chaining in tests
    '''
    def insert(self, key):
        if self.key is None:
            self.key = key
        elif self.key > key:
            if self.left is None:
                self.left = BinarySearchTree(self.debugger)
            self.left.insert(key)
            """ calculate_sizes takes O(n) time, revise to take O(h)
            by adding one to each node"""
            self.size += 1
        elif self.key < key:
            if self.right is None:
                self.right = BinarySearchTree(self.debugger)
            self.right.insert(key)
            self.size += 1
        return self

    ####### Part b #######

    '''
    Performs a `direction`-rotate the `side`-child of (the root of) T (self)
    direction: "L" or "R" to indicate the rotation direction
    child_side: "L" or "R" which child of T to perform the rotate on
    Returns: the root of the tree/subtree
    Example:
    Original Graph
      10
       \
        11
          \
           12

    Execute: NodeFor10.rotate("L", "R") -> Outputs: NodeFor10
    Output Graph
      10
        \
        12
        /
       11
    '''
    def rotate(self, direction, child_side):
        if direction == "R":
            if child_side == "L":
                # Define variables
                x = self.left
                y = x.left

                # Rotate
                x.left = y.right
                y.right = x

                # Change y
                self.left = y

                # Change sizes
                x.size = 1
                y.size = 1

                if y.right:
                    y.size += y.right.size
                if y.left:
                    y.size += y.left.size

                if x.right:
                    x.size += x.right.size
                if x.left:
                    x.size += x.left.size

                self.left.size = x.size

            if child_side == "R":
                # Define variables
                x = self.right
                y = x.left

                # Rotate
                x.left = y.right
                y.right = x

                # Change y
                self.right = y

                # Change sizes
                x.size = 1
                y.size = 1

                if y.right:
                    y.size += y.right.size
                if y.left:
                    y.size += y.left.size

                if x.right:
                    x.size += x.right.size
                if x.left:
                    x.size += x.left.size

                self.right.size = x.size

        if direction == "L":
            if child_side == "L":
                # Define nodes
                x = self.left
                y = x.right

                # Rotate
                x.right = y.left
                y.left = x

                # Change y
                self.left = y

                # Change sizes
                x.size = 1
                y.size = 1

                if y.right:
                    y.size += y.right.size
                if y.left:
                    y.size += y.left.size

                if x.right:
                    x.size += x.right.size
                if x.left:
                    x.size += x.left.size

                self.left.size = x.size

            if child_side == "R":
                # Define nodes
                x = self.right
                y = x.right

                # Rotate
                x.right = y.left
                y.left = x

                # Change y
                self.right = y

                # Change sizes
                x.size = 1
                y.size = 1

                if y.right:
                    y.size += y.right.size
                if y.left:
                    y.size += y.left.size

                if x.right:
                    x.size += x.right.size
                if x.left:
                    x.size += x.left.size

                self.right.size = x.size
        return self

    def print_bst(self):
        if self.left is not None:
            self.left.print_bst()
        print( self.key),
        if self.right is not None:
            self.right.print_bst()
        return self


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# Función para estructurar los datos recibidos de txt a un dataframe
def structure_data(file):
    data = {"E": [], "J": []}

    with open(file) as f:
        for line in f.readlines():
            line_array = line.split()
            for i in range(len(line_array)):

                if i == 1:
                    data["J"].append(float(line_array[i]))

                if i == 0:
                    data["E"].append(float(line_array[i]))

    return pd.DataFrame(data)

# Función para analizar eléctricamente una determinada muestra, ajustando los datos al modelo
def sample_analysis(df):

    # Instanciar las variables de corte
    x_inicial = 0
    x_prerruptura = 10
    x_ruptura = 20
    x_final = len(df)

    # Variables de ajuste
    min_r2_exponential = 0.99
    min_r2_lineal = 0.80

    # Ajuste de curva lineal : Evaluación para determinar el inicio del punto de ruptura
    # El ajuste se explora fijando un punto en la izquierda y recorriendo a la derecha
    # la operación termina una vex que el score alcanza un valor adecuado (0.95)

    err_lineal = 100
    for i in range(len(df) - 1):
        # Generar el modelo lineal
        x_lineal = np.array(df[x_inicial: x_final - i]["E"]).reshape((-1, 1))
        y_lineal = np.array(df[x_inicial: x_final - i]["J"])
        lineal_reg = LinearRegression().fit(x_lineal, y_lineal)

        # Predecir la recta y evaluar el error recorriendo la curva a la derecha
        y_lineal_fit = lineal_reg.predict(x_lineal)
        score = "{0:.2f}".format(lineal_reg.score(x_lineal, y_lineal))
        lineal_coefficient = lineal_reg.coef_[0]
        lineal_intercept = lineal_reg.intercept_

        if float(score) >= min_r2_lineal:
            print(score)
            x_prerruptura = x_final - i
            break

    # Ajuste de curva exponencial : En este caso, el ajuste de curva se realiza en el sentido contrario,
    # Fijando el punto al final de la gráfica y recortando los datos de la izquierda hasta llegar a una
    # evaluación adecuada (0.90). Es necesario establecer que no se considera el efecto joule

    err_exponecial = 100
    for i in range(x_prerruptura + 1, len(df)):
        # Calcular el valor de alfa
        alfa_array = []
        for j in range(i, len(df) - 1):
            try:
                alfa = ((np.log(df["J"][j + 1]) - np.log(df["J"][j])) / (np.log(df["E"][j + 1]) - np.log(df["E"][j])))
                alfa_array.append(alfa)
            except:
                print("Error in alfa calculation")

        x_exponential = df[i:x_final]["E"]
        y_exponential = df[i:x_final]["J"]

        log_y = np.log(y_exponential)

        fit = np.polyfit(x_exponential, log_y, 1)
        y_exponential_fit = np.exp(fit[1]) * np.exp(fit[0]*x_exponential)

        score = r2_score(y_exponential, y_exponential_fit)

        if score > min_r2_exponential:
            x_ruptura = i
            print("hola" + str(np.exp(fit[1]))+ " " + str(fit[0]))

            print("MEDIA DE ALFA:", np.mean(alfa_array))
            print("DISTRIBUCIÓN ESTÁNDAR DE ALFA:", np.std(alfa_array))
            print("MÍNIMO DE ALFA:", min(alfa_array))
            print("MÁXIMO DE ALFA:", max(alfa_array))
            print("- - - - - - - - - - - - - - - - - - -")

            break

    # Impresión de las zonas
    print("ZONA ÓHMICA: ", str(x_inicial), ": ", str(x_prerruptura))
    print("ZONA DE TRANSICIÓN: ", str(x_prerruptura + 1), ": ", str(x_ruptura))
    print("ZONA NO-ÓHMICA: ", str(x_ruptura + 1), ": ", str(x_final))
    print("- - - - - - - - - - - - - - - - - - -")

    # Graficar los ajustes del modelo
    plt.scatter(df["E"], df["J"], c="r")
    # Definición de las ecuaciones de ajuste
    try:
        E_entre_R = np.power(y_exponential_fit, (1/np.mean(alfa_array)))   # sentido físico de la exponencial
        physical_exponential_fit = np.array(E_entre_R)**np.mean(alfa_array)
        plt.plot(x_exponential, physical_exponential_fit, c="b",
        label="Exponential Fit2:" + "(V/R)^" + str("{0:.2f}".format(np.mean(alfa_array))))
    except:
        print("NO HAY COMPORTAMIENTO EXPONENCIAL")

    try:
        plt.plot(x_lineal, y_lineal_fit, c="b", label="Lineal Fit: " + str("{0:.2f}".format(lineal_coefficient)) + "x"
                                                 + " + " + str("{0:.2f}".format(lineal_intercept)))
        print(lineal_intercept)
    except:
        print("NO HAY COMPORTAMIENTO LINEAL")
    plt.grid()
    plt.legend()
    plt.title("CAMPO ELÉCTRICO CONTRA DENSIDAD DE CORRIENTE")
    plt.xlabel("CAMPO ELÉCTRICO (V/cm)")
    plt.ylabel("DENSIDAD DE CORRIENTE (A/cm^2)")
    plt.show()

# Función para graficar la data que se recibe
def graph_data(df):
    plt.plot(df["E"], df["J"])
    plt.scatter(df["E"], df["J"], c="r")
    plt.grid()
    plt.title("CAMPO ELÉCTRICO CONTRA DENSIDAD DE CORRIENTE")
    plt.xlabel("CAMPO ELÉCTRICO (V/cm)")
    plt.ylabel("DENSIDAD DE CORRIENTE (A/cm^2)")
    plt.show()

file0 = 'Pruebas_electricas_1.txt'
file1 = 'Prueba1Eq1.txt'
file2 = 'Prueba2Eq1.txt'
file3 = 'Prueba3Eq1.txt'
file4 = 'Prueba4Eq1.txt'

df = structure_data(file0)
sample_analysis(df)


import socket

ip = "127.0.0.1"
port = 4444

server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print("Socket Succesfully Created")
server.bind((ip, port))
print("Socket Succesfully Binded")
server.listen(5)
print("Socket is Listening..")

while True:
    client, address = server.accept ()
    print (f"Connection Estabished {address}")
    string = client.recv(1024)
    string = string.decode("utf-8")
    string = string.upper()
    client.send(bytes (string, "utf-8"))
    client.close ()
    break


import sys

def gen(n, count_l, count_r, sequence):
    if count_l + count_r == n:
        if abs(count_r - count_l) % 4 == 0:
            print(sequence)
        return
    gen(n, count_l + 1, count_r, sequence + 'L')
    gen(n, count_l, count_r + 1, sequence + 'R')

sys.stdout = open("sequences.txt", "w")
for i in range(2, 17, 2):
    gen(i, 0, 0, "")


import sys

input = sys.stdin.readline

N, M = map(int, input().split())

# conditions: bit weights
vowels = 'aeiou'
cons = 'bcdfghjklmnpqrstvwxyz'

bit_weights = dict()
for i in range(len(cons)):
    bit_weights[cons[i]] = i

# preprocessing
words = []

for i in range(N):
    # input word
    temp = set()
    for c in input().strip():
        temp.add(c)

    # input word -> bits
    num = 0
    for c in temp:
        if c in vowels:
            continue
        else:
            num += 1 << bit_weights.get(c)

    words.append(num)

# func
current_bits = (1 << 21) - 1  # all 21-bits to 1

for i in range(M):
    o, x = input().split()

    # do
    if o == '1':
        current_bits -= 1 << bit_weights.get(x)
    else:
        current_bits += 1 << bit_weights.get(x)

    # count
    cnt = 0
    for word in words:
        if current_bits & word == word:
            cnt += 1

    # print
    print(cnt)


import math
def cilinder_square():
    side = 2 * math.pi * radius * height
    cicle_square = math.pi * (radius ** 2)
    return side, cicle_square

height = int(input('Высота цилиндра: '))
radius = int(input('Радиус цилиндра: '))

full = cilinder_square()[0] + 2 * cilinder_square()[1]
print(f'Площадь цилиндра {round(full, 2)}')

2. Цилиндр.py


class Sieve:
    def __init__(self, n: int, sieve_max=100_000_000):
        self.sieve_max = sieve_max
        self.values = self.sieve(n)

    def sieve(self, n: int) -> [int]:
        """takes n and returns a list of all primes from 2 to n using
        the sieve of Eratosthenes"""
        if n > self.sieve_max:
            raise ValueError(f"{n} exceeds max sieve value ({self.sieve_max}). To override, manually set Sieve's `sieve_max` attribute")

        print(f'setting search_max to {n}')
        self.search_max = n

        if n < 2:
            return []
        arr = [True] * (n+1)
        for i in range(2, n+1):
            if arr[i]:
                for j in range(i ** 2, n+1, i):
                    arr[j] = False

        return [i for i in range(2,n+1) if arr[i]]

    def is_prime(self, n: int) -> bool:
#         print(f'checking if {n} is prime')
        if n < 2:
            return False

        if n <= self.search_max:
            return n in self.values

        print(f"{n} exceeds search max ({self.search_max})")

        # Re-perform sieve and update self.values
        self.values = self.sieve(n)
        return n in self.values

    def prime_factors(self, n: int) -> [int]:
        print(f'looking for factors of {n}')

        if n < 2:  # no prime factors
            return []

        if n > self.search_max:
            print(f'expanding search max from {self.search_max}...')
            self.values = self.sieve(n)
            print(f'...done')

        for prime in self.values:
            if n % prime == 0:
                print(prime)
                return [prime] + self.prime_factors(int(n/prime))

        return []

# Example usage:
# --------------
MAX_VALUE = 1_000

sieve = Sieve(MAX_VALUE)

sieve.search_max  # 1000
sieve.values  # all the primes <= 1000, [2,3,5,...,983,991,997]

sieve.is_prime(999_999)  # False
sieve.values  # all the primes <= 999,999 [2,3,5,...,etc]

pf = sieve.prime_factors(231_510_111)  # ValueError: n exceeds max sieve value

sieve.sieve_max = 250_000_000  # produces about 12.7M primes, might take up to a minute or so.
pf = sieve.prime_factors(231_510_111)  # [3, 7, 23, 479317]

from functools import reduce
reduce(lambda x,y: x*y, pf)  # 231,510,111


import os
from google.cloud.devtools import cloudbuild_v1

client = cloudbuild_v1.services.cloud_build.CloudBuildClient()

def validate(event, context):
    """Triggered by a change to a Cloud Storage bucket.
    Args:
        event (dict): Event payload.
        context (google.cloud.functions.Context): Metadata for the event.
    """

    build = cloudbuild_v1.Build()

    core_org_id = os.environ.get('ORG_ID')
    project_id = os.environ.get('PROJECT_ID')
    region_name = os.environ.get('REGION')
    trigger_branch = os.environ.get('BRANCH')
    csr_repo_name = os.environ.get('REPO_NAME')
    asset_inventory_bucket_name = os.environ.get('ASSET_INVENTORY_GCS_BUCKET')
    guardrails_artifact_registry_name = os.environ.get('GUARDRAILS_ARTIFACT_REGISTRY_NAME')
    guardrails_report_bucket_name = os.environ.get('GUARDRAILS_REPORTS_GCS_BUCKET')
    guardrails_report_bucket_name_suffix = os.environ.get('GUARDRAILS_REPORTS_GCS_BUCKET_SUFFIX')
    guardrails_policies_container_name = os.environ.get('GUARDRAILS_POLICIES_CONTAINER_NAME')
    guardrails_policies_container_tag = os.environ.get('GUARDRAILS_POLICIES_CONTAINER_TAG')

    folder = event['name'].split('/')[0]
    filename = event['name'].split('/')[1]
    inventory_org_id = filename.split('.')[0]

    build.steps = [
        {
            "name": "gcr.io/cloud-builders/gcloud",
            "args": ["cp","gs://{}/{}".format(asset_inventory_bucket_name,event['name']),"/assets/asset_inventory.json"],
            "entrypoint": "gsutil"
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": ["-c","cp /assets/asset_inventory.json assets"],
            "entrypoint": "bash"
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": ["run","-v","/workspace/guardrails-validation:/app","{}-docker.pkg.dev/{}/{}/{}:{}".format(region_name,project_id,guardrails_artifact_registry_name,guardrails_policies_container_name,guardrails_policies_container_tag)],
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": ["-c","cat report.txt"],
            "entrypoint": "bash"
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": ["-c","cp report.txt /assets/{}".format(filename)],
            "entrypoint": "bash"
        },
        {
            "name": "gcr.io/cloud-builders/gcloud",
            "args": ["cp","/assets/{}".format(filename), "gs://{}/{}/{}.txt".format(guardrails_report_bucket_name,folder,inventory_org_id)],
            "entrypoint": "gsutil"
        }
    ]

    # Send to remote bucket if scanning remote organization
    if core_org_id.strip() != inventory_org_id.strip():
        remote_report_bucket_name = "{}-{}".format(inventory_org_id,guardrails_report_bucket_name_suffix)
        build.steps.append({
            "name": "gcr.io/cloud-builders/gcloud",
            "args": ["cp","/assets/{}".format(filename), "gs://{}/{}/{}.txt".format(remote_report_bucket_name,folder,inventory_org_id)],
            "entrypoint": "gsutil"
        })

    build.options = {
        "volumes": [
            {
                "name": "assets",
                "path": "/assets"
            }
        ]
    }

    build.source = {
        "repo_source":{
            "project_id": project_id,
            "repo_name": csr_repo_name,
            "branch_name": trigger_branch,
            "dir_": "guardrails-validation"
        }
    }

    result = client.create_build(project_id=project_id, build=build)
    return result


'''
INFO 523 Final Project DBSCAN code
https://www.kaggle.com/code/rpsuraj/outlier-detection-techniques-simplified
'''

import pandas as pd
from sklearn.cluster import DBSCAN
import matplotlib.pyplot as plt

df = pd.read_csv("fetal_health.csv")
X = df[['abnormal_short_term_variability', 'baseline value']].values
db = DBSCAN(eps=3.0, min_samples=10).fit(X)

labels = db.labels_
#print(pd.Series(labels).value_counts())

plt.figure()
unique_labels = set(labels)
colors = ['blue', 'red']

for color, label in zip(colors, unique_labels):
    sample_mask = [True if l == label else False for l in labels]
    plt.plot(X[:,0][sample_mask], X[:, 1][sample_mask], 'o', color=color)

plt.xlabel('abnormal_short_term_variability')
plt.ylabel('baseline value')
plt.show()


# Lisa's Workbook
# A workbook with chapters. Some number of problems per page. How many problems have a number equal to a page's number?
#
# https://www.hackerrank.com/challenges/lisa-workbook/problem
#

# pas compliqué, il faut bien lire et suivre l'énoncé

def workbook(n, k, arr):
    resultat = 0
    page = 0

    # parcourt les chapitres
    for num_pb in arr:
        pb = 1

        # parcourt les pages
        while True:
            page += 1
            if pb <= page < pb + min(num_pb, k):
                resultat += 1

            # il n'y a plus de problème dans ce chapitre
            if num_pb <= k:
                break

            # il y en a encore: décrémente le nombre de problèmes restant
            # et incrémente le numéro du premier problème de la page suivante
            num_pb -= k
            pb += k

    return resultat

if __name__ == "__main__":
    n, k = input().strip().split(' ')
    n, k = [int(n), int(k)]
    arr = list(map(int, input().strip().split(' ')))
    result = workbook(n, k, arr)
    print(result)


import torch
import torch.nn as nn
from torchsummary import summary
from dataclasses import asdict
from typing import Optional

from .configs.dqn import DQNConfig
from .utils.layer_params import LinearParams, ConvParams

def conv(params: ConvParams, pool: bool = True) -> nn.Module:
    layers = [
        nn.Conv2d(**asdict(params)),
        nn.ReLU(inplace=True),
        nn.BatchNorm2d(params.out_channels),
    ]
    if pool is True:
        layers.append(nn.MaxPool2d(2, 2))
    return nn.Sequential(*layers)

def linear(params: LinearParams, dropout: Optional[float] = None) -> nn.Module:
    layers = [nn.Linear(**asdict(params))]
    if dropout is not None:
        layers.append(nn.Dropout(dropout))
    layers.append(nn.ReLU(inplace=True))
    return nn.Sequential(*layers)

class DQN(nn.Module):
    def __init__(self, config: DQNConfig) -> None:
        super().__init__()
        num_features = self.__get_num_features(config.width, config.height)
        self.network = nn.Sequential(
            conv(ConvParams(config.in_channels, 8)),
            conv(ConvParams(8, 16)),
            conv(ConvParams(16, 32)),
            nn.Flatten(),
            linear(LinearParams(num_features, 64), dropout=0.5),
            linear(LinearParams(64, config.out_features)),
        )
        self.config = config

    def __get_num_features(self, width: int, height: int) -> int:
        num_channles, reduce_by = 32, 8
        width = width // reduce_by
        height = height // reduce_by
        return int(width * height * num_channles)

    def forward(self, state: torch.Tensor) -> torch.Tensor:
        return self.network(state)

if __name__ == "__main__":
    shape = in_channels, width, height = 4, 24, 32
    model = DQN(width, height, in_channels)
    summary(model, shape, device="cpu")


"""Simulations module

simulation_1():
    "Preliminary observations" - There are three possible cases.

simulation_2():
    "Homogeneous case" - Calculates asymptotic eigenvalues and alignments of eigenvectors.

simulation_3():
    "Homogeneous case" - Calculates asymptotic alignment of eigenvectors for growing n.

simulation_4():
    "Homogeneous case" - Performs community detection.
"""

from model import Model
from utils import *
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import warnings
warnings.filterwarnings('ignore')  # use only after debugging

def simulation_1():
    """Shows spectrum and extremal eigenvectors for the chosen case.
    """

    # Input basic variables
    n = int(input('Enter number of points (n, default 1000): ') or "1000")
    k = 3
    case = int(input('Enter case desired (1, 2, or 3): '))

    # Build Q from case
    q = 0*np.ones(n)  # initialise

    # CASE 1
    if case == 1:
        q_0 = float(input("Enter q_0 (default 0.05): ") or "0.05")
        q = q_0*np.ones(n)

    # CASE 2
    if case == 2:
        epsilon = 0.25
        q_0 = 0.5
        q = np.random.uniform(low=q_0-epsilon, high=q_0+epsilon, size=n)

    # CASE 3
    if case == 3:
        q_1 = float(input("Enter q_1 (default 0.5): ") or "0.5")
        q_2 = float(input("Enter q_2 (default 0.05): ") or "0.05")
        q = np.random.choice(np.array([q_1,q_2]), size = n)

    Q = np.diag(q)

    # Build the model and take eigenvalues
    model = Model(n, k, Q)

    # Graphical representations
    # Spectrum
    isolated_evals = isolated_eigenvalues(model)
    plt.hist(model.B_evals, density=True, bins=100)
    plt.title(r'Empirical spectral distribution of $B/\sqrt{n}$')
    plt.xlabel(r'Spectrum of $B/\sqrt{n}$')
    plt.ylabel('Density')
    annotation_string = f'n = {n} \nM ~ {int(model.order)} \nq_0 \
= {np.round(model.Q[0,0],2)} \nn. of spikes = {len(isolated_evals)}'
    plt.text(0.75, 0.8, annotation_string, transform=plt.gca().transAxes)
    # Indicate spikes clearly, if any (attention: only for homogeneous case)
    if case == 1:
        for _, val in enumerate(isolated_evals):
            plt.annotate('Spike', xy=(val, 0), xycoords='data',
                    xytext=(0, 10), textcoords='offset points',
                    ha='center', color='red', rotation=45
                    )

    # Eigenvectors
    plt.figure()
    plt.title(f'Extremal ({model.k} largest) eigenvectors')  # not showing
    for i in range(model.k):
        plt.subplot(model.k, 1, i+1)
        plt.plot(model.B_evecs[:,-i-1])
        plt.annotate(r'$\lambda =$ '+f'{np.round(model.B_evals[-i-1], 4)}',
                xy=(0.9,0.9), xycoords='axes points')
        for j in range(model.k):
            plt.axvline(x=np.sum(model.class_sizes[:j+1]), c='gray', linestyle='--')
        if i < model.k-1:
            plt.xticks([])
    plt.xlabel('Dimensions')
    plt.show()

def simulation_2():
    """Calculates the asymptotics of eigenvalues.
    """

    # Input basic variables
    n = int(input('Enter number of points (n, default 1000): ') or "1000")
    k = 3
    q_0 = float(input('Enter q_0 (default 0.05): ') or '0.05')
    Q = np.diag(q_0*np.ones(n))

    # Build model
    model = Model(n, k, Q)

    # Eigenvalues
    lambd = isolated_eigenvalues(model)
    n_isolated_eigvals = len(lambd)

    # Graphical representation (Eigenvalues)
    color = iter(plt.cm.rainbow(np.linspace(0, 1, len(lambd))))
    plt.hist(model.B_evals, density=True, bins=100)
    for i in range(len(lambd)):
        plt.axvline(lambd[i], c=next(color), linestyle='dashed')
    plt.title(f"Number of isolated eigenvalues: {n_isolated_eigvals}.")
    plt.show()

def simulation_3():
    """Calculates alignements of eigenvectors for growing n.
    """

    # Basic variables
    min_n = int(input("Enter minimal n (default 200): ") or "200")
    max_n = int(input("Enter maximal n (default 2000): ") or "2000")+200
    step_n = int(input("Enter step for n (default 200): ") or "200")
    list_n = list(range(min_n, max_n, step_n))
    k = 3
    q_0 = float(input("Enter q_0 (default 0.05): ") or "0.05")

    # Fix diagonal M
    order = float(input("Enter an order for M (default 100): ") or "100")
    m = order*np.random.rand(k)
    M = np.diag(m)

    # For saving results
    alignments_final = []
    alignments_theoretical = []

    # Main loop
    for i, n in enumerate(list_n):
        # Create model with n points but fixed M
        q = q_0*np.ones(n)
        Q = np.diag(q)
        model_n = Model(n, k, Q, M, ask_priors=False)

        # Isolated eigenvectors
        alignments_n, theoretical_alignments_n = alignments(model_n)

        np.set_printoptions(precision=3, suppress=True)
        print(f'n = {n} \n')
        print('Observed alignments: ', np.array_str(alignments_n, precision=4), '\n')
        print('Theoret. alignments: ', np.array_str(theoretical_alignments_n, precision=4), '\n')

        # Register iteration
        alignments_final.append(alignments_n)
        alignments_theoretical.append(theoretical_alignments_n)

    # Transform into convenient format
    alignments_final = np.array(alignments_final)
    alignments_theoretical = np.array(alignments_theoretical)

    # Print M to know its influence on observations
    print('M: ', m)

    # Graphical representation
    # Observed alignments
    for i in range(k):
        plt.plot(list_n, alignments_final[:,i], label=f'Observed alignments {i+1}')
        plt.plot(list_n, alignments_theoretical[:, i], linestyle='dashed', label=f'Predicted {i+1}')
        plt.ylim([0,1])
        plt.legend()
    plt.show()

def simulation_4():
    """Performs community detection by K-means on rows of isolated eigenvectors.
    """

    # Take isolated eigenvectors
    n = int(input('Enter number of points (n, default 1000): ') or "1000")
    k = 3
    q_0 = float(input('Enter q_0 (default 0.1): ') or '0.1')
    Q = np.diag(q_0*np.ones(n))

    # Build model
    model = Model(n, k, Q)

    # Perform K-means clustering on the rows of k largest eigenvectors.
    kmeans_predictions = KMeans(n_clusters=k).fit_predict(model.B_evecs[:,-k:])
    print("Accuracy: ", np.mean(kmeans_predictions == model.indicatrix))

    # For n=1000, q_0=0.1, M=150, I get 0.968 accuracy.


import csv
import requests
from bs4 import BeautifulSoup
import write_db as wdb

def check_in_file(file_csv,line_csv):
    open(f'{file_csv}','a')
    with open(f'{file_csv}',encoding='utf-16', newline="") as file:
        reader = csv.reader(file)
        for line in reader:
            if line == line_csv:
                return False
        return True

def get_quotes(soup):
    quotes = soup.find_all('span', class_='text')
    authors = soup.find_all('small', class_='author')
    for i in range(len(quotes)):
        quote = [quotes[i].text,authors[i].text]
        if check_in_file('quotes.csv',quote):
            with open('quotes.csv', "a",encoding='utf-16', newline="") as file:
                writer = csv.writer(file)
                writer.writerow(quote)

def get_authors(soup):
    authors = soup.find_all('small', class_='author')
    for author in authors:
        author = [author.text]
        if check_in_file('authors.csv',author):
            with open('authors.csv', "a",encoding='utf-16', newline="") as file:
                writer = csv.writer(file)
                writer.writerow(author)

def get_about_author(param):
    url = f'https://quotes.toscrape.com/{param}'
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'lxml')
    names = soup.find('h3', class_='author-title')
    born = soup.find('span', class_='author-born-date')
    born_loc = soup.find('span', class_='author-born-location')
    description = soup.find('div', class_='author-description')
    about_auth = [names.get_text().strip(), born.get_text(), born_loc.get_text(), description.get_text().replace("\n","")]
    if check_in_file('about_authors.csv',about_auth):
        with open('about_authors.csv','a',encoding='utf-16',newline="") as file:
            writer = csv.writer(file)
            writer.writerow(about_auth)

def href_author(soup):
    name_author = soup.find_all('small', class_='author')
    if check_in_file('authors.csv',name_author):
        for link in soup.find_all('a', href = True, text = '(about)'):
            get_about_author(link.get('href'))

def main():
    param = 'page/1/'
    while param != None:
        url = f'https://quotes.toscrape.com/{param}'
        response = requests.get(url)
        soup = BeautifulSoup(response.text, 'lxml')
        get_quotes(soup)
        get_authors(soup)
        href_author(soup)
        try:
            page = soup.find('li', class_='next')
            for i in page.find_all('a'):
                page = i['href']
        except:
            break
        param = page

main()
wdb.main()


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

def integrate(f, a, b, N):
    """ Uses pure python to integrate function using Riemann sum

        Example usage:
        integrate(f=lambda x: x**2 , a=0, b=1, N=6000000)
    """
    y = np.zeros(1)
    if isinstance(f(y), (int, float)): #Checking if the function is constant
        return(f(y))
    else:
        x = np.linspace(a, b, N + 1)
        _sum = 0
        dx = float(b - a)/N
        for xi in x:
            _sum += f(xi)*dx
        return _sum

def midpoint_integrate(f, a, b, N):
    """ Uses pure python to integrate function using midpoint method

        Example usage:
        midpoint_integrate(f=lambda x: x**2 , a=0, b=1, N=6000000)
    """
    y = np.zeros(1)
    if isinstance(f(y), (int, float)):
        return(f(y))

    else:
        _sum = 0
        dx = float(b-a)/N
        dx_midpoint = dx*0.5
        x = np.linspace(a, b, N + 1) - dx_midpoint #Creating an array with the midpoints
        x[0] = 0 #Replace first element with zero
        for xi in x:
            _sum += f(xi)*dx
        return _sum

def plot_error(f = lambda x: x**2, a=0, b=1, Nmax=500, Nmin=10, stepsize=10, plot = True):
    "Plots the error of a x^2 compared to the real answer which is 1/3 "
    error = []
    mesh = []

    for N in range(Nmin, Nmax + 1, stepsize):
        mesh.append(N)
        error.append(abs(1./3 - integrate(f, a, b, N)))
    if plot:
        fig = plt.figure(figsize=[7,5])
        ax = plt.subplot(111)
        ax.plot(mesh, error)
        ax.set_xlabel('Number of mesh points (N)')
        ax.set_ylabel('Error')
        ax.set_title("Error for nummerical integral of f(x) = x^2")
        fig.savefig("quadratic_error.png")
        plt.show()
if __name__ == "__main__":
    for i in range(4):

        t_start = time.clock()
        integrate(f = lambda x: x**2, a=0, b=1, N = 10000)
        t_stop = time.clock()
        print("Runtime for pure python integral: {}".format(t_stop - t_start))
        # t_start = time.clock()
        # midpoint_integrate(f = lambda x: x**2, a=0, b=1, N = 2000)
        # t_stop = time.clock()
        # print("Runtime for pure python midpoint integral: {}".format(t_stop - t_start))
    #plot_error()


'''
Descripción: Operando con Listas
Autor: Jessica Castillo
Fecha: 29 de Septiembre 2022
'''

my_list = [1, 2, 4, 4, 1, 4, 2, 6, 2, 9]

resultado = []
for i in my_list:
    if i not in resultado:
        resultado.append(i)

print("La lista con elementos únicos:")
print(resultado)


# -----------------------------------------------------------
# Creating a candlestick chart of stock-market data using python.
#
# (C) 2020 Sandra VS Nair, Trivandrum
# email sandravsnair@gmail.com
# -----------------------------------------------------------

from pandas_datareader import data
from bokeh.models.annotations import Title
from bokeh.plotting import figure,show,output_file
import datetime

#The time period for which you need the data.
starttime=datetime.datetime(2018,5,2)
endttime=datetime.datetime(2018,5,20)

#pandas_datareader imports data from a number of online sources.
#Parameters: Stock symbol, Data source, Start time and End time.
stock_data=data.DataReader(name="AAPL", data_source="yahoo", start=starttime, end=endttime)

#Setting properties of the plot.
plot=figure(x_axis_type='datetime',width=1000,height=300)
t = Title()
t.text = 'Candlestick chart'
plot.title = t
plot.grid.grid_line_alpha=0.3

#Twelve horus in milliseconds.
twelve_hours=12*60*60*1000

#Updating status of the stock.
def status_update(open_price,close_price):
    if close_price > open_price:
        value="Increase"
    elif open_price > close_price:
        value="Decrease"
    else:
        value="Equal"
    return value

#Finding mean value of opening price and closing price.
def middle_value(open_price,close_price):
    value=(open_price+close_price)/2
    return value

#Finding the difference between opening price and closing price.
def height(open_price,close_price):
    value=abs(close_price-open_price)
    return value

#Adding three more columns to the table.
stock_data["Status"]=[status_update(open_price,close_price) for open_price,close_price in zip(stock_data.Open,stock_data.Close)]
stock_data["Middle"]=[middle_value(open_price,close_price) for open_price,close_price in zip(stock_data.Open,stock_data.Close)]
stock_data["Height"]=[height(open_price,close_price) for open_price,close_price in zip(stock_data.Open,stock_data.Close)]

#Adding rectangles and segments to the plot

#Four mandatory parameters
#1. x-coordinate of central point of rectangles
#2. y-coordinate of central point of rectangles
#3. Width
#4. Height

plot.rect(stock_data.index[stock_data.Status=="Increase"], stock_data.Middle[stock_data.Status=="Increase"], \
          twelve_hours, stock_data.Height[stock_data.Status=="Increase"],fill_color="green",line_color="black")
plot.rect(stock_data.index[stock_data.Status=="Decrease"], stock_data.Middle[stock_data.Status=="Decrease"], \
          twelve_hours,stock_data.Height[stock_data.Status=="Decrease"],fill_color="red",line_color="black")

#Four mandatory parameters
#1. Highest x-coordinate.
#2. Highest y-coordinate.
#3. Lowest x-coordinate.
#4. Lowest y-coordinate.

plot.segment(stock_data.index,stock_data.High,stock_data.index,stock_data.Low,color="black")

#Saving the plot.
output_file("Candlestick.html")

#Displaying the plot.
show(plot)


from math import *
import numpy as np

class Kinematics:
    def __init__(self):
        # Leg length
        self.l1 = 50
        self.l2 = 20
        self.l3 = 100
        self.l4 = 100
        # Body width, length
        self.L = 140
        self.W = 75

        # Leg iterator
        # ex) LEG_BACK + LEG_LEFT = array[2]
        self.LEG_FRONT = 0
        self.LEG_BACK = 2
        self.LEG_LEFT = 0
        self.LEG_RIGHT = 1

        self.thetas = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], dtype = np.float64)

    def bodyIK(self, omega, phi, psi, xm, ym, zm):
        # Rotaion matrix
        Rx = np.array([[1, 0, 0, 0], [0, np.cos(omega), -np.sin(omega), 0], [0, np.sin(omega), np.cos(omega), 0], [0, 0, 0, 1]])
        Ry = np.array([[np.cos(phi), 0, np.sin(phi), 0], [0, 1, 0, 0], [-np.sin(phi), 0, np.cos(phi), 0], [0, 0, 0, 1]])
        Rz = np.array([[np.cos(psi), -np.sin(psi), 0, 0], [np.sin(psi), np.cos(psi), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
        # All axis rotation matrix
        Rxyz = Rx.dot(Ry.dot(Rz))

        # Translation matrix
        T = np.array([[0, 0, 0, xm], [0, 0, 0, ym], [0, 0, 0, zm], [0, 0, 0, 0]])
        # Transformation matrix
        Tm = T + Rxyz

        # Half PI
        sHp = np.sin(pi / 2)
        cHp = np.cos(pi / 2)

        # Body width, length
        (L, W) = (self.L, self.W)

        return ([Tm.dot(np.array([[cHp, 0, sHp, L/2], [0, 1, 0, 0], [-sHp, 0, cHp, W/2], [0, 0, 0, 1]])),
                Tm.dot(np.array([[cHp, 0, sHp, L/2], [0, 1, 0, 0], [-sHp, 0, cHp, -W/2], [0, 0, 0, 1]])),
                Tm.dot(np.array([[cHp, 0, sHp, -L/2], [0, 1, 0, 0], [-sHp, 0, cHp, W/2], [0, 0, 0, 1]])),
                Tm.dot(np.array([[cHp, 0, sHp, -L/2], [0, 1, 0, 0], [-sHp, 0, cHp, -W/2], [0, 0, 0, 1]]))])

    def legIK(self, point):
        (x, y, z) = (point[0], point[1], point[2])
        (l1, l2, l3, l4) = (self.l1, self.l2, self.l3, self.l4)

        # Calculate theta1 (hip joint)
        try:
            F = sqrt(x**2 + y**2 - l1**2)
        except ValueError:
            print("Error")
            F = l1
        theta1 = -atan2(y, x) - atan2(F, -l1)

        G = F - l2
        H = sqrt(G**2 + z**2)
        D = (H**2 - l3**2 - l4**2) / (2 * l3 * l4)

        # Calculate theta3 (knee joint)
        try:
            theta3 = acos(D)
        except ValueError:
            print("Error")
            theta3 = 0

        # Calculate theta2 (shoulder joint)
        theta2 = atan2(z, G) - atan2(l4 * sin(theta3), l3 + l4 * cos(theta3))

        return (theta1, theta2, theta3)

    def legPair(self, Tl, Tr, Ll, Lr, LEG_FR):
        # Identity matrix
        Ix = np.array([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])

        # LEG_FR = LEG_FRONT -> 0 + 0 = 0
        self.thetas[LEG_FR + self.LEG_LEFT] = np.array(self.legIK(np.linalg.inv(Tl).dot(Ll)))

        # LEG_FR = LEG_BACK -> 2 + 1 = 3
        self.thetas[LEG_FR + self.LEG_RIGHT] = np.array(self.legIK(Ix.dot(np.linalg.inv(Tr).dot(Lr))))

    # drawRobot
    def robot(self, position, angle, center):
        # Rotation angle
        # omega: roll, phi: pitch, psi: yaw
        (omega, phi, psi) = angle
        # Center of body
        (xm, ym, zm) = center

        # FP = [0, 0, 0, 1]  # FP??

        # Final matrix ??
        # Tlf: LEFT-FRONT, Trf: RIGHT-FRONT, Tlb: LEFT-BACK, Trb: LEFT-BACK
        (Tlf, Trf, Tlb, Trb) = self.bodyIK(omega, phi, psi, xm, ym, zm)
        # CP??
        # CP = [x.dot(FP) for x in [Tlf, Trf, Tlb, Trb]]
        # CPs = [CP[x] for x in [0, 1, 3, 2, 0]]

        # FRONT
        self.legPair(Tlf, Trf, position[0], position[1], self.LEG_FRONT)
        # BACK
        self.legPair(Tlb, Trb, position[2], position[3], self.LEG_BACK)

def initIK(position):
    moduleKinematics = Kinematics()
    moduleKinematics.robot(position, (0, 0, 0), (0, 0, 0))

    return moduleKinematics.thetas

if __name__ == "__main__":
    # [LEFT-FRONT], [RIGNT-FRONT], [LEFT-BACK], [RIGHT-BACK]
    foot_position = np.array([[100, -100, 100, 1], [100, -100, -100, 1], [-100, -100, 100, 1], [-100, -100, -100, 1]])

    # Calculate inverse kinematics
    initIK(foot_position)


#%%
import gspread

import pandas as pd
import re

gc = gspread.service_account()
# %%
worksheet = gc.open('Total partidas').sheet1

rows = worksheet.get_all_values()

data = pd.DataFrame.from_records(rows)
data.columns = data.iloc[0]
data.drop(0, inplace=True)
display(data.info())
display(data.describe())

#%%


from django import template

register = template.Library()

@register.filter(nome="remover_texto")
def remover(texto, r):
    return texto.replace(r, "")

@register.filter(name="verificardddpr")
def verificardddpr(telefone):
    ddd = telefone[0:4]
    if ddd == "(44)":
        return True
    else:
        return False

@register.filter(name="verificaruser")
def verificausuario(usuario, nome_do_grupo):
    if usuario.groups.filter(name=nome_do_grupo):
        return True
    else:
        return False

@register.filter(name="verificaplaca")
def verificaplaca(usuario, nome_do_grupo):
    if usuario.groups.filter(name=nome_do_grupo):
        return True
    else:
        return False


#!/usr/bin/env python
import os
import sys

from django.core.exceptions import ImproperlyConfigured

def run_gunicorn(is_production: bool):
    from django_events.wsgi import application  # noqa
    from django_docker_helpers.management import run_gunicorn  # noqa

    gunicorn_module_name = 'gunicorn_prod' if is_production else 'gunicorn_dev'
    run_gunicorn(application, gunicorn_module_name=gunicorn_module_name)

def _prepare():
    from django_docker_helpers.db import ensure_databases_alive, ensure_caches_alive, migrate  # noqa
    from django_docker_helpers.files import collect_static
    from django_docker_helpers.management import create_admin

    collect_static()
    ensure_databases_alive(100)
    ensure_caches_alive(100)
    migrate()
    create_admin()

if __name__ == '__main__':
    BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__)))

    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_events.settings')

    IS_PRODUCTION = bool(int(os.environ.get('PRODUCTION', 0) or 0))
    IS_DOCKERIZED = bool(int(os.environ.get('DOCKERIZED', 0) or 0))

    if IS_DOCKERIZED:
        _prepare()

    if len(sys.argv) == 2:
        if sys.argv[1] == 'runuwsgi':
            from django.conf import settings

            os.environ.setdefault('PORT', str(settings.COMMON_BASE_PORT))
            safe = getattr(settings, 'UWSGI_STATIC_SAFE', None)
            if safe or safe == '':
                if IS_PRODUCTION:
                    raise ImproperlyConfigured(r"""
                        WARNING: UWSGI_STATIC_SAFE is the unsafe security option! DO NOT USE IT ON PRODUCTION!!!
                        (We treat an empty string and non-falsy values as 'enable static-safe option')""")

                os.environ.setdefault('UWSGI_STATIC_SAFE', str(settings.UWSGI_STATIC_SAFE))

        if sys.argv[1] == 'gunicorn':
            run_gunicorn(IS_PRODUCTION)
            exit()

    from django.core.management import execute_from_command_line
    execute_from_command_line(sys.argv)


"""
this is a classifier
input is the normalized ECG vector
output is the class of the ECG
"""

import json
import os
import random
import sys

import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.optim as optim
from datetime import datetime
from torch.utils.data import DataLoader, TensorDataset
import torch.nn.functional as F
from sklearn.metrics import roc_auc_score, precision_recall_curve, auc
import csv
from torchvision import datasets
import torchvision.transforms as transforms
from collections import Counter
import gc
import copy

from tqdm import tqdm

from ekg_class import dicts
import torch.nn as nn
from models_classifier import EcgResNet34
from sklearn.metrics import classification_report as report
from sklearn.metrics import confusion_matrix as cf_matrix
from utils import print_confusion_matrix

os.environ['CUDA_LAUNCH_BLOCKING'] = "1"

num2descr, letter2num, letter2descr, num2letter = dicts()
start_time = datetime.now()

print(("\n" + "*" * 61 + "\n\t\t\t\t\tstart time  {0:02d}:{1:02d}:{2:02.0f}\n" + "*" * 61).format(
    start_time.hour, start_time.minute, start_time.second))

drive = "E:\\"
myPath_base = os.path.join(drive, "UTSA")
path_aux = 'paper3_DM\\paper3_data'
myPath_base = os.path.join(myPath_base, 'paper3_DM\\paper3_data')

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Hyper-parameters etc.
dry_run = False
BATCH_SIZE = 16
LEARNING_RATE = 1e-3
NUM_CLASSES = 2

if dry_run:
    NUM_EPOCHS = 1
else:
    NUM_EPOCHS = 10

classes2keep = ['N', 'L']
classes2keep_folder = ['N', 'L']

key_aug = "aug"
# key_aug = "notaug"

key_bal = 'balanced'
# key_bal = 'imbalanced'

# key_case = 'rl'
# key_case = "02"
key_case = "wgan"

# len_ratio = .01                   # shorter train sets
len_ratio = 1                  # shorter train sets
num_samples = 8000
tst_len = 1000
print('\ncase: {}, {}, {}\n'.format(key_case, key_bal, key_aug))
# num_N_samples = int(len_ratio*num_samples)

if '.' in str(len_ratio):
    len_ratio_str = str(len_ratio).replace('.', '')
else:
    len_ratio_str = str(len_ratio)

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
path = "gb_dm_case_{}".format(key_case)
myPath_save = os.path.join(myPath_base, path)
os.makedirs(myPath_save, exist_ok=True)

brk = 'here'

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  begin: generate and save MIT-BIH dataset   %%%%%%%%%%%%%%%%%%
"""
with open(os.path.join(myPath_base, 'mitbih_64_allN.json'.format(key_case)), "r") as f:
    mitbih_64_N = json.load(f)[:num_samples]

with open(os.path.join(myPath_base, 'mitbih_64_allL.json'.format(key_case)), "r") as f:
    mitbih_64_L = json.load(f)[:num_samples]

rand_idx = random.sample(range(0, num_samples), num_samples)
idx_trn = rand_idx[:7000]
idx_tst = rand_idx[7000:]
X_N_trn = [mitbih_64_N[idx] for idx in idx_trn]
X_N_tst = [mitbih_64_N[idx] for idx in idx_tst]

rand_idx = random.sample(range(0, num_samples), num_samples)
idx_trn = rand_idx[:7000]
idx_tst = rand_idx[7000:]
X_L_trn = [mitbih_64_L[idx] for idx in idx_trn]
X_L_tst = [mitbih_64_L[idx] for idx in idx_tst]

path = os.path.join(myPath_base, "X_N_trn.json")
with open(path, 'w') as f:
    json.dump(X_N_trn, f)

path = os.path.join(myPath_base, "X_N_tst.json")
with open(path, 'w') as f:
    json.dump(X_N_tst, f)

path = os.path.join(myPath_base, "X_L_trn.json")
with open(path, 'w') as f:
    json.dump(X_L_trn, f)

path = os.path.join(myPath_base, "X_L_tst.json")
with open(path, 'w') as f:
    json.dump(X_L_tst, f)
"""
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  end: generate and save MIT-BIH dataset   %%%%%%%%%%%%%%%%%%

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  begin: load X and y   %%%%%%%%%%%%%%%%
path = os.path.join(myPath_base, "X_N_trn.json")
with open(path, 'r') as f:
    X_N_trn = json.load(f)

path = os.path.join(myPath_base, "X_N_tst.json")
with open(path, 'r') as f:
    X_N_tst = json.load(f)

path = os.path.join(myPath_base, "X_L_trn.json")
with open(path, 'r') as f:
    X_L_trn = json.load(f)

path = os.path.join(myPath_base, "X_L_tst.json")
with open(path, 'r') as f:
    X_L_tst = json.load(f)
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  end: load X and y   %%%%%%%%%%%%%%%%%%
X_tst = X_N_tst + X_L_tst
y_N_tst = [0 for _ in range(len(X_N_tst))]
y_L_tst = [1 for _ in range(len(X_L_tst))]
y_tst = y_N_tst + y_L_tst

if key_aug == 'aug':
    with open(os.path.join(myPath_base, 'gb_dm_case_{}\\gb_dm_1d_case_{}.json'.format(key_case, key_case)), "r") as f:
        gb_for_aug = json.load(f)

    rand_idx = random.sample(range(0, len(gb_for_aug)), len(gb_for_aug))
    temp = [gb_for_aug[idx] for idx in rand_idx]
    X_aug = temp[:7000-350]
else:
    X_aug = []

# # imbalanced case N: 350, select 350 elements in X_N_trn if 'imbalanced' or 'augmented'
if key_bal == 'imbalanced' or key_aug == 'aug':
    rand_idx = random.sample(range(0, len(X_N_trn)), len(X_N_trn))[:350]
    X_N_trn = [X_N_trn[idx] for idx in rand_idx]

X_N_trn = X_N_trn + X_aug
X_trn = X_N_trn + X_L_trn

y_N_trn = [0 for _ in range(len(X_N_trn))]
y_L_trn = [1 for _ in range(len(X_L_trn))]
y_trn = y_N_trn + y_L_trn

trn_set = TensorDataset(torch.tensor(X_trn), torch.tensor(y_trn))
tst_set = TensorDataset(torch.tensor(X_tst), torch.tensor(y_tst))
trn_loader = DataLoader(trn_set, batch_size=BATCH_SIZE, shuffle=True, drop_last=True)
tst_loader = DataLoader(tst_set, batch_size=BATCH_SIZE, shuffle=True, drop_last=True)

brk = 'here'
# %%%%%%%%%%%%%%%%%     begin save sample plots of classes in classes2keep    %%%%%%%%%%%%%%%%%%%%
'''
for cl in classes2keep:
    fig, axes = plt.subplots(nrows=3, ncols=3)
    fig.suptitle("Class {} ({}: {}), count: {}".
                 format(classes2keep.index(cl), cl, letter2descr[cl], len(data2keep_dict[cl])))

    count = 0
    for i in range(3):
        for j in range(3):
            count += 1
            if count >= len(data2keep_dict[cl]):
                continue
            axes[i][j].plot(data2keep_dict[cl][count])
            axes[i][j].grid()
    plt.savefig(os.path.join(myPath_save, "00_sample_cl_{}.png".format(classes2keep.index(cl))))

plt.close("all")
'''
# %%%%%%%%%%%%%%%%%     end save sample plots of classes in classes2keep      %%%%%%%%%%%%%%%%%%%%

# %%%%%%%%%%%%%%%%%%%% begin:     Select and Initialize Network       %%%%%%%%%%%%%%%%%%%%%%%%%%%%
# net = net_cnn(num_classes=NUM_CLASSES).to(device)
# net = net_fc(input_size=INPUT_SIZE, num_classes=NUM_CLASSES).to(device)
net = EcgResNet34(num_classes=NUM_CLASSES).to(device)

# loss function and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=LEARNING_RATE)
# %%%%%%%%%%%%%%%%%%%% end:     Select and Initialize Network       %%%%%%%%%%%%%%%%%%%%%%%%%%%%

'''
# NUM_EPOCHS = 1
# %%%%%%%%%%%%%%%%%%%%    begin:  Train Classifier       %%%%%%%%%%%%%%%%%%%%%%%%%%
for epoch in range(NUM_EPOCHS):
    for batch_idx, (inputs, labels) in enumerate(trn_loader, 0):
        inputs = inputs.to(device)
        labels = labels.to(device)
        inputs = inputs.reshape(inputs.shape[0], 1, -1)

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        scores = net(inputs)
        loss = criterion(scores.squeeze(), labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        # print statistics
        # running_loss += loss.item()
        if batch_idx % 200 == 0:  # print every 200 mini-batches
            now = datetime.now()
            print('{:02d}:{:02d}:{:02d}\t\tepoch={:4d} / {:4d}\t\titer={:5d} / {:5d}\t\t\tloss: {:7.5f}'.
                  format(now.hour, now.minute, now.second, epoch, NUM_EPOCHS, batch_idx, len(trn_loader), loss))

print('\n\tFinished Training\n')
# %%%%%%%%%%%%%%%%%%%%    end  Train Network       %%%%%%%%%%%%%%%%%%%%%%%%%%%%

print('\tSaving model ...\n')

# %%%%%%%%%%%%%%%%%%%%    begin save model   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
f_name = "classifier_{}_{}_{}.pth".format(key_case, key_bal, key_aug)
PATH = os.path.join(myPath_save, f_name)
torch.save(net.state_dict(), PATH)
# %%%%%%%%%%%%%%%%%%%%    end save model     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
'''

# %%%%%%%%%%%%%%%%%%%%    load trained classifier     %%%%%%%%%%%%%%%%%%%%%
path = "gb_dm_case_{}".format(key_case)
myPath = os.path.join(myPath_base, path)
classifier_name = "classifier_{}_{}_{}.pth".format(key_case, key_bal, key_aug)
net.load_state_dict(torch.load(os.path.join(myPath, classifier_name)))

brk = 'here'

# %%%%%%%%%%%%%%%%%%    print Classification Report to file      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
trntst = ['trn', 'tst']
for key_trntst in trntst:
    print('Preparing Classification Report: {}'.format(key_trntst))
    path = os.path.join(myPath_save, 'classification_report_{}_{}_{}_{}.txt'.
                        format(key_trntst, key_case, key_bal, key_aug))
    with open(path, 'w') as sys.stdout:
        y_scores = []
        y_true = []
        y_pred = []
        exec('loader = {}_loader'.format(key_trntst))
        for (inputs, labels) in tqdm(loader):
            inputs = inputs.reshape(inputs.shape[0], 1, -1).to(device)
            labels = labels.to(device)
            temp = net(inputs)
            output = temp.max(dim=1)

            y_true.extend(labels.data.tolist())
            y_pred.extend(output.indices.tolist())
            y_scores.extend((F.softmax(temp, dim=1).tolist()))

        print("\n")
        print("%" * 20 + "\tClassification Report ({} Set, {}, {}, {})\t".
              format(key_trntst, key_case, key_bal, key_aug) + "%" * 20)
        print("Classes:                             {}".format(classes2keep_folder))
        print("Classifier Model:                    {}".format(net._get_name()))
        print(f"number of epochs:                    {NUM_EPOCHS}\n")
        print("Train set length:                    {}".format(len(trn_set)))
        print("Test set length:                     {}".format(len(tst_set)))
        print("Train set reduction length ratio:    {}\t".format(len_ratio_str))
        print('\nClassification Report:')
        print(report(y_true, y_pred, target_names=classes2keep_folder))
        print("\nConfusion Matrix:\n {}".format(cf_matrix(y_true, y_pred)))
        precision, recall, thresholds = precision_recall_curve(y_true, np.asarray(y_scores)[:, 1])
        pr_recall_auc_score = auc(recall, precision)
        print('\nPrecision-Recall AUC Score:        {:6.4f}'.format(pr_recall_auc_score))
        rocauc_score = roc_auc_score(y_true, np.asarray(y_scores)[:, 1])
        print('\nROC AUC Score:                     {:6.4f}'.format(rocauc_score))
        print_confusion_matrix(cf_matrix(y_true, y_pred), class_names=classes2keep_folder,
                               fig_name="Conf. Matrix_{}_{}_{}_{}".format(key_trntst, key_case, key_bal, key_aug))
        plt.savefig(os.path.join(myPath_save, "cfmx_{}_{}_{}_{}.png".format(key_trntst, key_case, key_bal, key_aug)))
        plt.close("all")

        plt.plot(precision, recall)
        plt.title("Precision - Recall Curve ({}, {}, {}, {})".format(key_trntst, key_case, key_bal, key_aug))
        plt.grid()
        plt.savefig(os.path.join(myPath_save, "prec_recall_curve_{}_{}_{}_{}.png".
                                 format(key_trntst, key_case, key_bal, key_aug)))
        plt.close("all")
        sys.stdout = sys.__stdout__

finish_time = datetime.now()
print(("\n\n\n" + "finish time = {0:02d}:{1:02d}:{2:02.0f}").format(
    finish_time.hour, finish_time.minute, finish_time.second))

laps = finish_time - start_time
tot_sec = laps.total_seconds()
h = int(tot_sec // 3600)
m = int((tot_sec % 3600) // 60)
s = int(tot_sec - (h * 3600 + m * 60))

print("total elapsed time = {:02d}:{:2d}:{:2d}".format(h, m, s))

"""
#load model
model = model_name(*args, **kwargs)
model.load_state_dict(torch.load(PATH))
model.eval()
"""