"""
Utility funcions for plotting response analysis

Authors: Dylan Paiton, Santiago Cadena
"""

import os
import sys

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.ticker as plticker
from matplotlib.offsetbox import (OffsetImage, AnnotationBbox)
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np
import proplot as pro

ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),'..','..'))
if ROOT_DIR not in sys.path: sys.path.append(ROOT_DIR)

import response_contour_analysis.utils.dataset_generation as data_utils

def clear_axis(ax, spines='none'):
    for ax_loc in ['top', 'bottom', 'left', 'right']:
        ax.spines[ax_loc].set_color(spines)
    ax.set_yticklabels([])
    ax.set_xticklabels([])
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    ax.tick_params(axis='both', bottom=False, top=False, left=False, right=False)
    return ax

def set_size(width, fraction=1, subplot=[1, 1]):
    """
    Set aesthetic figure dimensions to avoid scaling in latex.
    Parameters:
        width: float
                Width in pts
        fraction: float
                Fraction of the width which you wish the figure to occupy
    Returns:
      fig_dim: tuple
              Dimensions of figure in inches
    Usage:
        figsize = set_size(text_width, fraction=1, subplot=[1, 1])
    Code obtained from: https://jwalton.info/Embed-Publication-Matplotlib-Latex/
    """
    fig_width_pt = width * fraction # Width of figure
    inches_per_pt = 1 / 72.27 # Convert from pt to inches
    golden_ratio = (5**.5 - 1) / 2 # Golden ratio to set aesthetic figure height
    fig_width_in = fig_width_pt * inches_per_pt # Figure width in inches
    fig_height_in = fig_width_in * golden_ratio * (subplot[0] / subplot[1]) # Figure height in inches
    fig_dim = (fig_width_in, fig_height_in) # Final figure dimensions
    return fig_dim

def plot_group_iso_contours(analysis_dict, num_levels, show_contours=True, targets_comparisons=[2,3], text_width=200, width_fraction=1.0, dpi=100):
    arrow_width = 0.0
    arrow_linewidth = 1
    arrow_headsize = 0.15
    arrow_head_length = 0.15
    arrow_head_width = 0.15
    gs0_hspace = 0.5
    gs0_wspace = -0.6
    phi_k_text_x_offset = 0.6 / width_fraction
    phi_k_text_y_offset = -1.2 / width_fraction
    phi_j_text_x_offset = 0.9 / width_fraction
    phi_j_text_y_offset = 0.3 / width_fraction
    nu_text_x_offset = -0.56 / width_fraction
    nu_text_y_offset = 0.3 / width_fraction
    num_plots_y = targets_comparisons[0] # num target neurons
    num_plots_x = targets_comparisons[1] # num comparison planes
    gs0 = gridspec.GridSpec(num_plots_y, num_plots_x, wspace=gs0_wspace, hspace=gs0_hspace)
    vmin = np.min(analysis_dict['activations'])
    vmax = np.max(analysis_dict['activations'])
    levels = np.linspace(vmin, vmax, num_levels)
    cmap = plt.get_cmap('cividis')
    cNorm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
    scalarMap = mpl.cm.ScalarMappable(norm=cNorm, cmap=cmap)
    fig = plt.figure(figsize=set_size(text_width, width_fraction, [num_plots_y, num_plots_x]), dpi=dpi)
    contour_handles = []
    curve_axes = []
    for plot_id in np.ndindex((num_plots_y, num_plots_x)):
        (y_id, x_id) = plot_id
        neuron_index = y_id
        orth_index = x_id
        inner_gs = gridspec.GridSpecFromSubplotSpec(1, 1, gs0[plot_id])
        curve_axes.append(clear_axis(fig.add_subplot(inner_gs[0])))
        #curve_axes[-1].set_title(str(plot_id)) # TODO: change title
        # plot colored mesh points
        norm_activity = analysis_dict['activations'][neuron_index, orth_index, ...]
        x_mesh, y_mesh = np.meshgrid(
            analysis_dict['contour_dataset']['x_pts'],
            analysis_dict['contour_dataset']['y_pts'])
        if show_contours:
            contsf = curve_axes[-1].contourf(x_mesh, y_mesh, norm_activity,
                levels=levels, vmin=vmin, vmax=vmax, alpha=1.0, antialiased=True, cmap=cmap)
        else:
            contsf = curve_axes[-1].scatter(x_mesh, y_mesh,
                vmin=vmin, vmax=vmax, cmap=cmap, marker='s', alpha=1.0, c=norm_activity, s=30.0)
        contour_handles.append(contsf)
        # plot target neuron arrow & label
        proj_target = analysis_dict['contour_dataset']['proj_target_vect'][neuron_index][orth_index]
        target_vector_x = proj_target[0].item()
        target_vector_y = proj_target[1].item()
        curve_axes[-1].arrow(0, 0, target_vector_x, target_vector_y,
            width=arrow_width, head_width=arrow_head_width, head_length=arrow_head_length,
            fc='k', ec='k', linestyle='-', linewidth=arrow_linewidth)
        tenth_range_shift = ((max(analysis_dict['x_range']) - min(analysis_dict['x_range']))/10) # For shifting labels
        text_handle = curve_axes[-1].text(
            target_vector_x+(tenth_range_shift*phi_k_text_x_offset),
            target_vector_y+(tenth_range_shift*phi_k_text_y_offset),
            r'$\Phi_{k}$', horizontalalignment='center', verticalalignment='center')
        # plot comparison neuron arrow & label
        proj_comparison = analysis_dict['contour_dataset']['proj_comparison_vect'][neuron_index][orth_index]
        comparison_vector_x = proj_comparison[0].item()
        comparison_vector_y = proj_comparison[1].item()
        curve_axes[-1].arrow(0, 0, comparison_vector_x, comparison_vector_y,
            width=arrow_width, head_width=arrow_head_width, head_length=arrow_head_length,
            fc='k', ec='k', linestyle='-', linewidth=arrow_linewidth)
        text_handle = curve_axes[-1].text(
            comparison_vector_x+(tenth_range_shift*phi_j_text_x_offset),
            comparison_vector_y+(tenth_range_shift*phi_j_text_y_offset),
            r'$\Phi_{j}$', horizontalalignment='center', verticalalignment='center')
        # Plot orthogonal vector Nu
        proj_orth = analysis_dict['contour_dataset']['proj_orth_vect'][neuron_index][orth_index]
        orth_vector_x = proj_orth[0].item()
        orth_vector_y = proj_orth[1].item()
        curve_axes[-1].arrow(0, 0, orth_vector_x, orth_vector_y,
            width=arrow_width, head_width=arrow_head_width, head_length=arrow_head_length,
            fc='k', ec='k', linestyle='-', linewidth=arrow_linewidth)
        text_handle = curve_axes[-1].text(
            orth_vector_x+(tenth_range_shift*nu_text_x_offset),
            orth_vector_y+(tenth_range_shift*nu_text_y_offset),
            r'$\nu$', horizontalalignment='center', verticalalignment='center')
        # Plot axes
        curve_axes[-1].set_aspect('equal')
        curve_axes[-1].plot(analysis_dict['x_range'], [0,0], color='k', linewidth=arrow_linewidth/2)
        curve_axes[-1].plot([0,0], analysis_dict['y_range'], color='k', linewidth=arrow_linewidth/2)
    # Add colorbar
    scalarMap._A = []
    cbar_ax = inset_axes(curve_axes[-1],
        width='5%',
        height='100%',
        loc='lower left',
        bbox_to_anchor=(1.05, 0., 1, 1),
        bbox_transform=curve_axes[-1].transAxes,
        borderpad=0,
        )
    cbar = fig.colorbar(scalarMap, cax=cbar_ax, ticks=[vmin, vmax])
    cbar.ax.tick_params(labelleft=False, labelright=True, left=False, right=True)
    cbar.ax.set_yticklabels(['{:.0f}'.format(vmin), '{:.0f}'.format(vmax)])
    plt.show()
    return fig, contour_handles

def plot_curvature_histograms(hist_list, label_list, color_list, bin_centers, title, xlabel,
                              text_width=200, width_ratio=1.0, dpi=100):
    """
    hist_list [nested list of floats] containing histogram values that is indexed by
        [curvature type]
        [dataset type]
        [target neuron id]
        [num_bins - 1]
    label_list [nested list of strings] containing labels that shares its structure with hist_list
    color_list [nested list of strings] containing color hash values that shares its structure with hist_list
    bin_centers [nested list of floats] containing bin center values that is indexed by
        [curvature type]
        [num_bins]
    title [string]
    xlabel [string]
    """
    gs0_wspace = 0.5
    hspace_hist = 0.7
    wspace_hist = 0.10
    num_y_plots = 1
    num_x_plots = 1
    fig = plt.figure(figsize=set_size(text_width, width_ratio, [num_y_plots, num_x_plots]), dpi=dpi)
    gs_base = gridspec.GridSpec(num_y_plots, num_x_plots, wspace=gs0_wspace)
    num_hist_y_plots = 2
    num_hist_x_plots = 2
    gs_hist = gridspec.GridSpecFromSubplotSpec(num_hist_y_plots, num_hist_x_plots, gs_base[0],
        hspace=hspace_hist, wspace=wspace_hist)
    orig_ax = fig.add_subplot(gs_hist[0,0])
    axes = []
    for sub_plt_y in range(0, num_hist_y_plots):
        axes.append([])
        for sub_plt_x in range(0, num_hist_x_plots):
            if (sub_plt_x, sub_plt_y) == (0,0):
                axes[sub_plt_y].append(orig_ax)
            else:
                axes[sub_plt_y].append(fig.add_subplot(gs_hist[sub_plt_y, sub_plt_x], sharey=orig_ax))
    all_x_lists = zip(hist_list, label_list, color_list, bin_centers, title)
    for axis_x, (type_hist, sub_label, sub_color, sub_bins, sub_title) in enumerate(all_x_lists):
        max_hist_val = 0.001
        min_hist_val = 100
        all_y_lists = zip(type_hist, sub_label, sub_color, xlabel)
        for axis_y, (dataset_hist, axis_labels, axis_colors, sub_xlabel) in enumerate(all_y_lists):
            axes[axis_y][axis_x].spines['top'].set_visible(False)
            axes[axis_y][axis_x].spines['right'].set_visible(False)
            axes[axis_y][axis_x].set_xticks(sub_bins, minor=True)
            axes[axis_y][axis_x].set_xticks(sub_bins[::int(len(sub_bins)/4)], minor=False)
            axes[axis_y][axis_x].xaxis.set_major_formatter(plticker.FormatStrFormatter('%0.3f'))
            for hist, label, color in zip(dataset_hist, axis_labels, axis_colors):
                axes[axis_y][axis_x].plot(sub_bins, hist, color=color, linestyle='-',
                    drawstyle='steps-mid', label=label)
                axes[axis_y][axis_x].set_yscale('log')
                if np.max(hist) > max_hist_val:
                    max_hist_val = np.max(hist)
                if np.min(hist) < min_hist_val:
                    min_hist_val = np.min(hist)
            axes[axis_y][axis_x].axvline(0.0, color='black', linestyle='dashed', linewidth=1)
            if axis_y == 0:
                axes[axis_y][axis_x].set_title(sub_title)
            axes[axis_y][axis_x].set_xlabel(sub_xlabel)
            if axis_x == 0:
                axes[axis_y][axis_x].set_ylabel('Relative\nFrequency')
                ax_handles, ax_labels = axes[axis_y][axis_x].get_legend_handles_labels()
                legend = axes[axis_y][axis_x].legend(handles=ax_handles, labels=ax_labels,
                    loc='upper right', ncol=1, borderaxespad=0., borderpad=0.,
                    handlelength=0., columnspacing=-0.5, labelspacing=0., bbox_to_anchor=(0.95, 0.95))
                legend.get_frame().set_linewidth(0.0)
                for text, color in zip(legend.get_texts(), axis_colors):
                    text.set_color(color)
                for item in legend.legendHandles:
                    item.set_visible(False)
            if axis_x == 1:
                axes[axis_y][axis_x].tick_params(axis='y', labelleft=False)
        #axes[axis_y][axis_x].set_ylim([0, 1.0])
    plt.show()
    return fig

def add_arrow(ax, vect, xrange, yx_offset=[1,1], linestyle='-', label='', text_color='k'):
    """
    adds an arrow to a given plot, defined by the vect input
    ax [matplotlib axis]
    vect [list] with entries [vect_x, vect_y]
    xrange [float] range of x values, to be used to rescale
    yx_offset [list of a pair of ints] offset label from arrow
    linestyle [str] same as matplotlib kwarg
    label [str] label to be given to the arrow
    text_color [str] same as color matplotlib kwarg
    """
    arrow_width = 0.0
    arrow_linewidth = 1
    arrow_headsize = 0.15
    arrow_head_length = 0.15
    arrow_head_width = 0.15
    vect_x = vect[0].item()
    vect_y = vect[1].item()
    ax.arrow(0, 0, vect_x, vect_y,
        width=arrow_width, head_width=arrow_head_width, head_length=arrow_head_length,
        fc='k', ec='k', linestyle=linestyle, linewidth=arrow_linewidth, length_includes_head=True)
    tenth_range_shift = xrange / 10 # For shifting labels
    text_handle = ax.text(
        vect_x + (tenth_range_shift * yx_offset[1]),
        vect_y + (tenth_range_shift * yx_offset[0]),
        label,
        weight='bold',
        color=text_color,
        horizontalalignment='center',
        verticalalignment='center')

def plot_contours(ax, activity, yx_pts, yx_range, proj_vects=None, num_levels=10, contours=None, fits=None, cmap='cividis', vlim=None, title=''):
    """
    ax [matplotlib axis]
    activity [numpy ndarray] neuron activation values
    yx_pts [list] returned from dataset_genration utilities
    yx_range [list] containing [y_range, x_range], returned from dataset_generation utilities
    proj_vects [list or None] if not None then plot target, comparison, and orthogonal vectors
    num_levels [int] number of contour levels
    contours [list of datapoints or None] if it is not None then the exctracted target contour points will be included
    fits [list of datapoints or None] if it is not None then the polynomial fit points will be included
    cmap [str] matplotlib kwarg
    vlim [tuple] containing (vmin, vmax)
    title [str] plot title
    """
    if vlim is None:
        vmin = np.min(activity)
        vmax = np.max(activity)
    else:
        vmin, vmax = vlim
    cmap = plt.get_cmap(cmap)
    cNorm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
    scalarMap = mpl.cm.ScalarMappable(norm=cNorm, cmap=cmap)
    # Plot contours
    x_mesh, y_mesh = np.meshgrid(*yx_pts[::-1])
    levels = np.linspace(vmin, vmax, num_levels)
    contsf = ax.contourf(x_mesh, y_mesh, activity,
        levels=levels, vmin=vmin, vmax=vmax, antialiased=True, cmap=cmap)#, alpha=1.0)
    if proj_vects is not None:
        # Add arrows
        proj_target = proj_vects[0]
        xrange = max(yx_range[1]) - min(yx_range[1])
        add_arrow(ax, proj_target, xrange, linestyle='-')
        proj_comparison = proj_vects[1]
        add_arrow(ax, proj_comparison, xrange, linestyle='--')
        proj_orth = proj_vects[2]
        add_arrow(ax, proj_orth, xrange, linestyle='-')
    # Add axis grid
    ax.set_aspect('equal')
    ax.plot(yx_range[1], [0,0], color='k', linewidth=0.5) # vertical
    ax.plot([0,0], yx_range[0], color='k', linewidth=0.5) # horizontal
    if contours is not None:
        ax.scatter(contours[0], contours[1], s=4, color='r')
    if fits is not None:
        ax.scatter(fits[0], fits[1], s=3, marker='*', color='k')
    ax.format(
        ylim=[np.min(yx_pts[0]), np.max(yx_pts[0])],
        xlim=[np.min(yx_pts[1]), np.max(yx_pts[1])],
        title=title
    )
    return contsf

def overlay_image(ax, images, y_pos, x_pos, yx_range, offset, arrowprops=None, cmap=None, vmin=None, vmax=None):
    """
    ax [matplotlib axis]
    images [np.ndarray] of shape [num_images_per_edge, num_images_per_edge, channels, height, weidth] images for each mesh point
    """
    num_images_per_edge = images.shape[0]
    image_y_pos = data_utils.remap_axis_index_to_dataset_index(
        axis_index=y_pos,
        axis_min=yx_range[0][0],
        axis_max=yx_range[0][1],
        num_images=num_images_per_edge)
    image_x_pos = data_utils.remap_axis_index_to_dataset_index(
        axis_index=x_pos,
        axis_min=yx_range[1][0],
        axis_max=yx_range[1][1],
        num_images=num_images_per_edge)
    height_ratio = images.shape[3] / np.maximum(*images.shape[3:])
    width_ratio = images.shape[4] / np.maximum(*images.shape[3:])
    inset_height = 0.35 * height_ratio
    inset_width = 0.35 * width_ratio
    arr_img = np.squeeze(images[image_y_pos, image_x_pos, ...].transpose((1,2,0)))
    imagebox = OffsetImage(arr_img, zoom=0.75, cmap=cmap)
    img = imagebox.get_children()[0]
    img.set_clim(vmin=vmin, vmax=vmax)
    imagebox.image.axes = ax
    if arrowprops is None:
        arrowprops = dict(
            linestyle='--',
            lw=1,
            arrowstyle='->',
            color='r'
        )
    ab = AnnotationBbox(imagebox,
        xy=[x_pos, y_pos],
        xybox=offset,
        xycoords=ax.transData,
        boxcoords='offset points',
        pad=0.0,
        arrowprops=arrowprops
    )
    ax.add_artist(ab)
    return arr_img


import numpy as np
import pandas as pd
from scipy.spatial import distance
from sklearn.datasets import make_circles
import matplotlib.pyplot as plt
from PIL import Image
from sklearn.ensemble import RandomForestClassifier
from sklearn.cluster import SpectralClustering
from sklearn.datasets import make_blobs
import warnings
warnings.filterwarnings('ignore')
import cv2

def kmeans_plus_centroids(X: np.ndarray,  k: int)-> (np.array):
    '''
    :param X: input array
    :param k: cluster size
    :return: Initialize the  centroid based on kmeans++ algorithm.
    '''
    index = np.random.choice(X.shape[0], 1, replace=False)
    centroids = []
    centroids.append(X[index][0])
    for cluster in range(k - 1):
        centroid_index = np.argmax(np.min(distance.cdist(centroids, X, 'euclidean'), axis=0))
        centroids.append(X[[centroid_index]][0])
    return np.array(centroids)

def kmeans(X: np.ndarray, k: int, centroids=None, max_iter=30, tolerance=1e-2)-> (np.ndarray, np.array):
    '''

    :param X: input array
    :param k: cluster size
    :param centroids: cluster intialization method, Could be kmeans++, None or custom initialized
    :param max_iter: number of iteration before cluster stops updating
    :param tolerance: difference in the cluster centers of two consecutive iterations to declare convergence.
    :return: centroid : final evaluated centroid coordinated based on max_iter and tolerance
             labels : final cluster labels for each data points in X
    '''
    if centroids == 'kmeans++':
        centroids = kmeans_plus_centroids(X, k)
    elif centroids is None:
        index = np.random.choice(X.shape[0], k, replace=False)
        centroids = X[index]

    norm = tolerance + 1
    distances = distance.cdist(centroids, X, 'euclidean')
    labels = np.argmin(distances, axis=0)
    iter_ = 0
    while iter_ < max_iter and norm > tolerance:
        distances = distance.cdist(centroids, X, 'euclidean')
        labels = np.argmin(distances, axis=0)
        norm = 0
        for i in range(k):
            X_i = X[labels == i]
            if len(X_i) == 0:
                index_ = np.random.choice(X.shape[0], 1, replace=False)
                centroid_i = X[index_][0]
            else:
                centroid_i = np.mean(X_i, axis=0)
            norm += np.sum(np.square(centroid_i - centroids[i]))
            centroids[i] = centroid_i
        norm = np.sqrt(norm) / k
        iter_ += 1
    return centroids, labels

'''These below functions are helper functions used for computing Affinity matrix using Breiman's RF'''
def conjure_twoclass(X : pd.DataFrame)-> (pd.DataFrame, pd.Series):
    '''

    :param X: Input DataFrame
    :return: X_synth: Returns synthetically generated data with labels
    '''
    X_rand = df_scramble(X)
    X_synth = pd.concat([X, X_rand], axis=0)
    y_synth = np.concatenate([np.zeros(len(X),dtype=int),np.ones(len(X_rand),dtype=int)],axis=0)
    return X_synth.to_numpy(), pd.Series(y_synth)

def df_scramble(X : pd.DataFrame) -> pd.DataFrame:
    '''
    :param X: Input DataFrame
    :return: shuffled version of dataframe X
    '''
    X_rand = X.copy()
    X_rand = X_rand.sample(frac=1).reset_index(drop=True)
    return X_rand

def leaf_samples(rf, X:np.ndarray):
    """
    Return a list of arrays where each array is the set of X sample indexes
    residing in a single leaf of some tree in rf forest. For example, if there
    are 4 leaves (in one or multiple trees), we might return:

        array([array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
               array([10, 11, 12, 13, 14, 15]), array([16, 17, 18, 19, 20]),
               array([21, 22, 23, 24, 25, 26, 27, 28, 29]))
    """
    n_trees = len(rf.estimators_)
    leaf_samples = []
    leaf_ids = rf.apply(X)  # which leaf does each X_i go to for sole tree?
    for t in range(n_trees):
        # Group by id and return sample indexes
        uniq_ids = np.unique(leaf_ids[:,t])
        sample_idxs_in_leaves = [np.where(leaf_ids[:, t] == id)[0] for id in uniq_ids]
        leaf_samples.extend(sample_idxs_in_leaves)
    return leaf_samples

def get_similarity(leaf_samples,n_estimators):
    '''
    :param leaf_samples: list of arrays where each array is the set of X sample indexes residing in a single leaf of some tree in rf forest.
    :param n_estimators: number of trees
    :return: similarity matrix for
    '''
    similarity  = np.zeros((500,500))
    for leaf in leaf_samples:
        for i in range(len(leaf)):
            for j in range(0, len(leaf)):
                similarity[leaf[i], leaf[j]] += 1
    similarity /= n_estimators
    return similarity

def get_labels(X:np.ndarray, n_estimators=500):
    '''
    :param X: Input data
    :param n_estimators: number of trees
    :return: labels for all X and similarity matrix.
    '''
    df = pd.DataFrame(X,columns=['col_1', 'col_2'])
    X_synth,y_synth = conjure_twoclass(df)
    rf = RandomForestClassifier(n_estimators=n_estimators, min_samples_leaf=50)
    rf.fit(X_synth,y_synth)
    leaf_sample = leaf_samples(rf, X)
    similarity = get_similarity(leaf_sample,n_estimators)
    cluster = SpectralClustering(n_clusters=2)
    labels = cluster.fit_predict(similarity)
    return labels, similarity


"""Web server gateway interface."""

from flask import request

from his import CUSTOMER, Application, admin, authenticated, authorized
from wsgilib import JSON, JSONMessage

from contactmgr.functions import get_contact, get_contacts
from contactmgr.orm import Contact

__all__ = ["APPLICATION"]

APPLICATION = Application("contactmgr")

@APPLICATION.route("/", methods=["GET"], strict_slashes=False)
@authenticated
@authorized("contactmgr")
@admin
def list_() -> JSON:
    """Lists available contacts."""

    return JSON([contact.to_json() for contact in get_contacts(CUSTOMER.id)])

@APPLICATION.route("/", methods=["POST"], strict_slashes=False)
@authenticated
@authorized("contactmgr")
@admin
def add() -> JSONMessage:
    """Adds a new contact."""

    contact = Contact.from_json(request.json, CUSTOMER.id)
    contact.save()
    return JSONMessage("Contact added.", status=201, id=contact.id)

@APPLICATION.route("/<int:ident>", methods=["PATCH"], strict_slashes=False)
@authenticated
@authorized("contactmgr")
@admin
def patch(ident: int) -> JSONMessage:
    """Patches a contact."""

    contact = get_contact(CUSTOMER.id, ident)
    contact.patch_json(request.json)
    return JSONMessage("Contact patched.", status=200)

@APPLICATION.route("/<int:ident>", methods=["DELETE"], strict_slashes=False)
@authenticated
@authorized("contactmgr")
@admin
def delete(ident: int) -> JSONMessage:
    """Deletes a contact."""

    get_contact(CUSTOMER.id, ident).delete_instance()
    return JSONMessage("Contact deleted.", status=200)


import time
import numpy as np
import argparse

def init_args():
    '''
    描述：生成全局参数
    参数：无
    返回：全局参数
    '''
    parser = argparse.ArgumentParser(description = "Arguments of the project.")
    parser.add_argument("--algorithm", type = str, default = 'QLearning')
    parser.add_argument("--num_train", type = int, default = 5000)
    parser.add_argument("--num_test", type = int, default = 1000)

    parser.add_argument("--gamma_q", type = float, default = 0.2)
    parser.add_argument("--lr_q", type = float, default = 1)
    parser.add_argument("--e_q", type = float, default = 1)
    parser.add_argument("--decay_rate_q", type = float, default = 0.99)

    parser.add_argument("--gamma_sarsa", type = float, default = 0.8)
    parser.add_argument("--lr_sarsa", type = float, default = 0.2)
    parser.add_argument("--e_sarsa", type = float, default = 0.5)
    parser.add_argument("--decay_rate_sarsa", type = float, default = 0.4)

    parser.add_argument("--gamma_l", type = float, default = 0.95)
    parser.add_argument("--lr_l", type = float, default = 0.1)
    parser.add_argument("--e_l", type = float, default = 1)
    parser.add_argument("--decay_rate_l", type = float, default = 0.99)
    parser.add_argument("--l", type = float, default = 0.5)
    parser.add_argument("--seed", type = int, default = 1453)
    parser.add_argument("--show", type = int, default = 0)
    args = parser.parse_args()
    return args

def render_single_Q(args, env, Q):
    """Renders Q function once on environment. Watch your agent play!

    Parameters
    ----------
    env: gym.core.Environment
      Environment to play Q function on. Must have nS, nA, and P as
      attributes.
    Q: np.array of shape [env.nS x env.nA]
      state-action values.
    """
    np.random.seed(args.seed)
    episode_reward = 0
    state = env.reset()
    done = False
    while not done:
        env.render()
        time.sleep(0.2)  # Seconds between frames. Modify as you wish.
        action = np.argmax(Q[state])
        state, reward, done, _ = env.step(action)
        episode_reward += reward
    print("Episode reward: %f" % episode_reward)

def evaluate_Q(args, env, Q, num_episodes = 100):
    '''
    描述：测试函数
    参数：全局参数，环境，策略函数Q，多少个episode
    返回：平均V
    '''
    np.random.seed(args.seed)
    tot_reward = 0
    rewards = []
    average_steps = 0
    for i in range(num_episodes):
        episode_reward = 0
        state = env.reset()
        done = False
        step = 0
        while not done:
            step += 1
            action = np.argmax(Q[state])
            state, reward, done, _ = env.step(action)
            episode_reward += reward

        tot_reward += episode_reward
        average_steps += step
        rewards.append(episode_reward)
    average_reward = tot_reward / num_episodes
    average_steps /= num_episodes
    reward_variance = 0
    for i in range(num_episodes):
        reward_variance += (rewards[i] - average_reward) ** 2
    reward_variance /= num_episodes

    if args.show:
        print("Total", tot_reward, "reward in", num_episodes, "episodes")
        print("Average Reward:", average_reward)
        print("Reward Variance:", reward_variance)
        print("Average steps:", average_steps)

    return tot_reward / num_episodes


from tkinter import *
# import the necessary packages
from imutils.video import VideoStream
from source.shapedetector import ShapeDetector
import numpy as np
import argparse
import cv2
import imutils
from PIL import Image
from PIL import ImageTk
import threading
import sqlite3 as sq

class camera:
    def __init__(self, window, vs, pts, layar):

        self.panel = None
        self.foto = layar
        self.frame2 = window
        self.vs = vs
        self.pts = pts

        self.stopEvent = threading.Event()
        self.thread = threading.Thread(target=self.videoLoop, args=())
        self.thread.start()

        current_row = 0
        #create a label for databases entry
        self.judul_label = Label(self.frame2, text="Judul: ", font=18)
        self.judul_label.grid(row=current_row, column=0)
        self.judul_text = StringVar()
        self.judul_entry = Entry(self.frame2, textvariable=self.judul_text, font=18)
        self.judul_entry.grid(row=current_row, column=1)
        current_row += 1

        self.pengarang_label = Label(self.frame2, text="Pengarang: ", font=18)
        self.pengarang_label.grid(row=current_row, column=0)
        self.pengarang_text = StringVar()
        self.pengarang_entry = Entry(self.frame2, textvariable=self.pengarang_text, font=18)
        self.pengarang_entry.grid(row=current_row, column=1)
        current_row += 1

        self.genre_label = Label(self.frame2, text="Genre: ", font=18)
        self.genre_label.grid(row=current_row, column=0)
        self.genre_text = StringVar()
        self.genre_entry = Entry(self.frame2, textvariable=self.genre_text, font=18)
        self.genre_entry.grid(row=current_row, column=1)
        current_row += 1

        self.tahun_label = Label(self.frame2, text="Tahun: ", font=18)
        self.tahun_label.grid(row=current_row, column=0)
        self.tahun_text = StringVar()
        self.tahun_entry = Entry(self.frame2, textvariable=self.tahun_text, font=18)
        self.tahun_entry.grid(row=current_row, column=1)
        current_row += 1

        self.penerbit_label = Label(self.frame2, text="Penerbit: ", font=18)
        self.penerbit_label.grid(row=current_row, column=0)
        self.penerbit_text = StringVar()
        self.penerbit_entry = Entry(self.frame2, textvariable=self.penerbit_text, font=18)
        self.penerbit_entry.grid(row=current_row, column=1)
        current_row += 1

        self.start = Button(self.frame2, text="Run Again", command=self.resume)
        self.start.grid(row=current_row, column=0)
        self.frame2.pack(expand="yes", side="left", fill='y')

    def videoLoop(self):
        # construct the argument parse and parse the arguments
        ap = argparse.ArgumentParser()
        ap.add_argument("-v", "--video",
                        help="path to the (optional) video file")
        ap.add_argument("-b", "--buffer", type=int, default=64,
                        help="max buffer size")
        args = vars(ap.parse_args())

        # define the lower and upper boundaries of the "green"
        # ball in the HSV color space, then initialize the
        # list of tracked points
        lower = {'blue': (110, 100, 100), 'red': (-10, 100, 100), 'green': (40, 70, 70),
                 'yellow': (20, 100, 117)}  # assign new item lower['blue'] = (93, 10, 0)
        upper = {'blue': (130, 255, 255), 'red': (10, 255, 255), 'green': (70, 255, 255), 'yellow': (40, 255, 255)}

        # database session
        con = sq.connect('data_comvis.db')  # dB browser for sqlite needed
        con.text_factory = str
        cmd_db = con.cursor()  # SQLite command, to connect to db so 'execute' method can be called

        # make a call for ShapeDetector class
        sd = ShapeDetector()

        stopEvent = threading.Event()

        # keep looping
        while not self.stopEvent.is_set():
            # grab the current frame
            self.foto = self.vs.read()
            # handle the frame from VideoCapture or VideoStream
            # resize the frame, blur it, and convert it to the HSV
            # color space
            self.frame = imutils.resize(self.foto, width=300)
            blurred = cv2.GaussianBlur(self.frame, (11, 11), 0)
            hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
            # construct a mask for the color "green", then perform
            # a series of dilations and erosions to remove any small
            # blobs left in the mask

            for key, value in upper.items():
                mask = cv2.inRange(hsv, lower[key], upper[key])
                mask = cv2.erode(mask, None, iterations=2)
                mask = cv2.dilate(mask, None, iterations=2)

                # find contours in the mask and initialize the current
                # (x, y) center of the ball
                cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
                                        cv2.CHAIN_APPROX_SIMPLE)
                cnts = imutils.grab_contours(cnts)
                center = None
                # only proceed if at least one contour was found
                if len(cnts) > 0:
                    # find the largest contour in the mask, then use
                    # it to compute the minimum enclosing circle and
                    # centroid
                    c = max(cnts, key=cv2.contourArea)
                    (x, y, w, h) = cv2.boundingRect(c)
                    M = cv2.moments(c)
                    center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
                    # only proceed if the radius meets a minimum size
                    if (x + y + w + h) > 400:
                        # Do when reach the minimum contours length
                        shape = sd.detect(c)
                        # draw the circle and centroid on the frame,
                        # then update the list of tracked points
                        cv2.putText(self.frame, key, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
                        cv2.drawContours(self.frame, [c], -1, (0, 0, 0), 2)

                        cv2.putText(self.frame, shape, (x + 15, y + 15), cv2.FONT_HERSHEY_SIMPLEX,
                                    0.5, (0, 0, 0), 2)
                        # cv2.circle(frame, (int(x), int(y)), int(radius),
                        #           (0, 255, 255), 2)
                        # cv2.circle(frame, center, 5, (0, 0, 255), -1)
                        # Gets data from database
                        text = key + " " + shape
                        plus = 'FROM buku INNER JOIN kode_buku ON buku.id = kode_buku.id WHERE kode_buku.kode = "' + text + '"'
                        cmd_db.execute('SELECT * ' + plus)

                        data = cmd_db.fetchall()  # Gets the data from the table

                        for row in data:
                            self.judul_text.set(row[1])
                            self.pengarang_text.set(row[2])
                            self.genre_text.set(row[3])
                            self.tahun_text.set(row[4])
                            self.penerbit_text.set(row[5])
                            self.penerbit_text.set(row[6])

                        con.commit()
                        self.stopEvent.set()
                # update the points queue
                # pts.appendleft(center)

            # loop over the set of tracked points
            for i in range(1, len(self.pts)):
                # if either of the tracked points are None, ignore
                # them
                if self.pts[i - 1] is None or self.pts[i] is None:
                    continue
                # otherwise, compute the thickness of the line and
                # draw the connecting lines
                thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
                cv2.line(self.frame, self.pts[i - 1], self.pts[i], (0, 0, 255), thickness)
            # show the frame to our screen

            # Show image in GUI
            #self.frame = cv2.cvtColor(self.frame, cv2.COLOR_HSV2BGR)
            #self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
            self.frame = Image.fromarray(self.frame)
            self.frame = ImageTk.PhotoImage(self.frame)
            #cv2.imshow("Frame", self.frame)
            #key = cv2.waitKey(1) & 0xFF

            # if the panel is not None, we need to initialize it
            if self.panel is None:
                self.panel = Label(image=self.frame)
                self.panel.image = self.frame
                self.panel.pack(side="left", padx=10, pady=10)

            # otherwise, simply update the panel
            else:
                self.panel.configure(image=self.frame)
                self.panel.image = self.frame

    def resume(self):
        # Resume the Thread
        kosong = ""
        self.judul_text.set(kosong)
        self.pengarang_text.set(kosong)
        self.genre_text.set(kosong)
        self.tahun_text.set(kosong)
        self.penerbit_text.set(kosong)
        self.penerbit_text.set(kosong)

        self.stopEvent = threading.Event()
        self.thread = threading.Thread(target=self.videoLoop, args=())
        self.thread.start()


# -*- coding: utf-8 -*-
"""\
This module tries to detect person names and assigns cable ids
to the mentioned person names.

Note: This script matches person names very naive. It's based on
string matching an cannot distinguish between the person JFK and
the airport JFK.

It expects a cable directory ./cable/ with the cables
and saves the cables into './cable2persons.csv'
"""
from __future__ import with_statement
import csv
import codecs
import cStringIO
from cablemap.core import cables_from_source

# Source: <http://docs.python.org/library/csv.html>
class UnicodeWriter:
    """
    A CSV writer which will write rows to CSV file "f",
    which is encoded in the given encoding.
    """

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
        # Redirect output to a queue
        self.queue = cStringIO.StringIO()
        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
        self.stream = f
        self.encoder = codecs.getincrementalencoder(encoding)()

    def writerow(self, row):
        self.writer.writerow([s.encode("utf-8") for s in row])
        # Fetch UTF-8 output from the queue ...
        data = self.queue.getvalue()
        data = data.decode("utf-8")
        # ... and reencode it into the target encoding
        data = self.encoder.encode(data)
        # write to the target stream
        self.stream.write(data)
        # empty queue
        self.queue.truncate(0)

    def writerows(self, rows):
        for row in rows:
            self.writerow(row)

def generate_csv(path, out):
    """\
    Walks through the `path` and generates the CSV file `out`
    """
    known_persons = ()
    with codecs.open(os.path.join(os.path.dirname(__file__), 'person_names.txt'), 'rb', 'utf-8') as f:
        known_persons = set((l.rstrip() for l in f))
    writer = UnicodeWriter(open(out, 'wb'), delimiter=';')
    for cable in cables_from_source(path):
        content = cable.content_body
        if not content:
            continue
        persons = [person for person in known_persons if person in content]
        if persons:
            row = [cable.reference_id]
            row.extend(persons)
            writer.writerow(row)

if __name__ == '__main__':
    import os
    if not os.path.isdir('./cable/'):
        raise Exception('Expected a directory "cable"')
    generate_csv('./cable/', './cable2persons.csv')


#!/usr/bin/env python3
"""
A script for running pylint
"""
import os
import sys
import re
import subprocess

MIN_SCORE = 9.5

THISDIR = os.path.dirname(os.path.realpath(__file__))
RCFILE = os.path.join(THISDIR, "pylintrc")
PYLINT_ARGS = ["--rcfile=%s" % RCFILE,
               "--exit-zero"]

PYLINT_SCORE_REGEX = re.compile(r"^Your code has been rated at (\S+?)/10")

# Modify path to get the import checks right
sys.path.insert(0, os.path.join(THISDIR, "../kratos"))

if len(sys.argv) > 1:
    ARGS = sys.argv[1:]
else:
    ARGS = [os.getcwd()]

def main():
    """
    Pylint runner
    """
    output = subprocess.check_output(
        [sys.executable, "-m", "pylint"] +
        PYLINT_ARGS +
        ARGS).decode()

    print(f"{output}")
    lines = output.replace("\r", "").split("\n")
    lines = [line for line in lines if line.strip() != ""]
    pylint_score = float(PYLINT_SCORE_REGEX.findall(lines[-1])[0])

    if pylint_score >= MIN_SCORE:
        print(f"Scored {pylint_score}/10, which is higher than the limit: {MIN_SCORE}\n")
        sys.exit(0)
    else:
        print(f"Scored {pylint_score}/10, which is lower than the limit: {MIN_SCORE}\n")
        sys.exit(1)

if __name__ == "__main__":
    main()


#!/usr/bin/env python

"""
recognize CAPTCHA at 2ch.hk

examples:
  python {title} vis     -i captcha.png
  python {title} collect -o captchas/ -k ag.txt
  python {title} train   -i captchas/ -o my.net
  python {title} ocr     -i captcha.png -n my.net
  python {title} serve   -n my.net
"""

from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from sklearn.preprocessing import LabelBinarizer

import os
import os.path
import glob
import re
import sys
import time
import errno
import argparse
from datetime import datetime
import threading
import traceback
import numpy as np
import cv2
import requests
import bottle
from keras.models import load_model
from helpers import resize_to_fit
from imutils import paths
import numpy as np
import imutils
import cv2
import pickle

__title__ = 'chaptcha.py'
__version__ = '0.0.1'
__license__ = 'CC0'

MODEL_FILENAME = "captcha_model.hdf5"
MODEL_LABELS_FILENAME = "model_labels.dat"

CAPTCHA_IMAGE_FOLDER = "dodgeCaptch"
OUTPUT_FOLDER = "cleaned_data_set"
counts = {}

NUM_CHARS = 0
# NUM_CHARS = 7
CAPTCHA_WIDTH = 200
CAPTCHA_HEIGHT = 80
CH_WIDTH = 25
CH_HEIGHT = 80
LINE_THICK = 2
MAX_LINE_THICKNESS = 8
MIN_DISTANCE = 7

# See <https://github.com/numpy/numpy/issues/7112>.
_CONSTANT = str('constant')

# Load up the model labels (so we can translate model predictions to actual letters)
with open(MODEL_LABELS_FILENAME, "rb") as f:
    lb = pickle.load(f)

# Load the trained neural network
model = load_model(MODEL_FILENAME)

def check_image(img):
    assert img is not None, 'cannot read image'
    assert img.shape == (CAPTCHA_HEIGHT, CAPTCHA_WIDTH), 'bad image dimensions'

def get_image(fpath):
    img = cv2.imread(fpath, 0)
    check_image(img)
    return cv2.threshold(img, 200, 255, cv2.THRESH_BINARY)[1]

def segment(img):
    chars = []
    lineStarted = False
    lineEnded = False
    foundStart = False
    startX = 0
    # endX = 0
    for col in range(img.shape[1]):
        isWhite = True
        cuts = 0
        thickness = 0
        distance = 0
        for x in range(0, CAPTCHA_HEIGHT):
            if (img[x, col] < 255):
                lineStarted = True
                if (isWhite):
                    cuts = cuts + 1
                    isWhite = False
                thickness = thickness + 1
                distance = distance + 1
            else:
                isWhite = True
            if (x == CAPTCHA_HEIGHT-1):
                # print("cuts: " + str(cuts))
                if (lineStarted and cuts == 0):
                    lineEnded = True
                if (lineEnded):
                    if (cuts >= 1 and not (foundStart)):
                        startX = col
                        foundStart = True
                    elif (lineEnded and foundStart and cuts == 0):
                        crop_img = img[0:79, startX-1:col]
                        chars.append(cv2.resize(crop_img, (25, 80)))
                        # cv2.imshow("cropped", crop_img)
                        # cv2.waitKey(0)
                        # cv2.destroyAllWindows()
                        foundStart = False
                elif (not lineEnded):
                    if (cuts >= 2 and not foundStart):
                        startX = col
                        foundStart = True
                    elif (cuts <= 1 and foundStart and (not thickness > MAX_LINE_THICKNESS) and (not distance >= MIN_DISTANCE)):
                        crop_img = img[0:79, startX-1:col]
                        chars.append(cv2.resize(crop_img, (25, 80)))
                        # cv2.imshow("cropped", crop_img)
                        # cv2.waitKey(0)
                        # cv2.destroyAllWindows()
                        foundStart = False
    return chars

def main():
    # Get a list of all the captcha images we need to process
    captcha_image_files = glob.glob(os.path.join(CAPTCHA_IMAGE_FOLDER, "*"))
    counts = {}
    images = []
    labels = []
    correctCount = 0
    totalCount = 0
    correctTotalCaptcha = 0
    totalCaptcha = 0
    # loop over the image paths
    for (i, captcha_image_file) in enumerate(captcha_image_files):

        print("[INFO] processing image {}/{}".format(i +
                                                     1, len(captcha_image_files)))
        filename = os.path.basename(captcha_image_file)
        captcha_correct_text = os.path.splitext(filename)[0]

        # Extract the letter from the original image
        captcha_chars = segment(
            get_image(CAPTCHA_IMAGE_FOLDER + "/" + filename))
        if (len(captcha_chars) == len(captcha_correct_text)):
            predictions = []
            for letter_image, letter_text in zip(captcha_chars, captcha_correct_text):
                #folder_name = letter_text
                #letter_image = np.expand_dims(letter_image, axis=2)

                #    folder_name = letter_text
                letter_image = resize_to_fit(letter_image, 25, 80)
                letter_image = np.expand_dims(letter_image, axis=2)
                letter_image = np.expand_dims(letter_image, axis=0)
                # if (not letter_text.isdigit() and letter_text.islower()):
                #    folder_name = "l" + letter_text
                # elif (not letter_text.isdigit() and not letter_text.islower()):
                #    folder_name = "u" + letter_text
                # images.append(letter_image)
                # labels.append(letter_text)
                prediction = model.predict(letter_image)

                # Convert the one-hot-encoded prediction back to a normal letter

                letter = lb.inverse_transform(prediction)[0]
                if (len(letter) == 2):
                    letter = letter[1]

                if (letter == letter_text):
                    correctCount = correctCount+1
                predictions.append(letter)
                totalCount = totalCount+1
                # print(folder_name)
                # Get the folder to save the image in
                #save_path = os.path.join(OUTPUT_FOLDER, folder_name)

                # if the output directory does not exist, create it
                # if not os.path.exists(save_path):
                #    os.makedirs(save_path)

                # write the letter image to a file
                count = counts.get(letter_text, 1)
                # p = os.path.join(
                #    save_path, "{}.png".format(str(count).zfill(6)))

                #cv2.imwrite(p, letter_image)

                # increment the count for the current key
                counts[letter_text] = count + 1
            captcha_text = "".join(predictions)
            print("CAPTCHA text is: {}".format(captcha_text))
            print("Correct text is: {}".format(captcha_correct_text))
            totalCaptcha = totalCaptcha+1
            if(captcha_text.lower() == captcha_correct_text.lower()):
                correctTotalCaptcha = correctTotalCaptcha+1
        else:
            with open("failedtestlist.txt", "a") as failedlist:
                failedlist.write("{}\n".format(filename))
                failedlist.close()
    print("Character By Character accuracy", correctCount/totalCount)
    print("total accuracy", correctTotalCaptcha/totalCaptcha)

    #labels1= np.array(labels)
    #data = np.array(images, dtype="float") / 255.0
    # print(labels1.shape)
    # print(data.shape)
    # scores=model.evaluate(data,labels1,verbose=1)
    #print("Test loss",scores[0])
    #print("Test Accuracy",scores[1])

def rescale_by_width(image, target_width, method=cv2.INTER_LANCZOS4):
    """Rescale `image` to `target_width` (preserving aspect ratio)."""
    h = int(round(target_width * image.shape[0] / image.shape[1]))
    return cv2.resize(image, (target_width, h), interpolation=method)

if __name__ == '__main__':
    main()


from guizero import App, PushButton, Text

app = App(title="Reaction Time", width = 900, height = 400, bg="white")
number = 0

def do_nothing():
    global number
    print ("Button Pressed!")
    app.bg = "green"
    number += 1
    Text.value = number

Text = Text(app, text = number, size = 20, align = "bottom")

button = PushButton(app, command=do_nothing)
app.display()


#! /usr/bin/env python3

import re
concert = "Katherine went to the concert to see Catheryn and the Cathryn’s. She ran into her friend Kathryn, who introduced Katherine to her friend Catherine. Together, they enjoyed the concert while texting inaudible snippets to their mutual friend, Kathrin. Their mercurial friend, Katharine, felt left out."
concert = concert.rstrip("\n")
print(concert)

#Finding positions of all Katherines
match = re.finditer(r"(K|C)(ath)[a-z]{1,6}", concert)
name = []
start_position = []
stop_position = []
length = []
for find in match:
    find_start = find.start()
    start_position.append(find_start)
    find_end = find.end()
    stop_position.append(find_end)
    print(str(find_start) + " to " + str(find_end))

#Finding all Katherines and their lengths
match = re.findall("((K|C)ath[a-z]{1,6})", concert)
for i in match:
    print(i[0])
    name.append(i[0])
    print("length =", len(str(i[0])))
    length.append(len(i[0]))

# Print tab delimited output
for i in range(0,8):
    print(name[i], start_position[i], stop_position[i], length[i], sep ="\t")


import json
import logging
import os
import shutil
import random
import time
import re
import numpy as np
import torch

from .data_utils.example import Batch
from .data_utils.iterator import Iterator

logger = logging.getLogger(__name__)

class SpecialTokenMap:
    def __init__(self, pattern, forward_func, backward_func=None):
        """
        Inputs:
            pattern: a regex pattern
            forward_func: a function with signature forward_func(str) -> str
            backward_func: a function with signature backward_func(str) -> list[str]
        """
        if isinstance(forward_func, list):
            self.forward_func = lambda x: forward_func[int(x)%len(forward_func)]
        else:
            self.forward_func = forward_func

        if isinstance(backward_func, list):
            self.backward_func = lambda x: backward_func[int(x)%len(backward_func)]
        else:
            self.backward_func = backward_func

        self.pattern = pattern

    def forward(self, s: str):
        reverse_map = []
        matches = re.finditer(self.pattern, s)
        if matches is None:
            return s, reverse_map
        for match in matches:
            occurrence = match.group(0)
            parameter = match.group(1)
            replacement = self.forward_func(parameter)
            s = s.replace(occurrence, replacement)
            reverse_map.append((self, occurrence))
        return s, reverse_map

    def backward(self, s: str, occurrence: str):
        match = re.match(self.pattern, occurrence)
        parameter = match.group(1)
        if self.backward_func is None:
            list_of_strings_to_match = [self.forward_func(parameter)]
        else:
            list_of_strings_to_match = sorted(self.backward_func(parameter), key=lambda x:len(x), reverse=True)
        for string_to_match in list_of_strings_to_match:
            l = [' '+string_to_match+' ', string_to_match+' ', ' '+string_to_match]
            o = [' '+occurrence+' ', occurrence+' ', ' '+occurrence]
            new_s = s
            for i in range(len(l)):
                new_s = re.sub(l[i], o[i], s, flags=re.IGNORECASE)
                if s != new_s:
                    break
            if s != new_s:
                s = new_s
                break

        return s

def tokenizer(s):
    return s.split()

def mask_special_tokens(string: str):
    exceptions = [match.group(0) for match in re.finditer('[A-Za-z:_.]+_[0-9]+', string)]
    for e in exceptions:
        string = string.replace(e, '<temp>', 1)
    return string, exceptions

def unmask_special_tokens(string: str, exceptions: list):
    for e in exceptions:
        string = string.replace('<temp>', e, 1)
    return string

def detokenize(string: str):
    string, exceptions = mask_special_tokens(string)
    tokens = ["'d", "n't", "'ve", "'m", "'re", "'ll", ".", ",", "?", "!", "'s", ")", ":"]
    for t in tokens:
        string = string.replace(' ' + t, t)
    string = string.replace("( ", "(")
    string = string.replace('gon na', 'gonna')
    string = string.replace('wan na', 'wanna')
    string = unmask_special_tokens(string, exceptions)
    return string

def tokenize(string: str):
    string, exceptions = mask_special_tokens(string)
    tokens = ["'d", "n't", "'ve", "'m", "'re", "'ll", ".", ",", "?", "!", "'s", ")", ":"]
    for t in tokens:
        string = string.replace(t, ' ' + t)
    string = string.replace("(", "( ")
    string = string.replace('gonna', 'gon na')
    string = string.replace('wanna', 'wan na')
    string = re.sub('\s+', ' ', string)
    string = unmask_special_tokens(string, exceptions)
    return string.strip()

def lower_case(string):
    string, exceptions = mask_special_tokens(string)
    string = string.lower()
    string = unmask_special_tokens(string, exceptions)
    return string

def get_number_of_lines(file_path):
    count = 0
    with open(file_path) as f:
        for line in f:
            count += 1
    return count

def get_part_path(path, part_idx):
    if path.endswith(os.path.sep):
        has_separator = True
        path = path[:-1]
    else:
        has_separator = False
    return path + '_part' + str(part_idx+1) + (os.path.sep if has_separator else '')

def split_folder_on_disk(folder_path, num_splits):
    new_folder_paths = [get_part_path(folder_path, part_idx) for part_idx in range(num_splits)]
    for subdir, dirs, files in os.walk(folder_path):
        for file in files:
            new_file_paths = [os.path.join(subdir.replace(folder_path, new_folder_paths[part_idx]), file) for part_idx in range(num_splits)]
            split_file_on_disk(os.path.join(subdir, file), num_splits, output_paths=new_file_paths)
    return new_folder_paths

def split_file_on_disk(file_path, num_splits, output_paths=None):
    """
    """
    number_of_lines = get_number_of_lines(file_path)

    all_output_paths = []
    all_output_files = []
    for part_idx in range(num_splits):
        if output_paths is None:
            output_path = get_part_path(file_path, part_idx)
        else:
            output_path = output_paths[part_idx]
        all_output_paths.append(output_path)
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        all_output_files.append(open(output_path, 'w'))

    with open(file_path, 'r') as input_file:
        output_file_idx = 0
        for line in input_file:
            all_output_files[output_file_idx].write(line)
            output_file_idx = (output_file_idx + 1) % len(all_output_files)

    for f in all_output_files:
        f.close()

    return all_output_paths

def combine_folders_on_disk(folder_path_prefix, num_files, line_group_size, delete=False):
    folder_paths = [get_part_path(folder_path_prefix, part_idx) for part_idx in range(num_files)]
    new_to_olds_map = {}
    for i in range(num_files):
        for subdir, dirs, files in os.walk(folder_paths[i]):
            for file in files:
                new_file_path = os.path.join(subdir.replace(folder_paths[i], folder_path_prefix), file)
                if new_file_path not in new_to_olds_map:
                    new_to_olds_map[new_file_path] = []
                new_to_olds_map[new_file_path].append(os.path.join(subdir, file))

    for new, olds in new_to_olds_map.items():
        os.makedirs(os.path.dirname(new), exist_ok=True)
        with open(new, 'w') as combined_file:
            if new.endswith('.json'):
                new_json = None
                for old in olds:
                    with open(old, 'r') as f:
                        if new_json is None:
                            new_json = json.load(f)
                        else:
                            for k, v in json.load(f).items():
                                new_json[k] += v
                for k, v in new_json.items():
                    new_json[k] /= float(num_files)
                json.dump(new_json, combined_file)
            else:
                all_old_file_contents = []
                for old in olds:
                    with open(old, 'r') as f:
                        all_old_file_contents.append([line for line in f])
                old_file_idx = 0
                all_indices = [0] * len(all_old_file_contents)
                finished_reading = [False] * len(all_old_file_contents)
                while True:
                    if finished_reading[old_file_idx]:
                        old_file_idx = (old_file_idx + 1) % len(all_old_file_contents)
                        continue
                    for i in range(line_group_size):
                        line = all_old_file_contents[old_file_idx][all_indices[old_file_idx]]
                        combined_file.write(line)
                        all_indices[old_file_idx] += 1
                    if all_indices[old_file_idx] == len(all_old_file_contents[old_file_idx]):
                        finished_reading[old_file_idx] = True
                        if all(finished_reading):
                            break
                    old_file_idx = (old_file_idx + 1) % len(all_old_file_contents)

    if delete:
        for folder in folder_paths:
            shutil.rmtree(folder)

def combine_files_on_disk(file_path_prefix, num_files, line_group_size, delete=False):
    all_input_file_contents = []
    all_input_file_paths = []
    for i in range(num_files):
        input_file_path = get_part_path(file_path_prefix, i)
        all_input_file_paths.append(input_file_path)
        with open(input_file_path, 'r') as f:
            all_input_file_contents.append([line for line in f])

    all_indices = [0] * len(all_input_file_contents)
    finished_reading = [False] * len(all_input_file_contents)
    input_file_idx = 0
    with open(file_path_prefix, 'w') as combined_file:
        while True:
            if finished_reading[input_file_idx]:
                input_file_idx = (input_file_idx + 1) % len(all_input_file_contents)
                continue
            for i in range(line_group_size):
                line = all_input_file_contents[input_file_idx][all_indices[input_file_idx]]
                combined_file.write(line)
                all_indices[input_file_idx] += 1
            if all_indices[input_file_idx] == len(all_input_file_contents[input_file_idx]):
                finished_reading[input_file_idx] = True
                if all(finished_reading):
                    break
            input_file_idx = (input_file_idx + 1) % len(all_input_file_contents)

    if delete:
        for file_path in all_input_file_paths:
            os.remove(file_path)

def map_filter(callable, iterable):
    output = []
    for element in iterable:
        new_element = callable(element)
        if new_element is not None:
            output.append(new_element)
    return output

def preprocess_examples(args, tasks, splits, logger=None, train=True):
    min_length = 1
    max_context_length = args.max_train_context_length if train else args.max_val_context_length
    is_too_long = lambda ex: (len(ex.answer) > args.max_answer_length or
                              len(ex.context) > max_context_length)
    is_too_short = lambda ex: (len(ex.answer) < min_length or
                               len(ex.context) < min_length)

    for task, s in zip(tasks, splits):
        if logger is not None:
            logger.info(f'{task.name} has {len(s.examples)} examples')

        l = len(s.examples)
        s.examples = map_filter(
            lambda ex: task.preprocess_example(ex, train=train, max_context_length=max_context_length),
            s.examples)

        if train:
            l = len(s.examples)
            s.examples = [ex for ex in s.examples if not is_too_long(ex)]
            if len(s.examples) < l:
                if logger is not None:
                    logger.info(f'Filtering out long {task.name} examples: {l} -> {len(s.examples)}')

            l = len(s.examples)
            s.examples = [ex for ex in s.examples if not is_too_short(ex)]
            if len(s.examples) < l:
                if logger is not None:
                    logger.info(f'Filtering out short {task.name} examples: {l} -> {len(s.examples)}')

        if logger is not None:
            context_lengths = [len(ex.context) for ex in s.examples]
            question_lengths = [len(ex.question) for ex in s.examples]
            answer_lengths = [len(ex.answer) for ex in s.examples]

            logger.info(
                f'{task.name} context lengths (min, mean, max): {np.min(context_lengths)}, {int(np.mean(context_lengths))}, {np.max(context_lengths)}')
            logger.info(
                f'{task.name} question lengths (min, mean, max): {np.min(question_lengths)}, {int(np.mean(question_lengths))}, {np.max(question_lengths)}')
            logger.info(
                f'{task.name} answer lengths (min, mean, max): {np.min(answer_lengths)}, {int(np.mean(answer_lengths))}, {np.max(answer_lengths)}')

        if logger is not None:
            logger.info('Tokenized examples:')
            for ex in s.examples[:10]:
                logger.info('Context: ' + ' '.join([token.strip() for token in ex.context]))
                logger.info('Question: ' + ' '.join([token.strip() for token in ex.question]))
                logger.info('Answer: ' + ' '.join([token.strip() for token in ex.answer]))

def init_devices(args, devices=None):
    if not torch.cuda.is_available():
        return [torch.device('cpu')]
    if not devices:
        return [torch.device('cuda:'+str(i)) for i in range(torch.cuda.device_count())]
    return [torch.device(ordinal) for ordinal in devices]

def set_seed(args):
    np.random.seed(args.seed)
    random.seed(args.seed)
    torch.manual_seed(args.seed)
    torch.cuda.manual_seed_all(args.seed)

def get_trainable_params(model, name=False):
    if name:
        return list(filter(lambda p: p[1].requires_grad, model.named_parameters()))
    else:
        return list(filter(lambda p: p.requires_grad, model.parameters()))

def log_model_size(logger, model, model_name):
    num_param = sum([p.nelement() for p in model.parameters() if p.requires_grad])
    logger.info(f'{model_name} has {num_param:,} parameters')

def elapsed_time(log):
    t = time.time() - log.start
    day = int(t // (24 * 3600))
    t = t % (24 * 3600)
    hour = int(t // 3600)
    t %= 3600
    minutes = int(t // 60)
    t %= 60
    seconds = int(t)
    return f'{day:02}:{hour:02}:{minutes:02}:{seconds:02}'

def make_data_loader(dataset, numericalizer, batch_size, device=None, paired=False, max_pairs=None, train=False,
                     valid=False, append_question_to_context_too=False, override_question=None, override_context=None):

    iterator = Iterator(dataset,
                        batch_size,
                        shuffle=train,
                        repeat=train,
                        use_data_batch_fn=train,
                        use_data_sort_key=train)

    collate_function = lambda minibatch: Batch.from_examples(minibatch, numericalizer, device=device,
                                           paired=paired and train, max_pairs=max_pairs, groups=iterator.groups,
                                           append_question_to_context_too=append_question_to_context_too,
                                           override_question=override_question, override_context=override_context)

    return torch.utils.data.DataLoader(iterator, batch_size=None, collate_fn=collate_function)

def pad(x, new_channel, dim, val=None):
    if x.size(dim) > new_channel:
        x = x.narrow(dim, 0, new_channel)
    channels = x.size()
    assert (new_channel >= channels[dim])
    if new_channel == channels[dim]:
        return x
    size = list(channels)
    size[dim] = new_channel - size[dim]
    padding = x.new(*size).fill_(val)
    return torch.cat([x, padding], dim)

def have_multilingual(task_names):
    return any(['multilingual' in name for name in task_names])

def load_config_json(args):
    args.almond_type_embeddings = False
    with open(os.path.join(args.path, 'config.json')) as config_file:
        config = json.load(config_file)
        retrieve = ['model', 'seq2seq_encoder', 'seq2seq_decoder', 'transformer_layers', 'rnn_layers', 'rnn_zero_state',
                    'transformer_hidden', 'dimension', 'rnn_dimension', 'load', 'max_val_context_length',
                    'transformer_heads', 'max_output_length', 'max_generative_vocab', 'lower',
                    'encoder_embeddings', 'context_embeddings', 'question_embeddings', 'decoder_embeddings',
                    'trainable_decoder_embeddings', 'trainable_encoder_embeddings', 'train_encoder_embeddings',
                    'train_context_embeddings', 'train_question_embeddings', 'locale', 'use_pretrained_bert',
                    'train_context_embeddings_after', 'train_question_embeddings_after',
                    'pretrain_context', 'pretrain_mlm_probability', 'force_subword_tokenize',
                    'append_question_to_context_too', 'almond_preprocess_context', 'almond_lang_as_question',
                    'override_question', 'override_context']

        # train and predict scripts have these arguments in common. We use the values from train only if they are not provided in predict
        if 'num_beams' in config and not isinstance(config['num_beams'], list):
            # num_beams used to be an integer in previous versions of the code
            config['num_beams'] = [config['num_beams']]
        overwrite = ['val_batch_size', 'num_beams', 'num_outputs', 'no_repeat_ngram_size', 'top_p', 'top_k', 'repetition_penalty', 'temperature', 'reduce_metrics']
        for o in overwrite:
            if o not in args or getattr(args, o) is None:
                retrieve.append(o)

        for r in retrieve:
            if r in config:
                setattr(args, r, config[r])
            # These are for backward compatibility with models that were trained before we added these arguments
            elif r == 'almond_lang_as_question':
                setattr(args, r, False)
            elif r == 'locale':
                setattr(args, r, 'en')
            elif r in ('trainable_decoder_embedding', 'trainable_encoder_embeddings', 'pretrain_context',
                       'train_context_embeddings_after', 'train_question_embeddings_after'):
                setattr(args, r, 0)
            elif r == 'pretrain_mlm_probability':
                setattr(args, r, 0.15)
            elif r == 'context_embeddings':
                if args.seq2seq_encoder == 'Coattention':
                    setattr(args, r, '')
                else:
                    setattr(args, r, args.encoder_embeddings)
            elif r == 'question_embeddings':
                setattr(args, r, args.encoder_embeddings)
            elif r == 'train_encoder_embeddings':
                setattr(args, r, False)
            elif r == 'train_context_embeddings':
                if args.seq2seq_encoder == 'Coattention':
                    setattr(args, r, False)
                else:
                    setattr(args, r, args.train_encoder_embeddings)
            elif r == 'train_question_embeddings':
                setattr(args, r, args.train_encoder_embeddings)
            elif r == 'rnn_dimension':
                setattr(args, r, args.dimension)
            elif r == 'rnn_zero_state':
                setattr(args, r, 'zero')
            elif r == 'use_pretrained_bert':
                setattr(args, r, True)
            elif r in ('append_question_to_context_too', 'almond_preprocess_context'):
                setattr(args, r, False)
            elif r == 'num_beams':
                setattr(args, r, [1])
            elif r == 'num_outputs':
                setattr(args, r, [1])
            elif r == 'no_repeat_ngram_size':
                setattr(args, r, [0])
            elif r == 'top_p':
                setattr(args, r, [1.0])
            elif r == 'top_k':
                setattr(args, r, [0])
            elif r == 'repetition_penalty':
                setattr(args, r, [1.0])
            elif r == 'temperature':
                setattr(args, r, [0.0])
            elif r == 'reduce_metrics':
                setattr(args, r, 'max')
            else:
                setattr(args, r, None)
        args.dropout_ratio = 0.0

    args.best_checkpoint = os.path.join(args.path, args.checkpoint_name)


# PySerial (Tested with v3.3)
import serial

# Connect to our Arduino-based CAN Adapter
arduino = serial.Serial("/dev/tty.usbmodem141101", 115200, timeout=.1)

# Send CAN Message with our custom adapter implementation
command = ">(4081) 10 1 12 1 255 0 0 0"
message = bytes(command.encode())
arduino.write(message)


from PIL import Image
import numpy as np
import math

def to_greyscale_balanced (image):
    data = image.load()

    result = Image.new('L', image.size)

    new_data = result.load()

    for x in range(image.size[0]):
        for y in range(image.size[1]):
            new_data[x, y] = round(0.3 * data[x,y][0] + 0.59 * data[x,y][1] + 0.11 * data[x,y][2])
    return result

def to_grayscale_dumb(image):
    data = image.load()

    result = Image.new('L', image.size)

    new_data = result.load()

    for x in range(image.size[0]):
        for y in range(image.size[1]):
            new_data[x, y] = round(data[x,y][0] + data[x,y][1] + data[x,y][2] / 3)
    return result

def threshold(image):
    bins = np.arange(image.min() - 1, image.max() + 1)
    hist, base = np.histogram(image, bins=bins, density=True)
    base = base[1:].astype(np.uint8)

    w0_raw = np.cumsum(hist)
    w1_raw = np.ones(shape=w0_raw.shape) - w0_raw
    t_rank = 0
    i_max = 0
    for i, (w0, w1) in enumerate(zip(w0_raw, w1_raw)):
        m0 = np.sum(base[:i] * hist[:i] / w0)
        m1 = np.sum(base[i + 1:] * hist[i + 1:] / w1)
        d0 = np.sum(hist[:i] * (base[:i] - m0)**2)
        d1 = np.sum(hist[i + 1:] * (base[i + 1:] - m1)**2)
        d_all = w0 * d0 + w1 * d1
        d_class = w0 * w1 * (m0 - m1)**2
        if d_all == 0:
            i_max = i
            break
        if d_class / d_all > t_rank:
            t_rank = d_class / d_all
            i_max = i

    return base[i_max]
def findMean(data, threshold):
    data_ft = data.flatten()
    data_1 = data_ft[data_ft >= threshold]
    data_2 = data_ft[data_ft < threshold]
    mean_1 = data_1.mean() if data_1.size > 0 else 0
    mean_2 = data_2.mean() if data_2.size > 0 else 0
    return mean_1, mean_2

def Helper(x, y, inner, outer, old_image, new_image, diff):
    s_window = old_image[y:min(y + inner, old_image.shape[0]), x:min(x + inner, old_image.shape[1])]
    l_window = old_image[max(y - outer // 2 + 1, 0):min(y + outer // 2 + inner - 1, old_image.shape[0]),
               max(x - outer // 2 + 1, 0):min(x + outer // 2 + inner - 1, old_image.shape[1])]

    t = threshold(l_window)
    m1, m2 = findMean(l_window, t)

    if abs(m1 - m2) >= diff:
        new_image[y:min(y + inner, old_image.shape[0]),
                  x:min(x + inner, old_image.shape[1])][s_window > t] = 255
    else:
        center = s_window[s_window.shape[0] // 2, s_window.shape[1] // 2]
        if abs(m1 - center) < abs(m2 - center):
            new_image[y:min(y + inner, old_image.shape[0]),
                      x:min(x + inner, old_image.shape[1])] = 255

def Eikvel_binarization(old_image, diff, inner, outer):
    new_image = np.zeros(shape=old_image.shape)

    x, y = 0, 0
    while y + inner <= old_image.shape[0]:
        if y % 2 == 0:
            while x + inner < old_image.shape[1]:
                Helper(x, y, inner, outer, old_image, new_image, diff)
                x += inner
        else:
            while x - inner > 0:
                Helper(x, y, inner, outer, old_image, new_image, diff)
                x -= inner

        y += inner

    return new_image.astype(np.uint8)

if __name__ == '__main__':

    # for imgn in range(1, 5):
    #     with Image.open(f'./src/sample{imgn}.bmp').convert('RGB') as img:
    #         print(f'Opened image #{imgn}')
    #         tmp1 = to_greyscale_balanced(img)
    #         tmp1.save(f'./out/grayscale{imgn}.bmp')
    #         print(f'Image #{imgn} grayscale done')
    #         print(f'Starting binarizing')
    #         tmp2 = Image.fromarray(Eikvel_binarization(np.array(tmp1), 5, 3, 15), 'L')
    #         tmp2.save(f'./out/binary{imgn}.bmp')
    #         print(f'Image #{imgn} done')
    imgn = 5

    with Image.open(f'./src/sample{imgn}.bmp').convert('RGB') as img:
        print(f'Opened image #{imgn}')
        tmp1 = to_greyscale_balanced(img)
        tmp1.save(f'./out/grayscale{imgn}.bmp')
        print(f'Image #{imgn} grayscale done')
        print(f'Starting binarizing')
        tmp2 = Image.fromarray(Eikvel_binarization(np.array(tmp1), 5, 3, 15), 'L')
        tmp2.save(f'./out/binary{imgn}.bmp')
        print(f'Image #{imgn} done')


import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from matplotlib import patches
from matplotlib.backend_bases import MouseButton
from matplotlib import colors
import matplotlib as mpl
from os import listdir

N=10 #Grid size (NxN)
max_iter=99999999999
speed=1
paused=True
color0 = 'black' #tile 0
color1 = 'grey' #tile 1
color2 = 'blue' #ant on tile 0 facing up
color3 = 'red' #ant on tile 0 facing right
color4 = 'green' #ant on tile 0 facing down
color5 = 'yellow' #ant on tile 0 facing left
color6 = 'orange' #ant on tile 1 facing up
color7 = 'purple' #ant on tile 1 facing right
color8 = 'brown' #ant on tile 1 facing down
color9 = 'pink' #ant on tile 1 facing left
cmap=colors.ListedColormap([color0,color1,color2,color3,color4,color5,color6,color7,color8,color9])
bounds=[0,1,2,3,4,5,6,7,8,9,10]
norm = colors.BoundaryNorm(bounds, cmap.N)
mat=[[0 for j in range(N)] for i in range(N)]

fig,ax=plt.subplots(1,2,figsize=(12,8))
fig.canvas.manager.set_window_title("Langton's Ant")

def on_click(event):
    global mat
    global paused
    global N
    global speed
    global color0
    global color1
    global color2
    global color3
    global color4
    global color5
    global color6
    global color7
    global color8
    global color9
    global cmap

    if event.button is MouseButton.LEFT:
        if event.inaxes==ax[1]:
            if paused:
                new_mat=[item[:] for item in mat]
                if new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==0:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=2
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==2:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=3
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==3:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=4
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==4:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=5
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==5:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=0

                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==1:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=6
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==6:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=7
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==7:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=8
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==8:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=9
                elif new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==9:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=1

                mat=np.copy(new_mat)
        elif event.inaxes==ax[0]:
            if event.xdata>1 and event.xdata<5.2 and event.ydata>8 and event.ydata<10: #Button run/pause
                paused= not paused
                ax[0].clear()
                update_GUI(paused)
            elif event.xdata>1 and event.xdata<5.2 and event.ydata>5 and event.ydata<7: #Save board
                extent = ax[1].get_window_extent().transformed(fig.dpi_scale_trans.inverted())
                nombres=[]
                for images in listdir():
                    if (images.endswith(".png")):
                            nombres.append(images)
                num=1
                while "Ant_"+str(num)+".png" in nombres:
                    num+=1
                fig.savefig("Ant_"+str(num)+'.png', bbox_inches=extent)
            elif event.xdata>1 and event.xdata<5.2 and event.ydata>2 and event.ydata<4: #Button new 10
                paused=True
                ax[0].clear()
                update_GUI(paused)
                N=10
                mat=[[0 for j in range(N)] for i in range(N)]
            elif event.xdata>1 and event.xdata<5.2 and event.ydata>-1 and event.ydata<1: #Button new 50
                paused=True
                ax[0].clear()
                update_GUI(paused)
                N=50
                mat=[[0 for j in range(N)] for i in range(N)]
            elif event.xdata>7 and event.xdata<11.2 and event.ydata>8 and event.ydata<10: #Button random board
                paused=True
                ax[0].clear()
                update_GUI(paused)
                mat=[[np.random.choice([0,1]) for i in range(N)] for j in range(N)]

            elif event.xdata>7 and event.xdata<11.2 and event.ydata>5 and event.ydata<7: #change color
                color0 = list(np.random.choice(range(256), size=3)/255)
                color1 = list(np.random.choice(range(256), size=3)/255)
                color2 = list(np.random.choice(range(256), size=3)/255)
                color3 = list(np.random.choice(range(256), size=3)/255)
                color4 = list(np.random.choice(range(256), size=3)/255)
                color5 = list(np.random.choice(range(256), size=3)/255)
                color6 = list(np.random.choice(range(256), size=3)/255)
                color7 = list(np.random.choice(range(256), size=3)/255)
                color8 = list(np.random.choice(range(256), size=3)/255)
                color9 = list(np.random.choice(range(256), size=3)/255)
                cmap=colors.ListedColormap([color0,color1,color2,color3,color4,color5,color6,color7,color8,color9])
            elif event.xdata>7 and event.xdata<11.2 and event.ydata>2 and event.ydata<4: #Button new 25
                paused=True
                ax[0].clear()
                update_GUI(paused)
                N=25
                mat=[[0 for j in range(N)] for i in range(N)]
            elif event.xdata>7 and event.xdata<11.2 and event.ydata>-1 and event.ydata<1: #Button new 100
                paused=True
                ax[0].clear()
                update_GUI(paused)
                N=100
                mat=[[0 for j in range(N)] for i in range(N)]

    elif event.button is MouseButton.RIGHT:
        if event.inaxes==ax[1]:
            if paused:
                new_mat=[item[:] for item in mat]
                if new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==0 or new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==2 or new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==3 or new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==4 or new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]==5:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=1
                else:
                    new_mat[int(event.ydata+0.5)][int(event.xdata+0.5)]=0
                mat=np.copy(new_mat)

plt.connect('button_press_event', on_click)

def init():
    global mat
    ax[1].set_xlim(-0.5,N-0.5)
    ax[1].set_ylim(-0.5,N-0.5)
    ax[1].set_xticks([])
    ax[1].set_yticks([])
    grilla=ax[1].imshow(mat,cmap = cmap,norm=norm)

def update():
    global mat
    new_mat=np.copy(mat)

    for i in range(N):
        for j in range(N):
            if mat[i][j]!=0 and mat[i][j]!=1: #There is an ant
                if mat[i][j]==2: #Ant is facing up on a tile 0
                    new_mat[i][j]=1
                    if new_mat[i][(j+1)%N]==0 or new_mat[i][(j+1)%N]==1:
                        if mat[i][(j+1)%N]==0:
                            new_mat[i][(j+1)%N]=3
                        elif mat[i][(j+1)%N]==1:
                            new_mat[i][(j+1)%N]=7
                    else:
                        new_mat[i][(j+1)%N]=0

                elif mat[i][j]==3: #Ant is facing right on a tile 0
                    new_mat[i][j]=1
                    if new_mat[(i+1)%N][j]==0 or new_mat[(i+1)%N][j]==1:
                        if mat[(i+1)%N][j]==0:
                            new_mat[(i+1)%N][j]=4
                        elif mat[(i+1)%N][j]==1:
                            new_mat[(i+1)%N][j]=8
                    else:
                        new_mat[(i+1)%N][j]=0
                elif mat[i][j]==4: #Ant is facing down on a tile 0 ERROR
                    new_mat[i][j]=1
                    if new_mat[i][(j-1)%N]==0 or new_mat[i][(j-1)%N]==1:
                        if mat[i][(j-1)%N]==0:
                            new_mat[i][(j-1)%N]=5
                        elif mat[i][(j-1)%N]==1:
                            new_mat[i][(j-1)%N]=9
                    else:
                        new_mat[i][(j-1)%N]=0
                elif mat[i][j]==5: #Ant is facing left on a tile 0
                    new_mat[i][j]=1
                    if new_mat[(i-1)%N][j]==0 or new_mat[(i-1)%N][j]==1:
                        if mat[(i-1)%N][j]==0:
                            new_mat[(i-1)%N][j]=2
                        elif mat[(i-1)%N][j]==1:
                            new_mat[(i-1)%N][j]=6
                    else:
                        new_mat[(i-1)%N][j]=0
                elif mat[i][j]==6: #Ant is facing up on a tile 1
                    new_mat[i][j]=0
                    if new_mat[i][(j-1)%N]==0 or new_mat[i][(j-1)%N]==1:
                        if mat[i][(j-1)%N]==0:
                            new_mat[i][(j-1)%N]=5
                        elif mat[i][(j-1)%N]==1:
                            new_mat[i][(j-1)%N]=9
                    else:
                        new_mat[i][(j-1)%N]=0
                elif mat[i][j]==7: #Ant is facing right on a tile 1
                    new_mat[i][j]=0
                    if new_mat[(i-1)%N][j]==0 or new_mat[(i-1)%N][j]==1:
                        if mat[(i-1)%N][j]==0:
                            new_mat[(i-1)%N][j]=2
                        elif mat[(i-1)%N][j]==1:
                            new_mat[(i-1)%N][j]=6
                    else:
                        new_mat[(i-1)%N][j]=0
                elif mat[i][j]==8: #Ant is facing down on a tile 1
                    new_mat[i][j]=0
                    if new_mat[i][(j+1)%N]==0 or new_mat[i][(j+1)%N]==1:
                        if mat[i][(j+1)%N]==0:
                            new_mat[i][(j+1)%N]=3
                        elif mat[i][(j+1)%N]==1:
                            new_mat[i][(j+1)%N]=7
                    else:
                        new_mat[i][(j+1)%N]=0
                else: #Ant is facing left on a tile 1
                    new_mat[i][j]=0
                    if new_mat[(i+1)%N][j]==0 or new_mat[(i+1)%N][j]==1:
                        if mat[(i+1)%N][j]==0:
                            new_mat[(i+1)%N][j]=4
                        elif mat[(i+1)%N][j]==1:
                            new_mat[(i+1)%N][j]=8
                    else:
                        new_mat[(i+1)%N][j]=0

    return new_mat

def initialize(iter):
    global mat
    ax[1].clear()
    ax[1].set_xticks([])
    ax[1].set_yticks([])
    ax[1].set_xlabel("Right click: add/remove cell\nLeft click: change cell's state",fontsize=16)
    new_mat=update()
    mat=np.copy(new_mat)
    ax[1].imshow(mat,cmap = cmap,norm=norm)

def update_GUI(paused_):
    ax[0].set_xlim(0,12)
    ax[0].set_ylim(-2,12)
    ax[0].set_aspect(1)
    ax[0].axis("off")

    if paused:
        ax[0].add_patch(patches.Rectangle((1, 8), 4.2, 2, edgecolor='Black',facecolor='green', linewidth=2)) #Pause/run
        ax[0].text(2.2,8.6,"Run",fontsize=24)
    else:
        ax[0].add_patch(patches.Rectangle((1, 8), 4.2, 2, edgecolor='Black',facecolor='red', linewidth=2)) #Pause/run
        ax[0].text(1.7,8.6,"Pause",fontsize=24)

    ax[0].add_patch(patches.Rectangle((7, 8), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #random board
    ax[0].text(7.15,8.1,"Random\n  board",fontsize=24)

    ax[0].add_patch(patches.Rectangle((1, 5), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #save frame
    ax[0].text(1.75,5.1,"Save\nboard",fontsize=24)

    ax[0].add_patch(patches.Rectangle((7, 5), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #change color
    ax[0].text(7.3,5.1,"Change\n  color",fontsize=24)

    ax[0].add_patch(patches.Rectangle((1, 2), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #new 10x10
    ax[0].text(1.7,2.1," New\n10x10",fontsize=24)

    ax[0].add_patch(patches.Rectangle((7, 2), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #new 25x25
    ax[0].text(7.7,2.1," New\n25x25",fontsize=24)

    ax[0].add_patch(patches.Rectangle((1, -1), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #new 50x50
    ax[0].text(1.7,-0.9," New\n50x50",fontsize=24)

    ax[0].add_patch(patches.Rectangle((7, -1), 4.2, 2, edgecolor='Black',facecolor='white', linewidth=2)) #new 100x100
    ax[0].text(7.005,-0.9,"   New\n100x100",fontsize=24)

    ax[0].text(1,-3.5,"Simulation must be paused in order\nto interact with the board (change the\nstate of a cell).",fontsize=14)
    ax[0].text(0,11.5,"Rules (at each step in time, for each ant):\n1- If it is at a tile of type 1, turn 90° clockwise, flip the type of the tile, move forward one cell.\n2- If it is at a tile of type 2, turn 90° counter-clockwise, flip the type of the tile, move forward one cell. \n3- If two or more ants moev to the same tile, they die.",fontsize=14)

def animate(iter):
    global mat
    ax[1].clear()
    ax[1].set_xticks([])
    ax[1].set_yticks([])
    if not paused:
        ax[1].set_xlabel("Simulation running",fontsize=16)
        new_mat=update()
        mat=np.copy(new_mat)
    else:
        ax[1].set_xlabel("Right click: change tile type\nLeft click: add/rotate/remove ant from tile",fontsize=16)
    ax[1].imshow(mat,cmap = cmap,norm=norm) #ACA ESTA EL PROBLEMA
    xcenter=(-0.5+(N-0.5))/2
    ycenter=(-0.5+(N-0.5))/2
    ax[1].text(xcenter-N/1.7,ycenter+N/1.45,'Tile 1:',fontsize=16)
    ax[1].text(xcenter-N/2.5,ycenter+N/1.45,'Empty',weight="bold",color=color0,fontsize=16)
    ax[1].text(xcenter-N/5,ycenter+N/1.45,'/',fontsize=16)
    ax[1].text(xcenter-N/5.8,ycenter+N/1.45,'Ant facing',fontsize=16)
    ax[1].text(xcenter+N/8.8,ycenter+N/1.45,'up',weight="bold",color=color2,fontsize=16)
    ax[1].text(xcenter+N/5,ycenter+N/1.45,'/',fontsize=16)
    ax[1].text(xcenter+N/4.4,ycenter+N/1.45,'right',weight="bold",color=color3,fontsize=16)
    ax[1].text(xcenter+N/2.55,ycenter+N/1.45,'/',fontsize=16)
    ax[1].text(xcenter+N/2.37,ycenter+N/1.45,'down',weight="bold",color=color4,fontsize=16)
    ax[1].text(xcenter+N/1.68,ycenter+N/1.45,'/',fontsize=16)
    ax[1].text(xcenter+N/1.59,ycenter+N/1.45,'left',weight="bold",color=color5,fontsize=16)

    ax[1].text(xcenter-N/1.7,ycenter+N/1.33,'Tile 2:',fontsize=16)
    ax[1].text(xcenter-N/2.5,ycenter+N/1.33,'Empty',weight="bold",color=color1,fontsize=16)
    ax[1].text(xcenter-N/5,ycenter+N/1.33,'/',fontsize=16)
    ax[1].text(xcenter-N/5.8,ycenter+N/1.33,'Ant facing',fontsize=16)
    ax[1].text(xcenter+N/8.8,ycenter+N/1.33,'up',weight="bold",color=color6,fontsize=16)
    ax[1].text(xcenter+N/5,ycenter+N/1.33,'/',fontsize=16)
    ax[1].text(xcenter+N/4.4,ycenter+N/1.33,'right',weight="bold",color=color7,fontsize=16)
    ax[1].text(xcenter+N/2.55,ycenter+N/1.33,'/',fontsize=16)
    ax[1].text(xcenter+N/2.37,ycenter+N/1.33,'down',weight="bold",color=color8,fontsize=16)
    ax[1].text(xcenter+N/1.68,ycenter+N/1.33,'/',fontsize=16)
    ax[1].text(xcenter+N/1.59,ycenter+N/1.33,'left',weight="bold",color=color9,fontsize=16)

##############################################
#### Welcome screen ####
aux_welcome=FuncAnimation(fig,initialize,frames=2,interval=1,init_func=init,repeat=False)
anim=FuncAnimation(fig,animate,frames=max_iter,interval=speed,init_func=init,repeat=False)

#### Buttons ####
update_GUI(paused)
plt.show()


import os
import glob
from PIL import Image
from tqdm import tqdm

# voc_annotations = '/media/vs/qi/data/VOC2021/Annotations/'
# yolo_txt = '/media/data/darknet/labels/'    #darknet txt文件地址
# img_path = 'ssd.pytorch/data/VOCdevkit/VOC2021/JPEGImages/'   #图片地址

voc_annotations = '/media/vs/qi/data/ssd.pytorch/data/VOCdevkit/VOC2021/Annotations/'
yolo_txt = '/media/vs/qi/data/ssd.pytorch/data/VOCdevkit/VOC2021/labels/'
img_path = '/media/vs/qi/data/ssd.pytorch/data/VOCdevkit/VOC2021/JPEGImages/'

labels = ['no helmet', 'wear helmet']  # label for datasets

# 图像存储位置
src_img_dir = img_path  # 添加你的路径
# 图像的txt文件存放位置
src_txt_dir = yolo_txt
src_xml_dir = voc_annotations
img_Lists = glob.glob(src_img_dir + '/*.jpg')
img_basenames = []

for item in img_Lists:
    img_basenames.append(os.path.basename(item))

img_names = []
for item in img_basenames:
    temp1, temp2 = os.path.splitext(item)
    img_names.append(temp1)

for img in tqdm(img_names):
    im = Image.open((src_img_dir + '/' + img + '.jpg'))
    width, height = im.size

    # 打开txt文件
    gt = open(src_txt_dir + '/' + img + '.txt').read().splitlines()
    # print(gt)
    if gt:
        # 将主干部分写入xml文件中
        xml_file = open((src_xml_dir + '/' + img + '.xml'), 'w')
        xml_file.write('<annotation>\n')
        xml_file.write('    <folder>VOC2007</folder>\n')
        xml_file.write('    <filename>' + str(img) + '.jpg' + '</filename>\n')
        xml_file.write('    <size>\n')
        xml_file.write('        <width>' + str(width) + '</width>\n')
        xml_file.write('        <height>' + str(height) + '</height>\n')
        xml_file.write('        <depth>3</depth>\n')
        xml_file.write('    </size>\n')

        # write the region of image on xml file
        for img_each_label in gt:  # txt 文件中的每一行
            spt = img_each_label.split(' ')  # 这里如果txt里面是以逗号‘，’隔开的，那么就改为spt = img_each_label.split(',')。
            # print(f'spt:{spt}')
            xml_file.write('    <object>\n')
            xml_file.write('        <name>' + str(labels[int(spt[0])]) + '</name>\n')
            xml_file.write('        <pose>Unspecified</pose>\n')
            xml_file.write('        <truncated>0</truncated>\n')
            xml_file.write('        <difficult>0</difficult>\n')
            xml_file.write('        <bndbox>\n')

            center_x = round(float(spt[1].strip()) * width)
            center_y = round(float(spt[2].strip()) * height)
            bbox_width = round(float(spt[3].strip()) * width)
            bbox_height = round(float(spt[4].strip()) * height)
            xmin = str(int(center_x - bbox_width / 2))
            ymin = str(int(center_y - bbox_height / 2))
            xmax = str(int(center_x + bbox_width / 2))
            ymax = str(int(center_y + bbox_height / 2))

            xml_file.write('            <xmin>' + xmin + '</xmin>\n')
            xml_file.write('            <ymin>' + ymin + '</ymin>\n')
            xml_file.write('            <xmax>' + xmax + '</xmax>\n')
            xml_file.write('            <ymax>' + ymax + '</ymax>\n')
            xml_file.write('        </bndbox>\n')
            xml_file.write('    </object>\n')

        xml_file.write('</annotation>')


import numpy as np
from modules.ObjectDetection.ObjDetectAPI import obj_dection

def render_color_bar_figure(color_vector: np.ndarray, path: str):
    import matplotlib.pyplot as plt

    plt.bar(x=range(48), height=color_vector.flatten().tolist(), color='bgr' * 16)
    plt.savefig(path)
    plt.close()

def render_texture_bar_figure(texture_vector: np.ndarray, path: str):
    import matplotlib.pyplot as plt

    plt.bar(x=range(256), height=texture_vector.flatten().tolist())
    plt.savefig(path)
    plt.close()

def ObjDetect(path: str):
    return obj_dection(path=path, dir="modules/ObjectDetection/")

def vec_search(imgpath: str, feats: np.ndarray, names: list, k=3):
    from modules.ImageFeatureVector.HistogramVector.hisvec import get_vector
    import cv2
    try:
        assert feats[0].shape == (20, 256, 1)
    except:
        raise Exception("assert feats shape failed", "expect (20, 256, 1)", " got ", feats[0].shape, " instead")
    v = get_vector(imgpath)
    assert v.shape == (20, 256, 1)
    nums = feats.shape[0]
    res = np.empty(nums)
    for i in range(nums):
        temp = np.empty(20)
        for j in range(20):
            temp[j] = (cv2.compareHist(v[j], feats[i][j], cv2.HISTCMP_BHATTACHARYYA))
        res[i] = np.linalg.norm(temp) / 20
    rank_ID = np.argsort(res)
    namelist = [names[index] for index in rank_ID[0:k]]
    sim = [res[index] for index in rank_ID[0:k]]  # similarities
    return namelist, sim


#importing libraries
import numpy as np
import pandas as pd

# Import Libraries for visualization
import matplotlib.pyplot as plt
import seaborn as sns

#importing data set using pandas
from google.colab import files
uploaded = files.upload()
import io
agri_data = pd.read_csv('C:/Users/Kummera Sneha/OneDrive/Desktop/csv.csv')

print(agri_data.shape)
agri_data.head()
agri_data.info()

c_data = agri_data.copy()
c_data.columns

#checking null value
c_data.isnull().sum()
price_data = c_data[['Price Date','Min Price (Rs./Quintal)','Max Price (Rs./Quintal)','Modal Price (Rs./Quintal)']]
#printing price data    TASK (A)
price_data
c_data
plt.figure(figsize=(10,5))
c_data.groupby(['Market Name'])['Modal Price (Rs./Quintal)'].count().sort_values(ascending=False).head(10).plot.bar()
plt.ylabel('Price of potatoes')
plt.title("Market comparision",fontsize=20)
plt.show()
#analyzing minimuim and maximuim value of potatoes in year
df1 = agri_data.copy()
df1.sort_values('Min Price (Rs./Quintal)',inplace=True)
df1.head(20)
df1.tail()
# Import libraries for train test split
from sklearn.model_selection import train_test_split

# import Ilbrary for Scaling
from sklearn.preprocessing import StandardScaler

# import Ilbrary for Model Building
from sklearn.linear_model import LinearRegression

#creating copy of data
ml_data = agri_data.copy()

#Applying mean encoding for Market name
name = ml_data.groupby('Market Name')['Modal Price (Rs./Quintal)'].mean()
ml_data['Market Name'] = ml_data['Market Name'].map(name)

print(ml_data['Market Name'])
#dropping unwanted columns
ml_data = ml_data.drop(['Sl no.','District Name','Commodity','Variety','Grade','Price Date'],axis = 1)
ml_data.info()
agri_train,agri_test = train_test_split(ml_data,train_size = 0.7,random_state = 42)

print(agri_train.shape)
print(agri_test.shape)
# Divide tarin set into Dependent and independent variables
y_train = agri_train.pop('Modal Price (Rs./Quintal)')

X_train = agri_train

# Divide test set into Dependent and independent variables
y_test = agri_test.pop('Modal Price (Rs./Quintal)')

X_test = agri_test

# Scale the train
scaler = StandardScaler()

X_train[X_train.columns] = scaler.fit_transform(X_train[X_train.columns])

X_train.describe()
# Scale the test
X_test[X_test.columns] = scaler.transform(X_test[X_test.columns])

X_test.describe()
# Build the model
lr = LinearRegression()

agri_reg = lr.fit(X_train,y_train)

# the r2 score
agri_reg.score(X_train,y_train)
# r2 for test data
agri_reg.score(X_test,y_test)
# Plot Distribution plot of Residuals
plt.figure(figsize=(10,5))
y_train_pred = agri_reg.predict(X_train)
res = y_train - y_train_pred
sns.distplot(res)
plt.xlabel('Residuals')
plt.title("Residual Analysis",fontsize=20)
plt.show()
sns.scatterplot(x=res,y=y_train_pred)
plt.xlabel('Residuals')
plt.title("Residual Analysis",fontsize=20)
plt.show()
# Print coef
print("Coef are:",agri_reg.coef_)

#print intercept
print("Intercept is",agri_reg.intercept_)
model = str(agri_reg.intercept_)

for i in range(len(agri_reg.coef_)):
    model = model +' + '  +(str(agri_reg.coef_[i])) + ' * ' +(str(X_train.columns[i]))
print(model)


import requests

response = requests.get('https://comic.naver.com/webtoon/weekday.nhn')
print(response.status_code)
# HTTP GET요청으로 받아온 Content를 text데이터로 리턴
print(response.text)
# response.text에 해당하는 데이터를
# weekday.html 이라는 파일에 기록
# 다 기록 했으면 close()호출

f = open('weekday.html', 'wt')
f.write(response.text)
f.close()


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import itertools

import numpy as np
import tensorflow as tf
from system import ODESystem
from spaces import GRF

import deepxde as dde
from utils import merge_values, trim_to_65535, mean_squared_error_outlier, safe_test

lr = 0.001
epochs = 50000
problem = "ode"
nn = "opnn"
activation = "relu"
initializer = "Glorot normal"  # "He normal" or "Glorot normal"
dim_x = 1 if problem in ["ode", "lt"] else 2

net = dde.maps.OpNN(
    [100, 40, 40],
    [1, 40, 40],
    activation,
    initializer,
    use_bias=True,
    stacked=False,
    )
dat = np.loadtxt('data_12.dat')
dat = dat[1:100001,:]
y = np.array([ele[-1] for ele in dat])
u = np.array([ele[0:-2] for ele in dat])
x = np.array([ele[-2] for ele in dat])
index = np.random.choice(100000,100000)
train_index = index[0:10000]
test_index = index[10000:100000]
x_train = x[train_index][:,None]
x_test = x[test_index][:,None]
y_train = y[train_index][:,None]
y_test = y[test_index][:,None]
u_train = u[train_index,:]
u_test = u[test_index,:]
x_train = [u_train,x_train]
x_test = [u_test,x_test]
#print(x_train.shape)
#np.savetxt("x_train.dat",x_train)
data = dde.data.OpDataSet(
            X_train=x_train, y_train=y_train, X_test=x_test, y_test=y_test
        )
model = dde.Model(data, net)
model.compile("adam", lr=lr, metrics=[mean_squared_error_outlier])

checker = dde.callbacks.ModelCheckpoint(
        "model/model.ckpt", save_better_only=True, period=1000
    )
losshistory, train_state = model.train(epochs=epochs, callbacks=[checker])
print("# Parameters:", np.sum([np.prod(v.get_shape().as_list()) for v in tf.compat.v1.trainable_variables()]))
dde.saveplot(losshistory, train_state, issave=True, isplot=False)
model.restore("model/model.ckpt-" + str(train_state.best_step), verbose=1)
# model.restore(f"model/model-{train_state.best_step}.ckpt", verbose=1)
safe_test(model, data, x_test, y_test)

### TEST
def ode_system(T,ic):
    """ODE"""

    def g(s,u,x):
        # Antiderivative
        # return u
        # Nonlinear ODE
        # return -s**2 + u
        # Gravity pendulum
        # k = 1
        # return [s[1], - k * np.sin(s[0]) + u]
        # Rober Problem
        k1,k2,k3 = 4, 3, 1
        return [(- k1 * s[0] + k3 * s[1] * s[2]) ,
                (k1 * s[0] - k2 * s[1] * s[1] - k3 * s[1] * s[2]) ,
                (k2 * s[1] * s[1]),
                u]

    # s0 = [0]
    s0 = ic  # Gravity pendulum
    return ODESystem(g, s0, T)
T = 1
m = 100
sensors = np.linspace(0, T, num=m)[:, None]
space = GRF(T, length_scale=0.2, N=1000 * T, interp="cubic")
ics = np.column_stack((np.array([1,0.5,0.7,0.9]),
                        np.array([0,0.5,0.2,0.2]),
                        np.array([0,0.5,0.1,0.2]),
                        np.array([0,0,0,0])))
system = ode_system(T,ics[0])
a, y1_test = system.gen_sensors_data(space,1,100,0)
a, y2_test = system.gen_sensors_data(space,1,100,1)
X_test = [np.tile(y1_test.T,(100,1)),sensors]
y2_pred = model.predict(data.transform_inputs(X_test))
np.savetxt("testPred.dat", np.hstack((sensors, y2_test, y2_pred)))
print("L2relative error:", dde.metrics.l2_relative_error(y2_test, y2_pred))