import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import Qt, QBasicTimer

# Уравнение в каноническом виде:
#   (y + (d-b))^2 = 2(x-c)/2a
#   p = 1/(2a)
#   f: [1/(4a) + c, b - d] - фокус
#   d: x = -1/(4a) + c - директриса

class DrawingWidget(QWidget):
    def __init__(self, scale=10, a=1.0, b=1.0, c=0.0, d=1.0):
        super().__init__()

        self.a, self.b, self.c, self.d = a, b, c, d
        self.scale_x, self.scale_y = scale, 0
        self.width, self.height = 0, 0
        self.dx, self.dy = 0, 0
        self.mouse_click_x = -1
        self.mouse_click_y = -1
        self.qp = QPainter()

        self.initUI()

    def initUI(self):
        self.setGeometry(150, 150, 900, 900)
        # self.timer = QBasicTimer()
        # self.timer.start(15, self)
        self.setWindowTitle('Drawing')
        self.show()

    def paintEvent(self, event):
        self.qp.setPen(Qt.black)
        self.qp.begin(self)

        self.draw()
        self.qp.end()

    def resizeEvent(self, event):
        new_width = event.size().width()
        new_height = event.size().height()
        self.width = new_width
        self.height = new_height
        self.scale_y = self.scale_x  # new_width * 6 / new_height

    def draw(self):
        # self.draw_parabola()
        # self.draw_parabola_dists()
        self.draw_parabola_deltas()
        self.draw_axes()

    def draw_axes(self):
        a_, b_, c_, d_ = self.a, self.b, self.c, self.d
        if a_ < 0:
            self.qp.scale(-1.0, 1.0)
            a_ = -a_
            c_ = -c_

        dx = self.get_screen_x(0) - self.get_screen_x(c_)
        dy = self.get_screen_y(d_ - b_) - self.get_screen_y(0)
        self.qp.setPen(Qt.black)
        self.qp.translate(dx, dy)

        self.qp.drawLine(-self.width / 2 - dx, 0, self.width / 2 - dx, 0)
        self.qp.drawLine(0, -self.height / 2 - dy, 0, self.height / 2 - dy)

    def draw_parabola_dists(self):
        self.qp.setPen(Qt.darkBlue)
        self.qp.resetTransform()
        self.qp.translate(self.width / 2, self.height / 2)
        self.qp.scale(1.0, -1.0)

        a_, c_ = self.a, self.c
        if a_ == 0:
            self.qp.drawLine(c_, self.height, c_, -self.height)
            return
        elif a_ < 0:
            self.qp.scale(-1.0, 1.0)
            a_ = -a_

        bound = self.width
        f = self.get_screen_x(1 / (4*a_)) - self.get_screen_x(0)
        x, y = 0, 0
        self.qp.drawPoint(x, y)

        while x <= bound:
            d1 = (f - x) ** 2 + (-(y + 1)) ** 2 - (-f - x) ** 2
            min_d = abs(d1)
            n_x, n_y = x, y + 1

            d2 = (f - (x + 1)) ** 2 + (-(y + 1)) ** 2 - (-f - (x + 1)) ** 2
            if abs(d2) < min_d:
                n_x, n_y = x + 1, y + 1
                min_d = abs(d2)

            d3 = (f - (x + 1)) ** 2 + (-y) ** 2 - (-f - (x + 1)) ** 2
            if abs(d3) < min_d:
                n_x, n_y = x + 1, y

            self.qp.drawPoint(n_x, n_y)
            self.qp.drawPoint(n_x, -n_y)
            x, y = n_x, n_y

    def draw_parabola_deltas(self):
        self.qp.setPen(Qt.red)
        self.qp.resetTransform()
        self.qp.translate(self.width / 2, self.height / 2)
        self.qp.scale(1.0, -1.0)

        a_, c_ = self.a, self.c
        if a_ == 0:
            self.qp.drawLine(c_, self.height, c_, -self.height)
            return
        elif a_ < 0:
            self.qp.scale(-1.0, 1.0)
            a_ = -a_

        bound = self.width
        p = self.get_screen_x(1/(2*a_)) - self.get_screen_x(0)
        x, y = 0, 0
        self.qp.drawPoint(x, y)

        p2 = 2 * p
        while x <= bound:
            delta = (y + 1)*(y + 1) - p2 * (x + 1)
            if delta < 0:
                other = delta + p2
                if abs(delta) < abs(other):
                    x, y = x + 1, y + 1
                else:
                    x, y = x, y + 1
            else:
                other = delta - 2 * y - 1
                if abs(delta) < abs(other):
                    x, y = x + 1, y + 1
                else:
                    x, y = x + 1, y

            self.qp.drawPoint(x, y)
            self.qp.drawPoint(x, -y)

    def draw_parabola(self):
        self.qp.setPen(Qt.black)
        self.qp.resetTransform()
        self.qp.translate(self.width / 2, self.height / 2)
        self.qp.scale(1.0, -1.0)

        a_, b_, c_, d_ = self.a, self.b, self.c, self.d
        if a_ == 0:
            self.qp.drawLine(c_, self.height, c_, -self.height)
            return
        elif a_ < 0:
            self.qp.scale(-1.0, 1.0)
            a_ = -a_
            c_ = -c_

        bound = self.width
        p = self.get_screen_x(1/(2*a_)) - self.get_screen_x(0)

        p2 = 2*p
        p4 = 2*p2
        x, y = 0, 0
        d = 1 - p

        while (y < p) and (x <= bound):
            self.qp.drawPoint(x, y)
            self.qp.drawPoint(x, -y)
            if d >= 0:
                x += 1
                d -= p2
            y += 1
            d += (2*y + 1)

        if d == 1:
            d = 1 - p4
        else:
            d = 1 - p2

        # self.qp.drawLine(x, 0, x, y)
        while x <= bound:
            self.qp.drawPoint(x, y)
            self.qp.drawPoint(x, -y)
            if d <= 0:
                y += 1
                d += 4 * y
            x += 1
            d -= p4

    def get_screen_x(self, x):
        return ((self.scale_x / 2 + x) / self.scale_x) * self.width

    def get_screen_y(self, y):
        return ((self.scale_y / 2 + y) / self.scale_y) * self.height

    def timerEvent(self, event):
        self.a += 0.15
        if self.a > 10:
            self.a = -10

        self.repaint()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = DrawingWidget(a=0, b=1, c=.25, d=1, scale=1)

    sys.exit(app.exec_())


import math

def dense_prims(adjList, n):
    MST = []
    visited = [False] * n
    A = [math.inf] * n
    # List used to store village indices that share the cheapest edge to each index
    MST_edges = [-1] * n

    # Use village 0 as the source
    A[0] = 0

    while len(MST) < n:
        minIndex = A.index(min(A))
        visited[minIndex] = True
        MST.append(minIndex)
        A[minIndex] = math.inf

        for neighbour in adjList[minIndex]:
            if not visited[neighbour[1]] and A[neighbour[1]] > neighbour[0]:
                A[neighbour[1]] = neighbour[0]
                # Update cheapest edge with minIndex. +1 because villages start from 1
                MST_edges[neighbour[1]] = minIndex+1

    # Print out edges
    # Ignore first index as it is the source
    # Did not check if there are edges to source so MST_edges[0] == -1
    # Does not matter as any cheapest edge with source will still be reflected by the respective indices
    for i in range(1, len(MST_edges)):
        print(i+1, MST_edges[i])

def main():
    n = int(input())

    # Create adjacency list from the adjacency matrix input
    adjList = [[]*n for _ in range(n)]
    for i in range(n):
        line = list(map(int, input().split()))
        for j in range(len(line)):
            # Don't include distance from village to itself
            if i != j:
                adjList[i].append((line[j], j))

    # Densely connected graph, do dense prims
    dense_prims(adjList, n)

if __name__ == '__main__':
    main()


from typing import Dict, List, Tuple
from javalang.tree import BasicType
from data.methods import ModifiedMethod
from data.types import Ratio

class MatchedFiles:
    """
    This class represents matched files and test files
    """

    def __init__(self, file_name, test_file_name, methods, test_methods):
        self.file_name = file_name
        self.test_file_name = test_file_name
        self.methods = methods
        self.test_methods = test_methods

    @property
    def matched_methods(self) -> Dict:
        """
        Returns dict of matched methods.
        """
        matched_methods = GetMethodsWithParsedData(self.methods, self.test_methods)
        matched_production_methods = set(method[0] for method in matched_methods)
        matched_test_methods = set(method[1] for method in matched_methods)

        result = {
            "matched_methods": matched_methods,
            "matched_production_methods": matched_production_methods,
            "matched_test_methods": matched_test_methods
        }
        return result

def GetMethodsWithParsedData(methods, test_methods) -> List[Tuple[ModifiedMethod, ModifiedMethod, Ratio]]:
    test_methods = [x for x in test_methods if "@Test" in x.source_code]
    matched_pairs = []

    for test_method in test_methods:
        # (test_method.source_code)
        test_method_parsed = test_method.parsed_method
        # print(test_method_parsed)
        for method in methods:
            method_parsed = method.parsed_method
            ratio = GetMatchedMethods(test_method_parsed, method_parsed)

            if ratio == Ratio.HIGH or ratio == Ratio.MEDIUM or ratio == Ratio.LOW:
                matched_pairs.append((method, test_method, ratio))
                # TODO: Best/ Good Practice => eine Testmethode testet eine Methode
                # wenn eine Testmethode mehrmals vorkommt, entscheiden, welche Übereinstimmung die richtige ist

    # print("len methods:", len(methods))
    matched_methods = set(x[0] for x in matched_pairs)
    # ("len matched methods:", len(matched_methods))
    # for x in matched_methods:
    # print(x.long_name)

    return matched_pairs

def GetMatchedMethods(test_method_parsed, method_parsed):
    test_methods = test_method_parsed["methods"]
    variables = test_method_parsed["variables"]
    if test_methods is None or method_parsed is None:
        return False, Ratio.NO_MATCH

    for x in test_methods:
        if x["name"] == method_parsed["name"]:
            if len(x["arguments"]) == len(method_parsed["arguments"]):
                # Case zero param:
                if len(method_parsed["arguments"]) == 0:
                    return Ratio.HIGH
                # Case: one parameter and multiple params true
                elif len(method_parsed["arguments"]) == 1 and method_parsed["arguments"][0].varargs:
                    return Ratio.NO_MATCH
                    #return Ratio.LOW
                # Case: one parameter and multiple param false
                elif len(method_parsed["arguments"]) == 1 and not method_parsed["arguments"][0].varargs:
                    # Case: One parameter and qualifier is an Object
                    if method_parsed["arguments"][0].type.name == "Object":
                        return Ratio.HIGH
                    # Case: entered parameter equals a string and method requires string
                    elif method_parsed["arguments"][0].type.name == "String":
                        if x["arguments"][0][0].startswith('"') and x["arguments"][0][0].endswith('"'):
                            return Ratio.HIGH
                    # Case: entered parameter equals a boolean and method requires boolean
                    elif method_parsed["arguments"][0].type.name == "boolean":
                        if x["arguments"][0][0] == "true" or x["arguments"][0][0] == "false":
                            return Ratio.HIGH
                    # Case: cover remaining cases
                    else:
                        ratio = CompareArgumentByType(method_parsed, variables, x)
                        return ratio
                # Multiple Params
                else:
                    ratio = CheckType(method_parsed["arguments"], x["arguments"])
                    if ratio == Ratio.HIGH:
                        return Ratio.HIGH
                    else:
                        # TODO: andere Cases betrachten
                        return Ratio.LOW
            elif len(x["arguments"]) != len(method_parsed["arguments"]):
                for arg in method_parsed["arguments"]:
                    if arg.varargs:
                        return Ratio.LOW

def CheckType(args, method_tested_args):
    match = []

    for method_arg, method_tested_arg in zip(args, method_tested_args):
        if method_arg.type.name == "Object":
            match.append(True)
        elif method_arg.type.name == "String":
            if method_tested_arg[0].startswith('"') and method_tested_arg[0].endswith('"'):
                match.append(True)
            else:
                match.append(False)
        elif method_arg.type.name == "boolean":
            if method_tested_arg[0] == "true" or method_tested_arg[0] == "false":
                match.append(True)
            else:
                match.append(False)
        else:
            match.append(False)

    if all(x == True for x in match):
        return Ratio.HIGH
    else:
        return Ratio.LOW

def CompareArgumentByType(method_parsed, variables, method_tested):
    args = []
    method_arg = method_parsed["arguments"][0]
    args.append(method_arg.type.name)
    # TODO:  if method_arg.type.arguments is not None: AttributeError: 'BasicType' object has no attribute 'arguments'
    if isinstance(method_arg.type, BasicType):
        print("method arg:", method_arg.type)
    elif method_arg.type.arguments is not None:
        for argument in method_arg.type.arguments:
            if argument.type is not None:
                args.append(argument.type.name)

    for variable in variables:
        if method_tested["arguments"][0][0] == variable["name"]:
            for arg in args:
                if len(variable["qualifier"]) > 0:
                    if arg in variable["qualifier"][0]:
                        return Ratio.HIGH
                    return Ratio.MEDIUM
                else:
                    return Ratio.LOW

    return Ratio.LOW

class NotMatchedFiles:
    """
    This class represent not matched files
    """

    def __init__(self, files, test_files, file_methods, test_file_methods):
        self.files = files
        self.test_files = test_files
        self.methods = file_methods
        self.test_methods = test_file_methods

class MatchedAnalyzedFiles:
    def __init__(self, production_file, test_file):
        self.production_file = production_file
        self.production_file_name = production_file.file_name
        self.production_methods = production_file.modified_methods
        self.test_file = test_file
        self.test_file_name = test_file.file_name
        self.test_methods = test_file.modified_methods

    @property
    def matched_methods(self) -> List[Tuple[ModifiedMethod, ModifiedMethod, Ratio]]:
        matched_methods = GetMethodsWithParsedData(self.production_methods, self.test_methods)
        return matched_methods

    @property
    def not_matched_methods(self) -> List[ModifiedMethod]:
        matched_methods = self.matched_methods
        methods = [x[0] for x in matched_methods]
        return [x for x in self.production_methods if x not in methods]

class NotMatchedAnalyzedFiles:
    def __init__(self, production_files, test_files):
        self.production_files = production_files
        self.test_files = test_files


with open('input.txt', 'r') as f:
    heightmap = [[int(p) for p in row if p != '\n'] for row in f.readlines()]

def get_neighbors(heightmap, row, col):
    maxrow = len(heightmap)
    maxcol = len(heightmap[0])
    neighborcoords = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    valid_neighbors = []
    for n in neighborcoords:
        rowdiff, coldiff = n
        if (0 <= row + rowdiff < maxrow) and (0 <= col + coldiff < maxcol):
            valid_neighbors.append((row + rowdiff, col + coldiff))

    return valid_neighbors

def find_low_points(heightmap):
    low_points = []
    for row, l in enumerate(heightmap):
        for col, point in enumerate(l):
            pneighbors = get_neighbors(heightmap, row, col)
            if all(point < heightmap[r][c] for r, c in pneighbors):
                low_points.append((row, col))
    return low_points

def create_basin(heightmap, lowpoint):
    frontier = [lowpoint]
    explored = []
    while frontier:
        curpoint = frontier.pop(0)
        explored.append(curpoint)
        currow, curcol = curpoint
        curneighbors = get_neighbors(heightmap, currow, curcol)
        for n in curneighbors:
            if n not in frontier and n not in explored:
                nrow, ncol = n
                if heightmap[nrow][ncol] < 9:
                    frontier.append(n)
    return explored

""" Current Idea:
    given that we can get low points with find_low_points,
    recursively run get_neighbors() on that point and it's neighbor until
    no non-9 can be found (on the origin point then it's immediate neighbors)
    and return a list of that"""
def find_basins(heightmap):
    low_points = find_low_points(heightmap)
    basins = []
    for lp in low_points:
        basins.append(create_basin(heightmap, lp))

    return basins

def part1():
    low_points = find_low_points(heightmap)
    return sum(heightmap[r][c] + 1 for r,c in low_points)
def part2():
    basins = sorted(find_basins(heightmap), key=lambda b: len(b), reverse=True)
    product = 1
    for i in range(3):
        product *= len(basins.pop(0))
    return product

print(f'PART 1: {part1()}')
print(f'PART 2: {part2()}')


from nonebot import on_command, on_regex, on_keyword, on_message
from nonebot.params import CommandArg, EventMessage
from nonebot.adapters import Event
from nonebot.adapters.onebot.v11 import Message, MessageSegment

from src.libraries.image import *
from src.libraries.secrets import *

from PIL import Image
from io import BytesIO
import glob, random, base64, requests, os, time

mrfz_dir = 'src/static/mrfz/'

lihui = on_command('zlh', aliases={'舟立绘'}, priority=40, block=True)
@lihui.handle()
async def _(message: Message = CommandArg()):
    argv = str(message).strip().split(" ")
    if len(argv) > 0 and len(argv) < 3:
        fpath_list = glob.glob(mrfz_dir + f"lihui/立绘_{argv[0]}_*.png")
        if len(fpath_list) == 0:
            fpath_list = glob.glob(mrfz_dir + f"lihui/立绘_*{argv[0]}*_*.png")
            if len(fpath_list) == 0:
                await lihui.finish("没有找到这样的干员，目前只支持干员精确中文名查询")
        try:
            if argv[1] in ["1", "2"]:
                fpath = random.choice(
                    [f for f in fpath_list if f"_{argv[1]}.png" in f])
            elif argv[1] in ["皮肤", "皮", "skin"]:
                fpath = random.choice(
                    [f for f in fpath_list if "skin" in f])
        except:
            fpath = random.choice(fpath_list)
        with open(fpath, 'rb') as fp:
            encoded = base64.b64encode(fp.read())
        url = "base64://" + encoded.decode('utf-8')
        await lihui.finish(MessageSegment.image(url))

cailiao = on_command('舟材料', aliases={'zcl'}, priority=40, block=True)
@cailiao.handle()
async def _(message: Message = CommandArg()):
    if str(message).strip() != "":
        return

    try:
        if os.path.getmtime(mrfz_dir + '材料.png') < time.time() - 86400:
            os.remove(mrfz_dir + '材料.png')
    except:
        pass

    if os.path.exists(mrfz_dir + '材料.png'):
        await cailiao.finish(MessageSegment.image(f"base64://{str(image_to_base64(Image.open(mrfz_dir + '材料.png')), encoding='utf-8')}"))

    else:
        html_to_img_url = f"http://{TENCENT_CLOUD_IP}:{HTML_TO_IMAGE_PORT}/screenshot"
        key = HTML_TO_IMAGE_KEY
        params = {
            'url': 'http://yituliu.site',
            'key': key,
            'w': '1000',
            'h': '1321'
            }
        res = requests.get(html_to_img_url, params=params)
        if res.status_code != 200:
            await cailiao.finish("渲染失败")
        else:
            img = Image.open(BytesIO(res.content))
            img = img.crop((0,134,1000,885))
            img.save(mrfz_dir + '材料.png')
            await cailiao.finish(MessageSegment.image(f"base64://{str(image_to_base64(img), encoding='utf-8')}"))

shuaxincailiao = on_command('刷新舟材料', priority=40, block=True, rule=range_checker)
@shuaxincailiao.handle()
async def _():
    html_to_img_url = f"http://{TENCENT_CLOUD_IP}:{HTML_TO_IMAGE_PORT}/screenshot"
    key = HTML_TO_IMAGE_KEY
    params = {
        'url': 'http://yituliu.site',
        'key': key,
        'w': '1000',
        'h': '1321'
        }
    res = requests.get(html_to_img_url, params=params)
    if res.status_code != 200:
        await cailiao.finish("渲染失败")
    else:
        img = Image.open(BytesIO(res.content))
        img = img.crop((0,134,1000,885))
        img.save(mrfz_dir + '材料.png')
        await cailiao.finish(MessageSegment.image(f"base64://{str(image_to_base64(img), encoding='utf-8')}"))


"""
Module for loading the data
"""
import os
from typing import Sequence, Optional, Tuple, Mapping

import pandas as pd
from PIL import Image
from torch.utils.data import Dataset
import torch
from torchvision.transforms import ToTensor

from poke_ml.datatypes import (
    ImageObject,
    ImageTransform,
    ComposedTorchTransforms,
    Tensor,
)

def load_index_table() -> pd.DataFrame:
    file = "../data/tables/pokemon_by_shape.csv"
    return pd.read_csv(file, sep=",", header=0)

def load_image(
    file_name: str, image_transform: Optional[ImageTransform] = None,
) -> ImageObject:
    """File name must be full path"""
    img = Image.open(file_name).convert("RGBA")
    if image_transform:
        return image_transform(img)
    return img

def load_raw_data(
    root_dir: str, image_transform: Optional[ImageTransform] = None
) -> Tuple[Sequence[ImageObject], Sequence[str]]:
    """
    Loads all images as color image objects.
    """
    files = os.listdir(root_dir)
    print(f"Total number of files: {len(files)}")
    images, filenames = [], []
    for ind, file in enumerate(files):
        img = load_image(f"{root_dir}/{file}", image_transform)
        images.append(img)
        filenames.append(file)

    return images, filenames

class IndexDataset(Dataset):
    def __init__(
        self,
        index_table: pd.DataFrame,
        img_dir: str,
        file_col: int = 1,
        label_col: int = 5,
        label_mapping: Optional[Mapping[str, int]] = None,
        image_transform: Optional[ImageTransform] = None,
        torch_transforms: Optional[ComposedTorchTransforms] = None,
    ) -> None:
        """
        file and label col are 0-based.

        label_mapping is to convert strings labels into integers.
        If none this is done implicitly.
        """
        self.index_table = index_table
        self.file_column = index_table.columns[file_col]
        self.label_column = index_table.columns[label_col]
        self.img_dir = img_dir
        self.image_transform = image_transform

        self.torch_transforms = torch_transforms
        if not torch_transforms:
            self.torch_transforms = ToTensor

        self.label_mapping = label_mapping
        if not label_mapping:
            labels = self.index_table[self.label_column].unique()
            self.label_mapping = {k: v for v, k in enumerate(labels)}

    def __len__(self) -> int:
        return len(self.index_table)

    def __getitem__(self, idx: int) -> Tuple[Tensor, Tensor]:
        data_item = self.index_table.iloc[idx]
        file_name = self.img_dir + "/" + data_item[self.file_column]
        img = load_image(file_name, self.image_transform)
        label = self.label_mapping[data_item[self.label_column]]

        if self.torch_transforms:
            img = self.torch_transforms(img)

        label = torch.tensor(label, dtype=torch.long)
        return img, label

class ImageDataset(Dataset):
    def __init__(
        self,
        images: ImageObject,
        transforms: Optional[ComposedTorchTransforms] = None,
    ) -> None:
        """Takes in PIL Images"""
        self.data = images
        self.transforms = transforms

    def __getitem__(self, idx: int) -> Tensor:
        item = self.data[idx]
        return self.transforms(item)

    def __len__(self) -> int:
        return len(self.data)


'''
문제2)
https://github.com/pykwon/python/tree/master/data
자전거 공유 시스템 분석용 데이터 train.csv를 이용하여 대여횟수에 영향을 주는 변수들을 골라 다중선형회귀분석 모델을 작성하시오.
모델 학습시에 발생하는 loss를 시각화하고 설명력을 출력하시오.
새로운 데이터를 input 함수를 사용해 키보드로 입력하여 대여횟수 예측결과를 콘솔로 출력하시오.
'''

import pandas as pd
import numpy as np

df = pd.read_csv("https://raw.githubusercontent.com/pykwon/python/master/data/train.csv",
                 sep=',', parse_dates=['datetime'])
print(df.info())
df.drop(columns='datetime', inplace=True)
print(df.info())
#상관계수 확인
co_re=df.corr()
print(co_re['count'].sort_values(ascending=False))

x= df.loc[:,['registered','casual','temp','atemp','humidity']]
y= df.iloc[:,-1]

from sklearn.preprocessing import MinMaxScaler
scaler=MinMaxScaler(feature_range=(0,1))
x=scaler.fit_transform(x)

from sklearn.model_selection import train_test_split
x_train, x_test, y_train,y_test=train_test_split(x,y,test_size=0.3)
# print(x_train.shape, x_test.shape, y_train.shape,y_test.shape)
# (7620, 5) (3266, 5) (7620,) (3266,)

from keras.models import Sequential
from keras.layers import Dense
model=Sequential()
model.add(Dense(units=1, input_dim=5, activation='linear'))

model.compile(optimizer='sgd', loss='mse', metrics=['mse'])
history=model.fit(x_train, y_train, epochs=20, verbose=0, validation_split=0.15)
print(history.history['loss'])

#시각화
import matplotlib.pyplot as plt
plt.plot(history.history['loss'], label='train loss')
plt.xlabel('epochs')
plt.show()

#설명계수
from sklearn.metrics import r2_score
pred=model.predict(x_test)
print('설명력',r2_score(y_test, pred)) #설명력 0.924356 #epochs=10


import logging

from cachetools import LRUCache
from .config import session_config
from tidalapi import Session

session_cache = LRUCache(maxsize=1)

def authenticate():
    # Load the config file
    config = session_config()

    # authenticate and save session
    session = Session()
    session.login_oauth_simple()

    if session.check_login():
        logging.info('Authentication successful!')
        # Save the session data to the config file
        session_data = {
            'access_token': session.access_token,
            'refresh_token': session.refresh_token,
            'expiry_time': session.expiry_time,
        }
        config.file['session_data'] = session_data
        config.save()
        logging.info('Session saved')
    else:
        logging.error('Authentication failed. Please try again.')

def load_session():
    # Check if session data is already in the cache
    session = session_cache.get('session')
    if session:
        return session

    # Load config
    config = session_config()
    logging.debug("check_session called")

    # Read session data from config
    session_data = config.file.get('session_data')
    if not session_data:
        return None

    # Load session data
    session = Session()
    if session.load_oauth_session(
        token_type='Bearer',
        access_token=session_data.get('access_token'),
        refresh_token=session_data.get('refresh_token'),
        expiry_time=session_data.get('expiry_time')
    ):
        # Retrieve session data
        session_id = session.session_id
        country_code = session.country_code
        user_id = session.user.id

        # Update session_data and save to config
        session_data['session_id'] = session_id
        session_data['country_code'] = country_code
        session_data['user_id'] = user_id
        config.file['session_data'] = session_data
        config.save()

        # Add session data to cache
        session_cache['session'] = session

        return session
    else:
        return None


from PyQt5 import QtWidgets, QtGui, uic
from PyQt5.QtWidgets import QMessageBox, QFileDialog, QTableWidgetItem
from qgis.core import QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject, Qgis, QgsWkbTypes
import os
import codecs
import math
import qgis
import sys
sys.modules['qgscolorbutton']=qgis.gui # a workaround to make setupUi know QGSColorButton

FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'scaled_models.ui'))

class ScaledModelsDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(ScaledModelsDialog, self).__init__(parent)
        self.setupUi(self)
        # event handlers
        self.pbOK.clicked.connect(self.confirmOK) # OK Button
        self.pbCancel.clicked.connect(self.reject) # Cancel button
        self.pbBrowse.clicked.connect(self.browseFile) # open file dialog on clicking the browse button
        self.layerList.currentIndexChanged.connect(self.getAttrList) # get attribute list when a layer is selected
        self.pbAdd.clicked.connect(self.addAttr) # Add button
        self.pbRemove.clicked.connect(self.removeAttr) # Remove button
        self.twTimesAttrs.itemSelectionChanged.connect(self.enableDisableRemove) # Enable/disable remove button
        self.rbLin.toggled.connect(self.showMinMax) # update min/max when scale type is changed
        self.rbSqrt.toggled.connect(self.showMinMax) # update min/max when scale type is changed
        self.rbLog.toggled.connect(self.showMinMax) # update min/max when scale type is changed
        self.scaleFactor.textEdited.connect(self.showMinMax) # update min/max when scale factor is changed

    def browseFile(self):
        """Opens a file save as dialog to get the file name"""
        fn,_=QFileDialog.getSaveFileName(self,"Save file as...","","CZML flies (*.czml)")
        if (fn!=""):
            self.leFileName.setText(fn)

    def confirmOK(self):
        """Checks if a filename was specified before accepting the dialog"""
        if (self.leFileName.text()==''):
            QMessageBox.warning(self,"Warning","You must specify a filename!")
        else:
            self.accept()

    def getAttrList(self):
        """Loads the attribute names of the selected layer into attrList and strAttrList comboboxes"""
        # find layer by chosen name
        name=self.layerList.currentText()
        alayer=None
        layers = [tree_layer.layer() for tree_layer in QgsProject.instance().layerTreeRoot().findLayers()]
        for layer in layers:
            if (layer.name()==name):
                alayer=layer
                break
        if alayer==None:
            return
        # get attr list
        al=[]
        self.strAttrList.clear()
        for fld in alayer.fields():
            if (fld.typeName() in ['Integer','Real']): # TODO: add other numeric types
                al.append(fld.name()) # a mappable attribute if numeric
            elif (fld.typeName()=='String'):
                self.strAttrList.addItem(fld.name()) # an attribute can be used as name if it is a string
        # dictionaries for min/max attribute values
        self.amin={}
        self.amax={}
        # get and min/max attribute values
        for i,f in enumerate(alayer.getFeatures()):
            for a in al:
                if (f[a]):
                    if (not a in self.amin): # when it is the first feature, simply set the min/max valuse for the attrs
                        self.amin[a]=f[a]
                        self.amax[a]=f[a]
                    else: # otherwise change min/max if neccessary
                        if (f[a]<self.amin[a]):
                            self.amin[a]=f[a]
                        if (f[a]>self.amax[a]):
                            self.amax[a]=f[a]
        # set attr list
        self.attrList.clear()
        self.attrList.addItems(al)

    def showMinMax(self):
        """Displays the min/max values for the chosen attribute set"""
        # if nothing is selected, empty the text field and return
        if self.twTimesAttrs.rowCount()==0:
            self.lblRange.setText('')
            return
        # iterate over selected attributes and find absolute min and max
        self.minV=None
        self.maxV=None
        for row in range(self.twTimesAttrs.rowCount()):
            aName=self.twTimesAttrs.item(row,1).text()
            if self.minV==None or self.minV>self.amin[aName]:
                self.minV=self.amin[aName]
            if self.maxV==None or self.maxV<self.amax[aName]:
                self.maxV=self.amax[aName]
        # min/max values using currently selected scale function and factor
        if (self.rbLin.isChecked()):
            mn=self.minV
            mx=self.maxV
        elif (self.rbSqrt.isChecked()):
            if (self.minV<0 or self.maxV<0):
                # use sqrt only for non-negative values
                QMessageBox.warning(self,"Warning","Square root is not applicable for negative values!")
                self.rbLin.toggle()
                return
            mn=math.sqrt(self.minV)
            mx=math.sqrt(self.maxV)
        else:
            if (self.minV<=0 or self.maxV<=0):
                # use log only for positive values
                QMessageBox.warning(self,"Warning","Logarithm is not applicable for non-positive values!")
                self.rbLin.toggle()
                return
            mn=math.log(self.minV)
            mx=math.log(self.maxV)
        # failsafe string-float conversion
        try:
            sf=float(self.scaleFactor.text())
        except ValueError:
            sf=0
        # modify min/max by scale
        mn=mn*sf
        mx=mx*sf
        self.sf=sf
        self.lblRange.setText(str(mn)+" - "+str(mx))

    def addAttr(self):
        """Add selected attribute and time to time/attribute list"""
        # current attr name
        aname=self.attrList.currentText()
        if (aname==""):
            return
        time=self.dteTime.dateTime().toString(1)+"Z" # ISO datetime
        # add new row
        row=self.twTimesAttrs.rowCount()+1
        self.twTimesAttrs.setRowCount(row)
        # put datetime and attribute name to table
        self.twTimesAttrs.setItem(row-1,0,QTableWidgetItem(time,0))
        self.twTimesAttrs.setItem(row-1,1,QTableWidgetItem(aname,0))
        self.twTimesAttrs.sortItems(0);
        # update min/max information
        self.showMinMax()

    def enableDisableRemove(self):
        """Enable/disable remove button"""
        # Remove button is enabled if there is something selected
        self.pbRemove.setEnabled(len(self.twTimesAttrs.selectedItems())>0)

    def removeAttr(self):
        """Add selected attribute and time to time/attribute list"""
        # remove selected row
        self.twTimesAttrs.removeRow(self.twTimesAttrs.selectedItems()[0].row())
        # disable remove button
        self.pbRemove.setEnabled(False)
        # update min/max information
        self.showMinMax()

    def runThis(self,iface):
        """This is called when user clicks on "CZML Scaled models with time"

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # store iface
        self.iface=iface

        # clear lists
        self.layerList.clear()
        self.twTimesAttrs.clear()
        self.twTimesAttrs.setRowCount(0)

        # place to store legend settings
        self.legendSamples=None

        # collect currently loaded vector layers to "layerList" comboBox
        #layers=iface.legendInterface().layers()
        layers = [tree_layer.layer() for tree_layer in QgsProject.instance().layerTreeRoot().findLayers()]
        ll=[]
        for layer in layers:
            # check if it is a vector layer
            if (layer.type()==layer.VectorLayer):
                ll.append(layer.name())
        self.layerList.addItems(ll)
        # die if no suitable layers found
        if (len(ll)==0):
            QMessageBox.warning(self,"Error","No suitable layers found.")
            return
        # show dialog
        self.show()
        if self.exec_():
            # OK clicked, let's create the CZML file

            # get filename
            filename=self.leFileName.text()
            # set html legend filename
            htmlFn=filename+".legend.html"
            # find layer by chosen name
            name=self.layerList.currentText()
            for layer in layers:
                if (layer.name()==name):
                    alayer=layer
                    break
            # get chosen attribute name
            aName=self.attrList.currentText()
            # create projection transformer object
            crsDest = QgsCoordinateReferenceSystem(4326) # WGS 84
            crsSrc = alayer.crs()
            xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
            # find minimum/maximum time and attribute value
            self.minT=None
            self.maxT=None
            usedAttrs=[]
            for row in range(self.twTimesAttrs.rowCount()):
                t=self.twTimesAttrs.item(row,0).text()
                usedAttrs.append(self.twTimesAttrs.item(row,1).text())
                if self.minT==None or self.minT>t:
                    self.minT=t
                if self.maxT==None or self.maxT<t:
                    self.maxT=t
            self.minV=None
            self.maxV=None
            for aName in usedAttrs:
                if self.minV==None or self.minV>self.amin[aName]:
                    self.minV=self.amin[aName]
                if self.maxV==None or self.maxV<self.amax[aName]:
                    self.maxV=self.amax[aName]
            # get model url
            modelURL=self.leModelURL.text()
            # open output file
            ofile=codecs.open(filename,'w','utf-8')
            # leading [ and document packet
            ofile.write('[\n{"id":"document","version":"1.0"}')
            # iterate over feaures
            polyN=0
            for f in alayer.getFeatures():
                # calculate animated value (scale) if there is more than one timestamp
                scales=[]
                for row in range(self.twTimesAttrs.rowCount()):
                    aTime=self.twTimesAttrs.item(row,0).text()
                    aName=self.twTimesAttrs.item(row,1).text()
                    # calculate height
                    value=f[aName]
                    if (not value):
                        value=0
                    if (self.rbLin.isChecked()):
                        h=value
                    elif (self.rbSqrt.isChecked()):
                        h=math.sqrt(value)
                    else:
                        h=math.log(value)
                    h=h*self.sf
                    if (self.minT==self.maxT):
                        scales.append(str(h))
                    else:
                        scales.append('"'+aTime+'",'+str(h))
                # get centroid in WGS84
                cent=xform.transform(f.geometry().centroid().asPoint())
                coords=str(cent.x())+","+str(cent.y())+",0"
                # add element name if checked
                if (self.cbAddName.isChecked()):
                    nameString=',\n\t"name":"'+f[self.strAttrList.currentText()]+'"'
                else:
                    nameString=''
                # create availability and scale series only if more than 1 attribute
                if (self.minT==self.maxT):
                    availString=''
                    scaleString=scales[0]
                else:
                    availString=',"availability":"'+self.minT+'/'+self.maxT+'"'
                    scaleString='['+(','.join(scales))+']'
                packetString='{\n\t"id":"point'+str(polyN)+'"'+nameString+availString+',\n\t"position":{\n\t\t"cartographicDegrees":['+coords+']},\n\t"model":{\n\t\t"gltf":"'+modelURL+'",\n\t\t"scale":{"number":'+scaleString+'}}}'
                ofile.write(",\n"+packetString);
                polyN=polyN+1
            # trailing ] and close flie
            ofile.write('\n]')
            ofile.close()
            # farewell message
            msg="CZML file ("+filename+")"
            msg=msg+" successfully created."
            QMessageBox.information(self,"Information",msg)


""" this program uses a while loop to repeatedly ask the user for their favourite movies """

# set list to store movies
movies = []

keep_asking = True

while keep_asking == True:
    movie_name = input("Enter a favourite movie\n")
    if movie_name == "stop":
        keep_asking = False

    else:
        movies.append(movie_name)

print(movies)

#loop through list and display the movies
for movie in movies:
    print(movie)

# loop through list and produce a numbered list of items
for i in range(len(movies)):
    print(i+1, movies[i])


from PIL import Image
import numpy as np
import requests
from transformers import CLIPProcessor, CLIPTokenizer, CLIPModel
import torch

# SETUP
CLIP_MODEL_NAME = 'openai/clip-vit-large-patch14-336'
# --- model + preprocess for images
ViTL14_336_model = CLIPModel.from_pretrained(CLIP_MODEL_NAME)
ViTL14_336_processor = CLIPProcessor.from_pretrained(CLIP_MODEL_NAME)
ViTL14_336_tokenizer = CLIPTokenizer.from_pretrained(CLIP_MODEL_NAME)

# METHODS
# --- helpers
def _image_file_urls_to_files(image_file_urls_arr):
    return list(map(lambda image_file_url: Image.open(requests.get(image_file_url, stream=True).raw), image_file_urls_arr))

# --- embedding
def clip_text_embedding(text_arr):
    print('INFO (clip.py:clip_text_embedding): ', text_arr)
    with torch.no_grad():
        processed_text_arr = ViTL14_336_tokenizer(text=text_arr, padding=True, return_tensors="pt")
        text_embeddings = ViTL14_336_model.get_text_features(**processed_text_arr)
        # convert to list of float32 np arrays to be consistent
        text_embeddings = list(map(lambda em: np.asarray(em, dtype='float32'), text_embeddings))
        return text_embeddings

def clip_image_embedding(image_file_url_arr):
    print(f'INFO (clip.py:clip_image_embedding):', image_file_url_arr)
    with torch.no_grad():
        image_arr = _image_file_urls_to_files(image_file_url_arr)
        print(f'INFO (clip.py:clip_image_embedding): image_arr', image_arr)
        processed_image_mappings = ViTL14_336_processor(images=image_arr, return_tensors="pt")
        print(f'INFO (clip.py:clip_image_embedding): processed_image_mappings', processed_image_mappings)
        image_embedding = ViTL14_336_model.get_image_features(**processed_image_mappings)
        # print(f'INFO (clip.py:clip_image_embedding): image_embedding', image_embedding)
        # convert to list of float32 np arrays to be consistent
        image_embeddings = list(map(lambda em: np.asarray(em, dtype='float32'), image_embedding))
        return image_embeddings

# --- text<>image similarity (https://huggingface.co/docs/transformers/model_doc/clip#usage)
def clip_classifications(image_file_urls, classifications, min_similarity=0.1):
    print('INFO (clip.py:clip_classifications)', classifications)
    # PREPROCESS
    # --- image embeddings
    image_files = _image_file_urls_to_files(image_file_urls)
    # --- classifications (actually, it just expects the text as is. no need to tokenize pre-process)
    classification_text = classifications
    # MULTI-MODAL COMPARISON
    alignment = ViTL14_336_processor(text=classification_text, images=image_files, padding=True, return_tensors="pt")
    # input_ids + attention masks =...
    outputs = ViTL14_336_model(**alignment)
    logits_per_image = outputs.logits_per_image
    probabilities = logits_per_image.softmax(dim=1).tolist() # float[][] -> predictionss arr for each image
    # CLASSIFICATIONS
    predictions = []
    # ... for each image
    for image_probs in probabilities:
        image_predicts = []
        for idx, value in enumerate(image_probs):
            # --- expect min of 0.1, otherwise don't push
            if value > min_similarity:
                image_predicts.append({ "classification": classifications[idx], "score": value })
        predictions.append(image_predicts)

    print('INFO (clip.py:clip_classifications) predictions:', predictions)
    return predictions


# -*- coding: utf-8 -*-
import sys, argparse, logging, joblib
sys.path.insert(0, 'lib/')
from filehandler import FileHandler
import pandas as pd
import numpy as np
from scipy.stats import expon

from dask.distributed import Client, progress
from sklearn.metrics import classification_report

from model.svct import SVCT

from sklearn.gaussian_process import GaussianProcessClassifier
from sklearn.gaussian_process.kernels import RBF, WhiteKernel, DotProduct, PairwiseKernel

from sklearn.ensemble import RandomForestClassifier

from sklearn.naive_bayes import GaussianNB

from util import evaluate, cv
from config import read_options
from viz import Viz

def main():

    if hasattr(options, 'dask'): client = Client('{}:8786'.format(options.dask))
    else: client = Client()

    logging.info(client)

    if hasattr(options, 's3_bucket'):
        fh = FileHandler(s3_bucket=options.s3_bucket)
        viz = Viz(io=fh)
    else:
        fh = FileHandler()
        viz = Viz()

    datasets = fh.read_data([options.train_data, options.test_data], options)

    X_train = datasets[0][0]
    y_train = datasets[0][1]
    X_test = datasets[1][0]
    y_test = datasets[1][1]

    # Train
    if options.model == 'svct':
        model = SVCT(verbose=True)
    elif options.model == 'gp':
        kernel = PairwiseKernel(metric='laplacian') *  DotProduct()
        model = GaussianProcessClassifier(kernel=kernel, n_jobs=-1)
    elif options.model == 'rfc':
        # param_grid_rfc = {
        # "n_estimators": [10, 100, 150, 200, 250, 500],
        # "max_depth": [20, 50, 100, None],
        # "max_features": ["auto", "log2", None],
        # "min_samples_split": [2,5,10],
        # "min_samples_leaf": [1, 2, 4],
        # "bootstrap": [False]
        # }

        # Fetched using 5-fold cv with random search from params above
        if "national" in options.dataset:
            params = {'n_estimators': 500, 'min_samples_split': 2, 'min_samples_leaf': 1, 'max_features': 'sqrt', 'max_depth': None, 'bootstrap': False, 'n_jobs': -1}
        else:
            params = {'n_estimators': 250, 'min_samples_split': 2, 'min_samples_leaf': 10, 'max_features': None, 'max_depth': 20, 'bootstrap': False, 'n_jobs': -1}

        model = RandomForestClassifier(**params)

    elif options.model == 'gnb':
        model = GaussianNB()
    else:
        raise Exception('Model not defined')

    logging.info('Training...')
    if options.model == 'gnb':
        priors = []
        for i in np.arange(0,1,.05):
            for j in np.arange(0, 1-i, .05):
                k = 1 - i - j
                priors.append([i, j, k])

        param_grid_gnb = {
        'priors': priors+[None],
        'var_smoothing': expon(scale=.01)
        }
        model, cv_results = cv(model, param_grid_gnb, X_train, y_train, n_iter=500)
    else:
        with joblib.parallel_backend('dask'):
            model.fit(X_train, y_train)

    # Evaluate
    y_pred_train = model.predict(X_train)
    logging.info('Training report:\n{}'.format(classification_report(y_train, y_pred_train)))

    y_pred = model.predict(X_test)
    logging.info('Validation report:\n{}'.format(classification_report(y_test, y_pred)))

    fname = '{}/confusion_matrix_testset.png'.format(options.output_path)
    viz.plot_confusion_matrix(y_test, y_pred, np.arange(3), filename=fname)

    fname = '{}/confusion_matrix_testset_normalised.png'.format(options.output_path)
    viz.plot_confusion_matrix(y_test, y_pred, np.arange(3), True, filename=fname)

    if options.model == 'rfc':
        # Sort feature importances in descending order and rearrange feature names accordingly
        indices = np.argsort(model.feature_importances_)[::-1]
        names = [options.feature_params[i] for i in indices]
        importances = model.feature_importances_[indices]

        fname = '{}/feature_importances.png'.format(options.output_path)

        viz.rfc_feature_importance(importances, fname, names)

    if options.model == 'svct':
        fh.save_svct(model, options.save_path)
    else:
        fh.save_model(model, options.save_path)

if __name__ =='__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('--config_filename', type=str, default='cnf/options.ini', help='Config filename for training config')
    parser.add_argument('--config_name', type=str, default='thin', help='Config section for training config')
    parser.add_argument('--train_data', type=str, default='', help='Train dtaset file')
    parser.add_argument('--test_data', type=str, default='', help='Test dataset file')
    parser.add_argument('--model', type=str, default='svct', help='Used model')
    parser.add_argument('--dataset', type=str, default='local_random', help='For saving results and model')
    parser.add_argument('--max_size', type=int, default=None, help='Cut data to this size')

    if len(sys.argv) <= 1:
        parser.print_help()
        sys.exit()

    options = parser.parse_args()
    read_options(options)

    logging.basicConfig(format=("[%(levelname)s] %(asctime)s %(filename)s:%(funcName)s:%(lineno)s %(message)s"),
                        level=logging.INFO)

    logging.info('Using config {} from {}'.format(options.config_name, options.config_filename))

    main()


from Utils import *
import random
import time
import string

def io_heavy(text,base):
    start = time.time() - base
    f = open('output.txt', 'wt', encoding='utf-8')
    f.write(text)
    f.close()
    stop = time.time() - base
    return start,stop

if __name__ == '__main__':
    TEXT_SIZE=10000000
    N=12
    TEXT = ''.join(random.choice(string.ascii_lowercase) for i in range(TEXT_SIZE))

    res_multithreading=multithreading(io_heavy, [TEXT for i in range(N)], 4)
    total_time=visualize_runtimes(res_multithreading, MULTITHREADING_TITLE)
    print(f"total time for multithreading = {total_time}")

    res_multiprocessing=multiprocessing(io_heavy, [TEXT for i in range(N)], 4)
    total_time=visualize_runtimes(res_multiprocessing,MULTIPROCESSING_TITLE)
    print(f"total time for multiprocessing = {total_time}")


def main():

    valor = float(input())

    nota_100 = valor // 100
    resto_100 = (valor %100)
    nota_50 = resto_100 // 50
    resto_50 = (resto_100 % 50)
    nota_20 = resto_50 // 20
    resto_20 = (resto_50 % 20)
    nota_10 = resto_20 // 10
    resto_10 = (resto_20 % 10)
    nota_5 = resto_10 // 5
    resto_5 = (resto_10 % 5)
    nota_2 = resto_5 // 2

    moeda_100 = (resto_5 % 2)

    novo_valor = moeda_100 * 100
    moeda_50 = novo_valor // 50
    if moeda_50 %2 == 0:
        moeda_50 = 0
    elif not(moeda_50%2==0) and moeda_50>1:
        moeda_50 = moeda_50 - 2
    resto_m50 = novo_valor % 50
    moeda_25 = resto_m50 // 25
    resto_m25 = round(resto_m50 % 25)
    moeda_10 = resto_m25 // 10
    resto_m10 = round(resto_m25 % 10)
    moeda_5 = resto_m10 // 5
    resto_m5 = round(resto_m10 % 5)
    moeda_1 = (resto_m5 // 1)

    print('NOTAS:')
    print('%d nota(s) de R$ 100.00' % nota_100)
    print('%d nota(s) de R$ 50.00' % nota_50)
    print('%d nota(s) de R$ 20.00' % nota_20)
    print('%d nota(s) de R$ 10.00' % nota_10)
    print('%d nota(s) de R$ 5.00' % nota_5)
    print('%d nota(s) de R$ 2.00' % nota_2)
    print('MOEDAS:')
    print('%d moeda(s) de R$ 1.00' % moeda_100)
    if moeda_50 != 1:
        print('%d moeda(s) de R$ 0.50' % 0)
    else:
        print('%d moeda(s) de R$ 0.50' % moeda_50)
    print('%d moeda(s) de R$ 0.25' % moeda_25)
    print('%d moeda(s) de R$ 0.10' % moeda_10)
    print('%d moeda(s) de R$ 0.05' % moeda_5)
    print('%d moeda(s) de R$ 0.01' % (moeda_1))

main()


import streamlit as st
from pyairtable import Table
from pyairtable.formulas import match
import os
from dotenv import load_dotenv

load_dotenv()  # Load environment variables from .env file

AIRTABLE_KEY = os.environ["AIRTABLE_API_KEY"]

def load_candidate_details(name):
    table = Table(
        api_key=AIRTABLE_KEY, base_id="appNHbOjDXpsU37JE", table_name="Candidates"
    )
    formula = match({"Name": name})
    candidate = table.first(formula=formula)
    return candidate

def go_back():
    st.session_state._page = "Form"

def display_candidate():
    col1, col2 = st.columns([0.2, 0.8])
    col1.button(label="Back", on_click=go_back)
    col2.header("Candidate :green[Details]", anchor=False)
    st.divider()

    candidate = load_candidate_details(st.session_state.candidate_name)

    st.subheader(candidate["fields"]["Name"], anchor=False)
    st.write(f'Country: {candidate["fields"]["Country"]}')
    st.write(f'Email: {candidate["fields"]["Email"]}')
    st.write(f'Phone: {candidate["fields"]["Phone"]}')
    st.divider()

    st.subheader(":green[Skills]", anchor=False)
    skills = candidate["fields"]["Skills"]
    skills_cols = st.columns(len(skills))
    st.write(skills)
    # for i, skill in enumerate(skills):
    #     skills_cols[i].write(skill)
    st.divider()

    st.subheader(":green[Computer Skills]", anchor=False)
    comp_skills = candidate["fields"]["Computer Skills"]
    comp_skills_cols = st.columns(len(comp_skills))
    st.write(comp_skills)
    # for i, comp_skill in enumerate(comp_skills):
    #     comp_skills_cols[i].write(comp_skill)
    st.divider()

    st.subheader(":green[Summary]", anchor=False)
    st.write(candidate["fields"]["Career Summary"])


"""Distributor m2m

Revision ID: 7ea7616eadf5
Revises: d96ab19acb14
Create Date: 2023-07-16 18:46:36.140907

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "7ea7616eadf5"
down_revision = "d96ab19acb14"
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "distributors",
        sa.Column("film_id", sa.Integer(), nullable=False),
        sa.Column("distributor_id", sa.Integer(), nullable=False),
        sa.ForeignKeyConstraint(
            ["distributor_id"],
            ["distributor.id"],
        ),
        sa.ForeignKeyConstraint(
            ["film_id"],
            ["film.id"],
        ),
        sa.PrimaryKeyConstraint("film_id", "distributor_id"),
    )
    op.drop_constraint("film_distributor_id_fkey", "film", type_="foreignkey")
    op.drop_column("film", "distributor_id")
    op.drop_constraint(
        "film_week_distributor_id_fkey", "film_week", type_="foreignkey"
    )
    op.drop_column("film_week", "distributor_id")
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column(
        "film_week",
        sa.Column(
            "distributor_id", sa.INTEGER(), autoincrement=False, nullable=True
        ),
    )
    op.create_foreign_key(
        "film_week_distributor_id_fkey",
        "film_week",
        "distributor",
        ["distributor_id"],
        ["id"],
    )
    op.add_column(
        "film",
        sa.Column(
            "distributor_id", sa.INTEGER(), autoincrement=False, nullable=True
        ),
    )
    op.create_foreign_key(
        "film_distributor_id_fkey",
        "film",
        "distributor",
        ["distributor_id"],
        ["id"],
    )
    op.drop_table("distributors")
    # ### end Alembic commands ###


from tkinter import *
import customtkinter
from Converter import Converter
from graphic import Graphic

# need custom tkinters for this to work
# pip3 install customtkinter
# documentation: https://github.com/TomSchimansky/CustomTkinter

class Table:

    def __init__(self, root, total_rows, total_columns, lst, size):

        # code for creating table
        for i in range(total_rows):
            for j in range(total_columns):
                current_size = 4

                if (len(lst[i][j]) > 4):
                    current_size = len(lst[i][j])

                self.e = Entry(root, width=current_size, fg='black',
                               font=('Consolas', size, 'bold'))

                self.e.grid(row=i, column=j)
                self.e.delete(0, END)
                self.e.insert(END, lst[i][j])

class Code_Hamming:

    def __init__(self):
        self.bit = '0'
        self.InPar = False
        self.p = [[3, 5, 7, 9, 11, 13, 15, 17], [3, 6, 7, 10, 11, 14, 15], [5, 6, 7, 12, 13, 14, 15],
                  [9, 10, 11, 12, 13, 14, 15], [17]]
        self.hambit = '0'

    def Obtener_dato(self, num):
        self.bit = num

    def calcRedundantBits(self, m):
        for i in range(m):
            if (2 ** i >= m + i + 1):
                return i

    def posRedundantBits(self, data, r):

        # Redundancy bits are placed at the positions
        # which correspond to the power of 2.
        j = 0
        k = 0
        m = len(data)
        res = ''

        # If position is power of 2 then insert '0'
        # Else append the data
        for i in range(1, m + r + 1):
            if (i == 2 ** j):
                res = 'N' + res
                j += 1
            else:
                res = data[k] + res
                k += 1

        # The result is reversed since positions are
        # counted backwards. (m + r+1 ... 1)
        return res[::-1]

    def checkbits(self, paritybits, bitlist):

        cant1s = 0

        for i in paritybits:
            if bitlist[i - 1] == '1':
                cant1s += 1

        return cant1s

    def calcBitParidad(self, paridad):

        self.InPar = paridad

        # Calculate the no of Redundant Bits Required
        m = len(self.bit)
        # print(m)
        r = self.calcRedundantBits(m)
        # print(r)

        # Determine the positions of Redundant Bits
        self.hambit = self.posRedundantBits(self.bit, r)
        # print(self.hambit)

        paritybit = 0

        bitlist = list(self.hambit)

        while paritybit < len(self.p):

            cant1s = self.checkbits(self.p[paritybit], bitlist)

            if self.InPar:
                if cant1s % 2 == 0:
                    bitlist[2 ** paritybit - 1] = '1'
                else:
                    bitlist[2 ** paritybit - 1] = '0'

                # print(cant1s)
            else:
                if cant1s % 2 == 0:
                    bitlist[2 ** paritybit - 1] = '0'
                else:
                    bitlist[2 ** paritybit - 1] = '1'

                # print(cant1s)

            paritybit += 1

        # print(bitlist)
        return bitlist

    def verBitParidad(self, binary, evenParity):

        verificationlist = [[], [], [], [], []]
        errorPosition = []
        bitlist = binary

        paritybit = 0

        while paritybit < 5:

            amountOf1s = self.checkbits(self.p[paritybit], bitlist)

            if evenParity:
                if amountOf1s % 2 == 0:
                    if bitlist[2 ** paritybit - 1] != '1':
                        verificationlist[paritybit] = ['     Error    ', '1']
                    else:
                        verificationlist[paritybit] = ['   Correcto   ', '0']
                else:
                    if bitlist[2 ** paritybit - 1] != '0':
                        verificationlist[paritybit] = ['     Error    ', '1']
                    else:
                        verificationlist[paritybit] = ['   Correcto   ', '0']
            else:
                if amountOf1s % 2 == 0:
                    if bitlist[2 ** paritybit - 1] != '0':
                        verificationlist[paritybit] = ['     Error    ', '1']
                    else:
                        verificationlist[paritybit] = ['   Correcto   ', '0']
                else:
                    if bitlist[2 ** paritybit - 1] != '1':
                        verificationlist[paritybit] = ['     Error    ', '1']
                    else:
                        verificationlist[paritybit] = ['   Correcto   ', '0']
            paritybit += 1

        for i in verificationlist:
            errorPosition.append(i[1])

        errorPosition.reverse()

        errornum = ''.join(errorPosition)

        errornum = int(errornum, 2)

        return (verificationlist, errornum)

class GUI(customtkinter.CTk):

    def __init__(self):
        super().__init__()

        # create a window
        self.newNumber = []
        self.geometry(f"{1105}x{600}")
        self.title("Hamming Code")
        self.resizable(False, False)

        # create a converter object
        self.converter = Converter()
        self.hamming = Code_Hamming()

        self.paridad = False
        self.bipolar = False

        # main frame
        self.frame = customtkinter.CTkFrame(master=self.master, width=1105, height=600)
        self.frame.place(x=0, y=0)

        # HammingGeneratorTable frame
        self.tableHammingGenerator = customtkinter.CTkFrame(master=self.master, width=400, height=200)
        self.tableHammingGenerator.place(x=325, y=75)

        # HammingGeneratorVerification frame
        self.tableHammingVerification = customtkinter.CTkFrame(master=self.master, width=400, height=200)
        self.tableHammingVerification.place(x=150, y=350)

        # number entry
        self.numberEntry = customtkinter.CTkEntry(master=self.frame, placeholder_text="Introducir numero")
        self.numberEntry.place(x=10, y=10)

        # entry number button
        self.numberButton = customtkinter.CTkButton(master=self.frame, text="Calcular", command=self.Calculate)
        self.numberButton.place(x=160, y=10)

        #generate Hamming code
        self.GnrHamButton = customtkinter.CTkButton(master=self.frame, text="Generar Hamming", command=self.generar)
        self.GnrHamButton.place(x=450, y=10)

        # generate converter table with labels
        self.label = customtkinter.CTkLabel(master=self.frame, text="Tabla de conversion")
        self.label.place(x=0, y=50)
        self.label = customtkinter.CTkLabel(master=self.frame,
        text="Tabla 1 Calculo de los bits de paridad en el código Hamming")
        self.label.place(x=510, y=45)

        self.label = customtkinter.CTkLabel(master=self.frame,
        text="Tabla 2 Verificación de los bits de paridad con el código Hamming")
        self.label.place(x=510, y=320)

        self.labelErrorNumber = customtkinter.CTkLabel(master=self.frame,
        text="")
        self.labelErrorNumber.place(x=510, y=500)

        self.decimal = customtkinter.CTkLabel(master=self.frame, text="Decimal")
        self.decimal.place(x=0, y=70)

        self.decimalNumber = customtkinter.CTkLabel(master=self.frame, text="")
        self.decimalNumber.place(x=130, y=70)

        self.binary = customtkinter.CTkLabel(master=self.frame, text="Binario")
        self.binary.place(x=0, y=90)

        self.binaryNumber = customtkinter.CTkLabel(master=self.frame, text="")
        self.binaryNumber.place(x=130, y=90)

        self.hexa = customtkinter.CTkLabel(master=self.frame, text="Hexadecimal")
        self.hexa.place(x=0, y=110)

        self.hexaNumber = customtkinter.CTkLabel(master=self.frame, text="")
        self.hexaNumber.place(x=130, y=110)

        # Switch to parity

        self.switchVar = StringVar(value="on")
        self.switchVar = customtkinter.CTkSwitch(master=self.frame, text="Paridad par", command=self.switch_event,
                                                 variable=self.switchVar, onvalue="On", offvalue="Off")
        self.switchVar.place(x=310, y=15)

        # Switch to bipolar
        self.switchVar2 = StringVar(value="on")
        self.switchVar2 = customtkinter.CTkSwitch(master=self.frame, text="Bipolar", command=self.switch_event2,
                                                    variable=self.switchVar2, onvalue="On", offvalue="Off")
        self.switchVar2.place(x=310, y=50)

        # entry for each number in binary table in total is 11 numbers

        self.entry1 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry2 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry3 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry4 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry5 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry6 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry7 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry8 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry9 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry10 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry11 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry12 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry13 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry14 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry15 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry16 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        self.entry17 = customtkinter.CTkEntry(master=self.frame, placeholder_text="", width=5)

        # list of entries
        self.listEntry = [self.entry17,self.entry16,self.entry15,self.entry14,self.entry13,self.entry12, self.entry11, self.entry10, self.entry9, self.entry8, self.entry7, self.entry6,
                          self.entry5,self.entry4, self.entry3, self.entry2, self.entry1]

        # Button for change binary number

        self.changeButton = customtkinter.CTkButton(master=self.frame, text="Verificar", command=self.VerifyNewNumber)
        # self.changeButton.place(x=385, y=120)

    def switch_event(self):

        if self.switchVar.get() == "On":

            self.paridad = True

        else:

            self.paridad = False

        print(self.paridad)

    def switch_event2(self):

        if self.switchVar2.get() == "On":

            self.bipolar = True

        else:

            self.bipolar = False

        print(self.bipolar)

    def Calculate(self):

        number = self.numberEntry.get()

        if self.ValidateNumber(number):

            self.decimal = self.converter.OctalToDecimal(number)
            self.binary = self.converter.OctalToBinary(number)
            self.hexa = self.converter.OctalToHexadecimal(number)

            self.binary = str(self.binary)
            self.binary = "0" * (12 - len(self.binary)) + self.binary

            print("binary with zeros ", self.binary)

            self.decimalNumber.configure(text=str(self.decimal))
            self.binaryNumber.configure(text=str(self.binary))
            self.hexaNumber.configure(text=str(self.hexa))

            graphic = Graphic(self.binary, self.bipolar)
            graphic.Run()

        else:

            self.decimalNumber.configure(text="Error con el numero octal")
            self.binaryNumber.configure(text="Error con el numero octal")
            self.hexaNumber.configure(text="Error con el numero octal")

            for i in self.listEntry:
                i.configure(placeholder_text="")

    def ValidateNumber(self, number):

        if len(number) <= 4:
            for i in number:
                if int(i) >= 8:
                    return False
            return True
        else:
            return False

    def SetNumberOnEntry(self, number):

        number = number[::-1]
        index = 0
        posx = 800
        posy = 270

        for i in self.listEntry:

            i.delete(0, END)

        for i in range(len(number)):

            self.listEntry[i].insert(0, number[i])
            self.listEntry[i].place(x=posx, y=posy)
            posx -= 25
            index += 1

        for i in range(index, len(self.listEntry)):

            self.listEntry[i].insert(0, "")
            self.listEntry[i].place(x=posx, y=posy)
            posx -= 25

        self.changeButton.place(x=900, y=270)

    def GetNewNumber(self):

        self.newNumber= []
        tempList = self.listEntry[::-1]

        for i in tempList:
            if i.get() != "":
                self.newNumber.append(i.get()[0])

       #newNumber será el nuevo número binario que se modificó por el usuario

    def ValidateChangeNumber(self):

        for i in self.listEntry:

            if i.get() != "":

                if int(i.get()) >= 1:
                    return True

        return False

    def VerifyNewNumber(self):

        self.GetNewNumber()
        self.verificarHamm(self.newNumber, self.tableHammingVerification, self.paridad)

    def generarHamm(self, binary, root, paridad):

        print("Generando codigo Hamming")
        self.hamming.Obtener_dato(binary)
        self.hammOutput = self.hamming.calcBitParidad(paridad)\

        self.SetNumberOnEntry(self.hammOutput)

        lista1 = [("                             ", "p1", "p2", "d1", "p3", "d2", "d3", "d4", "p4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "p5",
                  "d12"),
                  ("Palabra de datos sin paridad:", " ", " ", binary[0], " ", binary[1], binary[2], binary[3], " ",
                   binary[4], binary[5], binary[6],
                   binary[7], binary[8], binary[9], binary[10], " ", binary[11]),
                  ("             p1              ", self.hammOutput[0], " ", self.hammOutput[2], " ", self.hammOutput[4], "", self.hammOutput[6], " ", self.hammOutput[8],
                   " ", self.hammOutput[10],
                   " ", self.hammOutput[12], " ", self.hammOutput[14], " ", self.hammOutput[16]),
                  ("             p2              ", " ", self.hammOutput[1], self.hammOutput[2], " ", " ", self.hammOutput[5], self.hammOutput[6], " ", " ",
                   self.hammOutput[9], self.hammOutput[10],
                   " ", " ", self.hammOutput[13], self.hammOutput[14], " ", " "),
                  ("             p3              ", " ", " ", " ", self.hammOutput[3], self.hammOutput[4], self.hammOutput[5], self.hammOutput[6], " ", " ", " ", " ",
                   self.hammOutput[11],
                   self.hammOutput[12], self.hammOutput[13], self.hammOutput[14], " ", " "),
                  ("             p4              ", " ", " ", " ", " ", " ", " ", " ", self.hammOutput[7], self.hammOutput[8], self.hammOutput[9], self.hammOutput[10],
                   self.hammOutput[11],
                   self.hammOutput[12], self.hammOutput[13], self.hammOutput[14], " ", " "),
                  ("             p5              ", " ", " ", " ", " ", " ", " ", " ", "", "", "", "", "", "", "", "", self.hammOutput[15],
                   self.hammOutput[16]),
                  ("Palabra de datos con paridad:", self.hammOutput[0], self.hammOutput[1], self.hammOutput[2], self.hammOutput[3],
                   self.hammOutput[4], self.hammOutput[5],
                   self.hammOutput[6], self.hammOutput[7], self.hammOutput[8], self.hammOutput[9], self.hammOutput[10], self.hammOutput[11],
                   self.hammOutput[12], self.hammOutput[13], self.hammOutput[14], self.hammOutput[15], self.hammOutput[16])]

        tabla1 = Table(root, 8, 18, lista1, 10)
        self.GetNewNumber()

    def verificarHamm(self, binary, root, parity):

        print("Verificando codigo Hamming")

        hammingVerBits, hammingErrorPos = self.hamming.verBitParidad(binary, parity)

        lista2 = [("                          ", "p1", "p2", "d1", "p3", "d2", "d3", "d4", "p4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "p5",
                  "d12", "Prueba Paridad", "Bit de Paridad"),

                  ("Palabra de datos recibida:", binary[0], binary[1], binary[2], binary[3], binary[4], binary[5], binary[6], binary[7],
                   binary[8], binary[9], binary[10], binary[11], binary[12], binary[13],binary[14], binary[15], binary[16], "              ", "              "),

                  ("            p1            ", binary[0], " ", binary[2], " ", binary[4], "", binary[6], " ", binary[8], " ", binary[10],
                   " ", binary[12], " ", binary[14], " ", binary[16], hammingVerBits[0][0], "      " + hammingVerBits[0][1] + "       "),

                  ("            p2            ", " ", binary[1], binary[2], " ", " ", binary[5], binary[6], " ", " ", binary[9], binary[10],
                   " ", " ", binary[13], binary[14], " ", " ", hammingVerBits[1][0], "      " + hammingVerBits[1][1] + "       "),

                  ("            p3            ", " ", " ", " ", binary[3], binary[4], binary[5], binary[6], " ", " ", " ", " ", binary[11],
                   binary[12], binary[13], binary[14], " ", " ", hammingVerBits[2][0], "      " + hammingVerBits[2][1] + "       "),

                  ("            p4            ", " ", " ", " ", " ", " ", " ", " ", binary[7], binary[8], binary[9], binary[10], binary[11],
                   binary[12], binary[13], binary[14], " ", " ", hammingVerBits[3][0], "      " + hammingVerBits[3][1] + "       "),

                  ("            p5            ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", binary[15],
                   binary[16], hammingVerBits[4][0], "      " + hammingVerBits[4][1] + "       ")]

        tabla2 = Table(root, 7, 20, lista2, 10)

        if (hammingErrorPos != 0):
            print(hammingErrorPos)
            if(self.converter.BinaryToDecimal(hammingErrorPos) > 17):
                self.labelErrorNumber.configure(text="Error detectado. No es posible verificar su posición")
            else:
                self.labelErrorNumber.configure(text="Se ha encontrado un error el bit: " + str(hammingErrorPos))
        else:
                self.labelErrorNumber.configure(text="No se han detectado errores")

    def generar(self):
        num = "110101100101"
        self.generarHamm(self.binary, self.tableHammingGenerator, self.paridad)
        self.verificarHamm(self.newNumber, self.tableHammingVerification, self.paridad)
        print("Generado")

customtkinter.set_appearance_mode("Dark")
customtkinter.set_default_color_theme("green")
GUI = GUI()
GUI.mainloop()


import numpy as np
import os
import matplotlib.pyplot as plt
import pickle
import cifa_cnn

# data directory
RESULT_PATH = os.getcwd() + "/result"
#RESULT_PATH = "F:/tmp/cifar10_data/cifar-10-batches-py"

imageSize = 32
labelSize = 1
imageDepth = 3
debugEncodedImage = True

def unpickle(file):
    with open(os.path.join(RESULT_PATH, file), 'rb') as fo:
        dict = pickle.load(fo, encoding='latin1')

    return dict

def display_cifar(images, size, all=False):
    n = len(images)
    plt.figure()
    plt.gca().set_axis_off()

    if not all:
        im = np.vstack([np.hstack([images[np.random.choice(n)] for i in range(size)])
                    for i in range(size)])
    else:
        im = np.vstack([np.hstack([images[i] for i in range(size)])
                    for i in range(size)])
    plt.imshow(im)
    plt.show()

srcfiles=["train"]
#srcfiles=["test_batch"]
data = [unpickle(f) for f in srcfiles]
images = np.vstack([d["data"] for d in data])
n = len(images)
images = images.reshape(n, 3, 32, 32).transpose(0, 2, 3, 1).astype(float) / 255
display_cifar(images, 10)

srcfiles=["test"]
#srcfiles=["test_batch"]
data = [unpickle(f) for f in srcfiles]
images = np.vstack([d["data"] for d in data])
n = len(images)
images = images.reshape(n, 3, 32, 32).transpose(0, 2, 3, 1).astype(float) / 255
display_cifar(images, 2, True)


# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author   : wangbing
# @File        : DistanceFeature.py
# @Time     : 5/17/2023 2:14 PM
# @Emal     : wangbing587@163.com
# @Desc     :

import pandas as pd
import numpy as np
from sklearn.impute import KNNImputer
from scipy.spatial.distance import pdist
from scipy import stats
from copy import deepcopy
from joblib import Parallel, delayed

def Distance(args):
    p = deepcopy(args[0])
    q = deepcopy(args[1])
    if args[3]:
        p[p <= 0] = 0.001
        q[q <= 0] = 0.001
    return [pdist(np.vstack([p[i], q[i]]), metric=args[2])[0]
            for i in range(q.shape[0])]

def JS(u, v):
    M = (u + v) / 2
    return 0.5*np.sum(u*np.log(u/M))+0.5*np.sum(v*np.log(v/M))

def DistanceCalc(x, y):
    # 直接距离 9
    A1 = [x, y, 'cityblock', False]  # l1 曼哈顿距离
    A2 = [x, y, 'euclidean', False]  # l2 欧几里得距离
    A3 = [x, y, 'cosine', False]  # cosine 余弦距离
    A4 = [x, y, 'correlation', False]  # pcc 皮尔逊相关系数
    A5 = [x, y, 'chebyshev', False]  # max 切比雪夫距离
    A6 = [x, y, 'canberra', False]  # 兰氏距离 （加权曼哈顿凝距离）
    cov = np.cov((x - y).T)
    inv = np.linalg.inv(cov)
    A7 = [x, y, lambda u, v: np.dot(np.dot(u - v, inv), (u - v).T), False]  # 马氏距离
    A8 = [x, y, lambda u, v: np.abs(np.log2(u / v)).sum(), True]  # Sum(LogFC)
    A9 = [x, y, lambda u, v: np.abs(np.log2(u / v)).max(), True]  # =Max(LogFC)

    # 分布距离 5
    B1 = [x, y, lambda u, v: -np.log(np.sum(np.sqrt(u * v))), True]  # BC 巴氏距离
    B2 = [x, y, lambda u, v: np.sqrt(((np.sqrt(u) - np.sqrt(v)) ** 2).sum()), True]  # 海林格距离
    B3 = [x, y, lambda u, v: -np.sum(u * np.log2(v)), True]  # 交叉熵
    B4 = [x, y, lambda u, v: np.sum(u * np.log2(u / v)), True]  # KL
    B5 = [x, y, JS, True]  # JS

    # 排序距离 6
    C1 = [x, y, lambda u, v: stats.wilcoxon(u - v)[1], False]  # 秩和检验
    C2 = [x, y, lambda u, v: stats.spearmanr(u, v)[0], False]  # 斯皮尔
    C3 = [x, y, lambda u, v: stats.kendalltau(u, v)[0], False]  # 肯德尔秩相关
    C4 = [x, y, lambda u, v: (np.argsort(np.argsort(u)) != np.argsort(np.argsort(v))).sum(), False]  # 汉明距离
    C5 = [x, y, lambda u, v: np.abs((np.argsort(np.argsort(u)) - np.argsort(np.argsort(v)))).sum(), False]
    C6 = [x, y, lambda u, v: np.abs((np.argsort(np.argsort(u)) - np.argsort(np.argsort(v)))).max(), False]
    params = [A1, A2, A3, A4, A5, A6, A7, A8, A9, B1, B2, B3, B4, B5, C1, C2, C3, C4, C5, C6]
    return np.array(Parallel(n_jobs=-1)(delayed(Distance)(args) for args in params)).T

def DistanceFeature(data, R):
    data = np.array(data)
    F = int(data.shape[1] / R / 2)
    df_split = [data[:, i * F:(i + 1) * F] for i in range(R * 2)]
    D = np.hstack([DistanceCalc(df_split[i], df_split[i + R]) for i in range(R)])
    return KNNImputer(n_neighbors=3).fit_transform(D)

if __name__ == '__main__':
    pass


import argparse
import matplotlib

matplotlib.use('Agg')

from model_utils import *
from utilities import *
from preprocessIMDB import process_test_data, process_train_data
from preprocessSNLI import process_snli_train_data, process_snli_test_data

parser = argparse.ArgumentParser(description='Eqprop')
parser.add_argument('--dataset', type=str, default='IMDB', metavar='t', help='dataset')

parser.add_argument('--fc_layers', nargs='+', type=int, default=[1000, 40, 2], metavar='A',
                    help='Number of fully connected layers in the network')
parser.add_argument('--seqLen', nargs='+', type=int, default=[600], metavar='A',
                    help='Sequence Length of the data')

parser.add_argument('--act', type=str, default='mysig', metavar='a', help='activation function')
parser.add_argument('--lrs', nargs='+', type=float, default=[], metavar='l', help='layer wise lr (add the lr of projection layers at the beginning then the fc layers')
parser.add_argument('--alg', type=str, default='EP', metavar='al', help='EP or BPTT')
parser.add_argument('--batch_size', type=int, default=20, metavar='M', help='Batch Size')
parser.add_argument('--T', type=int, default=20, metavar='T', help='Time of first phase')
parser.add_argument('--K', type=int, default=4, metavar='K', help='Time of second phase')
parser.add_argument('--thirdphase', default=False, action='store_true', help='for better gradient estimates')
parser.add_argument('--betas', nargs='+', type=float, default=[0.0, 0.01], metavar='Bs', help='Betas')
parser.add_argument('--epochs', type=int, default=1, metavar='EPT', help='Number of epochs per tasks')
parser.add_argument('--check-thm', default=False, action='store_true', help='checking the gdu while training')
parser.add_argument('--lr-decay', default=False, action='store_true', help='enabling learning rate decay')
parser.add_argument('--save', default=False, action='store_true', help='saving results')
parser.add_argument('--execute', type=str, default='train', metavar='tr', help='training or plot gdu curves')
parser.add_argument('--load-path', type=str, default='', metavar='l', help='load a saved model')
parser.add_argument('--seed', type=int, default=None, metavar='s', help='random seed')
parser.add_argument('--device', type=int, default=0, metavar='d', help='device')

args = parser.parse_args()
command_line = ' '.join(sys.argv)
if args.seed is not None:
    torch.manual_seed(args.seed)
device = torch.device('cuda:' + str(args.device) if torch.cuda.is_available() else 'cpu')

if args.save:
    if args.load_path == '':
        path = 'results/' + args.dataset + '/' + datetime.now().strftime('%Y-%m-%d') + '/' + datetime.now().strftime('%H-%M-%S') + '_gpu' + str(args.device)
    else:
        path = args.load_path
    if not (os.path.exists(path)):
        os.makedirs(path)
else:
    path = ''

print('Default dtype :\t', torch.get_default_dtype(), '\n')

if args.dataset == 'IMDB':
    embed_dim = 300
    args.fc_layers = [args.seqLen[0] * embed_dim] + args.fc_layers
    if args.execute == 'train':
        train_loader = process_train_data(args.seqLen[0], batch_size=args.batch_size)
    test_loader = process_test_data(args.seqLen[0], batch_size=args.batch_size)

if args.dataset == 'SNLI':
    embed_dim = 300
    args.fc_layers = [4 * args.seqLen[0] * embed_dim] + args.fc_layers  #There are 4 projection layers for this model as described in the paper
    if args.execute == 'train':
        train_loader = process_snli_train_data(args.seqLen[0], batch_size=args.batch_size)
    test_loader = process_snli_test_data(args.seqLen[0], batch_size=args.batch_size)

if args.act == 'my_sigmoid':
    activation = my_sigmoid
elif args.act == 'sigmoid':
    activation = torch.sigmoid
elif args.act == 'tanh':
    activation = torch.tanh
elif args.act == 'hard_sigmoid':
    activation = hard_sigmoid
elif args.act == 'my_hard_sig':
    activation = my_hard_sig

criterion = torch.nn.MSELoss(reduction='none').to(device)       #loss Function used MSE LOss

if args.load_path == '':
    if args.dataset == 'IMDB':
        model = IMDB_model(args.fc_layers, activation=activation, seqLen=args.seqLen[0])
    if args.dataset == 'SNLI':
        model = P_MLP(args.fc_layers, activation=activation, seqLen=args.seqLen[0])
else:
    model = torch.load(args.load_path + '/model.pt', map_location=device)

model.to(device)
print(model)

betas = args.betas[0], args.betas[1]

if args.execute == 'train':
    assert (len(args.lrs) == len(model.synapses))

    # Constructing the optimizer
    optim_params = []

    for idx in range(len(model.synapses)):
        optim_params.append({'params': model.synapses[idx].parameters(), 'lr': args.lrs[idx]})

    optimizer = torch.optim.Adam(optim_params, eps=1e-8)
    if args.lr_decay:
        scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, 100, eta_min=1e-5)
    else:
        scheduler = None

    checkpoint = None
    print(optimizer)
    print('\ntraining algorithm : ', args.alg, '\n')

    train(model, optimizer, train_loader, test_loader, args.T, args.K, betas, device, args.epochs, criterion,
          alg=args.alg,
          check_thm=args.check_thm, save=args.save, path=path, checkpoint=checkpoint,
          thirdphase=args.thirdphase, scheduler=scheduler)

elif args.execute == 'gducheck':
    print('\ntraining algorithm : ', args.alg, '\n')
    dataiter = iter(test_loader)
    images, labels = dataiter.next()
    images, labels = images[0:20, :], labels[0:20]
    images, labels = images.to(device), labels.to(device)
    BPTT, EP = check_gdu(model, images, labels, args.T, args.K, betas, criterion, alg=args.alg)
    if args.thirdphase:
        beta_1, beta_2 = args.betas
        _, EP_2 = check_gdu(model, images, labels, args.T, args.K, (beta_1, -beta_2), criterion, alg=args.alg)

    RMSE(BPTT, EP)
    if args.save:
        bptt_est = get_estimate(BPTT)
        ep_est = get_estimate(EP)
        if args.thirdphase:
            ep_2_est = get_estimate(EP_2)
            compare_estimate(bptt_est, ep_est, ep_2_est, path)
            plot_gdu(BPTT, EP, path, EP_2=EP_2, alg=args.alg)
        else:
            plot_gdu(BPTT, EP, path, alg=args.alg)

elif args.execute == 'test':
    print('---Testing model---')
    test_acc = test_model(model, test_loader, args.T, device)
    test_acc /= len(test_loader.dataset)
    print('\nTest accuracy :', round(test_acc, 2))


import numpy as np
import cv2 as cv
import os.path
import os
import sys

class fglfw_reader():

    def __init__(self):
        self.data_path = "D:/Database/lfwcrop_color"
        self.list_path = "/lists"
        self.img_path = "/faces"
        self.txt_name = "/pair_FGLFW.txt"

        # 图片属性
        self.img_width = 64
        self.img_height = 64
        self.img_depth = 3

    # 将txt内容存放到列表中
    def parse_txt_to_list(self):
        file_path = self.data_path + self.list_path + self.txt_name
        label = 0
        pair_list = []
        pair = []
        with open(file_path) as f:
            lines = f.readlines()
            for i, line in enumerate(lines):
                # 每三百行标签修改一次
                if i%300 == 0:
                    label = (i//300)%2
                # 每两行组成一个pair
                pair.append(line.strip())
                if (i+1)%2 == 0:
                    # 添加标签
                    pair.append(label)
                    pair_list .append(pair)
                    pair = []
        return pair_list

    def get_pairs(self, ext=".ppm"):
        file_list = self.parse_txt_to_list()
        file_list = self.fix_list_type(file_list, ext)
        file_list = self.reserve_list_filename(file_list)
        return file_list

    def get_full_path_pairs(self):
        file_list = self.get_pairs()
        for each in file_list:
            each[0] = self.data_path + self.img_path  + "/" + each[0]
            each[1] = self.data_path + self.img_path  + "/" + each[1]
        return file_list

    def get_data(self, flatten=False):
        print("loading FGLFW data...")
        img_lst = self.get_full_path_pairs()
        pair_num = len(img_lst)
        if flatten == True:
            x = np.zeros([pair_num, 2, self.img_width*self.img_width*self.img_depth], dtype="float32")
        else:
            x = np.zeros([pair_num, 2, self.img_width, self.img_height, self.img_depth], dtype="float32")
        y = np.zeros([pair_num, 1], dtype="float32")
        for i in range(pair_num):
            img1_path = img_lst[i][0]
            img2_path = img_lst[i][1]
            img1_data = cv.imread(img1_path)
            img2_data = cv.imread(img2_path)
            # if sample_rate != 1:
            #     img1_data = img1_data[::sample_rate, ::sample_rate, ::]
            #     img2_data = img2_data[::sample_rate, ::sample_rate, ::]
            if flatten == True:
                img1_data = img1_data.flatten()
                img2_data = img2_data.flatten()
            x[i, 0] = img1_data
            x[i, 1] = img2_data
            y[i] = img_lst[i][2]
        return x, y

    # 修改FGLFW提供的txt中所有的文件名的后缀
    def fix_list_type(self, file_list, ext):
        # file_list = self.parse_txt_to_list()
        for each in file_list:
            each[0] = self.fix_type(each[0], ext)
            each[1] = self.fix_type(each[1], ext)
        return file_list

    # 去掉FGLFW提供的txt中，所有的文件名的路径，只保留文件名
    def reserve_list_filename(self, file_list):
        # file_list = self.parse_txt_to_list()
        for each in file_list:
            each[0] = self.reserve_filename(each[0])
            each[1] = self.reserve_filename(each[1])
        return file_list

    # 修改文件名的后缀
    def fix_type(self, file_name, ext):
        # 将后缀名与文件名分开
        file_name = os.path.splitext(file_name)[0]
        # 为文件名添加新的后缀名
        file_name = file_name + ext
        return file_name

    # 去掉路径，只保留文件名
    def reserve_filename(self, file_path):
        # 将/前的部分与文件名分开
        file_name = os.path.split(file_path)[-1]
        return file_name

if __name__ == "__main__":
    fr = fglfw_reader()
    # pairs = fr.parse_txt_to_list()
    # for each in pairs:
    #     print(each)
    x, y = fr.get_data()
    print(x.shape)
    print(y.shape)
    input("press enter...")
    # print((int)True)
    # print((int)False)


import os
import json
import torch
import random
import numpy as np
import transformers
from tqdm import trange
from transformers import AutoModelForCausalLM, AutoTokenizer

transformers.logging.set_verbosity_error() # suppress tokenizer warnings

# ------ helper functions
def set_seed(seed):
  if seed is not None:
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)

# ----------
print("Loading Started")
# load up the model and tokenizer
model_str = "gpt2"
model = AutoModelForCausalLM.from_pretrained(model_str)
tok = AutoTokenizer.from_pretrained(model_str)

# define the device and load model there
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
if torch.cuda.device_count() > 1:
  device = torch.device("cuda:0")

model = model.to(device)
model.eval()
print("Total parameters:", sum(dict((p.data_ptr(), p.numel()) for p in model.parameters()).values()))
# ---------

def generate(
  sentence,
  n_steps,
  seed = 4,
  do_sample = True,
  temperature = 0.9,
  top_k = 40,
  top_p=0.95,
  num_beams = 1,
  early_stopping=True,
  num_return_sequences = 10,
):
  data = {k:v.to(model.device) for k,v in tok([sentence], return_tensors = "pt").items()}
  set_seed(seed)
  with torch.no_grad():
    len_ = data["input_ids"].size(-1)
    beam_outputs = model.generate(
        **data,
        do_sample=do_sample,
        max_length=len_ + n_steps,
        temperature=temperature,
        top_k=top_k,
        top_p=top_p,
        early_stopping=early_stopping,
        num_return_sequences=num_return_sequences,
        num_beams=num_beams
    )
  generations = [
    tok.decode(beam_output, skip_special_tokens=True, clean_up_tokenization_spaces=True)
    for beam_output in beam_outputs
  ]
  return generations

def get_sample(question, examples, questions):
  t = f"{question}\n"
  for x in examples:
    t = t + f"{x}\n"
  prompts = []
  for q in questions:
    prompts.append(t + q[:-2])
  return prompts

def run_and_store_result(p, q, gen_config):
  corr = 0
  for x in generate(p, 1, **gen_config):
    pred = x.split("->")[-1].strip()
    target = q.split("->")[-1].strip()
    # print("--------")
    # print("prediction:", pred)
    # print("PP", x)
    # print("QQ:", q)
    # print("target:", target)
    if pred == target:
      corr += 1
  # exit()
  return corr/gen_config["num_return_sequences"]

def one_complete_config(gen_config, ex_idx_list, ex_size = 10):
  # name for this result sheet as well
  name = f"nex={ex_size}_" + "_".join([f"{k}={v}" for k,v in gen_config.items()])
  results = {} # dict with data
  pbar = trange(len(nth_dataset["samples"]))
  for n in pbar:
    pbar.set_description(f"t={n}_{name}")
    this_n_res = []

    idx = ex_idx_list[str((n, ex_size))]  # from predefined list
    train_idx = np.array(idx["train"])
    test_idx = np.array(idx["test"])
    samples = np.array(nth_dataset["samples"][n])

    for qidx in range(N_QUESTIONS):
      question = nth_dataset["questions"][n][qidx]
      prompts = get_sample(
        question=question,
        examples=samples[train_idx],
        questions=samples[test_idx],
      )

      # run results for this config
      res = []
      for i,p in enumerate(prompts):
        res.append(run_and_store_result(p, samples[test_idx][i], gen_config))
      this_n_res.append(res)

    results[n] = this_n_res

  with open(f"./{name}.json", "w") as f:
    f.write(json.dumps(results))

if __name__ == "__main__":
  set_seed(4)

  with open("./nth_letter.json", "r") as f:
    nth_dataset = json.load(f)

  # step 1: load the experiment parameters
  N_TEST_EXAMPLES = 50                # with upto 20 examples and 50 test cases
  N_QUESTIONS = 1                     # only check for 1st question as that is clear enough
  num_beams = [1, 5]                  # number of beams for searching
  tempratures = [0.8, 0.9, 0.95, 1.0] # temprature value
  top_k = [2, 10, 25, 40]             # top_k value in generation
  top_p = [0.8, 0.9, 0.95, 0.99]      # top_p value in generation
  n_examples = [1, 5, 10, 15, 20]     # number of examples for priming

  # step 2: load indices
  if os.path.exists("./ex_idx_list.json"):
    # there is previously stored list of train/test idx
    print("Loading previously stored version of indices")
    with open("./ex_idx_list.json", "r") as f:
      ex_idx_list = json.load(f)
  else:
    # else create a new one
    print("Generating new indices")
    total_n = len(nth_dataset["samples"]) # 10
    ex_idx_list = {}
    for n in range(total_n):
      this_n = nth_dataset["samples"][n]  # 237
      for ex_size in n_examples:
        # take a list, shuffle it and then split first for example and rest for test
        idx = np.arange(len(this_n))
        np.random.shuffle(idx)
        train_idx = idx[:ex_size]
        test_idx = idx[ex_size: ex_size + N_TEST_EXAMPLES]
        ex_idx_list[str((n, ex_size))] = {"train": train_idx.tolist(), "test": test_idx.tolist()}
    with open("./ex_idx_list.json", "w") as f:
      f.write(json.dumps(ex_idx_list))

  # step 3: master loops ---- this program will take a few days to complete
  for nb in num_beams:               # 2x
    for temp in tempratures:         # 4x
      for tk in top_k:               # 4x
        for tp in top_p:             # 4x
          for ex_size in n_examples: # 5x
            # so total multiplier    = 640x
            gen_config={
              "temperature":float(temp),
              "top_k":int(tk),
              "top_p":float(tp),
              "num_beams":int(nb),
              "early_stopping":True,
              "num_return_sequences":10
            }
            one_complete_config(gen_config, ex_idx_list, ex_size)


from odoo import models, fields,api

class Purchase(models.Model):
     _inherit = 'purchase.order'

     # @api.depends('order_line.price_total','product_price')
     # def _amount_all(self):
     #     for order in self:
     #         amount_untaxed = amount_tax = 0.0
     #         for line in order.order_line:
     #             line._compute_amount()
     #             amount_untaxed += line.price_subtotal
     #             amount_tax += line.price_tax
     #         currency = order.currency_id or order.partner_id.property_purchase_currency_id or self.env.company.currency_id
     #         order.update({
     #             'amount_untaxed': currency.round(amount_untaxed),
     #             'amount_tax': currency.round(amount_tax),
     #             'amount_total': amount_untaxed + amount_tax,
     #             'total_amount' : amount_untaxed + amount_tax + order.total_amount
     #         })

     @api.model
     def _get_mrp_productions(self):
         print('>>>>>>>>>>>>>>>>>.')
         res = super(Purchase,self)._get_mrp_productions()
         return res

     @api.depends('order_line.price_total','product_price')
     def _purchase_amount_all(self):
         for order in self:
             amount_untaxed = amount_tax = 0.0
             for line in order.order_line:
                 amount_untaxed += line.price_subtotal
                 amount_tax += line.price_tax
             order.update({
                 'total_amount' : amount_untaxed + amount_tax + order.total_amount
             })

     category = fields.Selection([
         ('fruits', 'Fruits'),
         ('meat&fish', 'Meat & Fish'),
         ('pasta', 'Pasta'),
         ('rice', 'Rice'),
         ('oils', 'Oils'),
         ('soups', 'Soups'),
         ('drinks', 'Drinks'),
         ('vegetables', 'Vegetables')], 'Category'
     )
     product_price = fields.Integer(string="Product Price")
     total_amount = fields.Monetary(compute='_purchase_amount_all' ,string='Total Amount')

class PurchaseLine(models.Model):
    _inherit = 'purchase.order.line'

    product_code = fields.Integer("Product Code")


import numpy as np
import pytest

from cartpole.entities import EpisodeHistory, EpisodeHistoryRecord

# mypy: disable-error-code="no-untyped-def"

def test_blank_history_goal_not_reached():
    history = EpisodeHistory(
        goal_consecutive_episodes=10,
        goal_avg_episode_length=100,
    )
    assert not history.is_goal_reached()

def test_blank_history_permissive_settings_goal_reached():
    history = EpisodeHistory(
        goal_consecutive_episodes=0,
        goal_avg_episode_length=0,
    )
    assert history.is_goal_reached()

def test_goal_reached_when_average_exceeds():
    history = EpisodeHistory(
        goal_consecutive_episodes=10,
        goal_avg_episode_length=100,
    )
    for i, length in enumerate([0, 0, 0, 0, 0, 200, 200, 200, 200]):
        history.record_episode(
            EpisodeHistoryRecord(episode_index=i, episode_length=length, is_successful=False)
        )
    assert history.last_episode_index == 8
    assert not history.is_goal_reached()

    history.record_episode(
        EpisodeHistoryRecord(
            episode_index=9,
            episode_length=200,
            is_successful=False,
        )
    )
    assert history.is_goal_reached()

@pytest.mark.parametrize(
    ["n", "expected"],
    [
        (0, []),
        (1, [100]),
        (5, [15, 18, 12, 10, 100]),
        (10, [10, 15, 18, 12, 10, 100]),
    ],
)
def test_most_recent_lengths(n, expected):
    history = EpisodeHistory()
    for i, length in enumerate([10, 15, 18, 12, 10, 100]):
        history.record_episode(
            EpisodeHistoryRecord(episode_index=i, episode_length=length, is_successful=False)
        )

    actual = history.most_recent_lengths(n)
    assert isinstance(actual, np.ndarray)
    np.testing.assert_array_equal(actual, expected)

@pytest.mark.parametrize(
    ["n", "window_size", "expected"],
    [
        (1, 1, [100]),
        (2, 1, [10, 100]),
        (1, 3, [40.66666]),
        (3, 3, [15, 13.33333, 40.66666]),
        (10, 10, [10, 12.5, 14.33333, 13.75, 13, 27.5]),
    ],
)
def test_most_recent_rolling_mean_lengths(n, window_size, expected):
    history = EpisodeHistory()
    for i, length in enumerate([10, 15, 18, 12, 10, 100]):
        history.record_episode(
            EpisodeHistoryRecord(episode_index=i, episode_length=length, is_successful=False)
        )

    actual = history.most_recent_rolling_mean_lengths(n, window_size=window_size)
    assert isinstance(actual, np.ndarray)
    np.testing.assert_almost_equal(actual, expected, decimal=3)