# -*- coding: utf-8 -*-
"""
Created on Mon May 31 09:35:47 2021

@author: robin
"""

from smoot import MOO
from smoot import ZDT

import ast
import matplotlib.pyplot as plt
import numpy as np
import pickle
import time
from smt.sampling_methods import LHS
from pymoo.factory import get_performance_indicator

def write_increase_iter(
    fun,
    path,
    xlimits=None,
    reference=None,
    n_max=10,
    runs=5,
    paraMOO={},
    verbose=True,
    indic="igd",
    start_seed=0,
    criterions=["PI", "EHVI", "GA", "WB2S", "MPI"],
    subcrits=["EHVI", "EHVI", "EHVI", "EHVI", "EHVI"],
    transfos=[
        lambda l: sum(l),
        lambda l: sum(l),
        lambda l: sum(l),
        lambda l: sum(l),
        lambda l: sum(l),
    ],
    titles=None,
):
    """
    write a dictionnary with the results of the runs for each criterion in path.

    Parameters
    ----------
    fun : function
        function to optimize.
    path : str
        path to store datas.
    xlimits : ndarray[n_var,2], if None then it takes fun.xlimits
        bounds limits of fun, optional
    reference : ndarray[ n_points, n_obj], optional
        comparison explicit pareto points or reference point if "hv" is the indicator. The default is None.
    n_max : int
        maximal number of points added during the enrichent process. The default is 10.
    runs : int, optional
        number of runs with different seeds. The default is 5.
    paraMOO : dictionnary, optional
        Non-default MOO parameters for the optimization. The default is {"pop_size" : 50}.
    verbose : Bool, optional
        If informations are given during the process. The default is True.
    subcrits : list of str
        Subcriterions for wb2S
    transfos : list of function
        Transformations for wb2S
    """
    if xlimits is None:
        xlimits = fun.xlimits
    if reference is None and indic != "hv":
        reference = fun.pareto()[1]
    if indic == "hv":
        igd = get_performance_indicator(indic, ref_point=reference)
    else:
        igd = get_performance_indicator(indic, reference)
    if titles is None:
        titles = criterions
    fichier = open(path, "wb")
    mo = MOO(xlimits=xlimits)
    for clef, val in paraMOO.items():
        mo.options._dict[clef] = val

    def obj_profile(
        criterion="PI", n=n_max, seed=3, subcrit="EHVI", transfo=lambda l: sum(l)
    ):
        """
        Intermediate function to run for a specific criterion 1 run
        of MOO, giving the resulting front at each iteration
        """
        fronts = []
        times = []
        sampling = LHS(xlimits=xlimits, random_state=seed)
        xdoe = sampling(mo.options["n_start"])
        mo.options["criterion"] = criterion
        mo.options["random_state"] = seed
        mo.options["xdoe"] = xdoe
        mo.options["n_iter"] = 0
        mo.options["subcrit"] = subcrit
        mo.options["transfo"] = transfo
        mo.optimize(fun)
        fronts.append(mo.result.F)
        mo.options["n_iter"] = 1
        for i in range(1, n):
            stime = time.time()
            mo.options[
                "xdoe"
            ] = xdoe  # the last doe is used for the new iteration to add a point
            X, _ = mo.optimize(fun)
            fronts.append(fun(X))
            times.append(time.time() - stime)
            xdoe = mo.modeles[0].training_points[None][0][0]
        dists = [igd.calc(fr) for fr in fronts]  # - to have the growth as goal

        if verbose:
            print("xdoe", xdoe)
            # print("distances",dists)
        return dists, fronts, times

    dico_res = {crit: {} for crit in titles}
    # plots_moy = []
    for i, crit in enumerate(criterions):
        fronts_pareto = []
        distances = []
        temps = []
        if verbose:
            print("criterion ", titles[i])
        for graine in range(start_seed, start_seed + runs):
            if verbose:
                print("seed", graine)
            di, fr, tmps = obj_profile(
                crit, n=n_max, seed=graine, subcrit=subcrits[i], transfo=transfos[i]
            )
            fronts_pareto.append(fr)
            distances.append(di)
            temps.append(tmps)
        dico_res[titles[i]] = {
            "time": temps.copy(),
            "fronts": fronts_pareto.copy(),
            "dists": distances.copy(),
        }
    pickle.dump(dico_res, fichier)
    fichier.close()

def write_results(fun, path, runs=1, paraMOO={}):
    """
    Run runs times the optimizer on fun using the paraMOO parameters.
    The results of each run are stored in path using the pickle module.
    To get the datas for postprocessing, use read_results(path).

    Parameters
    ----------
    fun : function
        black box function to optimize : ndarray[ne,nx] -> ndarray[ne,ny]
    path : string
        Absolute path to store the datas.
    runs : int, optional
        Number of runs of the MOO solver. The default is 1.
    paraMOO : dictionnary, optional
        parameters for MOO solver. The default is {}.
    """
    fichier = open(path, "wb")
    mo = MOO()
    for clef, val in paraMOO.items():
        mo.options._dict[clef] = val
    pickle.dump(mo.options._dict, fichier)
    dico_res = {}
    for i in range(runs):
        titre = "run" + str(i)
        dico_res[titre] = {}
        mo.optimize(fun)
        dico_res[titre]["F"] = mo.result.F
        dico_res[titre]["X"] = mo.result.X
    pickle.dump(dico_res, fichier)
    fichier.close()

def read_results(path):
    """
    read the results written thanks to write_results in path

    Parameters
    ----------
    path : string
        Absolute path.

    Returns
    -------
    param : dictionnary
        dictionnary of the given parameters for the runs
    results : dictionnary
        contains the datas relatives to the runs. For instance,
        results["run0"]["F"] contains the pareto front of the first run.
    """
    fichier = open(path, "rb")
    param = pickle.load(fichier)
    results = pickle.load(fichier)
    fichier.close()
    return param, results

def pymoo2fun(pb):
    """
    Takes a pymoo problem and makes of it a funtion optimizable thanks to MOO

    Parameters
    ----------
    pb : pymoo.problems
        Pymoo problem, such as those obtained thanks to get_problem from pymoo.factory.

    Returns
    -------
    f_equiv : function
        Callable function, equivalent to the one of the problem : ndarray[ne,nx] -> ndarray[ne,ny].

    """

    def f_equiv(x):
        output = {}
        pb._evaluate(x, output)
        return output["F"]

    return f_equiv

def pymoo2constr(pb):
    """
    Creates the list of the constraints relatives to the pymoo problem in argument.

    Parameters
    ----------
    pb : pymoo.problems
        Constrained pymoo problem to optimize.

    Returns
    -------
    list_con : list
        List of the callable constraints : ndarray[ne,nx] -> ndarray[ne].

    """
    list_con = []
    for i in range(pb.n_constr):

        def g_equiv(x, i=i):
            output = {}
            pb._evaluate(x, output)
            return output["G"][:, i]

        list_con.append(g_equiv)
    return list_con


# https://programmers.co.kr/learn/courses/30/lessons/42586

def solution(progresses, speeds):
    import collections
    progresses = collections.deque(progresses)
    speeds = collections.deque(speeds)
    deploy_counts = []
    while progresses:
        # 100 이상인 것들 카운트
        deploy_count = 0
        pop_cnt = 0
        for i in range(len(progresses)):
            i -= pop_cnt
            if progresses[i] >= 100:
                deploy_count += 1
                speeds.popleft()
                progresses.popleft()
                pop_cnt += 1
            else:
                break

        # count 만큼 pop
        if deploy_count:
            deploy_counts.append(deploy_count)

        for i in range(len(progresses)):
            progresses[i] += speeds[i]

    return deploy_counts


from django.contrib import messages
from django.contrib.auth.mixins import AccessMixin
from django.core.cache import cache
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db import models
from django.db.models import ProtectedError
from django.http import JsonResponse, HttpRequest
from django.urls import reverse_lazy
from django.views.generic.detail import SingleObjectTemplateResponseMixin
from django.views.generic.edit import ModelFormMixin, ProcessFormView

from utilities.methods import get_model_foreignkey_fields, \
    get_model_manytomany_fields, render_pdf
from utilities.views_helper_methods import create_form, update_form, \
    search_query

class CRUDView(
    SingleObjectTemplateResponseMixin,
    ModelFormMixin,
    ProcessFormView,
    AccessMixin
):
    """
    CRUD View provide create update delete functionality from on view
    """
    submit = True
    assign_shop = True
    has_update_url = False
    pdf_response = False
    pdf_template = None
    pdf_file_name = None
    paginated_by = 10
    queryset = None

    def get_success_url(self):
        if self.success_url:
            return self.success_url
        return reverse_lazy(
            self.model._meta.app_label + ':' + self.model._meta.model_name
        )

    def get_cache_key(self):
        return '%s-queryset-%s' % (self.model._meta.model_name,
                                   self.request.user.id)

    def get_permission_denied_message(self):
        """
        Override this method to override
        the permission_denied_message attribute.
        """
        messages.error(self.request, self.permission_denied_message)
        return self.permission_denied_message

    def dispatch(self, request, *args, **kwargs):
        """
        :return: view after checking all required permission
        """
        if not request.user.is_authenticated:
            return self.handle_no_permission()
        if not self.is_permitted(request, 'view'):
            return self.handle_no_permission()
        return super().dispatch(request, *args, **kwargs)

    def has_shop(self):
        return self.request.user.staff_shop_id is not None

    def is_permitted(self, request: HttpRequest, permission_type: str):
        if request.user.is_active and request.user.is_superuser:
            return True

        permission = '{0}.{1}_{2}'.format(
            str(self.model._meta.app_label),
            permission_type,
            str(self.model._meta.model_name)
        )
        if request.user.has_perm(permission):
            return True
        self.permission_denied_message = \
            "You have no {0} permission..!".format(
                permission_type
            )
        return False

    def get_object(self, queryset=None):
        try:
            return super(CRUDView, self).get_object(queryset)
        except AttributeError:
            return None

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        if self.pdf_response:
            if self.pdf_template is None or self.pdf_file_name is None:
                raise ValueError('PDF File Name And Template Name Must Be Set')
            return render_pdf(
                request=request,
                template=self.pdf_template,
                context=self.get_context_data(),
                file_name=self.pdf_file_name
            )
        if request.GET.get('page'):
            return super(CRUDView, self).get(request, *args, **kwargs)
        if request.is_ajax():

            if 'update' in request.path:
                if self.object and self.is_permitted(
                        request,
                        'change'
                ):  # if has permission to change object then render form

                    return JsonResponse(
                        data={'html_form': update_form(self, request)}
                    )

            if self.is_permitted(
                    request,
                    'add'
            ):  # if has permission to add object then render form

                return JsonResponse(
                    data={'html_form': create_form(self, request)}
                )

            return JsonResponse(
                data={'error': 'Error Permission Denied For You'})

        return super(CRUDView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()

        if 'confirm_delete' in request.POST:
            if self.is_permitted(request, 'delete'):
                name = self.object
                try:
                    self.object.delete()
                    messages.success(
                        self.request, str(
                            self.model._meta.verbose_name
                        ).capitalize() + ' ' + str(
                            name) + ' Delete Successfully'
                    )
                    cache.delete(self.get_cache_key())
                    return JsonResponse({'msg': "Deleted Successfully"})
                except ProtectedError:
                    return JsonResponse(
                        {'error': "Can\'t Delete It has some depended data"}
                    )

            self.permission_denied_message = "You have no delete permission..!"
            return JsonResponse({'error': self.permission_denied_message})

        if self.object and self.is_permitted(
                request,
                'change'
        ) or self.is_permitted(
            request, 'add'
        ):
            return super(CRUDView, self).post(request, *args, **kwargs)
        self.permission_denied_message = \
            "You have no create or add permission..!"
        return self.handle_no_permission()

    def form_valid(self, form):
        cache.delete(self.get_cache_key())
        if self.object:
            form = self.get_form()
            messages.success(self.request,
                             f'{self.object} Update Successfully')
        else:
            form.instance.creator = self.request.user
            if self.assign_shop:
                form.instance.shop_id = self.request.user.staff_shop_id
            messages.success(
                self.request,
                f'{self.model._meta.verbose_name} Created Successfully'
            )

        return super().form_valid(form)

    def get_queryset(self):
        queryset = cache.get(self.get_cache_key())
        if queryset:
            return self.get_filtered_queryset(queryset)
        if self.queryset:
            queryset = self.queryset
        else:
            queryset = self.model.objects.select_related(
                *get_model_foreignkey_fields(self.model)
            ).prefetch_related(
                *get_model_manytomany_fields(self.model)
            ).all()
        cache.set(self.get_cache_key(), queryset, 600)
        return self.get_filtered_queryset(queryset.order_by('updated'))

    def paginated_list(self, object_list):
        page = self.request.GET.get('page', 1)
        paginator = Paginator(object_list, self.paginated_by)
        try:
            objects = paginator.page(page)
        except PageNotAnInteger:
            objects = paginator.page(1)
        except EmptyPage:
            objects = paginator.page(paginator.num_pages)
        return objects

    def get_filtered_queryset(self, queryset):
        filter_dict = {}
        search_value = None
        fields = []
        for field in queryset.model._meta.get_fields():
            if isinstance(field, models.ForeignKey):
                fields.append(field.name + '_id')
            else:
                fields.append(field.name)

        for key, value in dict(self.request.GET).items():
            if key == 'search':
                search_value = self.request.GET.get(key)
                continue
            if key == 'page':
                continue
            if self.request.GET.get(key) != '' and key in fields:
                filter_dict[key] = self.request.GET.get(key)
        object_list = queryset.filter(**filter_dict)
        if search_value:
            object_list = search_query(self, search_value, object_list)
        if self.assign_shop:
            object_list = object_list.filter(shop=self.request.user.staff_shop)
        return object_list

    def get_paginated_list(self):
        object_list = self.get_queryset()
        return self.paginated_list(object_list)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['page_title'] = self.model._meta.verbose_name
        context['app_label'] = self.model._meta.app_label
        context['object_list'] = self.get_paginated_list()
        context['total_found'] = self.get_queryset().count()
        context['permitted_for_delete'] = self.is_permitted(
            request=self.request, permission_type='delete')
        context['permitted_for_view'] = self.is_permitted(
            request=self.request,
            permission_type='view'
        )
        context['permitted_for_change'] = self.is_permitted(
            request=self.request,
            permission_type='change'
        ) and self.has_shop()
        context['permitted_for_add'] = self.is_permitted(
            request=self.request,
            permission_type='add'
        ) and self.has_shop()
        if self.submit:  # if true add submit button html snippets in context
            context['submit'] = \
                '<input type="submit" name="submit" ' \
                'value="Save" class="btn btn-primary float-right mb-2"' \
                ' id="submit-id-submit">'
        try:
            context['url_params'] = '?' + \
                                    self.request.get_full_path().split('?')[
                                        1] + '&page='
        except IndexError:
            context['url_params'] = '?page='
        return context

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs


from collections import deque
import sys

n, m = map(int, sys.stdin.readline().split()) # n: 가로 크기/ m: 세로 크기

field = []
# field = [list(sys.stdin.readline().strip()) for _ in range(m)]
for i in range(m):
    field.append(list(input()))

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

result_W = 0
result_B = 0

def solution(x, y, color):
    cnt = 0

    queue = deque()
    queue.append((x, y))

    field[x][y] == 0

    while queue:
        x, y = queue.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if nx < 0 or ny < 0 or nx >= m or ny >= n:
                continue

            if field[nx][ny] != 0 and field[nx][ny] == color:
                queue.append((nx, ny))
                field[nx][ny] = 0
                cnt += 1

    return (1 if cnt==0 else cnt)

for i in range(m):
    for j in range(n):
        if field[i][j] != 0:
            if field[i][j] == 'W':
                result_W += solution(i, j, 'W') ** 2

            elif field[i][j] == 'B':
                result_B += solution(i, j, 'B') ** 2

print(result_W, result_B)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 12 23:50:36 2019

@author: hazem
"""

import torch.nn as nn

class GNetInitialBlock(nn.Module):
    def __init__(self, n_out_c):
        super(GNetInitialBlock, self).__init__()

        # c7s1-k: 7x7 Convolution-InstanceNorm-ReLU layer with k filters and stride 1
        # k = n_out_c
        layers = [   nn.ReflectionPad2d(3),
                     nn.Conv2d(3, n_out_c, 7),
                     nn.InstanceNorm2d(n_out_c),
                     nn.ReLU(inplace=True) ]

        self.block = nn.Sequential(*layers)

    def forward(self, x):
        return self.block(x)

class GNetFinalBlock(nn.Module):
    def __init__(self, n_in_c):
        super(GNetFinalBlock, self).__init__()

        # c7s1-3: 7x7 Convolution-Tanh layer with 3 filters and stride 1
        layers = [   nn.ReflectionPad2d(3),
                     nn.Conv2d(n_in_c, 3, 7),
                     nn.Tanh() ]

        self.block = nn.Sequential(*layers)

    def forward(self, x):
        return self.block(x)

class DownBlock(nn.Module):
    def __init__(self, n_in_c, n_out_c):
        super(DownBlock, self).__init__()

        # dk: 3x3 Convolution-InstanceNorm-ReLU layers with k filters and stride 2
        # k = n_out_c
        layers = [   nn.Conv2d(n_in_c, n_out_c, 3, stride=2, padding=1),
                     nn.InstanceNorm2d(n_out_c),
                     nn.ReLU(inplace=True) ]

        self.block = nn.Sequential(*layers)

    def forward(self, x):
        return self.block(x)

class UpBlock(nn.Module):
    def __init__(self, n_in_c, n_out_c):
        super(UpBlock, self).__init__()

        # uk: 3x3 Deconvolution-InstanceNorm-ReLU layers with k filters and stride 2
        # k = n_out_c
        layers = [   nn.ConvTranspose2d(n_in_c, n_out_c, 3, stride=2, padding=1, output_padding=1),
                     nn.InstanceNorm2d(n_out_c),
                     nn.ReLU(inplace=True) ]

        self.block = nn.Sequential(*layers)

    def forward(self, x):
        return self.block(x)

class ResBlock(nn.Module):
    def __init__(self, n_c):
        super(ResBlock, self).__init__()

        # Rk: Two 3 × 3 convolutional layers with k filters
        # k = n_c
        layers = [  nn.ReflectionPad2d(1),
                    nn.Conv2d(n_c, n_c, 3),
                    nn.InstanceNorm2d(n_c),
                    nn.ReLU(inplace=True),
                    nn.ReflectionPad2d(1),
                    nn.Conv2d(n_c, n_c, 3),
                    nn.InstanceNorm2d(n_c) ]

        self.block = nn.Sequential(*layers)

    def forward(self, x):
        return x + self.block(x)

class DNetConvBlock(nn.Module):
    def __init__(self, n_in_c, n_out_c, s=2, norm=True):
        super(DNetConvBlock, self).__init__()

        # Ck: 4 × 4 Convolution-InstanceNorm-LeakyReLU layer with k filters and stride 2
        # k = n_out_c
        layers = [nn.Conv2d(n_in_c, n_out_c, 4, stride=s, padding=1)]

        if norm:
            layers += [nn.InstanceNorm2d(n_out_c)]

        layers += [nn.LeakyReLU(0.2, inplace=True)]

        self.block = nn.Sequential(*layers)

    def forward(self, x):
        return self.block(x)

class GNet(nn.Module):
    def __init__(self, n_init=64, depth=2, width=9):
        super(GNet, self).__init__()

        blocks = []

        # Initial Block: 7x7 Convolution-InstanceNorm-ReLU layer with stride 1
        blocks += [GNetInitialBlock(n_init)]

        n_c = n_init

        # Downsampling: 3x3 Convolution-InstanceNorm-ReLU layers with stride 2
        for _ in range(depth):
            blocks += [DownBlock(n_c, n_c*2)]
            n_c *= 2

        # Residual blocks: Each has two 3 × 3 convolutional layers
        for _ in range(width):
            blocks += [ResBlock(n_c)]

        # Upsampling: 3 × 3 Deconvolution-InstanceNorm-ReLU layers
        for _ in range(depth):
            blocks += [UpBlock(n_c, n_c//2)]
            n_c //= 2

        # Final Block: 7x7 Convolution-Tanh layer with stride 1
        blocks += [GNetFinalBlock(n_c)]

        self.net = nn.Sequential(*blocks)

    def forward(self, x):
        return self.net(x)

class DNet(nn.Module):
    def __init__(self, n_init=64, depth=4):
        super(DNet, self).__init__()

        blocks = []

        # A few 4 × 4 Convolution-InstanceNorm-LeakyReLU blocks with stride 2
        # First convolution block does not use InstanceNorm
        blocks += [DNetConvBlock(3, n_init, norm=False)]

        n_c = n_init

        # The middle convolution blocks
        for _ in range(depth - 2):
            blocks += [DNetConvBlock(n_c, n_c*2)]
            n_c *= 2

        # Last convolution block uses stride=1
        blocks += [DNetConvBlock(n_c, n_c*2, s=1)]
        n_c *= 2

        # One last convolution to produce a 1-dimensional output
        blocks += [nn.Conv2d(n_c, 1, 4, padding=1)]

        self.net = nn.Sequential(*blocks)

    def forward(self, x):
        return self.net(x)


from flask import render_template, redirect, request, url_for
from database import conexion as db

def home():
    insertObject = []
    try:
        with db:
            with db.cursor() as cursor:
                sentencia = 'SELECT * FROM paciente'
                cursor.execute(sentencia)
                myresult = cursor.fetchall()

                columNames = [column[0] for column in cursor.description]
                for record in myresult:
                    insertObject.append(dict(zip(columNames, record)))
    except Exception as e:
        print(f'Ocurrió un error: {e}')
    finally:
        cursor.close()
        return render_template('index.html', data = insertObject)

def agregar_paciente():
    nombre = request.form['nombre']
    segundo_nombre = request.form['segundo_nombre']
    apellido = request.form['apellido']
    nro_dni = request.form['nro_dni']
    fecha_nacimiento = request.form['fecha_nacimiento']
    dosis = request.form['dosis']
    fecha_aplicacion = request.form['fecha_aplicacion']
    centro_salud = request.form['centro_salud']
    nombre_vacuna = request.form['nombre_vacuna']
    lote_vacuna = request.form['lote_vacuna']
    try:
        with db:
            with db.cursor() as cursor:
                sentencia = 'INSERT INTO paciente (nombre, segundo_nombre, apellido,nro_dni,fecha_nacimiento,dosis,fecha_aplicacion, centro_salud, nombre_vacuna, lote_vacuna) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
                valores = (nombre,segundo_nombre, apellido,nro_dni,fecha_nacimiento,dosis,
                        fecha_aplicacion, centro_salud, nombre_vacuna, lote_vacuna)
                cursor.execute(sentencia,valores)
    except Exception as e:
        print(f'Ocurrió un error al cargar los datos: {e}')
    finally:
        cursor.close()
        return redirect(url_for('home'))

def borrar_paciente(id):
    try:
        with db:
            with db.cursor() as cursor:
                sentencia = f'DELETE FROM paciente WHERE id_paciente = {id}'
                cursor.execute(sentencia, id)
    except Exception as e:
        print(f'No se puedo borrar el paciente: {e}')
    finally:
        cursor.close()
        return redirect(url_for('home'))

def editar_paciente(id):
    nombre = request.form['nombre']
    segundo_nombre = request.form['segundo_nombre']
    apellido = request.form['apellido']
    nro_dni = request.form['nro_dni']
    fecha_nacimiento = request.form['fecha_nacimiento']
    dosis = request.form['dosis']
    centro_salud = request.form['centro_salud']

    try:
        with db:
            with db.cursor() as cursor:
                sentencia = 'UPDATE paciente SET nombre=%s, segundo_nombre = %s, apellido=%s,nro_dni=%s, fecha_nacimiento=%s, dosis=%s, centro_salud=%s WHERE id_paciente=%s'
                valores = (nombre, segundo_nombre, apellido,nro_dni,fecha_nacimiento,dosis,
                        centro_salud, id)
                cursor.execute(sentencia, valores)
    except Exception as e:
        print(f'No se pudo modificar los valores: {e}')
    finally:
        cursor.close()
        return redirect(url_for('home'))


#!/usr/bin/env python3

# class for the extraction of values from simulation output to pandas DataFrame

import pandas as pd
import os as os
import re as re
import glob as glob
import sys as sys
import numpy as np

class extract:
    """
    In the constructor give folder from which to extract
    other arguments are:
    - long cont folder (standard value False)
    - which file to extract (standard is ionicmodel.txt)

    import with:
    from CleftAnalysis import extract

    ------------------------------
    to initiate the class call e.g.
    f = extract.extract(folder_num, subfolder_name, values)
    where:
    folder_num : number of the generated cleftdyn folder
    subfolder_name : string of the possible subfolder. If nothing specified, then no subfolder set
                     numerical values possible: 0 and 1 are special cases defined in determineFolder
    values : name or name snippet of the values to be extracted

    """

    def __init__(self, folder_num, subfolder = False, values = "ionic"):
        self.folder = folder_num
        # setFolder var ensures a folder is not initiated twice
        self.setFolder = False

        self.subfolder = subfolder
        self.determineFolder()

        self.values = values
        self.determineValues()

        self.folderDefinition()
        self.printInfo()
        self.param = self.getParam()
        self.crunumber =  int(self.param["z_discs"][0]*self.param["crus_per_sec_line"][0]**2 -
                              4*self.param["z_discs"][0])

    def read(self):
        var = pd.read_csv(self.folder + self.values, delim_whitespace = True)
        return var

    def readMass(self):
        self.values = "massconversionlog.txt"
        return self.read()

    def readIonic(self):
        self.values = "ionicmodel.txt"
        return self.read()

    def printInfo(self):
        '''
        print info when initiating class
        '''
        print("extraction folder: ", self.folder,
              "\nis it a continuation from long simulations? If yes, which? ", self.subfolder)

    def folderDefinition(self, new_folder = ""):
        '''
        set folder from which to extract data
        Args:
        new_folder: if set can allow changing the actual folder
        '''
        if (not self.setFolder and not self.subfolder):
            self.folder = "../" + str(self.folder) + "/"
            self.setFolder = True
        elif (not self.setFolder and (self.subfolder == True)):
            self.folder = "../long-cont/" + str(self.folder) + "/"
            self.setFolder = True
        elif (not self.setFolder and (type(self.subfolder) == str)):
            self.folder = "../" + self.subfolder + "/" + str(self.folder) + "/"
            self.setFolder = True
        elif (self.setFolder and new_folder):
            print("folder changed to: " + new_folder)
            self.folder = new_folder
        else:
            print("folder already set to: " + self.folder + " or not valid")

    def determineFolder(self):
        ''''
        look for subfolder arg and set it if found
        '''
        if (self.subfolder == 0):
            self.subfolder = False
        elif (self.subfolder == 1):
            self.subfolder = True
        else:
            self.subfolder = self.subfolder

    def getParam(self):
        '''
        get dataframe of parameters from parameter file of cleftdyn (use var names as keys)
        '''
        final_param = pd.DataFrame()
        final_param["params"] = [0]
        param = pd.read_csv(self.folder + "parameters.txt", sep="=", index_col=0).T
        for val in param:
            try:
                final_param[val] = [float(param[val])]
            except TypeError:
                # here some error occurs, to be checked/fixed!
                # print(val)
                pass
            except ValueError:
                pass
            except KeyError:
                pass
        return final_param

    def getParameters(self):
        return self.param

    def getSimulationFolders(self, rootdir = "sampling"):
        """get list of simulation numbers given a root directory where the sims can be found
        needed for analysis of sampling data

        The fct discards all folders in which no maxchanneldata.txt
        file is found (i.e. the simulation did not end yet)

        (this fct is independent of the folder with which the class was initialized)

        """
        sim_dirs = []
        rootdir = "../" + rootdir + "/"
        dirs = os.listdir(rootdir)
        for directory in dirs:
            try:
                val = int(directory)
                # the name trick checks if maxchanneldata.txt is present in the dir,
                # if not it means the sim is not finished yet and it skips it
                name = "{}{}/maxchanneldata.txt".format(rootdir, directory)
                if os.path.exists(name):
                    sim_dirs.append(directory)
                else:
                    continue
                    #sim_dirs.append(directory)
            except ValueError:
                pass
        return sim_dirs

    def crusInfo(self, getRadius = False, getLocations = False, getCRULcation = False):
        '''get total number of RyR and LCCs. Optional radius, channel locations and CRU location

        output are lists of the two channel types optional if
        variables set to True also output CRU radius and channel
        locations (in lists)

        '''
        ryr_numbers = []
        lcc_numbers = []
        radii = []
        ryr_location = []
        lcc_location = []
        for i in range(self.crunumber):
            crufile = open(self.folder + "clefts/cleft" + str(i) + ".log")
            cruinfo = crufile.readline()
            crufile.close()
            cruinfo = cruinfo.strip().replace("  ", " ").split(" ")
            # append number of RyR, LCCs and Radius to list
            ryr_numbers.append(int(cruinfo[cruinfo.index("RyRs") - 1]))
            lcc_numbers.append(int(cruinfo[cruinfo.index("LCCs") - 1]))
            radii.append(float(cruinfo[cruinfo.index("Radius") - 1]))
            # get the locations of the channels only if wished
            if getLocations:
                tmp1, tmp2 = self.__getLocations(ryr_numbers[i], lcc_numbers[i], cruinfo)
                ryr_location.append(tmp1)
                lcc_location.append(tmp2)

        # return different lists according to the wished arguments
        if getRadius and not getLocations:
            return ryr_numbers, lcc_numbers, radii
        elif getLocations and not getRadius:
            return ryr_numbers, lcc_numbers, ryr_location, lcc_location
        elif getRadius and getLocations:
            return ryr_numbers, lcc_numbers, radii, ryr_location, lcc_location
        else:
            return ryr_numbers, lcc_numbers

    def getCRUConcentrations(self, cleftnr):
        """
        get local Ca concentrations for a given CRU in the bulk and in the jSR

        Args:
        - cleftnumber

        Return:
        - numpy arrays with timesteps and bulk/jSR concentrations
        """

        lines, totR, totL = self.__getCleftLogLines(cleftnr)
        times = np.zeros(len(lines))
        bulk_conc = np.zeros(len(lines))
        jsr_conc = np.zeros(len(lines))

        for ind, line in enumerate(lines):
            line_list = line.replace("  ", " ").split(" ")
            times[ind] = line_list[0]
            bulk_conc[ind] = line_list[1]
            jsr_conc[ind] = line_list[2]

        return times, bulk_conc, jsr_conc

    def getCRUFluxes(self, cleftnr):
        """
        get refill and CRU flux for a given CRU number

        Args:
        - cleftnumber

        Return:
        - numpy arrays with timesteps and refill/CRU fluxes
        """

        lines, totR, totL = self.__getCleftLogLines(cleftnr)
        times = np.zeros(len(lines))
        refill_flux = np.zeros(len(lines))
        cru_flux = np.zeros(len(lines))

        for ind, line in enumerate(lines):
            line_list = line.replace("  ", " ").split(" ")
            times[ind] = line_list[0]
            refill_flux[ind] = line_list[3]
            cru_flux[ind] = line_list[4]

        return times, refill_flux, cru_flux

    def __getLocations(self, nryr, nlcc, cru_info_list):
        '''
        To be used only for crusInfo()

        gets x y pairs from first line of the cleft logs

        returns np 2d array of RyR and LCC locations in cleft
        '''
        loc_index = cru_info_list.index("Location")
        cru_info_list = cru_info_list[loc_index + 1:]
        ryr_loc = np.zeros([2, nryr])
        lcc_loc = np.zeros([2, nlcc])

        if ('(' in cru_info_list[0] or '(' in cru_info_list[1]):
            for ind, pair in enumerate(cru_info_list[:nryr]):
                loc = pair[1:-1].split(";")
                ryr_loc[0,ind] = float(loc[0])
                ryr_loc[1,ind] = float(loc[1])
            for ind, pair in enumerate(cru_info_list[nryr: nryr + nlcc]):
                loc = pair[1:-1].split(";")
                lcc_loc[0,ind] = float(loc[0])
                lcc_loc[1,ind] = float(loc[1])
        else:
            import warnings
            warnings.warn("""\nExtracting the Locations 'old' saving style, be AWARE they probably will cause numerical issues, since the output is not consistent.""")

            for ind, num in enumerate(cru_info_list[:nryr-1:2]):
                ryr_loc[0,ind] = float(cru_info_list[ind])
                ryr_loc[1,ind] = float(cru_info_list[ind + 1])

            for ind, num in enumerate(cru_info_list[nryr + 1: nryr + nlcc:2]):
                lcc_loc[0,ind] = float(cru_info_list[ind])
                lcc_loc[1,ind] = float(cru_info_list[ind + 1])
        return ryr_loc, lcc_loc

    def saveCleftPlot(self, mergeOutput = False, overwrite = False):
        """
        Save a plot of each cleft using the channel Locations
        """
        import os
        outputname = self.folder + "clefts/cleftall.pdf"
        if os.path.isfile(outputname) and not overwrite:
            import warnings
            warnings.warn("cleft ouput plots already exist!")
            return None

        import matplotlib.pyplot as plt
        nR, nL, radii, rloc, lloc = self.crusInfo(getRadius=True, getLocations=True)
        savepath = self.folder + "clefts/cleftplot{}.pdf"
        for i in range(self.crunumber):
            rad = radii[i]
            fig, ax = plt.subplots()
            ax.plot(rloc[i][0,], rloc[i][1,], "go", label="{} RyR".format(nR[i]))
            ax.plot(lloc[i][0,], lloc[i][1,], "bo", label="{} LCC".format(nL[i]))
            circ = plt.Circle((0,0), rad, color='k', fill=False)
            ax.add_artist(circ)
            ax.set_xlabel("x [$\mu m$]")
            ax.set_ylabel("y [$\mu m$]")
            ax.set_xlim((-1.5*rad, 1.5*rad))
            ax.set_ylim((-1.5*rad, 1.5*rad))
            ax.legend()
            fig.savefig(savepath.format(i), bbox_inches = "tight")
        if mergeOutput:
            savepath = savepath.format("*")
            print(savepath)
            os.system('pdfunite {} {}clefts/cleftall.pdf'.format(savepath, self.folder))

    def processCRUInfo(self):
        '''
        function that processes and saves Informations of all channels of a sim into a csv file

        Return:
        chInfo_df: pandas DF
        '''

        df = self.getCleftChannelInformation()

        ryrpertime = sum(df["openRyR"])/max(df["time"])
        chInfo_df = pd.DataFrame()
        chInfo_df["openRyR_per_ms"] = [ryrpertime]

        # saving information to file
        outputname = self.folder + "clefts/channelInfo.csv"
        chInfo_df.to_csv(outputname, index=False)

        return chInfo_df

    def getCleftChannelInformation(self):
        '''
        get time, open RyR, open LCC, cleft Location and total channel numbers
        from file in clefts/
        if not existing create it

        - Return:
        pandas DataFrame
        '''

        outputname = self.folder + "clefts/openChannels.csv"
        if (not os.path.exists(outputname)):
            self.saveOpenChannels()

        df = pd.read_csv(outputname, sep=" ")
        df = df.rename(index=str, columns={"Unnamed: 0": "counter0", "Unnamed: 1": "counter1"})

        return df

    def getCleftChannelInformation_fromCSV(self):
        '''
        get time, open RyR, open LCC, cleft Location and total channel numbers
        from files in linescan/
        if not existing create it

        - Return:
        pandas DataFrame
        '''

        outputname = self.folder + "linescan/openChannels_fluo4.csv"
        if (not os.path.exists(outputname)):
            self.saveOpenChannels_fromCSV()

        df = pd.read_csv(outputname, sep=" ")
        df = df.rename(index=str, columns={"Unnamed: 0": "counter0", "Unnamed: 1": "counter1"})

        return df

    def getOpenChannels(self):
        """
        same fct as getCleftChannelInformation
        renaming of fct meaningfull
        """
        return self.getCleftChannelInformation()

    def saveOpenChannels_fromCSV(self, overwrite = False):
        '''
        save time steps, number of open RyR and LCC to file in clefts/ dir

        ATTENTION: works properly only with master branch from (2019/07/09)
        '''

        print("Warning: saving open channels, this might take a while..")
        outputname = self.folder + "linescan/openChannels_fluo4.csv"
        if os.path.isfile(outputname) and not overwrite:
            import warnings
            warnings.warn("cleft ouput for open channels already exists!")
            return None

        cru_info = self.get_linescan_cru_info()
        parameters = self.getParameters()

        cru_info_clean = pd.DataFrame(data=[], index=[], columns=["time","clefts","bulkCa"])

        Fmax = float(parameters['Bspecial_tot'])
        Fmin = 0.0
        Kd = float(parameters['kspecial_minus'])/float(parameters['kspecial_plus'])

        index = 0
        for cru_id in cru_info["cru_id"].unique():
            temp = cru_info[cru_info["cru_id"] == cru_id]# .astype(float)
            #print(cru_id)
            #print(temp["time"].unique())

            for time in temp["time"].unique():
                #range(len(cru_info["time"].unique())):
                #time =  temp["time"].unique()[i]
                temp_time =  temp[ temp["time"] == time].astype(float)

                cru_info_clean.at[index,"time"] = time

                fluo4_conc = np.array(temp_time['fluo4'].astype(float)).max()

                cru_info_clean.at[index,"cyto_ca2+"] = np.array(temp_time['cyto_ca2+'].astype(float)).mean()
                cru_info_clean.at[index,"fluo4"] = np.array(temp_time['fluo4'].astype(float)).mean()

                cru_info_clean.at[index,"bulkCa"] = np.array(temp_time['cyto_ca2+'].astype(float)).mean()
                cru_info_clean.at[index,"openRyR"] = np.array(temp_time['open_ryrs'].astype(int)).max()

                cru_info_clean.at[index,"clefts"] = cru_id

                ca_exp = Kd*(fluo4_conc- Fmin)/(Fmax - fluo4_conc)
                cru_info_clean.at[index,"ca_exp"] = ca_exp

                cru_info_clean.at[index,"xcru"] = np.array(temp_time['cru_x'].astype(float))[0]
                cru_info_clean.at[index,"ycru"] = np.array(temp_time['cru_y'].astype(float))[0]
                cru_info_clean.at[index,"zcru"] = np.array(temp_time['cru_z'].astype(float))[0]

                index += 1

        print("length of cru info: %s" % len(cru_info_clean))

        outfile = open(outputname, 'a')
        cru_info_clean.to_csv(outfile, header=True, sep=" ", index=False)
        outfile.close()

    def saveOpenChannels(self, overwrite = False):
        '''
        save time steps, number of open RyR and LCC to file in clefts/ dir

        ATTENTION: works properly only with not merged cleftdyn branch (addition_CRU_debug_output)
        (2018/10/13)
        where cleft.log output has been changed (num of open channels outputted)
        '''
        print("Warning: saving open channels, this might take a while..")
        outputname = self.folder + "clefts/openChannels.csv"
        if os.path.isfile(outputname) and not overwrite:
            import warnings
            warnings.warn("cleft ouput for open channels already exists!")
            return None

        totDF = pd.DataFrame()
        for i in range(self.crunumber):
            timesteps = []
            openRyR = []
            openLCC = []
            caBulk = []
            cleftname = "cleft" + str(i)
            # get all lines from cleftlogs
            lines, totalRyR, totalLCC, cruloc = self.__getCleftLogLines(i, getCRULocation=True)
            x, y, z = cruloc[0][0], cruloc[0][1], cruloc[0][2]
            #print(lines, totalRyR, totalLCC, cruloc)
            # dirty hack: list starts from 1 since the first time step with time=0 (no dot for float) is not covered by regular expression (CHANGE THIS!)
            for line in lines[1:]:
                nums = re.findall("\d+\.\d+", line)
                timesteps.append(nums[0])
                caBulk.append(nums[1])
                nums = re.findall("\d+", line)
                openRyR.append(int(nums[-2]))
                openLCC.append(int(nums[-1]))

            # create pandas dataframe to save file to csv
            outDF = pd.DataFrame({'clefts': cleftname, 'xcru': x, 'ycru': y, 'zcru': z, 'time': timesteps, 'bulkCa': caBulk, 'openRyR': openRyR, 'openLCC': openLCC, 'totalRyR': totalRyR, 'totalLCC': totalLCC})

            del(timesteps[:], openRyR[:], openRyR[:])
            totDF = pd.concat([totDF, outDF])
        totDF["ratioRyR"] = totDF["openRyR"]/totDF["totalRyR"]
        totDF["ratioLCC"] = totDF["openLCC"]/totDF["totalLCC"]
        outfile = open(outputname, 'a')
        totDF.to_csv(outfile, header=True, sep=" ", index=False)
        outfile.close()

    def __getChannelInformations(self, which="conc", cleftnr=0):
        """
        get Ca concentrations/fluxes at channel mouth from cleft logs given the cleftnumber

        Args:
        - which: determines whether concentrations (conc) or fluxes (flux) are to be determined
        - cleftnumber

        Return:
        - numpy arrays with channel concentrations/fluxes and timesteps
        """
        lines, totR, totL = self.__getCleftLogLines(cleftnr)
        times = np.zeros([1, len(lines)])
        ryr_conflux = np.zeros([len(lines), totR])
        lcc_conflux = np.zeros([len(lines), totL])
        if which == "conc":
            first_channel_ind = 5
        elif which == "flux":
            first_channel_ind = 6
        else:
            print("======== Some error in asked information occured ======== ")
        for ind, line in enumerate(lines):
            line_list = line.replace("  ", " ").split(" ")
            times[:,ind] = line_list[0]
            line_list = line_list[first_channel_ind:]
            ryr_conflux[ind,:] = line_list[1:3*totR:3]
            line_list = line_list[3*totR:]
            lcc_conflux[ind,:] = line_list[1:3*totL:3]

        return times, ryr_conflux, lcc_conflux

    def getChannelConcentrations(self, cleftnr=0):
        """
        get Ca concentrations at channel mouth from cleft logs given the cleftnumber

        Args:
        - cleftnumber

        Return:
        - numpy arrays with channel concentrations and timesteps
        """
        times, ryr_conc, lcc_conc = self.__getChannelInformations("conc", cleftnr=cleftnr)

        return times, ryr_conc, lcc_conc

    def getChannelFluxes(self, cleftnr=0):

        """
        get Ca fluxes at channel mouth from cleft logs given the cleftnumber

        Args:
        - cleftnumber

        Return:
        - numpy arrays with channel fluxes and timesteps
        """
        times, ryr_flux, lcc_flux= self.__getChannelInformations("flux", cleftnr=cleftnr)

        return times, ryr_flux, lcc_flux

    def __getCleftLogLines(self, crunum, getCRULocation = False):
        """
        private fct returning the lines of the cleftlogs and the total number of RyR LCCs
        without the first line
        used by getChannelConcentration() and saveOpenChannels() fcts.
        """
        crufile = open(self.folder + "clefts/cleft" + str(crunum) + ".log")
        lines = [line.rstrip('\n') for line in crufile]
        crufile.close()
        firstline = lines[0].split(" ")
        totalRyR = int(firstline[0])
        totalLCC = int(firstline[2])
        locationCRU = [[float(firstline[6]), float(firstline[7]), float(firstline[8])]]
        del(lines[0])
        if getCRULocation:
            return lines, totalRyR, totalLCC, locationCRU
        else:
            return lines, totalRyR, totalLCC

    def determineValues(self):
        if ((self.values == "ionic") or (self.values == "ionicmodel") or
            (self.values == "ionicmodel.txt") or (self.values == 1) or (self.values == "ion")):
            self.values = "ionicmodel.txt"
        elif ((self.values == "mass") or (self.values == "massconversion") or
              (self.values == "massconversionlog.txt") or (self.values == 0) or
              (self.values == "massconversionlog")):
            self.values = "massconversionlog.txt"
        else:
            print("no considered/implemented value, skip")

    def get_openCRUs(self, year=2018):
        """
        Gets the number of open crus from the outputfile (year is the starting name of the file)
        also gets the according times (works with output that is in simfolder and has the date)

        Output:
        - list of time steps
        - list of open crus
        """
        out_file = self.folder + str(year) + "*"
        out_file = glob.glob(out_file)[0]
        time = []
        crus = []
        # sentence to be matched
        match = " number of open crus: "
        with open(out_file, "r") as fp:
            time_lines = [line for line in fp if match in line]
        for line in time_lines:
            nums = re.findall("\d+", line)
            # the first two ints are the time
            time.append(float(nums[0] + "." + nums[1]))
            # the third int found is the num of open crus
            crus.append(int(nums[2]))
        return time, crus

    def get_linescan_cru_info(self, start_time = -np.infty, end_time = np.infty, min_z = -np.infty, max_z = np.infty):
        '''
            extracts cru_info_rank*.csv files from linescan folder
        '''
        # find files in subfolder

        linescan_folder = self.folder + "linescan/"
        path, dirs, files = next(os.walk(linescan_folder))

        frames_cru_info = []

        for filename in files:

            if filename.find("cru_info") == -1:
                continue

            temp_cru_info = pd.read_csv(linescan_folder + filename)

            #print temp_cru_info
            #
            '''
            z-disc selection
            '''

            temp_cru_info = temp_cru_info[temp_cru_info['cru_z'] >= min_z]
            temp_cru_info = temp_cru_info[temp_cru_info['cru_z'] <= max_z]

            '''
            time selection
            '''

            temp_cru_info = temp_cru_info[temp_cru_info['time'] >= start_time]

            '''
            sort values
            '''

            temp_cru_info = temp_cru_info.sort_values(by=["time", "cru_id"])

            '''
            round values to needed precission
            '''

            temp_cru_info = temp_cru_info.round({'time': 1, 'cru_flux': 2, 'cyto_ca2+': 2, 'cyto_bm': 2, 'cyto_bs':2, 'sarco_ca': 0 , 'fluo4': 2})

            '''
            delete round postion values and delete duplicates to reduce memory cost
            '''
            temp_cru_info = temp_cru_info.drop_duplicates()

            # uncomment the following to see memory usage

            '''
            append to data frame
            '''

            frames_cru_info.append(temp_cru_info)

        cru_info_all = pd.concat(frames_cru_info)

        cru_info_all = cru_info_all.sort_values(by=["time", "cru_id"])

        return cru_info_all


import model_objects
import pandas as pd
import datetime
import os

_MODEL_DATA_PATH = os.getcwd() + '\\tennis\women\model\data\\'
_MODEL_OBJECTS_PATH = os.getcwd() + '\\tennis\women\model\objects\\'
_PREDICTIONS_FOLDER_PATH = os.getcwd() + '\\tennis\women\predictions\\'

def predict_fixtures():
    prediction_df, results_df = prepare_fixtures()
    clf_models = get_fixture_models()
    clf_keys = clf_models.keys()
    preds = []
    probas = []
    for key in clf_keys:
        model = clf_models[key]
        preds.append(pd.DataFrame(model.predict(prediction_df), index=prediction_df.index, columns=[f"{key}_preds"]))
        proba = model.predict_proba(prediction_df)
        probas.append(pd.DataFrame({f"{key}_proba_a" : proba.T[0], f"{key}_proba_b" : proba.T[1]},  index=prediction_df.index))

    preds = pd.concat(preds, axis=1)
    probas = pd.concat(probas, axis=1)
    predictions = pd.concat([preds, probas], axis=1)
    results_df = pd.concat([results_df, predictions], axis=1)
    save_predictions(results_df)

def save_predictions(results_df):
    pred_cols = results_df.columns[results_df.columns.str.contains('preds')]
    for col in pred_cols:
        results_df[col] = results_df.apply(lambda row: row['player_a_name'] if row[col] == 0 else row['player_b_name'], axis=1)

    today = datetime.date.today()

    count = 1
    while True:
        filename =_PREDICTIONS_FOLDER_PATH +  f"{today}_pred_{count}"
        if os.path.isfile(filename):
            count = count + 1
        else:
            results_df.to_csv(filename)
            break

def prepare_fixtures():
    df = pd.read_csv(_MODEL_DATA_PATH + 'fixtures.csv', parse_dates=['match_time']).set_index('match_time').sort_index()
    results_df = df[['player_a_name', 'player_b_name', 'comp_level']]
    oh_encoder = model_objects.load_object('\clf_encoders\onehot_encoder.pkl')
    ord_encoder = model_objects.load_object('\clf_encoders\ordinal_encoder.pkl')
    oh_df = pd.DataFrame(oh_encoder.transform(df[oh_encoder.feature_names_in_]), index=df.index, columns=oh_encoder.get_feature_names_out())
    ord_df = pd.DataFrame(ord_encoder.transform(df[ord_encoder.feature_names_in_]), index=df.index, columns=ord_encoder.get_feature_names_out())
    moving_df = df[df.columns[df.columns.str.contains('moving')]]
    return pd.concat([ord_df, oh_df, moving_df], axis= 1), results_df

def get_fixture_models():
    clf_models = {}
    models_files = os.listdir(_MODEL_OBJECTS_PATH + 'clf_models')
    for file in models_files:
        clf_models[file.split('.')[0]] = model_objects.load_object(f"clf_models\{file}")

    return clf_models

# predict_fixtures()


import numpy as np
import math
from skyscreen_core.interface import Screen

import plumbum.cli as cli
from patterns.cli import PatternPlayer, PatternPlayerMixin

@PatternPlayer.subcommand("stars")
class StarsCLI(cli.Application, PatternPlayerMixin):
	"""
	Attempts to recreate the glory of the Windows 98 screen saver.
	"""

	def main(self):
		self.main_from_renderer(starsMain)

def drawStars(stars):
	screen = np.zeros((Screen.screen_vane_count, Screen.screen_max_magnitude, 3))
	for star in stars:
		if int(star[1]) < Screen.screen_max_magnitude:
			dir_array = [(0,0)]
			if star[1] < 100: # Is the star close?
				dir_array = [(0,0),(0,-1),(0,-2),(0,-3)] # How to draw a close star?
			for d in dir_array:
				tx = star[0]+d[0]
				ty = star[1]+d[1]
				if tx >= 0 and tx < Screen.screen_vane_count and \
				   ty >= 0 and ty < Screen.screen_max_magnitude:
					screen[tx, ty, :] = 255
	return screen

# How far behind the 'zero line' (the innermost circle) should the stars pretend to start?
offset = 10

def speed(d):
	return (d+offset+1) / 20.0

def moveStars(stars):
	for i in xrange(len(stars)):
		stars[i] = (stars[i][0], stars[i][1] - speed(Screen.screen_max_magnitude - stars[i][1]))

def starsMain(writer):
	"""
	:param writer: A writer to use
	:type writer: :class:`skyscreen_core.memmap_interface.NPMMAPScreenWriter`
	"""
	with writer as writer_buf:
		writer_buf_reshaped = writer_buf.reshape((Screen.screen_vane_count, Screen.screen_max_magnitude, 3))
		screen = np.zeros((Screen.screen_vane_count, Screen.screen_max_magnitude, 3))

		stars = []
		while True:
			for i in xrange(2): # Increase '2' for moar starz
				stars.append((int(np.random.random() * Screen.screen_vane_count), Screen.screen_max_magnitude + offset))

			writer_buf_reshaped[:, :, :] = drawStars(stars)
			writer.frame_ready()
			moveStars(stars)
			stars = [x for x in stars if x[1] >= 0]


"""Qdrant reader."""

from typing import Dict, List, Optional, cast

from llama_index.readers.base import BaseReader
from llama_index.schema import Document

class QdrantReader(BaseReader):
    """Qdrant reader.

    Retrieve documents from existing Qdrant collections.

    Args:
        location:
            If `:memory:` - use in-memory Qdrant instance.
            If `str` - use it as a `url` parameter.
            If `None` - use default values for `host` and `port`.
        url:
            either host or str of
            "Optional[scheme], host, Optional[port], Optional[prefix]".
            Default: `None`
        port: Port of the REST API interface. Default: 6333
        grpc_port: Port of the gRPC interface. Default: 6334
        prefer_grpc: If `true` - use gPRC interface whenever possible in custom methods.
        https: If `true` - use HTTPS(SSL) protocol. Default: `false`
        api_key: API key for authentication in Qdrant Cloud. Default: `None`
        prefix:
            If not `None` - add `prefix` to the REST URL path.
            Example: `service/v1` will result in
            `http://localhost:6333/service/v1/{qdrant-endpoint}` for REST API.
            Default: `None`
        timeout:
            Timeout for REST and gRPC API requests.
            Default: 5.0 seconds for REST and unlimited for gRPC
        host: Host name of Qdrant service. If url and host are None, set to 'localhost'.
            Default: `None`
    """

    def __init__(
        self,
        location: Optional[str] = None,
        url: Optional[str] = None,
        port: Optional[int] = 6333,
        grpc_port: int = 6334,
        prefer_grpc: bool = False,
        https: Optional[bool] = None,
        api_key: Optional[str] = None,
        prefix: Optional[str] = None,
        timeout: Optional[float] = None,
        host: Optional[str] = None,
        path: Optional[str] = None,
    ):
        """Initialize with parameters."""
        import_err_msg = (
            "`qdrant-client` package not found, please run `pip install qdrant-client`"
        )
        try:
            import qdrant_client
        except ImportError:
            raise ImportError(import_err_msg)

        self._client = qdrant_client.QdrantClient(
            location=location,
            url=url,
            port=port,
            grpc_port=grpc_port,
            prefer_grpc=prefer_grpc,
            https=https,
            api_key=api_key,
            prefix=prefix,
            timeout=timeout,
            host=host,
            path=path,
        )

    def load_data(
        self,
        collection_name: str,
        query_vector: List[float],
        should_search_mapping: Optional[Dict[str, str]] = None,
        must_search_mapping: Optional[Dict[str, str]] = None,
        must_not_search_mapping: Optional[Dict[str, str]] = None,
        rang_search_mapping: Optional[Dict[str, Dict[str, float]]] = None,
        limit: int = 10,
    ) -> List[Document]:
        """Load data from Qdrant.

        Args:
            collection_name (str): Name of the Qdrant collection.
            query_vector (List[float]): Query vector.
            should_search_mapping (Optional[Dict[str, str]]): Mapping from field name
                to query string.
            must_search_mapping (Optional[Dict[str, str]]): Mapping from field name
                to query string.
            must_not_search_mapping (Optional[Dict[str, str]]): Mapping from field
                name to query string.
            rang_search_mapping (Optional[Dict[str, Dict[str, float]]]): Mapping from
                field name to range query.
            limit (int): Number of results to return.

        Example:
            reader = QdrantReader()
            reader.load_data(
                 collection_name="test_collection",
                 query_vector=[0.1, 0.2, 0.3],
                 should_search_mapping={"text_field": "text"},
                 must_search_mapping={"text_field": "text"},
                 must_not_search_mapping={"text_field": "text"},
                 # gte, lte, gt, lt supported
                 rang_search_mapping={"text_field": {"gte": 0.1, "lte": 0.2}},
                 limit=10
             )

        Returns:
            List[Document]: A list of documents.
        """
        from qdrant_client.http.models import (
            FieldCondition,
            Filter,
            MatchText,
            MatchValue,
            Range,
        )
        from qdrant_client.http.models.models import Payload

        should_search_mapping = should_search_mapping or {}
        must_search_mapping = must_search_mapping or {}
        must_not_search_mapping = must_not_search_mapping or {}
        rang_search_mapping = rang_search_mapping or {}

        should_search_conditions = [
            FieldCondition(key=key, match=MatchText(text=value))
            for key, value in should_search_mapping.items()
            if should_search_mapping
        ]
        must_search_conditions = [
            FieldCondition(key=key, match=MatchValue(value=value))
            for key, value in must_search_mapping.items()
            if must_search_mapping
        ]
        must_not_search_conditions = [
            FieldCondition(key=key, match=MatchValue(value=value))
            for key, value in must_not_search_mapping.items()
            if must_not_search_mapping
        ]
        rang_search_conditions = [
            FieldCondition(
                key=key,
                range=Range(
                    gte=value.get("gte"),
                    lte=value.get("lte"),
                    gt=value.get("gt"),
                    lt=value.get("lt"),
                ),
            )
            for key, value in rang_search_mapping.items()
            if rang_search_mapping
        ]
        should_search_conditions.extend(rang_search_conditions)
        response = self._client.search(
            collection_name=collection_name,
            query_vector=query_vector,
            query_filter=Filter(
                must=must_search_conditions,
                must_not=must_not_search_conditions,
                should=should_search_conditions,
            ),
            with_vectors=True,
            with_payload=True,
            limit=limit,
        )

        documents = []
        for point in response:
            payload = cast(Payload, point.payload)
            try:
                vector = cast(List[float], point.vector)
            except ValueError as e:
                raise ValueError("Could not cast vector to List[float].") from e
            document = Document(
                id_=payload.get("doc_id"),
                text=payload.get("text"),
                metadata=payload.get("metadata"),
                embedding=vector,
            )
            documents.append(document)

        return documents


import csv
import datetime
import json
import os
import sys
import time

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

input_csv_str = os.environ.get("BENCH_IN_CSV", "-")
output_tsv_str = os.environ.get("BENCH_OUT_TSV", "-")

eprint(f"reading from '{input_csv_str}'")
eprint(f"writing to '{output_tsv_str}'")

input_csv = sys.stdin if input_csv_str == "-" else open(input_csv_str, "r")
output_tsv = sys.stdout if output_tsv_str == "-" else open(output_tsv_str, "w")

writer = csv.writer(
    output_tsv, delimiter="\t", quoting=csv.QUOTE_MINIMAL, lineterminator="\n"
)

start = time.perf_counter()

for line in csv.reader(input_csv):
    writer.writerow(line)

elapsed = round((time.perf_counter() - start) * 1000)
eprint(f"completed in {elapsed} ms")

with open("performance", "a") as performance_file:
    performance_file.write(
        json.dumps(
            {
                "recorded_at": datetime.datetime.now().isoformat(),
                "duration": elapsed,
                "env_args": {k: v for (k, v) in os.environ.items() if "BENCH_" in k},
            }
        )
        + "\n"
    )


#!/usr/bin/env python3

"""IPPcode18 language interpret
@author Jiri Furda (xfurda00)
"""

# Libraries
import sys
import xml.etree.ElementTree as ET
import re
import logging

# === Main function ===
def main():
	"""Main body of the interpret"""

	filePath = processProgramArguments()

	# --- Open input file ---
	try:
		tree = ET.ElementTree(file=filePath)
	except IOError:
		Error.exit(Error.file, "Opening input file error")
	except ET.ParseError:
		Error.exit(Error.structure, "No element found in the file")

	# --- Check root node ---
	root = tree.getroot()

	# --- Process instructions ---
	Interpret.loadInstructions(root)

	# --- Successful end ---
	sys.exit(0)

# === Other functions ===
def processProgramArguments():
	"""Checks and process interpret's start parameters
	Returns path to source file to be interpreted
	"""

	# --- Check argument count ---
	if len(sys.argv) != 2:
		Error.exit(Error.argument, "Invalid argument count")

	# --- Print argument "--help" ---
	if sys.argv[1] == "--help":
		print("This program interprets code in language IPPcode18 parsed to XML")
		print("Author: Jiri Furda (xfurda00)")
		print("Usage:")
		print("python3.6 interpret.py --source=<path to .src>")
		sys.exit(0)

	# --- Load arguemnt "--source" ---
	elif sys.argv[1][:9] == "--source=":
		return sys.argv[1][9:]

	# --- Check illegal argument ---
	else:
		Error.exit(Error.argument, "Invalid argument")

# === Classes ===
class Error:
	"""Class used to store error codes and to print them"""

	# Input errors
	argument = 10
	file = 11

	# Pre-run errors
	structure = 31
	syntax = 32

	# Running errors
	semantic = 52
	operands = 53
	varExistence = 54
	scopeExistence = 55
	missingValue = 56
	zeroDivide = 57
	string = 58

	# Other errors
	custom = 59
	internal = 99

	@staticmethod
	def exit(code, msg):
		"""Prints error message to STDERR and ends with defined return code"""

		print("ERROR: {0}".format(msg), file=sys.stderr)
		sys.exit(code)

class Frames:
	"""Class working with IPPcode18 frames to store values (Global Frame, Local Frame and Temporary Frame)"""

	globalFrame = {}
	localFrame = None
	temporaryFrame = None
	stack = []	# Stack used to store temporary frames when PUSHFRAME and POPFRAME is called

	@classmethod
	def add(cls, name):
		"""Creates new variable in the frame defined in its name"""

		# --- Identify frame ---
		frame = cls.__identifyFrame(name)

		# --- Remove frame prefix ---
		name = name[3:]

		# --- Check for duplicity ---
		if name in frame:
			Error.exit(Error.custom, "Variable '{0}' already exist in global frame".format(name))

		# --- Create var in frame ---
		frame[name] = None;

	@classmethod
	def set(cls, name, value):
		"""Sets value to variable stored in certain frame"""

		# --- Identify frame ---
		frame = cls.__identifyFrame(name)

		# --- Remove frame prefix ---
		name = name[3:]

		# --- Check if exists ---
		if name not in frame:
			Error.exit(Error.varExistence, "Couldn't set value to non-existing variable '{0}'".format(name))

		# --- Get actual value ---
		if type(value) == var:	# If trying to add var (e.g. MOVE GF@aaa GF@bbb)
			value = value.getValue()	# Save its value not whole object

		# --- Save value to frame ---
		frame[name] = value;

	@classmethod
	def get(cls, name):
		"""Returns value of variable stored in certain frame"""

		# --- Identify frame ---
		frame = cls.__identifyFrame(name)

		# --- Remove frame prefix ---
		name = name[3:]

		# --- Check if exists ---
		if name not in frame:
			Error.exit(Error.varExistence, "Variable '{0}' does not exist".format(name))

		# --- Get value from frame ---
		result = frame[name]

		# --- Check if initialized ---
		if type(result) == type(None):
			Error.exit(Error.missingValue, "Tried to get non-initilaized value")

		# --- Result ---
		return result;

	@classmethod
	def __identifyFrame(cls, name):
		"""Returns specific frame depending on preffix (e.g. GF@) in variable name"""

		# --- Find certain frame ---
		if name[:3] == "GF@":
			frame = cls.globalFrame

		elif name[:3] == "LF@":
			frame = cls.localFrame

		elif name[:3] == "TF@":
			frame = cls.temporaryFrame

		# --- Check for invalid frame ---
		else:
			Error.exit(Error.syntax, "Invalid frame prefix") # Maybe should be Error.internal because it should be already chceked in Instruction.__loadArguments()

		# --- Check for not initialized frame ---
		if frame == None:
			Error.exit(Error.scopeExistence, "Cannot access not initialized frame")

		# --- Result frame ---
		return frame

class Stack:
	"""Class used for stack (values and calls)"""

	def __init__(self):
		"""Creates empty list for stack"""

		self.content = []

	def pop(self):
		"""Pops value on top of the stack"""

		# --- Check for empty stack ---
		if len(self.content) == 0:
			Error.exit(Error.missingValue, "Cannot pop empty stack")

		# --- Pop value ---
		return self.content.pop()

	def push(self, value):
		"""Pushes value to the stack"""

		self.content.append(value)

class Labels:
	"""Class used to store IPPcode18 labels and to jump to them"""

	labels = {}

	@classmethod
	def add(cls, name):
		"""Saves new label and its value"""

		# --- Convert type label to str ---
		name = str(name)

		# --- Check for duplicity ---
		if name in cls.labels:
			Error.exit(Error.semantic, "Label '{0}' already exists".format(name))

		# --- Save label ---
		cls.labels[name] = Interpret.instrOrder

	@classmethod
	def jump(cls, name):
		"""Jump interpret reading to certain label"""

		# --- Convert type label to str ---
		name = str(name)

		# --- Check for existence ---
		if name not in cls.labels:
			Error.exit(Error.semantic, "Label '{0}' does not exist".format(name))

		# --- Jump interpret reading to label ---
		Interpret.instrOrder = cls.labels[name]

class var:
	"""Class representing IPPcode18 type var"""

	def __init__(self, name):
		"""Sets name of var"""

		self.name = name

	def getValue(self):
		"""Returns value stored inside var"""

		return Frames.get(self.getName())

	def getName(self):
		"""Returns name of var including frame prefix"""

		return self.name

	def setValue(self, value):
		"""Changes value stored inside var"""

		Frames.set(self.getName(), value)

	# == Actual value convert method ==
	def __getValueWithType(self, expectedType):
		"""Get value stored inside var and check its type"""

		# --- Get value stored in var ---
		value = self.getValue()

		# --- Check if value is really str ---
		if type(value) != expectedType:
			Error.exit(Error.operands, "Unexpected type stored inside variable")

		# --- Return result ---
		return value

	def __str__(self):
		"""Get str value stored inside var"""

		return self.__getValueWithType(str)

	def __int__(self):
		"""Get int value stored inside var"""

		return self.__getValueWithType(int)

	def __bool__(self):
		"""Get bool value stored inside var"""

		return self.__getValueWithType(bool)

class symb:
	"""Dummy class representing str, int, bool or var in instruction.checkArguments()"""

	pass

class label:
	"""Class representing IPPcode18 type label"""

	def __init__(self, name):
		"""Sets name of the label"""

		self.name = name

	def __str__(self):
		"""Gets name of the label"""

		return self.name

class Interpret():
	"""Main class of this program. It represents the interpret itself"""

	instrOrder = 1	# Defines order number of instruction which is currently loaded
	valStack = Stack()	# Used by POPS and PUSHS
	callStack = Stack()	# Used by CALL and RETURN

	@staticmethod
	def checkRoot(root):
		"""Checks if root node is valid"""

		if root.tag != "program":
			Error.exit(Error.structure, "Root node <program> not found")

		if "language" in root.attrib:
			if root.attrib["language"].lower() != "ippcode18":
				Error.exit(Error.syntax, "Invalid language attribute")
			del root.attrib["language"]
		else:
			Error.exit(Error.structure, "Language attribute missing")

		if "name" in root.attrib:
			del root.attrib["name"]
		if "description" in root.attrib:
			del root.attrib["description"]

		if len(root.attrib) != 0:
			Error.exit(Error.structure, "Invalid <program> attributes")

	@classmethod
	def loadInstructions(cls, root):
		"""Loads all instruction nodes in source file and executes them"""

		# --- Search all nodes ---
		instrNodes = root.findall("./")
		instrNodesCount = len(instrNodes)

		# --- Search for LABEL nodes ---
		cls.__findLabels(instrNodes)
		cls.instrOrder = 1	# Reset instruction counter

		# --- Cycle throught every node ---
		while cls.instrOrder <= instrNodesCount:	# Watchout! instrOrder starts at 1
			# -- Get current node --
			node = instrNodes[cls.instrOrder-1]

			# -- Skip LABEL nodes --
			if node.attrib["opcode"].upper() == "LABEL":
				cls.instrOrder = cls.instrOrder+1
				continue	# They are already loaded by __findLabels()

			# -- Processing instruction --
			instruction = Instruction(node)
			instruction.execute()

			# -- Add counter --
			cls.instrOrder = cls.instrOrder+1

	@classmethod
	def __findLabels(cls, instrNodes):
		"""Search every LABEL instruction used and saves it"""
		for node in instrNodes:
			if node.attrib["opcode"].upper() == "LABEL":
				cls.instrOrder = int(node.attrib["order"])	# This is read from Labels.add
				instruction = Instruction(node)
				instruction.execute()

	@staticmethod
	def convertValue(xmlType, xmlValue, die):
		"""Converts XML value (str in python) to actual type (int, str, bool or var)
		Parameter die is bool value determining if program ends with error or if it
		reuturn default value when invalid input is given
		"""

		# --- Variable type ---
		if xmlType == "var":
			if not re.search(r"^(LF|TF|GF)@[\w_\-$&%*][\w\d_\-$&%*]*$", xmlValue):
				Error.Exit(Error.syntax, "Invalid var name")

			return var(xmlValue)

		# --- Integer type ---
		elif xmlType == "int":
			if not re.search(r"^[-+]?\d+$$", xmlValue):
				if die == True:
					Error.Exit(Error.syntax, "Invalid int value")
				else:
					return 0

			return int(xmlValue)	# Convert str to int

		# --- String type ---
		elif xmlType == "string":
			# -- Check empty string --
			if xmlValue == None:
				xmlValue = ""

			if re.search(r"(?!\\[0-9]{3})[\s\\#]", xmlValue):	# @see parse.php for regex legend
				if die == True:
					Error.Exit(Error.syntax, "Illegal characters in string")
				else:
					return ""

			# -- Search escape sequences --
			groups = re.findall(r"\\([0-9]{3})", xmlValue)	# Find escape sequences
			groups = list(set(groups))	# Remove duplicates

			# -- Decode escape sqeuences --
			for group in groups:
				if group == "092":	# Special case for \ (I don't even know why)
					xmlValue = re.sub("\\\\092", "\\\\", xmlValue)
					continue
				xmlValue = re.sub("\\\\{0}".format(group), chr(int(group)), xmlValue)

			# -- Return decoded string --
			return xmlValue

		# --- Boolean type ---
		elif xmlType == "bool":
			if xmlValue == "true":
				boolean = True
			elif xmlValue == "false":
				boolean = False
			else:
				if die == True:
					Error.Exit(Error.syntax, "Invalid bool value (given {0})".format(xmlValue))
				else:
					return False

			return boolean

		# --- Type type ---
		if xmlType == "type":
			if not re.search(r"^(int|string|bool)$", xmlValue):
				Error.Exit(Error.syntax, "Invalid type value")

			return xmlValue

		# --- Type label ---
		if xmlType == "label":
			if not re.search(r"^[\w_\-$&%*][\w\d_\-$&%*]*$", xmlValue):
				Error.Exit(Error.syntax, "Invalid label name")

			return label(xmlValue)

		# --- Invalid type ---
		else:
			Error.Exit(Error.syntax, "Unknown argument type (given {0})".format(xmlType))

class Instruction():
	"""Class representing one IPPcode18 instruction"""

	def __init__(self, node):
		"""Initialization of internal strcture of XML <instruction> node"""

		# --- Check node ---
		if node.tag != "instruction":
			Error.exit(Error.structure, "Wrong node loaded (Expected instruction)")

		# --- Order check ---
		if int(node.attrib["order"]) != Interpret.instrOrder:
			Error.exit(Error.structure, "Wrong instruction order")

		# --- Process node ---
		self.opCode = node.attrib["opcode"].upper()
		self.args = self.__loadArguments(node)
		self.argCount = len(self.args)

	def __loadArguments(self, instrNode):
		"""Loads child nodes (<argX>) of <instruction> node"""

		# --- Create list for arguments ---
		args = [None] * len(instrNode)

		# --- Load child nodes ---
		for argNode in instrNode:
			if argNode.tag[:3] != "arg":
				Error.exit(Error.structure, "Wrong node loaded (expected arg node given)")

			# -- Get arg index --
			argIndex = int(argNode.tag[3:])-1

			if argIndex > len(args):
				Error.exit(Error.structure, "Argument node out of range")

			if args[argIndex] != None:
				Error.exit(Error.structure, "Duplicated argument node")

			# --- Save arg value ---
			args[argIndex] = Interpret.convertValue(argNode.attrib["type"], argNode.text, True)

		# --- Check if loaded all expected arguments ---
		for arg in args:
			if arg == None:
				Error.exit(Error.structure, "Argument node missing")

		# --- Return loaded arguments ---
		return(args)

	def __checkArguments(self, *expectedArgs):
		"""Checks if arguments have expected type"""

		# --- Checking arguments count ---
		if self.argCount != len(expectedArgs):
			Error.exit(Error.semantic, "Invalid argument count")

		# --- Converting tuple to list ---
		expectedArgs = list(expectedArgs)

		# --- Checking arguments type ---
		i = 0;
		for arg in self.args: # Check every argument
			# -- Replacing <symb> --
			if expectedArgs[i] == symb:
				expectedArgs[i] = [int, bool, str, var]

			argType = type(arg)	# Saved argument's type

			# -- Only one allowed type --
			if type(expectedArgs[i]) == type:
				if argType != expectedArgs[i]:
					Error.exit(Error.operands, "Invalid argument type (expected {0} given {1})".format(expectedArgs[i],argType))

			# -- More allowed types --
			elif type(expectedArgs[i]) == list:
				if argType not in expectedArgs[i]:	# Check if used argument has one of expected types
					Error.exit(Error.operands, "Invalid argument type (expected {0} given {1})".format(expectedArgs[i],argType))

			# -- Wrong method parameters --
			else:
				Error.exit(Error.internal, "Illegal usage of Instruction.checkArguments()")

			i = i+1

	def execute(self):
		"""Executes instruction depending on opCode"""

		if self.opCode == "DEFVAR":
			self.__DEFVAR()
		elif self.opCode == "ADD":
			self.__ADD()
		elif self.opCode == "SUB":
			self.__SUB()
		elif self.opCode == "MUL":
			self.__MUL()
		elif self.opCode == "IDIV":
			self.__IDIV()
		elif self.opCode == "WRITE":
			self.__WRITE()
		elif self.opCode == "MOVE":
			self.__MOVE()
		elif self.opCode == "PUSHS":
			self.__PUSHS()
		elif self.opCode == "POPS":
			self.__POPS()
		elif self.opCode == "STRLEN":
			self.__STRLEN()
		elif self.opCode == "CONCAT":
			self.__CONCAT()
		elif self.opCode == "GETCHAR":
			self.__GETCHAR()
		elif self.opCode == "SETCHAR":
			self.__SETCHAR()
		elif self.opCode == "TYPE":
			self.__TYPE()
		elif self.opCode == "AND":
			self.__AND()
		elif self.opCode == "OR":
			self.__OR()
		elif self.opCode == "NOT":
			self.__NOT()
		elif self.opCode == "LT" or self.opCode == "EQ" or self.opCode == "GT":
			self.__LT_EQ_GT(self.opCode)
		elif self.opCode == "INT2CHAR":
			self.__INT2CHAR()
		elif self.opCode == "STRI2INT":
			self.__STRI2INT()
		elif self.opCode == "READ":
			self.__READ()
		elif self.opCode == "LABEL":	# Called from Interpret.__findLabels()
			self.__LABEL()
		elif self.opCode == "JUMP":
			self.__JUMP()
		elif self.opCode == "JUMPIFEQ":
			self.__JUMPIFEQ_JUMPIFNEQ(True)
		elif self.opCode == "JUMPIFNEQ":
			self.__JUMPIFEQ_JUMPIFNEQ(False)
		elif self.opCode == "DPRINT" or self.opCode == "BREAK":
			pass
		elif self.opCode == "CREATEFRAME":
			self.__CREATEFRAME()
		elif self.opCode == "PUSHFRAME":
			self.__PUSHFRAME()
		elif self.opCode == "POPFRAME":
			self.__POPFRAME()
		elif self.opCode == "CALL":
			self.__CALL()
		elif self.opCode == "RETURN":
			self.__RETURN()
		else:
			Error.exit(Error.syntax, "Unknown instruction code")

	# === IPPcode18 methods ===

	# --- Instrcution DEFVAR ---
	def __DEFVAR(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var)

		Frames.add(self.args[0].getName())

	# --- Instrcution ADD ---
	def __ADD(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [int, var], [int, var])

		# -- Count and save result --
		result = int(self.args[1]) + int(self.args[2])
		self.args[0].setValue(result)

	# --- Instrcution SUB ---
	def __SUB(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [int, var], [int, var])

		# -- Count and save result --
		result = int(self.args[1]) - int(self.args[2])
		self.args[0].setValue(result)

	# --- Instrcution ADD ---
	def __MUL(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [int, var], [int, var])

		# -- Count and save result --
		result = int(self.args[1]) * int(self.args[2])
		self.args[0].setValue(result)

	# --- Instrcution ADD ---
	def __IDIV(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [int, var], [int, var])

		# -- Check for zero divide --
		if int(self.args[2]) == 0:
			Error.exit(Error.zeroDivide, "Tried to divide by zero")

		# -- Count and save result --
		result = int(self.args[1]) // int(self.args[2])
		self.args[0].setValue(result)

	# --- Instrcution WRITE ---
	def __WRITE(self):
		"""@see zadani.pdf"""

		self.__checkArguments(symb)

		# --- Get value stored in var ---
		if type(self.args[0]) == var:
			value = self.args[0].getValue()
		else:
			value = self.args[0]

		# --- Prepare print for bool ---
		if type(value) == bool:
			if value == True:
				value = "true"
			else:
				value = "false"

		# --- Print result ---
		result = str(value)
		print(result)

	# --- Instrcution MOVE ---
	def __MOVE(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, symb)

		self.args[0].setValue(self.args[1])

	# --- Instrcution PUSHS ---
	def __PUSHS(self):
		"""@see zadani.pdf"""

		self.__checkArguments(symb)

		Interpret.valStack.push(self.args[0])

	# --- Instrcution POPS ---
	def __POPS(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var)

		value = Interpret.valStack.pop()

		self.args[0].setValue(value)

	# --- Instrcution STRLEN ---
	def __STRLEN(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [str, var])

		result = len(str(self.args[1]))

		self.args[0].setValue(result)

	# --- Instrcution CONCAT ---
	def __CONCAT(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [str, var], [str, var])

		result = str(self.args[1]) + str(self.args[2])

		self.args[0].setValue(result)

	# --- Instrcution GETCHAR ---
	def __GETCHAR(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [str, var], [int, var])

		string = str(self.args[1])
		position = int(self.args[2])

		if position >= len(string):
			Error.exit(Error.string, "GETCHAR/STRI2INT position out of range")

		result = string[position]

		self.args[0].setValue(result)

	# --- Instrcution GETCHAR ---
	def __SETCHAR(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [int, var], [str, var])

		string = str(self.args[0])
		position = int(self.args[1])
		character = str(self.args[2])

		if position >= len(string):
			Error.exit(Error.string, "SETCHAR position out of range")
		if len(character) == 0:
			Error.exit(Error.string, "SETCHAR replacement character not given")

		result = string[:position] + character[0] + string[position+1:]

		self.args[0].setValue(result)

	# --- Instrcution TYPE ---
	def __TYPE(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, symb)

		# -- Get value inside var --
		if type(self.args[1]) == var:
			value = self.args[1].getValue()
		else:
			value = self.args[1]

		# -- Convert value type name to str --
		valueType = re.search(r"<class '(str|bool|int)'>", str(type(value))).group(1)

		# -- Rename str to string --
		if valueType == "str":
			result = "string"
		else:
			result = valueType

		# -- Save value --
		self.args[0].setValue(result)

	# --- Instrcution AND ---
	def __AND(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [bool, var], [bool, var])

		result = bool(self.args[1]) and bool(self.args[2])

		self.args[0].setValue(result)

	# --- Instrcution OR ---
	def __OR(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [bool, var], [bool, var])

		result = bool(self.args[1]) or bool(self.args[2])

		self.args[0].setValue(result)

	# --- Instrcution NOT ---
	def __NOT(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [bool, var])

		result = not bool(self.args[1])

		self.args[0].setValue(result)

	# --- Instrcution LT/EQ/GT ---
	def __LT_EQ_GT(self, operation):
		"""@see zadani.pdf"""

		self.__checkArguments(var, symb, symb)

		# -- Get values inside var --
		if type(self.args[1]) == var:
			valueA = self.args[1].getValue()
		else:
			valueA = self.args[1]

		if type(self.args[2]) == var:
			valueB = self.args[2].getValue()
		else:
			valueB = self.args[2]

		# -- Check for same type --
		if type(valueA) != type(valueB):
			Error.exit(Error.operands, "Can't compare different types")

		# -- Compare values --
		if operation == "LT":
			result = valueA < valueB
		elif operation == "EQ":
			result = valueA == valueB
		elif operation == "GT":
			result = valueA > valueB
		else:
			Error.exit(Error.internal, "Invalid operation in Instruction.LT_EQ_GT")

		# -- Save result --
		self.args[0].setValue(result)

	# --- Instrcution INT2CHAR ---
	def __INT2CHAR(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, [int, var])

		value = int(self.args[1])

		try:
			result = chr(value)
		except ValueError:
			Error.exit(Error.string, "INT2CHAR invalid character code")

		# -- Save result --
		self.args[0].setValue(result)

	# --- Instrcution STRI2INT ---
	def __STRI2INT(self):
		"""@see zadani.pdf"""

		self.__GETCHAR()

		result = ord(self.args[0].getValue())	# Get char's ASCII code

		# -- Save result --
		self.args[0].setValue(result)

	# --- Instrcution READ ---
	def __READ(self):
		"""@see zadani.pdf"""

		self.__checkArguments(var, str)	# Should be <var> <type> but there is no class Type

		inputStr = input()

		# -- Bool input special rules --
		inputStr = inputStr.lower()

		# -- Convert input type --
		result = Interpret.convertValue(self.args[1], inputStr, False)

		# -- Save result --
		self.args[0].setValue(result)

	# --- Instrcution LABEL ---
	def __LABEL(self):	# Called from Interpret.__findLabels()
		"""@see zadani.pdf"""

		self.__checkArguments(label)

		Labels.add(self.args[0])

	# --- Instrcution JUMP ---
	def __JUMP(self):
		"""@see zadani.pdf"""

		self.__checkArguments(label)

		Labels.jump(self.args[0])

	# --- Instrcutions JUMPIFEQ & JUMPIFNEQ ---
	def __JUMPIFEQ_JUMPIFNEQ(self, expectedResult):
		"""@see zadani.pdf"""

		self.__checkArguments(label, symb, symb)

		# -- Get values inside var --
		if type(self.args[1]) == var:
			valueA = self.args[1].getValue()
		else:
			valueA = self.args[1]

		if type(self.args[2]) == var:
			valueB = self.args[2].getValue()
		else:
			valueB = self.args[2]

		# -- Check for same type --
		if type(valueA) != type(valueB):
			Error.exit(Error.operands, "Can't compare different types")

		# -- Compare values --
		result = valueA == valueB

		# -- Jump if condition is met --
		if result == expectedResult:
			Labels.jump(self.args[0])

	# --- Instrcution CREATEFRAME ---
	def __CREATEFRAME(self):
		"""@see zadani.pdf"""

		self.__checkArguments()

		# -- Reset TF --
		Frames.temporaryFrame = {}

	# --- Instrcution PUSHFRAME ---
	def __PUSHFRAME(self):
		"""@see zadani.pdf"""

		self.__checkArguments()

		if Frames.temporaryFrame == None:
			Error.exit(Error.scopeExistence, "Tried to access not defined frame")

		# -- Move TF to stack --
		Frames.stack.append(Frames.temporaryFrame)

		# -- Set LF --

		Frames.localFrame = Frames.stack[-1]	# LF = top of the stack (previously TF)

		# -- Reset TF --
		Frames.temporaryFrame = None

	# --- Instrcution POPFRAME ---
	def __POPFRAME(self):
		"""@see zadani.pdf"""

		self.__checkArguments()

		# -- Check if LF exists --
		if Frames.localFrame == None:
			Error.exit(Error.scopeExistence, "Local frame not defined")

		# -- Set TF --
		Frames.temporaryFrame = Frames.stack.pop()	# TF = previous top of the stack (LF)

		# -- Reset LF --
		Frames.localFrame = None

	# --- Instrcution CALL ---
	def __CALL(self):
		"""@see zadani.pdf"""

		Interpret.callStack.push(Interpret.instrOrder)

		self.__JUMP()

	# --- Instrcution RETURN ---
	def __RETURN(self):
		"""@see zadani.pdf"""

		self.__checkArguments()

		Interpret.instrOrder = Interpret.callStack.pop()

main()


"""
transform_compose = transforms.Compose([
                       transforms.Resize((84, 84)), #redimension
                       transforms.ToTensor()
                    ])

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters())
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=85)

Training complete in 8m 39s
Best accuracy on epoch 93: 0.891179
Accuracy of the network on the test images: 82.02%
"""
import torch.nn as nn
import torch.nn.functional as F

class KutralBlock(nn.Module):
    def __init__(self, in_ch, out_ch, kernel_size=3, stride=1, padding=1, bias=False):
        super(KutralBlock, self).__init__()
        self.conv = nn.Conv2d(in_channels=in_ch, out_channels=out_ch,
                    kernel_size=kernel_size, stride=stride, padding=padding, bias=bias)
        self.bn = nn.BatchNorm2d(num_features=out_ch)
        self.act = nn.LeakyReLU(inplace=True)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)

    def forward(self, x):
        x = self.bn(self.conv(x))
        x = self.pool(self.act(x))
        return x

class KutralNet(nn.Module): # test 12
    def __init__(self, classes, initial_filters=32):
        super(KutralNet, self).__init__()
        self.block1 = KutralBlock(in_ch=3, out_ch=initial_filters, kernel_size=3, stride=1, padding=1, bias=False)

        n_filters = initial_filters * 2
        self.block2 = KutralBlock(in_ch=initial_filters, out_ch=n_filters, kernel_size=3, stride=1, padding=1, bias=False)

        initial_filters = n_filters
        n_filters = initial_filters * 2
        self.block3 = KutralBlock(in_ch=initial_filters, out_ch=n_filters, kernel_size=3, stride=1, padding=1, bias=False)

        initial_filters = n_filters
        n_filters = initial_filters // 2
        self.block4 = nn.Sequential(
            nn.Conv2d(in_channels=initial_filters, out_channels=n_filters, kernel_size=1, stride=1, padding=0, bias=False),
            nn.Conv2d(in_channels=n_filters, out_channels=n_filters, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(num_features=n_filters)
        )

        self.down_sample = nn.Sequential(
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            nn.BatchNorm2d(num_features=n_filters)
        )

        self.global_pool = nn.AdaptiveAvgPool2d((1, 1))
        self.classifier = nn.Linear(n_filters, classes)

        self._init_params()

    def forward(self, x):
        debug = False
        if debug:
            print('x.size()', x.size())
        x = self.block1(x)
        if debug:
            print('block1.size()', x.size())
        shortcut = self.block2(x)
        if debug:
            print('block2.size()', x.size())
        x = self.block3(shortcut)
        if debug:
            print('block3.size()', x.size())
        x = self.block4(x)
        if debug:
            print('block4.size()', x.size())
        x += self.down_sample(shortcut)
        # global average pooling
        x = self.global_pool(F.leaky_relu(x))
        x = x.flatten(start_dim=1)
        x = self.classifier(x)
        return x

    def _init_params(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)


import chainer
import cupy
import chainer.functions as F
import chainer.links as L
import torch
import torch.nn.functional as TF

from pynvrtc.compiler import Program
from collections import namedtuple

Stream = namedtuple('Stream', ['ptr'])
s = Stream(ptr=torch.cuda.current_stream().cuda_stream)

from cupy.cuda import function

CUDA_NUM_THREADS = 1024

def GET_BLOCKS(N):
    return (N + CUDA_NUM_THREADS - 1) // CUDA_NUM_THREADS

kernel = '''
extern "C"
__global__ void copy(float *dst, const float *src, int total)
{
   int i = blockIdx.x * blockDim.x + threadIdx.x;
   if(i >= total)
      return;
   dst[i] = src[i];
}
'''

program = Program(kernel, 'copy.cu')
ptx = program.compile()

m = function.Module()
m.load(bytes(ptx.encode()))

copy_func = m.get_function('copy')

def datacopy(src_ptr, dst_ptr, size):
    copy_func(block=(CUDA_NUM_THREADS, 1, 1),
              grid=(GET_BLOCKS(size), 1, 1),
              args=[src_ptr, dst_ptr, size],
              stream=cupy.cuda.get_current_stream())

class PyTorchFunc(chainer.function_node.FunctionNode):
    def __init__(self, torch_func):
        self.torch_func = torch_func

    def forward_gpu(self, x):
        for i in range(len(x)):
            # Assert all inputs are float32
            assert x[i].dtype == cupy.float32

        self.gpu = chainer.cuda.get_device_from_array(x[0]).id

        torch_x = [torch.zeros(*x[i].shape, device=torch.device("cuda:"+str(self.gpu)), requires_grad=True, dtype=torch.float32).contiguous() for i in range(len(x))]

        for i in range(len(x)):
            datacopy(torch_x[i].data.data_ptr(), x[i], x[i].size)

        self.torch_x = torch_x
        torch_y = self.torch_func(*torch_x)
        self.torch_y = torch_y

        output = [cupy.ascontiguousarray(cupy.zeros(tuple(torch_y[i].shape), dtype=cupy.float32)) for i in range(len(torch_y))]
        for i in range(len(torch_y)):
            datacopy(output[i], torch_y[i].data.data_ptr(), torch_y[i].numel())

        return tuple(output)

    def backward(self, indexes, gx):
        torch_y_grad = [torch.zeros(*gx[i].shape, device=torch.device("cuda:"+str(self.gpu)), requires_grad=False, dtype=torch.float32).contiguous() for i in range(len(gx))]
        for i in range(len(gx)):
            if gx[i] is not None:
                datacopy(torch_y_grad[i].data.data_ptr(), cupy.ascontiguousarray(gx[i].data), torch_y_grad[i].numel())

        for i in range(len(gx)):
            if gx[i] is not None:
                self.torch_y[i].backward(torch_y_grad[i])

        x_grad = [cupy.ascontiguousarray(cupy.zeros(tuple(self.torch_x[indexes[i]].grad.shape), dtype=cupy.float32)) for i in range(len(indexes))]
        for i in range(len(indexes)):
            datacopy(x_grad[i], self.torch_x[indexes[i]].grad.contiguous().data_ptr(), x_grad[i].size)

        # Not support Double Backprop for now
        x_grad = [chainer.Variable(x, requires_grad=False) for x in x_grad]
        return tuple(x_grad)

def pytorch_func(func, inputs):
    return PyTorchFunc(func).apply(tuple(inputs))