from django.shortcuts import render, get_object_or_404
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics
from rest_framework.decorators import action

from .errors import MissingQueryParameterException
from .models import Banks, Branches
from .serializers import BankSerializer, BranchSerializer

class BranchListView(generics.ListAPIView):
    serializer_class = BranchSerializer

    def get_queryset(self):
        bank_name = self.request.query_params.get('bank_name')
        city = self.request.query_params.get('city')
        if city is None and bank_name is None:
            raise MissingQueryParameterException(
                detail='city and bank_name missing in query params. Provide at least one.')
        results = None
        if city:
            res = Branches.objects.filter(city=city)
        if bank_name:
            res = res.filter(bank__name=bank_name)
        return res

    city_param = openapi.Parameter(
        'city',
        openapi.IN_QUERY,
        description="The city to query for.",
        type=openapi.TYPE_STRING)
    bank_name_param = openapi.Parameter(
        'bank_name',
        openapi.IN_QUERY,
        description="The bank name to search for.",
        type=openapi.TYPE_STRING)

    @swagger_auto_schema(manual_parameters=[
        city_param, bank_name_param
    ])
    def get(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

class BranchRetrieveView(generics.RetrieveAPIView):
    serializer_class = BranchSerializer

    def get_object(self):
        ifsc = self.kwargs.get('ifsc', None)
        if ifsc is None:
            raise MissingQueryParameterException(
                detail='ifcs code missing in url params.')

        return get_object_or_404(Branches, ifsc=ifsc)


import cv2                      #导入 Opencv
import os
import numpy as np
import matplotlib.pyplot as plt
from skimage import color  # require skimage
import torchvision.transforms as transforms
import torch
from scipy import stats

# a = torch.randint(size=(1, 3, 6, 6), high=10)
# b = a[:, 1, :, :]
# print(a, b)

img_file = r"H:\Datasets\VOC2012\JPEGImages\2007_000123.jpg" #读取图片
img = cv2.imread(img_file, 1)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #z BGR转RGB
lab = color.rgb2lab(img1).astype(np.float32)
print(lab)
# lab_t = transforms.ToTensor()(lab)
# print(lab)
# L = lab_t[[0], ...] / 50.0 - 1.0
# AB = lab_t[[1, 2], ...] / 110.0
L = lab[:, :, 0]
AB = lab[:, :, 1:3]
img_a = AB[:, :, 0] + 128
img_b = AB[:, :, 1] + 128
a = np.around(img_a.flatten(), decimals=3)
b = np.around(img_b.flatten(), decimals=3)
L = np.around(L.flatten(), decimals=3)
# a = img_a.flatten()
# b = img_b.flatten()
# print(a, b)
za = stats.mode(a)[0][0]
zb = stats.mode(b)[0][0]
zl = stats.mode(L)[0][0]
print(zl, za, zb)
# LAB = torch.cat((L, AB), dim=0)
# print(L, LAB)
# 按R、G、B三个通道分别计算颜色直方图
# 显示3个通道的颜色直方图
# plt.plot(b_hist, label='B', color='blue')
# plt.plot(g_hist, label='G', color='green')
# plt.plot(r_hist, label='R', color='red')
# plt.legend(loc='best')
# plt.xlim([0, 256])
# plt.show()
#
hist_a = cv2.calcHist([a], [0], None, [256], [0, 255])
hist_b = cv2.calcHist([b], [0], None, [256], [0, 255])
hist_L = cv2.calcHist([L], [0], None, [100], [0, 99])
plt.plot(hist_a)
plt.plot(hist_b)
plt.plot(hist_L)
plt.xlim([0, 255])
plt.show()

# # ============================ √ rgb2lab2rgb =================================
# img_file = r"H:\SMU\dataset\EUVP\test_samples-20230425T075315Z-001\test_samples\TrainA\test_p0_.jpg"  #读取图片
# img = cv2.imread(img_file, 1)
# img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #z BGR转RGB
# img2 = img1.transpose([2, 0, 1])
# img3 = img2.transpose([1, 2, 0])
# lab = color.rgb2lab(img1).astype(np.float32)
# lab_t = transforms.ToTensor()(lab)
# L = lab_t[[0], ...] / 50.0 - 1.0
# AB = lab_t[[1, 2], ...] / 110.0
#
#
# AB2 = AB * 110.0
# L2 = (L + 1.0) * 50.0
# print(L2.shape, AB2.shape)
# Lab = torch.cat([L2, AB2], dim=0)
# print(Lab.shape)
# Lab = Lab.data.cpu().float().numpy()
# Lab = np.transpose(Lab.astype(np.float64), (1, 2, 0))
# rgb = np.around(color.lab2rgb(Lab) * 255)
# rgb = rgb.astype(np.int)
#
# print(img1, rgb, img1==rgb)
#
# plt.imshow(rgb)
# plt.show()

ZGP/颜色直方图/直方图.py


from tqdm import tqdm
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader
from utils import TrainSet
from AdaIN import StyleTransferNet
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--content_dir', type=str, default='./data/mscoco/', help='content data set path')
parser.add_argument('--style_dir', type=str, default='./data/wikiart', help='style data set path')
parser.add_argument('--epochs', type=int, default=1, help='training epoch number')
parser.add_argument('--resume', type=int, default=0, help='continues from epoch number')
parser.add_argument('--cuda', action='store_true', help='Using GPU to train')

def main():
	opt = parser.parse_args()
	check_points_dir = './results/check_points/'
	weights_dir = './results/weights/'
	train_set = TrainSet(opt.content_dir, opt.style_dir)
	batch_size = 8
	trainloader = DataLoader(dataset=train_set, num_workers =4, batch_size=batch_size, shuffle=True)
	vgg_model = torch.load('vgg_normalized.pth')
	net = StyleTransferNet(vgg_model)
	if torch.cuda.is_available() and opt.cuda:
		net.cuda()

	decoder_optimizer = optim.Adam(net.decoder.parameters(), lr=1e-6)
	running_loss = 0.0
	running_losses = []
	it = 0

	if opt.resume != 0:
		check_point = torch.load(check_points_dir + "check_point_epoch_" + str(opt.resume)+'.pth')
		net.decoder.load_state_dict(check_point['decoder'])
		decoder_optimizer.load_state_dict(check_point['decoder_optimizer'])
		it, running_losses = check_point['it'], check_point['running_losses']

	for epoch in range(1+opt.resume, opt.epochs+1):
		print("epoch: %i/%i" % (int(epoch), int(opt.epochs)))
		training_bar = tqdm(trainloader)
		training_bar.set_description('Running Loss: %f' % (running_loss))
		running_losses.append((it, running_loss))
		running_loss = 0

		for content_sample, style_sample in training_bar:

			if torch.cuda.is_available() and opt.cuda:
				content_sample = content_sample.cuda()
				style_sample = style_sample.cuda()
			loss_content, loss_style = net([content_sample, style_sample])

			loss_tot = loss_content + 10 * loss_style
			loss_tot.backward()
			decoder_optimizer.step()
			running_loss += loss_tot.item() * style_sample.size(0)
			decoder_optimizer.zero_grad()
			sample_num += style_sample.size(0)
			if ((it) % 500 ==0) and it!= 0:

				running_loss /= sample_num
				print('')
				training_bar.set_description('Running Loss: %f' % (running_loss))

				running_losses.append((it, running_loss))

				running_loss = 0.0
				sample_num = 0

			if ((it)% np.ceil(len(trainloader.dataset)/batch_size)== 0) and it!= 0:
				running_loss /= sample_num
				sample_num = 0
			it += 1

		check_point = {'decoder': net.decoder.state_dict(), 'decoder_optimizer': decoder_optimizer.state_dict(),
								'running_losses': running_losses, 'it': it}
		torch.save(check_point, check_points_dir+ 'check_point_epoch_%d.pth' % (epoch))
		torch.save(net.decoder.state_dict(), weights_dir+ 'decoder_epoch_%d.pth' % (epoch))
		np.savetxt("running_losses", running_losses, fmt='%i,%f')
if __name__ == '__main__':
	main()


#Tomes, Christopher
#Cal Poly Pomona CS4650
#update_data.py
#This program will make a prediction on which stocks to buy and sell.
#
import requests
import json
import os
#Grab api key from folder
def read_api_key_file(filename):
    with open(filename, 'r') as file:
        api_key = file.readline().strip()
    return api_key
#Grab Data from api.
def get_time_series(ticker_symbol, api, start_date, interval):
    url = f"https://api.twelvedata.com/time_series?symbol={ticker_symbol}&interval={interval}&format=JSON&start_date={start_date}&apikey={api}"
    response = requests.get(url)
    if response.status_code == 200:
        data = response.json()
        filename = f"{ticker_symbol}.json"
        filepath = os.path.join("data4", filename)
        with open(filepath, "w") as f:
            json.dump(data, f)
        print(f"JSON data saved to file {filepath}!")
    else:
        print("Request failed with status code:", response.status_code)
    return response

api_key = read_api_key_file("api_key.txt")
start_date = "04/01/2023 8:00 PM"
interval = "4h" #Supports: 1min, 5min, 15min, 30min, 45min, 1h, 2h, 4h, 1day, 1week, 1month
tickers = {"AAPL","AMZN","GOOGL","MSFT","NFLX","TSLA","NVDA","INTC"}

print('Downloading Dat...')
for ticker in tickers:
    get_time_series(ticker, api_key, start_date, interval)

print('Done!')


#add requests
import requests
import re
from bs4 import BeautifulSoup
import json
import csv

pagenum = 9500
cat = ['[好雷]','[普雷]','[負雷]']
sup = []
nom = []
min = []
def extract(pagenum):
  response = requests.get("https://www.ptt.cc/bbs/movie/index" + str(pagenum) + ".html")
  soup = BeautifulSoup(response.text, "html.parser")
  p_list = soup.find_all('a', href=True)
  for i in p_list:
    #print (i)
    if i.getText()[0:4] in cat and i.getText() != 'None':
      return i.getText()

for i in range(10):
  if (extract(pagenum)) != None:
    if extract(pagenum)[0:4] == '[好雷]':
      sup.append(extract(pagenum))
    elif extract(pagenum)[0:4] == '[普雷]':
      nom.append(extract(pagenum))
    elif extract(pagenum)[0:4] == '[負雷]':
      min.append(extract(pagenum))
  pagenum -= 1

with open('movie.txt','x') as output:
  for i in sup:
    output.write(i + '\n')
  for i in nom:
    output.write(i + '\n')
  for i in min:
    output.write(i + '\n')


import atexit
from collections import namedtuple, defaultdict
import datetime
import os
import subprocess

import feedgenerator
from jinja2 import Environment, FileSystemLoader, select_autoescape
import watchdog
import watchdog.events
import watchdog.observers

WEBSITE_URL = 'https://www.moderndescartes.com'
# Where to look for various files
ESSAY_DIR = "essays"
STATIC_DIR = "static"
STAGING_DIR = "staging"
TEMPLATE_DIR = "templates"

ESSAY_WEBDIR = "essays"

ALLOWED_EXTENSIONS = ('.md', '.txt', '.html')

BASIC_PAGES = (
    '404.html',
    'index.html',
)

JINJA_ENV = Environment(
    loader=FileSystemLoader('templates'),
    autoescape=select_autoescape(['html', 'xml']))

Essay = namedtuple('Essay', ['slug', 'title', 'date', 'content', 'tags'])

def is_public_essay(essay_path):
    dirpath, filename = os.path.split(essay_path)
    (essay_shortname, extension) = os.path.splitext(filename)
    if extension not in ALLOWED_EXTENSIONS:
        return False
    if filename[0] == '_':
        return False
    return True

def make_rss(compiled_essays: list[Essay]):

    feed = feedgenerator.Atom1Feed(
        title="Modern Descartes - Essays by Brian Lee",
        link=os.path.join(WEBSITE_URL, ESSAY_WEBDIR),
        description="I seek, therefore I am")
    for essay in compiled_essays[:10]:
        feed.add_item(
            title=essay.title,
            link=os.path.join(WEBSITE_URL, ESSAY_WEBDIR, essay.slug),
            description=compile_html('rss_item.txt', essay=essay),
            pubdate=essay.date)
    with open(os.path.join(STAGING_DIR, ESSAY_WEBDIR, 'rss.xml'), 'w') as f:
        feed.write(f, 'utf-8')

def compile_html(template_name, **context):
    default_context = {"ESSAY_WEBDIR": ESSAY_WEBDIR}
    default_context.update(**context)
    template = JINJA_ENV.get_template(template_name)
    compiled = template.render(**default_context)
    return compiled

def compile_and_write_html(template_name: str, output_file: str, **context):
    compiled = compile_html(template_name, **context)
    output_path = os.path.join(STAGING_DIR, output_file)
    os.makedirs(os.path.dirname(output_path), exist_ok=True)
    with open(output_path, 'w') as f:
        f.write(compiled)

def parse_essay(essay_path):
    essay_shortname = os.path.splitext(os.path.basename(essay_path))[0]
    with open(essay_path, 'r') as f:
        essay_longname = f.readline().rstrip('\n')
        year, month, day = f.readline().rstrip('\n').split('/')
        tags = list(filter(bool, f.readline().rstrip('\n').split(',')))
        essay_date = datetime.date(year=int(year), month=int(month),
            day=int(day))
        essay_content = f.read()
    result = subprocess.run(
        "pandoc -f markdown -t html --mathjax --shift-heading-level-by=1",
        stdout=subprocess.PIPE,
        input=essay_content.encode('utf8'),
        shell=True)
    essay_content = result.stdout.decode('utf8')

    return Essay(slug=essay_shortname, title=essay_longname,
                 date=essay_date, content=essay_content, tags=tags)

def compile_essay(essay_path) -> list[Essay]:
    if not is_public_essay(essay_path):
        return []

    try:
        essay = parse_essay(essay_path)
        compile_and_write_html('essay_detailed.html',
            'essays/{}/index.html'.format(essay.slug), essay=essay)
        return [essay]
    except Exception as e:
        print('Failed to process {}'.format(essay_path))
        print(type(e), e)
    return []

def compile_essays() -> list[Essay]:
    print("Processing essays...")
    all_essays = []
    for dirpath, _, filenames in os.walk(ESSAY_DIR):
        for filename in filenames:
            all_essays.extend(compile_essay(os.path.join(dirpath, filename)))

    print("Compiled {} essays".format(len(all_essays)))
    return all_essays

def compile_all():
    assert STAGING_DIR not in ('/', '.', '..', '')
    subprocess.run('[ -d {} ] && rm -r {}'.format(STAGING_DIR, STAGING_DIR), shell=True, stderr=subprocess.STDOUT)
    compile_and_write_html('404.html', '404.html')
    compile_and_write_html('index.html', 'index.html')
    all_essays = compile_essays()
    essays_sorted = sorted(all_essays, key=lambda e: e.date, reverse=True)
    essays_by_tag = defaultdict(list)
    for essay in essays_sorted:
        for tag in essay.tags:
            essays_by_tag[tag].append(essay)
    compile_and_write_html('essay_index.html', 'essays/index.html',
        essays_sorted=essays_sorted, tags=essays_by_tag)
    for tag, essays_with_tag in essays_by_tag.items():
        compile_and_write_html('essay_tag.html', 'essays/tags/{}/index.html'.format(tag),
            tag=tag, essays_with_tag=essays_with_tag)
    make_rss(essays_sorted)
    subprocess.run('cp -r -p {static} {staging}/{static}'.format(
        static=STATIC_DIR, staging=STAGING_DIR), shell=True)

class RecompileEssayHandler(watchdog.events.LoggingEventHandler):
    def dispatch(self, event):
        essay_path = os.fsdecode(event.src_path)
        if is_public_essay(essay_path):
            print(f'Recompiling {essay_path}...', end="")
            compile_essay(essay_path)
            print('done.')
        else:
            print(f"Ignoring {essay_path}")

if __name__ == '__main__':
    compile_all()
    webserver = subprocess.Popen(['python', '-m', 'http.server', '8888', '-d', 'staging'])
    atexit.register(webserver.kill)
    event_handler = RecompileEssayHandler()
    observer = watchdog.observers.Observer()
    observer.schedule(event_handler, ESSAY_DIR, recursive=True)
    observer.start()
    try:
        while observer.is_alive():
            observer.join(1)
    finally:
        observer.stop()
        observer.join()


# -*- coding: utf-8 -*-
__author__ = "yangtao"

import sys
import datetime
import os

from PySide2 import QtWidgets
from PySide2 import QtGui

class Unpack_Widget(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(Unpack_Widget, self).__init__(parent=parent)
        self.setWindowTitle("释放")
        self.setMinimumWidth(400)

        self.pack_dir_edit = QtWidgets.QLineEdit()
        self.pack_dir_edit.setPlaceholderText("输入“包文件”夹路径")
        self.resolve_button = QtWidgets.QPushButton("解析")
        self.pack_dir_layout = QtWidgets.QHBoxLayout()
        self.pack_dir_layout.addWidget(self.pack_dir_edit)
        self.pack_dir_layout.addWidget(self.resolve_button)

        self.map_layout = QtWidgets.QFormLayout()

        # 开始
        self.start_button = QtWidgets.QPushButton("释放")
        self.start_button.setEnabled(False)

        self.main_layout = QtWidgets.QVBoxLayout(self)
        self.main_layout.addLayout(self.pack_dir_layout)
        self.main_layout.addLayout(self.map_layout)
        self.main_layout.addWidget(self.start_button)

        self.start_button.clicked.connect(lambda: self.close())

    def get_map(self, map_label):
        drives_map = {}
        for l in map_label:
            value = self.findChild(QtWidgets.QLineEdit, l).text()
            drives_map[l] = value
        return drives_map

    def add_map(self, map_label):
        self.remove_map()
        if map_label:
            for l in map_label:
                label = QtWidgets.QLabel("%s >>> "%l)
                edit = QtWidgets.QLineEdit()
                edit.setObjectName(l)
                self.map_layout.addRow(label, edit)
            self.start_button.setEnabled(True)

    def remove_map(self):
        for row in range(self.map_layout.rowCount()):
            self.map_layout.removeRow(0)
        self.start_button.setEnabled(False)

class Pack_Widget(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(Pack_Widget, self).__init__(parent=parent)
        self.setWindowTitle("打包")
        self.setMinimumWidth(400)

        file_name_label = QtWidgets.QLabel("Nuke工程文件")
        self.file_name_edit = QtWidgets.QLineEdit()
        export_dir_label = QtWidgets.QLabel("输出路径")
        self.export_dir_edit = QtWidgets.QLineEdit()

        # 开始
        self.start_button = QtWidgets.QPushButton("打包")

        self.main_layout = QtWidgets.QFormLayout(self)
        self.main_layout.addRow(file_name_label, self.file_name_edit)
        self.main_layout.addRow(export_dir_label, self.export_dir_edit)
        self.main_layout.addRow(self.start_button)

        self.start_button.clicked.connect(lambda :self.close())

class Mian_Widget(QtWidgets.QWidget):
    def __init__(self):
        super(Mian_Widget, self).__init__()
        self.setWindowIcon(QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_TitleBarCloseButton))
        self.setWindowTitle("DZL Nuke 工程打包工具 by yangtao")
        self.setMinimumWidth(485)

        # 信息框
        self.info_edit = QtWidgets.QTextEdit()
        self.info_edit.setWordWrapMode(QtGui.QTextOption.NoWrap)

        # 打包，释放按钮
        self.pack_button = QtWidgets.QPushButton("打包")
        self.pack_button.setObjectName("pack_project")
        self.pack_button.setIcon(QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_ArrowDown))
        self.unpack_button = QtWidgets.QPushButton("释放")
        self.unpack_button.setObjectName("unpack_project")
        self.unpack_button.setIcon(QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_ArrowUp))

        expand_button_layout = QtWidgets.QHBoxLayout()
        expand_button_layout.addWidget(self.pack_button)
        expand_button_layout.addWidget(self.unpack_button)

        # 打包，释放 UI
        self.pack_widget = Pack_Widget(self)
        self.unpack_widget = Unpack_Widget(self)
        #self.unpack_widget.add_map(["a", "b", "c", "d"])
        #self.unpack_widget.setHidden(True)

        main_layout = QtWidgets.QVBoxLayout(self)
        main_layout.addWidget(self.info_edit)
        main_layout.addLayout(expand_button_layout)

        # connect
        self.pack_button.clicked.connect(self.show_pack_widget)
        self.unpack_button.clicked.connect(self.show_pack_widget)

    def set_button_enabled(self, status):
        self.pack_button.setEnabled(status)
        self.unpack_button.setEnabled(status)

    def add_info(self, text, add_time_line=True):
        current_info = self.info_edit.toPlainText()
        if add_time_line:
            time_line = "%s:\n"%datetime.datetime.now().strftime("%H:%M:%S")
        else:
            time_line = ""
        new_info = current_info + time_line + text
        self.info_edit.setText("%s\n"%new_info)
        self.info_edit.moveCursor(QtGui.QTextCursor.End)

    def show_pack_widget(self):
        if self.sender().objectName() == "pack_project":
            self.pack_widget.show()
            self.unpack_widget.close()

        if self.sender().objectName() == "unpack_project":
            self.pack_widget.close()
            self.unpack_widget.show()

if __name__ == "__main__":
    app = QtWidgets.QApplication()
    mw = Mian_Widget()
    mw.show()
    sys.exit(app.exec_())


import numpy
import numpy as np
import logging, os
import pandas as pd
import plotly.graph_objects as go
from tabulate import tabulate
import plotly.express as px
# import EntropicFOMs
from EntropicFOMs.SyntheticData import *
from EntropicFOMs.ObjFunctions import *
import numpy.random as nprand
import numpy.linalg as nplin
logging.basicConfig(level = logging.INFO)

class sFoms(object):
    """
    The class for first order stochastic methods to solve the strongly convex optimization problem.

    Attributes
    ----------
        path:  str
            The path to the folder to which the results are going to be saved.
        optim_problem: str
            quadratic:          Smooth strongly convex quadratic cost function.
            synthetic_logit:    Smooth strongly convex logistic cost defined on synthetic data.
        init_x0:
            The initial point for the algorithm.
              None:     The initialization sampled from a standard uniform distribution.
              "fixed":  The initialization is unit vector.
              np.ndarray: (# of feat, 1)
        eig_vals: np.array
            The eigenvalues of the Hessian of quadratic objective function.
            Required by "quadratic" optimization problem..
        reg_param: np.array
            The regularization parameter of the optimization problem. Set to be 1 by default.
        noise_std: float (default: 0)
            The standard deviation of the additive Gaussian noise on the gradient of the cost function.
        data_std: float
            The standard deviation of the random matrix used to generate synthetic data.
            Required by "synthetic_logit" optimization problem.
        data_size:
            The size of the syntethic data required by "synthetic_logit" optimization problem.
        num_of_feat:
            The number of features in the "synthetic_logit" optimization problem.

    Functions
    -------
    train(learning_rate=0.01, iter_momentum=0, grad_momentum=0, stop_criteria=None, Samples=1, seed=None)
        Trains the model using stochastic first order method:
        .. math ::

            x_{k+1}=x_{k}+iter_momentum*(x_{k}-x_{k-1})-learning_rate*\tilde{\nabla}f(x_k)+\gamma*(x_{k}-x_{k-1})

    subopt_fig_data():
        Generates mean, one standard deviation below and above of the mean for the iterates of the  stochastic first order method.
    """
    # Path to the folder in which the results are going to be stored.
    # Enter local folder manually:
    # path = "local folder/",
    # or retrieve the current path and create an experiment results folder inside the current path:
    path=os.getcwd()+"/risk-averse GMM experiments/"
    # Check whether the path exists. Create if it does not
    if not os.path.isdir(path):
        os.mkdir(path)

    def __init__(self, optim_problem=None,eig_vals=None, init_x0=None, reg_param=0,
    noise_std=0, data_std=None, data_size=None, num_of_feat=None):
        self.__dict__.update(locals())
        # Quadratic objectives
        if optim_problem == "quadratic":
            if self.eig_vals is None:
                raise Exception("Enter the attribute: eig_vals ")
            self.num_of_feat = len(self.eig_vals)
            self.data_optim=None

            # Define the objective function
            self.func= lambda x: quadratic_cost(x, eigs=self.eig_vals, regulizer=self.reg_param, sigma=self.noise_std)

        # Logistic regression on synthetic data
        elif optim_problem == "synthetic_logit":
            # Check for attributes
            if (self.data_std or self.data_size or self.num_of_feat) is None:
                raise Exception("Enter the attributes: data_std, data_size and num_of_feat ")

            # Generate the synthetic data
            self.X, self.Y, self.data_optim = Create_Classification_Data(self.data_std, self.data_size, self.num_of_feat,
                                                                  seed=1)
            try:
                self.noise_std
            except:
                self.noise_std=0
            try:
                self.reg_param
            except:
                logging.info("Setting regularization parameter = 1")
                self.reg_param=float(1)
            # Define the objective function
            self.func = lambda w: logistic_cost(w, self.X, self.Y, reg=self.reg_param, sigma=self.noise_std)

        else:
            raise Exception("Unknown optimization problem. The allowed methods are 'quadratic' and 'synthetic_logit'.")

        if self.init_x0 is None and self.optim_problem is not None:
            self.init_x0 = nprand.normal(size=(self.num_of_feat, 1))
        elif self.init_x0 == "fixed" and self.optim_problem is not None:
            self.init_x0 = np.ones((self.num_of_feat, 1))

    def train(self, learning_rate=0.01, iter_momentum=0, grad_momentum=0, stop_criteria=None, Samples=1,seed=None):
        """
        Runs the first order methods under given choice of parameters to solve the optimization problem, optim_problem, until stopping criteria is satisfied.

        :param learning_rate: float
            The learning rate of the algorithm.
        :param iter_momentum: float (default: 0)
            The momentum parameter on the iterations, i.e. \beta
        :param grad_momentum: float (default: 0)
            The momentum parameter on the iterates on which the gradient is computed, i.e. \gamma
        :param stop_criteria: (default: None)
            None: The algorithm runs until the gradient norm computed at the iteration is below 1e-4 or number
                  of iterations is less than 2000.
            int: The algorithm runs until the number of iterations reaches stop_criteria.
        :param Samples: (default: 100)
            The number of sample paths that will be generated.
        :param seed: int (default: None)
            Fix the seed for random number generators.
        :return:
            csv file:
                The function values, generated using stochastic first
                order methods, together with the last iterate are saved to
                    "path/optim_problem".
        """
        if seed is not None: nprand.seed(seed)

        logging.info( f"Training model...\n"\
                      f"learning rate |  { learning_rate :2.3f} | Iteration momentum |  {iter_momentum :2.3f} "\
                      f"| Gradient Momentum | {grad_momentum : 2.3f}")
        # Store the results at fk_values.
        colnames=[str(i) for i in range(0,Samples)]
        self.suboptimality_data = pd.DataFrame([], columns=colnames)

        # Generate the results path
        if iter_momentum == 0 and grad_momentum == 0:
            method_name = "_GD" + "_Var_" + str(self.noise_std)
        elif iter_momentum != 0 and grad_momentum == 0:
            method_name = "_Polyak" + "_Var_" + str(self.noise_std)
        elif iter_momentum != 0 and grad_momentum == iter_momentum:
            method_name = "_AGD" + "_Var_" + str(self.noise_std)
        else:
            method_name = "_TMM" + "_Var_" + str(self.noise_std)

        # Assign results to attribute for further reference.
        self.suboptimality_data_path = self.path + self.optim_problem +"_subopt" + method_name + ".csv"
        self.log_path = self.path+self.optim_problem+"_log"+method_name+".txt"

        self.train_result=None # Collect last iterates of each trial

        # Generate the log for the algorithm
        alg_log=f"The Parameters: \n"\
                      f"learning rate |  { learning_rate :2.3f} | Iteration momentum |  {iter_momentum :2.3f} "\
                      f"| Gradient Momentum | {grad_momentum : 2.3f}"+"\n"
        x0=self.init_x0

        for trial in range(Samples):
            # Initiate algorithm
            run_algorithm = True
            num_of_iterations=1
            xk=x0
            xk_1=x0
            fn, gn = self.func(xk)
            iterates=[fn]
            if trial==0:
                logging.info(f"Iterations of 1st sample:")
                alg_log+=f"Iterations of 1st sample: \n"

            # Run the algorithm
            while run_algorithm:
                yk=xk+iter_momentum*(xk-xk_1)
                zk=xk+grad_momentum*(xk-xk_1)
                _, gn= self.func(zk)
                x_next=yk-learning_rate*gn
                xk_1=xk
                xk=x_next
                fn, gn = self.func(xk)
                iterates=np.append(np.around(iterates,decimals=5),fn)
                # Logging
                if trial == 0 and num_of_iterations%50==0 :
                    logging.info(f"Iteration: {num_of_iterations}| Function Value: {fn :.4f}"+f"| Norm of gradient: {np.linalg.norm(gn): .4f}")
                    alg_log+= f"Iteration: {num_of_iterations}| Function Value: {fn :.4f}"+f"| Norm of gradient: {np.linalg.norm(gn): .4f}"+"\n"
                # Stopping criteria
                num_of_iterations += 1
                if stop_criteria == None:
                    if nplin.norm(gn) < 1e-4 or num_of_iterations>=2000:
                        run_algorithm=False
                else:
                    if num_of_iterations > stop_criteria:
                        run_algorithm=False

            # Collect the iterations of trial.
            self.suboptimality_data[str(trial)]=iterates

            # Collect the last iterate of each trial
            if self.train_result is None:
                self.train_result=xk.reshape(-1, 1)
            else:
                self.train_result=np.append(self.train_result,xk.reshape(-1,1),axis=1)

        # Save data into csv file.
        self.suboptimality_data.to_csv(self.suboptimality_data_path)
        logging.info(f'Saved the suboptimality results into the path: \n' \
                     f'{self.suboptimality_data_path}')
        with open(self.log_path, 'w') as logfile:
            print(alg_log,file=logfile)

    def subopt_fig_data(self):
        """
        Generates mean, one standard deviation below and above of the mean for the iterates of the  stochastic first order method.
        :return:
        std_below: pandas.Series (# of iterations)
            The expected suboptimality - std of suboptimality at each iteration.
        mean:     pandas.Series (# of iterations)
            The expected suboptimality path generated by train().

        std_above: pandas.Series (# of iterations)
            The expected suboptimality + std of suboptimality at each iteration.
        """
        # Collect graph data
        graph_data=pd.read_csv(self.suboptimality_data_path, index_col=0)
        # Compute the mean and std
        mean, std = graph_data.mean(1), graph_data.std(1)
        std_above, std_below = mean + std, mean - std
        return std_below, mean, std_above

    def L_and_mu_logistic_reg(self):
        """
        Compute the upper bound on the L-smoothness parameter of the logistic regression over data.
        Source: http://lcsl.mit.edu/courses/isml2/isml2-2015/scribe14A.pdf
        :return:
        """
        s,f=self.X.shape
        eigs, _ =nplin.eig(np.matmul(self.X.T,self.X))
        return 1/s*eigs.max()+self.reg_param, self.reg_param

    def create_subopt_plot(self ,name, fig_color="rgba(0, 91, 247)", Figure= None):
        """
        Generates the plot of suboptimality data generated by train() function.
        :param name: str
            The name of the figure that s going to be printed in the legend
        :param fig_color: str (rgba color format, default: "rgba(0, 91, 247)")
            The color of the figure that is plotted.
        :param Figure: (default:  None)
            None:         Creates a new go.Figure() file and generates the suboptimality figure.
            go.Figure():  Generates the suboptimality figure and adds it into the go.Figure() file provided.
        :return:
            go.Figure()
        """

        if Figure == None:
            subopt_figures= go.Figure()
        else:
            subopt_figures= Figure
        std_below, mean, std_above = self.subopt_fig_data()
        subopt_figures.add_trace(go.Scatter(y=mean,
                                            name=name + "-mean",
                                            line=dict(width=5, color=fig_color[0:-1] + ",1)")))

        subopt_figures.add_trace(go.Scatter(y=std_above,
                                            name="",
                                            fill=None,
                                            # fillcolor='rgba(0, 91, 247,0.30)',
                                            line=dict(width=0, color=fig_color[0:-1] + ",0.25)"),
                                            showlegend=False))
        subopt_figures.add_trace(go.Scatter(y=std_below,
                                            name="",
                                            fill="tonexty",
                                            fillcolor=fig_color[0:-1] + ",0.25)",
                                            mode='none',
                                            showlegend=False))
        subopt_figures.update_layout(legend=dict(orientation="h",
                                                 xanchor="center",
                                                 x=0.5,
                                                 yanchor="top",
                                                 y=1,
                                                 ),
                                     font=dict(size=20),
                                     legend_font_size=25)
        return subopt_figures

    # Functions parameter selection and plotting regions
    #  Quadratic objectives
    def quad_stab_reg(self, eigs, nbins=50):
        """
        Calculates the stable region of GMM, S_q, given in [Can and Gurbuzbalaban, 2022] for convex quadratic
        objectives using grid search.
        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param nbins: int
            The number of bins that is going to be used in grid search on all alpha, beta, and gamma.
        :return:
            region: np.array (alpha,beta,gamma ,rho)
                The list that contains the parameters alpha, beta, gamma belonging to stable set and the rate
                rho suggested by Lemma 3.1
        """
        beta, gamma = np.linspace(0,1,nbins), np.linspace(0,1,nbins)
        alpha= np.linspace(0,1/max(eigs),nbins)
        # Alpha should be positive
        alpha= np.delete(alpha, np.where(alpha==0))
        # check the type of eigs:
        if type(eigs) != numpy.ndarray:
            eigs=np.array(eigs)
        region=None
        for a in alpha:
            for b in beta:
                for g in gamma:
                    c_i = (1 + b) - a * (1 + g)*eigs
                    d_i = -b+a*g*eigs
                    rho_i_1=abs(c_i-np.emath.sqrt(c_i**2+4*d_i))/2
                    rho_i_2=abs(c_i+np.emath.sqrt(c_i**2+4*d_i))/2
                    rho_i=np.concatenate([[rho_i_1],[rho_i_2]])
                    rho=np.max(np.max(rho_i,0))
                    if rho<1:
                        if region is None:
                            region=np.array([[a,b,g,rho]])
                        else:
                            region=np.concatenate((region,
                                                   np.array([[a,b,g,rho]])),axis=0)
        return region

    def quad_agd_stab_reg(self, eigs, nbins=50):
        """
        Calculates the stable region of AGD given in [Can and Gurbuzbalaban, 2022] for convex quadratic
        objectives using grid search.
        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param nbins: int
            The number of bins that is going to be used in grid search on all alpha, beta, and gamma.
        :return:
            region: np.array (alpha,beta,beta,rho)
                The list that contains the parameters alpha, beta, gamma belonging to stable set and the rate
                rho suggested by Lemma 3.1
        """
        beta = np.linspace(0,1,nbins)
        alpha= np.linspace(0,2/(min(eigs)+max(eigs)),nbins)
        # Alpha should be positive
        alpha= np.delete(alpha, np.where(alpha==0))
        # check the type of eigs:
        if type(eigs) != numpy.ndarray:
            eigs=np.array(eigs)
        region=None
        for a in alpha:
            for b in beta:
                g = b
                c_i = (1 + b) - a * (1 + g)*eigs
                d_i = -b+a*g*eigs
                rho_i_1=abs(c_i-np.emath.sqrt(c_i**2+4*d_i))/2
                rho_i_2=abs(c_i+np.emath.sqrt(c_i**2+4*d_i))/2
                rho_i=np.concatenate([[rho_i_1],[rho_i_2]])
                rho=np.max(np.max(rho_i,0))
                if rho<1:
                    if region is None:
                        region=np.array([[a,b,g,rho]])
                    else:
                        region=np.concatenate((region,
                                               np.array([[a,b,g,rho]])),axis=0)
        return region

    def quad_gd_stab_reg(self, eigs, nbins=50):
        """
        Calculates the stable region of GD given in [Can and Gurbuzbalaban, 2022] for convex quadratic
        objectives using grid search.
        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param nbins: int
            The number of bins that is going to be used in grid search on all alpha, beta, and gamma.
        :return:
            region: np.array (alpha, 0, 0,rho)
                The list that contains the parameters alpha, beta, gamma belonging to stable set and the rate
                rho suggested by Lemma 3.1
        """
        alpha= np.linspace(0,2/(min(eigs)+max(eigs)),nbins)
        # Alpha should be positive
        alpha= np.delete(alpha, np.where(alpha==0))
        # check the type of eigs:
        if type(eigs) != numpy.ndarray:
            eigs=np.array(eigs)
        region=None
        for a in alpha:
            b=0
            g=b
            c_i = (1 + b) - a * (1 + g)*eigs
            d_i = -b+a*g*eigs
            rho_i_1=abs(c_i-np.emath.sqrt(c_i**2+4*d_i))/2
            rho_i_2=abs(c_i+np.emath.sqrt(c_i**2+4*d_i))/2
            rho_i=np.concatenate([[rho_i_1],[rho_i_2]])
            rho=np.max(np.max(rho_i,0))
            if rho<1:
                if region is None:
                    region=np.array([[a,b,g,rho]])
                else:
                    region=np.concatenate((region,
                                           np.array([[a,b,g,rho]])),axis=0)
        return region

    def quad_stab_region_borders(self,eigs, nbins=50):
        """
        Calculates the borders/frontier of the stable region of GMM based on quad_stab_reg().
        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param nbins: float
            The number of bins that is going to be used in grid search on all alpha, beta, and gamma.
        :return:
            border: np.array (alpha, beta/gamma)
                The region alpha versus the maximum beta/gamma belonging to stable set at given alpha.
        """
        stable_region=self.quad_stab_reg(eigs,nbins)
        non_zero_gamma = np.where(stable_region[:, 2] != 0)
        ratio = np.array(stable_region[non_zero_gamma, 1] / stable_region[non_zero_gamma, 2])
        # Round the alpha to obtain the borders ofg the set
        alpha = np.round(np.array(stable_region[non_zero_gamma, 0]), 3)
        # Retrieve the borders
        border = None
        for a in np.unique(alpha):
            r = ratio[np.where(alpha == a)]
            if border is None:
                border = np.array([[a, r.max()]])
            else:
                border = np.concatenate((border, np.array([[a, r.max()]])))
        return border

    def quad_feas_region(self, stable_region, eigs, theta=1, std=1):
        """
        Calculates the feasible region given in [Can and Gurbuzbalaban, 2022. Prop 3.3].
        :param stable_region: np.array
            The stable region of GMM
        :param eigs: np.array
            The eigenvalues of the Hessian of quadratic objective.
        :param theta:
            The risk averseness parameter.
        :param std:
            The standard deviation on the noise in the gradient.
        :return:
            feas_region: np.array (alpha,beta,gamma, risk_meas, rate)
                The list of parameters alpha, beta, and gamma together with suggested risk measure and the rate.
        """
        # Check the format of stable region
        feas_region= None
        if len(stable_region.shape)==1:
            alpha, beta, gamma = stable_region
        else:
            for params in stable_region:
                # Stable region has alpha,beta,gamma, and rho.
                alpha,beta,gamma, rate = params
                risk_meas=self.quad_risk_measure(alpha, beta, gamma, eigs, theta, std)
                if risk_meas != None:
                    if feas_region is None:
                        feas_region = np.array([[alpha,beta,gamma,risk_meas,rate]])
                    else:
                        feas_region=np.concatenate((feas_region,np.array([[alpha,beta,gamma,risk_meas,rate]])))
        return feas_region

    def quad_feas_region_borders(self, e_vals, nbins=50, theta=1, std=1):
        """
        Calculate the border of the feasible region computed for smooth convex quadratic objectives.

        :param e_vals: np.array
            The eigenvalues of the Hessian of quadratic objective.
        :param nbins: float
            The number of bins for grid searching the parameters.
        :param theta: float
            The risk averseness paramters
        :param std:
            The standard deviation of noise on the gradient.
        :return:
            border: np.array (alpha, beta/gamma)
                The border of the feasible region. That is alpha versus maximum feasible beta/gamma for given alpha.
        """
        stable_region=self.quad_stab_reg(e_vals,nbins)
        feas_region=self.quad_feas_region(stable_region, e_vals, theta, std)
        # feas_region = [alpha,beta, gamma, risk measure, rate]
        non_zero_gamma= np.where(feas_region[:,2]!=0)
        ratio= np.array(feas_region[non_zero_gamma,1]/feas_region[non_zero_gamma,2])
        # Round the alpha to obtain the borders ofg the set
        alpha= np.round(np.array(feas_region[non_zero_gamma,0]),3)
        rate= np.array(feas_region[non_zero_gamma,3])
        # Retrieve the borders
        border=None
        for a in np.unique(alpha):
            r=ratio[np.where(alpha==a)]
            if border is None:
                border= np.array([[a,r.max()]])
            else:
                border= np.concatenate((border, np.array([[a,r.max()]])))

        # ratio= feas_region[:,1]/feas_region[:,2]
        # Save figure as html
        # fig.write_html(fig_path+"/str_cnvx_stable_region.html")
        # Save figure as png
        # fig.write_image(fig_path + "/quad_feasible_region.png")
        return border

    def quad_risk_measure(self, alpha, beta, gamma, eigs, theta=1, std=1):
        """
        Computes the entropic risk measure of strongly convex quadratic objectives,

        :param alpha, beta,gamma : float
            The parameters of the TMM algorithm on quadratic objective
        :param eigs: numpy.darray
            The eigenvalues of the Hessian of quadratic objective.
        :param theta:
            The risk parameter for entropic risk measure
        :param std:
            The variance bound on the noise.
        :return:

        risk_meas:   float or None
        ---------
             Returns none if parameters are not feasible, otherwise computes the entropic risk measure at given risk parameter and noise variance.
        """
        if type(eigs)!= numpy.ndarray:
            eigs=np.array(eigs)
        ratio_nom = alpha * (1 + beta - alpha * gamma * eigs)
        ratio_denom = 2*(1 - beta + alpha * gamma * eigs)*(2 * (1 + beta) - alpha * (1 + 2 * gamma) * eigs)
        if 0 in ratio_denom:
            return None
        else:
            ratio = ratio_nom/ratio_denom
            if max(ratio)<1/theta:
                risk_meas= -std ** 2 / theta * sum(np.log(1 - theta * ratio))
            else:
                risk_meas=None
            return risk_meas

    def quad_risk_meas_vs_rate_region_frontier(self, eigs, method="gmm", nbins=50, theta=1, std=1):
        """
        Calculates the frontier of the region quadratic risk measure vs convergence rate on convex quadratic objectives.

        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective function,
        :param method:
            The optimization algorithm, "gd", "agd", or "gmm".
        :param nbins:
            The number of bins used at grid search
        :param theta:
            The risk averseness parameter
        :param std:
            The standard deviation of the noise on the gradient.
        :return:
            frontier: np.array (rate, risk_measure)
                The rate versus the best risk measure found using grid search for that rate.
        """
        if method == "gmm":
            stable_region=self.quad_stab_reg(eigs,nbins)
        elif method=="agd":
            stable_region = self.quad_agd_stab_reg(eigs, nbins)
        elif method=="gd":
            stable_region = self.quad_gd_stab_reg(eigs,nbins)
        rate_sorted_index=np.argsort(stable_region[:,3])
        sorted_stable_region=stable_region[rate_sorted_index,:]
        rate_vs_risk_meas = None
        for params in sorted_stable_region:
            a,b,g,rate = params
            risk_meas=self.quad_risk_measure(a, b, g, eigs, theta, std)
            # Round the risk measure to have a better border
            if risk_meas is not None:
                # Round the rates to obtain a better border for the region
                rate=np.round(rate,2)
                if rate_vs_risk_meas is None:
                    rate_vs_risk_meas=np.array([[rate,risk_meas]])
                else:
                    rate_vs_risk_meas=np.concatenate((rate_vs_risk_meas,np.array([[rate,risk_meas]])))
        # Retrieve the frontier of the set rate_vs_risk_meas
        frontier= None
        for rho in np.unique(rate_vs_risk_meas[:,0]):
            rho_ind = np.where(rate_vs_risk_meas[:, 0] == rho)
            frontier_risk_meas = np.min(rate_vs_risk_meas[rho_ind,1])
            if frontier is None:
                frontier=np.array([[rho, frontier_risk_meas]])
            else:
                frontier=np.concatenate((frontier, np.array([[rho,frontier_risk_meas]])))
        return frontier

    def quad_evar(self, alpha, beta, gamma, eigs, nbins_theta=50, std=1, conf_level=0.95):
        """
        Computes the EVAR for convex quadratic objective by using grid search over theta to solve the minimization problem:
        ..math:
            EV@R_{1-\zeta}= \inf_{0<\theta} r_{\sigma^2}(\theta)+ \frac{2\sigma^2}{\theta}\log(1/\zeta),
        where $\zeta$ is the confidence level.

        :param alpha: float
            Learning rate of the algorithm
        :param beta: float
            Momentum parameter of the iterates of the algorithm
        :param gamma: float
            Momentum parameter of the gradient of the algorithm
        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param nbins_theta:
            The number of bins for the grid searching over theta to compute EVAR by solving the minimization problem.
        :param std:
            The standard deviation of the additive Gaussian noise on the gradient of the objective.
        :param conf_level:
            The confidence level of the EV@R of the algorihtm.
        :return:
            evar: np.array
                The evar computed by solving the minimization problem using grid search over theta.
        """
        theta_range=np.linspace(0,5,nbins_theta)
        # delete theta=0
        theta_range=np.delete(theta_range,0)
        evar=float("inf")
        for theta in theta_range:
            evar_temp=self.quad_risk_measure(alpha, beta, gamma, eigs, theta, std)
            if evar_temp is not None:
                evar_temp+= 2 * std / theta * np.log(1 / conf_level)
                if evar_temp < evar:
                    evar=evar_temp

        return evar

    def frontier_quad_evar_vs_rate_region(self, eigs, method="gmm", nbins_params=50, nbins_theta=50, std=1, conf_level=0.95):
        """
        Calculates the minimum evar suggested at a given rate.

        :param eigs: np.array
            The eigenvalues of the Hessian of quadratic objective.
        :param method:
            The optimization algorithm: "gd", "agd, or "gmm".
        :param nbins_params:
            The number of bins for grid searching over the parameters alpha,beta, and gamma.
        :param nbins_theta:
            The number of bins for grid searchin over theta to find evar.
        :param std:
            The standard deviation of the additive Gaussian noise on the gradient.
        :param conf_level:
            The confidence level for the EV@R
        :return:
            frontier: np.array (rate, evar)
                The rate and the best evar computed at given rate.
        """
        if method == "gmm":
            stable_region = self.quad_stab_reg(eigs, nbins_params)
        elif method == "agd":
            stable_region = self.quad_agd_stab_reg(eigs,nbins_params)
        elif method == "gd":
            stable_region= self.quad_gd_stab_reg(eigs,nbins_params)
        rate_sorted_index = np.argsort(stable_region[:, 3])
        sorted_stable_region = stable_region[rate_sorted_index, :]
        rate_vs_evar = None

        for params in sorted_stable_region:
            a, b, g, rate = params
            evar = self.quad_evar(a, b, g, eigs, nbins_theta, std, conf_level)
            # Round the risk measure to have a better border
            if evar is not None and evar != float("inf"):
                # Round the rates to obtain a better border for the region
                rate = np.round(rate, 2)
                if rate_vs_evar is None:
                    rate_vs_evar = np.array([[rate, evar]])
                else:
                    rate_vs_evar = np.concatenate((rate_vs_evar, np.array([[rate, evar]])))

        # Retrieve the frontier of the set evar vs rate
        frontier = None
        for rho in np.unique(rate_vs_evar[:, 0]):
            rho_ind = np.where(rate_vs_evar[:, 0] == rho)
            frontier_evar = np.min(rate_vs_evar[rho_ind, 1])
            if frontier is None:
                frontier = np.array([[rho, frontier_evar]])
            else:
                frontier = np.concatenate((frontier, np.array([[rho, frontier_evar]])))
        return frontier

    def quad_evar_bound(self, alpha, beta, gamma, eigs, std, conf_level):
        """
        Calculate the evar bound for convex quadratic objectives given in [Can and Gurbuzbalaban, 2022. Theorem 1].
        :param alpha: float
            Learning rate of the algorithm
        :param beta: float
            Momentum parameter on the iterations of the algorithm.
        :param gamma: float
            Momentum parameters on the gradient of the algorithm
        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param std:
            The standard deviation of the additive Gaussian noise on the gradient of the objective.
        :param conf_level:
            The confidence level of EV@R
        :return:
            evar_bound: np.array
                The evar bound comoputed at given parameters and confidence level for noise with std provided.
        """
        if type(eigs)!= numpy.ndarray:
            eigs=np.array(eigs)
        d=len(eigs)
        ratio_denom = alpha * (1 + beta - alpha * gamma * eigs)
        ratio_nom = (1 - beta + alpha * gamma * eigs)*(2 * (1 + beta) - alpha * (1 + 2 * gamma) * eigs)
        if 0 in ratio_denom:
            return None
        else:
            u_i = ratio_nom/ratio_denom
            u_min=min(2*u_i)
            theta_0=np.log(1/conf_level)/d*(np.sqrt(1+(2*d)/np.log(1/conf_level))-1)
            evar_bound= std / (u_min * theta_0) * (-d * np.log(1 - theta_0) + 2 * np.log(1 / conf_level))
            return evar_bound

    def frontier_quad_evar_bound_vs_rate(self, eigs, method="gmm", nbins_params=50, std=1, conf_level=0.95):
        """
        Calculates frontier for the region rate vs bound on the evar of quadratic objective.

        :param eigs: np.array
            The eigenvalues of the Hessian of the quadratic objective.
        :param method:
            The optimization method: "gd", "agd", or "gmm".
        :param nbins_params:
            The number of bins to grid search over the parameters alpha, beta, and gamma.
        :param std:
            The standard deviation of the additive Gaussian noise on the gradient.
        :param conf_level:
            The confidence level of EV@R
        :return:
            frontier: np.array (rho, evar_bound)
                The list of rate and the evar bound computed at parameters giving the same rate.
        """
        if method == "gmm":
            stable_region = self.quad_stab_reg(eigs, nbins_params)
        elif method == "agd":
            stable_region = self.quad_agd_stab_reg(eigs, nbins_params)
        elif method == "gd":
            stable_region = self.quad_gd_stab_reg(eigs, nbins_params)
        rate_sorted_index = np.argsort(stable_region[:, 3])
        sorted_stable_region = stable_region[rate_sorted_index, :]
        rate_vs_evar_bound = None

        for params in sorted_stable_region:
            a, b, g, rate = params
            evar_bound = self.quad_evar_bound(a, b, g, eigs, std, conf_level)
            # Round the risk measure to have a better border
            if evar_bound is not None and evar_bound != float("inf"):
                # Round the rates to obtain a better border for the region
                rate = np.round(rate, 2)
                if rate_vs_evar_bound is None:
                    rate_vs_evar_bound = np.array([[rate, evar_bound]])
                else:
                    rate_vs_evar_bound = np.concatenate((rate_vs_evar_bound, np.array([[rate, evar_bound]])))

        # Retrieve the frontier of the set evar vs rate
        frontier = None
        for rho in np.unique(rate_vs_evar_bound[:, 0]):
            rho_ind = np.where(rate_vs_evar_bound[:, 0] == rho)
            frontier_evar = np.min(rate_vs_evar_bound[rho_ind, 1])
            if frontier is None:
                frontier = np.array([[rho, frontier_evar]])
            else:
                frontier = np.concatenate((frontier, np.array([[rho, frontier_evar]])))
        return frontier

    # Strongly convex smooth objectives
    def str_cnvx_stab_reg_params(self, L, mu, vart_nbins=100, psi_nbins=100):
        """
        Finds stable region, S_q, of GMM on strongly convex smooth non-quadratic objective
        which is given in [Can and Gurbuzbalaban, 2022. Theorem 2].
        :param L: float
            The smoothness parameter of the objective
        :param mu: float
            The strong convexity constant of the objective.
        :param vart_nbins:
            The number of bins to be used to grid search over vartheta.
        :param psi_nbins:
            The number of bins to be used to grid search over psi.

        :return:
            stable_set: np.array (vartheta, psi, rate)
                The stable region found by grid search over vartheta and psi.
        """
        kappa = L/mu
        psi_vals_low = np.linspace(0, 1, psi_nbins + 1)
        psi_vals_high = np.linspace(1, 2*kappa*(1+np.sqrt(1-1/kappa)), psi_nbins + 1)
        # Erase the 1 from arrays
        psi_vals_low = np.delete(psi_vals_low, psi_nbins)
        psi_vals_high = np.delete(psi_vals_high, 0)
        psi_vals = np.concatenate([psi_vals_low, psi_vals_high])

        # Collect stable params
        stable_vart, stable_psi, stable_rate= [], [], []

        for psi in psi_vals:
            # Set S1 as given in the paper
            if psi<1:
                if psi==0:
                    vart_vals_low = 1 / (1 + kappa * (1 - psi))
                else:
                    vart_vals_low = max(2 - 1 / psi, 1 / (1 + kappa * (1 - psi)))
                vart_vals = np.linspace(vart_vals_low, 1, vart_nbins + 1)
                # Erase 1
                vart_vals = np.delete(vart_vals, vart_nbins)
            elif psi>1:
                vart_high = min(2 - 1 / psi, 1/2*(1+np.sqrt(1+4*kappa*(psi-1))))
                vart_vals = np.linspace(1,vart_high, vart_nbins + 1)
                # Erase 1
                vart_vals = np.delete(vart_vals, 0)

            for vart in vart_vals:
                alpha= (1-vart)/(L*(1-psi))
                m_psi= mu*(psi**2)-L*(1-psi)**2
                rho2=1-np.sqrt(vart*alpha*mu)
                condition= rho2*(1-alpha*m_psi/vart)-(1-alpha*psi*mu)**2
                if condition <=0:
                    stable_vart = np.append(stable_vart, vart)
                    stable_psi = np.append(stable_psi, psi)
                    stable_rate = np.append(rho2,stable_rate)

        sort_ind = np.argsort(stable_psi)
        stable_set = np.concatenate([[stable_vart[sort_ind]], [stable_psi[sort_ind]],[stable_rate[sort_ind]]])
        # stable_set=([[stable_vart],[stable_psi], [stable_rate]]) where psi !=1
        return stable_set

    def str_cnvx_agd_stab_reg_params(self, L, mu, alpha_nbins=100):
        """
        Finds stable region, S_q, of AGD on strongly convex smooth non-quadratic objective
        which is given in [Can and Gurbuzbalaban, 2022. Theorem 2].
        :param L: float
            The smoothness parameter of the objective
        :param mu: float
            The strong convexity constant of the objective.
        :param alpha_nbins: float (default: 100)
            The number of bins to be used to grid search over vartheta.
        :return:
            stable_set: np.array (alpha, rate)
                The stable region found by grid search over alpha.
        """

        kappa = L/mu
        vart, psi=1, 1
        alpha_lin=np.linspace(0,2/(L+mu),alpha_nbins)
        # Erase 0 from alpha
        alpha_lin=np.delete(alpha_lin,0)
        # Collect stable params
        stable_alpha, stable_rate= [], []

        for alpha in alpha_lin:
            # Set S0 as given in the paper
            m_psi= mu*(psi**2)-L*(1-psi)**2
            rho2=1-np.sqrt(vart*alpha*mu)
            condition= rho2*(1-alpha*m_psi/vart)-(1-alpha*psi*mu)**2
            if condition <=0:
                stable_alpha = np.append(stable_alpha, alpha)
                stable_rate = np.append(rho2,stable_rate)

        sort_ind = np.argsort(stable_alpha)
        stable_set = np.concatenate([[stable_alpha[sort_ind]],[stable_rate[sort_ind]]])
        # stable_set=([[stable_alpha],[stable_rate]])
        return stable_set

    def str_convx_MI_check(self, L, mu, vart, psi):
        """
        This function checks the MI inequality for alpha, beta, and gamma defined as
        in [Can and Gurbuzbalaban, 2022. (MI)] with respect to vartheta and psi.
        :param L: float
            The smoothness constant of the objective.
        :param mu: float
            The strong convexity constant of the objective.
        :param vart: float
            The parameter of the algorithm
        :param psi: float
            The parameter of the algorithm.
        :return:
            V: np.array
                The matrix M-X, suggested by the MI which should be negative semi-definite.
            eigs: np.array
                The eigenvalues of the matrix (sorted).
        """
        kappa = L/mu
        alpha = (1 - vart)/(L * (1 - psi))
        p = np.sqrt(vart/(2 * alpha))
        p0 = np.sqrt(mu/2)

        rho2 = 1 - np.sqrt(alpha*vart*mu)
        beta = rho2 / (1 - alpha * psi * mu) * (1 - np.sqrt(alpha * mu / vart))
        gamma = psi*beta

        P = np.array([[p], [-p + p0]])
        P= np.matmul(P,P.T)
        A=np.array([[1 + beta, -beta],[1, 0]])
        B = np.array([[-alpha],[0]])
        C = np.array([[(1 + gamma)],[-gamma]])
        delta = beta - gamma
        M1 = np.matmul(A.T,np.matmul(P,A))-rho2*P
        M2 = np.matmul(B.T,np.matmul(P,A))
        M3 = np.matmul(B.T,np.matmul(P,B))
        M1shape= M1.shape
        M2shape= M2.shape
        M3shape= M3.shape
        M =np.zeros((M1shape[0]+M2shape[0], M1shape[1]+M2shape[0]))
        M[0:M1shape[0],0:M1shape[1]]=M1
        M[0:M1shape[0],M1shape[1]:(M1shape[1]+M2shape[0])]=M2.T
        M[M1shape[0]:(M1shape[0]+M2shape[0]),0:M2shape[1]]=M2
        M[M1shape[0]:(M1shape[0]+M3shape[0]),M1shape[1]:(M1shape[1]+M3shape[1])]=M3

        X1 = 1/2 * np.array([[-L*delta**2,L*delta**2,-(1 - alpha * L) * delta],
                            [L*delta**2, -L*delta**2, (1 - alpha * L) * delta],
                            [-(1-alpha*L)*delta, (1-alpha*L)*delta, alpha*(2-alpha*L)]])

        X2 = 1 / 2 * np.array([[gamma**2 * mu, -gamma**2 * mu, -gamma],
                               [-gamma**2*mu, gamma**2*mu, gamma],
                               [-gamma, gamma, 0]])

        X3 = 1 / 2 * np.array([[(1 + gamma)**2*mu, -gamma*(1+gamma)*mu, -(1+gamma)],
                                [-gamma * (1 + gamma) * mu, gamma**2*mu, gamma],
                                [-(1 + gamma), gamma, 0]])
        X=X1+rho2*X2+(1-rho2)*X3
        V=M-X
        return V, np.linalg.eig(V)[0]

    def str_cnvx_evar_bound(self, L, mu, varth, psi, dimension, conf_lev=0.99, std=1):
        """
        Calculates the evar bound provided for strongly convex smooth non-quadratic objectives
        in [Can and Gurbuzbalaban, 2022. Theorem 3]
        :param L: float
            The smoothness parameter of the objective function.
        :param mu: float
            The strong convexity constant of the objective.
        :param varth: float
            The parameter of the algorithm.
        :param psi: float
            The parameter of the algorithm.
        :param dimension: int
            The dimension of the problem, i.e. the number of features.
        :param conf_lev: float
            The confidence level of EV@R
        :param std: float
            The standard deviation of the additive Gaussian noise on the gradient.
        :return:
            evar_bound: np.array
                The evar bound computed at given parameters.
        """
        d=dimension
        kappa=L/mu
        varphi=0.99
        if psi!=1:
            alpha=(1-varth)/(L*(1-psi))
            beta=1-np.sqrt(varth*alpha*mu)/(1-alpha*psi*mu)*(1-np.sqrt((alpha*mu)/varth))
            gamma=psi*beta

        # Define v_{\vartheta,\psi}
        v_vp=2*(L**2)/mu*(2*(beta-gamma)**2+(1-alpha*L)**2*(1+2*gamma+2*(gamma**2)))\
            +0.5*varth/alpha*(1-np.sqrt(varth*alpha*mu))

        # Define the Theta_u^{g} and \theta_\varphi^{g} as defined in equation (4.7)
        theta_u = np.sqrt(varth * mu)/(alpha*(8*v_vp*np.sqrt(alpha)+alpha*np.sqrt(varth*mu)*(varth+alpha*L)))
        theta_var=varphi*theta_u

        bbrho_1 = 0.5 * (1 - np.sqrt(varth * alpha*mu)+(theta_var*4*alpha**2*v_vp)/(2-theta_var*alpha*(varth+alpha*L)))
        bbrho_2=bbrho_1**2+(16*theta_var*alpha**2*v_vp)/(2-theta_var*alpha*(varth+alpha*L))
        bbrho=0.5*bbrho_1+0.5*np.sqrt(bbrho_2)

        if np.log(1/conf_lev)< 0.5*d/(1-bbrho)*((theta_var*alpha*(varth+alpha*L))/(2-theta_var*(varth+alpha*L)))**2:
            out=0.5*alpha*(varth+alpha*L)*(np.sqrt(d/(1-bbrho))+np.sqrt(2*np.log(1/conf_lev)))**2
        else:
            out=d*alpha*(varth+alpha*L)/((1-bbrho)*(2-theta_var*alpha*(varth+alpha*L)))\
                +2*np.log(1/conf_lev)/theta_var
        return std * out

    def str_cnvx_agd_evar_bound(self, L, mu, alpha, dimension, conf_lev=0.95, std=1):
        """
        Calculates the evar bound provided for AGD on strongly convex smooth non-quadratic objectives
        in [Can and Gurbuzbalaban, 2022. Theorem 3]

        :param L: float
            The smoothness parameter of the objective function.
        :param mu: float
            The strong convexity constant of the objective.
        :param alpha: float
            The parameter of the algorithm.
        :param dimension: int
            The dimension of the problem, i.e. the number of features.
        :param conf_lev: float
            The confidence level of EV@R
        :param std: float
            The standard deviation of the additive Gaussian noise on the gradient.
        :return:
            evar_bound: np.array
                The evar bound computed at given parameters.

        """
        d = dimension
        kappa = L / mu
        psi,varth=1, 1
        if np.log(1 / conf_lev) < d / (2 * mu * alpha * varth):
            out = np.sqrt(varth * alpha) * (np.sqrt(2 * np.log(1 / conf_lev)) + np.sqrt(d)) ** 2
        else:
            out = (1 + np.sqrt(alpha * varth * mu)) * \
                  (d / np.sqrt(alpha * varth * mu) + 2 * np.log(1 / conf_lev))
        return 0.5 * (std**2) * out / np.sqrt(mu)

    # Boundary smoothing to compensate for the grid-search
    def smoothTriangle(self, data, degree):
        """
        This part is to smooth out the region data that has been computed using grid search.
        :param data: np.array
            The region data
        :param degree: int
            The degree of smoothing, i.e. averaging scale.
        :return:
            smoothed: np.array
                The smoothed region.
        """
        triangle = np.concatenate((np.arange(degree + 1), np.arange(degree)[::-1]))  # up then down
        smoothed = [data[0]]
        for i in range(degree + 1, len(data) - degree * 2):
            point = data[i:i + len(triangle)] * triangle
            smoothed.append(np.sum(point) / np.sum(triangle))
        # Handle boundaries
        smoothed = [smoothed[0]] * int(degree + degree / 2) + smoothed
        while len(smoothed) < len(data):
            smoothed.append(smoothed[-1])
        return smoothed

    def str_cnv_stable_region_frontier(self, L, mu,vartbins=250, psibins=250):
        """
        Finds the stable region suggested by Theorem 2.

        :param L: float
             The smoothness parameter of the strongly convex smooth non-quadratic objective.
        :param mu:
            The stong convexity paramter of the objective.
        :param vartbins:
            The number of bins to be used to grid search over vartheta.
        :param psibins:
            The number of binst to be used to grid search over psi.
        :return:
            region: np/array (alpha, min(beta/gamma), max(beta/gamma))
                The frontier of the stable region with respect to alpha and the ratio beta/gamma which are defined as
                 a function of vartheta and psi as given in [Can and Gurbuzbalaban, 2022. Theorem 2].
        """
        region = self.str_cnvx_stab_reg_params(L, mu, vart_nbins=vartbins, psi_nbins=psibins)
        # region = (vartheta; psi)
        psi=region[1]
        alpha = (1 - region[0]) / (L * (1 - region[1]))
        alpha = np.round(np.array(alpha),2)
        rate = 1 - np.sqrt(region[0] * alpha * mu)
        rate_opt = 1 - np.sqrt(mu / L)
        rate /= rate_opt
        border=None
        for a in np.unique(alpha):
            # Retrieve the psi values for same a
            ind_a=np.where(alpha == a)
            psi_a= psi[ind_a]
            if border is None:
                border= np.array([[a, psi_a.min(), psi_a.max()]])
            else:
                border=np.concatenate((border, np.array([[a,psi_a.min(),psi_a.max()]])))
        # Smooth out
        for ind, bounds in enumerate(border):
            if ind<len(border)-2 and ind>0:
                if border[ind][2]<border[ind+1][2]:
                    border[ind][2]=1/4*(border[ind-2][2]+border[ind-1][2]+border[ind+1][2]+border[ind+2][2])
        # Neighborhood averaging
        for ind, bounds in enumerate(border):
            if ind<len(border)-3 and ind>1:
                border[ind][2]=1/4*(border[ind-2][2]+border[ind-1][2]+border[ind+1][2]+border[ind+2][2])
        for ind, bounds in enumerate(border):
            if ind<len(border)-2 and ind>0:
                border[ind][2]=1/3*(border[ind-1][2]+border[ind][2]+border[ind+1][2])

        # Add more alpha into region
        new_border= None
        for ind, bounds in enumerate(border):
            if new_border is None:
                new_border=bounds.reshape(1,len(bounds))
            else:
                new_border=np.concatenate((new_border,bounds.reshape(1,len(bounds))))
            if ind>0 and ind<len(border)-2:
                a=0.5*(border[ind][0]+border[ind+1][0])
                psi_min= 0.5*(border[ind][1]+border[ind+1][1])
                psi_max=0.5*(border[ind][2] + border[ind+1][2])
                new_border=np.concatenate((new_border,np.array([[a,psi_min,psi_max]])))

        # Write over the border parameter
        border=new_border
        end=len(border[:,2])-55
        # Triangular smoothing out
        border[53:end,2]=self.smoothTriangle(border[53:end,2],10)
        # border[:,2]=self.smoothTriangle(border[:,2],5)
        return border

    def rate_vs_evar_bound_frontier(self, L, mu, dimension, std=1, conf_level=0.95, varthbins=250):
        """
        Finds the rate and evar bound for agd at given parameters so that the comparison rate versus evar bound can be done.
        :param L: float
            The smoothness parameter of the objective.
        :param mu: float
            The strong convexity parameter of the objective.
        :param dimension: int
            The dimension of the problem, i.e. the number of features.
        :param std: float
            The stadnard deviation of the additive Gaussian noise on the gradient.
        :param conf_level: float
            The confidence level of the EV@R.
        :param varthbins:
            The number of bins to grid search over vartheta.
        :return:
            frontier: np.array (alpha,rate,evar)
                The list of alpha, rate and evar suggested by given alpha.
        """
        psi=1
        varth= np.linspace(0,1/L,varthbins)
        varth= np.delete(varth,len(varth)-1)
        varth= np.delete(varth,0)
        frontier= None
        for v in varth:
            evar= self.str_cnvx_evar_bound(L, mu, v, psi, dimension, conf_level, std)
            a = (1 - v) / L
            rate= 1-np.sqrt(a*v*mu)
            if frontier is None:
                frontier=np.array([[a,rate,evar]])
            else:
                frontier=np.concatenate((frontier, np.array([[a,rate,evar]])))
        return frontier


import asyncio
import logging
from functools import wraps
from typing import Generator, Tuple

from fastapi import HTTPException
from google.auth.exceptions import InvalidValue, MalformedError
from google.auth.transport import requests
from google.oauth2 import id_token
from requests import status_codes

from app.config import get_settings
from app.models import GoogleAuth

log = logging
log.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s",
    handlers=[logging.FileHandler("logs.txt"), logging.StreamHandler()],
)

def chunkify(lst: list, size: int) -> Tuple[Generator[list, None, None], int]:
    """Chunks lst into unique subsets of length chunk_size"""
    chunks = 0
    for i in range(len(lst)):
        if not (i % size):
            chunks += 1
    return (lst[i : i + size] for i in range(0, len(lst), size)), chunks

def coroutine(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        return asyncio.run(f(*args, **kwargs))

    return wrapper

def decode_jwt(encoded_jwt: str):
    try:
        idinfo = id_token.verify_oauth2_token(
            encoded_jwt, requests.Request(), get_settings().google_client_id
        )
        return GoogleAuth(**idinfo)

    # Error for malformed jwt's
    except MalformedError:
        raise HTTPException(status_code=498, detail="Could not parse JWT")

    # Error for f.x expiration
    except InvalidValue as e:
        # Here we would refresh the token
        raise HTTPException(status_code=498, detail=str(e))


import re
import os
import csv
from itertools import islice

import numpy as np

def parse_inputs(filename, label_dict):
    """Read input file and convert into inputs, labels for training

    Args:
      filename: text file - has content format as
          image_path, x1, x2, y1, y2, label1
          image_path, x1, x2, y1, y2, label2
      label_dict:  an encoding dictionary -
        mapping class names to indices

    Returns:
      inputs :  a list of all image paths to dataset
      labels :  a dictionary,
        key : image_path
        value: all objects in that image

    @TODO: when dataset is large, we should consider this method a generator
    """
    training_instances = dict()
    with open(filename, "r") as f:
        reader = csv.reader(f)
        for line in islice(reader, 1, None):
            if not line:
                continue  # Ignore empty line

            img_path = line[0]
            cls_name = line[-1]
            x1, y1, x2, y2 = [float(x) for x in line[1:-1]]
            an_object = [y1, x1, y2, x2, label_dict[cls_name]]

            if img_path in training_instances:
                training_instances[img_path].append(an_object)
            else:
                training_instances[img_path] = [an_object]
    inputs = training_instances.keys()
    labels = {k: np.stack(v).flatten() for k, v in training_instances.items()}

    return inputs, labels

def parse_label_map(label_map_path):
    """Parse label map file into a dictionary
    Args:
      label_map_path:

    Returns:
      a dictionary : key: obj_id value: obj-name
    """
    # match any group having language of {id:[number] .. name:'name'}
    parser = re.compile(r'id:[^\d]*(?P<id>[0-9]+)\s+name:[^\']*\'(?P<name>[\w_-]+)\'')

    with open(label_map_path, 'r') as f:
        lines = f.read().splitlines()
        lines = ''.join(lines)

        # a tuple (id, name)
        result = parser.findall(lines)
        label_map_dict = {int(item[0]): item[1] for item in result}

        return label_map_dict

def load_data(starting_path, file_extensions=['jpg', 'png', 'jpeg'], load_gt=False):
    data = {'': {}}
    for dir_path, subdir_list, file_names in os.walk(starting_path):
        d = data
        dir_path = dir_path[len(starting_path):]
        for sub_dir in dir_path.split(os.sep):
            based = d
            d = d[sub_dir]
        if subdir_list:
            for dn in subdir_list:
                d[dn] = {}
        else:
            label_path = os.path.join(starting_path + dir_path, 'labels.csv')
            labels = None
            if os.path.isfile(label_path):
                labels = parse_detection_file(label_path) if not load_gt else parse_ground_truth_file(label_path)

            based[sub_dir] = {'images': [os.path.join(dir_path, f)
                                         for f in file_names if f.split('.')[-1] in file_extensions],
                              'detections':  labels if labels else None}

    return data['']

def parse_ground_truth_file(gt_file):
    ground_truths = {}
    with open(gt_file, 'r') as f:
        lines = f.readlines()
        splitlines = [x.strip().split(' ') for x in lines][1:]

        for line in splitlines:
            img_id = line[0]
            obj_bbox = np.array(line[1:5], dtype=np.float)
            obj_idx = float(line[-1])
            if img_id not in ground_truths.keys():
                ground_truths[img_id] = {
                    'scores': [obj_idx],
                    'bboxes': [obj_bbox]
                }
            else:
                ground_truths[img_id]['scores'].append(obj_idx)
                ground_truths[img_id]['bboxes'].append(obj_bbox)
    return ground_truths

def parse_detection_file(detection_file):

    detections = {}
    with open(detection_file, 'r') as f:
        lines      = f.readlines()
        splitlines = [x.strip().split(' ') for x in lines]

        for line in splitlines:
            img_id    = line[0]
            obj_score = float(line[1])
            obj_bbox  = np.array(line[2:], dtype=np.float)

            if img_id not in detections.keys():
                detections[img_id] = {
                    'scores': [obj_score],
                    'bboxes': [obj_bbox]
                }
            else:
                detections[img_id]['scores'].append(obj_score)
                detections[img_id]['bboxes'].append(obj_bbox)

    return detections

def flatten_dict(d, current_level, max_level):
    def expand(key, value, curr_level, max):
        if isinstance(value, dict) and current_level < max_level:
            return [(key + '::' + k, v) for k, v in flatten_dict(value, curr_level+1, max).items()]
        else:
            return [(key, value)]
    items = [item for k, v in d.items() for item in expand(k, v, curr_level=current_level, max=max_level)]
    return dict(items)


import ctypes
import time

import pandas as pd  # 가져온 채팅내용 DF로 쓸거라서
import win32api
import win32con
import win32gui
from pywinauto import clipboard  # 채팅창내용 가져오기 위해

# 카톡창 이름
# kakao_opentalk_name = '♥ 디아블로2레저렉션 대장방 ♥'
kakao_opentalk_name = '이인우'
# 체크할 커맨드
# chat_command = '계약번호'
chat_command = 'ㅋ'

PBYTE256 = ctypes.c_ubyte * 256
_user32 = ctypes.WinDLL("user32")
GetKeyboardState = _user32.GetKeyboardState
SetKeyboardState = _user32.SetKeyboardState
PostMessage = win32api.PostMessage
SendMessage = win32gui.SendMessage
FindWindow = win32gui.FindWindow
IsWindow = win32gui.IsWindow
GetCurrentThreadId = win32api.GetCurrentThreadId
GetWindowThreadProcessId = _user32.GetWindowThreadProcessId
AttachThreadInput = _user32.AttachThreadInput

MapVirtualKeyA = _user32.MapVirtualKeyA
MapVirtualKeyW = _user32.MapVirtualKeyW

MakeLong = win32api.MAKELONG
w = win32con

def kakao_sendtext(chatroom_name, text):
    """ 채팅방 메시지 전송 """
    # # 핸들 _ 채팅방
    hwndMain = win32gui.FindWindow(None, chatroom_name)
    hwndEdit = win32gui.FindWindowEx(hwndMain, None, "RICHEDIT50W", None)

    win32api.SendMessage(hwndEdit, win32con.WM_SETTEXT, 0, text)
    SendReturn(hwndEdit)

def copy_chatroom(chatroom_name):
    """ 채팅방 내용 복사 """
    # # 핸들 _ 채팅방
    hwndMain = win32gui.FindWindow(None, chatroom_name)
    hwndListControl = win32gui.FindWindowEx(hwndMain, None, "EVA_VH_ListControl_Dblclk", None)

    # #조합키, 본문을 클립보드에 복사 ( ctl + c , v )
    time.sleep(0.5)
    PostKeyEx(hwndListControl, ord('A'), [w.VK_CONTROL], False)
    time.sleep(0.5)
    PostKeyEx(hwndListControl, ord('C'), [w.VK_CONTROL], False)
    time.sleep(1)
    ctext = clipboard.GetData()
    # print(ctext)
    return ctext

def PostKeyEx(hwnd, key, shift, specialkey):
    """ 조합키 """
    if IsWindow(hwnd):

        ThreadId = GetWindowThreadProcessId(hwnd, None)

        lparam = MakeLong(0, MapVirtualKeyA(key, 0))
        msg_down = w.WM_KEYDOWN
        msg_up = w.WM_KEYUP

        if specialkey:
            lparam = lparam | 0x1000000

        if len(shift) > 0:
            pKeyBuffers = PBYTE256()
            pKeyBuffers_old = PBYTE256()

            SendMessage(hwnd, w.WM_ACTIVATE, w.WA_ACTIVE, 0)
            AttachThreadInput(GetCurrentThreadId(), ThreadId, True)
            GetKeyboardState(ctypes.byref(pKeyBuffers_old))

            for modkey in shift:
                if modkey == w.VK_MENU:
                    lparam = lparam | 0x20000000
                    msg_down = w.WM_SYSKEYDOWN
                    msg_up = w.WM_SYSKEYUP
                pKeyBuffers[modkey] |= 128

            SetKeyboardState(ctypes.byref(pKeyBuffers))
            time.sleep(0.01)
            PostMessage(hwnd, msg_down, key, lparam)
            time.sleep(0.01)
            PostMessage(hwnd, msg_up, key, lparam | 0xC0000000)
            time.sleep(0.01)
            SetKeyboardState(ctypes.byref(pKeyBuffers_old))
            time.sleep(0.01)
            AttachThreadInput(GetCurrentThreadId(), ThreadId, False)

        else:
            SendMessage(hwnd, msg_down, key, lparam)
            SendMessage(hwnd, msg_up, key, lparam | 0xC0000000)

def SendReturn(hwnd):
    """ 엔터키 입력 """
    win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
    time.sleep(0.01)
    win32api.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0)

def open_chatroom(chatroom_name):
    """ 채팅방 오픈 """
    # 채팅방 목록 검색하는 Edit (채팅방이 열려있지 않아도 전송 가능하기 위하여)
    hwndkakao = win32gui.FindWindow(None, "카카오톡")
    hwndkakao_edit1 = win32gui.FindWindowEx(hwndkakao, None, "EVA_ChildWindow", None)
    hwndkakao_edit2_1 = win32gui.FindWindowEx(hwndkakao_edit1, None, "EVA_Window", None)
    hwndkakao_edit2_2 = win32gui.FindWindowEx(hwndkakao_edit1, hwndkakao_edit2_1, "EVA_Window",
                                              None)  # ㄴ시작핸들을 첫번째 자식 핸들(친구목록) 을 줌(hwndkakao_edit2_1)
    hwndkakao_edit3 = win32gui.FindWindowEx(hwndkakao_edit2_2, None, "Edit", None)

    # # Edit에 검색 _ 입력되어있는 텍스트가 있어도 덮어쓰기됨
    win32api.SendMessage(hwndkakao_edit3, win32con.WM_SETTEXT, 0, chatroom_name)
    time.sleep(0.5)  # 안정성 위해 필요
    SendReturn(hwndkakao_edit3)
    time.sleep(0.5)

def save_last_chat():
    """ 채팅방 오픈, 마지막 채팅정보 리턴 """
    print("최초 세팅 시작")
    open_chatroom(kakao_opentalk_name)  # 채팅방 열기
    copied_chat_text = copy_chatroom(kakao_opentalk_name)  # 채팅내용 가져오기
    copied_chat_array = copied_chat_text.split('\r\n')  # \r\n 으로 스플릿 (대화내용에 개행이 포함뙨 경우 \r 때문에 스플릿 안됨)
    copied_chat_df = pd.DataFrame(copied_chat_array)  # DF 으로 바꾸기
    copied_chat_df[0] = copied_chat_df[0].str.replace('\[([\S\s]+)\] \[(오전|오후)([0-9:\s]+)\] ',
                                                      '')  # 정규식으로 이름, 시간 지우고 채팅내용만 남기기

    # 마지막 채팅의 인덱스, 채팅내용 리턴
    return copied_chat_df.index[-2], copied_chat_df.iloc[-2, 0]

# 채팅방 커멘드 체크
def check_command_chat(cls, clst):
    print("채팅방 내용을 탐색합니다")
    open_chatroom(kakao_opentalk_name)  # 채팅방 열기
    copied_chat_text = copy_chatroom(kakao_opentalk_name)  # 채팅내용 가져오기
    copied_chat_array = copied_chat_text.split('\r\n')  # \r\n 으로 스플릿 (대화내용에 개행이 포함뙨 경우 \r 때문에 스플릿 안됨)
    copied_chat_df = pd.DataFrame(copied_chat_array)  # DF 으로 바꾸기
    copied_chat_df[0] = copied_chat_df[0].str.replace('\[([\S\s]+)\] \[(오전|오후)([0-9:\s]+)\] ',
                                                      '')  # 정규식으로 이름, 시간 지우고 채팅내용만 남기기

    # 초기 세팅 시 마지막 채팅정보와 현재 시점의 마지막 채팅정보가 같을 때
    if copied_chat_df.iloc[-2, 0] == clst:
        print("새로운 채팅 없음")
        return copied_chat_df.index[-2], copied_chat_df.iloc[-2, 0]
    else:
        print("새로운 채팅 있음")
        copied_new_chat_df = copied_chat_df.iloc[cls + 1:, 0]  # 초기 세팅 시 채팅을 제외한 신규 채팅내용만 남김
        is_command_found = copied_new_chat_df[copied_new_chat_df.str.contains(chat_command)]  # 커맨드가 있는지 확인
        if 1 <= int(is_command_found.count()):
            print("-------커멘드 확인--------")
            # message = str(copied_new_chat_df).split(chat_command)[1].replace('[', '').replace(']', '')[:7]
            message = copied_chat_df.iloc[-2, 0]
            kakao_sendtext(kakao_opentalk_name, message)

            # 명령어 여러개 쓸경우 리턴값으로 각각 빼서 쓰면 될듯. 일단 테스트용으로 위에 하드코딩 해둠
            return copied_chat_df.index[-2], copied_chat_df.iloc[-2, 0]

        else:
            print("-------커멘드 미확인--------")
            return copied_chat_df.index[-2], copied_chat_df.iloc[-2, 0]

# # 네이버 실검 상위 20개, 리턴
def get_message_to_send():
    s = "계약번호가 있네요"
    return s

def main():
    last_chat_index, last_chat_text = save_last_chat()  # 초기 채팅방 열기, 마지막 채팅 정보 저장

    tryCount = 0
    while True:
        tryCount = tryCount + 1
        print("시도횟수: " + str(tryCount))
        last_chat_index, last_chat_text = check_command_chat(last_chat_index, last_chat_text)  # 커멘드 체크
        time.sleep(3)

if __name__ == '__main__':
    main()


from collections import defaultdict
from typing import Dict
from typing import List
from typing import Optional
from typing import Set

from adventofcode.tools.input import read_puzzle_input

def parse_puzzle_input(puzzle_input: List[str]) -> Dict[str, Set[str]]:
    network = defaultdict(set)
    for line in puzzle_input:
        origin, destination = line.split("-")
        network[origin].add(destination)
        network[destination].add(origin)
    return network

def count_paths(
    network: Dict[str, Set[str]],
    extra: bool = False,
    *,
    cave: str = "start",
    visited: Optional[Set[str]] = None,
) -> int:
    if cave == "end":
        return 1
    if visited is None:
        visited = {cave}
    paths = 0
    for adj in network[cave]:
        if adj not in visited:
            new = {adj} if adj.islower() else set()
            paths += count_paths(network, extra, cave=adj, visited=visited | new)
        elif extra and adj != "start":
            paths += count_paths(network, False, cave=adj, visited=visited)
    return paths

def solve_part1(puzzle_input: List[str]) -> int:
    network = parse_puzzle_input(puzzle_input)
    return count_paths(network)

def solve_part2(puzzle_input: List[str]) -> int:
    network = parse_puzzle_input(puzzle_input)
    return count_paths(network, True)

if __name__ == "__main__":
    puzzle_input = read_puzzle_input(2021, 12)
    print(solve_part1(puzzle_input))
    print(solve_part2(puzzle_input))


"""Customized ProcessPoolExecutor."""
import concurrent.futures
import concurrent.futures.process
import multiprocessing

def _process_worker(initializer, call_queue, result_queue):
    """Runs initializer before _process_worker to set signal handlers."""
    initializer()
    concurrent.futures.process._process_worker(call_queue, result_queue)  # pylint: disable=protected-access

class ProcessPoolExecutorWithInit(concurrent.futures.ProcessPoolExecutor):
    """Process pool executor with initializer.

    Allows executing _initializer on each worker before processing tasks.
    """

    def __init__(self, *args, initializer=None, **kwargs):
        super().__init__(*args, **kwargs)
        self._initializer = initializer

    def _adjust_process_count(self):
        for _ in range(len(self._processes), self._max_workers):
            p = multiprocessing.Process(
                target=_process_worker,
                args=(self._initializer,
                      self._call_queue,
                      self._result_queue))
            p.start()
            self._processes[p.pid] = p


import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QDialog
from PyQt5.QtWidgets import QPushButton, QVBoxLayout, QHBoxLayout, QGridLayout, QGroupBox, QScrollArea, QPlainTextEdit
from PyQt5.QtWidgets import QDesktopWidget, QMenu, QAction
from PyQt5.QtGui import QIcon, QPixmap

class QLoadMVADialog(QDialog):
    def __init__(self, parent):
        super().__init__()
        self.left = 100
        self.top = 100
        self.height = 300
        self.width = 300
        self.title = "Load MVA"
        self.initUI()
        self.parent = parent

    def initUI(self):
        self.setGeometry(self.left, self.top, self.width, self.height)

        VBoxLayout = QVBoxLayout()

        HBoxLayout = QHBoxLayout()
        self.mva_text = QPlainTextEdit()
        # self.mva_text.setStyleSheet("font: 24px;")
        HBoxLayout.addWidget(self.mva_text)

        save_btn = QPushButton("Save")
        cancel_btn = QPushButton("Cancel")
        save_btn.clicked.connect(self.saveSettings)
        cancel_btn.clicked.connect(self.cancelSettings)
        confirm_HBoxLayout = QHBoxLayout()
        confirm_HBoxLayout.addStretch()
        confirm_HBoxLayout.addWidget(save_btn)
        confirm_HBoxLayout.addWidget(cancel_btn)

        VBoxLayout.addLayout(HBoxLayout)
        VBoxLayout.addLayout(confirm_HBoxLayout)
        self.setLayout(VBoxLayout)

    def saveSettings(self):
        self.parent.setLoadedMVAText(self.mva_text.toPlainText())
        self.accept()
        return

    def cancelSettings(self):
        self.reject()
        return

    def exec_(self):
        self.mva_text.setPlainText(self.parent.loaded_mva_text)
        super().exec_()


import argparse
import cv2

parser = argparse.ArgumentParser()
parser.add_argument("-i", "--image", default="phantom.jpg",
                    help="path to input image")
args = vars(parser.parse_args())

image = cv2.imread(args["image"])
cv2.imshow("RGB", image)

for (name, channel) in zip(("B", "G", "R"), cv2.split(image)):
	cv2.imshow(name, channel)

cv2.waitKey(0)
cv2.destroyAllWindows()

hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
cv2.imshow("HSV", hsv)

for (name, channel) in zip(("H", "S", "V"), cv2.split(hsv)):
	cv2.imshow(name, channel)

cv2.waitKey(0)
cv2.destroyAllWindows()

lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
cv2.imshow("L*a*b*", lab)

for (name, channel) in zip(("L*", "a*", "b*"), cv2.split(lab)):
	cv2.imshow(name, channel)

cv2.waitKey(0)
cv2.destroyAllWindows()

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Original", image)
cv2.imshow("Grayscale", gray)
cv2.waitKey(0)


import requests
import yaml
import json
import time

TARGET_URL = "https://sudomaze.dev"
BASE_URL = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed"
PATHS = ['/']#,'/about','/notes','/projects','/cv','/site']
CATEGORIES = ["accessibility", "best-practices", "performance", "pwa", "seo"]

# get the dynamic pages
# r_urls = json.loads(requests.get("https://sudomaze.dev/search.json").text)
# for i in range(len(r_urls)):
#     PATHS.append(r_urls[i]['url'])
sstart = time.time()
for path in PATHS:
    start = time.time()
    print(f'PATH: {path}')
    api_key = yaml.load(open('secret.yml'), Loader=yaml.FullLoader)['api']
    total_url_desktop = f'{BASE_URL}?url={TARGET_URL}{path}&key={api_key}&category={"&category=".join(CATEGORIES)}&strategy=desktop'
    total_url_mobile = f'{BASE_URL}?url={TARGET_URL}{path}&key={api_key}&category={"&category=".join(CATEGORIES)}&strategy=mobile'
    data_desktop = json.loads(requests.get(total_url_desktop).text)
    data_mobile = json.loads(requests.get(total_url_mobile).text)
    for category in data_desktop['lighthouseResult']['categories']:
        print(f"(DESKTOP) {category}: {data_desktop['lighthouseResult']['categories'][category]['score']}")
        print(f"(MOBILE) {category}: {data_mobile['lighthouseResult']['categories'][category]['score']}")
    end = time.time() - start
    print(f'TIME: {end}')
end = time.time() - sstart
print(end)


# -*- coding: utf-8 -*-
"""
Created on Sat Jul 11 20:03:36 2020

@author: Meihaonan
"""
import os
import paddle
import numpy as np
import paddle.fluid as fluid
from multiprocessing import cpu_count
import matplotlib.pyplot as plt

def to_image(L):            #将1*2400连续胎心率数据点转化成120*2400胎心率曲线图
    image=np.zeros([120,2400],dtype=np.int)
    #np.zero(120,2400)好像有点问题
    for i in range(2400):
        if(L[i]<80):
            L[i]=80
        if(L[i]>=200):
            L[i]=199
        image[L[i]-80][i]=1
    return image

def data_reader(data,label,buffered_size=512):
  def reader():
      x=data.shape[0]
      for i in range(0,x):
          image=to_image(data[i,:])
          yield image,[label[i]-1]  #算交叉熵label要从0开始
  return reader

train_data=np.loadtxt("heart_data/train_data.txt",
                      delimiter=" ",dtype=int)
train_data_label=np.loadtxt("heart_data/train_label.txt",
                            delimiter=" ",dtype=int)

test_data=np.loadtxt("heart_data/test_data.txt",
                     delimiter=" ",dtype=int)
test_data_label=np.loadtxt("heart_data/test_label.txt",
                           delimiter=" ",dtype=int)

#构造训练、测试数据提供器
BATCH_SIZE = 16
train_r =data_reader(train_data,train_data_label)
train_reader =paddle.batch(paddle.reader.shuffle(reader=train_r,buf_size=128),
                          batch_size=BATCH_SIZE)

test_r=data_reader(test_data,test_data_label)
test_reader = paddle.batch(test_r,batch_size=BATCH_SIZE)

def mknet(input,type_size): #输入图片，分出的类别
    def conv_block(ipt, num_filter, groups, dropouts):
        return fluid.nets.img_conv_group(
            input=ipt,
            pool_size=2,
            pool_stride=2,
            conv_num_filter=[num_filter] * groups,
            conv_filter_size=3,
            conv_act='relu',
            conv_with_batchnorm=True,
            conv_batchnorm_drop_rate=dropouts,
            pool_type='max')

    conv1 = conv_block(input, 64, 2, [0, 0])
    conv2 = conv_block(conv1, 128, 2, [0, 0])
    conv3 = conv_block(conv2, 256, 3, [0, 0, 0])
    conv4 = conv_block(conv3, 512, 3, [0, 0, 0])
    conv5 = conv_block(conv4, 512, 3, [0, 0, 0])

    drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5)
    fc1 = fluid.layers.fc(input=drop, size=512, act=None)
    bn = fluid.layers.batch_norm(input=fc1, act='relu')
    drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.5)
    fc2 = fluid.layers.fc(input=drop2, size=512, act=None)
    predict = fluid.layers.fc(input=fc2, size=type_size, act='softmax')
    return predict

# 定义输入输出层
# 定义两个张量
image =fluid.layers.data(name='image', shape=[1, 120, 2400], dtype='float32')
label =fluid.layers.data(name='label', shape=[1], dtype='int64')

# 获取分类器
predict=mknet(image,3) #分成3类

# 定义损失函数和准确率函数
cost =fluid.layers.cross_entropy(input=predict, label=label)
avg_cost =fluid.layers.mean(cost)
accuracy =fluid.layers.accuracy(input=predict, label=label)

# 克隆main_program得到test_program，使用参数for_test来区分该程序是用来训练还是用来测试
# 该fluid.default_main_program().clone()要在optimization之前使用.
test_program =fluid.default_main_program().clone(for_test=True)

# 使用Adam优化器，定学习率为0.002。
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.002)
opts = optimizer.minimize(avg_cost)

#定义使用CPU还是GPU，使用CPU时use_cuda = False,使用GPU时use_cuda = True
use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
#创建一个Executor实例exe
exe =fluid.Executor(place)
#正式进行网络训练前，需先执行参数初始化
exe.run(fluid.default_startup_program())

feeder = fluid.DataFeeder(place=place, feed_list=[image, label])

EPOCH_NUM = 60
#训练过程数据记录
all_train_iter=0
all_train_iters=[]
all_train_costs=[]
all_train_accs=[]

#测试过程数据记录
all_test_iter=0
all_test_iters=[]
all_test_costs=[]
all_test_accs=[]
model_save_dir ="work"

for pass_id in range(EPOCH_NUM):
    # 开始训练
    for batch_id, data in enumerate(train_reader()):      #遍历训练集，并为数据加上索引batch_id
        train_cost,train_acc =exe.run(program=fluid.default_main_program(),#运行主程序
                             feed=feeder.feed(data),                 #喂入一个batch的数据
                            fetch_list=[avg_cost, accuracy])         #fetch均方误差和准确率
        all_train_iter=all_train_iter+BATCH_SIZE
        all_train_iters.append(all_train_iter)
        all_train_costs.append(train_cost[0])
        all_train_accs.append(train_acc[0])
        #每10次batch打印一次训练、进行一次测试
        if batch_id % 10== 0:
            print('Pass:%d, Batch:%d,Cost:%0.5f, Accuracy:%0.5f' %
            (pass_id, batch_id, train_cost[0],train_acc[0]))
    # 开始测试
    test_costs = []                                                        #测试的损失值
    test_accs = []                                                         #测试的准确率
    for batch_id, data in enumerate(test_reader()):
        test_cost, test_acc =exe.run(program=test_program,              #执行训练程序
                                     feed=feeder.feed(data),            #喂入数据
                                     fetch_list=[avg_cost, accuracy])         #fetch 误差、准确率
        test_costs.append(test_cost[0])                                #记录每个batch的误差
        test_accs.append(test_acc[0])                             #记录每个batch的准确率
        all_test_iter=all_test_iter+BATCH_SIZE
        all_test_iters.append(all_test_iter)
        all_test_costs.append(test_cost[0])
        all_test_accs.append(test_acc[0])
# 求测试结果的平均值
    test_cost = (sum(test_costs) /len(test_costs))        #计算误差平均值（误差和/误差的个数）
    test_acc = (sum(test_accs) /len(test_accs))  #计算准确率平均值（ 准确率的和/准确率的个数）
    print('Test:%d, Cost:%0.5f, ACC:%0.5f' %(pass_id, test_cost, test_acc))

# 每轮训练完成后，对模型进行一次保存，使用飞桨提供的fluid.io.save_inference_model()进行模型保存：
# 保存模型
# 如果保存路径不存在就创建
if not os.path.exists(model_save_dir):
    os.makedirs(model_save_dir)
print('savemodels to %s' % (model_save_dir))
fluid.io.save_inference_model(model_save_dir,  # 保存预测Program的路径
                              ['image'],      #预测需要feed的数据
                              [predict],       #保存预测结果
                              exe)             #executor 保存预测模型

def draw_cost_process(title,iters,costs,label_cost):
    plt.title(title, fontsize=24)
    plt.xlabel("iter", fontsize=20)
    plt.ylabel("cost", fontsize=20)
    plt.plot(iters,costs,color='red',label=label_cost)
    plt.legend()
    plt.grid()
    plt.show()

def draw_acc_process(title,iters,acc,label_acc):
    plt.title(title, fontsize=24)
    plt.xlabel("iter", fontsize=20)
    plt.ylabel("acc", fontsize=20)
    plt.plot(iters,acc,color='green',label=label_acc)
    plt.legend()
    plt.grid()
    plt.show()

#调用绘制曲线
draw_acc_process("training",all_train_iters, all_train_accs, "trainning acc")
draw_acc_process("testing",all_test_iters, all_test_accs, "test acc")
draw_cost_process("training",all_train_iters, all_train_costs, "trainning acc")
draw_cost_process("testing",all_test_iters, all_test_costs, "test acc")