try:
    from typing import Literal
except ImportError:
    from typing_extensions import Literal

from typing import List, Optional, Union

import numpy as np
from anndata import AnnData
from pyvista import PolyData

from spateo.tdr import (
    add_model_labels,
    center_to_zero,
    collect_models,
    construct_pc,
    merge_models,
    translate_model,
)

from .three_dims_plots import three_d_multi_plot

def _check_cpos_in_multi_plot(
    models: List,
    window_size: Optional[tuple] = None,
    cpo: Union[str, list] = "xy",
):
    cpos, cpos_size = [], []
    for model in models:
        _window_size = (512, 512) if window_size is None else window_size
        _cpo = model.plot(
            cpos=cpo,
            jupyter_backend="none",
            return_cpos=True,
            off_screen=True,
            window_size=_window_size,
        )
        cpos.append(_cpo)
        cpos_size.append(_cpo[0][2])
    cpo_index = np.argmax(np.asarray(cpos_size))
    cpo = cpos[cpo_index]
    return cpo

def multi_models(
    *adata: AnnData,
    layer: str = "X",
    group_key: Union[str, list] = None,
    spatial_key: str = "align_spatial",
    id_key: str = "slices",
    mode: Literal["single", "overlap", "both"] = "single",
    center_zero: bool = False,
    filename: Optional[str] = None,
    jupyter: Union[bool, Literal["none", "static", "trame"]] = False,
    off_screen: bool = False,
    cpo: Union[str, list] = "xy",
    shape: Union[str, list, tuple] = None,
    window_size: Optional[tuple] = None,
    background: str = "white",
    colormap: Union[str, list, dict] = "red",
    overlap_cmap: Union[str, list, dict] = "dodgerblue",
    alphamap: Union[float, list, dict] = 1.0,
    overlap_amap: Union[float, list, dict] = 0.5,
    ambient: Union[float, list] = 0.2,
    opacity: Union[float, np.ndarray, list] = 1.0,
    model_size: Union[float, list] = 3.0,
    show_axes: bool = True,
    show_legend: bool = True,
    legend_kwargs: Optional[dict] = None,
    text: Union[bool, str] = True,
    text_kwargs: Optional[dict] = None,
    **kwargs,
):
    """
    Visualize multiple models separately in one figure.

    Args:
        *adata: A list of models[Anndata object].
        layer: If ``'X'``, uses ``.X``, otherwise uses the representation given by ``.layers[layer]``.
        group_key: The key that stores clustering or annotation information in ``.obs``, a gene name or a list of gene names in ``.var``.
        spatial_key: The key in ``.obsm`` that corresponds to the spatial coordinate of each bucket.
        id_key: The key in ``.obs`` that corresponds to the model id of each bucket.
        mode: Three modes of visualization.  Available ``mode`` are:

                * ``'single'`` - Visualize each model individually.
                * ``'overlap'`` - Simultaneously visualize two models aligned front to back in one subplot.
                * ``'both'`` - Simultaneously visualize both types above.
        center_zero: Whether to move the center point of the model to the (0, 0, 0).
        filename:  Filename of output file. Writer type is inferred from the extension of the filename.

                * Output an image file,please enter a filename ending with
                  ``'.png', '.tif', '.tiff', '.bmp', '.jpeg', '.jpg', '.svg', '.eps', '.ps', '.pdf', '.tex'``.
                  When ``jupyter=False``, if you want to save '.png' file, please ensure ``off_screen=True``.
        jupyter: Whether to plot in jupyter notebook. Available ``jupyter`` are:

                * ``'none'`` - Do not display in the notebook.
                * ``'trame'`` - Show a trame widget
                * ``'static'`` - Display a static figure.
        off_screen: Renders off-screen when True. Useful for automated screenshots.
        cpo: Camera position of the active render window. Available ``cpo`` are:

                * Iterable containing position, focal_point, and view up.
                    ``E.g.: [(2.0, 5.0, 13.0), (0.0, 0.0, 0.0), (-0.7, -0.5, 0.3)].``
                * Iterable containing a view vector.
                    ``E.g.: [-1.0, 2.0, -5.0].``
                * A string containing the plane orthogonal to the view direction.
                    ``E.g.: 'xy', 'xz', 'yz', 'yx', 'zx', 'zy', 'iso'.``
        shape: Number of sub-render windows inside the main window. By default, there is only one render window.

               * Specify two across with ``shape``=(2, 1) and a two by two grid with ``shape``=(2, 2).
               * ``shape`` Can also accept a string descriptor as shape.

                    ``E.g.: shape="3|1" means 3 plots on the left and 1 on the right,``
                    ``E.g.: shape="4/2" means 4 plots on top and 2 at the bottom.``
        window_size: Window size in pixels. The default window_size is ``[512, 512]``.
        background: The background color of the window.
        colormap: Colors to use for plotting pc. The default colormap is ``'dodgerblue'``.
        overlap_cmap: Colors to use for plotting overlapped pc. The default colormap is ``'red'``.
        alphamap: The opacity of the colors to use for plotting pc. The default alphamap is ``1.0``.
        overlap_amap: The opacity of the colors to use for plotting overlapped pc. The default alphamap is ``.5``.
        ambient: When lighting is enabled, this is the amount of light in the range of 0 to 1 (default 0.0) that reaches
                 the actor when not directed at the light source emitted from the viewer.
        opacity: Opacity of the model.

                 If a single float value is given, it will be the global opacity of the model and uniformly applied
                 everywhere, elif a numpy.ndarray with single float values is given, it
                 will be the opacity of each point. - should be between 0 and 1.

                 A string can also be specified to map the scalars range to a predefined opacity transfer function
                 (options include: 'linear', 'linear_r', 'geom', 'geom_r').
        model_size: The point size of any nodes in the dataset plotted.
        show_axes: Whether to add a camera orientation widget to the active renderer.
        show_legend: whether to add a legend to the plotter.
        legend_kwargs: A dictionary that will be pass to the ``add_legend`` function.

                       By default, it is an empty dictionary and the ``add_legend`` function will use the
                       ``{"legend_size": None, "legend_loc": None,  "legend_size": None, "legend_loc": None,
                       "title_font_size": None, "label_font_size": None, "font_family": "arial", "fmt": "%.2e",
                       "n_labels": 5, "vertical": True}`` as its parameters. Otherwise, you can provide a dictionary
                       that properly modify those keys according to your needs.
        text: The text to add the rendering.
        text_kwargs: A dictionary that will be pass to the ``add_text`` function.

                     By default, it is an empty dictionary and the ``add_legend`` function will use the
                     ``{ "font_family": "arial", "font_size": 12, "font_color": "black", "text_loc": "upper_left"}``
                     as its parameters. Otherwise, you can provide a dictionary that properly modify those keys
                     according to your needs.
        **kwargs: Additional parameters that will be passed to ``three_d_multi_plot`` function.
    """
    adata_list = adata[0]
    adata_list = adata_list if isinstance(adata_list, list) else [adata_list]

    # Construct a point cloud model
    pcs, ids, keys, cmaps = [], [], [], []
    for i, adata in enumerate(adata_list):
        adata = adata.copy()
        adata_id = str(adata.obs[id_key].unique().tolist()[0])
        group_key = id_key if group_key is None else group_key

        if adata.obsm[spatial_key].shape[1] == 2:
            z = np.zeros(shape=(adata.obsm[spatial_key].shape[0], 1))
            adata.obsm[spatial_key] = np.c_[adata.obsm[spatial_key], z]

        pc, plot_cmap = construct_pc(
            adata=adata.copy(),
            layer=layer,
            spatial_key=spatial_key,
            groupby=group_key,
            key_added=f"{adata_id}-{group_key}",
            colormap=colormap,
            alphamap=alphamap,
        )
        if center_zero is True:
            center_to_zero(model=pc, inplace=True)
        ids.append(adata_id)
        pcs.append(pc)
        keys.append(f"{adata_id}-{group_key}")
        cmaps.append(plot_cmap)

    # Check the shared cpo again
    cpo = _check_cpos_in_multi_plot(models=pcs, window_size=window_size, cpo=cpo)

    # Visualization.
    if mode == "single":
        three_d_multi_plot(
            model=collect_models(pcs),
            key=keys,
            filename=filename,
            jupyter=jupyter,
            off_screen=off_screen,
            shape=shape,
            window_size=window_size,
            background=background,
            ambient=ambient,
            opacity=opacity,
            colormap=cmaps,
            cpo=[cpo],
            model_style=["points"],
            model_size=[model_size],
            show_axes=show_axes,
            show_legend=show_legend,
            legend_kwargs=legend_kwargs,
            text=[f"\nModel id: {id}" for id in ids] if text is True else text,
            text_kwargs=text_kwargs,
            **kwargs,
        )
    elif mode in ["overlap", "both"]:
        overlap_pcs, overlap_ids, overlap_keys, overlap_cmaps = [], [], [], []
        for i in range(len(pcs) - 1):
            pc1, pc2 = pcs[i].copy(), pcs[i + 1].copy()
            npc1, opc1_1 = add_model_labels(
                model=pc1.copy(),
                labels=np.asarray(pc1.point_data[keys[i]]),
                key_added=f"overlap-{keys[i]}-{keys[i + 1]}",
                where="point_data",
                colormap=overlap_cmap,
                alphamap=overlap_amap,
                inplace=False,
            )
            _, opc1_2 = add_model_labels(
                model=npc1,
                labels=np.asarray(pc1.point_data[keys[i]]),
                key_added=f"overlap-{keys[i]}",
                where="point_data",
                colormap=overlap_cmap,
                alphamap=overlap_amap,
                inplace=True,
            )

            npc2, opc2_1 = add_model_labels(
                model=pc2.copy(),
                labels=np.asarray(pc2.point_data[keys[i + 1]]),
                key_added=f"overlap-{keys[i]}-{keys[i + 1]}",
                where="point_data",
                colormap=colormap,
                alphamap=alphamap,
                inplace=False,
            )
            _, opc2_2 = add_model_labels(
                model=npc2,
                labels=np.asarray(npc2.point_data[keys[i + 1]]),
                key_added=f"overlap-{keys[i + 1]}",
                where="point_data",
                colormap=colormap,
                alphamap=alphamap,
                inplace=True,
            )
            overlap_pc = merge_models([npc1, npc2])
            if not (cmaps[i] is None):
                overlap_pc = merge_models([npc1, npc2])
                _, plot_cmap = add_model_labels(
                    model=overlap_pc,
                    labels=np.asarray(overlap_pc.point_data[f"overlap-{keys[i]}-{keys[i + 1]}"]),
                    key_added=f"overlap-{keys[i]}-{keys[i + 1]}",
                    where="point_data",
                    colormap=colormap,
                    inplace=True,
                )
            else:
                plot_cmap = None

            if mode == "overlap":
                overlap_pcs.append(overlap_pc)
                overlap_ids.append(f"{ids[i]} & {ids[i + 1]}")
                overlap_keys.append(f"overlap-{keys[i]}-{keys[i + 1]}")
                overlap_cmaps.append(plot_cmap)
            elif mode == "both":
                overlap_pcs.extend([npc1, npc2, overlap_pc])
                overlap_ids.extend([ids[i], ids[i + 1], f"{ids[i]} & {ids[i + 1]}"])
                overlap_keys.extend(
                    [
                        f"overlap-{keys[i]}",
                        f"overlap-{keys[i + 1]}",
                        f"overlap-{keys[i]}-{keys[i + 1]}",
                    ]
                )
                overlap_cmaps.extend([opc1_2, opc2_2, plot_cmap])

        three_d_multi_plot(
            model=collect_models(overlap_pcs),
            key=overlap_keys,
            filename=filename,
            jupyter=jupyter,
            off_screen=off_screen,
            shape=shape,
            window_size=window_size,
            background=background,
            ambient=ambient,
            opacity=opacity,
            colormap=overlap_cmaps,
            cpo=[cpo],
            model_style=["points"],
            model_size=[model_size],
            show_axes=show_axes,
            show_legend=show_legend,
            legend_kwargs=legend_kwargs,
            text=[f"\nModel id: {id}" for id in overlap_ids] if text is True else text,
            text_kwargs=text_kwargs,
            **kwargs,
        )

def deformation(
    *adata: AnnData,
    deformed_grid: Union[PolyData, List[PolyData]],
    layer: str = "X",
    group_key: Union[str, list] = None,
    spatial_key: str = "align_spatial",
    id_key: str = "slices",
    deformation_key: Optional[str] = "deformation",
    center_zero: bool = False,
    show_model: bool = True,
    filename: Optional[str] = None,
    jupyter: Union[bool, Literal["none", "static", "trame"]] = False,
    off_screen: bool = False,
    cpo: Union[str, list] = "xy",
    shape: Union[str, list, tuple] = None,
    window_size: Optional[tuple] = (1024, 756),
    background: str = "white",
    model_color: Union[str, list] = "red",
    model_alpha: Union[float, list, dict] = 1,
    colormap: Union[str, list, dict] = "black",
    alphamap: Union[float, list, dict] = 1.0,
    ambient: Union[float, list] = 0.2,
    opacity: Union[float, np.ndarray, list] = 1.0,
    grid_size: Union[float, list] = 2.0,
    model_size: Union[float, list] = 3.0,
    show_axes: bool = True,
    show_legend: bool = False,
    legend_kwargs: Optional[dict] = None,
    text: Union[bool, str] = True,
    text_kwargs: Optional[dict] = None,
    **kwargs,
):
    adata_list = adata[0]
    adata_list = adata_list if isinstance(adata_list, list) else [adata_list]

    grid_list = deformed_grid if isinstance(deformed_grid, list) else [deformed_grid]
    assert len(adata_list) == len(
        grid_list
    ), "The number of Anndata objects is not equal to the number of deformed grids."

    # Construct a point cloud model
    plot_models, ids, keys, cmaps = [], [], [], []
    for adata, grid in zip(adata_list, grid_list):
        adata, raw_grid = adata.copy(), grid.copy()
        adata_id = str(adata.obs[id_key].unique().tolist()[0])
        group_key = id_key if group_key is None else group_key

        if deformation_key is None:
            labels = np.asarray(grid.n_points * [f"{adata_id}-deformed grid"])
        else:
            labels = np.asarray(grid.point_data[deformation_key])
        _, plot_grid_cmap = add_model_labels(
            model=grid,
            labels=labels,
            key_added=f"{adata_id}-{group_key}",
            where="point_data",
            colormap=colormap,
            alphamap=alphamap,
            inplace=True,
        )
        if center_zero is True:
            center_to_zero(model=grid, inplace=True)

        if show_model:
            if adata.obsm[spatial_key].shape[1] == 2:
                z = np.zeros(shape=(adata.obsm[spatial_key].shape[0], 1))
                adata.obsm[spatial_key] = np.c_[adata.obsm[spatial_key], z]
            pc, plot_pc_cmap = construct_pc(
                adata=adata.copy(),
                layer=layer,
                spatial_key=spatial_key,
                groupby=group_key,
                key_added=f"{adata_id}-{group_key}",
                colormap=model_color,
                alphamap=model_alpha,
            )
            if center_zero is True:
                translate_distance = (
                    -raw_grid.center[0],
                    -raw_grid.center[1],
                    -raw_grid.center[2],
                )
                translate_model(model=pc, distance=translate_distance, inplace=True)
            plot_model = collect_models([pc, grid])
        else:
            plot_model = grid.copy()

        ids.append(adata_id)
        plot_models.append(plot_model)
        keys.append(f"{adata_id}-{group_key}")
        cmaps.append([plot_pc_cmap, plot_grid_cmap] if show_model else plot_grid_cmap)

    # Check the shared cpo again
    cpo = _check_cpos_in_multi_plot(models=grid_list, window_size=window_size, cpo=cpo)

    # Visualization.
    three_d_multi_plot(
        model=collect_models(plot_models),
        key=keys,
        filename=filename,
        jupyter=jupyter,
        off_screen=off_screen,
        shape=shape,
        window_size=window_size,
        background=background,
        ambient=ambient,
        opacity=opacity,
        colormap=cmaps,
        cpo=[cpo],
        model_style=[["points", "wireframe"]] if show_model else ["wireframe"],
        model_size=[[model_size, grid_size]] if show_model else [grid_size],
        show_axes=show_axes,
        show_legend=show_legend,
        legend_kwargs=legend_kwargs,
        text=[f"\nModel id: {id}" for id in ids] if text is True else text,
        text_kwargs=text_kwargs,
        **kwargs,
    )


#coding:utf-8
import os, config
from sklearn.datasets import load_svmlight_file
from sklearn import svm, tree
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier

#抽象类 所有的分类器都以此类为父类进行派生
class Strategy(object):
    def train_model(self, train_file_path, model_path):
        return None
    def test_model(self, test_file_path, model_path, result_file_path):
        return None

#主分类器 用于调用各个分类器
class Classifier(object):
    def __init__(self, strategy):
        self.strategy = strategy

    def train_model(self, train_file_path, model_path):
        self.strategy.train_model(train_file_path, model_path)

    def test_model(self, test_file_path, model_path, result_file_path):
        self.strategy.test_model(test_file_path, model_path, result_file_path)

''' skLearn '''
'''
每个模型都有两个类成员和两个成员函数
trainer : 分类器名称,在主函数运行时用于打印提示字符
clf     : 即classifier,分类器对象
train_model : 训练模型函数
test_model:   测试模型函数
所有分类器的函数流程大同小异
在这里做统一解释:
train_model:
(1)通过load_svmlight_file加载特征文件
(2)调用sklearn的库进行模型训练

test_model:
(1)通过load_svmlight_file加载特征文件
(2)调用sklearn的库进行模型预测
(3)将预测结果写入结果文件当中
'''
#模型1: 决策树
class skLearn_DecisionTree(Strategy):
    def __init__(self):
        self.trainer = "skLearn decisionTree"
        self.clf = tree.DecisionTreeClassifier()
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型2: 朴素贝叶斯
class skLearn_NaiveBayes(Strategy):
    def __init__(self):
        self.trainer = "skLearn NaiveBayes"
        self.clf = GaussianNB()
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        train_X = train_X.toarray()
        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        test_X = test_X.toarray()
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型3: 支持向量机
class skLearn_svm(Strategy):
    def __init__(self):
        self.trainer = "skLearn svm"
        self.clf = svm.LinearSVC()
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型4: 逻辑回归
class skLearn_lr(Strategy):
    def __init__(self):
        self.trainer = "skLearn LogisticRegression"
        self.clf = LogisticRegression()
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型5: k近邻算法(default k = 3)
class skLearn_KNN(Strategy):
    def __init__(self):
        self.trainer = "skLearn KNN"
        self.clf = KNeighborsClassifier(n_neighbors=10)
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型6: 集成学习
class skLearn_AdaBoostClassifier(Strategy):
    def __init__(self):
        self.trainer = "skLearn AdaBoostClassifier"
        self.clf = AdaBoostClassifier()
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型7: 随机森林分类
class sklearn_RandomForestClassifier(Strategy):
    def __init__(self):
        self.trainer = "skLearn RandomForestClassifier"
        self.clf = RandomForestClassifier()
        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

#模型8: 投票分类(hard—少数服从多数)
class sklearn_VotingClassifier(Strategy):
    def __init__(self):
        self.trainer = "skLearn VotingClassifier"

        clf1 = tree.DecisionTreeClassifier()
        clf2 = GaussianNB()
        clf3 = LogisticRegression()
        clf4 = svm.LinearSVC()
        clf5 = KNeighborsClassifier(n_neighbors=3)
        clf6 = AdaBoostClassifier()
        clf7 = RandomForestClassifier()
        self.clf = VotingClassifier(estimators=[('dtc',clf1), ('lr', clf3), ('svm', clf4), ('knc',clf5), ('ada', clf6), ('rfc',clf7)], voting='hard')

        print("Using %s Classifier" % (self.trainer))

    def train_model(self, train_file_path, model_path):
        train_X, train_y = load_svmlight_file(train_file_path)

        print("==> Train the model ...")
        self.clf.fit(train_X, train_y)

    def test_model(self, test_file_path, model_path, result_file_path):

        print("==> Test the model ...")
        test_X, test_y = load_svmlight_file(test_file_path)
        pred_y = self.clf.predict(test_X)

        # write prediction to file
        with open(result_file_path, 'w') as fout:
            fout.write("\n".join(map(str, map(int, pred_y))))

if __name__ == "__main__":
    pass


from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User

class RemoteUserBackend(ModelBackend):
    """
    This backend is to be used in conjunction with the ``RemoteUserMiddleware``
    found in the middleware module of this package, and is used when the server
    is handling authentication outside of Django.

    By default, the ``authenticate`` method creates ``User`` objects for
    usernames that don't already exist in the database.  Subclasses can disable
    this behavior by setting the ``create_unknown_user`` attribute to
    ``False``.
    """

    # Create a User object if not already in the database?
    create_unknown_user = True

    def authenticate(self, remote_user):
        """
        The username passed as ``remote_user`` is considered trusted.  This
        method simply returns the ``User`` object with the given username,
        creating a new ``User`` object if ``create_unknown_user`` is ``True``.

        Returns None if ``create_unknown_user`` is ``False`` and a ``User``
        object with the given username is not found in the database.
        """
        if not remote_user:
            return
        user = None
        username = self.clean_username(remote_user)

        # Note that this could be accomplished in one try-except clause, but
        # instead we use get_or_create when creating unknown users since it has
        # built-in safeguards for multiple threads.
        if self.create_unknown_user:
            user, created = User.objects.get_or_create(username=username)
            if created:
                user = self.configure_user(user)
        else:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                pass
        return user

    def clean_username(self, username):
        """
        Performs any cleaning on the "username" prior to using it to get or
        create the user object.  Returns the cleaned username.

        By default, returns the username unchanged.
        """
        return username

    def configure_user(self, user):
        """
        Configures a user after creation and returns the updated user.

        By default, returns the user unmodified.
        """
        return user


import sqlite3
from urllib.request import urlopen as uReq
import random
from bs4 import BeautifulSoup as soup

myurl = "https://books.toscrape.com/catalogue/"
def scrape():
    for i in range(1,50):
        uClient = uReq(myurl+"page-"+str(i)+".html")
        page_html = uClient.read()
        uClient.close()
        page_soup = soup(page_html, "html.parser")
        bookshelf = page_soup.findAll("li", {"class": "col-xs-6 col-sm-4 col-md-3 col-lg-3"})
        for books in bookshelf:
            book_title = books.h3.a["title"]
            book_price = books.findAll("p", {"class": "price_color"})
            price = book_price[0].text.strip()
            price1=price.replace("£", "")
            insert_book(book_title, price1)

def insert_book(Title, Price):
    query = "INSERT INTO Books(Title, Price) " "VALUES(?, ?)"
    args = (Title, Price)
    try:
        con = sqlite3.connect("databas.db")
        cur = con.cursor()
        cur.execute(query, args)
        if cur.lastrowid:
            print("last inserted id", cur.lastrowid)
        else:
            print("last inserted id not found")
        con.commit()
    except sqlite3.Error as error:
        print(error)

#below code connects to database and selects the ID from books table
#and fetch all of the id to then use to create a random int for amount
def create_random_amount_db():
    con3 = sqlite3.connect("databas.db")
    cur3 = con3.cursor()
    ID = "SELECT ID FROM books"
    cur3.execute(ID)
    records = cur3.fetchall()
    for row in records:
        rands = random.randint(1,30)
        queries2 = f"UPDATE books SET Amount = {rands} WHERE ID = {row[0]}"
        cur3.execute(queries2)
    con3.commit()

def main():
    create_random_amount_db()
    #scrape()
    #insert_book("temp", "£20")
if __name__ == "__main__":
    main()


import argparse
import torch
import torch.optim as  optim
from torchvision.utils import save_image
from utils import prepare_MNIST
import torch.nn.functional as F
import os
import time
import math
import random
import pickle
from encoder import *
import shutil
from torch.utils.data import DataLoader
import numpy as np
import matplotlib.pyplot as plt
from torch.distributions.kl import kl_divergence
from torch.distributions.normal import Normal
import time
from dataset import Dataset
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

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

parser = argparse.ArgumentParser(description='Convolutional VAE MNIST Example')
parser.add_argument('--result_dir', type=str, default='./result', metavar='DIR',
					help='output directory')
parser.add_argument('--save_dir', type=str, default='./mydata', metavar='DIR',
					help='model saving directory')
parser.add_argument('--batch_size', type=int, default=128, metavar='N',
					help='input batch size for training (default: 128)')
parser.add_argument('--epochs', type=int, default=20, metavar='N',
					help='number of epochs to train (default: 10)')
parser.add_argument('--seed', type=int, default=1, metavar='S',
					help='random seed (default: 1)')
parser.add_argument('--model', default='./model/ooo/epoch_19.pt', type=str, metavar='PATH',
					help='path to latest checkpoint (default: None')
parser.add_argument('--test_every', default=5, type=int, metavar='N',
					help='test after every epochs')
parser.add_argument('--num_worker', type=int, default=2, metavar='N',
					help='num_worker')
parser.add_argument('--data_dir', type=str, default='./mydata/', metavar='DIR',
					help='data directory')

# model options
parser.add_argument('--lr', type=float, default=1e-4,
					help='learning rate')
parser.add_argument('--line_dim', type=int, default=25, metavar='N',
					help='attribute vector size of encoder')
parser.add_argument('--input_dim', type=int, default=28 * 28, metavar='N',
					help='input dimension (28*28 for MNIST)')
parser.add_argument('--input_channel', type=int, default=1, metavar='N',
					help='input channel (1 for MNIST)')

args = parser.parse_args()
kwargs = {'num_workers': 2, 'pin_memory': True} if cuda else {}
def load_data(image_data,start_data,number_data,lebal_data,thick_data,segment_data, batch_size):
    data_loader = None
    if number_data != '':
        image = pickle.load(open(image_data,'rb'))
        number = pickle.load(open(number_data, 'rb'))
        lebal = pickle.load(open(lebal_data, 'rb'))
        data = Dataset(image ,number,lebal)
        data_loader = DataLoader(data, batch_size=batch_size, shuffle = False)
    return data_loader

def filter(images,positions,sums):
    rate = 0.0
    lists = [0,0,0,0,0,0,0,0,0,0]
    sources, lines = [], []
    for i in range(len(images)):
        threshold = 2
        position = np.round( positions[i] ).astype(int)
        pos = (position[0],position[1])
        image = images[i][0].cpu().numpy()
        value = image[pos]
        valid = ( value < 0.25) * 1
        invalid = np.sum(valid)
        index = sums[i].int()
        if index == 8 or index == 9 : threshold = 3
        if index == 1 : threshold = 1
        if invalid >= threshold:
            rate += 1
            lists[index] += 1
            continue
        sources.append(image)
        lines.append(positions[i])

    rate = rate / len(images)
    print("rate is :",rate)

    print("got filter :",len(sources))

    return sources, lines

def get_more_sample(sources,lines):
    lens = len(sources)
    images = []
    new_lines = []
    test = [0,0,0,0]
    for i in range(lens):
        image = sources[i]

        pos  = np.nonzero(image)
        pos = list(pos)

        images.append(sources[i])
        new_lines.append(lines[i])

        right_up , right_down , left_up , left_down = 0,0,0,0

        x_min = np.min(pos[1])
        x_max = 27 - np.max(pos[1])
        y_min = np.min(pos[0])
        y_max = 27 - np.max(pos[0])

        right_up = min( y_min, x_max )
        right_down = min( x_max , y_max )
        left_down = min ( x_min , y_max )
        left_up =  min ( x_min , y_min )

        ll = random.sample(range(0,4),2)
        for index in ll:
            if index == 0 and right_up >=2 :
                test[0]+=1
                add_new = image[ 2: , :26 ]
                add_new = np.pad(add_new,((0,2),(2,0)),'constant', constant_values=(0,0))
                line = lines[i].copy()
                line[1]+=2
                line[0]-=2

                images.append( add_new )
                new_lines.append( line )
                continue

            if index == 1 and right_down >=2:
                test[1]+=1
                add_new = image[ :26 , :26 ]
                add_new = np.pad(add_new,((2,0),(2,0)),'constant', constant_values=(0,0))
                line = lines[i].copy()
                line[1]+=2
                line[0]+=2

                images.append( add_new )
                new_lines.append( line )
                continue

            if index == 2 and left_down >=2:
                test[2]+=1
                add_new = image[ :26 , 2: ]
                add_new = np.pad(add_new,((2,0),(0,2)),'constant', constant_values=(0,0))
                line = lines[i].copy()
                line[1]-=2
                line[0]+=2

                images.append( add_new )
                new_lines.append( line )
                continue

            if index == 3 and left_up >=2:
                test[3]+=1
                add_new = image[ 2: , 2: ]
                add_new = np.pad(add_new,((0,2),(0,2)),'constant', constant_values=(0,0))
                line = lines[i].copy()
                line[1]-=2
                line[0]-=2

                images.append( add_new )
                new_lines.append( line )

    print(test)
    return images, new_lines

def get_thickness( images , positions):
    lists = []
    for j in range(len(images)):
        position = np.round( positions[j] ).astype(int)
        image = images[j]
        thicks= np.array([])

        for i in range(len(position[0])) :
            y = position[0,i]
            x = position[1,i]
            slash_pos =min([x,y])
            slash_pos2 =min ([27-x,y])
            left, right,up,down,upleft,downleft,upright,downright = 0,0,0,0,0,0,0,0

            right = image[y , x:].argmin(axis = 0)
            left = image[y , x::-1].argmin(axis = 0)
            horizontal = right + left -1

            up = image  [y::-1 , x].argmin(axis = 0)
            down = image[y:, x].argmin(axis = 0)
            vertical = up + down -1

            upleft = image.diagonal(x-y)[slash_pos::-1].argmin(axis = 0)
            downright = image.diagonal(x-y)[slash_pos:].argmin(axis = 0)
            diagonal = upleft + downright

            upright = np.fliplr(image).diagonal(27-x-y)[slash_pos2::-1].argmin(axis = 0)
            downleft = np.fliplr(image).diagonal(27-x-y)[slash_pos2:].argmin(axis = 0)
            back_diagonal = upright + downleft
            data =np.array([horizontal,vertical,diagonal,back_diagonal])
            thick = np.min(data)
            thicks = np.append(thicks,thick)
        pos_thick = np.vstack((positions[j],thicks))
        lists.append(pos_thick)

    return lists

def train():
    model = ConvEncoder(input_channels=args.input_channel, x_dim= line_dim , y_dim = line_dim ).cuda()
    model.load_state_dict(torch.load(args.model))
    model.cuda()
    optimizer = optim.Adam(model.parameters(), lr=args.lr)
    start_epoch = 0
    if not os.path.exists(args.result_dir):
        os.makedirs(args.result_dir)

    data_loader = load_data( args.data_dir + 'all_image.pickle',
                             args.data_dir + 'all_start.pickle',
                             args.data_dir + 'all_data.pickle',
                             args.data_dir +'all_sum.pickle',
                             args.data_dir +'all_thick.pickle',
                             args.data_dir +'all_segment.pickle',
                             args.batch_size )

    positions, sources  ,digit= [],[],[]
    with torch.no_grad():
        for i, data in enumerate(data_loader):
            inputs = data[0]
            inputer = inputs.clone()
            inputer[:,0:2,0:2] =0 ; inputer[:,0:2,26:] = 0 ; inputer[:,26:,0:2] = 0 ; inputer[:,26:,26:] = 0

            images = data[1]
            sums = data[2]
            inputs = inputs.unsqueeze(1)

            model.cuda()
            x_line,y_line = model(inputs)
            x_line = x_line.cpu().detach().numpy()
            y_line = y_line.cpu().detach().numpy()

            for j in range(len(images)):
                x = x_line[j]
                y = y_line[j]
                pos = np.stack((y, x))
                positions.append(pos)
                sources.append(images[j])
                digit.append(sums[j])

        print('len of positions is :',len(positions))
        print('len of images is :',len(sources))

        sources, lines = filter(sources,positions,digit)
        pos_thick = get_thickness( sources , lines)
        print('got thickness')
        new_images , new_lines =  get_more_sample(sources,pos_thick)
        print('added sample:',len(new_images))

        if not os.path.exists(args.save_dir):
            os.makedirs(args.save_dir)
        pickle.dump(new_images,open(args.save_dir+'/processed_sources.pickle', 'wb'))
        pickle.dump(new_lines,open(args.save_dir+'/processed_inputs.pickle', 'wb'))
        print("data saved")

if __name__ == '__main__':
    sample_num = 20
    resolution = 1.5
    test_num = 15

    dis_para = 10
    std_para = 100
    line_dim = args.line_dim
    if torch.cuda.is_available():
        print('Using: ', torch.cuda.get_device_name(torch.cuda.current_device()))
    else:
        print('CPU mode')
    train()


import requests

from core.http_config import HTTPConfig, HTTP_POST, HTTP_GET, HTTP_PUT, HTTP_DELETE

class HTTPConnection:
    http_config = None

    def __init__(self, config: HTTPConfig = None):
        if not HTTPConfig:
            raise ValueError("Config required")

        self.http_config = config

    def execute(self, *, data: None) -> requests.Response:
        """

        :param data: JSON encoded payload
        :return:
        """
        params = {"url": self.http_config.url, "headers": self.http_config.headers}

        if data:
            params["data"] = data

        if self.http_config.method == HTTP_POST:
            response = requests.post(**params)

        elif self.http_config.method == HTTP_GET:
            response = requests.get(**params)
        elif self.http_config.method == HTTP_PUT:
            response = requests.put(**params)
        elif self.http_config.method == HTTP_DELETE:
            response = requests.delete(**params)

        else:
            raise ValueError("Method not implemented!")

        return response


import unittest
from shellutils import run_shell_cmd, ShellCmdException
import config

import pexpect
import sys, os, signal, time

class Test00PyCompilable(unittest.TestCase):
    ''' Verifies that all Python files are syntactically correct '''
    def test_compile_file(self):
        try:
            run_shell_cmd("find . -name *py -type f -print0 | xargs -0 -n1 -P20 python -m py_compile", config.TESTDIR)
        except ShellCmdException as exc:
            self.fail("Error compiling python files: %s" % (exc))

    def test_pylint_file(self):
        try:
            run_shell_cmd(r"find . -iname \"*\.py\" -type f -print0 | PYTHONPATH=${PYTHONPATH}:. xargs -r -0 -n1 pylint --load-plugins pylint_django -E --reports=n 2>&1", cwd=config.TESTDIR + "/bitbake/lib/toaster")
        except ShellCmdException as exc:
            self.fail("Pylint fails: %s\n" % exc)

class Test01PySystemStart(unittest.TestCase):
    ''' Attempts to start Toaster, verify that it is succesfull, and stop it '''
    def setUp(self):
        run_shell_cmd("bash -c 'rm -f build/*log'")

    def test_start_interactive_mode(self):
        try:
            run_shell_cmd("bash -c 'source %s/oe-init-build-env && source toaster start webport=%d && source toaster stop'" % (config.TESTDIR, config.TOASTER_PORT), config.TESTDIR)
        except ShellCmdException as exc:
            self.fail("Failed starting interactive mode: %s" % (exc))

    def test_start_managed_mode(self):
        try:
            run_shell_cmd("%s/bitbake/bin/toaster webport=%d nobrowser & sleep 10 && curl http://localhost:%d/ && kill -2 %%1" % (config.TESTDIR, config.TOASTER_PORT, config.TOASTER_PORT), config.TESTDIR)
        except ShellCmdException as exc:
            self.fail("Failed starting managed mode: %s" % (exc))

class Test02HTML5Compliance(unittest.TestCase):
    def setUp(self):
        self.origdir = os.getcwd()
        self.crtdir = os.path.dirname(config.TESTDIR)
        self.cleanup_database = False
        os.chdir(self.crtdir)
        if not os.path.exists(os.path.join(self.crtdir, "toaster.sqlite")):
            self.cleanup_database = True
            run_shell_cmd("%s/bitbake/lib/toaster/manage.py syncdb --noinput" % config.TESTDIR)
            run_shell_cmd("%s/bitbake/lib/toaster/manage.py migrate orm" % config.TESTDIR)
            run_shell_cmd("%s/bitbake/lib/toaster/manage.py migrate bldcontrol" % config.TESTDIR)
            run_shell_cmd("%s/bitbake/lib/toaster/manage.py loadconf %s/meta-yocto/conf/toasterconf.json" % (config.TESTDIR, config.TESTDIR))
            run_shell_cmd("%s/bitbake/lib/toaster/manage.py lsupdates" % config.TESTDIR)

            setup = pexpect.spawn("%s/bitbake/lib/toaster/manage.py checksettings" % config.TESTDIR)
            setup.logfile = sys.stdout
            setup.expect(r".*or type the full path to a different directory: ")
            setup.sendline('')
            setup.sendline('')
            setup.expect(r".*or type the full path to a different directory: ")
            setup.sendline('')
            setup.expect(r"Enter your option: ")
            setup.sendline('0')

        self.child = pexpect.spawn("bash", ["%s/bitbake/bin/toaster" % config.TESTDIR, "webport=%d" % config.TOASTER_PORT, "nobrowser"], cwd=self.crtdir)
        self.child.logfile = sys.stdout
        self.child.expect("Toaster is now running. You can stop it with Ctrl-C")

    def test_html5_compliance(self):
        import urllist, urlcheck
        results = {}
        for url in urllist.URLS:
            results[url] = urlcheck.validate_html5(config.TOASTER_BASEURL + url)

        failed = []
        for url in results:
            if results[url][1] != 0:
                failed.append((url, results[url]))

        self.assertTrue(len(failed) == 0, "Not all URLs validate: \n%s " % "\n".join(["".join(str(x)) for x in failed]))

        #(config.TOASTER_BASEURL + url, status, errors, warnings))

    def tearDown(self):
        while self.child.isalive():
            self.child.kill(signal.SIGINT)
            time.sleep(1)
        os.chdir(self.origdir)
        toaster_sqlite_path = os.path.join(self.crtdir, "toaster.sqlite")
        if self.cleanup_database and os.path.exists(toaster_sqlite_path):
            os.remove(toaster_sqlite_path)


from import_export.widgets import(
    format_datetime,
    Widget,
)
from django.conf import settings
from datetime import date, datetime
from django.utils import timezone
import django

class BooleanWidget(Widget):
    TRUE_VALUES = ["1", 1, True, "true", "TRUE", "True"]
    FALSE_VALUES = ["0", 0, False, "false", "FALSE", "False"]
    NULL_VALUES = ["", None, "null", "NULL", "none", "NONE", "None"]

    def render(self, value, obj=None):
        """
        On export, ``True`` is represented as ``1``, ``False`` as ``0``, and
        ``None``/NULL as a empty string.

        Note that these values are also used on the import confirmation view.
        """
        if value in self.NULL_VALUES:
            return ""
        return self.TRUE_VALUES[2] if value else self.FALSE_VALUES[2]

    def clean(self, value, row=None, *args, **kwargs):
        if value in self.NULL_VALUES:
            return None
        return True if value in self.TRUE_VALUES else False

class CustomDateWidget(Widget):
    """
    Widget for converting date fields.

    Takes optional ``format`` parameter.
    """

    def __init__(self, format=None):
        if format is None:
            if not settings.DATE_INPUT_FORMATS:
                formats = ("%Y-%m-%d",)
            else:
                formats = settings.DATE_INPUT_FORMATS
        else:
            formats = (format,)
        self.formats = formats

    def clean(self, value, row=None, *args, **kwargs):
        if not value:
            return None
        if isinstance(value, date):
            return value
        for format in self.formats:
            try:
                return datetime.strptime(value, format).date()
            except (ValueError, TypeError):
                continue
        raise ValueError("Enter a valid date.")

    def render(self, value, obj=None):
        if not value:
            return ""
        return format_datetime(value, self.formats[0])

class CustomDateTimeWidget(Widget):
    """
    Widget for converting date fields.

    Takes optional ``format`` parameter. If none is set, either
    ``settings.DATETIME_INPUT_FORMATS`` or ``"%Y-%m-%d %H:%M:%S"`` is used.
    """

    def __init__(self, format=None):
        if format is None:
            if not settings.DATETIME_INPUT_FORMATS:
                formats = ("%Y-%m-%d %H:%M:%S",)
            else:
                formats = settings.DATETIME_INPUT_FORMATS
        else:
            formats = (format,)
        self.formats = formats

    def clean(self, value, row=None, *args, **kwargs):
        if not value:
            return None
        if isinstance(value, datetime):
            return value
        for format in self.formats:
            try:
                dt = datetime.strptime(value, format)
                if settings.USE_TZ:
                    # make datetime timezone aware so we don't compare
                    # naive datetime to an aware one
                    dt = timezone.make_aware(dt, timezone.get_default_timezone())
                return dt
            except (ValueError, TypeError):
                continue
        raise ValueError("Enter a valid date/time.")

    def render(self, value, obj=None):
        if not value:
            return ""
        if settings.USE_TZ:
            value = timezone.localtime(value)
        return format_datetime(value, self.formats[0])


import time
from keras.models import Sequential
from keras.layers import LSTM, TimeDistributed, Dense, Activation, Dropout, BatchNormalization
from keras.utils import np_utils
from keras.utils.np_utils import to_categorical

import pandas as pd
from pandas import Series,DataFrame
import seaborn as sns
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from keras.wrappers.scikit_learn import KerasClassifier

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy

# パラメーター
length_of_sequence = 10
in_out_neurons = 50
n_hidden = 100
dropout = 0.0

data = pd.read_csv('../all_stream.csv', header=None)
column_len = len(data.columns)
X = data.loc[:, 0 : (column_len-2)]
y = data.loc[:, column_len-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

X_train = X_train.values
X_train /= 1920.0
X_test = X_test.values
X_test /= 1920.0
y_train = y_train.values
y_test = y_test.values

num_classes = 3
X_train = numpy.reshape(X_train, (X_train.shape[0], length_of_sequence, in_out_neurons))
X_test = numpy.reshape(X_test, (X_test.shape[0], length_of_sequence, in_out_neurons))
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)

def create_model(n_hidden = n_hidden, dropout=dropout):
  model = Sequential([
            TimeDistributed(Dense(n_hidden), input_shape=(length_of_sequence, in_out_neurons)),
            TimeDistributed(Dense(n_hidden)),
            LSTM(n_hidden, return_sequences=True, dropout=dropout, input_shape=(length_of_sequence, in_out_neurons)),
            LSTM(n_hidden),
            Dense(num_classes),
            Activation('sigmoid')
          ])

  model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
  return model

model = KerasClassifier(build_fn=create_model, verbose=0)
n_hidden = [50, 75, 100, 125, 150]
dropout = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
param_grid = dict(dropout=dropout)
grid = GridSearchCV(estimator=model, param_grid=param_grid, cv=3)

#model = create_model()
#model.summary()
start = time.time()
#fit = model.fit(X_train, y_train, verbose=2, epochs=2000, validation_data=(X_test, y_test))
grid_result = grid.fit(X_train, y_train, verbose=2, epochs=1600, validation_data=(X_test, y_test))
process_time = time.time() - start

#start = time.time()
#process_time = time.time() - start
print ("best_score : ", grid_result.best_score_)
print ("best_params : ", grid_result.best_params_)

print("training time")
print(process_time)

results = pd.DataFrame(grid_result.cv_results_)
print("shape: ", results.shape)
print(results.columns)

print(results)

scores = results.pivot("param_dropout", "mean_test_score")
print(scores)
#plt.figure()
#sns.heatmap(scores, annot=True)
#plt.savefig('image/hidden_heatmap.png')
"""
train_score = model.evaluate(X_train, y_train, verbose=0)
print("train loss:",train_score[0])
print('train accuracy : ', train_score[1])

test_score = model.evaluate(X_test, y_test, verbose=0)
print("Test loss:", test_score[0])
print('test accuracy : ', test_score[1])

fig, (axL, axR) = plt.subplots(ncols=2, figsize=(10,4))
def plot_history_loss(fit):
  # Plot the loss in the history
  axL.plot(fit.history['loss'],label="loss for training")
  axL.plot(fit.history['val_loss'],label="loss for validation")
  axL.set_title('model loss')
  axL.set_xlabel('epoch')
  axL.set_ylabel('loss')
  axL.legend(loc='upper right')

def plot_history_acc(fit):
  # Plot the loss in the history
  axR.plot(fit.history['acc'],label="accuracy for training")
  axR.plot(fit.history['val_acc'],label="accuracy for validation")
  axR.set_title('model accuracy')
  axR.set_xlabel('epoch')
  axR.set_ylabel('accuracy')
  axR.legend(loc='upper right')

plot_history_loss(fit)
plot_history_acc(fit)
fig.savefig('./image/all3_dobn_2000.png')
plt.close()
"""


import os
import time
import copy

import matplotlib.pyplot as plt # for plotting
import numpy as np # for transformation

import torch # PyTorch package
import torchvision # load datasets
#import torchvision.transforms as transforms # transform data
from torchvision import datasets, models, transforms
import torch.nn as nn # basic building block for neural neteorks
import torch.nn.functional as F # import convolution functions like Relu
import torch.optim as optim # optimzer
from torch.optim import lr_scheduler

from image_handling import imshow
from neural_network_resnet import preprocess_transform
from neural_network_resnet import validation_transform, Net

import csv

def main():
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print(device)

    # define directory
    dirname = os.path.dirname(__file__)
    data_directory = os.path.join(dirname, 'vision_dataset_combined\\')
    train_directory = os.path.join(data_directory, 'train')
    val_directory = os.path.join(data_directory, 'val')

    # python image library of range [0, 1]
    # transform them to tensors of normalized range[-1, 1]

    train_transform = preprocess_transform()
    valid_transform = validation_transform()

    # set batch_size
    batch_size = 64

    # set number of workers
    num_workers = 2

    # load train data
    trainset = torchvision.datasets.ImageFolder(root=train_directory, transform=train_transform)
    validset = torchvision.datasets.ImageFolder(root=val_directory, transform=valid_transform)
    dataset_sizes = {'train': len(trainset), 'val': len(validset)}

    class_names = trainset.classes
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=num_workers)
    validloader = torch.utils.data.DataLoader(validset, batch_size=batch_size, shuffle=True, num_workers=num_workers)
    dataloaders = {'train': trainloader, 'val': validloader}

    # Model Building
    # model_ft = models.resnet18(pretrained=True)
    model_ft = Net()
    # num_ftrs = model_ft.fc.in_features
    # model_ft.fc = nn.Linear(num_ftrs, len(class_names))
    model_ft = model_ft.to(device)

    print(model_ft)

    criterion = nn.CrossEntropyLoss()
    #optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)#lr=0.001, momentum=0.9
    optimizer_ft = optim.Adam(model_ft.parameters(), lr=0.001)#lr=0.001
    # exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
    exp_lr_scheduler = 0
    start = torch.cuda.Event(enable_timing=True)
    end = torch.cuda.Event(enable_timing=True)

    csv_file = open('accuracy.csv', 'w')
    csv_writer = csv.writer(csv_file)

    start.record()

    model = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, device, dataloaders, dataset_sizes, csv_writer, num_epochs=250)

    # whatever you are timing goes here
    end.record()

    csv_file.close()

    # Waits for everything to finish running
    torch.cuda.synchronize()

    print('Finished Training')
    print(start.elapsed_time(end))  # milliseconds

    # save
    PATH = './cifar_net.pth'
    torch.save(model.state_dict(), PATH)

def train_model(model, criterion, optimizer, scheduler, device, dataloaders, dataset_sizes, csvwriter, num_epochs=25):
    since = time.time()

    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0

    for epoch in range(num_epochs):
        print(f'Epoch {epoch}/{num_epochs - 1}')
        print('-' * 10)

        if epoch == 99:
            PATH = './cifar_net_99.pth'
            torch.save(model.state_dict(), PATH)
            optimizer = optim.Adam(model.parameters(), lr=0.0001)
        elif epoch == 149:
            PATH = './cifar_net_149.pth'
            torch.save(model.state_dict(), PATH)
            optimizer = optim.Adam(model.parameters(), lr=0.00001)
        elif epoch == 199:
            PATH = './cifar_net_199.pth'
            torch.save(model.state_dict(), PATH)
            optimizer = optim.Adam(model.parameters(), lr=0.000001)

        csv_data = [epoch]
        # Each epoch has a training and validation phase
        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()  # Set model to training mode
            else:
                model.eval()   # Set model to evaluate mode

            running_loss = 0.0
            running_corrects = 0

            # Iterate over data.
            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # statistics
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
            # if phase == 'train':
                # scheduler.step()

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]
            csv_data.extend([epoch_loss,epoch_acc])

            print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')

            # deep copy the model
            if phase == 'val' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())
        csvwriter.writerow(csv_data)
        print()

    time_elapsed = time.time() - since
    print(f'Training complete in {time_elapsed // 60:.0f}m {time_elapsed % 60:.0f}s')
    print(f'Best val Acc: {best_acc:4f}')

    # load best model weights
    model.load_state_dict(best_model_wts)
    return model

if __name__ == '__main__':
    main()


#Runtime ~0.125s. (Using Binet's formula would be faster.)
import mpmath

#Define recursive Fibonacci function for postive integer n. Use a dictionary to avoid recalculation of results.
def Fibonacci(n, Fibonacci_dict):
    if "{}".format(n) in Fibonacci_dict:
        return Fibonacci_dict["{}".format(n)]
    else:
        new_number = Fibonacci(n-1, Fibonacci_dict) + Fibonacci(n-2, Fibonacci_dict)
        Fibonacci_dict["{}".format(n)] = new_number
        return new_number

Fibonacci_numbers = {"1" : 1, "2" : 1}

#Note that the ratio between two Fibonacci numbers F_n and F_{n+1} approaches the golden ratio "phi" as n tends to infinity. Hence for F_x >= 10^999, a lower bound on x is derived from \phi^x = 10^999.
phi = (1 + mpmath.sqrt(5))/2
x=int(mpmath.ceil(999 * mpmath.log(10) / mpmath.log(phi)))
print("Lower bound of first Fibonacci index to contain one-thousand digits is", x)

#Increment Fibonacci numbers until one with a thousand digits is found. This will occur for n>=4781.
for n in range(1, 5000):
    Fibonacci(n, Fibonacci_numbers)
    if n >= x and Fibonacci(n, Fibonacci_numbers) >= mpmath.mpf(10**999):
        print("First Fibonacci index to contain one-thousand digits is", n)
        break


# Import modules
from PIL import Image, ImageTk
import numba as nb
import numpy as np
import math

# =========================================
# Def functions
# - HSV to RGB (HSV: 0 to 1; RGB: 0 to 255)
@nb.njit(fastmath=True)
def HSVtoRGB(h: float, s: float, v: float):
  """HSV to RGB (HSV: 0 to 1; RGB: 0 to 255)"""
  if s == 0.0:
    return v, v, v
  i = int(h*6.0)
  f = (h*6.0) - i
  p = ( v*(1.0 - s) ) * 255
  q = ( v*(1.0 - s*f) ) * 255
  t = ( v*(1.0 - s*(1.0-f)) ) *255
  i = i%6
  if i == 0:
      return v, t, p
  if i == 1:
      return q, v, p
  if i == 2:
      return p, v, t
  if i == 3:
      return p, q, v
  if i == 4:
      return t, p, v
  if i == 5:
      return v, p, q

# - Calculates Mandelbrot pixel
@nb.njit(fastmath=True)
def pixelMandelbrot(position: tuple, maxIter: int):
  """Calculate Mandelbrot pixel"""
  cR = position[0]
  cI = position[1]
  zR = 0
  zI = 0
  i = 0

  while (zR * zR) + (zI * zI) < 4 and i < maxIter:
    tmp = zR
    zR = zR ** 2 - zI ** 2 + cR
    zI = 2 * zI * tmp + cI
    i += 1

  if i == maxIter:
    return (0, 0, 0)
  else:
    #return HSVtoRGB(i/maxIter, 1, 1)
    value = int(255*i/maxIter)
    return (value, 255, 255)
    #return (int(value), int(value*.75), int(value*.5))

# Calculates Julia Set pixel
@nb.njit(fastmath=True)
def pixelJuliaSet(position: tuple, C: tuple, maxIter: int):
  """Calculate Mandelbrot pixel"""
  cR = C[0]
  cI = C[1]
  zR = position[0]
  zI = position[1]
  i = 0

  while (zR * zR) + (zI * zI) < 4 and i < maxIter:
    tmp = zR
    zR = zR ** 2 - zI ** 2 + cR
    zI = 2 * zI * tmp + cI
    i += 1

  if i == maxIter:
    return (0, 0, 0)
  else:
    #return HSVtoRGB(i/maxIter, 1, 1)
    value = int(255*i/maxIter)
    return (value, 255, 255)
    #return (int(value), int(value*.75), int(value*.5))

# - Calculates Burning Ship pixel
@nb.njit(fastmath=True)
def pixelBurningShip(position: tuple, maxIter: int):
  """Calculate Burningship pixel"""
  cR = position[0]
  cI = position[1]
  zR = zI = 0
  i = 0

  while (zR * zR) + (zI * zI) < 4 and i < maxIter:
    tmp = zR
    zR = zR ** 2 - zI ** 2 + cR
    zI = abs(2 * zI * tmp) + cI
    i += 1

  if i == maxIter:
    return (0, 0, 0)
  else:
    value = i/maxIter*255
    return ( int(math.sqrt(value) * math.sqrt(255)), int(value), int(value) )

# fractalsInfos dict
fractalsInfos = {
  "mandelbrot":
    {"func": pixelMandelbrot,
    "mode": "HSV",
    "pos": (-0.68, 0)},
  "burningship":
    {"func": pixelBurningShip,
    "mode": "RGB",
    "pos": (0, 0)},
    "julia set":
    {"func": pixelJuliaSet,
    "mode": "HSV",
    "pos": (0, 0)}
}
# - Render function without numba to be able to use non jittable functions
def render(params, fractal: str="mandelbrot"):
  """Render function without numba for non jittable functions
  Supported fractals: mandelbrot ; burningship"""

  renderImage = np.zeros((params["res"][0], params["res"][1], 3), dtype=np.uint8)
  if fractal == "julia set":
    renderImage = optimizedRenderArg(renderImage, params["pos"], params["scale"], params["res"], fractalsInfos[fractal]["func"],params["C"],
                                                                                params["maxIter"])
  else:
    renderImage = optimizedRender(renderImage, params["pos"], params["scale"], params["res"], fractalsInfos[fractal]["func"], params["maxIter"])

  return arrayToImage(renderImage, fractalsInfos[fractal]["mode"])

# - Calculate fractal image with no arguments
@nb.njit(fastmath=True)
def optimizedRender(image, position: tuple, scale: float, res: tuple, fractalFunction, maxIter: int=20):
  """Renders image with no function argument"""

  for y in nb.prange(int(-res[1]/2), int(res[1]/2-1)):
    # Y loop
    yPos = ((y + res[1]/4)/res[1])*scale + position[1]

    for x in range(int(-res[0]/2), int(res[0]/2-1)):
      # X loop
      image[y][x] = fractalFunction(( ((x + res[0]/4)/res[0])*scale + position[0], yPos), maxIter)

  return image

@nb.njit(fastmath=True)
def optimizedRenderArg(image, position: tuple, scale: float, res: tuple, fractalFunction, arg, maxIter: int=20):
  """Renders image with one function agrument"""

  for y in nb.prange(int(-res[1]/2), int(res[1]/2-1)):
    # Y loop
    yPos = ((y + res[1]/4)/res[1])*scale + position[1]

    for x in range(int(-res[0]/2), int(res[0]/2-1)):
      # X loop
      image[y][x] = fractalFunction(( ((x + res[0]/4)/res[0])*scale + position[0], yPos), arg, maxIter)

  return image

# - Convert numpy array to TKImage
def arrayToImage(array, colorSpace: str="HSV"):
  """Convert numpy array to TKImage
  colorSpace: should be "HSV" or "RGB" """

  return ImageTk.PhotoImage(image=Image.fromarray(array, mode=colorSpace))

# - Convert Image to TkImage
def imageToTK(image):
  """Convert Image to TkImage"""

  return ImageTk.PhotoImage(image=image, size=(100, 100))


import sys
from PIL import Image  # pip install Pillow
import numpy as np
from random import shuffle
import matplotlib.pyplot as plt
from random import shuffle, random
import os

def load_image(file_name):
    img = np.array(Image.open(file_name))
    print("'{}' loaded with shape = {}".format(file_name, img.shape))
    return img

def save_image(img, file_name):
    Image.fromarray(img).save(file_name)

def reconstruct_image(pieces_order, pieces):
    # build columns and them assemble them
    columns = []
    n_cols = pieces_order.shape[1]
    for col in range(n_cols):
        ids_in_col = pieces_order[:, col]
        temp_col = pieces[ids_in_col[0]]
        for idx in ids_in_col[1:]:
            temp_col = np.concatenate((temp_col, pieces[idx]), axis=0)
        columns.append(temp_col)
    res = columns[0]
    for i in range(1, len(columns)):
        res = np.concatenate((res, columns[i]), axis=1)
    return res

def compute_lr_border_cost(s1, s2):
    # compute a fitness score between the right part of s1 and the left part of s2
    r_col = s1[:, -1, :].astype(np.int16)
    l_col = s2[:, 0, :].astype(np.int16)
    diff_col = np.absolute(np.subtract(r_col, l_col))
    return np.sum(diff_col)

def find_n_cols(img, threshold):
    # assuming a constant column width
    costs = []
    ids = []
    print("width = img.shape[1] = {}".format(img.shape[1]))
    for i in range(img.shape[1]-1):
        l = img[:, i:i+1, :]
        r = img[:, i+1:i+2, :]
        cost = compute_lr_border_cost(l, r)
        costs.append(cost)
    for i, c in enumerate(costs):
        if c > threshold:
            ids.append(i)
    print("{} transitions above threshold={} @ pixel {}".format(len(ids), threshold, ids))
    plot_costs(costs, threshold)
    if len(ids) == 0:
        return 1
    if len(ids) == 1:
        col_width = min(img.shape[1] - ids[0], ids[0])
        print(img.shape[1] / col_width)
        res = round(img.shape[1] / col_width)
        return res
    gaps = [ids[i+1]-ids[i] for i in range(len(ids)-1)]
    print("gaps = {}".format(gaps))
    col_width = smallest_common_diviser(gaps)
    res = int(img.shape[1] / col_width)
    return res

def find_n_rows(img, threshold):
    copy_img = np.copy(img)
    rot_img = np.copy(np.rot90(copy_img))
    return find_n_cols(rot_img, threshold)

def find_first_piece(lr_costs_matrix, ud_costs_matrix):
    # which one to go at the top-left corner
    lr_scores = np.min(lr_costs_matrix, axis=0)
    ud_scores = np.min(ud_costs_matrix, axis=0)
    tot_scores = lr_scores + ud_scores
    id_top_right_corner = np.argmax(tot_scores)
    return id_top_right_corner

def get_pieces(path):

    pieces = []
    for piece_path in os.listdir(path):
        img_path = path+piece_path
        if img_path == './pieces/.ipynb_checkpoints':
            pass
        else :
            piece = load_image(path+piece_path)
            pieces.append(piece)
    return pieces


import csv
import requests
# Web-scraping of:
# https://drug-interactions.medicine.iu.edu/MainTable.aspx
# Ouverture du fichier CSV en mode lecture
ddi_cyp = []
with open('cyp_ddi_scrap.csv', newline='') as csvfile:
    # Création d'un objet lecteur CSV
    csv_reader = csv.reader(csvfile, delimiter=',', quotechar='"')

    # Parcours des lignes du fichier CSV
    for row in csv_reader:
        # Nettoyage des noms de médicaments
        cleaned_row = [name.strip().lower() for name in row]

        # Ajout de la ligne à la liste ddi_cyp
        ddi_cyp.append(tuple(cleaned_row))

# Liste de noms de médicaments en minuscules
ls_pa = ["citalopram", "amlodipine", "atorvastatin", "pantoprazole", "clopidogrel"]
print(len(ddi_cyp))

my_drugs = []
drugs = []
n = 0
for ddi in ddi_cyp:
    if(ddi[0] not in drugs):
        n += 1
        drugs.append(ddi[0])
        my_drugs.append((n, ddi[0]))

print("nb drugs  in db :", len(my_drugs))

substrates_ddi = []
not_sub_ddi = []
for ddi in ddi_cyp:
    if(ddi[2] == "substrates"):
        substrates_ddi.append(ddi)
    else:
        not_sub_ddi.append(ddi)

ddi_for_fhir = []
for victim in substrates_ddi:
    for perpet in not_sub_ddi:
        if(perpet[3] == "inhebitors"):
            effet = "Augmentation de la Bio disponibilité de %s"%(victim[0])
        else:
            effet = "Diminution de la Bio disponibilité de %s"%(victim[0])
        if(victim[1]==perpet[1]):

            ddi_for_fhir.append({"d1":victim[0],
                "d2":perpet[0],
                "type": "%s_%s_%s"%(perpet[3], perpet[1], perpet[2]),
                "incidence": effet,
            })

print("len sub :", len(substrates_ddi))
print("len non sub :", len(not_sub_ddi))

print("len FHIR DDI :", len(ddi_for_fhir))

print(ddi_for_fhir[2:6])

def get_cyp_fhir_ressource(inter):
    my_resource = """"{
  "resourceType" : "MedicinalProductInteraction",

  "subject" : [{ Reference(Medication/%s) }],
  "description" : "Description clear",
  "interactant" : [{
    "itemReference" : { Reference(Medication/%s) }
    "itemCodeableConcept" : { "text": "No more information" }
  }],
  "type" : { "text": "%s" },
  "effect" : { "text": "Interaction between two drugs" },
  "incidence" : { "text": "%s" },
  "management" : { "text" : "Adapatation posologique ou gestion du plan de prise sinon alternative therapeutique" } // Actions for managing the interaction
}"""%(inter["d1"], inter["d2"], inter["type"], inter["incidence"])

    return my_resource

print(get_cyp_fhir_ressource(ddi_for_fhir[89]))

host = 'https://fhir.st2c88fqxgfh.workload-nonprod-fhiraas.isccloud.io'
api_key = 'ton token'

def create_medication(my_drug):
    my_resource = """{
  "resourceType" : "Medication",
  "id" : "%s",
  "code" : {
    "coding" : [{
      "system" : "http://www.nlm.nih.gov/research/umls/rxnorm",
      "code" : "%s",
      "display" : "%s"
    }]
  }
}"""%(my_drug[0], my_drug[1], my_drug[1])
    return my_resource, my_drug[0]

for drug in my_drugs:
    json_drug,id = create_medication(drug)
    # put the medication in the FHIR server
    url = host + '/Medication'
    # create the headers

    headers = {
        'Content-Type': 'application/json+fhir',
        'x-api-key': api_key
    }

    # make the request
    response = requests.put(url+'/'+str(id), headers=headers, data=json_drug)
    # raise an exception in case of http errors
    response.raise_for_status()