#!/usr/bin/env python
# -*- coding: utf-8 -*-

#-- General imports --#

#-- 3rd party imports --#
import spacy

class Sentence_processor(object):

    def __init__(self, language):
        if language == 'Id' :
            self.model = spacy.load('Id')
        else:
            self.model = spacy.load('en')

    def remove_stop_words_and_lemmatize(self, sentence):
        print("This is the sentence processing {}".format(sentence))
        spacy_sentence = self.model(sentence)
        final_sentence = ""
        for token in spacy_sentence:
            print("analysing {}".format(token))
            if not token.lemma_.lower() in self.stop_words:
                if not final_sentence: final_sentence = str(token).lower()#.lemma_
                else: final_sentence = "{} {}".format(final_sentence, str(token).lower())#.lemma_)
        return final_sentence

    def process_sentence(self, sentence):
        processed_sentence = sentence
        processed_sentence = self.remove_stop_words_and_lemmatize(processed_sentence)
        return processed_sentence


import pandas as pd

df_d = pd.read_csv('../Data_Science_Post/survey_results_public.csv')
df_q = pd.read_csv('../Data_Science_Post/survey_results_schema.csv')

# Creating an excel spreadsheet for easier raw data visualization:

with pd.ExcelWriter('stack_data.xlsx',mode='w') as writer:
    df_d.to_excel(writer,sheet_name='Data',)
    df_q.to_excel(writer,sheet_name='Description')


import os
import re
from collections import defaultdict
from typing import Dict, Iterable, List

import matplotlib
import matplotlib.pyplot as plt

from datatypes import Feerate, btc_to_sat
from feerates import logger
from feerates.graphs.graph_utils import PlotData, plot_figure
from paths import FEE_ESTIMATIONS_DIR

matplotlib.rcParams.update({'font.size': 10})

BYTE_IN_KBYTE = 1000

estimation_sample_file_regex = re.compile("estimatesmartfee_blocks=(\\d+)_mode=(\\w+)")

# only estimations in the time window [MIN_TIMESTAMP, MAX_TIMESTAMP] will be included
# by the parse_estimation_files method. set both to None to include all estimations

# this range gives us blocks 620136-630247
MIN_TIMESTAMP = 1583317269
MAX_TIMESTAMP = 1589384721

# only show graphs for these values of num_blocks. set to None to include all
num_blocks_to_include = [1]

def parse_estimation_files() -> Dict[int, List[PlotData]]:
    """
    read all fee estimation files and prepare the plot data

    returns a dictionary from blocks_count (number of blocks used for the estimation)
    to a list of 'graphs' (represented by PLOT_DATA)
    """
    data = defaultdict(list)
    for entry in os.listdir(FEE_ESTIMATIONS_DIR):
        match = estimation_sample_file_regex.fullmatch(entry)
        if not match:
            continue  # not an estimation file
        num_blocks: int = int(match.group(1))
        mode: str = match.group(2)
        if num_blocks_to_include is not None and num_blocks not in num_blocks_to_include:
            continue

        timestamps = []
        feerates = []
        with open(os.path.join(FEE_ESTIMATIONS_DIR, entry)) as f:
            for line in f.readlines():
                try:
                    timestamp_str, feerate_str = line.strip().split(",")
                    # feerate returned by `estimatesmartfee` is in BTC/kB
                    feerate_btc_kb = float(feerate_str)
                    feerate: Feerate = btc_to_sat(feerate_btc_kb) / BYTE_IN_KBYTE
                    timestamp = int(timestamp_str)
                    if MIN_TIMESTAMP is None or MAX_TIMESTAMP is None or MIN_TIMESTAMP <= timestamp <= MAX_TIMESTAMP:
                        timestamps.append(timestamp)
                        feerates.append(feerate)
                except ValueError:
                    logger.error(f"ignoring line in file `{entry}` with unexpected format: `{line}`")

        data[num_blocks].append(
            PlotData(timestamps=timestamps, feerates=feerates, label=f"estimatesmartfee(n={num_blocks},mode={mode})")
        )

    return data

def get_feerates_percentile(samples: Iterable[float], p: float) -> float:
    """
    return the p'th percentile of the samples
    0 < p < 1
    """
    sorted_samples = sorted(samples)
    return sorted_samples[:int(len(sorted_samples) * p)][-1]

def main():
    data = parse_estimation_files()

    p_values = [0.2, 0.5, 0.8]
    for num_blocks, plot_data_list in data.items():
        for plot_data in plot_data_list:
            fig = plot_figure(title="", plot_data_list=[plot_data], figsize=(6.66, 3.75))
            plt.figure(fig.number)
            # for p in p_values:
            #     percentile = get_feerates_percentile(plot_data.feerates, p=p)
            #     plt.hlines(
            #         y=percentile,
            #         xmin=plot_data.timestamps[0],
            #         xmax=plot_data.timestamps[-1],
            #         label=f"{int(p * 100)}'th percentile ({round(percentile, 1)})",
            #     )
            plt.legend(loc="best")
            plt.grid()
            plt.xlabel("Estimation time")
            plt.ylabel("Estimated feerate (sat/B)")
    plt.savefig("estimated-feerates.svg", bbox_inches='tight')
    # plt.show()

if __name__ == "__main__":
    main()


#!/usr/bin/python3
"""
This module multiplies 2 matrix
Raises ValueError TypeError
"""

def matrix_mul(m_a, m_b):
    """
    function to multiply 2 matrix
    """
    listErr = "{} must be a list"
    emptyErr = "{} can't be empty"
    typeErr = "{} should contain only integers or floats"
    sizeErr = "each row of {} must should be of the same size"

    if type(m_a) is not list:
        raise TypeError(listErr.format('m_a'))
    if type(m_b) is not list:
        raise TypeError(listErr.format('m_b'))

    if len(m_a) == 0 or type(m_a[0]) is list and len(m_a[0]) == 0:
        raise ValueError(emptyErr.format('m_a'))
    if len(m_b) == 0 or type(m_b[0]) is list and len(m_b[0]) == 0:
        raise ValueError(emptyErr.format('m_b'))

    s = -1

    for x in m_a:
        if type(x) is list:
            if s == -1:
                s = len(x)
            else:
                if s != len(x):
                    raise TypeError(sizeErr.format('m_a'))
            for y in x:
                if not isinstance(y, (int, float)):
                    raise TypeError(typeErr.format('m_a'))
        else:
            raise TypeError(typeErr.format('m_a'))

    s = -1

    for x in m_b:
        if isinstance(x, list):
            if s == -1:
                s = len(x)
            else:
                if s != len(x):
                    raise TypeError(sizeErr.format('m_b'))
            for y in x:
                if not isinstance(y, (int, float)):
                    raise TypeError(typeErr.format('m_b'))
        else:
            raise TypeError(typeErr.format('m_b'))

    if len(m_a[0]) != len(m_b):
        raise ValueError('m_a and m_b can\'t be multiplied')

    final = [[0 for a in m_b[0]] for x in m_a]
    for i in range(len(m_a)):
        for n in range(len(m_b[0])):
            for k in range(len(m_b)):
                final[i][n] += m_a[i][k] * m_b[k][n]

    return final


"""
Word Transformation
Source: Big-O   Time Limit: 1000ms   Memory Limit: 512MB
"""
def checkword(s1, s2):
    if len(s1) != len(s2):
        return False
    count = 0
    for i in range(len(s1)):
        if s1[i] != s2[i]:
            count += 1
            if count == 2:
                return False
    return True

def bfs(s, e, n, graph):
    visited = [False] * n
    visited[s] = True
    queue = [(s, 0)]
    while len(queue) > 0:
        u, w = queue.pop(0)
        for v in graph[u]:
            if not visited[v]:
                visited[v] = True
                queue.append((v, w + 1))
                if v == e:
                    return w + 1
    return 0

def process():
    words = []
    while True:
        d = input()
        if d != '*':
            words.append(d)
        else:
            break

    size = len(words)
    graph = [[] for _ in range(size)]
    for i in range(size-1):
        for j in range(i + 1, size):
            if checkword(words[i], words[j]):
                graph[i].append(j)
                graph[j].append(i)

    while True:
        try:
            params = input()
            if len(params) == 0:
                break
            text1, text2 = params.split()
            res = bfs(words.index(text1), words.index(text2), size, graph)
            print(text1, text2, res)
        except EOFError:
            break

if __name__ == "__main__":
    iTC = int(input())
    for i in range(iTC):
        if i == 0:
            input()
        process()
        if i < iTC - 1:
            print()


import math

def CalcFuel(mass):
    fuel = math.floor(mass / 3) - 2
    print(fuel)
    return fuel

# UnitTest
arr = [12, 14, 1969, 100756]
sum = 0

for item in arr:
    sum += CalcFuel(item)
print(sum)

# Input from File and Sum
inputsum = 0.0
with open('Data.txt') as f:
    for line in f:
        inputsum += CalcFuel(int(line))
        print(inputsum)


# code from: https://www.pygame.org/wiki/OBJFileLoader
# modified to fit our models

import pygame
from OpenGL.GL import *
from os import path
import importlib

def MTL(filename):
    contents = {}
    mtl = None
    for line in open("models/"+filename, "r"):
        if line.startswith('#'):
            continue
        values = line.split()
        if not values:
            continue
        if values[0] == 'newmtl':
            mtl = contents[values[1]] = {}
        elif mtl is None:
            raise ValueError("mtl file doesn't start with newmtl stmt")
        elif values[0] == 'map_d':
            pass
        elif values[0] == 'map_Ks':
            pass
        elif values[0] == 'map_Bump':
            pass
        elif values[0] == 'map_Kd':
            # load the texture referred to by this declaration
            mtl[values[0]] = values[1]
            surf = pygame.image.load("models/"+mtl['map_Kd'])
            image = pygame.image.tostring(surf, 'RGBA', 1)
            ix, iy = surf.get_rect().size
            texid = mtl['texture_Kd'] = glGenTextures(1)
            glBindTexture(GL_TEXTURE_2D, texid)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                            GL_LINEAR)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                            GL_LINEAR)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, image)
        else:
            mtl[values[0]] = list(map(float, values[1:]))
    return contents

class OBJ:
    def __init__(self, filename, mtl_index, swapyz=False):
        # l_f = "{}_loaded.py".format(filename.split(".")[0])
        l_f = ""
        if path.exists(l_f):
            print("File found")
            module_name = l_f.split(".")[0]
            module = importlib.import_module(module_name)
            self.gl_list = module.get_gl_list()
            return
        else:
            print("Loading")
            self.load(filename, mtl_index, swapyz)

    def load(self, filename, mtl_index, swapyz=False):
        """Loads a Wavefront OBJ file. """
        self.vertices = []
        self.normals = []
        self.texcoords = []
        self.faces = []

        material = None
        for line in open(filename, "r"):
            if line.startswith('#'):
                continue
            values = line.split()
            if not values:
                continue
            if values[0] == 'v':
                v = list(map(float, values[1:4]))
                if swapyz:
                    v = v[0], v[2], v[1]
                self.vertices.append(v)
            elif values[0] == 'vn':
                v = list(map(float, values[1:4]))
                if swapyz:
                    v = v[0], v[2], v[1]
                self.normals.append(v)
            elif values[0] == 'vt':
                self.texcoords.append(list(map(float, values[1:3])))
            elif values[0] in ('usemtl', 'usemat'):
                material = values[1]
            elif values[0] == 'mtllib':
                if int(values[1]) == mtl_index:
                    self.mtl = MTL(values[2])
            elif values[0] == 'f':
                face = []
                texcoords = []
                norms = []
                for v in values[1:]:
                    w = v.split('/')
                    face.append(int(w[0]))
                    if len(w) >= 2 and len(w[1]) > 0:
                        texcoords.append(int(w[1]))
                    else:
                        texcoords.append(0)
                    if len(w) >= 3 and len(w[2]) > 0:
                        norms.append(int(w[2]))
                    else:
                        norms.append(0)
                self.faces.append((face, norms, texcoords, material))

        self.gl_list = glGenLists(1)
        glNewList(self.gl_list, GL_COMPILE)
        # glEnable(GL_TEXTURE_2D)
        glFrontFace(GL_CCW)
        for face in self.faces:
            vertices, normals, texture_coords, material = face

            mtl = None
            if self.mtl and material:
                mtl = self.mtl[material]
                if 'texture_Kd' in mtl:
                    # use diffuse texmap
                    glBindTexture(GL_TEXTURE_2D, mtl['texture_Kd'])
                else:
                    # just use diffuse colour
                    glColor(*mtl['Kd'])

            glBegin(GL_POLYGON)
            for i in range(len(vertices)):
                if normals[i] > 0:
                    glNormal3fv(self.normals[normals[i] - 1])
                if texture_coords[i] > 0:
                    glTexCoord2fv(self.texcoords[texture_coords[i] - 1])
                glVertex3fv(self.vertices[vertices[i] - 1])
            glEnd()
        # glDisable(GL_TEXTURE_2D)
        glEndList()


# -*- coding: utf-8 -*-
"""
Created on Thu Sep  2 14:52:37 2021

@author: angel
"""

from numpy import transpose, linalg, set_printoptions, full, copy, array, zeros, asarray, vstack, shape, ones, dot, arange, empty
from pylab import legend, xlabel, ylabel, title, plot, xlim, grid
from linear_algebra import transposition, rank, echelon_form, pivot_index, laplace, gauss_elimination

set_printoptions(precision=4)

def linear_independent(*v):
    """
    OK
    Determines which vectors are linearly independent.
    The algorithm inserts every column-like vector in an emtpy matrix, then proceeds to reduce this
    matrix to echelon form; indexes of pivot columns are searched and stored in a list by pivot_column()

    Parameters
    ----------
    *v : array
        Arbitraty number of vectors.

    Returns
    -------
    independent : array
        Array of linear independent vectors.
    """
    vectors = copy(v)
    c = len(vectors)
    r = len(vectors[0])

    M = full((c, r), vectors)
    M = transposition(M)

    E = copy(M)
    E = echelon_form(E)
    pivot_row, pivot_column = pivot_index(E)

    independent = []
    for p in pivot_column:
        independent.append(M[:,p])

    print('Column index(es) of linear independet vectors: ', pivot_column)
    return independent

def generator(*v):
    """
    Determines whether the input vectors are a generating set.

    Parameters
    ----------
    *v : array
        Arbitraty number of vectors.

    Returns
    -------
    generators : array
        Array of generating set vectors.

    """
    vectors = copy(v)
    c = len(vectors)
    r = len(vectors[0])

    M = full((c, r), vectors)
    M = transposition(M)

    E = copy(M)
    E = echelon_form(E)
    pivot_row, pivot_column = pivot_index(E)

    generators = []
    for p in pivot_row:
        generators.append(M[p,:])

    print('Row index(es) of generator vectors: ', pivot_row)
    return generators

def base(*v):
    """
    Determines whether the input vectors are base of a vector space.

    Parameters
    ----------
    *v : array
        Arbitraty number of vectors.

    Returns
    -------
    is_base: bool
    base: bidimensional array
        Base.

    """

    tol=1e-10
    vectors = copy(v)
    c = len(vectors)
    r = len(vectors[0])
    is_base = False

    base = full((c, r), vectors)
    base = transposition(base)

    if abs(c-r)<tol and laplace(base)!=0:
        is_base = True
        return is_base, base
    else:
        return is_base

def norm(A, s):
    """
    Computes norm 1 or Inf of a generic matrix m-by-n.

    Parameters
    ----------
    A : bidimensional array
        m-by-n matrix.
    s : string
        type of norm.

    Returns
    -------
    norm : floar
        computed norm.

    """

    [m,n] = shape(A)
    values = []

    if s == '1':
        for j in range(0, n):
            sum = 0
            for i in range(0, m):
                sum = abs(A[i,j]) + sum
            values.append(sum)

    elif s == 'inf':
        for i in range(0, m):
            sum = 0
            for j in range(0, n):
                sum = abs(A[i,j]) + sum
            values.append(sum)

    norm = max(values)
    return norm

def hilbert_matrix(n):
    """
    Generates a n-by-n Hilbert matrix

    Parameters
    ----------
    n : int
        Dimension of the matrix.

    Returns
    -------
    H : bidimensional array
        Hilber matrix.

    """
    x = int(n)
    H = empty((x, x))
    for i in range(0, x):
        for j in range(0, x):
                H[i,j] = 1/((i+1)+(j+1)-1)
    return H

def hilbert_system(n):
    """
    Solve a linear system using its theoric solution e, n-by-1 array of ones.
    Its matrix of coefficients is the Hilbert matrix.

    Parameters
    ----------
    n : int
        Dimension of the Hilbert matrix.

    Returns
    -------
    x : array
        Vector n-by-1 of variables.

    """

    H = hilbert_matrix(n)
    e = ones((n))
    b = dot(H, e)

    x = linalg.solve(H, b)
    #x = inverse_linear_system(H, b)
    print('x:', x)
    return x

def hilbert_cond(n):
    """
    Computes the conditioning on the solution of a linear system whose matrix of
    coefficients is an Hilbert matrix.

    Parameters
    ----------
    n : int
        Starting from dimension 1, computes matrices until dimension n is reached.

    Returns
    -------
    None.

    """

    y = []
    for i in range(1, n+1):
       H = hilbert_matrix(i)
       b = hilbert_system(i)
       c = linalg.cond(vstack((H, b)))
       print(c)
       y.append(c)
    x = arange(1, n+1, 1)
    xlim(1, n)
    #ylim(0, 10)
    title('Condizionamento della matrice di Hilbert')
    xlabel('Dimensione n')
    ylabel('CONDIZIONAMENTO della soluzione')
    grid(axis='both')
    plot(x, y, label="Condizionamento")
    legend(loc='upper left')

def hilbert_RE(n):
    """
    Computer relative error on the theoric solution and the actual one of a Hilbert
    linear system.

    Parameters
    ----------
    n : int
        Starting from dimension 1, computes matrices until dimension n is reached.

    Returns
    -------
    None.

    """

    for i in range(1, n+1):
        b = hilbert_system(i)
        e = ones((i))
        y = abs(b - e)/abs(e)
    x = arange(1, n+1, 1)
    xlim(1, n)
    #ylim(0, 10)
    title('Condizionamento della matrice di Hilbert')
    xlabel('Dimensione n')
    ylabel('ERRORE RELATIVO sulla soluzione')
    grid(axis='both')
    plot(x, y, label="Errore relativo")
    legend(loc='upper left')

#TEST LINEAR INDEPENDENCE
#v1 = array([-1,2,-1,2,3], dtype=float)
#v2 = array([0,1,0,1,1], dtype=float)
#v3 = array([-2,2,-2,1,3], dtype=float)
#v4 = array([1,1,1,1,1], dtype=float)

#v5 = array([-2,0,1,2])
#v6 = array([-1,-1,2,-2])
#v7 = array([2,2,-2,-2])

#v1 = array([-1, 1, -1])
#v2 = array([-3, 3, -3])
#v3 = array([2, 1, 5])
#v4 = array([-3, 0, -6])
#pivot = [0,2]

#BASE
#e1 = array([1,0,0])
#e2 = array([0,1,0])
#e3 = array([0,0,1])


import asyncio
import json
import os

from fpdf import FPDF
from pylatex import Document, Section
from spade.agent import Agent
from spade.behaviour import CyclicBehaviour, OneShotBehaviour
from spade.message import Message

from spade_proto.PDF import PDF
from spade_proto.auxiliary import load_config_from_file, change_country_names_to_codes, create_symmetry_figure
from spade_proto.clusters_seeker import ClustersSeeker
from spade_proto.correlation_seeker import CorrelationSeeker

from io import StringIO
import pandas as pd

#

# Creates pdf raport
class RaportGenerator(Agent):
    correlation_seekers = []
    symmetry_results = pd.DataFrame()

    # class MyBehav(CyclicBehaviour):
    #     async def on_start(self):
    #         print(f"{self.agent.jid}: Starting behaviour . . .")
    #         self.counter = 0
    #         config = load_config_from_file()
    #         print(config)
    #
    #     async def run(self):
    #         print(f"{self.agent.jid}: Counter: {self.counter}")
    #         self.counter += 1
    #         if self.counter > 3:
    #             self.kill(exit_code=10)
    #             return
    #         await asyncio.sleep(1)
    #
    #     async def on_end(self):
    #         print(f"{self.agent.jid}: Behaviour finished with exit code {self.exit_code}.")

    # class InformBehav(OneShotBehaviour):
    #     async def run(self):
    #         print(f"{self.agent.jid}: InformBehav running")
    #         msg = Message(to="correlation_seeker@localhost")  # Instantiate the message
    #         msg.set_metadata("performative", "inform")  # Set the "inform" FIPA performative
    #         msg.set_metadata("ontology", "myOntology")  # Set the ontology of the message content
    #         msg.set_metadata("language", "OWL-S")  # Set the language of the message content
    #         msg.body = "Hello World"  # Set the message content
    #
    #         await self.send(msg)
    #         print(f"{self.agent.jid}: Message sent!")
    #
    #         # set exit_code for the behaviour
    #         self.exit_code = "Job Finished!"
    #
    #         # stop agent from behaviou

    # create an agent from within anagent
    class CreateCorrelationSeekerBehav(OneShotBehaviour):
        seeker_jid = 'correlation_seeker@localhost'

        async def on_start(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: Creating new Correlation Seeker agent behaviour . . .")

        async def run(self):
            agent = CorrelationSeeker(self.seeker_jid, "RADiance89")
            # This start is inside an async def, so it must be awaited
            await agent.start(auto_register=True)
            self.agent.add_behaviour(self.agent.SendConfigBehav())

    class CreateClustersSeekerBehav(OneShotBehaviour):
        seeker_jid = 'clusters_seeker@localhost'

        async def on_start(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: Creating new Clusters Seeker agent behaviour . . .")

        async def run(self):
            agent = ClustersSeeker(self.seeker_jid, "RADiance89")
            # This start is inside an async def, so it must be awaited
            await agent.start(auto_register=True)
            self.agent.add_behaviour(self.agent.SendConfigToClustersSeekerBehav())

    class RecvBehav(CyclicBehaviour):
        async def run(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: RecvBehav running")

            timeout = 15
            msg = await self.receive(timeout=timeout)  # wait for a message for 10 seconds
            if msg:
                print(f"{self.agent.jid}: {self.__class__.__name__}: Message received.")
                if msg.metadata["ontology"] == 'symmetry_results':
                    print(f"{self.agent.jid}: {self.__class__.__name__}: RESULTS")
                    res = pd.read_json(msg.body, orient='table')
                    print(f"{self.agent.jid}: {self.__class__.__name__}: res: {res}")
                    if self.agent.symmetry_results.empty:
                        self.agent.symmetry_results = res
                    else:
                        self.agent.symmetry_results = pd.concat([self.agent.symmetry_results, res])

            else:
                print(f"{self.agent.jid}: Did not received any message after {timeout} seconds")
                self.agent.add_behaviour(self.agent.GenerateFigures())
                self.kill()

    class SendConfigBehav(OneShotBehaviour):
        correlation_seekers = ['jeden']

        async def run(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: {self.__class__.__name__} running")
            msg = Message(to="correlation_seeker@localhost")  # Instantiate the message
            msg.set_metadata("performative", "inform")  # Set the "inform" FIPA performative
            msg.set_metadata("ontology", "config")  # Set the ontology of the message content
            msg.set_metadata("language", "OWL-S")  # Set the language of the message content
            config = load_config_from_file()
            config['countries'] = change_country_names_to_codes(config['countries'])
            print(config)
            msg.body = json.dumps(config)  # Set the message content

            await self.send(msg)
            print(f"{self.agent.jid}: {self.__class__.__name__}: Message sent!")

            # set exit_code for the behaviour
            self.exit_code = "Job Finished!"

            # stop agent from behaviou

    class SendConfigToClustersSeekerBehav(OneShotBehaviour):
        correlation_seekers = ['jeden']

        async def run(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: {self.__class__.__name__} running")
            msg = Message(to="clusters_seeker@localhost")  # Instantiate the message
            msg.set_metadata("performative", "inform")  # Set the "inform" FIPA performative
            msg.set_metadata("ontology", "config")  # Set the ontology of the message content
            msg.set_metadata("language", "OWL-S")  # Set the language of the message content
            config = load_config_from_file()
            config['countries'] = change_country_names_to_codes(config['countries'])
            print(config)
            msg.body = json.dumps(config)  # Set the message content

            await self.send(msg)
            print(f"{self.agent.jid}: {self.__class__.__name__}: Message sent!")

            # set exit_code for the behaviour
            self.exit_code = "Job Finished!"

            # stop agent from behaviou

    class GenerateFigures(OneShotBehaviour):
        async def run(self):
            # print(f"{self.agent.jid}: {self.__class__.__name__}: {self.agent.symmetry_results}")
            # create_symmetry_figure()
            symmetry_results = self.agent.symmetry_results
            # print(symmetry_results)
            # connections = symmetry_results['                         Percentage']['Connection'].drop_duplicates()
            # for con in connections:
            #     condf = symmetry_results.iloc[symmetry_results['                         Percentage']['Connection'] == con]
            #     print(f'{con} :condf: {condf}')
            self.agent.add_behaviour(self.agent.GeneratePdfBehav())

    class GeneratePdfBehav(OneShotBehaviour):
        async def run(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: {self.__class__.__name__} running")
            pdf = PDF()
            pdf.set_title('Raport')
            pdf.set_author('Michal Patyk')

            pdf.add_chapter(1, 'Symmetry analyse')
            fig_dir = 'figures/symmetry'

            with os.scandir(f'{fig_dir}/') as entries:
                for entry in entries:
                    name = entry.name
                    if name.endswith(".png"):
                        pdf.add_image(f'{fig_dir}/{name}', width=180)

            pdf.add_chapter(2, 'Power-client analyse')
            fig_dir = 'figures/power-client'

            with os.scandir(f'{fig_dir}/') as entries:
                for entry in entries:
                    name = entry.name
                    if name.endswith(".png"):
                        pdf.add_image(f'{fig_dir}/{name}', width=180)

            pdf.add_chapter(3, 'Pairwise correlation')
            fig_dir = 'figures/pairwise_correlation'

            with os.scandir(f'{fig_dir}/') as entries:
                for entry in entries:
                    name = entry.name
                    if name.endswith(".png"):
                        pdf.add_image(f'{fig_dir}/{name}', width=180)

            pdf.output('Automated PDF Report.pdf')

            doc = Document('basic')
            with doc.create(Section('A section')):
                doc.append('Also some crazy characters: $&#{}')

            doc.generate_pdf(clean_tex=False)
            # doc.generate_tex('basic.tex')

        async def on_end(self):
            print(f"{self.agent.jid}: {self.__class__.__name__}: Behaviour finished with exit code {self.exit_code}.")

    async def setup(self):
        print(f"{self.jid}: Agent starting . . .")
        # self.my_behav = self.MyBehav()
        # self.add_behaviour(self.my_behav)
        self.add_behaviour(self.CreateCorrelationSeekerBehav())
        self.add_behaviour(self.CreateClustersSeekerBehav())
        self.add_behaviour(self.RecvBehav())


from __future__ import division
from __future__ import print_function

__author__ = "Maximilian Bisani"
__version__ = "$LastChangedRevision: 1691 $"
__date__ = "$LastChangedDate: 2011-08-03 15:38:08 +0200 (Wed, 03 Aug 2011) $"
__copyright__ = "Copyright (c) 2004-2005  RWTH Aachen University"
__license__ = """
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 2 (June
1991) as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, you will find it at
http://www.gnu.org/licenses/gpl.html, or write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
USA.

Should a provision of no. 9 and 10 of the GNU General Public License
be invalid or become invalid, a valid provision is deemed to have been
agreed upon which comes closest to what the parties intended
commercially. In any case guarantee/warranty shall be limited to gross
negligent actions or intended actions or fraudulent concealment.
"""

import itertools, math, sys
import numpy as num
import sequitur_, SequenceModel, Minimization, misc
from symbols import SymbolInventory
from misc import reversed, sorted, set

class MultigramInventory(sequitur_.MultigramInventory):
    def __getstate__(self):
        return [self.symbol(i) for i in range(1, self.size() + 1)]

    def __setstate__(self, data):
        super(MultigramInventory, self).__init__()
        for i, lr in enumerate(data):
            j = self.index(lr)
            assert j == i + 1

    def sizeTemplates(self):
        result = set()
        for i in range(1, self.size() + 1):
            left, right = self.symbol(i)
            result.add((len(left), len(right)))
        return sorted(result)

class Sequitur:
    """
    Multigram / sequence model tokens / indices: 0 (zero) indicates
    VOID, and is only used internally as a sentinel. term is the index
    of the (term,term) multigram which is the end-of-string token.
    (Also used as begin-of-string token.)
    """

    def __init__(self, leftInventory=None, rightInventory=None):
        self.leftInventory = leftInventory
        self.rightInventory = rightInventory
        if not self.leftInventory:
            self.leftInventory = SymbolInventory()
        if not self.rightInventory:
            self.rightInventory = SymbolInventory()
        self.inventory = MultigramInventory()
        self.term = self.inventory.index(
            ((self.leftInventory.term,), (self.rightInventory.term,))
        )

    def compileSample(self, sample):
        return [
            (self.leftInventory.parse(left), self.rightInventory.parse(right))
            for left, right in sample
        ]

    def symbol(self, i):
        "multigramFromTokenIndex"
        l, r = self.inventory.symbol(i)
        l = self.leftInventory.format(l)
        r = self.rightInventory.format(r)
        return (l, r)

    def symbols(self):
        return [self.symbol(i) for i in range(1, self.inventory.size() + 1)]

    def index(self, left, right):
        "tokenIndexFromMultigram"
        left = self.leftInventory.parse(left)
        right = self.rightInventory.parse(right)
        return self.inventory.index((left, right))

    def makeStringInventory(self):
        result = []
        for i in range(1, self.inventory.size() + 1):
            result.append("%s:%s" % self.symbol(i))
        return sequitur_.StringInventory(result)

class Model(object):
    discount = None
    sequenceModel = None

    def __init__(self, sequitur=None):
        self.sequitur = sequitur

    def strip(self):
        oldSequitur = self.sequitur
        self.sequitur = Sequitur(
            self.sequitur.leftInventory, self.sequitur.rightInventory
        )
        data = []
        for history, predicted, score in self.sequenceModel.get():
            history = map(oldSequitur.inventory.symbol, history)
            history = tuple(map(self.sequitur.inventory.index, history))
            if predicted is not None:
                predicted = oldSequitur.inventory.symbol(predicted)
                predicted = self.sequitur.inventory.index(predicted)
            data.append((history, predicted, score))
        self.sequenceModel = SequenceModel.SequenceModel()
        self.sequenceModel.set(data)
        self.sequenceModel.setInitAndTerm(self.sequitur.term, self.sequitur.term)

        return oldSequitur.inventory.size(), self.sequitur.inventory.size()

    def transpose(self):
        oldInventory = self.sequitur.inventory
        self.sequitur = Sequitur(
            self.sequitur.rightInventory, self.sequitur.leftInventory
        )
        for i in range(1, oldInventory.size() + 1):
            left, right = oldInventory.symbol(i)
            j = self.sequitur.inventory.index((right, left))
            assert i == j  # hope

    def rampUp(self):
        self.sequenceModel.rampUp()

    def wipeOut(self, inventorySize):
        self.sequenceModel.wipeOut(inventorySize)

class MixtureModel(Model):
    "for side-ways compatibility with branch mixture-model"

    def __setstate__(self, data):
        Model.__init__(self, data["sequitur"])
        if len(data["components"]) > 1:
            raise NotImplementedError("mixture models not supported")
        component = data["components"][0]
        self.sequenceModel = component.sequenceModel
        self.discount = component.discount

class MixtureModelComponent(object):
    "for side-ways compatibility with branch micture-model"
    pass

class EstimationGraphBuilder(sequitur_.EstimationGraphBuilder):
    def setSizeTemplates(self, templates):
        self.clearSizeTemplates()
        for left, right in templates:
            self.addSizeTemplate(left, right)

class Sample(object):
    def __init__(self, sequitur, sizeTemplates, emergenceMode, sample, model):
        self.sequitur = sequitur
        self.sizeTemplates = sizeTemplates
        self.emergenceMode = emergenceMode
        self.builder = EstimationGraphBuilder()
        self.builder.setSizeTemplates(self.sizeTemplates)
        self.builder.setEmergenceMode(self.emergenceMode)
        self.sample = sample

        self.masterModel = model
        self.currentModel = None
        self.storedGraphs = None

    def __getstate__(self):
        state = {
            "sequitur": self.sequitur,
            "sizeTemplates": self.sizeTemplates,
            "emergenceMode": self.emergenceMode,
            "sample": self.sample,
            "masterModel": self.masterModel,
        }
        return state

    def __setstate__(self, state):
        self.__dict__.update(state)
        self.builder = EstimationGraphBuilder()
        self.builder.setSizeTemplates(self.sizeTemplates)
        self.builder.setEmergenceMode(self.emergenceMode)
        self.currentModel = None
        self.storedGraphs = None

    def size(self):
        return len(self.sample)

    def makeGraphs(self):
        for left, right in self.sample:
            self.builder.setSequenceModel(self.sequitur.inventory, self.masterModel)
            try:
                eg = self.builder.create(left, right)
            except RuntimeError:
                error = sys.exc_info()[1]
                if str(error) != "final node not reachable":
                    raise
                print(
                    "warning: dropping one sample that has no segmentation",
                    repr((left, right)),
                )
                continue
            eg.thisown = True
            if self.currentModel is not self.masterModel:
                self.builder.setSequenceModel(
                    self.sequitur.inventory, self.currentModel
                )
                self.builder.update(eg)
            yield eg

    class GraphsOnDemand:
        def __init__(self, master, model):
            self.master = master
            self.model = model

        def __iter__(self):
            assert self.model is self.master.currentModel
            return self.master.makeGraphs()

    maxStoredGraphs = 5000

    def graphs(self, model):
        if len(self.sample) > self.maxStoredGraphs:
            self.currentModel = model
            return self.GraphsOnDemand(self, model)
        else:
            if self.storedGraphs is None:
                self.builder.setSequenceModel(self.sequitur.inventory, self.masterModel)
                graphs = []
                for left, right in self.sample:
                    try:
                        eg = self.builder.create(left, right)
                    except RuntimeError:
                        error = sys.exc_info()[1]
                        if str(error) != "final node not reachable":
                            raise
                        print(
                            "warning: dropping one sample that has no segmentation",
                            repr((left, right)),
                        )
                        continue
                    eg.thisown = True
                    graphs.append(eg)
                self.storedGraphs = graphs
                self.currentModel = self.masterModel
            if model is not self.currentModel:
                self.builder.setSequenceModel(self.sequitur.inventory, model)
                for eg in self.storedGraphs:
                    self.builder.update(eg)
                self.currentModel = model
            return self.storedGraphs

    def evidence(self, model, useMaximumApproximation):
        evidences = sequitur_.EvidenceStore()
        evidences.setSequenceModel(model)
        if useMaximumApproximation:
            accumulator = sequitur_.ViterbiAccumulator()
        else:
            accumulator = sequitur_.Accumulator()
        accumulator.setTarget(evidences)
        logLik = 0.0
        for eg in self.graphs(model):
            logLik += accumulator.accumulate(eg, 1.0)
        misc.reportMemoryUsage()
        return evidences, logLik

    def logLik(self, model, useMaximumApproximation):
        if useMaximumApproximation:
            accumulator = sequitur_.ViterbiAccumulator()
        else:
            accumulator = sequitur_.Accumulator()
        logLik = 0.0
        for eg in self.graphs(model):
            logLik += accumulator.logLik(eg)
        return logLik

    def overlappingOccurenceCounts(self, model):
        counts = sequitur_.EvidenceStore()
        counts.setSequenceModel(model)
        accumulator = sequitur_.OneForAllAccumulator()
        accumulator.setTarget(counts)
        for eg in self.graphs(model):
            accumulator.accumulate(eg, 1.0)
        return counts

class TrainingContext:
    def __init__(self):
        self.iteration = 0
        self.order = None
        self.logLikTrain = []
        self.logLikDevel = []
        self.bestModel = None
        self.bestLogLik = None
        self.log = sys.stdout

    def registerNewModel(self, newModel, logLik):
        if self.bestModel is None or logLik >= self.bestLogLik:
            print("new best model found", file=self.log)
            self.bestModel = newModel
            self.bestLogLik = logLik

class StaticDiscounts:
    """
    Dummy discount adjuster, that just keeps the current discounts.
    """

    def __init__(self, modelFactory, develSample, discount, useMaximumApproximation):
        self.discount = discount
        if self.discount is None:
            self.discount = [0.0]
        self.discount = num.array(self.discount, dtype=num.float64)

    def adjust(self, context, evidence, order):
        if len(self.discount) < order + 1:
            oldSize = len(self.discount)
            highestOrderDiscount = self.discount[-1]
            self.discount.resize(order + 1)
            self.discount[oldSize:] = highestOrderDiscount
        print("keep discount: %s" % self.discount, file=context.log)
        return self.discount

class FixedDiscounts:
    """
    Dummy discount adjuster, that just returns a fixed value.
    """

    def __init__(self, discount):
        self.discount = num.array(discount, dtype=num.float64)

    def __call__(self, modelFactory, develSample, discount, useMaximumApproximation):
        return self

    def adjust(self, context, evidence, order):
        if len(self.discount) < order + 1:
            oldSize = len(self.discount)
            highestOrderDiscount = self.discount[-1]
            self.discount.resize(order + 1)
            self.discount[oldSize:] = highestOrderDiscount
        print("fixed discount: %s" % self.discount, file=context.log)
        return self.discount

class DefaultDiscountAdjuster:
    """
    Optimize discounts at constant evidence by optimizing
    log-likelihood of the development set.
    """

    maximumReasonableDiscount = 10.0

    def __init__(self, modelFactory, develSample, discount, useMaximumApproximation):
        self.modelFactory = modelFactory
        self.develSample = develSample
        if discount is not None:
            discount = num.asarray(discount, dtype=num.float64)
        self.discounts = [None, discount]
        self.shallUseMaximumApproximation = useMaximumApproximation

    def adjustOrderZero(self, evidence, maximumDiscount):
        def criterion(discount):
            sm = self.modelFactory.sequenceModel(evidence, [max(0.0, discount)])
            ll = self.develSample.logLik(sm, self.shallUseMaximumApproximation)
            crit = -ll - min(discount, 0) + max(discount - maximumDiscount, 0)
            print(discount, ll, crit)  # TESTING
            return crit

        initialGuess = self.discounts[-1]
        previous = self.discounts[-2]
        if initialGuess is None:
            initialGuess = 0.1
        else:
            initialGuess = initialGuess[0]

        discount, ll = Minimization.linearMinimization(
            criterion, initialGuess, tolerance=1e-4
        )
        discount = max(0.0, discount)
        discount = num.array([discount])
        return discount, -ll

    def adjustHigherOrder(self, evidence, order, maximumDiscount):
        def criterion(discount):
            disc = tuple(num.maximum(0.0, discount))
            sm = self.modelFactory.sequenceModel(evidence, disc)
            ll = self.develSample.logLik(sm, self.shallUseMaximumApproximation)
            crit = (
                -ll
                - sum(num.minimum(discount, 0))
                + sum(num.maximum(discount - maximumDiscount, 0))
            )
            print(discount, ll, crit)  # TESTING
            return crit

        initialGuess = self.discounts[-1]
        firstDirection = None
        if initialGuess is None:
            initialGuess = 0.1 * num.arange(1, order + 2, dtype=num.float64)
        elif len(initialGuess) < order + 1:
            oldGuess = initialGuess
            oldSize = len(initialGuess)
            initialGuess = num.zeros(order + 1, dtype=num.float64)
            initialGuess[:oldSize] = oldGuess
            initialGuess[oldSize:] = oldGuess[-1]
        elif len(initialGuess) > order + 1:
            initialGuess = initialGuess[: order + 1]
        else:
            previous = self.discounts[-2]
            if previous is not None and len(previous) == order + 1:
                firstDirection = initialGuess - previous
                if not num.sometrue(num.abs(firstDirection) > 1e-4):
                    firstDirection = None

        directions = num.identity(order + 1, dtype=num.float64)
        directions = directions[::-1]
        if firstDirection is not None:
            directions = num.concatenate((firstDirection[num.newaxis, :], directions))
        directions *= 0.1
        print(directions)  # TESTING

        discount, ll = Minimization.directionSetMinimization(
            criterion, initialGuess, directions, tolerance=1e-4
        )

        discount = num.maximum(0.0, discount)
        return discount, -ll

    def adjust(self, context, evidence, order):
        if self.shouldAdjustDiscount(context, evidence):
            print("adjusting discount ...", file=context.log)
            maximumDiscount = min(evidence.maximum(), self.maximumReasonableDiscount)
            evidence = evidence.makeSequenceModelEstimator()
            evidence.thisown = True
            if order == 0:
                discount, logLik = self.adjustOrderZero(evidence, maximumDiscount)
            else:
                discount, logLik = self.adjustHigherOrder(
                    evidence, order, maximumDiscount
                )
            self.discounts.append(discount)
            print("optimal discount: %s" % discount, file=context.log)
            print("max. rel. change: %s" % self.maxRelChange(), file=context.log)
        else:
            discount = self.discounts[-1]
            print("keep discount: %s" % discount, file=context.log)
        return discount

    def shouldAdjustDiscount(self, context, evidence):
        if len(context.logLikDevel) < 1:
            return True
        tentativeModel = self.modelFactory.sequenceModel(evidence, self.discounts[-1])
        logLikDevel = context.develSample.logLik(
            tentativeModel, self.shallUseMaximumApproximation
        )
        return logLikDevel <= context.logLikDevel[-1]

    def maxRelChange(self):
        if self.discounts[-2] is None:
            maxRelChange = 1.0
        elif len(self.discounts[-1]) != len(self.discounts[-2]):
            maxRelChange = 1.0
        else:
            maxRelChange = max(
                abs(
                    (self.discounts[-1] - self.discounts[-2])
                    / (self.discounts[-2] + 1e-10)
                )
            )
        return maxRelChange

class EagerDiscountAdjuster(DefaultDiscountAdjuster):
    def shouldAdjustDiscount(self, context, evidence):
        return True

class ModelTemplate:
    sizeTemplates = [(1, 1), (1, 0), (0, 1)]

    def __init__(self, sequitur):
        self.sequitur = sequitur
        self.observers = []
        self.shallUseMaximumApproximation = False
        self.emergenceMode = EstimationGraphBuilder.emergeNewMultigrams

    def useMaximumApproximation(self, viterbi):
        self.shallUseMaximumApproximation = viterbi

    def allowEmergenceOfNewMultigrams(self, allow):
        self.emergenceMode = {
            True: EstimationGraphBuilder.emergeNewMultigrams,
            False: EstimationGraphBuilder.suppressNewMultigrams,
        }[allow]

    def setLengthConstraints(
        self, minLeftLength, maxLeftLength, minRightLength, maxRightLength
    ):
        assert 0 <= minLeftLength and minLeftLength <= maxLeftLength
        assert 0 <= minRightLength and minRightLength <= maxRightLength
        self.sizeTemplates = [
            (left, right)
            for left in range(minLeftLength, maxLeftLength + 1)
            for right in range(minRightLength, maxRightLength + 1)
            if left > 0 or right > 0
        ]

    def setSizeTemplates(self, templates):
        self.sizeTemplates = templates

    def nPossibleMultigrams(self):
        nLeftSymbols = self.sequitur.leftInventory.size() - 1  # for __term__
        nRightSymbols = self.sequitur.rightInventory.size() - 1  # for __term__
        result = 0
        for left, right in self.sizeTemplates:
            result += (nLeftSymbols ** left) * (nRightSymbols ** right)
        result += 1  # for __term__
        return result

    # =======================================================================
    def obliviousSequenceModel(self):
        result = SequenceModel.SequenceModel()
        result.setInitAndTerm(self.sequitur.term, self.sequitur.term)
        result.setZerogram(self.nPossibleMultigrams())
        return result

    def sequenceModel(self, evidence, discount):
        result = SequenceModel.SequenceModel()
        if type(evidence) is not sequitur_.SequenceModelEstimator:
            evidence = evidence.makeSequenceModelEstimator()
            evidence.thisown = True
        evidence.makeSequenceModel(result, self.nPossibleMultigrams(), discount)
        return result

    # =======================================================================
    def showMostEvident(self, f, evidence, limit):
        sample = evidence.asList()
        sample = [(value, predicted, history) for history, predicted, value in sample]
        sample.sort()
        sample.reverse()

        def asString(index):
            left, right = self.sequitur.symbol(index)
            return "".join(left) + ":" + "_".join(right)

        def show(value, predicted, history):
            print(
                "    ",
                value,
                "      ",
                asString(predicted),
                "      ",
                " ".join(map(asString, history)),
                file=f,
            )

        if limit and 1.5 * limit < len(sample):
            for vph in sample[:limit]:
                show(*vph)
            print("    ...", file=f)
            for vph in sample[-limit // 2 :]:
                show(*vph)
        else:
            for vph in sample:
                show(*vph)
        print(len(sample), "evidences total", file=f)
        print(self.sequitur.inventory.size(), "multigrams ever seen", file=f)

    # =======================================================================
    def masterSequenceModel(self, model):
        allHistories = set()
        for history, predicted, score in model.sequenceModel.get():
            allHistories.add(history)
        result = SequenceModel.SequenceModel()
        result.setInitAndTerm(self.sequitur.term, self.sequitur.term)
        result.set([(history, None, 0.0) for history in allHistories])
        return result

    def obliviousModel(self):
        result = Model(self.sequitur)
        result.sequenceModel = self.obliviousSequenceModel()
        result.discount = None
        return result

    def initializeWithOverlappingCounts(self, context):
        counts = context.trainSample.overlappingOccurenceCounts(
            context.model.sequenceModel
        )

        print("  count types: %s" % counts.size(), file=context.log)
        print(
            "  count total / max: %s / %s" % (counts.total(), counts.maximum()),
            file=context.log,
        )

        self.showMostEvident(context.log, counts, 10)  ### TESTING

        context.model = Model(self.sequitur)
        context.model.discount = num.zeros(counts.maximumHistoryLength() + 1)
        context.model.sequenceModel = self.sequenceModel(counts, context.model.discount)

        print("  model size: %s" % context.model.sequenceModel.size(), file=context.log)
        print("", file=context.log)

        context.log.flush()

    def iterate(self, context):
        evidence, logLikTrain = context.trainSample.evidence(
            context.model.sequenceModel, self.shallUseMaximumApproximation
        )

        print(("LL train: %s (before)" % logLikTrain), file=context.log)
        context.logLikTrain.append(logLikTrain)

        if (not context.develSample) and (context.iteration > self.minIterations):
            context.registerNewModel(context.model, logLikTrain)

        order = evidence.maximumHistoryLength()
        print("  evidence order: %s" % order, file=context.log)
        if context.order is not None and order != context.order:
            print(
                "  warning: evidence order changed from %d to %d!"
                % (context.order, order),
                file=context.log,
            )
        context.order = order

        print("  evidence types: %s" % evidence.size(), file=context.log)
        print(
            "  evidence total / max: %s / %s" % (evidence.total(), evidence.maximum()),
            file=context.log,
        )
        self.showMostEvident(context.log, evidence, 10)  ### TESTING

        newModel = Model(self.sequitur)
        newModel.discount = context.discountAdjuster.adjust(context, evidence, order)
        newModel.sequenceModel = self.sequenceModel(evidence, newModel.discount)
        print("  model size: %s" % newModel.sequenceModel.size(), file=context.log)

        if context.develSample:
            logLikDevel = context.develSample.logLik(
                newModel.sequenceModel, self.shallUseMaximumApproximation
            )
            print("LL devel: %s" % logLikDevel, file=context.log)
            context.logLikDevel.append(logLikDevel)

        for observer in self.observers:
            observer(context.log, context, newModel)

        if (context.develSample) and (context.iteration >= self.minIterations):
            context.registerNewModel(newModel, logLikDevel)

        shouldStop = False
        if context.bestModel:
            if context.develSample:
                crit = context.logLikDevel
            else:
                crit = context.logLikTrain
            crit = [-ll for ll in crit[-self.convergenceWindow :]]
            if not Minimization.hasSignificantDecrease(crit):
                print("iteration converged.", file=context.log)
                shouldStop = True

        context.model = newModel
        return shouldStop

    maxIterations = 100
    minIterations = 20
    convergenceWindow = 10
    DiscountAdjustmentStrategy = DefaultDiscountAdjuster
    checkpointInterval = None  # or CPU time in seconds
    checkpointFile = None  # filename template must contain '%d'

    def makeContext(self, trainSample, develSample, initialModel=None):
        context = TrainingContext()
        if initialModel:
            context.model = initialModel
        else:
            context.model = self.obliviousModel()
        masterModel = self.masterSequenceModel(context.model)
        context.trainSample = Sample(
            self.sequitur,
            self.sizeTemplates,
            self.emergenceMode,
            trainSample,
            masterModel,
        )
        if develSample:
            context.develSample = Sample(
                self.sequitur,
                self.sizeTemplates,
                EstimationGraphBuilder.anonymizeNewMultigrams,
                develSample,
                masterModel,
            )
        else:
            context.develSample = None
        context.discountAdjuster = self.DiscountAdjustmentStrategy(
            self,
            context.develSample,
            context.model.discount,
            self.shallUseMaximumApproximation,
        )
        context.iteration = 0
        return context

    def run(self, context):
        lastCheckpoint = misc.cputime()
        shouldStop = False
        while not shouldStop:
            if context.iteration >= self.maxIterations:
                print("maximum number of iterations reached.", file=context.log)
                break
            print("iteration: %s" % context.iteration, file=context.log)
            try:
                shouldStop = self.iterate(context)
            except:
                import traceback

                traceback.print_exc()
                print("iteration failed.", file=context.log)
                break
            if (self.checkpointInterval) and (
                misc.cputime() > lastCheckpoint + self.checkpointInterval
            ):
                self.checkpoint(context)
                lastCheckpoint = misc.cputime()
            context.iteration += 1
            misc.reportMemoryUsage()
            print("", file=context.log)
            context.log.flush()

    def resume(cls, filename):
        from six.moves import cPickle as pickle

        if sys.version_info[:2] >= (3, 0):
            self, context = pickle.load(open(filename), encoding="latin1")
        else:
            try:
                self, context = pickle.load(open(filename))
            except ValueError:
                print(
                    "This error most likely occurred because the loaded model was created in python3.\n",
                    file=sys.stderr,
                )
                raise
        self.run(context)
        return context.bestModel

    resume = classmethod(resume)

    def checkpoint(self, context):
        print("checkpointing", file=context.log)
        import cPickle as pickle

        fname = self.checkpointFile % context.iteration
        f = open(fname, "wb")
        pickle.dump((self, context), f, pickle.HIGHEST_PROTOCOL)
        f.close()

# ===========================================================================
class Translator:
    def __init__(self, model):
        self.setModel(model)

    def setModel(self, model):
        self.model = model
        self.sequitur = self.model.sequitur
        self.translator = sequitur_.Translator()
        self.translator.setMultigramInventory(self.sequitur.inventory)
        self.translator.setSequenceModel(self.model.sequenceModel)

    def setStackLimit(self, n):
        self.translator.setStackLimit(n)

    class TranslationFailure(RuntimeError):
        pass

    def unpackJoint(self, joint):
        assert joint[0] == self.sequitur.term
        assert joint[-1] == self.sequitur.term
        return [self.sequitur.inventory.symbol(q) for q in joint[1:-1]]

    def translateFirstBest(self, left):
        left = self.sequitur.leftInventory.parse(left)
        try:
            logLik, joint = self.translator(left)
        except RuntimeError:
            exc = sys.exc_info()[1]
            raise self.TranslationFailure(*exc.args)
        return logLik, self.unpackJoint(joint)

    def firstBestJoint(self, left):
        logLik, joint = self.translateFirstBest(left)
        joint = [
            (
                self.sequitur.leftInventory.format(left),
                self.sequitur.rightInventory.format(right),
            )
            for left, right in joint
        ]
        return logLik, joint

    def jointToLeftRight(self, joint):
        left = [l for ll, rr in joint for l in ll]
        left = self.sequitur.leftInventory.format(left)
        right = [r for ll, rr in joint for r in rr]
        right = self.sequitur.rightInventory.format(right)
        return left, right

    def firstBest(self, left):
        logLik, joint = self.translateFirstBest(left)
        left2, right = self.jointToLeftRight(joint)
        assert tuple(left) == left2
        return logLik, right

    def __call__(self, left):
        logLik, right = self.firstBest(left)
        return right

    def nBestInit(self, left):
        left = self.sequitur.leftInventory.parse(left)
        try:
            result = self.translator.nBestInit(left)
        except RuntimeError:
            exc = sys.exc_info()[1]
            raise self.TranslationFailure(*exc.args)
        result.thisown = True
        result.logLikBest = self.translator.nBestBestLogLik(result)
        result.logLikTotal = self.translator.nBestTotalLogLik(result)
        return result

    def nBestNext(self, nBestContext):
        try:
            logLik, joint = self.translator.nBestNext(nBestContext)
        except RuntimeError:
            exc = sys.exc_info()[1]
            if exc.args[0] == "no further translations":
                raise StopIteration
            else:
                raise self.TranslationFailure(*exc.args)
        joint = self.unpackJoint(joint)
        left, right = self.jointToLeftRight(joint)
        return logLik, right

    def reportStats(self, f):
        print("stack usage: ", self.translator.stackUsage(), file=f)

class Segmenter:
    def __init__(self, model):
        self.model = model
        self.sequitur = model.sequitur
        self.builder = EstimationGraphBuilder()
        self.builder.setSizeTemplates(self.sequitur.inventory.sizeTemplates())
        #       self.builder.setEmergenceMode(EstimationGraphBuilder.anonymizeNewMultigrams)
        self.builder.setEmergenceMode(EstimationGraphBuilder.suppressNewMultigrams)
        self.builder.setSequenceModel(self.sequitur.inventory, self.model.sequenceModel)
        self.viterbi = sequitur_.ViterbiAccumulator()

    class SegmentationFailure(RuntimeError):
        pass

    def firstBestJoint(self, left, right):
        try:
            eg = self.builder.create(
                self.sequitur.leftInventory.parse(left),
                self.sequitur.rightInventory.parse(right),
            )
            logLik, joint = self.viterbi.segment(eg)
        except RuntimeError:
            exc = sys.exc_info()[1]
            raise self.SegmentationFailure(*exc.args)
        assert joint[-1] == self.sequitur.term
        joint = map(self.sequitur.inventory.symbol, joint[:-1])
        joint = [
            (
                self.sequitur.leftInventory.format(left),
                self.sequitur.rightInventory.format(right),
            )
            for left, right in joint
        ]
        return logLik, joint


import json

def getLocalities():
    #RITORNA UNA LISTA DI LOCALITY NAMES [bardo, sauze,...]
    file  = open("data/network.json")
    data = json.load(file)
    output = []
    print("\n\n\n\n\n\n\nRITORNO LE LOCALITA\n\n\n\n\n\n")
    for l in data["localities"]:
       output.append(l["name"])
    out_d = { "data": output}
    return json.dumps(out_d)

def getSlopesByLocalityName(loc):
    # http://127.0.0.1:8080/edit/getSlopesByLocalityName?loc=Bardonecchia
    # body: empty
    # return: ["SlopeA", "SlopeB"]

    file  = open("data/network.json")
    data = json.load(file)
    slope_names = []
    for locality in data['localities']:
        if str(locality["name"]) == str(loc):
            for slope  in locality["slopes"]:
                slope_names.append(slope["name"])
    out_d = { "data": slope_names}

    print(out_d)
    return json.dumps(out_d)

def getSectorsBySlopeNameByLocalityName(loc, slope):
    file  = open("data/network.json")
    data = json.load(file)
    sec_names = []
    for l in data["localities"]:
        if l["name"]==loc:
            for s in l["slopes"]:
                if s["name"]== slope:
                    for sec in s["sectors"]:
                        sec_names.append(sec["name"])
    out_d = { "data": sec_names}

    print(out_d)
    return json.dumps(out_d)

getSlopesByLocalityName("Bardonecchia")

getSectorsBySlopeNameByLocalityName("Bardonecchia", "SlopeA")


from __future__ import annotations
from dataclasses import dataclass, field
from typing import Optional
import math, random

from svgpdtools.utils import number_repr
from svgpdtools.transform import Transform

@dataclass
class Point:
    x: float = 0.
    y: float = 0.

    def __repr__(self) -> str:
        return number_repr(self.x) + ',' + number_repr(self.y)

    def __add__(self, other: Point) -> Point:
        return Point(self.x + other.x, self.y + other.y)

    def __sub__(self, other: Point) -> Point:
        return Point(self.x - other.x, self.y - other.y)

    def __mul__(self, t: float) -> Point:
        return Point(self.x * t, self.y * t)

    def distance_to(self, other: Point) -> float:
        delta = other - self
        return math.sqrt(delta.x**2 + delta.y**2)

    def point_between(self, other: Point, t: float) -> Point:
        delta = other - self
        return self + delta * t

    def transform(self, t: Transform) -> None:
        self.x, self.y = t.apply_point(self)

    def transformed(self, t: Transform) -> Point:
        return Point(*t.apply_point(self))

    def svg_repr(self, r: float, *, color: str='', dot: str='O') -> str:
        if dot == 'A':
            dx = .8660254037844386 * r
            dy = .5 * r
            s = f'<path d="M {Point(self.x, self.y-r)} {Point(self.x+dx, self.y+dy)} {Point(self.x-dx, self.y+dy)} Z"'
        else:
            s = f'<circle cx="{number_repr(self.x)}" cy="{number_repr(self.y)}" r="{number_repr(r)}"'

        if color:
            return s + f' fill="{color}"/>'
        return s + '/>'

@dataclass
class Circle:
    c: Point = field(default_factory=Point)
    r: float = 0.

    def svg_repr(self, *, fill: str='none', stroke: str='', stroke_width: str='', transform: str='') -> str:
        s = f'<circle fill="{fill}"'
        if stroke:
            s += f' stroke="{stroke}"'
            if stroke_width:
                s += f' stroke-width="{stroke_width}"'

        if transform:
            s += f' transform="{transform}"'

        s += f' cx="{number_repr(self.c.x)}" cy="{number_repr(self.c.y)}" r="{number_repr(self.r)}"/>'
        return s

@dataclass
class Line:
    """a*x + b*y = c"""
    a: float
    b: float
    c: float

    def perpendicular_through(self, p: Point) -> Line:
        a = self.b
        b = -self.a
        c = a * p.x + b * p.y
        return Line(a, b, c)

    def intersection(self, other: Line) -> Optional[Point]:
        det = self.a * other.b - other.a * self.b
        if math.isclose(det, 0, abs_tol=1e-7):
            return None

        return Point(
            x = (other.b * self.c - self.b * other.c) / det,
            y = (self.a * other.c - other.a * self.c) / det,
        )

    @staticmethod
    def through_points(*ps: Point) -> Line:
        assert len(ps) > 1
        a =   ps[0].y - ps[1].y
        b = -(ps[0].x - ps[1].x)
        c = a * ps[0].x + b * ps[0].y
        return Line(a, b, c)

def random_3points(span: float, min_distance: float) -> list[Point]:
    t = .1
    x0, x1 = span*t, span*(1 - t*2)
    y0, y1 = span*t, span*(1 - t*2)
    def randp():
        return Point(
            x = x0 + x1 * random.random(),
            y = y0 + y1 * random.random(),
        )

    ps = [randp()]
    while len(ps) < 3:
        _p = randp()
        if any([_p.distance_to(p) < min_distance for p in ps]):
            continue

        if len(ps) == 2:
            l1 = Line.through_points(*ps)
            l2 = l1.perpendicular_through(_p)
            x = l1.intersection(l2)
            if x is not None and math.isclose(_p.distance_to(x), 0, abs_tol=min_distance):
                continue

        ps.append(_p)

    return ps

def circle_from_3points(A: Point, B: Point, C: Point) -> Circle:
    ab = Line.through_points(A, B)
    bc = Line.through_points(B, C)
    ab_to_O = ab.perpendicular_through(A.point_between(B, .5))
    bc_to_O = bc.perpendicular_through(B.point_between(C, .5))
    O = ab_to_O.intersection(bc_to_O)
    assert O is not None
    return Circle(
        c = O,
        r = O.distance_to(A)
    )

@dataclass
class EllipticalArc:
    radii: tuple[float, float]
    x_axis_rotation: float
    flags: tuple[bool, bool]
    from_point: Point = field(default_factory=Point)
    to_point: Point = field(default_factory=Point)

    def svg_repr(self, *, fill: str='none', stroke: str='', stroke_width: str='') -> str:
        s = f'<path fill="{fill}"'
        if stroke:
            s += f' stroke="{stroke}"'
            if stroke_width:
                s += f' stroke-width="{stroke_width}"'

        s += f' d="M {self.from_point} A {number_repr(self.radii[0])} {number_repr(self.radii[1])} {number_repr(self.x_axis_rotation)} '
        s += '1' if self.flags[0] else '0'
        s += '1' if self.flags[1] else '0'
        s += f' {self.to_point}"/>'
        return s


#The program below is a financial calculator which calculate either an investment or a home loan repayment using user input.

import math

#1 menu options - user can choose either investment or bond

print("=========== MENU OPTIONS ===========")
print("Type 'i' for investment: to calculate the amount of interest you will earn on your investment")
print("Type 'b' for bond: to calculate the amount you will have to pay on a home loan")
print("Type 'q' to quit")

menu_choice = input("\n Choose 'i' for investment or 'b' for bond to proceed: \n ").lower()

#2 ensure user enter a valid option to proceed

while (menu_choice != 'i' and menu_choice != 'b' and menu_choice != 'q'):
    menu_choice = input("\n You have not enter a valid option. \n Choose 'i' for investment or 'b' to proceed: \n").lower()

#3 investment selected - calculate simple or compound interest according to user input

if menu_choice == 'i':
    print("=========== INVESTMENT ===========")
    print("*** Enter only numbers ***")
    amount = float(input('Enter the amount of money: '))
    rate = float(input('Enter the interest rate (%): '))
    years = float(input('Enter the number of years: '))
    interest = input("Choose 's' for simple or 'c' for compound interest: ").lower()
    rate = rate / 100

    if interest == 's':
        total_invested = amount * (1 + rate * years)
        print(f'The total amount of your investment will be £ {round(total_invested,2)} after {years} years.')
    if interest == 'c':
        total_invested = amount * math.pow((1 + rate), years)
        print(f'The total amount of your investment will be £ {round(total_invested,2)} after {years} years.')

#4 bond selected - calculate amount to be paid on home loan

elif menu_choice == 'b':
    print("=========== BOND ===========")
    print("*** Enter only numbers ***")
    house_value = float(input('Enter the current house value: '))
    bond_rate = float(input('Enter the interest rate (%): '))/100
    bond_months = int(input('Enter the number of months for the bond repayment: '))

    total_repay = (bond_rate * house_value) / (1 - (1 + bond_rate) ** (- bond_months))
    print(f'The bond repayment will be £ {round(total_repay,2)} for {bond_months} months.')

else:
    print('You quit the system. Thank you')


# -- coding: utf-8 --
# @Time : 2022/8/17
# @Author : ykk648
# @Project : https://github.com/ykk648/AI_power
"""
ref https://github.com/zju3dv/EasyMocap/blob/master/easymocap/estimator/mediapipe_wrapper.py
"""

import numpy as np
import cv2
import mediapipe as mp
from cv2box import CVBbox

mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_holistic = mp.solutions.holistic

def bbox_from_keypoints(keypoints, rescale=1.2, detection_thresh=0.05, MIN_PIXEL=5):
    """Get center and scale for bounding box from openpose detections."""
    valid = keypoints[:, -1] > detection_thresh
    if valid.sum() < 3:
        return [0, 0, 100, 100, 0]
    valid_keypoints = keypoints[valid][:, :-1]
    center = (valid_keypoints.max(axis=0) + valid_keypoints.min(axis=0)) / 2
    bbox_size = valid_keypoints.max(axis=0) - valid_keypoints.min(axis=0)
    # adjust bounding box tightness
    if bbox_size[0] < MIN_PIXEL or bbox_size[1] < MIN_PIXEL:
        return [0, 0, 100, 100, 0]
    bbox_size = bbox_size * rescale
    bbox = [
        center[0] - bbox_size[0] / 2,
        center[1] - bbox_size[1] / 2,
        center[0] + bbox_size[0] / 2,
        center[1] + bbox_size[1] / 2,
        keypoints[valid, 2].mean()
    ]
    return bbox

def get_hand_bbox(pose_keypoints, image_shape):
    """

    Args:
        pose_keypoints: 33*3

    Returns:

    """
    left_hand_index = [15, 21, 17, 19]
    right_hand_index = [16, 18, 20, 22]
    left_hand_points = pose_keypoints[left_hand_index]
    right_hand_points = pose_keypoints[right_hand_index]
    # print(left_hand_points)
    left_bbox = CVBbox(None).get_bbox_from_points(left_hand_points[:, :2], image_shape)
    right_bbox = CVBbox(None).get_bbox_from_points(right_hand_points[:, :2], image_shape)

    return left_bbox, right_bbox

NUM_BODY = 33
NUM_HAND = 21
NUM_FACE = 468

class MediapipeDetector:
    def __init__(self, model_type, show, cfg) -> None:

        self.model_type = model_type
        cfg = cfg
        self.show = show

        if model_type == 'holistic':
            model_name = mp_holistic.Holistic
        elif model_type == 'pose':
            model_name = mp.solutions.pose.Pose
        elif model_type == 'face':
            model_name = mp.solutions.face_mesh.FaceMesh
            cfg.pop('model_complexity')
        elif model_type in ['hand', 'handl', 'handr']:
            model_name = mp.solutions.hands.Hands
        else:
            raise NotImplementedError
        self.model = model_name(**cfg)

    @staticmethod
    def to_array(pose, W, H, start=0):
        N = len(pose.landmark) - start
        res = np.zeros((N, 3))
        for i in range(start, len(pose.landmark)):
            res[i - start, 0] = pose.landmark[i].x * W
            res[i - start, 1] = pose.landmark[i].y * H
            res[i - start, 2] = pose.landmark[i].visibility
        return res

    @staticmethod
    def to_array_world(pose, start=0):
        N = len(pose.landmark) - start
        res = np.zeros((N, 4))
        for i in range(start, len(pose.landmark)):
            res[i - start, 0] = pose.landmark[i].x
            res[i - start, 1] = pose.landmark[i].y
            res[i - start, 2] = pose.landmark[i].z
            res[i - start, 3] = pose.landmark[i].visibility
        return res

    def get_body(self, pose, W, H):
        if pose is None:
            bodies = np.zeros((NUM_BODY, 3))
            return bodies, [0, 0, 100, 100, 0]
        poses = self.to_array(pose, W, H)
        world_poses = self.to_array_world(pose)
        return poses, bbox_from_keypoints(poses), world_poses

    def get_hand(self, pose, W, H):
        if pose is None:
            bodies = np.zeros((NUM_HAND, 3))
            return bodies, [0, 0, 100, 100, 0.]
        poses = self.to_array(pose, W, H)
        poses[:, 2] = 1.
        return poses, bbox_from_keypoints(poses)

    def get_face(self, pose, W, H):
        if pose is None:
            bodies = np.zeros((NUM_FACE, 3))
            return bodies, [0, 0, 100, 100, 0]
        poses = self.to_array(pose, W, H)
        poses[:, 2] = 1.
        return poses, bbox_from_keypoints(poses)

    def process_body(self, data, results, image_width, image_height):
        if self.model_type in ['pose', 'holistic']:
            keypoints, bbox, world_poses = self.get_body(results.pose_landmarks, image_width, image_height)
            data['keypoints'] = keypoints
            data['bbox'] = bbox
            data['keypoints_world'] = world_poses

    def process_hand(self, data, results, image_width, image_height):
        lm = {'Left': None, 'Right': None}
        if self.model_type in ['hand', 'handl', 'handr']:
            if results.multi_hand_landmarks:
                for i in range(len(results.multi_hand_landmarks)):
                    label = results.multi_handedness[i].classification[0].label
                    if lm[label] is not None:
                        continue
                    lm[label] = results.multi_hand_landmarks[i]
            if self.model_type == 'handl':
                lm['Right'] = None
            elif self.model_type == 'handr':
                lm['Left'] = None
        elif self.model_type == 'holistic':
            lm = {'Left': results.left_hand_landmarks, 'Right': results.right_hand_landmarks}
        if self.model_type in ['holistic', 'hand', 'handl', 'handr']:
            handl, bbox_handl = self.get_hand(lm['Left'], image_width, image_height)
            handr, bbox_handr = self.get_hand(lm['Right'], image_width, image_height)

            # flip
            if self.model_type != 'holistic':
                handl[:, 0] = image_width - handl[:, 0] - 1
                handr[:, 0] = image_width - handr[:, 0] - 1
                bbox_handl[0] = image_width - bbox_handl[0] - 1
                bbox_handl[2] = image_width - bbox_handl[2] - 1
                bbox_handr[0] = image_width - bbox_handr[0] - 1
                bbox_handr[2] = image_width - bbox_handr[2] - 1
                bbox_handl[0], bbox_handl[2] = bbox_handl[2], bbox_handl[0]
                bbox_handr[0], bbox_handr[2] = bbox_handr[2], bbox_handl[0]
            if self.model_type in ['hand', 'handl', 'holistic']:
                data['handl2d'] = handl.tolist()
                data['bbox_handl2d'] = bbox_handl
            if self.model_type in ['hand', 'handr', 'holistic']:
                data['handr2d'] = handr.tolist()
                data['bbox_handr2d'] = bbox_handr

    def process_face(self, data, results, image_width, image_height):
        if self.model_type == 'holistic':
            face2d, bbox_face2d = self.get_face(results.face_landmarks, image_width, image_height)
            data['face2d'] = face2d
            data['bbox_face2d'] = bbox_face2d
        elif self.model_type == 'face':
            if results.multi_face_landmarks:
                # only select the first
                face_landmarks = results.multi_face_landmarks[0]
            else:
                face_landmarks = None
            face2d, bbox_face2d = self.get_face(face_landmarks, image_width, image_height)
            data['face2d'] = face2d
            data['bbox_face2d'] = bbox_face2d

    def forward(self, image_, show=False):
        image_height, image_width, _ = image_.shape
        image_ = CVImage(image_).rgb()
        if self.model_type in ['hand', 'handl', 'handr']:
            image_ = cv2.flip(image_, 1)
        image_.flags.writeable = False

        results_ = self.model.process(image_)
        data = {
            'personID': 0,
        }
        self.process_body(data, results_, image_width, image_height)
        self.process_hand(data, results_, image_width, image_height)
        self.process_face(data, results_, image_width, image_height)

        if show:
            show_img = CVImage(CVImage(image_).rgb()).draw_landmarks(data['keypoints'])
            CVImage(show_img).show(0, 'results')

        return data

if __name__ == '__main__':
    from cv2box import CVImage, MyFpsCounter

    image_in = CVImage(
        'resources/for_pose/t_pose_1080p.jpeg').bgr

    md = MediapipeDetector(model_type='pose', show=True, cfg={
        'model_complexity': 2,
        'static_image_mode': True,
        'min_detection_confidence': 0.5,
        'min_tracking_confidence': 0.5,
        'smooth_landmarks': False,  # only for holistic & pose
        # 'refine_face_landmarks': True,  # only for holistic
        # 'max_num_faces' :1 # only for face
    })
    # with MyFpsCounter() as mfc:
    #     for i in range(100):
    # results = md.forward(image_in, show=True)
    # annots = detector([image_in,image_in,image_in,image_in,])
    # print(results)
    # print(results.keys())
    # print(len(results['keypoints']))
    # print(get_hand_bbox(results['keypoints'], image_in.shape))

    # video tracking test
    from cv2box import CVVideoLoader

    with CVVideoLoader('') as cvvl:
        for _ in range(len(cvvl)):
            _, frame = cvvl.get()
            landmarks = md.forward(frame, show=True)


import numpy as np
from cv2 import cv2
import time
import os
import re

def readData(ymlFile):
    fs = cv2.FileStorage(ymlFile,cv2.FileStorage_READ)
    if not fs.isOpened():
        print('Cannot open yml file, program exit')
        exit(-2)
    data = []
    simulationTime = fs.getNode('simulationTime').real()/60 # minutes
    toRight = fs.getNode('toRight').mat()/simulationTime
    toLeft = fs.getNode('toLeft').mat()/simulationTime
    toUp = fs.getNode('toUp').mat()/simulationTime
    toDown = fs.getNode('toDown').mat()/simulationTime

    toRight = cv2.resize(toRight,(512,512))
    toLeft = cv2.resize(toLeft,(512,512))
    toUp = cv2.resize(toUp,(512,512))
    toDown = cv2.resize(toDown,(512,512))

    data = np.concatenate((toRight[np.newaxis,:],toLeft[np.newaxis,:],toUp[np.newaxis,:],toDown[np.newaxis,:]),axis=0)
    fs.release()
    return data

testingIndex = np.array([i*10 + j for i in range(72) for j in [5] ])

# YMLFilePath = 'D:/Research/IV2020MapPrediction/Code/MapPrediction/GenerateFakeMap/datas/EastSouthGate/stateMapForCalculateInsideDiff5'
# varList = []
# for M in testingIndex:
#     print(M)
#     data = []
#     for p in range(10):
#         fileName = os.path.join(YMLFilePath,'EastSouth_M%d_P%d.yml'%(M,p))
#         data.append(readData(fileName))
#     data = np.array(data)
#     var = np.var(data,axis=0)
#     var = np.average(var)
#     varList.append(var)

# np.savetxt('SETestingVar.txt',varList)
# exit(0)
# # SEVar = np.average(varList)
# # print('EastSouth average variance = ',SEVar)

YMLFilePath = 'D:/Research/IV2020MapPrediction/Code/MapPrediction/GenerateFakeMap/datas/EastGate/stateMapForCalculateInsideDiff5'
varList = []
for M in testingIndex:
    print(M)
    data = []
    for p in range(10):
        fileName = os.path.join(YMLFilePath,'East_M%d_P%d.yml'%(M,p))
        data.append(readData(fileName))
    data = np.array(data)
    var = np.var(data,axis=0)
    var = np.average(var)
    varList.append(var)
np.savetxt('E5TestingVar.txt',varList)

EVar = np.average(varList)
print('East average variance = ',EVar)
# print('EastSouth average variance = ',SEVar)
# print('Average variance = ',0.5*(EVar+SEVar))


from layers_shellnet import ConvolutionalLayer,  ShellConvLayer
import utils
import tensorflow.compat.v1 as tf
import numpy as np
flags = tf.app.flags
FLAGS = flags.FLAGS

_GRAPH_UIDS = {}
def get_graph_uid(graph_name=''):
    if graph_name not in _GRAPH_UIDS:
        _GRAPH_UIDS[graph_name] = 1
        return 1
    else:
        _GRAPH_UIDS[graph_name] += 1
        return _GRAPH_UIDS[graph_name]

def dense(input, output, is_training, name, bn_decay=None, with_bn=False, activation=tf.nn.relu):
    if with_bn:
        input = tf.layers.batch_normalization(input, momentum=0.98, training=is_training, name=name+'bn')

    dense = tf.layers.dense(input, output, activation=activation, name=name)

    return dense

class BaseNet(object):
    def __init__(self, **kwargs):
        graph = self.__class__.__name__.lower()
        name = graph + '_' + str(get_graph_uid(graph))
        self.name = name
        self.weights = {}
        self.placeholders = {}
        self.is_training = None
        self.layers = []
        self.activations = []
        self.inputs = None
        self.outputs = None
        self.loss = 0
        self.accuracy = 0
        self.pos_pred = 0
        #modify here
        self.points = None
        self.edge_features = None

        self.optimizer = None
        self.opt_op = None
    def _build(self):
        raise NotImplementedError

    def build(self):

        with tf.variable_scope(self.name, reuse=tf.AUTO_REUSE):
            self._build()
        self.activations.append(self.inputs)

        hidden = self.layers[0](self.edge_features, self.activations[-1])
        self.activations.append(hidden)

        # nodes coords for shellnet
        points = self.points
        # edge coords for shellnet
        edge_points_1 = tf.reshape(points,(FLAGS.batchsize,points.get_shape().as_list()[1],1,3))
        edge_points_1 = tf.tile(edge_points_1,(1,1, points.get_shape().as_list()[1],1))
        edge_points_2 = tf.reshape(points,(FLAGS.batchsize,1,points.get_shape().as_list()[1],3))
        edge_points_2 = tf.tile(edge_points_2,(1, points.get_shape().as_list()[1],1,1))
        edge_points = tf.concat([edge_points_1,edge_points_2],axis=3)
        edge_points = tf.reshape(edge_points, (FLAGS.batchsize,points.get_shape().as_list()[1]**2,6))

        P = 16
        #queries = tf.slice(points, (0, 0, 0), (-1, P, -1), name='sconv1_queries')
        index = list(range(34))
        np.random.shuffle(index)
        #sample_index = [ 0,  1,  2,  3,  8, 12, 13, 14, 17, 21, 23, 26, 28, 29, 31, 32]
        sample_index = index[:P]

        queries_indices = tf.tile(tf.reshape(sample_index,(1,P)),(FLAGS.batchsize,1))
        batch_indices = tf.tile(tf.reshape(tf.range(FLAGS.batchsize), (-1, 1, 1)), (1, P, 1)) #(N,P,1)
        indices = tf.concat([batch_indices, tf.expand_dims(queries_indices, axis=2)], axis=2)
        # node queries for shellnet
        queries = tf.gather_nd(points, indices, name='sconv1_queries')
        #edge queries for shellnet
        edge_queries_1 = tf.reshape(queries,(FLAGS.batchsize,queries.get_shape().as_list()[1],1,-1))
        edge_queries_1 = tf.tile(edge_queries_1,(1,1, queries.get_shape().as_list()[1],1))
        edge_queries_2 = tf.reshape(queries,(FLAGS.batchsize,1,queries.get_shape().as_list()[1],-1))
        edge_queries_2 = tf.tile(edge_queries_2,(1, queries.get_shape().as_list()[1],1,1))
        edge_queries = tf.concat([edge_queries_1,edge_queries_2],axis=3)
        edge_queries = tf.reshape(edge_queries, (FLAGS.batchsize,queries.get_shape().as_list()[1]**2,-1))

        # previous edge features
        edge_features_prev = tf.reshape(self.edge_features,(FLAGS.batchsize,self.edge_features.get_shape().as_list()[1]**2,8))
        #previous node features
        features_prev = tf.reshape(self.activations[-1],[FLAGS.batchsize, -1,
                                   self.activations[-1].get_shape().as_list()[1]])
        hidden =  self.layers[2](points, features_prev, queries)     # batchsize*P*C
        hidden = tf.reshape(hidden,(FLAGS.batchsize*P, -1))
        self.activations.append(hidden)

        edge_features = self.layers[3](edge_points, edge_features_prev, edge_queries)
        edge_features = tf.reshape(edge_features,(FLAGS.batchsize,queries.get_shape().as_list()[1],queries.get_shape().as_list()[1],-1))

        hidden = self.layers[1](edge_features, self.activations[-1])
        self.activations.append(hidden)

        points = queries

        #queries = tf.slice(points, (0, 0, 0), (-1, P, -1), name='sconv2_queries')
        index = list(range(P))
        np.random.shuffle(index)
        P = 1
        sample_index = index[:P]
        #sample_index = [8]
        queries_indices = tf.tile(tf.reshape(sample_index,(1,P)),(FLAGS.batchsize,1))
        batch_indices = tf.tile(tf.reshape(tf.range(FLAGS.batchsize), (-1, 1, 1)), (1, P, 1)) #(N,P,1)
        indices = tf.concat([batch_indices, tf.expand_dims(queries_indices, axis=2)], axis=2)
        queries = tf.gather_nd(points, indices, name='sconv2_queries')

        features_prev = self.activations[-1]
        features_prev = tf.reshape(features_prev, (FLAGS.batchsize, 16,-1))
        hidden =  self.layers[-1](points, features_prev, queries)
        self.activations.append(hidden)

        hidden = dense(self.activations[-1], output = FLAGS.classes, is_training=self.is_training, name='logits', activation=lambda x: x)
        hidden = tf.reshape(hidden, [FLAGS.batchsize * P,hidden.get_shape().as_list()[2]])
        self.activations.append(hidden)

        self.outputs = self.activations[-1]
        #这里记录了所有的tf variable(global)
        self.weights = {var.name: var for var in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=self.name)}

        self._loss()
        self._accuracy()

        self.opt_op = self.optimizer.minimize(self.loss)

    def predict(self):
        pass

    def _loss(self):
        raise NotImplementedError

    def _accuracy(self):
        raise NotImplementedError

class GCNGraphs(BaseNet):
    def __init__(self, placeholders, input_dim,  idx, num_graphs, num_nodes, with_pooling, **kwargs):
        super(GCNGraphs, self).__init__(**kwargs)

        #modify here
        self.points = placeholders['points']
        self.edge_features = placeholders['edge_features']

        self.pooling = with_pooling
        self.num_graphs = num_graphs
        self.num_nodes = num_nodes
        self.idx = idx
        self.inputs = placeholders['feats']
        self.input_dim = input_dim
        #modify here

        self.placeholders = placeholders
        self.is_training = placeholders['is_training']
        self.optimizer = tf.train.AdamOptimizer(learning_rate=FLAGS.learning_rate)
        self.build()

    def _loss(self):
        # Weight decay loss
        for var in self.layers[0].weights.values():
            self.loss += FLAGS.weight_decay * tf.nn.l2_loss(var)

        #cross entropy loss dopo aver applicato un softmax layer
        self.loss += utils.cross_entropy(self.outputs, self.placeholders['labels'])
        #self.loss += utils.binary_cross_entropy(self.outputs, self.placeholders['labels'])

    def _accuracy(self):
        self.accuracy , self.pos_pred= utils.accuracy_cal(self.outputs, self.placeholders['labels'])
        #self.accuracy= utils.binary_accuracy_cal(self.outputs, self.placeholders['labels'])

    def _build(self):
        self.layers.append(ConvolutionalLayer(input_dim=self.input_dim,
                                            output_dim=FLAGS.hidden2,
                                            placeholders=self.placeholders,
                                            activation=tf.nn.relu,
                                            dropout=True,
                                            sparse_inputs=False
                                            ))

        self.layers.append(ConvolutionalLayer(input_dim=FLAGS.hidden2,
                                            output_dim=FLAGS.hidden3,
                                            placeholders=self.placeholders,
                                            activation=tf.nn.relu,
                                            dropout=True,
                                            sparse_inputs=False
                                            ))
        '''
        if self.pooling:
            self.layers.append(PoolingLayer(    num_graphs = self.num_graphs,
                                                num_nodes = self.num_nodes,
                                                idx=self.idx,
                                                placeholders=self.placeholders,
                                                activation=lambda x: x

                                                ))

        '''

        self.layers.append(ShellConvLayer(is_training=self.is_training, tag = 'shellconv1', K =8, D=2, P=16, C=FLAGS.hidden2, with_local=FLAGS.with_local)) # for node pooling
        self.layers.append(ShellConvLayer(is_training=self.is_training, tag = 'shellconv2', K =64, D=4, P=256, C=8, with_local=FLAGS.with_local))   # for edge pooling
        self.layers.append(ShellConvLayer(is_training=self.is_training, tag = 'shellconv3', K =16, D=4, P=1, C=64, with_local=FLAGS.with_local))

    def predict(self):
        return tf.nn.softmax(self.outputs)


# -*- coding: utf-8 -*

from loguru import logger

import torch
import torch.nn as nn
from timm.models.layers import trunc_normal_

from videoanalyst.model.module_base import ModuleBase
from videoanalyst.model.task_model.taskmodel_base import (TRACK_TASKMODELS,
                                                          VOS_TASKMODELS)

torch.set_printoptions(precision=8)

@TRACK_TASKMODELS.register
@VOS_TASKMODELS.register
class TATrack(ModuleBase):

    default_hyper_params = dict(pretrain_model_path="",
                                head_width=256,
                                conv_weight_std=0.01,
                                corr_fea_output=False,
                                amp=False)

    support_phases = ["train", "memorize", "track"]

    def __init__(self, backbone, neck, head, loss=None):
        super(TATrack, self).__init__()
        self.basemodel = backbone
        # self.basemodel_q = backbone      ##
        self.neck = neck
        self.head = head
        self.loss = loss
        self._phase = "train"
        self.reset_parameters()

    def reset_parameters(self):
        def _init_weights(m):
            if isinstance(m, nn.Linear):
                trunc_normal_(m.weight, std=.02)
                if isinstance(m, nn.Linear) and m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.LayerNorm):
                nn.init.constant_(m.bias, 0)
                nn.init.constant_(m.weight, 1.0)

        if self.neck.z_input_projection is not None:
            self.neck.z_input_projection.apply(_init_weights)
        if self.neck.x_input_projection is not None:
            self.neck.x_input_projection.apply(_init_weights)

        self.neck.encoder.apply(_init_weights)
        self.neck.decoder.apply(_init_weights)
        self.basemodel.encoder.apply(_init_weights)
        self.neck.out_norm.apply(_init_weights)
        self.neck.box_encoding.apply(_init_weights)

    @property
    def phase(self):
        return self._phase

    @phase.setter
    def phase(self, p):
        assert p in self.support_phases
        self._phase = p

    def _track(self, z_feat, pre_z_feat, x_feat):
        z_pos = None
        x_pos = None

        if self.neck.z_pos_enc is not None:
            z_pos = self.neck.z_pos_enc().unsqueeze(0)
        if self.neck.x_pos_enc is not None:
            x_pos = self.neck.x_pos_enc().unsqueeze(0)

        z_feat, pre_z_feat, x_feat = self.neck.encoder(z_feat, pre_z_feat, x_feat, z_pos, x_pos)

        decoder_feat = self.neck.decoder(z_feat, pre_z_feat, x_feat, z_pos, x_pos)
        decoder_feat = self.neck.out_norm(decoder_feat)

        return self.head(decoder_feat)

    def memorize(self, im_crop, ltbr_label, gauss_label):
        fp = self.basemodel(im_crop,False)      #, fg_bg_label_map

        return fp

    def train_forward(self, training_data):
        memory_img = training_data["im_m"]
        query_img = training_data["im_q"]
        pre_img = training_data["im_p"]
        fm,fp,fq = self.basemodel(memory_img,pre_img,query_img)

        fp += self.neck.box_encoding(training_data["ltbr_label"],training_data["gauss_label"])

        return self._track(fm,fp,fq)

    def forward(self, *args, phase=None):
        if phase is None:
            phase = self._phase
        # used during training
        if phase == 'train':
            # resolve training data
            if self._hyper_params["amp"]:
                with torch.cuda.amp.autocast():
                    return self.train_forward(args[0])
            else:
                return self.train_forward(args[0])

        elif phase == 'memorize':
            target_img, ltbr_label, gauss_label  = args
            fp = self.memorize(target_img, ltbr_label, gauss_label)
            out_list = fp

        elif phase == 'track':

            fq, fm, fp, gauss_label, ltbr_label = args

            fp = fp.to(device = fm.device,dtype=torch.float)
            fm,fp,fq = self.basemodel(fm,fp,fq)
            ltbr_label = ltbr_label.to(device = fm.device,dtype=torch.float)
            gauss_label = gauss_label.to(device = fm.device,dtype=torch.float)
            fp += self.neck.box_encoding(ltbr_label,gauss_label)

            out_list = self._track(fm,fp,fq)

        else:
            raise ValueError("Phase non-implemented.")

        return out_list

    def update_params(self):
        super().update_params()

    def set_device(self, dev):
        if not isinstance(dev, torch.device):
            dev = torch.device(dev)
        self.to(dev)
        if self.loss is not None:
            for loss_name in self.loss:
                self.loss[loss_name].to(dev)


import sys
import random
import time

#Decide-My-Lunch Version 1.0 Created By @logman77 2018
#Welcome Message
print("""Thank you for using Decide My Lunch!
Please follow the directions. Let's get started
How many choices are you deciding between (2-5)?""")

#prompt user to input how number of options
option_number = input("> ")
print(f"Ok, so you have {option_number} options")
#define variable choices as an integar
choices = int(option_number)
#if user enters 1 or less than 1 -  close program
if choices <= 1:
	print("Stop wasting my time! Enter between 2 and 5 choices please.")
	time.sleep(4)
	sys.exit(0)
#if user enter 6 or more than 6 - close program
elif choices >= 6:
	print("Stop wasting my time! Enter between 2 and 5 choices please.")
	time.sleep(4)
	sys.exit(0)
#if everything is good, continue
else:
	print("Now you will enter the restaurant names: ")
#user enters 2 restaurants
if choices == 2:
	print("Restaurant Name 1:")
	name1 = input("> ")
	print("Restaurant Name 2:")
	name2 = input("> ")
	choice_of_2 = [name1, name2]
	print("You should go to: ",random.choice(choice_of_2))
#user enters 3 restaurants
if choices == 3:
	print("Restaurant Name 1:")
	name1 = input("> ")
	print("Restaurant Name 2:")
	name2 = input("> ")
	print("Restaurant Name 3:")
	name3 = input("> ")
	choice_of_3 = [name1, name2, name3]
	print("You should go to: ",random.choice(choice_of_3))
#user enters 4 restaurants
if choices == 4:
	print("Restaurant Name 1:")
	name1 = input("> ")
	print("Restaurant Name 2:")
	name2 = input("> ")
	print("Restaurant Name 3:")
	name3 = input("> ")
	print("Restaurant Name 4:")
	name4 = input("> ")
	choice_of_4 = [name1, name2, name3, name4]
	print("You should go to: ",random.choice(choice_of_4))
#user enters 5 restaurants
if choices == 5:
	print("Restaurant Name 1:")
	name1 = input("> ")
	print("Restaurant Name 2:")
	name2 = input("> ")
	print("Restaurant Name 3:")
	name3 = input("> ")
	print("Restaurant Name 4:")
	name4 = input("> ")
	print("Restaurant Name 5:")
	name5 = input("> ")
	choice_of_5 = [name1, name2, name3, name4, name5]
	print("You should go to: ",random.choice(choice_of_5))
#Pause and end script
print("Thanks for using Decide My Lunch. Goodbye")
time.sleep(10)