"""Testing the writer, i.e., the deserialized-to-bibtex-converter."""

import pytest

from bibtexparser import BibtexFormat, Library, writer
from bibtexparser.model import (
    Entry,
    ExplicitComment,
    Field,
    ImplicitComment,
    ParsingFailedBlock,
    Preamble,
    String,
)

_DUMMY_STRING = String(key="myKey", value='"myValue"')
_DUMMY_PREAMBLE = Preamble(value='"myValue"')
_DUMMY_EXPLICIT_COMMENT = ExplicitComment(comment="myValue")
_DUMMY_IMPLICIT_COMMENT = ImplicitComment(comment="#myValue")

def _dummy_entry():
    return Entry(
        entry_type="article",
        key="myKey",
        fields=[
            Field(key="title", value='"myTitle"'),
            Field(key="author", value='"myAuthor"'),
        ],
    )

@pytest.mark.parametrize(
    "block, expected_string",
    [
        (_DUMMY_STRING, '@string{myKey = "myValue"}\n'),
        (_DUMMY_PREAMBLE, '@preamble{"myValue"}\n'),
        (_DUMMY_EXPLICIT_COMMENT, "@comment{myValue}\n"),
        (_DUMMY_IMPLICIT_COMMENT, "#myValue\n"),
    ],
)
def test_single_simple_blocks(block, expected_string):
    """Test the @string serializer."""
    library = Library(blocks=[block])
    string = writer.write(library)
    assert string == expected_string

@pytest.mark.parametrize("indent", [None, "", " ", "\t"])
def test_write_entry_with_indent(indent):
    entry_block = _dummy_entry()
    library = Library(blocks=[entry_block])
    bib_format = BibtexFormat()
    expected_indent = "\t"  # default
    if indent is not None:
        bib_format.indent = indent
        expected_indent = indent

    string = writer.write(library, bib_format)
    assert (
        string == f'@article{{myKey,\n{expected_indent}title = "myTitle",'
        f'\n{expected_indent}author = "myAuthor"\n}}\n'
    )

@pytest.mark.parametrize("trailing_comma", [None, True, False])
def test_write_entry_with_trailing_comma(trailing_comma):
    entry_block = _dummy_entry()
    library = Library(blocks=[entry_block])
    bib_format = BibtexFormat()
    expected = ""  # default
    if trailing_comma is not None:
        bib_format.trailing_comma = trailing_comma
        if trailing_comma:
            expected = ","

    string = writer.write(library, bib_format)
    assert (
        string == f'@article{{myKey,\n\ttitle = "myTitle",'
        f'\n\tauthor = "myAuthor"{expected}\n}}\n'
    )

@pytest.mark.parametrize("value_column", [None, 10, "auto"])
def test_entry_value_column(value_column):
    entry_block = _dummy_entry()
    entry_block.set_field(Field(key="veryverylongkeyfield", value="2020"))
    library = Library(blocks=[entry_block])
    bib_format = BibtexFormat()
    if value_column is not None:
        bib_format.value_column = value_column
    string = writer.write(library, bib_format)
    if value_column is None:
        # Make sure there are no unneeded spaces
        assert f'{bib_format.indent}title = "myTitle"' in string
        assert f'{bib_format.indent}author = "myAuthor"' in string
        assert f"{bib_format.indent}veryverylongkeyfield = 2020" in string
    elif value_column == 10:
        assert f'{bib_format.indent}title   = "myTitle"' in string
        assert f'{bib_format.indent}author  = "myAuthor"' in string
        assert f"{bib_format.indent}veryverylongkeyfield = 2020" in string
    if value_column == "auto":
        assert f'{bib_format.indent}title                = "myTitle"' in string
        assert f'{bib_format.indent}author               = "myAuthor"' in string
        assert f"{bib_format.indent}veryverylongkeyfield = 2020" in string

@pytest.mark.parametrize("block_separator", [None, "\n\n", "\n-----\n"])
def test_block_separator(block_separator):
    library = Library(blocks=[_DUMMY_STRING, _DUMMY_PREAMBLE])
    bib_format = BibtexFormat()
    if block_separator is not None:
        bib_format.block_separator = block_separator
    else:
        block_separator = "\n\n"  # default
    string = writer.write(library, bib_format)
    lines = string.splitlines()

    if block_separator == "\n":
        # Case where the next line immediately is the next block
        assert len(lines) == 2
        assert lines[0] == '@string{myKey = "myValue"}'
        assert lines[1] == '@preamble{"myValue"}'
    else:
        # Case where blocks are separated by at least one line
        expected_lines = block_separator.splitlines()
        for i, l in enumerate(expected_lines):
            assert lines[1 + i] == l

        assert lines[1 + len(expected_lines)] == '@preamble{"myValue"}'

def test_write_failed_block():
    raw = "@article{irrelevant-for-this-test,\nexcept = {that-there-need-to-be},\nother = {multiple-lines}\n}"
    block = ParsingFailedBlock(
        error=ValueError("Some error"), raw=raw, ignore_error_block=None
    )
    library = Library(blocks=[block])
    string = writer.write(library)
    lines = string.splitlines()

    assert len(lines) == 5
    assert lines[0].startswith("% WARNING")
    assert lines[1] == "@article{irrelevant-for-this-test,"
    assert lines[2] == "except = {that-there-need-to-be},"
    assert lines[3] == "other = {multiple-lines}"
    assert lines[4] == "}"


"""
Featurizers that mostly concern protein-based models
"""
from __future__ import annotations
from collections import Counter
import logging
from typing import Union

import numpy as np

from .core import ParallelBaseFeaturizer, BaseOneHotEncodingFeaturizer, OEBaseModelingFeaturizer
from ..core.proteins import Protein, KLIFSKinase
from ..core.sequences import AminoAcidSequence
from ..core.systems import ProteinSystem, ProteinLigandComplex

logger = logging.getLogger(__name__)

class SingleProteinFeaturizer(ParallelBaseFeaturizer):
    """
    Provides a minimally useful ``._supports()`` method for all Protein-like featurizers.
    """

    _COMPATIBLE_PROTEIN_TYPES = (Protein, KLIFSKinase)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def _supports(self, system: Union[ProteinSystem, ProteinLigandComplex]) -> bool:
        """
        Check that exactly one protein is present in the System
        """
        super_checks = super()._supports(system)
        proteins = [c for c in system.components if isinstance(c, self._COMPATIBLE_PROTEIN_TYPES)]
        return all([super_checks, len(proteins) == 1])

class AminoAcidCompositionFeaturizer(SingleProteinFeaturizer):

    """Featurizes the protein using the composition of the residues in the binding site."""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    # Initialize a Counter object with 0 counts
    _counter = Counter(sorted(AminoAcidSequence.ALPHABET))
    for k in _counter.keys():
        _counter[k] = 0

    def _featurize_one(
        self, system: Union[ProteinSystem, ProteinLigandComplex]
    ) -> Union[np.array, None]:
        """
        Featurizes a protein using the residue count in the sequence.

        Parameters
        ----------
        system: ProteinSystem or ProteinLigandComplex
            The System to be featurized.

        Returns
        -------
        : np.array or None
            The count of amino acids in the binding site.
        """
        count = self._counter.copy()
        try:
            sequence = system.protein.sequence
        except ValueError:  # e.g. erroneous uniprot_id in lazy instantiation
            return None
        count.update(system.protein.sequence)
        sorted_count = sorted(count.items(), key=lambda kv: kv[0])
        return np.array([number for _, number in sorted_count])

class OneHotEncodedSequenceFeaturizer(BaseOneHotEncodingFeaturizer, SingleProteinFeaturizer):

    """Featurizes the sequence of the protein to a one hot encoding."""

    ALPHABET = AminoAcidSequence.ALPHABET

    def __init__(self, sequence_type: str = "full", **kwargs):
        """
        Featurizes the sequence of the protein to a one hot encoding.

        Parameters
        ----------
        sequence_type: str, default=full
            The sequence to use for one hot encoding ('full', 'klifs_kinase' or 'klifs_structure').
        """
        if sequence_type not in ["full", "klifs_kinase", "klifs_structure"]:
            raise ValueError(
                "Only 'full', 'klifs_kinase' and 'klifs_structure' are supported sequence_types, "
                f"you provided {sequence_type}."
            )
        self.sequence_type = sequence_type
        if sequence_type != "full":
            self.ALPHABET += "-"  # add gap symbol for KLIFS sequence to ALPHABET
        super().__init__(**kwargs)  # update ALPHABET first

    def _retrieve_sequence(self, system: Union[ProteinSystem, ProteinLigandComplex]) -> str:
        try:
            if self.sequence_type == "full":
                sequence = system.protein.sequence
            elif self.sequence_type == "klifs_kinase":
                sequence = system.protein.kinase_klifs_sequence
            else:
                sequence = system.protein.structure_klifs_sequence
        except ValueError:  # e.g. erroneous uniprot_id in lazy instantiation
            return ""
        return sequence

class OEProteinStructureFeaturizer(OEBaseModelingFeaturizer, SingleProteinFeaturizer):
    """
    Given systems with exactly one protein, prepare the protein structure by:

     - modeling missing loops with OESpruce according to the PDB header unless
       a custom sequence is specified via the `uniprot_id` or `sequence`
       attribute in the protein component (see below), missing sequences at
       N- and C-termini are not modeled
     - building missing side chains
     - substitutions, deletions and insertions, if a `uniprot_id` or `sequence`
       attribute is provided for the protein component alteration will be
       modeled with OESpruce, if an alteration could not be modeled, the
       corresponding mismatch in the structure will be deleted
     - removing everything but protein and water
     - protonation at pH 7.4

    The protein component of each system must be a `core.proteins.Protein`
    or a subclass thereof, must be initialized with toolkit='OpenEye' and
    give access to a molecular structure, e.g. via a pdb_id. Additionally,
    the protein component can have the following optional attributes to
    customize the protein modeling:

     - `name`: A string specifying the name of the protein, will be used for
        generating the output file name.
     - `chain_id`: A string specifying which chain should be used.
     - `alternate_location`: A string specifying which alternate location
        should be used.
     - `expo_id`: A string specifying a ligand bound to the protein of
       interest. This is especially useful if multiple proteins are found in
       one PDB structure.
     - `uniprot_id`: A string specifying the UniProt ID that will be used to
       fetch the amino acid sequence from UniProt, which will be used for
       modeling the protein. This will supersede the sequence information
       given in the PDB header.
     - `sequence`: A  string specifying the amino acid sequence in
       one-letter-codes that should be used during modeling the protein. This
       will supersede a given `uniprot_id` and the sequence information given
       in the PDB header.

    Parameters
    ----------
    loop_db: str
        The path to the loop database used by OESpruce to model missing loops.
    cache_dir: str, Path or None, default=None
        Path to directory used for saving intermediate files. If None, default
        location provided by `appdirs.user_cache_dir()` will be used.
    output_dir: str, Path or None, default=None
        Path to directory used for saving output files. If None, output
        structures will not be saved.
    use_multiprocessing : bool, default=True
        If multiprocessing to use.
    n_processes : int or None, default=None
        How many processes to use in case of multiprocessing. Defaults to
        number of available CPUs.
    """

    from MDAnalysis.core.universe import Universe

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def _featurize_one(self, system: ProteinSystem) -> Union[Universe, None]:
        """
        Prepare a protein structure.

        Parameters
        ----------
        system: ProteinSystem
            A system object holding a protein component.

        Returns
        -------
        : Universe or None
            An MDAnalysis universe of the featurized system. None if no design unit was found.
        """
        from pathlib import Path

        from ..modeling.MDAnalysisModeling import read_molecule

        structure = self._read_protein_structure(system.protein)
        if structure is None:
            logger.warning(
                f"Could not read protein structure for {system.protein}, returning None!"
            )
            return None

        logging.debug("Preparing protein structure ...")
        design_unit = self._get_design_unit(
            structure=structure,
            chain_id=system.protein.chain_id if hasattr(system.protein, "chain_id") else None,
            alternate_location=system.protein.alternate_location
            if hasattr(system.protein, "alternate_location")
            else None,
            has_ligand=hasattr(system.protein, "expo_id"),
            ligand_name=system.protein.expo_id if hasattr(system.protein, "expo_id") else None,
            model_loops_and_caps=False if system.protein.sequence else True,
        )  # if sequence is given model loops and caps separately later
        if not design_unit:
            logging.debug("No design unit found, returning None!")
            return None

        logging.debug("Extracting design unit components ...")
        protein, solvent = self._get_components(
            design_unit=design_unit,
            chain_id=system.protein.chain_id if hasattr(system.protein, "chain_id") else None,
        )[:-1]

        if system.protein.sequence:
            first_id = 1
            if "construct_range" in system.protein.metadata.keys():
                first_id = int(system.protein.metadata["construct_range"].split("-")[0])
            protein = self._process_protein(
                protein_structure=protein,
                amino_acid_sequence=system.protein.sequence,
                first_id=first_id,
            )

        logging.debug("Assembling components ...")
        solvated_protein = self._assemble_components(protein, solvent)

        logging.debug("Updating pdb header ...")
        solvated_protein = self._update_pdb_header(
            solvated_protein, protein_name=system.protein.name
        )

        logging.debug("Writing results ...")
        file_path = self._write_results(
            solvated_protein,
            "_".join(
                [
                    info
                    for info in [
                        system.protein.name,
                        system.protein.pdb_id
                        if system.protein.pdb_id
                        else Path(system.protein.metadata["file_path"]).stem,
                        f"chain{system.protein.chain_id}"
                        if hasattr(system.protein, "chain_id")
                        else None,
                        f"altloc{system.protein.alternate_location}"
                        if hasattr(system.protein, "alternate_location")
                        else None,
                    ]
                    if info
                ]
            ),
        )

        logging.debug("Generating new MDAnalysis universe ...")
        structure = read_molecule(file_path)

        if not self.output_dir:
            logging.debug("Removing structure file ...")
            file_path.unlink()

        return structure


from rl import RLAgent, StateGenerator, Controller, ActionRepresentation
from reward import RewardCalculator
from simulation import Simulator
from action import PhaseModifier
from stats import SimulationOutputParser
import tensorflow as tf
import numpy as np

N_ACTIONS = 3

class SingleIntersectQAgent (RLAgent):
    def __init__(self, reward_calc, state, controller, actions):
        super().__init__(reward_calc, state, controller, actions)
        self._build_model_graph()
        self._discount = .9
        self._explore_prob = 0.2

    def _select_action(self, state):
        if np.random.rand(1) < self._explore_prob:
            action = np.eye(N_ACTIONS)[np.random.randint(N_ACTIONS)]
            return action
        output = self._session.run(self._model_output, feed_dict={self._model_input: state})

        action_number = np.argmax(output)
        one_hot = np.eye(output.size)[action_number]
        return one_hot

    def set_explore_probability(self, explore_probability):
        self._explore_prob = explore_probability

    def _build_model_graph(self):
        self._model_input = tf.placeholder(dtype=tf.float64, shape=[1,120])
        layer1 = tf.layers.dense(inputs=self._model_input,units=100, activation=tf.nn.relu)
        layer2 = tf.layers.dense(inputs=layer1,units=100, activation=tf.nn.relu)
        layer3 = tf.layers.dense(inputs=layer2, units=3)
        self._model_output = layer3

        self._calculated_q = tf.placeholder(dtype=tf.float64, shape=(1, N_ACTIONS))
        self._loss = tf.reduce_sum(tf.square(self._calculated_q - self._model_output))
        self._optimizer = tf.train.AdamOptimizer().minimize(self._loss)

        g_initializer = tf.global_variables_initializer()
        l_initializer = tf.local_variables_initializer()

        self._session = tf.Session()
        self._saver = tf.train.Saver()
        self._session.run(g_initializer)
        self._session.run(l_initializer)

    def _update_model(self, state, action, reward, new_state):
        initial_q = self._session.run(self._model_output, feed_dict={self._model_input: state})
        next_q = self._session.run(self._model_output, feed_dict={self._model_input: new_state})
        max_next_q = np.max(next_q)

        action_index = np.argmax(action)
        calculated_q = initial_q
        calculated_q[0,action_index] = reward + self._discount*max_next_q
        self._session.run(self._optimizer, feed_dict={self._model_input: state, self._calculated_q: calculated_q})

    def save_model(self, save_path):
        self._saver.save(self._session, save_path)

    def restore_model(self, save_path):
        self._saver.restore(self._session, save_path)

if __name__ == "__main__":
    sumocfg = "..\\..\\test_environments\\single_intersection_random_trips\\newnet.sumocfg"
    rc = RewardCalculator(alpha=0)
    action_translator = ActionRepresentation([0, 3, 4])
    controller = Controller(PhaseModifier("node1"), action_translator)
    state_gen = StateGenerator()
    agent = SingleIntersectQAgent(rc, state_gen, controller, np.eye(3))
    explore_prob = .4
    avg_speed = []
    mean_dur = []
    for episode in range(500):
        controller.reset()
        rc.reset()
        agent.reset()

        explore_prob *= .99
        agent.set_explore_probability(explore_prob)

        sim = Simulator()
        sim.add_tickable(rc)
        sim.add_tickable(controller)
        sim.add_tickable(agent)
        sim.add_simulation_component(SimulationOutputParser)
        sim.run(sumocfg, time_steps=3000, gui=False)
        mean_speed = sim.results["mean_speed"].mean()
        mean_dur.append(sim.results["duration"].mean())
        print("Episode %i : avg speed %.3f, mean journey %.3f"%(episode, mean_speed, mean_dur[-1]))
        avg_speed.append(mean_speed)
        agent.save_model("./rl_models/2_layer_model_100_100")

    print(avg_speed)
    print(mean_dur)


# -*- coding: utf-8 -*-

from collections import defaultdict
from collections import Counter
import time
import math
import sys
from nodo import NodoDT

"""
Comprueba si un nodo de un arbol es interior
"""

def es_interior(nodo):
    if nodo.ramas:
        return len([rama for rama in nodo.ramas if rama]) > 0
    else:
        return False

'''
Obtiene el nodo raiz de un nuevo arbol que llega hasta el nodo intermedio indicado, que se convertirá en un nodo hoja.
'''

def obtener_nuevo_arbol(raiz, objetivo):
    return obtener_nuevo_arbol_recursivo(raiz, objetivo)

def obtener_nuevo_arbol_recursivo(actual, objetivo):
    if actual == objetivo:
        key = maxima_frecuencia(objetivo.distr)
        nodo = NodoDT(None, objetivo.distr, None, key)
    else:
        if actual.ramas:
            for key in actual.ramas:
                hijo = actual.ramas[key]
                actual.ramas[key] = obtener_nuevo_arbol_recursivo(hijo, objetivo)

        nodo = actual

    return nodo

"""
Crea un diccionario donde la clave es el nombre de la clase
y el valor es el número de veces que aparece esta.
"""

def distribucion_clases(datos):
    res = defaultdict(int)

    [res.update({x[-1]: res[x[-1]] + 1}) for x in datos]

    return res

"""
Crea un diccionario donde la clave es el nombre del atributo y el valor
es el índice de este.
"""

def indice_atributos(atributos):
    res = dict()

    [res.update({x[0]: atributos.index(x)}) for x in atributos]

    return res

"""
Función utilizada para capturar el momento en el que comienza todo.
"""

def comienzo_tiempo_ejecucion():
    # Variable usada para medir los tiempos de ejecución
    start_time = time.time()
    return start_time

"""
Función utilizada para calcular los tiempos de ejecución de la aplicación en base al comienzo.
"""

def tiempo_ejecucion_obtenido(start_time):
    # Tiempo de ejecución obtenido
    print("Tiempo de ejecución en segundos: --- %s seconds ---" % (time.time() - start_time))

"""
Calcula el total de datos pasando una distribución.
"""

def total_datos_distribucion(distribucion):
    return sum([distribucion[key] for key in distribucion])

"""
Calcula la proporción de los datos dados.
"""

def proporcion_datos(datos):
    result = dict()

    total = sum([datos[x] for x in datos])

    for key in datos:
        result[key] = datos[key] / total

    return result

"""
Devuelve la clave de la máxima frecuencia, dado un conjunto de datos de ejemplo
"""

def maxima_frecuencia(datos):
    return max(datos, key=datos.get)

"""
Calcula la tasa de error de un conjunto de datos.
"""

def tasa_error(S):
    total = total_datos_distribucion(S)
    key = max(S, key=S.get)
    Pd = S.get(key)

    return 1 - (Pd / total)

def tasa_error_media_ponderada(S, Si):
    total_S = total_datos_distribucion(S)
    total_Si = total_datos_distribucion(Si)

    return (total_Si / total_S) * tasa_error(Si)

"""
Calcula el índice de gini de un conjunto de datos.
"""

def gini(S):
    res = 0
    total = total_datos_distribucion(S)

    for key in S:
        p = S[key] / total
        res += math.pow(p, 2)

    return 1 - res

def gini_media_ponderada(S, Si):
    total_S = total_datos_distribucion(S)
    total_Si = total_datos_distribucion(Si)

    return (total_Si / total_S) * gini(Si)

"""
Calcula la entropia de un conjunto de datos dada la distribución total.
"""

def entropia(S):
    res = 0
    total = total_datos_distribucion(S)

    for key in S:
        p = S[key] / total
        res += p * math.log(p, 2)

    return -res

"""
Calcula el grado de entropía del criterio de decisión.
Media ponderada de los grados de entropía de los conjuntos obtenidos tras la decisión.
"""

def entropia_media_ponderada(S, Si):
    total_S = total_datos_distribucion(S)
    total_Si = total_datos_distribucion(Si)

    return (total_Si / total_S) * entropia(Si)

"""
Calcula la media ponderada según el criterio de medida
"""

def calcular_media_ponderada(medida, S, Si):
    if medida == "entropia":
        resultado = entropia_media_ponderada(S, Si)
    elif medida == "error":
        resultado = tasa_error_media_ponderada(S, Si)
    elif medida == "gini":
        resultado = gini_media_ponderada(S, Si)
    else:
        raise ValueError("La medida {} no está registrada.".format(medida))

    return resultado

"""
Selecciona la mejor opción para elegir qué rama es mejor explorar
"""

def criterio_decision(medida, datos, atributos, indice_atributos):
    S = distribucion_clases(datos)
    Si = []
    Si_dict = dict()

    # Buscamos en cada atributo restante
    for atributo, indice in indice_atributos.items():
        for valor in atributos[indice][1]:
            # Cogemos los datos correspondientes a ese atributo y valor
            datos_filtrados = [dato for dato in datos if dato[indice] == valor]

            # Realizamos la distribución de cada conjunto de datos
            Si.append(distribucion_clases(datos_filtrados))

        Si_dict.update({atributo: Si})
        Si = []

    """
    Declaramos la variable total para calcular cada una de las medias
    ponderadas
    """
    total = 0
    minimo = sys.maxsize
    mejor_atributo = ""

    for atributo in Si_dict:
        for Si in Si_dict[atributo]:

            # Si 'Si' no está vacio calculo su media
            if not not Si:
                total += calcular_media_ponderada(medida, S, Si)

        if total <= minimo:
            minimo = total
            mejor_atributo = atributo

    return mejor_atributo

"""
Obtiene un nuevo conjunto de datos
"""

def filtrar_nuevos_datos(datos, valor, indice):
    nuevos_datos = []

    for dato in datos:
        if valor in dato[indice]:
            nuevos_datos.append(dato)

    return nuevos_datos

"""
Obtener la categoría con más frecuencia
"""

def obtener_frecuencia_ordenada(lista):
    dict_aux = distribucion_clases(lista)
    resultado = dict()
    [resultado.update({k: dict_aux[k]}) for k in sorted(dict_aux, key=dict_aux.get)]
    return resultado

"""
Devuelve los ejemplos cubiertos que quedan cubiertos por la regla R en el conjunto de datos D
"""

def ejemplos_cubiertos(R, D):
    ejemplos_cubiertos = D

    for condicion in R:
        indice_atributo, valor = condicion
        ejemplos_cubiertos = [ejemplo for ejemplo in ejemplos_cubiertos if ejemplo[indice_atributo] == valor]

    return ejemplos_cubiertos

"""
Devuelve los ejemplos que están correctamente cubiertos por la regla R en el conjunto de datos D, y que coincidan con
la clase C.
"""

def ejemplos_correctamente_cubiertos(R, D, C):
    ejemplos = ejemplos_cubiertos(R, D)
    return filtrar_clase(ejemplos, C)

"""
Devuelve la frecuencia relativa para la regla R, en el conjunto de datos D, y para la clase C
"""

def frecuencia_relativa(R, D, C):
    t = len(ejemplos_cubiertos(R, D))
    p = len(ejemplos_correctamente_cubiertos(R, D, C))

    return p / t

"""
Una funcion que dada los atributos A y un conjuntos de datos D, devuelva una regla para ese conjunto de datos
"""

# =============================================================================
#         Una regla tiene la siguiente forma:
#         reglas = [
#             ([(1, 'uno'), (0, 'parado'), (3, 'dos o mas')], 'estudiar'),
#             ([(1, 'dos'), (0, 'parado'), (3, 'dos o mas')], 'no conceder'),
#         ]
# =============================================================================
def obtener_regla(A, D):
    indices = indice_atributos(A)
    regla_list = list()
    max_ejemplos_cubiertos = 0
    tupla_max = tuple()

    for atributo in indices:

        for valor_atributo in A[indices[atributo]][1]:

            # Genero la tupla con el indice del atributo y su valor
            tupla = (indices[atributo], valor_atributo)

            # Añado la tupla nueva a la copia de la lista
            regla_list.append(tupla)

            # Calculo cuantos ejemplos cubrimos con dicha regla
            ej_cubiertos = len(ejemplos_cubiertos(regla_list, D))

            # Compruebo si el recubrimiento de ejemplos es más grande que el maximo
            if ej_cubiertos > max_ejemplos_cubiertos:
                max_ejemplos_cubiertos = ej_cubiertos
                tupla_max = tupla

            # Elimino la tupla que insertamos al principio
            regla_list.remove(regla_list[-1])

        regla_list.append(tupla_max)
        max_ejemplos_cubiertos = 0

    return regla_list

"""
Función encargada de filtrar un conjunto de entrenamiento dada una clase
"""

def filtrar_clase(lista, clase):
    return [item for item in lista if item[-1] == clase]

"""
Una funcion que para una clase entera, devuelva todas las reglas de esa clase,
itera sobre la anterior y con el resto de atributos que no estén cubiertos por esa primera regla, se llama a la anterior
con el conjunto de ejemplos restante para crear otra regla, hasta que no queden ejemplos
"""

def obtener_reglas_por_clases(A, D, C):
    filtro_conjunto_datos = filtrar_clase(D, C)
    reglas_list = list()

    while len(filtro_conjunto_datos) != 0:
        regla = (obtener_regla(A, filtro_conjunto_datos), C)
        reglas_list.append(regla)
        filtro_conjunto_datos = list(
            filter(lambda x: x not in ejemplos_cubiertos(regla[0], filtro_conjunto_datos), filtro_conjunto_datos))

    return reglas_list

"""
Por último, otra que itere sobre todas las clases y llame a la anterior, pero en esta funcion en concreto no se reducen
los ejemplos.
"""

def obtener_total_reglas(A, D):
    reglas_list = list()

    C =list(obtener_frecuencia_ordenada(D).keys())

    # Cogemos todas las clases menos la última que será la de por defecto
    for clase in C[:-1]:
        reglas_list.append(obtener_reglas_por_clases(A, D, clase))

    # Aplanar lista de listas
    reglas_list = sum(reglas_list, [])

    # Añadimos la última regla por defecto
    reglas_list.append((None, C[-1]))

    return reglas_list


#!/usr/bin/env python

import rosbag
import os

path = '/data/ai02/didi/'

files = os.listdir(path)
for f in files:
    if f.endswith('.bag'):
        file = os.path.join(path, f)
        print('[ %s ]' % f)
        topicMap = {}
        bag = rosbag.Bag(file)
        totalTopics = 0
        for topic, _, _ in bag.read_messages():
            if topic not in topicMap:
                topicMap[topic] = 1
            else:
                topicMap[topic] += 1
            totalTopics += 1
        bag.close()
        topics = topicMap.keys()
        topics.sort()
        for topic in topics:
            print('  %s => %d' % (topic, topicMap[topic]))
        print('Total: %d\n' % totalTopics)


a = [1, 2, 3, 4, 5, 6]
b = [3, 4, 5, 6, 7, 8]

# Option-1

# for i in a:
#     if i in b:
#         print("yes--->{}".format(i))
#     else:
#         print("no--->{}".format(i))

# Option-2
# for i in a:
#     for j in b:
#         if i < j:
#             break
#         elif i == j:
#             print("Yes--->{}".format(i))
#             break
#         else:
#             continue

# Option-3
a = set(a)
b = set(b)

if a & b:
    print(a & b)
else:
    print("No Match")

# Option-4
if len(a.intersection(b)) > 0:
    print(a.intersection(b))
else:
    print("No Match")


from processors.awards import AwardProcessor,Column,PLAYER_COL

class Processor(AwardProcessor):
    '''
    Overview
    This processor keeps track of the most number of kills using defibrillator.

    Implementation
	Whenever a kill event is received involving a shotgun, the kill event
    is cached.

    Notes
	None.
    '''

    def __init__(self):
        AwardProcessor.__init__(self, 'The Shocker',
                'Most Kills with Defibrillators',
                [PLAYER_COL, Column('Kills', Column.NUMBER, Column.DESC)])

    def on_kill(self, e):

        # Ignore suicides and team kills
        if not e.valid_kill:
            return

        if e.weapon.id == 'defibrillator':
            self.results[e.attacker] += 1


lista = list()

while True:
    num = int(input("digite um valor: "))
    if num in lista:
        print("Valor duplicado! nao vou adicionar...")
        continue
    lista.append(num)
    print("Valor adicionado com sucesso...")
    perg = str(input("Quer continuar? [S/N] ")).upper().strip()[0]

    if perg not in 'SN':
        print("Resposta invalida!")

    if perg == 'N':
        break

print("-=" * 30)
lista.sort()
print(f'Você digitou os valores: {lista}')


from glob import glob
import os.path as osp

import numpy as np

from . import extra

def get_set_data(set_name, gtdir):
    if set_name == 'FDDB':
        fn, gt = get_fddb_data(gtdir)
    elif set_name == 'ICARTOON':
        fn, gt = get_icartoon_data(gtdir)
    elif set_name == 'PIXIV2018':
        fn, gt = get_pixiv2018_data(gtdir)
    elif set_name == 'PIXIV2018_ORIG':
        fn, gt = extra.get_pixiv2018_data_ORIG(gtdir)
    return fn, gt

def get_pixiv2018_data(gtdir):
    """Parses annotations given in a single "boxes.txt" file in the form of:
    <filename.jpg>, <number of boxes>, <n lines with x1, y1, x2, y2>, repeat.
    """
    fn, gt = [], []
    with open(osp.join(gtdir, 'boxes.txt')) as f:
        fni = f.readline()
        while fni:
            gti = []
            c = int(f.readline().rstrip())
            for _ in range(c):
                box = [int(c) for c in f.readline().rstrip().split(' ')]
                gti.append(box)
            gt.append(gti)
            fn.append(fni.rstrip())
            fni = f.readline()
    gt = [np.array(e) for e in gt]
    return fn, gt

def get_icartoon_data(gtdir):
    """Parses iCartoonFace detval annotations, which are given as '<filename>,x1,y1,x2,y2,face'"""
    fn, gt = [], []
    with open(osp.join(gtdir, 'personai_icartoonface_detval.csv')) as f:
        for line in f:
            s = line.split(',')
            name, box = s[0], [int(e) for e in s[1:5]]
            if not fn or fn[-1] != name:
                fn.append(name)
                gt.append([box])
            else:
                gt[-1].append(box)
    gt = [np.array(e) for e in gt]
    return fn, gt

def get_wider_data(gtdir):
    """Parses WIDER Face annotations. They are in Matlab's .mat files, so depends on scipy to read that.

    Source format example:
    event[i]:       13--Interview
    file[i][j]:     13_Interview_Interview_On_Location_13_921
    easy[i]:        []
    medium[i][j]:   [2 3]
    hard[i][j]:     [1 2 3 4]
    facebox[i][j]:  [[200 392  21  26]
                     [660 389  26  32]
                     [753 393  27  34]
                     [935 388  18  29]]

    The split into 3 difficulty settings is implemented by giving subsets of indices for all boxes,
    e.g. for example above for "medium" only boxes 2, 3 need to be detected and are treated as
    "false negatives" if absent, while boxes 1, 4 are ignored (so if a model detects them, they
    don't count as "false positives" (thus not lowering precision), but also don't count as
    "true positives" (thus not improving recall).
    """
    from scipy.io import loadmat
    gt_mat = loadmat(osp.join(gtdir, 'wider_face_val.mat'))
    hard_mat = loadmat(osp.join(gtdir, 'wider_hard_val.mat'))
    medium_mat = loadmat(osp.join(gtdir, 'wider_medium_val.mat'))
    easy_mat = loadmat(osp.join(gtdir, 'wider_easy_val.mat'))

    facebox_list = gt_mat['face_bbx_list']
    event_list = gt_mat['event_list']
    file_list = gt_mat['file_list']

    fn, gt, st = [], [], []
    for i in range(len(event_list)):
        for j in range(len(file_list[i][0])):
            flname = osp.join(event_list[i][0][0], file_list[i][0][j][0][0]) + '.jpg'
            bboxes = facebox_list[i][0][j][0]
            bboxes[:, 2] = bboxes[:, 2] + bboxes[:, 0]
            bboxes[:, 3] = bboxes[:, 3] + bboxes[:, 1]
            idx = [
                easy_mat['gt_list'][i][0][j][0],
                medium_mat['gt_list'][i][0][j][0],
                hard_mat['gt_list'][i][0][j][0]
            ]
            idx = [k if k.shape != (0, 0) else np.empty((0, 1), np.uint8) for k in idx]
            idx = [np.squeeze(k, axis=1) - 1 for k in idx]
            fn.append(flname)
            gt.append(bboxes)
            st.append(idx)
    return fn, gt, st

def get_fddb_data(gtdir):
    """Parses FDDB annotations. They are given as ellipses instead of boxes, so also converts that.

    Source line format: "major_axis_radius minor_axis_radius angle center_x center_y  1"
    (yes, always two spaces and 1 at the end)

    Also, here's a code example to draw an ellipse with cv2 if some testing is needed:
      center = (int(e[3]), int(e[4]))
      axesln = (int(e[0]), int(e[1]))
      angle = e[2] * 180 / np.pi
      cv2.ellipse(im, center, axesln, angle, 0, 360, (0, 0, 255), 2)
    """
    listing = sorted(glob(osp.join(gtdir, 'FDDB-fold-[0-9][0-9].txt')))
    details = sorted(glob(osp.join(gtdir, 'FDDB-fold-[0-9][0-9]-ellipseList.txt')))
    fn, gt = [], []
    for c in range(len(listing)):
        with open(listing[c]) as f:
            filenames = f.read().splitlines()
        with open(details[c]) as f:
            txt = f.read().splitlines()
        i = 0
        for f in filenames:
            assert f == txt[i]
            n = int(txt[i + 1])
            i += 2
            v = [list(map(float, s[:-3].split(' '))) for s in txt[i:i+n]]
            v = [get_ellipse_bounding_box(e[3], e[4], e[0], e[1], e[2]) for e in v]
            fn.append(f + '.jpg')
            gt.append(np.array(v))
            i += n
    return fn, gt

def get_ellipse_bounding_box(center_x, center_y, radius_x, radius_y, angle_radians):
    """Returns the bounding box for an arbitrarily rotated ellipse
    using a solution from here: https://stackoverflow.com/a/14163413
    """
    ux = radius_x * np.cos(angle_radians)
    uy = radius_x * np.sin(angle_radians)
    vx = radius_y * np.sin(angle_radians)
    vy = radius_y * np.cos(angle_radians)
    half_w = np.sqrt(ux * ux + vx * vx)
    half_h = np.sqrt(uy * uy + vy * vy)
    x1, x2 = center_x - half_w, center_x + half_w
    y1, y2 = center_y - half_h, center_y + half_h
    return [x1, y1, x2, y2]


from src.utility.config import Config
from src.preprocessor import IPreprocessor, TextPreprocessor

# --- [Global Variable] ---
textPrep: IPreprocessor = None

def build_text_prep(config: Config) -> IPreprocessor:
    global textPrep
    if textPrep is not None:
        return textPrep

    params = {
        "component": config.preprocessor_component,
    }

    prep = TextPreprocessor(**params)
    textPrep = prep

    return prep


"""Make HTTP PUT request.

Make a HTTP request with method PUT to URL _u

Source: programming-idioms.org
"""

# Implementation author: awesmubarak
# Created on 2019-09-26T19:06:19.150608Z
# Last modified on 2019-09-27T19:11:23.885446Z
# Version 2

requests

import requests

content_type = "text/plain"
headers = {"Content-Type": content_type}
data = {}

r = requests.put(url, headers=headers, data=data)
status_code, content = r.status_code, r.content


from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
import requests, json

# Create your views here.
def home(request):
    return HttpResponse("Hello, Django!")

def taskstring(request):
    result = 'Rest API string!'
    return HttpResponse(result, content_type="text/plain")

def taskxml(request):
    result = '''<employees>
                <employee><firstName>John</firstName> <lastName>Doe</lastName></employee>
                <employee><firstName>Anna</firstName> <lastName>Smith</lastName></employee>
                </employees>'''
    return HttpResponse(result, content_type='text/xml')

def taskjson(request):
    result = {"employees":[{"firstName":"John", "lastName":"Doe"},
                           {"firstName":"Anna", "lastName":"Smith"},
                           {"firstName":"Peter", "lastName":"Jones"}]}
    return JsonResponse(result)

def openweatherget(request):
    url = 'http://api.openweathermap.org/data/2.5/weather?q={}&appid=fd3121df45fa165283b9f3fe57b82b19'
    cities = ['London', "Seoul"]
    for city in cities:
        return city
    c = url.format(city)
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'}
    res = requests.get(url=c, headers=headers)
    res.raise_for_status()
    rt_dict = json.loads(res.content)
    return JsonResponse(rt_dict)

    #depts = {'name':[{'f':'moon'},{'s':'seob'}]}
    #print(depts['name'][0]['f'])
    #output(moon)


import random
def game(computer,a):
    if computer == a:
        return None
    elif computer == "rock":
        if a == "paper":
            return False
        elif a == "scissor":
            return True
    elif computer == "paper":
        if a == "scissor":
            return False
        elif a == "rock":
            return True
    elif computer == "scissor":
        if a == "rock":
            return False
        elif a == "paper":
            return True

print("computers: rock,paper & scissor")
r = random.choice(["rock","paper","scissor"])
if r == "rock":
    computer = "rock"
if r == "paper":
    computer = "paper"
if r == "scissor":
    computer = "scissor"
w = 0
l = 0
z = 0
for i in range(5):
    a = input("Choose:")
    while(a!= "rock"and a!= "paper"and a!= "scissor"):
        print("Value is not given")
        a = input("Choose:")
    b = game(computer,a)

    print(f"Computer choose: {computer}")
    print(f"You Choose: {a}")

    if b == None:
        z = (int(z))+1

        print("This game is tied")
    elif b:
        print("You Win")
        w = w+1

    else:
        print("you Lose")
        l = l+1
    print("you:\n",w)
    print("computer:\n",l)
    print("Tied:\n",z)
if (w>l):
    print("You win")
elif(l>w):
    print("Computer wins")
else:
    print("The Game is Tied")

print ("Thankyou for playing")


#!/bin/python
# -*- encoding:utf-8 -*-

# 给定一个长度为n的整数数组，你的任务是在最多改变一个元素的情况下该数组能否变成一个的非递减数列

def if_in_ordered(arr):
    count = 0
    n = len(arr)
    for i in range(1, n):
        if arr[i] < arr[i - 1]:
            count += 1
            if count > 1:
                return False
            if i > 1:
                if arr[i] <= arr[i - 2]:
                    arr[i] = arr[i - 1]
    return True

a = [1, 2, 3, 5, 6, 7, 8, 3, 7, 10]
print(if_in_ordered(a))


#!/usr/bin/python3
def add_integer(a, b=98):
    """ Add two integers """
    if isinstance(a, int) and isinstance(b, int):
        return a + b
    elif isinstance(a, float) and isinstance(b, float):
        return int(a) + int(b)
    elif isinstance(a, float) and isinstance(b, int):
        return int(a) + b
    elif isinstance(a, int) and isinstance(b, float):
        return a + int(b)
    elif not isinstance(a, int) and not isinstance(a, float):
        raise TypeError("a must be an integer")
    else:
        raise TypeError("b must be an integer")

if __name__ == "__main__":
    import doctest
    doctest.testfile("./tests/0-add_integer.txt")


import random

def coin(n):
    head = tail = 0
    for i in range(n):
        x = random.randint(0, 1)
        if x == 0:
            tail += 1
        else:
            head += 1
    return head / n, tail / n

head, tail = coin(1000000)
print(f'tura: {head}, yazı: {tail}')


#%%
from base import *

#%% Construct \text{d}\Psi_X matrix
dPsi_X = np.zeros((k, m))
for row in range(k):
    for column in range(m-1):
        dPsi_X[row, column] = dpsi(X, row, column)
dPsi_X_T = dPsi_X.T

#%%
def sparsifyDynamics(Theta, dXdt, lamb, n):
    Xi = np.linalg.lstsq(Theta, dXdt, rcond=None)[0] # Initial guess: Least-squares

    for k in range(10):
        smallinds = np.abs(Xi) < lamb # Find small coefficients
        Xi[smallinds] = 0                          # and threshold
        for ind in range(n):                       # n is state dimension
            biginds = smallinds[:, ind] == 0
            # Regress dynamics onto remaining terms to find sparse Xi
            Xi[biginds, ind] = np.linalg.lstsq(Theta[:, biginds], dXdt[:, ind], rcond=None)[0]

    return Xi

#%%
lamb = 0.05 # sparsification knob lambda
Xi = sparsifyDynamics(Psi_X.T, dPsi_X.T, lamb, d)
#%%
L = Xi # estimate of Koopman generator

#%%
L_times_B_transposed = (L @ B).T
def b(l):
    return L_times_B_transposed @ Psi_X[:, l] # (k,)

#%% Performs really well!
r = 10
for l in range(r):
    b_l = b(l)
    print(f"b({r}):", b_l)

# %%
L_times_second_order_B_transpose = (L @ second_order_B).T
def a(l):
    return (L_times_second_order_B_transpose @ Psi_X[:, l]) - \
        (second_order_B.T @ nablaPsi[:, :, l] @ b(l))

#%% Reshape a vector as matrix and perform some tests
def covarianceMatrix(a_func, l):
    a_l = a_func(l)
    covariance = np.zeros((d, d))
    covariance[0, 0] = a_l[0]
    row = 0
    col = 1
    n = 1
    while col < d:
        covariance[row, col] = a_l[n]
        covariance[col, row] = a_l[n]
        if row == col:
            col += 1
            row = 0
        else:
            row += 1
        n +=1
    return covariance

#%% Did not perform well ):
test = covarianceMatrix(a, 2)
test_df = pd.DataFrame(test)
print("a:", test_df)
print("a diagonal:", np.diagonal(test))

#%% Condition numbers - we want small numbers
print("Condition number of L:", np.linalg.cond(L)) # inf
print("Condition number of Phi_X:", np.linalg.cond(Psi_X)) # 98 million+
# %%


import pandas as pd

data={
    "cus_id":[1,2,3,4,5,6],
    "cus_name":["nithin","kishore","sai nithin","nithin sai","sai kishore","rocky"],
    "cus_age":[20,30,20,25,25,25]
    }

data1=pd.DataFrame(data)
group=data1.groupby('cus_age')['cus_id']
print(group.count())


if __name__ == "__main__":
    scores = []
    names = []
    results = {}

    for _ in range(int(input())):
        name = input()
        score = float(input())
        names.append(name)
        scores.append(score)
        results[name] = score

    scores = list(set(scores))
    scores.sort()
    low2 = scores[1]

    lowersNames = []

    for i in names:
        if results[i] == low2:
            lowersNames.append(i)

    lowersNames.sort()

    for lower in lowersNames:
        print(lower)


from django.test import TestCase
from django.http import HttpRequest

from students.models import Student, Group
from students.util import get_groups, get_current_group, paginate, boundsStuds

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

from datetime import date

class UtilsTestCase(TestCase):
	"""Test functions from util module"""

	def setUp(self):
		# create group
		group1, created = Group.objects.get_or_create(
			id=1,
			title="Group1")
		group2, created = Group.objects.get_or_create(
			id=2,
			title="Group2")
		group3, created = Group.objects.get_or_create(
			id=3,
			title="Group3")
		student1, created = Student.objects.get_or_create(
			id=1,
			first_name="Ivan",
			last_name="Ivanenko",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group1,
			study_start=date(2007, 9, 1))
		student2, created = Student.objects.get_or_create(
			id=2,
			first_name="Ivan2",
			last_name="Ivanenko2",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group1,
			study_start=date(2007, 9, 1))
		student3, created = Student.objects.get_or_create(
			id=3,
			first_name="Ivan3",
			last_name="Ivanenko3",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group2,
			study_start=date(2007, 9, 1))
		student4, created = Student.objects.get_or_create(
			id=4,
			first_name="Ivan4",
			last_name="Ivanenko4",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group2,
			study_start=date(2007, 9, 1))
		student5, created = Student.objects.get_or_create(
			id=5,
			first_name="Ivan5",
			last_name="Ivanenko5",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group3,
			study_start=date(2007, 9, 1))
		student6, created = Student.objects.get_or_create(
			id=6,
			first_name="Ivan6",
			last_name="Ivanenko6",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group3,
			study_start=date(2007, 9, 1))
		student7, created = Student.objects.get_or_create(
			id=7,
			first_name="Ivan7",
			last_name="Ivanenko7",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group3,
			study_start=date(2007, 9, 1))
		student8, created = Student.objects.get_or_create(
			id=8,
			first_name="Ivan8",
			last_name="Ivanenko8",
			birthday=date(2000, 12, 5),
			ticket=123,
			student_group=group3,
			study_start=date(2007, 9, 1))

	def test_get_current_group(self):
		# prepare request object to pass to utility function
		request = HttpRequest()

		# test with no group set in cookie
		request.COOKIES['current_group'] = ''
		self.assertEqual(None, get_current_group(request))

		# test with invalid group id
		request.COOKIES['current_group'] = '12345'
		self.assertEqual(None, get_current_group(request))

		# test with proper group identificator
		group = Group.objects.filter(title='Group1')[0]
		request.COOKIES['current_group'] = str(group.id)
		self.assertEqual(group, get_current_group(request))

	def test_get_group(self):
		request = HttpRequest()
		queryset_groups = Group.objects.all()

		request.COOKIES['current_group'] = queryset_groups.filter(title='Group1')[0]
		groups = get_groups(request)
		self.assertEqual(type([]), type(groups))

		value_groups = len(queryset_groups)
		self.assertEqual(value_groups, len(groups))

		for group in groups:
			self.assertTrue(len(queryset_groups.filter(pk=group['id'])))

	def test_paginate(self):
		request = HttpRequest()
		paginator = Paginator

		request.GET['page'] = 2
		size = 1
		objects = Group.objects.all()
		dict_context = {}

		paginator = paginator(objects, size)
		page = paginator.page(2)

		context = paginate(objects, size, request, dict_context)
		# self.assertTrue(page == context['object_list'])
		self.assertTrue(context['is_paginated'])
		# self.assertEqual(page, context['page_obj'])
		# self.assertEqual(paginator, context['paginator'])
		self.assertEqual(paginator.object_list, context['paginator'].object_list)

		self.assertRaises(EmptyPage, paginator.page, 1212)
		self.assertRaises(PageNotAnInteger, paginator.page, "number")

	def test_boundsStuds(self):
		students = Student.objects.all()
		request = HttpRequest()

		students_on_page = 3
		request.GET['page'] = '1'
		self.assertEqual((0,3), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '2'
		self.assertEqual((3,6), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '3'
		self.assertEqual((6,8), boundsStuds(students, students_on_page, request))

		students_on_page = 2
		request.GET['page'] = '1'
		self.assertEqual((0,2), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '2'
		self.assertEqual((2,4), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '3'
		self.assertEqual((4,6), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '4'
		self.assertEqual((6,8), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '56'
		self.assertEqual((6,8), boundsStuds(students, students_on_page, request))

		request.GET['page'] = '-23'
		self.assertEqual((0,2), boundsStuds(students, students_on_page, request))

		request.GET['page'] = 'strPage'
		self.assertEqual((0,2), boundsStuds(students, students_on_page, request))
		self.assertRaises(TypeError, boundsStuds(students, students_on_page, request))


import torch
from classifier import ColorClassifier
from dataset_det import Balls_CF_Detection
from torch.utils.tensorboard import SummaryWriter
import numpy as np

# environment settings
device = torch.device("cuda" if torch.cuda.is_available() else 'cpu')
print(torch.cuda.get_device_name(torch.cuda.current_device()))
writer = SummaryWriter("runs/color_classifier.01")

# dataset
train_dataset = Balls_CF_Detection("train", 18899, train=1)
valid_dataset = Balls_CF_Detection("valid", 2099)

# dataloader
training = torch.utils.data.DataLoader(train_dataset,
                                       batch_size=50, shuffle=True)
validation = torch.utils.data.DataLoader(valid_dataset,
                                         batch_size=50, shuffle=True)

# model
model = ColorClassifier().to(device)
model.cuda()
criterion = torch.nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

batch_size_1 = 378
batch_size_2 = 42
dataset_1 = 18900 * 9
dataset_2 = 2100 * 9
train_loss = 0
train_error = 0
validation_loss = 0
validation_error = 0

for epoch in range(200):
    print("starting epoch:", epoch, "loss:", "training", train_loss, "validation", validation_loss, "error:",
          "training", train_error, "validation", validation_error)

    train_loss = 0
    train_error = 0
    validation_loss = 0
    validation_error = 0

    for batch, (train_img, train_presence, train_box) in enumerate(training):

        if (batch % 50) == 0:
            print("batch:", batch)

        optimizer.zero_grad()
        out1 = model(train_img.to(device))

        loss = criterion(out1.to(device), train_presence.to(device))
        train_loss += loss.item()

        loss.backward()
        optimizer.step()

        out1[out1 > 0.5] = 1
        out1[out1 < 0.5] = 0
        train_error += (out1 != train_presence.to(device)).sum().item()

    for batch, (valid_img, valid_presence, valid_box) in enumerate(validation):

        if (batch % 20) == 0:
            print("batch:", batch)

        out2 = model(valid_img.to(device))

        loss = criterion(out2.to(device), valid_presence.to(device))
        validation_loss += loss.item()

        out2[out2 > 0.5] = 1
        out2[out2 < 0.5] = 0
        validation_error += (out2 != valid_presence.to(device)).sum().item()

    train_loss = train_loss / batch_size_1
    train_error = train_error / dataset_1

    validation_loss = validation_loss / batch_size_2
    validation_error = validation_error / dataset_2

    writer.add_scalars("loss", {"training": train_loss, "validation": validation_loss}, epoch)
    writer.add_scalars("error", {"training": train_error, "validation": validation_error}, epoch)

# save the results
torch.save({"state_dict": model.state_dict(),
            "epoch": 200},
           "colorClassifier.pth")
writer.close()


import collections
from winnow.utils import deep_copy_dict as deepcopy
# from copy import deepcopy

from winnow import utils
from winnow.values.option_values import OptionWinnowValue

from winnow.values import value_factory, value_path_factory
from winnow.values.option_values import OptionResourceWinnowValue, OptionStringWinnowValue
from winnow.values.exception_values import ExceptionWinnowValue

from winnow.keys.key_matching import KeyMatcher
from winnow.exceptions import OptionsExceptionSetWithException
import time

"""

OptionsSet

This is the beef.

all the logical operations on sieves actually happen in their options dict

"""

class OptionsSet(collections.MutableMapping):
    """a dict like object that supports merging, patching etc wraps an existing dict"""

    def __init__(self, d):
        """
        really its just a wrapped around an existing dict
        """
        self.store = d
        self.matcher = KeyMatcher.from_dict(d)

    def __getitem__(self, key):
        return self.store[key]

    def __setitem__(self, key, value):
        self.store[key] = value

    def __delitem__(self, key):
        del self.store[key]

    def __iter__(self):
        return iter(self.store)

    def __len__(self):
        return len(self.store)

    def mega_store(self, other):

        #
        # print "****STORES****"
        # print self.store
        # print other.store
        #

        expanded = deepcopy(self.store)
        for k in self.store.keys():
            if "*" in k:
                matching = other.matcher.get_matching_paths(k)
                for match in matching:
                    expanded[match] = self.store[k]
                # this consumes matched wildcards values
                if matching:
                    del expanded[k]
        mega_store = {}

        for k, v in expanded.iteritems():
            new_key, real_value = value_path_factory(k, v)
            if real_value is not None:
                if not new_key in mega_store.keys():
                    mega_store[new_key] = []
                mega_store[new_key].append(real_value)

        return mega_store

    def _merge_value_array(self, key, values):

        value_types = set([type(v) for v in values])
        #
        if value_types == {OptionStringWinnowValue, OptionResourceWinnowValue}:
            raise Exception("cant mix strings and resources")

        if len(values) == 1:
            return values[0]
        result = values[0]
        for v in values[1:]:
            result = result.intersection(v)
            if result == None:
                return ExceptionWinnowValue(key, [v.as_json() for v in values])

        return result

    def _check_for_exceptions(self, all_values):
        for v in all_values:
            if isinstance(v, ExceptionWinnowValue):
                return v

        return None

    def merge(self, other):
        """
        A union of all keys
        An intersection of values
        """

        options = {}
        this_mega_store = self.mega_store(other)
        that_mega_store = other.mega_store(self)
        this_keys = set(this_mega_store.keys())
        that_keys = set(that_mega_store.keys())
        emptyValues = []

        # print this_keys, that_keys
        for key in this_keys.union(that_keys):
            all_values = this_mega_store.get(key, []) + that_mega_store.get(key, [])
            exception_value = self._check_for_exceptions(all_values)
            if exception_value:
                merged_value = exception_value
            else:
                merged_value = self._merge_value_array(key, all_values)

            options[key] = merged_value.as_json()
            if isinstance(merged_value, ExceptionWinnowValue):
                options[key] = None
                emptyValues.append((key, all_values))

        options_set = OptionsSet(options)

        if emptyValues:
            raise OptionsExceptionSetWithException(options_set, emptyValues)

        return options_set

    def disallowed_keys(self, other):
        return self._disallowed(other)

    def allows(self, other):
        disallowed = self._disallowed(other)
        return not bool(disallowed)

    def _disallowed(self, other):
        """
        An intersection of keys
        A subset check on values
        """

        disallowed = []

        this_mega_store = self.mega_store(other)
        that_mega_store = other.mega_store(self)
        this_keys = set(this_mega_store.keys())
        that_keys = set(that_mega_store.keys())

        if this_keys is not None and that_keys is not None:
            all_keys = this_keys.intersection(that_keys)
            if all_keys is not None:
                for key in all_keys:
                    all_values = this_mega_store.get(key, []) + that_mega_store.get(key, [])
                    exception_value = self._check_for_exceptions(all_values)
                    if exception_value:
                        disallowed.append(key)
                    else:
                        this = self._merge_value_array(key, this_mega_store[key])
                        that = self._merge_value_array(key, that_mega_store[key])
                        if not that.issubset(this):
                            disallowed.append(key)
        return disallowed

    def default(self):
        options = {}
        for k, v in self.store.iteritems():
            value = value_factory(v)
            options[k] = value.default
            if isinstance(value, OptionWinnowValue):
                child_options = value.get_default_value_options()
                if child_options is not None:
                    childSet = OptionsSet(child_options)
                    child_defaults = childSet.default().store
                    for ck, cv in child_defaults.iteritems():
                        path = "{}/{}".format(k, ck)
                        options[path] = cv
        return OptionsSet(options)

    def default_full_values(self):
        options = {}
        for k, v in self.store.iteritems():
            options[k] = value_factory(v).default_full_value
        return OptionsSet(options)

    #
    # def scope(self, scope_name):
    #     """
    #     extracts a subset of options by scope
    #     """
    #     options = {}
    #     for k, v in self.store.iteritems():
    #         if isinstance(v, dict) and u"scopes" in v.keys():
    #             scopes = set(v[u"scopes"])
    #             if not scopes.isdisjoint(set([scope_name])):
    #                 options[k] = deepcopy(v)
    #         else:
    #             options[k] = deepcopy(v)
    #     return OptionsSet(options)

    def match(self, others):
        return [other for other in others if self.allows(other)]

    def reverse_match(self, others):
        return [other for other in others if other.allows(self)]

    @property
    def key_set(self):
        return set(self.store.keys())


# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    launcher.py                                        :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: ariard <ariard@student.42.fr>              +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2017/04/21 20:57:06 by ariard            #+#    #+#              #
#    Updated: 2017/05/11 23:41:15 by ariard           ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

import os
import sys
import time
import copy
import pty
import logging
import threading

from taskmaster.debug import *
from taskmaster.task_error import *

import taskmaster.settings as settings

def start_launcher(program, name_process, name_prog, retries):
    t = threading.Thread(target=launcher, args=(program, name_process, name_prog, retries))
    t.start()

def start_protected_launcher(program, name_process, name_prog, retries):
    t = threading.Thread(target=protected_launcher, args=(program, name_process, name_prog, retries))
    t.start()

class Process:
    def __init__(self, name_process, pid, status, retries, name_prog, write_in, read_out, read_err):
        self.name_process = name_process
        self.pid = pid
        self.status = status
        self.retries = retries
        self.father = name_prog
        self.time = time.time()
        self.process_fd = [write_in, read_out, read_err]

def protected_launcher(program, name_process, name_prog, retries):

    while settings.tab_process[name_process].status != "EXITED" and settings.tab_process[name_process].status != "STOPPED" \
        and settings.tab_process[name_process].status != "FATAL" and settings.tab_process[name_process].status != "UNKNOWN":
        time.sleep(1)
    DG("ok " + name_process)
    launcher(program, name_process, name_prog, retries)

def launcher(program, name_process, name_prog, retries):

    read_in, write_in = os.pipe()
    read_out, write_out = os.pipe()
    read_err, write_err = os.pipe()

    try:
        pid = os.fork()
    except BlockingIOError:
        logging.info("Taskmasterd server ended")
        error_msg("Fork temporary unavailable, taskmasterd exiting")

    if pid > 0:
        DG("in_process is " + str(write_in))
        settings.fds.append(read_out)
        settings.fds.append(read_err)
        settings.fd2realfile[read_out] = program.stdout
        settings.fd2realfile[read_err] = program.stderr
        os.close(read_in)
        os.close(write_out)
        os.close(write_err)
        if program.startsecs > 0:
            status = "STARTING"
        elif program.startretries > retries:
            status = "BACKOFF"
        else:
            status = "RUNNING"
        process = Process(name_process, pid, status, retries, name_prog, write_in, read_out, read_err)
        settings.pid2name[pid] = name_process
        settings.tab_process[name_process] = process
        settings.lst_pid.append(pid)

    if pid == 0:
        os.dup2(read_in, 0)
        os.dup2(write_out, sys.stdout.fileno())
        os.dup2(write_err, sys.stderr.fileno())
        os.close(write_in)
        os.close(read_out)
        os.close(read_err)
        program.conf()
        try:
            args = program.command.split(' ')
            DG("I launch " + name_process)
            DG(args[0])
            os.execv(args[0], args)
        except:
            sys.exit(-1)


import serial
import time
import threading
import logging

logger = logging.getLogger('main_logger')
logger.setLevel(logging.DEBUG)
logging_format = logging.Formatter('  %(asctime)s - %(levelname)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S')

fileHandler = logging.FileHandler(filename="./software_log.log")
fileHandler.setFormatter(logging_format)
logger.addHandler(fileHandler)

consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logging_format)
logger.addHandler(consoleHandler)

class linear_displacement:
    def __init__(self,portname=None):
        self.serial_port = serial.Serial(port=portname,baudrate=9600,timeout=0.5)
        self.data_list = []
        self.temp_data = ""
        self.serial_state = 0
        self.run_mthread = True
        self.displacement_thread = None

    def run(self):
        self.displacement_thread = threading.Thread(target=self.read_data,)
        self.run_mthread = True
        self.displacement_thread.start()

    def read_data(self):
        while self.run_mthread:
            if self.serial_port.inWaiting():
            # if self.serial_port.in_waiting():
                input_char = self.serial_port.read()
                if ord(input_char) == 0:
                    # logger.debug(self.temp_data)
                    try:
                        self.data_list.append(self.temp_data)
                        self.temp_data = ""
                    except:
                        self.temp_data = ""
                elif ord(input_char) >= 80:
                    self.temp_data = ""
                else:
                    self.temp_data = self.temp_data + input_char.decode()
            time.sleep(0.005)

    def stop(self):
        self.run_mthread = False
        self.displacement_thread.join()
        self.serial_port.close()
        self.displacement_thread = None

    def get_last(self):
        return_value = None
        if len(self.data_list) > 0:
            return_value = self.data_list[-1]
            self.data_list = []
        return return_value

    def get_data(self):
        return_value = None
        if len(self.data_list) > 0:
            return_value = self.data_list[0]
            self.data_list.pop(0)
        return return_value

    def clear_data(self):
        self.data_list = []

if __name__ == "__main__":
    pass
    # print("11111")
    # dd = linear_displacement(portname="COM9")
    # dd.run()
    # # time.sleep(2)
    # for i in range(1000):
    #     int_data = dd.get_last()
    #     # print(int_data)
    #     if int_data != None:
    #         logger.debug(int_data)
    #     time.sleep(0.01)
    # dd.stop()
    # while True:
    #     in_data = dd.get_data()
    #     if in_data != None:
    #         logger.debug(in_data)
    #     time.sleep(0.01)
    # int_data = dd.get_data()
    # for i in range(1000):
    #     int_data = dd.get_last()
    #     if int_data != None:
    #         logger.debug(int_data)
    #     time.sleep(0.01)
    # dd.stop()
    # dd.run()
    # for i in range(3000):
    #     int_data = dd.get_data()
    #     if int_data != None:
    #         logger.debug(int_data)
    #     time.sleep(0.01)
    # dd.stop()


import streamlit as st
import pandas as pd
import plotly.express as px

df = pd.read_excel('D:\dakeshna\Django Python\phonepe.xlsx')

st.set_page_config(page_title='My Dashboard')
st.title('My Dashboard')

state = st.sidebar.selectbox('Select a state', df['state'].unique())

filtered_df = df[df['state'] == state]

fig = px.bar(filtered_df, x='transaction_type', y='transaction_count', color='year',
             title='Transaction Count by Transaction Type')
st.plotly_chart(fig)

fig = px.line(filtered_df, x='year', y='transaction_amount', title='Transaction Amount Over Time')
st.plotly_chart(fig)

fig = px.scatter(filtered_df, x='transaction_count', y='transaction_amount', color='year',
                 title='Transaction Count vs. Transaction Amount')
st.plotly_chart(fig)


import os
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QWidget, QGridLayout, QHBoxLayout, QLabel, QVBoxLayout, QTextEdit, QPushButton, QScrollArea, \
    QSizePolicy, QSpacerItem
from PyQt5.QtCore import Qt, QRect
import json

class InputTab(QWidget):
    """
    Create the data input tab for the simulation
    """
    def __init__(self, mainWindow):
        super().__init__()
        # tab structure --> tab --> horizontal layout --> QScrollArea (scrollArea) --> QWidget (scrollAreaWidgetContents) --> QGridLayout --> 4 QGridLayouts + save button --> labels + textEdits in each of the 4 sub grid layouts
        self.scrollArea = QScrollArea()
        self.scrollArea.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self.scrollArea.setWidgetResizable(True)

        self.scrollAreaWidgetContents = QWidget(self.scrollArea)
        self.scrollAreaWidgetContents.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))

        self.saveButton = QPushButton()
        self.saveButton.setText("Save")
        self.saveButton.setMaximumWidth(100)
        self.HeadingFont()

        # these 4 methods generate the four settings categories and labels/Textedits for each category
        self.GeneralSettings()
        self.CostingSettings()
        self.AnalysisSettings()
        self.VisualiserSettings()
        self.saveButton.clicked.connect(lambda: self.SaveSettings(mainWindow))

        # sets layouts parent to be the scrollAreaWidget
        self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
        # adds the 4 layouts for the 4 sections
        self.gridLayout.addLayout(self.generalGridLayout, 0, 0, 1, 1)
        self.gridLayout.addLayout(self.costingGridLayout, 1, 0, 1, 1)
        self.gridLayout.addLayout(self.analysisGridLayout, 0, 1, 1, 1)
        self.gridLayout.addLayout(self.visualiserGridLayout, 1, 1, 1, 1)
        self.gridLayout.addWidget(self.saveButton,2,1,alignment=Qt.AlignRight)

        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.tabLayout = QHBoxLayout()
        self.tabLayout.addWidget(self.scrollArea)
        self.setLayout(self.tabLayout)

    def GeneralSettings(self):
        self.generalGridLayout = QGridLayout()
        self.generalGridLayout.setContentsMargins(0,0,0,10)
        # heading label for the section
        headingLabel = QLabel(self.scrollAreaWidgetContents)
        headingLabel.setText("General Settings")
        headingLabel.setFont(self.headingFont)

        # these store the label/textEdit objects
        self.generalSettingsLabels = []
        self.generalSettingsEdits = []
        # stores the text for the labels
        self.generalSettingsLabelNames = ['Version number:','Memory allocation:','Multicore enabled:','Something else:']
        # generates a textEdit and label for each named label
        for i in range(len(self.generalSettingsLabelNames)):
            self.generalSettingsLabels.append(QLabel(self.scrollAreaWidgetContents))
            self.generalSettingsEdits.append(QTextEdit(self.scrollAreaWidgetContents))
            self.generalSettingsEdits[i].setMaximumSize(100, 25)
            self.generalSettingsLabels[i].setText(self.generalSettingsLabelNames[i])
            self.generalGridLayout.addWidget(self.generalSettingsLabels[i], i+1, 0)
            self.generalGridLayout.addWidget(self.generalSettingsEdits[i], i+1, 1)
        # adds the heading label and a spacer to force the labels to the top of the section
        self.generalGridLayout.addWidget(headingLabel,0,0)
        self.generalGridLayout.addItem(QSpacerItem(0,0,QSizePolicy.Minimum,QSizePolicy.Expanding))

    def CostingSettings(self):
        self.costingGridLayout = QGridLayout()
        headingLabel = QLabel(self.scrollAreaWidgetContents)
        headingLabel.setText("Costing Settings")
        headingLabel.setFont(self.headingFont)

        self.costingSettingsLabels = []
        self.costingSettingsEdits = []
        self.costingSettingsLabelNames = ['Cost threshold:','Evolution limit:','Nodes limit:','Nodes per evolution limit:']

        for i in range(len(self.costingSettingsLabelNames)):
            self.costingSettingsLabels.append(QLabel(self.scrollAreaWidgetContents))
            self.costingSettingsEdits.append(QTextEdit(self.scrollAreaWidgetContents))
            self.costingSettingsEdits[i].setMaximumSize(100, 25)
            self.costingSettingsLabels[i].setText(self.costingSettingsLabelNames[i])
            self.costingGridLayout.addWidget(self.costingSettingsLabels[i], i+1, 0)
            self.costingGridLayout.addWidget(self.costingSettingsEdits[i], i+1, 1)

        self.costingGridLayout.addWidget(headingLabel,0,0)
        self.costingGridLayout.addItem(QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))

    def AnalysisSettings(self):
        self.analysisGridLayout = QGridLayout()
        self.analysisGridLayout.setContentsMargins(30,0,0,10)

        headingLabel = QLabel(self.scrollAreaWidgetContents)
        headingLabel.setText("Analysis Settings")
        headingLabel.setFont(self.headingFont)

        self.analysisSettingsLabels = []
        self.analysisSettingsEdits = []
        self.analysisSettingsLabelNames = ['All match value:','Negatives match value:','Positives match value:','Same sign value:','All values value:','All nones value:','Same order mag value:']

        for i in range(len(self.analysisSettingsLabelNames)):
            self.analysisSettingsLabels.append(QLabel(self.scrollAreaWidgetContents))
            self.analysisSettingsEdits.append(QTextEdit(self.scrollAreaWidgetContents))
            self.analysisSettingsEdits[i].setMaximumSize(100, 25)
            self.analysisSettingsLabels[i].setText(self.analysisSettingsLabelNames[i])
            self.analysisGridLayout.addWidget(self.analysisSettingsLabels[i], i+1, 0)
            self.analysisGridLayout.addWidget(self.analysisSettingsEdits[i], i+1, 1)

        self.analysisGridLayout.addWidget(headingLabel,0,0)
        self.analysisGridLayout.addItem(QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))

    def VisualiserSettings(self):
        self.visualiserGridLayout = QGridLayout()
        self.visualiserGridLayout.setContentsMargins(30,0,0,0)
        headingLabel = QLabel(self.scrollAreaWidgetContents)
        headingLabel.setText("Visualiser Settings")
        headingLabel.setFont(self.headingFont)

        self.visualiserSettingsLabels = []
        self.visualiserSettingsEdits = []
        self.visualiserSettingsLabelNames = ['Visualiser on:','Task view:','Evolution view:','Max nodes to visualise:']
        for i in range(len(self.visualiserSettingsLabelNames)):
            self.visualiserSettingsLabels.append(QLabel(self.scrollAreaWidgetContents))
            self.visualiserSettingsEdits.append(QTextEdit(self.scrollAreaWidgetContents))
            self.visualiserSettingsEdits[i].setMaximumSize(100, 25)
            self.visualiserSettingsLabels[i].setText(self.visualiserSettingsLabelNames[i])
            self.visualiserGridLayout.addWidget(self.visualiserSettingsLabels[i], i+1, 0, 1, 1)
            self.visualiserGridLayout.addWidget(self.visualiserSettingsEdits[i], i+1, 1, 1, 1)
        self.visualiserGridLayout.addWidget(headingLabel,0,0,1,1)
        self.visualiserGridLayout.addItem(QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))

    def HeadingFont(self):
        self.headingFont = QFont('Arial', 12)
        self.headingFont.setUnderline(True)

    def SaveSettings(self, mainWindow):
        data = {}
        data['general'] = []
        data['costing'] = []
        data['analysis'] = []
        data['visualiser'] = []

        for i, textValue in enumerate(self.generalSettingsEdits):
            data['general'].append({self.generalSettingsLabelNames[i]:textValue.toPlainText()})

        for i, textValue in enumerate(self.costingSettingsEdits):
            data['costing'].append({self.costingSettingsLabelNames[i]:textValue.toPlainText()})

        for i, textValue in enumerate(self.analysisSettingsEdits):
            data['analysis'].append({self.analysisSettingsLabelNames[i]:textValue.toPlainText()})

        for i, textValue in enumerate(self.visualiserSettingsEdits):
            data['visualiser'].append({self.visualiserSettingsLabelNames[i]:textValue.toPlainText()})

        with open('data.txt','w') as outFile:
            json.dump(data,outFile)
            mainWindow.textBrowser.append("Save Successful")


# -*- coding: utf-8 -*-

from frfs.solvers.base import BaseSystem
from frfs.solvers.dgfs.elements import DGFSElements
from frfs.solvers.dgfs.velocitymesh import DGFSVelocityMesh
from frfs.solvers.dgfs.scattering import DGFSScatteringModel
from frfs.solvers.dgfs.initcond import DGFSInitCondition
from frfs.solvers.dgfs.inters import (DGFSIntInters, DGFSMPIInters,
                                       DGFSBCInters)
from frfs.inifile import Inifile
from frfs.util import subclass_where, proxylist, ndrange
import numpy as np
import pycuda.driver as cuda
from pycuda import gpuarray
from frfs.mpiutil import get_comm_rank_root, get_mpi

class DGFSSystem(BaseSystem):
    #print("Initializing DGFS system")

    name = 'dgfs'

    elementscls = DGFSElements
    intinterscls = DGFSIntInters
    mpiinterscls = DGFSMPIInters
    bbcinterscls = DGFSBCInters
    velocitymeshcls = DGFSVelocityMesh
    scatteringcls = DGFSScatteringModel

    _nqueues = 2

    def __init__(self, backend, rallocs, mesh, initsoln, nreg, cfg):

        # load the velocity mesh
        self.vm = self.velocitymeshcls(backend, cfg)

        cv = self.vm.cv()
        vsize = self.vm.vsize()

        # need to define the expressions
        # the prefix "f_" should be same as in elementcls distvar
        # size of distvar should be equal to NvBatchSize
        for ivar in range(self.vm.NvBatchSize()):
            cfg.set('soln-ics', 'f_' + str(ivar), '0.')

        # now, we can initialize things
        super().__init__(backend, rallocs, mesh, initsoln, nreg, cfg,
            vm=self.vm)
        print('Finished initializing the BaseSystem')

        # define the time-step
        minjac = 100.0
        for t, ele in self.ele_map.items():
            djac = ele.djac_at_np('upts')
            minjac = np.min([minjac, np.min(djac)])
        advmax = self.vm.L()
        unitCFLdt = np.array([np.sqrt(minjac)/advmax/self.ndims])
        gunitCFLdt = np.zeros(1)
        # MPI info
        comm, rank, root = get_comm_rank_root()
        # Reduce and, if we are the root rank, output
        if rank != root:
            comm.Reduce(unitCFLdt, gunitCFLdt, op=get_mpi('min'), root=root)
        else:
            comm.Reduce(unitCFLdt, gunitCFLdt, op=get_mpi('min'), root=root)
            print("Time-step for unit CFL:", gunitCFLdt)
            print("The actual time-step will depend on DG order CFL")

        # load the scattering model
        smn = cfg.get('scattering-model', 'type')
        scatteringcls = subclass_where(self.scatteringcls,
            scattering_model=smn)
        self.sm = scatteringcls(backend, self.cfg, self.vm)

        # Allocate and bank the storage required by the time integrator
        eles_scal_upts_full = proxylist(self.ele_banks)
        eles_scal_upts_inb_full = proxylist(self.ele_banks)
        #eles_scal_upts_outb_full = proxylist(self.ele_banks)

        if initsoln:
            # Load the config and stats files from the solution
            solncfg = Inifile(initsoln['config'])
            solnsts = Inifile(initsoln['stats'])

            # Get the names of the conserved variables (fields)
            solnfields = solnsts.get('data', 'fields', '')
            currfields = ','.join(['f_'+str(i) for i in range(vsize)])

            # Ensure they match up
            if solnfields and solnfields != currfields:
                raise RuntimeError('Invalid solution for system')

            # Ensure the solnfields are not empty
            if not solnfields:
                raise RuntimeError('Invalid solution for system')

            # Process the solution
            for t, (k, ele) in enumerate(self.ele_map.items()):
                soln = initsoln['soln_%s_p%d' % (k, rallocs.prank)]

                #ele.set_ics_from_soln(soln, solncfg)
                # Recreate the existing solution basis
                solnb = ele.basis.__class__(None, solncfg)

                # Form the interpolation operator
                interp = solnb.ubasis.nodal_basis_at(ele.basis.upts)

                # Apply and reshape
                eles_scal_upts_full[t] = np.dot(
                    interp, soln.reshape(solnb.nupts, -1))
                eles_scal_upts_full[t] = eles_scal_upts_full[t].reshape(
                    ele.nupts, vsize, ele.neles)
        else:
            # load the initial condition model
            icn = cfg.get('soln-ics', 'type')
            initcondcls = subclass_where(DGFSInitCondition, model=icn)
            ic = initcondcls(backend, cfg, self.vm, 'soln-ics')

            # loop over the sub-domains in the full mixed domain
            for t, ele in enumerate(self.ele_map.values()):
                eles_scal_upts_full[t] = np.empty(
                    (ele.nupts, vsize, ele.neles))

                ic.apply_init_vals(eles_scal_upts_full[t], ele)
                # Convert from primitive to conservative form if needed

        for t, scal_upts_full in enumerate(eles_scal_upts_full):
            scal_upts_full = [
                backend.matrix(scal_upts_full.shape,
                scal_upts_full, tags={'align'}) for i in range(nreg)]

            eles_scal_upts_inb_full[t] = backend.matrix_bank(scal_upts_full)
            #eles_scal_upts_outb_full[t] = backend.matrix_bank(scal_upts_full)

        #self.eles_scal_upts_full = eles_scal_upts_full
        self.eles_scal_upts_inb_full = eles_scal_upts_inb_full
        #self.eles_scal_upts_outb_full = eles_scal_upts_outb_full

    def rhs(self, t, uinbank, foutbank, batch, varidx):
        runall = self.backend.runall
        q1, q2 = self._queues
        kernels = self._kernels

        self.eles_scal_upts_inb.active = uinbank
        self.eles_scal_upts_outb.active = foutbank

        dtype = self.eles_scal_upts_inb[0][0].dtype
        varidx_f = np.array([varidx], dtype=dtype)[0]

        q1 << kernels['eles', 'disu']()
        q1 << kernels['mpiint', 'scal_fpts_pack']()
        runall([q1])

        if ('eles', 'copy_soln') in kernels:
            q1 << kernels['eles', 'copy_soln']()
        q1 << kernels['eles', 'tdisf'](varidx=varidx_f)
        q1 << kernels['eles', 'tdivtpcorf']()
        q1 << kernels['iint', 'comm_flux'](varidx=varidx_f)
        q1 << kernels['bcint', 'comm_flux'](t=t, varidx=varidx_f)

        q2 << kernels['mpiint', 'scal_fpts_send']()
        q2 << kernels['mpiint', 'scal_fpts_recv']()
        q2 << kernels['mpiint', 'scal_fpts_unpack']()

        runall([q1, q2])

        q1 << kernels['mpiint', 'comm_flux'](varidx=varidx_f)
        q1 << kernels['eles', 'tdivtconf']()
        if ('eles', 'tdivf_qpts') in kernels:
            q1 << kernels['eles', 'tdivf_qpts']()
            q1 << kernels['eles', 'negdivconf'](t=t)
            q1 << kernels['eles', 'divf_upts']()
        else:
            q1 << kernels['eles', 'negdivconf'](t=t)

        runall([q1])

    def updatebc(self, t, uinbank, foutbank, batch, varidx):
        runall = self.backend.runall
        q1, q2 = self._queues
        kernels = self._kernels

        self.eles_scal_upts_inb.active = uinbank
        self.eles_scal_upts_outb.active = foutbank

        dtype = self.eles_scal_upts_inb[0][0].dtype
        varidx_f = np.array([varidx], dtype=dtype)[0]

        # compute the face-point soln given the initial soln
        q1 << kernels['eles', 'disu']()
        runall([q1])

        q1 << kernels['bcint', 'update_bc'](t=t, varidx=varidx_f)
        runall([q1])

    def collide(self, t, uinbank, foutbank):
        runall = self.backend.runall
        q1, q2 = self._queues
        kernels = self._kernels

        self.eles_scal_upts_inb_full.active = uinbank
        self.eles_scal_upts_inb_full.active = foutbank

        fsoln = self.eles_scal_upts_inb_full

        #for t in range(len(fsoln)):
        for t, ele in enumerate(self.ele_types):
            arr_in = fsoln[t][uinbank]
            arr_out = fsoln[t][foutbank]
            nupts, _, _ = arr_in.traits
            _, neles = arr_in.ioshape[1:]
            #djac = ele.djac_at('upts')

            for elem, upt in ndrange(neles, nupts):
                self.sm.fs(arr_in, arr_out, elem, upt)

    def invmass(self, uinbank, foutbank):
        runall = self.backend.runall
        q1, q2 = self._queues
        kernels = self._kernels

        self.eles_scal_upts_inb.active = uinbank
        self.eles_scal_upts_outb.active = foutbank

        # multiply by the inverse mass matrix
        q1 << kernels['eles', 'invmass']()
        runall([q1])


import SimpleITK as sitk
from typing import Sequence, Tuple

def overlay_bounding_boxes(
    image: sitk.Image,
    bounding_boxes: Sequence[Sequence[float]],
    bounding_box_format: str = "MINXY_MAXXY",
    normalized: bool = False,
    colors: Sequence[int] = [],
    half_line_width: int = 0,
) -> Tuple[sitk.Image, bool]:
    """
    Overlay axis aligned bounding boxes on a 2D image. The function supports several ways of specifying a
    bounding box using pixel indexes:

    1. "MINXY_MAXXY" - [min_x, min_y, max_x, max_y]
    2. "MINXY_WH" - [min_x, min_y, width, height]
    3. "CENT_WH" - [center_x, center_y, width, height]
    4. "CENT_HALFWH" - [center_x, center_y, width/2, height/2]

    Bounding boxes are plotted in the order they appear in the iterable/list. To change the overlap between rectangles
    change the order in the list. The last entry in the list will be plotted on top of the previous ones.

    Caveat: When using larger line widths, bounding boxes that are very close to the image border may cause an exception
    and result in partial overlay. A trivial solution is to decrease the value of the half_line_width parameter.

    :param image: Input image, 2D image with scalar or RGB pixels on which we plot the bounding boxes.
    :param bounding_boxes: Bounding boxes to plot. Each bounding box is represented by four numbers.
    :param bounding_box_format: One of ["MINXY_MAXXY", "MINXY_WH", "CENT_WH", "CENT_HALFWH"] specifying the meaning of
    the four entries representing the bounding box.
    :param normalized: Indicate whether the bounding box numbers were normalized to be in [0,1].
    :param colors: Specify the color for each rectangle using RGB values, triplets in [0,255].
    Useful for visually representing different classes (relevant for object detection). Most often a flat
    list, e.g. colors = [255, 0, 0, 0, 255, 0] reresents red, and green.
    :param half_line_width: Plot using thicker lines.
    :return: A tuple where the first entry is a SimpleITK image with rectangles plotted on it and the second entry is a boolean
    which is true if one or more of the rectangles were out of bounds, false otherwise.
    """
    # functions that convert from various bounding box representations to the [min_x, min_y, max_x, max_y] representation.
    convert_to_minxy_maxxy = {
        "MINXY_MAXXY": lambda original: original,
        "MINXY_WH": lambda original: [
            [bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3]]
            for bbox in original
        ],
        "CENT_WH": lambda original: [
            [
                bbox[0] - bbox[2] / 2.0,
                bbox[1] - bbox[3] / 2.0,
                bbox[0] + bbox[2] / 2.0,
                bbox[1] + bbox[3] / 2.0,
            ]
            for bbox in original
        ],
        "CENT_HALFWH": lambda original: [
            [bbox[0] - bbox[2], bbox[1] - bbox[3], bbox[0] + bbox[2], bbox[1] + bbox[3]]
            for bbox in original
        ],
    }

    # Confirm image is in expected format
    pixel_type = image.GetPixelID()
    num_channels = image.GetNumberOfComponentsPerPixel()
    if pixel_type not in [sitk.sitkUInt8, sitk.sitkVectorUInt8]:
        raise ValueError(
            f"Image channels expected to have type of 8-bit unsigned integer, got ({image.GetPixelIDTypeAsString()})"
        )
    if num_channels not in [1, 3]:
        raise ValueError(
            f"Image expected to have one or three channels, got ({num_channels})"
        )
    if num_channels == 3:
        overlay_image = sitk.Image(image)
    else:
        overlay_image = sitk.Compose([image] * 3)
    if half_line_width < 0:
        raise ValueError(
            f"Half line width parameter expected to be non-negative, got ({half_line_width})"
        )
    # Convert bounding box information into standard format, based on user specification of the original format
    try:
        standard_bounding_boxes = convert_to_minxy_maxxy[bounding_box_format](
            bounding_boxes
        )
        if normalized:
            scale_x, scale_y = image.GetSize()
            standard_bounding_boxes = [
                [
                    bbox[0] * scale_x,
                    bbox[1] * scale_y,
                    bbox[2] * scale_x,
                    bbox[3] * scale_y,
                ]
                for bbox in standard_bounding_boxes
            ]
        # round to integer coordinates
        standard_bounding_boxes = [
            [int(b + 0.5) for b in bbox] for bbox in standard_bounding_boxes
        ]
    except KeyError:
        raise ValueError(
            f"Unknown bounding box format ({bounding_box_format}), valid values are [MINXY_WH, MINXY_MAXXY, CENT_WH, CENT_HALFWH]"
        )
    if not colors:  # use a single color for all bounding boxes
        colors = [[255, 0, 0]] * len(standard_bounding_boxes)
    else:
        colors = [colors[i : i + 3] for i in range(0, len(colors), 3)]
    line_width = 1 + 2 * half_line_width
    out_of_bounds = False
    for bbox, color in zip(standard_bounding_boxes, colors):
        width = bbox[2] - bbox[0]
        height = bbox[3] - bbox[1]
        vert = sitk.Compose(
            [
                sitk.Image([line_width, height + line_width], sitk.sitkUInt8)
                + color[0],
                sitk.Image([line_width, height + line_width], sitk.sitkUInt8)
                + color[1],
                sitk.Image([line_width, height + line_width], sitk.sitkUInt8)
                + color[2],
            ]
        )
        horiz = sitk.Compose(
            [
                sitk.Image([width, line_width], sitk.sitkUInt8) + color[0],
                sitk.Image([width, line_width], sitk.sitkUInt8) + color[1],
                sitk.Image([width, line_width], sitk.sitkUInt8) + color[2],
            ]
        )
        try:
            overlay_image[
                bbox[0] - half_line_width : bbox[0] + half_line_width + 1,  # noqa E203
                bbox[1] - half_line_width : bbox[3] + half_line_width + 1,  # noqa E203
            ] = vert
            overlay_image[
                bbox[2] - half_line_width : bbox[2] + half_line_width + 1,  # noqa E203
                bbox[1] - half_line_width : bbox[3] + half_line_width + 1,  # noqa E203
            ] = vert
            overlay_image[
                bbox[0] : bbox[2],  # noqa E203
                bbox[1] - half_line_width : bbox[1] + half_line_width + 1,  # noqa E203
            ] = horiz
            overlay_image[
                bbox[0] : bbox[2],  # noqa E203
                bbox[3] - half_line_width : bbox[3] + half_line_width + 1,  # noqa E203
            ] = horiz
        except Exception:  # Drawing outside the border of the image will cause problems
            out_of_bounds = True
            continue
    return overlay_image, out_of_bounds


from typing import Optional

import nltk
from nltk.corpus import wordnet as wn
from pycorenlp import StanfordCoreNLP

from importer.database.data_types import Post
from importer.database.mongodb import MongodbStorage

nltk.download('wordnet')

nlp = StanfordCoreNLP('http://localhost:9000')
properties_pos = {'annotators': 'pos', 'outputFormat': 'json'}

def _replace_pos(pos_tag: str) -> Optional[str]:
    if pos_tag.startswith("NN"):
        return "n"
    elif pos_tag.startswith("JJ"):
        return "a"
    elif pos_tag.startswith("V"):
        return "v"
    elif pos_tag.startswith("RB"):
        return "r"
    else:
        return None

def get_synonym(post_content: str) -> list:
    output = nlp.annotate(post_content, properties_pos)
    if not isinstance(output, dict):
        return []

    tokens = []
    for sentence in output.get("sentences", []):
        for token in sentence["tokens"]:
            tokens.append((token["originalText"], _replace_pos(token["pos"])))

    augmentations = []
    for index in range(len(tokens)):
        helper(tokens=tokens, index=index, augmentations=augmentations)

    return [" ".join([word[0] for word in sentence]).strip() for sentence in augmentations]

def helper(tokens: list, index: int, augmentations: list):
    if index > len(tokens) - 1:
        return

    token = tokens[index]
    synonyms = []
    if token[1] is not None:
        synsets = wn.synsets(token[0], pos=token[1])
        if len(synsets) > 0:
            synonyms = synsets[0].lemma_names()

    synonyms = list(set([synonym.lower() for synonym in synonyms]))

    synonyms_cleaned = []
    lower = token[0].lower()
    for synonym in synonyms:
        if synonym.lower() != lower:
            synonyms_cleaned.append(synonym)

    del synonyms

    if len(synonyms_cleaned) > 0:
        # Use only the first synonym due to the high number of new posts
        synonym = synonyms_cleaned[0]

        del synonyms_cleaned

        new_tokens = list(tokens)
        new_tokens[index] = (synonym, token[1])
        augmentations.append(new_tokens)
        helper(new_tokens, index=index + 1, augmentations=augmentations)

if __name__ == '__main__':
    db = MongodbStorage()
    reactions_list = ["LIKE", "LOVE", "WOW", "HAHA", "SAD", "ANGRY"]

    posts_with_reactions = []

    count = db.count_posts(filter={})
    for index, post in enumerate(db.iterate_single_post(filter={})):
        assert isinstance(post, Post)

        print("\rReading data %.2f%%" % ((index + 1) / count * 100), end='')

        sum = 0
        for key in reactions_list:
            sum += post.reactions[key]
        if sum == 0:
            continue

        posts_with_reactions.append(post)

    count = len(posts_with_reactions)
    for index, post in enumerate(posts_with_reactions):

        print("\rProcessing data %.2f%%" % ((index + 1) / count * 100), end='')

        for i, sentence in enumerate(get_synonym(post.message)):
            data = dict(post.data)
            data[Post.COLL_MESSAGE] = sentence
            data[Post.COLL_POST_ID] += "_{}".format(i)
            new_post = Post(data)
            db.insert_post(new_post)


import json
import requests
import pandas as pd
import numpy as np
import datetime as dt
from sqlalchemy import create_engine
import pymysql
import os
res = pd.DataFrame()

#명촌돟 평창리비에르2차 : 16248
#화봉동 쌍용예가 : 105026
#번영로 하늘채 : 132862
#야음 동부 : 6053
#대현 더샵 2 : 111348

#단지 LIST
aptArray = ['16248','105026','132862','6053','111348']

for i in range(0, len(aptArray)):

    # 네이버 한페이지에 20개 밖에 로드 안시킴. 넉넉히 20페이지 까지 탐색하고 결과값 없으면 break
    for j in range(1, 20):

        url = f"https://m.land.naver.com/complex/getComplexArticleList?hscpNo={aptArray[i]}&cortarNo=3120012000&tradTpCd=A1%3AB1%3AB2&order=point_&showR0=N&page={j}"

        payload={}
        headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.151 Whale/3.14.134.62 Safari/537.36'}
        response = requests.request("GET", url, headers=headers, data=payload)

        # print(response.text)c

        data = json.loads(response.text)
        # print(data)
        items = data['result']['list']
        # print(items[0])

        df = pd.DataFrame.from_dict(items)
        # print(df[['spc2','prcInfo']])

        # 호출되는 모든 apt별 page concat
        if i == 0 and j == 1:
            res = df
        else :
           res = pd.concat([res,df], ignore_index=True)

        # print(f'{i} - {j} - {len(df)}')

        # page호출 결과 없으면 for문 중단
        if len(df) == 0 :
            break

#필요한 Column만 골라 씀
# sortRes = res[['atclNm','bildNm', 'flrInfo', 'spc2','tradTpNm', 'prcInfo']].sort_values(by=['prcInfo'],ascending=False)
finalRes = pd.DataFrame(res[['atclNm','bildNm', 'flrInfo', 'spc2','tradTpNm', 'prcInfo']])
finalRes['date'] = dt.datetime.now().date()
finalRes['date'] = pd.to_datetime(finalRes['date'])

# 면적, 가격은 Numeric으로 변환
finalRes['spc2'] = pd.to_numeric(finalRes['spc2'])
# finalRes['prcInfo'] = pd.to_numeric(finalRes['prcInfo'].str.replace('억','').str.replace(',','').str.replace(' ',''))

# 가격 string to int
def priceRe(x) :

    total = 0

    if '억' in x :

        a = x.split('억')[0]
        b = x.split('억')[1]
        if b == '' :
            total = int(a) * 10000
        else :

            total = int(a) * 10000 + int(b.replace('/',''))
    else:

        if '/' in x :
            total = int(x.replace('/','999'))
        else :
            total = int(x)

    return total

finalRes['prcInfo'] = finalRes['prcInfo'].str.replace(',','').apply(lambda x : priceRe(x))

print(finalRes)
print(finalRes.info())

#CSV파일 저장
# finalRes.to_csv(os.path.join("check.csv"), index=False,encoding="euc-kr")

#DB 저장 (MySQL Connector using pymysql)

pymysql.install_as_MySQLdb()

engine = create_engine('mysql+mysqlconnector://crawl_user:test001@localhost:3306/crawl_data', encoding='utf-8')
conn = engine.connect()

finalRes.to_sql(name='naver2', con=engine, if_exists='append', index = False)

conn.close()