# Necesitamos tener instalados los packages: librosa, matplotlib
import sys
import os
import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt

pathMpowerEnfermos = "./audios/audios-mpower/true/"
pathMPowerSanos = "./audios/audios-mpower/false/"

#Rutas donde se encuentran guardados los archivos de audios
pathAudiosEnfermos = "./audios/audios-unlam/audios-editados-renombrados/enfermos/U/"
pathAudiosSanos = "./audios/audios-unlam/audios-editados-renombrados/sanos/U/"

#Rutas donde serán guardados los espectrogramas de entrenamiento
pathEntrenamientoEnfermos = "./images-unlam/entrenamiento/enfermos"
pathEntrenamientoSanos = "./images-unlam/entrenamiento/sanos"

#Rutas donde serán guardados los espectrogramas de validación
pathValidacionEnfermos = "./images-unlam/validacion/enfermos"
pathValidacionSanos = "./images-unlam/validacion/sanos"

#Ruta donde serán guardadas las imágenes de prueba
pathTestImagesEnfermos = "./images-unlam/test-images/enfermos"
pathTestImagesSanos = "./images-unlam/test-images/sanos"

#Porcentaje asignado a entrenamiento y validación
porcentajeEntrenamiento = 100
porcentajeValidacion = 0

# hop_length
hop_length = 512

# Color map
C_MAP = "magma"

#Offset y duracion que usamos para los audios de mPower
#Si se van a crear esos espectrogramas, deberiamos enviar dichos parametros a las funciones
# off = 2.5
# dur = 2.0

def main():
	#Crea los directorios especificados (en caso de que no existan)
    crearDirectorios()

    print("Elija el color map de los espectrogramas")
    print("1- Default color map (magma)")
    print("2- Gray scale color map")
    print("3- Viridis color map")
    input_cmap = int(input("Selecciona: "))

    if (input_cmap == 1):
    	C_MAP = "magma"
    elif (input_cmap == 2):
    	C_MAP = "gray_r"
    elif (input_cmap == 3):
    	C_MAP = "viridis"

    print(C_MAP)

    print("Elija el tipo de gráfico a crear")
    print("1- Melspectrogram con ejes")
    print("2- Melspectrogram sin ejes")
    print("3- MFCC (Coeficientes Cepstrales) con ejes")
    print("4- MFCC (Coeficientes Cepstrales) sin ejes")
    print("5- Log spectrogram con ejes")
    print("6- Log spectrogram sin ejes")

    num = int(input("Selecciona: "))

    if (num == 1):
        recorrerAudios(crearEspectrogramaConEjes)
    elif (num == 2):
        recorrerAudios(crearEspectrogramaSinEjes)
    elif (num == 3):
        recorrerAudios(crearMFCCConEjes)
    elif (num == 4):
        recorrerAudios(crearMFCCSinEjes)
    elif (num == 5):
        recorrerAudios(crearEspectrogramaLogConEjes)
    elif (num == 6):
        recorrerAudios(crearEspectrogramaLogSinEjes)

    print("Todos los espectrogramas fueron creados")

def porcentaje(num, porciento):
    return int((num*porciento)/100)

def crearDirectorios():
    if not os.path.exists(pathEntrenamientoEnfermos):
	    os.makedirs(pathEntrenamientoEnfermos)

    if not os.path.exists(pathEntrenamientoSanos):
	    os.makedirs(pathEntrenamientoSanos)

    if not os.path.exists(pathValidacionEnfermos):
	    os.makedirs(pathValidacionEnfermos)

    if not os.path.exists(pathValidacionSanos):
	    os.makedirs(pathValidacionSanos)

    if not os.path.exists(pathTestImagesEnfermos):
	    os.makedirs(pathTestImagesEnfermos)

    if not os.path.exists(pathTestImagesSanos):
	    os.makedirs(pathTestImagesSanos)

def recorrerAudios(metodoAEjecutar):
    listaEnfermos = os.listdir(pathAudiosEnfermos)
    listaSanos = os.listdir(pathAudiosSanos)

    #Resultados de los porcentajes realizados sobre las listas
    cantEntrenamientoEnfermos = porcentaje(len(listaEnfermos), porcentajeEntrenamiento)
    cantValidacionEnfermos = porcentaje(len(listaEnfermos), porcentajeValidacion)
    cantEntrenamientoSanos = porcentaje(len(listaSanos), porcentajeEntrenamiento)
    cantValidacionSanos = porcentaje(len(listaSanos), porcentajeValidacion)

    # Cada foreach crea espectrogramas con ejes dentro de las carpetas indicadas, de acuerdo a los porcentajes que se hayan definido
    for audio in listaEnfermos[0:cantEntrenamientoEnfermos]:
        metodoAEjecutar(pathAudiosEnfermos, audio, pathEntrenamientoEnfermos)
    for audio in listaEnfermos[cantEntrenamientoEnfermos:cantEntrenamientoEnfermos+cantValidacionEnfermos]:
        metodoAEjecutar(pathAudiosEnfermos, audio, pathValidacionEnfermos)
    for audio in listaEnfermos[cantEntrenamientoEnfermos+cantValidacionEnfermos:len(listaEnfermos)]:
        metodoAEjecutar(pathAudiosEnfermos, audio, pathTestImagesEnfermos)

    for audio in listaSanos[0:cantEntrenamientoSanos]:
        metodoAEjecutar(pathAudiosSanos, audio, pathEntrenamientoSanos)
    for audio in listaSanos[cantEntrenamientoSanos:cantEntrenamientoSanos+cantValidacionSanos]:
        metodoAEjecutar(pathAudiosSanos, audio, pathValidacionSanos)
    for audio in listaSanos[cantEntrenamientoSanos+cantValidacionSanos:len(listaSanos)]:
        metodoAEjecutar(pathAudiosSanos, audio, pathTestImagesSanos)

def crearMFCCSinEjes(path, file, carpetaDestino, off=0.0, dur=None):
    try:
        y, sr = librosa.load(path + file, offset=off, duration=dur)
        mfcc = librosa.feature.mfcc(y=y, sr=sr)
        removerEjes()
        librosa.display.specshow(mfcc, cmap=C_MAP)
        guardarGrafico(carpetaDestino, file)
    except Exception as e:
        print(e)

def crearMFCCConEjes(path, file, carpetaDestino, off=0.0, dur=None):
    try:
        y, sr = librosa.load(path + file, offset=off, duration=dur)
        mfcc = librosa.feature.mfcc(y=y, sr=sr)
        plt.figure(figsize=(6,4))
        librosa.display.specshow(mfcc, x_axis='time')
        plt.colorbar()
        guardarGrafico(carpetaDestino, file)
    except Exception as e:
        print(e)

def crearEspectrogramaConEjes(path, file, carpetaDestino, off=0.0, dur=None):
    try:
        # offset: cuantos segundos nos desplazamos desde el archivo original (float)
        # duration: cuantos segundos de audio leemos (float)
        # Podemos utilizar el offset y la duracion para evitar los problemas que hayan en el audio grabado.
        y, sr = librosa.load(path + file, offset=off, duration=dur)

        # Librosa utiliza una STFT para realizar los espectrogramas. La STFT utiliza una "ventana de tiempo".
        #
        # Las ventanas de tiempo son muy importantes e influyen en el resultado del espectrograma, debido a que uno de los problemas que tiene STFT es que, dependiendo del tamaño de la ventana,
        # puede perder resolución de frecuencia, o resolución de tiempo.
        #
        # La "resolución de frecuencia" es lo que nos permite identificar con claridad el valor de la frecuencia en el espectrograma. Si perdemos resolución de frecuencia en un espectrograma,
        # nos va a costar distinguir el valor de la frecuencia.
        #
        # La "resolución de tiempo" nos indica el tiempo en que las frecuencias cambian. Si perdemos resolución de frecuencia, en el espectrograma no vamos a notar claramente cuándo
        # cambian esas frecuencias.
        #
        # La regla es la siguiente: si disminuimos el tamaño de la ventana, aumenta la resolución de tiempo. Si aumentamos el tamaño de la ventana, aumenta la resolución
        # de la frecuencia.
        #
        # Parámetros:
        # n_ftt se usa para establecer el tamaño de la ventana en la STFT
        # para análisis de voz, se recomienda utilizar n_ftt = 512 (lo que da una window lenght de 23ms, similar a la que usaron en el paper)
        # win_length es para dividir cada trama del audio en ventanas, si no se indica este parámetro por defecto es igual a n_ftt
        spectrogram = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=hop_length*2, hop_length=hop_length)
        plt.figure(figsize=(6,4))

        # Power_to_db convierte un espectrograma a unidades de decibeles
        # fmax es un parámetro para definir cuál es la frecuencia máxima
        #librosa.display.specshow(librosa.power_to_db(spectrogram, ref=np.max), fmax=8000)
        librosa.display.specshow(librosa.power_to_db(spectrogram, ref=np.max), x_axis='time', y_axis='mel', fmax=8000, cmap=C_MAP)
        plt.colorbar(format='%+2.0f dB')
        guardarGrafico(carpetaDestino, file)
    except Exception as e:
        print(e)

def crearEspectrogramaSinEjes(path, file, carpetaDestino, off=0.0, dur=None):
    try:
        y, sr = librosa.load(path + file, offset=off, duration=dur)
        spectrogram = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=hop_length*2, hop_length=hop_length)
        removerEjes()
        librosa.display.specshow(librosa.power_to_db(spectrogram, ref=np.max), fmax=8000, cmap=C_MAP)
        guardarGrafico(carpetaDestino, file)
    except Exception as e:
        print(e)

def crearEspectrogramaLogConEjes(path, file, carpetaDestino, off=0.0, dur=None):
    try:
        y, sr = librosa.load(path + file, offset=off, duration=dur)
        spectrogram = librosa.amplitude_to_db(np.abs(librosa.stft(y, hop_length=hop_length)), ref=np.max)
        plt.figure(figsize=(6,4))
        librosa.display.specshow(spectrogram, y_axis='log', sr=sr, hop_length=hop_length, x_axis='time', cmap=C_MAP)
        plt.colorbar(format='%+2.0f dB')
        guardarGrafico(carpetaDestino, file)
    except Exception as e:
        print(e)

def crearEspectrogramaLogSinEjes(path, file, carpetaDestino, off=0.0, dur=None):
    try:
        y, sr = librosa.load(path + file, offset=off, duration=dur)
        spectrogram = librosa.amplitude_to_db(np.abs(librosa.stft(y, hop_length=hop_length)), ref=np.max)
        removerEjes()
        librosa.display.specshow(spectrogram, sr=sr, hop_length=hop_length, cmap=C_MAP)
        guardarGrafico(carpetaDestino, file)
    except Exception as e:
        print(e)

def removerEjes():
    # Removemos los bordes del espectrograma y ajustamos su tamaño (figsize)
    fig, ax = plt.subplots(1, figsize=(6,4))
    fig.subplots_adjust(left=0,right=1,bottom=0,top=1)
    # Removemos los ejes del espectrograma
    ax.axis('off')

def guardarGrafico(carpetaDestino, file):
    # Guardamos la imagen en el directorio
    plt.savefig(carpetaDestino + '/' + file[:-4] + '.png')
    plt.close()

main()


from typing import List

class Node:
    def __init__(self, name: str, k: float, link: str):
        self.name = name
        self.k = k
        self.link = link

class Solution:
    def get_nodes(self, a: str, b:str) -> List[Node]:
        result_a = []
        result_b = []
        for node in self.nodes:
            if node.name == a:
                result_a.append(node)
            if node.name == b:
                result_b.append(node)
        return result_a, result_b

    def recursive_calculate(self, a: str, b: str, k:int = 1, except_nodes=None) -> float:
        result = -1.0
        if except_nodes is None:
            except_nodes = []

        for node in self.nodes:
            if node in except_nodes:
                continue
            if node.name == a:
                if node.link == b:
                    result = k * node.k
                    break
                else:
                    except_nodes.append(node)
                    result = self.recursive_calculate(node.link, b, k * node.k, except_nodes)
                    if result != -1.0:
                        break

        return result

    def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
        result = []
        self.nodes = []
        names = []
        for i, n in enumerate(equations):
            cur_value = values[i]
            self.nodes.append(Node(n[0], cur_value, n[1]))
            self.nodes.append(Node(n[1], 1/cur_value, n[0]))
            names.append(n[0])
            names.append(n[1])

        for q in queries:
            if q[0] not in names or q[1] not in names:
                result.append(-1.0)
            else:
                result.append(self.recursive_calculate(q[0], q[1]))

        return result

equations = [["a","b"],["b","c"],["bc","cd"]]
values = [1.5,2.5,5.0]
queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]

equations = [["a","b"],["b","c"]]
values = [2.0,3.0]
queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]

print(Solution().calcEquation(equations, values, queries))


import pandas as pd
import numpy as np
import configparser
import os

config = configparser.ConfigParser()
parent = os.path.dirname
config.read(os.path.join(parent(parent(__file__)), 'config.ini'))
data_url = config['DEFAULT']['data_url']

def geo_mean(iterable):
    a = np.array(iterable).astype(float)
    return (a+1).prod() ** (1.0 / len(a)) - 1

def read_dp_csv(cluster):
    df = pd.read_csv(data_url + f"/expert_point_info_{cluster[:2]}.csv")
    return df['Point'], df['Lng'], df['Lat']

def read_survey_data(name, date):
    df = pd.read_csv(data_url + '/{}.csv'.format(name))
    df = df.iloc[2:]
    df = df[pd.to_datetime(df['EndDate']) > pd.to_datetime(date)]
    df.columns = [c.replace(' ', '_') for c in df.columns]
    df.columns = [c.replace('.', '_') for c in df.columns]
    return df

def build_matrix(data):
    """ Create the PC matrix from the data
    :param data:
    :return: matrix of mx5x5 where m is the number of experts. 5 is hardcoded since every expert ranked 5 locations
    """
    n_experts = len(data)
    matrix = np.ones((n_experts, 5, 5))
    col_idx = [1, 2, 3, 4, 2, 3, 4, 3, 4, 4]
    row_idx = [0, 0, 0, 0, 1, 1, 1, 2, 2, 3]
    val_idx = [0, 7, 5, 3, 1, 3, 5, 7]  # AHP-like: with one option less (9x)
    s = 1.5  # scale parameter
    val_idx = [0, (1+s)**3, (1+s)**2, (1+s), 1, (1+s), (1+s)**2, (1+s)**3]  # geometric scale (Finan,Hurley): Transitive calibration of the AHP verbal scale

    for i, expert in enumerate(data.itertuples()):  # loop over expert comparison matrices
        for j, comp in enumerate(data.columns[-10:]):
            c = col_idx[j]
            r = row_idx[j]
            value = int(getattr(expert, comp))
            if value < 4:  # A more suitable
                matrix[i, r, c] = val_idx[value]
                matrix[i, c, r] = 1 / val_idx[value]
            elif value > 4:   # B more suitable
                matrix[i, r, c] = 1 / val_idx[value]
                matrix[i, c, r] = val_idx[value]
            else:  # value == 4 -> equally suitable
                matrix[i, r, c] = 1
                matrix[i, c, r] = 1
    return matrix

def compute_priority_weights(matrix):
    """
    Computes the priority weights of elements in a pairwise comparison matrix.
    First normalizes column-wise, then aggregates row-wise
    See e.g. https://www.spicelogic.com/docs/ahpsoftware/intro/ahp-calculation-methods-396 for explanation
    :param matrix: pairwise nxn comparison matrix
    :return: priority vector size n
    """
    return list(np.mean(matrix / np.sum(matrix, axis=0), axis=1).round(4))

def compute_consistency_ratio(matrix):
    n = len(matrix)
    lambda_max = np.max(np.linalg.eigvals(matrix))
    consistency_index = (lambda_max - n) / (n - 1)

    ri_dict = {3: 0.52, 4: 0.89, 5: 1.11, 6: 1.25, 7: 1.35, 8: 1.40, 9: 1.45,
               10: 1.49, 11: 1.52, 12: 1.54, 13: 1.56, 14: 1.58, 15: 1.59}

    random_index = ri_dict[n]
    consistency_ratio = np.real(consistency_index / random_index)
    return consistency_ratio


from django.db.models import Q
from statistics import mode
from django.contrib import admin
from .models import *

# Register your models here.

@admin.register(Cliente)
class ClienteAdmin(admin.ModelAdmin):
    list_display = ['cliente_name','telefono','direccion','email','estado']
    search_fields=('cliente_name', 'estado')
    list_filter = ('estado',)

@admin.register(Paquete)
class PaqueteAdmin(admin.ModelAdmin):
    fieldsets = [
        ("Tracking", {"fields": ["tracking"]}),
            ( "Datos de Paquete",
                {"fields":['direccion_des', 'telefono_des', 'nombre_des'] }
            ),
            ( "Peso - Altura",
                {"fields":['peso', 'altura'] }
            ),
            ( "Caracteristicas",
                {"fields":['cliente', 'estado', 'tipo_paquete'] }
            )

    ]
    list_display = ['pk','tracking','direccion_des','telefono_des','cliente','tipo_paquete','estado']
    list_filter = ('tracking', 'estado')
    search_fields=('tracking', 'estado','cliente')
    list_display_links = ('cliente', 'pk')
    readonly_fields = ('tipo_paquete',)

class ItemInline(admin.StackedInline):
    model = Item
    extra = 0

@admin.register(Plantilla)
class PlantillaAdmin(admin.ModelAdmin):
    list_display = ['pk','posicion','fecha']
    list_filter = ('posicion','fecha')
    search_fields=('pk', 'posicion')
    readonly_fields = ('fecha',)
    inlines = [ItemInline]
    ordering = ['fecha']
    actions = ['Pasar_Distribucion']

    def Pasar_Distribucion(self, request, queryset):
        id_item = Item.pk
        for plantilla in queryset:
            #Paquete.objects.filter(Q(estado=1) &
            #~Q(pk = Item.pk)).update(estado=2)
            #variable = Paquete.objects.filter(plantilla.pk)
            print(plantilla.pk)
    Pasar_Distribucion.short_description = 'Pasar a Distribución'

@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
    list_display = ['pk','num_plantilla','posicion','motivo_fallo']
    list_filter = ('motivo_fallo','posicion')
    search_fields=('num_platilla','posicion','motivo_fallo')

@admin.register(Estado_Tracking)
class Estado_TrackingAdmin(admin.ModelAdmin):
    list_display = ['pk','estado_tracking']
    search_fields = ('estado_tracking',)
    ordering = ['pk']

admin.site.register(Motivo_Fallo)

## ---Admin Titulos---- ##
admin.site.site_header = "Sistema de Logistica"
admin.site.site_title = "Ejercicio"
admin.site.index_title = "Ejercicio StormTech"


# 导入模块
import math
import pandas as pd
import matplotlib.pyplot as plt

# 获取数据
origin_data = pd.DataFrame(pd.read_csv('./Data/origin_slice_data.csv', header=None, usecols=[0]))
linear_predict = pd.DataFrame(pd.read_csv('./Data/Linear_predict_data.csv', header=None, usecols=[0]))
RNN_predict = pd.DataFrame(pd.read_csv('./Data/RNN_predict_data.csv', header=None, usecols=[0]))
Attention_predict = pd.DataFrame(pd.read_csv('./Data/Attention_predict_data.csv', header=None, usecols=[0]))
Transformer_predict = pd.DataFrame(pd.read_csv('./Data/Transformer_predict_data.csv', header=None, usecols=[0]))
# Parameter
max = 11.4628629917588
min = 6.85751406254539

# 获取list数据
def get_data(data):
    data_list = []
    for col in data.columns:
        data_list = data[col]

    return data_list

# 逆归一化
def data_process(data, min, max):
    difference = max - min
    for number in range(0, len(data)):
        data[number] = data[number]*difference+min
    return data

# 获取list
linear_predict = get_data(linear_predict)
RNN_predict = get_data(RNN_predict)
Attention_predict = get_data(Attention_predict)
Transformer_predict = get_data(Transformer_predict)
# 逆归一化
linear_predict = data_process(linear_predict, min, max)
RNN_predict = data_process(RNN_predict, min, max)
Attention_predict = data_process(Attention_predict, min, max)
Transformer_predict = data_process(Transformer_predict, min, max)

plt.plot(origin_data[:50], 'b', label='Ground Truth')
plt.plot(linear_predict[:50], 'orange', label='Linear')
plt.plot(RNN_predict[:50], 'pink', label='RNN')
plt.plot(Attention_predict[:50], 'green', label='Linear_Attention')
plt.plot(Transformer_predict[:50], 'red', label='Transformer')
plt.xlabel('Data Index')
plt.ylabel('Data Value')
plt.legend(loc='best')
plt.show()
plt.close()


"""A module for generating Replay recommendations."""
from enum import IntEnum
from itertools import chain, islice
from hearthstone.enums import BnetGameType
from hsreplaynet.games.models import GameReplay, Visibility

class ReplayRecommendationReason(IntEnum):
	FRIENDLY_DECK_MATCH = 0
	OPPONENT_DECK_MATCH = 1
	CLASSES_AND_RANKS_MATCH = 3
	CLASSES_AND_ARENA_KEY_MATCH = 4

class RelatedReplayRecommendation:
	def __init__(self, replay, reason):
		self.replay = replay
		self.reason = reason

	def __repr__(self):
		return "<RelatedReplayRecommendation %s - %s>" % (
			self.reason.name, self.replay.pretty_name
		)

class RecommendationGenerator:
	"""
	Subclasses should supply a reason and populate recommendations during generate()
	"""

	reason = None

	def __init__(self, source_replay, max):
		self.source_replay = source_replay
		self.recommendations = []
		self.max = max

	def __iter__(self):
		self.generate()
		return self

	def __next__(self):
		if self.recommendations:
			reco = self.recommendations.pop(0)
			return RelatedReplayRecommendation(reco, self.reason)
		raise StopIteration

	def generate(self, replay):
		raise NotImplementedError("Must be implemented by subclasses.")

class DeckMatchGenerator(RecommendationGenerator):
	def generate(self):
		account_lo = self.source_replay.friendly_player.pegasus_account.account_lo
		query = GameReplay.objects.filter(
			visibility=Visibility.Public,
			global_game__players__deck_list=self.deck
		).exclude(global_game__players__pegasus_account__account_lo=account_lo)[:self.max]
		self.recommendations += query

class FriendlyDeckMatchGenerator(DeckMatchGenerator):
	reason = ReplayRecommendationReason.FRIENDLY_DECK_MATCH

	@property
	def deck(self):
		return self.source_replay.friendly_player.deck_list

class OpponentDeckMatchGenerator(DeckMatchGenerator):
	reason = ReplayRecommendationReason.OPPONENT_DECK_MATCH

	@property
	def deck(self):
		return self.source_replay.opposing_player.deck_list

# Generators are evaluated in order
# Thus the ordering in the lists determine which recommendations get higher priority
GENERATORS = {
	BnetGameType.BGT_UNKNOWN: [FriendlyDeckMatchGenerator],
	BnetGameType.BGT_FRIENDS: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
	BnetGameType.BGT_RANKED_STANDARD: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
	BnetGameType.BGT_ARENA: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
	BnetGameType.BGT_VS_AI: [FriendlyDeckMatchGenerator],
	BnetGameType.BGT_CASUAL_STANDARD: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
	BnetGameType.BGT_TAVERNBRAWL_PVP: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
	BnetGameType.BGT_TAVERNBRAWL_1P_VERSUS_AI: [FriendlyDeckMatchGenerator],
	BnetGameType.BGT_TAVERNBRAWL_2P_COOP: [],
	BnetGameType.BGT_RANKED_WILD: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
	BnetGameType.BGT_CASUAL_WILD: [FriendlyDeckMatchGenerator, OpponentDeckMatchGenerator],
}

def recommend_related_replays(replay, num):
	"""
	Attempts to generate up to num RelatedReplayRecommendation objects
	"""
	game_type = replay.global_game.game_type
	generators = [G(replay, num) for G in GENERATORS[game_type]]

	if generators:
		return list(islice(chain.from_iterable(generators), 0, num))
	return []


import csv
from matplotlib import pyplot as plt
import os

def read_csv(path, max_step, l, step_count):
    step = []
    loss = []
    prev_step = -1
    with open(path, "rt") as infile:
        csvreader = csv.DictReader(infile)
        for row in csvreader:
            cur_step = int(row["Step"])
            if cur_step > max_step:
                break
            if cur_step - prev_step > step_count:
                step.append(cur_step)
                loss.append(l * float(row["Value"]))
                prev_step = cur_step
    return step,loss

input_path = "mnist_losses"

fig, ax1 = plt.subplots()
plt.title("Generator Losses by Source")
step, loss = read_csv("summaries/lfw0/run_.,tag_generator_image_discriminator_cost.csv", 200000, 0.001, 5000)
ax1.plot(step, loss, label="Output Dis.", color='b')
ax1.set_ylabel("Output Dis. Cost", color='b')
ax1.tick_params('y', colors='b')

ax2 = ax1.twinx()
step, loss = read_csv("summaries/lfw0/run_.,tag_generator_reconstruction_cost.csv", 200000, 1, 5000)
ax2.plot(step, loss, label="Reconstruction", color='r')
ax1.set_xlabel("Training Step")
ax2.set_ylabel("Reconstruction Cost", color='r')
ax2.tick_params('y', colors='r')
fig.tight_layout()

plt.savefig(os.path.join(input_path, "LFW_genlosses.png"))


#!/usr/bin/env python3

import os.path as path
import csv

FILENAME = "history.csv"
HISTORY = []

class SaveUserEntries():

    def saveFileLocation():
        history = HISTORY
        header = ["File Path", "Resize Paramter", "Red Filter Level", "Green Filter Level", "Blue Filter Level", "Opacity Scale", "Saved Image Path"]

        while True:
            if path.exists(FILENAME):
                with open (FILENAME, "a", newline="") as file:
                    writer = csv.writer(file)
                    writer.writerow(history)
                    HISTORY.clear()
                    break
            else:
                with open('history.csv', 'w', newline='') as outcsv:
                    writer = csv.writer(outcsv)
                    writer.writerow(header)
                    continue


import json
import os
import uuid
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Dict, List

import torch
from fastapi import FastAPI
from loguru import logger
from pydantic import BaseModel, validator

from src.model_extractors import Predictor, QuestionAnsweringPredictor, Seq2SeqPredictor

PREDICTORS: Dict[str, Predictor] = {
    "qa": None,
    "seq2seq": None,
}

@dataclass
class ApiServerConfig:
    prediction_log_path: str = "./data/logs/predictions/logs.jsonl"
    api_log_path: str = "./data/logs/api/logs.txt"
    model_name_qa: str = "choosistant/qa-model"
    model_name_seq2seq: str = "choosistant/seq2seqmodel"
    batch_size: int = 8
    inference_device_code: str = os.environ.get("INFERENCE_DEVICE", "cpu")
    inference_device: torch.device = field(init=False)
    inference_device_name: str = field(init=False)

    def __post_init__(self):
        self.inference_device = torch.device(self.inference_device_code)
        if "cpu" in self.inference_device_code:
            self.inference_device_name = "CPU"
        elif "cuda" in self.inference_device_code:
            self.inference_device_name = torch.cuda.get_device_name(
                self.inference_device
            )
        else:
            raise ValueError("Unknown inference device")

class PredictRequest(BaseModel):
    url: str
    review_text: str
    model_type: str

    @validator("review_text")
    def review_text_must_not_be_empty(cls, val: str):
        if val is None or len(val.strip()) == 0:
            raise ValueError("review_text must not be empty")
        return val

    @validator("model_type")
    def model_type_must_be_one_of_known_types(cls, val: str):
        if val not in PREDICTORS:
            err = f"model_type must be one of types: {list(PREDICTORS.keys())}"
            raise ValueError(err)
        return val

class PredictResponse(BaseModel):
    id: str
    segments: List[str]
    labels: List[str]
    scores: List[float]

app = FastAPI()
cnf = ApiServerConfig()

@app.on_event("startup")
def startup_event():
    global prediction_log_file

    logger.add(cnf.api_log_path, rotation="1 day", retention="7 days")
    logger.info("Starting API server")
    logger.info(
        f"Using inference device: {cnf.inference_device_name} ({cnf.inference_device})"
    )

    PREDICTORS["qa"] = QuestionAnsweringPredictor(
        qa_model_name=cnf.model_name_qa,
        batch_size=cnf.batch_size,
        inference_device=cnf.inference_device_code,
    )
    PREDICTORS["seq2seq"] = Seq2SeqPredictor(
        model_name_seq2seq=cnf.model_name_seq2seq,
        inference_device=cnf.inference_device_code,
    )

    # Ensure parent directories exist.
    Path(cnf.prediction_log_path).parent.mkdir(parents=True, exist_ok=True)
    prediction_log_file = open(cnf.prediction_log_path, "a")

    logger.info("Setup completed")

@app.on_event("shutdown")
def shutdown_event():
    prediction_log_file.close()
    logger.info("Shutting down application")

@app.get("/")
def read_root():
    return {"message": "Please use the /predict endpoint to make predictions"}

@app.post("/predict", response_model=PredictResponse)
def predict(request: PredictRequest):
    # get model prediction for the input request
    start_time = datetime.now()
    predictor = PREDICTORS[request.model_type]
    predictions = predictor.predict(request.review_text)
    end_time = datetime.now()
    inference_time_ms = (end_time - start_time).total_seconds() * 1000

    # Generate a unique ID for this prediction for tracking purposes.
    prediction_id = uuid.uuid4().hex

    # construct the data to be logged
    log_info = {
        "prediction_id": prediction_id,
        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "request": request.dict(),
        "predictions": [o.to_dict() for o in predictions],
        "inference_time_ms": int(inference_time_ms),
        "inference_device": cnf.inference_device_name,
    }
    prediction_log_file.write(f"{json.dumps(log_info)}\n")
    prediction_log_file.flush()

    # construct response
    return PredictResponse(
        id=prediction_id,
        segments=[pred.segment for pred in predictions],
        labels=[pred.label for pred in predictions],
        scores=[pred.score for pred in predictions],
    )


import pydot
from trees.node import Node
from uuid import uuid4

RED = 1
BLACK = 0

class RbNode(Node):

    def __init__(self, key, value, left=None, right=None, size=1, color=RED):
        self.color = color
        super(RbNode, self).__init__(key, value,
                                     left=left, right=right, size=size)

class RBT():

    def __init__(self):
        self.root = None

    def put(self, key, value):
        self.root = self._put(self.root, key, value)

    def _put(self, root, key, value):
        if root is None:
            return RbNode(key, value)

        if root > key:
            root.left = self._put(root.left, key, value)
        elif root < key:
            root.right = self._put(root.right, key, value)
        else:
            # keys are equal, overwrite value
            root.value = value

        if self.is_red(root.right) and not self.is_red(root.left):
            root = self.rotate_to_left(root)
        if self.is_red(root.left) and self.is_red(root.left.left):
            root = self.rotate_to_right(root)
        if self.is_red(root.left) and self.is_red(root.right):
            self.flip_color(root)

        return root

    def rotate_to_right(self, node):
        new_root = node.left
        node.left = node.left.right
        new_root.right = node
        new_root.color = node.color
        node.color = RED

        return new_root

    def rotate_to_left(self, node):
        new_root = node.right
        node.right = node.right.left
        new_root.left = node
        new_root.color = node.color
        node.color = RED

        return new_root

    def flip_color(self, node):
        node.color = RED
        node.left.color = BLACK
        node.right.color = BLACK

    def show_graph(self, name="example1_graph.png"):
        graph = pydot.Dot(graph_type='digraph')
        self._show_graph(self.root, graph)
        graph.write_png(name)

    def _make_node(self, node, graph):
        node_label_tmpl = "%s - %s - %s"

        if node is not None:
            node_text = node_label_tmpl % (node.key, node.value, node.size)
            graph_node = pydot.Node(node_text)
        else:
            # empty node
            graph_node = pydot.Node(str(uuid4()),  style="invis")
        graph.add_node(graph_node)
        return graph_node

    def is_red(self, node):
        if node is None:
            return False
        return node.color == RED

    def _show_graph(self, node, graph):
        if node is not None:
            root = self._make_node(node, graph)

            for child_node in [node.left, node.right]:
                child_node_graph = self._make_node(child_node, graph)
                edge = pydot.Edge(root, child_node_graph)
                if self.is_red(child_node):
                    edge.set_color("red")
                graph.add_edge(edge)
                self._show_graph(child_node, graph)

if __name__ == "__main__":
    from random import shuffle, randint
    a = RBT()
    data = [randint(0, 100) for i in range(10)]
    shuffle(data)
    for i in data:
        a.put(i, i)

    a.show_graph()


'''
문) breast_cancer 데이터셋을 이용하여 다음과 같이 keras 모델을 생성하시오.
  조건1> keras layer
       L1 =  30 x 64
       L2 =  64 x 32
       L3 =  32 x 2
  조건2> output layer 활성함수 : sigmoid
  조건3> optimizer = 'adam',
  조건4> loss = 'binary_crossentropy'
  조건5> metrics = 'accuracy'
  조건6> epochs = 300
'''

import tensorflow as tf # ver2.x
from sklearn.datasets import load_breast_cancer # data set
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import minmax_scale, OneHotEncoder
from tensorflow.keras import Sequential # model 생성
from tensorflow.keras.layers import Dense # DNN layer

# 1. breast_cancer data load
cancer = load_breast_cancer()

x_data = cancer.data
y_data = cancer.target
print(x_data.shape) # (569, 30) : matrix
print(y_data.shape) # (569,) : vector

# x_data : 정규화
x_data = minmax_scale(x_data) # 0~1

# y변수 one-hot-encoding
obj = OneHotEncoder()
# reshape(2d) -> one hot encoding -> numpy
y_one_hot = obj.fit_transform(y_data.reshape([-1, 1])).toarray()
y_one_hot
'''
[1, 00]
[0, 10]
'''
y_one_hot.shape # (569, 2)

# 2. 공급 data 생성 : 훈련용, 검증용
x_train, x_val, y_train, y_val = train_test_split(
    x_data, y_one_hot, test_size = 0.3)

# 3. keras model
model = Sequential()

# 4. DNN model layer 구축 : hidden layer(2) -> output layer(3)
# hidden layer1 : [30, 64]
model.add(Dense(64, input_shape = (30,), activation = 'relu'))  # 1층

# hidden layer2 : [64, 32]
model.add(Dense(32, activation = 'relu')) # 2층

# output layer : [32, 2]
model.add(Dense(2, activation = 'sigmoid')) # 3층

# 5. model compile : 학습과정 설정(이항 분류기)
model.compile(optimizer = 'adam',
              loss = 'binary_crossentropy', # one hot encoding
              metrics = ['accuracy'])

'''
optimizer : 최적화 알고리즘('adam','sgd')
loss : 비용 함수('categorical_crossentropy','binary_crossentropy','mse')
metrics : 평가 방법('accuracy', 'mae')
'''

# 6. model trainint : train(300) -> test(1)
model.fit(x_train, y_train,
          epochs = 300, # 학습횟수
          verbose=1, # 출력여부
          validation_data=(x_val, y_val)) # 검증data
'''
Epoch 100/100
105/105 [==============================] - 0s 893us/sample - loss: 0.1154 - accuracy: 0.9619
- val_loss: 0.1021 - val_accuracy: 0.9778
#'''

# 7. model evaluation : test dataset
print('optimizered model evaluation')
model.evaluate(x_val, y_val)


from networkx import nx
import pickle
import numpy as np

with open('graph.pickle', 'rb') as input_graph_file:
    G = pickle.load(input_graph_file)

newGs = []

for i in range(500):
    newG = nx.DiGraph()
    newG.add_nodes_from(list(G.nodes))
    for u, v in G.out_edges:
        rand_num = np.random.random()
        if G.nodes[u]['region'] == G.nodes[v]['region']:
            if rand_num < 0.2:
                newG.add_edge(u, v)
        else:
            if rand_num < 0.1:
                newG.add_edge(u, v)
    newGs.append(newG)
with open('simulation.pickle', 'wb') as output_graph_file:
    pickle.dump(newGs, output_graph_file, pickle.HIGHEST_PROTOCOL)


#/usr/bin/env python3

import re
import sys
import numpy as np
from modules import afbeeldingen as afb
import random as rnd
from modules import inp as inp
from modules import plot as plot
import os

def create_data_dictionary(images, positions, main_frame):
	"""
	This function generates a dictionary using the voltage at which an image is
	taken as keywords. Each keyword is connected to a list containg tuples of
	the modulation at a given spatial frequency and the corresponding standard
	deviation on that modulation. As we wish to plot these values later on the
	list of modulations is order in the same way as the spatial frequencies.

	Args:
		images (list of str): A list of strings representing the path to the image
			files.
		positions (list of lists of strings): A list of lists formatted in a specific way which contains
			all the information on the positions and the spatial frequency at these
			positions. See help(get_modulations()) for specifics on the used format.
	"""
	# First close the gui.
	main_frame.destroy()
	# Initialise the needed variables.
	run = False
	main_dict = {}
	spatial_freqs = [float(pos[0]) for pos in positions]

	# Start looping over all the images.
	for image in images:

		# Reset the modulations list.
		modulations = []

		# Get the modulation for each position on the image.
		for position in positions:
			modulations.append(get_modulation(image, position))

		# Add these (normalized) modulations to the main dictionary.
		modulations = normalize(modulations)
		main_dict[get_voltage(image)] = modulations

		# Ask the user for input if run is False.
		if not run:
			print(":: Processed image {}\n:: What would you like to"\
					" do?".format(os.path.basename(image)))
			reply = inp.ask()
			run = execute_user_input(reply, spatial_freqs, modulations, image)
		else:
			print(":: Processed image {}".format(os.path.basename(image)))

	# When the loop is done with all the images ask what to do with the
	# main_dict.
	finalize(main_dict, spatial_freqs)

def normalize(data_points):
	modulations = [point[0] for point in data_points]
	stds = [point[1] for point in data_points]

	normalized_modulations = [(value - min(modulations))/(max(modulations) - min(modulations)) for value in modulations]

	return_data = []
	for i in range(len(modulations)):
		return_data.append([normalized_modulations[i], stds[i]])

	return return_data

def get_modulation(image, position, spacing = 10):
	"""
	This function calculates the intensity modulation at a specific position
	on the image.

	Args:
		image (str): path the image file.
		position (list): a list containing all the information on a specifc position.
			formatted as such [linepairs/distance, x_initial, x_final, y]

	Returns:
		A list containing the average modulation at that position and the standard
		deviation.
	"""
	lines = []
	for count in range(5):
		lines.append(afb.Read_Image(image,True,int(position[1]), int(position[2]),
			int(position[3])+count*spacing))

	def modulation(line):
		return (max(line)-min(line))/(max(line)+min(line))

	modulation = [modulation(line) for line in lines]
	return [np.average(modulation), np.std(modulation)]

def get_voltage(image):
	"""
	Given an image path this functions returns the value for the voltage
	at which this image was taken.

	Args:
		image (str): A string representing the path to the image file.

	Returns:
		voltage (int): An integer representing the voltage.
	"""
	"""
	name = os.path.basename(image)
	name_reduced = name[11:][:-6]
	return int(name_reduced[:2])
	"""
	res = re.search('(?i)\d{2,3}kV',image)
	return int(res.group(0)[:-2])
def execute_user_input(reply, spatial_freqs, modulations, image):
	"""
	This function controls the execution of commandline inputs from the user.
	It also returns the boolean value for the run variable.

	Args:
		reply (str): A string containing the command from the user
		spatial_freqs (list):
	"""
	if reply == 'p':
		plot.plot_modulation_transfer(image, modulations, spatial_freqs)
		print(":: Processing next image...")
		return False

	elif reply == "r":
		print(":: Processing next image...")
		return True

	else:
		print(":: Processing next image...")
		return False

def finalize(main_dict,spatial_freqs):

	print(":: Processed all the images!\n:: What was the power setting for these images?")
	reply = inp.ask()
	power = int(reply)

	plot.plot_data_dict(main_dict, spatial_freqs, power)
	print(":: Finished!")


import climnet.time_utils as tu
import numpy as np
import pandas as pd
import xarray as xr
import scipy.interpolate as interp
import copy
from importlib import reload
import climnet.general_utils as ut
#import climnet.spatial_mean as spm
#import climnet.tsa.filters as flt

def compute_rm(da, rm_val, dim='time', sm='Jan', em='Dec'):
    """This function computes a rolling mean on an input
    xarray dataarray. The first and last rm_val elements
    of the time series are deleted.py

    Args:
        da (xr.dataarray): dataarray of the input dataset
        rm_val (int): size of the rolling mean

    Returns:
        [type]: [description]
    """
    reload(tu)
    times = da.time
    if dim != 'time':
        da_rm = da.rolling(time=rm_val, center=True).mean(
            skipna=True).dropna(dim, how='all')
    else:
        start_year, end_year = tu.get_sy_ey_time(times)
        all_year_arr = []
        for idx, year in enumerate(np.arange(start_year, end_year)):
            print(f'Compute RM Year {year}')
            start_date, end_date = tu.get_start_end_date(
                sy=year,
                ey=year,
                sm=sm,
                em=em)
            arr_1_year = da.sel(time=slice(start_date, end_date))
            arr_1_year_rm = arr_1_year.rolling(
                time=rm_val, center=True, min_periods=1).mean(skipna=True).dropna(dim=dim,
                                                                                how='all')
            all_year_arr.append(arr_1_year_rm)
        da_rm_ds = xr.merge(all_year_arr)

        for name, da in da_rm_ds.data_vars.items():
            var_name = name
        da_rm = da_rm_ds[var_name]

    return da_rm

def get_map_for_def_map(data_map, def_map):
    if data_map.shape[1:] != def_map.shape[:]:
        raise ValueError("Error! Not same shape of def map and data map!")
    nan_map = xr.where(def_map > 0, data_map, np.nan)
    return nan_map

def interp_fib2gaus(dataarray, grid_step=2.5):
    """Interpolate dataarray on Fibonacci grid to Gaussian grid.

    Args:
        dataarray (xr.DataArray): Dataarray with fibonacci grid
        grid_step (float, optional): Grid step of new Gaussian grid. Defaults to 2.5.

    Returns:
        dataarray_gaus: Dataarray interpolated on Gaussian grid.
    """
    # Create gaussian grid
    lon_gaus = np.arange(np.round_(dataarray.coords['lon'].min()),
                         dataarray.coords['lon'].max(),
                         grid_step)
    lat_gaus = np.arange(np.round_(dataarray.coords['lat'].min()),
                         dataarray.coords['lat'].max(),
                         grid_step)
    lon_mesh, lat_mesh = np.meshgrid(lon_gaus, lat_gaus)
    new_points = np.array([lon_mesh.flatten(), lat_mesh.flatten()]).T
    origin_points = np.array(
        [dataarray.coords['lon'], dataarray.coords['lat']]).T

    # Interpolate
    if len(dataarray.data.shape) < 2:  # If there is not time dimension
        origin_values = dataarray.data.flatten()
        assert len(origin_values) == origin_points.shape[0]
        new_values = interp.griddata(origin_points, origin_values, new_points,
                                     method='nearest')
        new_data = new_values.reshape(len(lat_gaus), len(lon_gaus))
        coordinates = dict(lon=lon_gaus, lat=lat_gaus)
        dims = ['lat', 'lon']
    else:  # with time dimension
        new_data = []
        for idx, t in enumerate(dataarray.time):
            origin_values = dataarray.sel(time=t.data).data.flatten()
            assert len(origin_values) == origin_points.shape[0]
            new_values = interp.griddata(origin_points, origin_values,
                                         new_points,
                                         method='nearest')
            new_data.append(
                new_values.reshape(len(lat_gaus), len(lon_gaus))
            )
        coordinates = dict(time=dataarray.time.data,
                           lon=lon_gaus, lat=lat_gaus)
        dims = ['time', 'lat', 'lon']
        new_data = np.array(new_data)

    da_gaus = xr.DataArray(
        data=new_data,
        dims=dims,
        coords=coordinates,
        name=dataarray.name)

    return da_gaus

def cut_map(ds, lon_range=[-180, 180], lat_range=[-90, 90], shortest=True):
    """Cut an area in the map. Use always smallest range as default.
    It lon ranges accounts for regions (eg. Pacific) that are around the -180/180 region.

    Args:
    ----------
    lon_range: list [min, max]
        range of longitudes
    lat_range: list [min, max]
        range of latitudes
    shortest: boolean
        use shortest range in longitude (eg. -170, 170 range) contains all points from
        170-180, -180- -170, not all between -170 and 170. Default is True.
    Return:
    -------
    ds_area: xr.dataset
        Dataset cut to range
    """
    if (max(lon_range) - min(lon_range) <= 180) or shortest is False:
        ds_cut = ds.sel(
            lon=slice(np.min(lon_range), np.max(lon_range)),
            lat=slice(np.min(lat_range), np.max(lat_range))
        )
    else:
        # To account for areas that lay at the border of -180 to 180
        ds_cut = ds.sel(
            lon=ds.lon[(ds.lon < min(lon_range)) | (ds.lon > max(lon_range))],
            lat=slice(np.min(lat_range), np.max(lat_range))
        )

    return ds_cut

def compute_zonal_mean(ds, ):
    zonal_mean = ds.mean(dim='lat', skipna=True)

    return zonal_mean

def compute_meridional_mean(ds):
    lats_rad = np.deg2rad(ds['lat'])
    weighted_meridional_mean = ds.mean(
        dim='lon', skipna=True) # * np.cos(lats_rad)

    weighted_meridional_std = ds.std(
        dim='lon', skipna=True)
    return weighted_meridional_mean, weighted_meridional_std

def compute_meridional_quantile(ds, q):
    lats_rad = np.deg2rad(ds['lat'])
    weighted_meridional_mean = ds.quantile(
        q=q, dim='lon', skipna=True)  # * np.cos(lats_rad)

    return weighted_meridional_mean

def get_map4indices(ds, indices):
    da = xr.ones_like(ds.ds['anomalies']) * np.NAN
    da[:, indices] = ds.ds['anomalies'].sel(points=indices).data

    return da

def get_locations_in_range(def_map, lon_range, lat_range):
    """Returns a map with nans at the positions that are not within lon_range-lat_range

    Args:
        def_map (xr.DataArray): dataarray, must contain lat and lon definition
        lon_range (list): list of lons
        lat_range (list): list of lats

    Returns:
        xr.DataArray: masked xr.DataArray.
    """
    if (max(lon_range) - min(lon_range) < 180):
        mask = (
            (def_map['lat'] >= min(lat_range))
            & (def_map['lat'] <= max(lat_range))
            & (def_map['lon'] >= min(lon_range))
            & (def_map['lon'] <= max(lon_range))
        )
    else:   # To account for areas that lay at the border of -180 to 180
        mask = (
            (def_map['lat'] >= min(lat_range))
            & (def_map['lat'] <= max(lat_range))
            & ((def_map['lon'] <= min(lon_range)) | (def_map['lon'] >= max(lon_range)))
        )
    mmap = xr.where(mask, def_map, np.nan)
    return mmap


# list and tuple
a = [1,2,3] # list can read and  write
b = (4,5,6) # tuple can only read
a.append(10)
# b.append(10)
c = tuple(a)
# c.append(12)
d = list(b)
d.append(12)
b = tuple(d)

print('a = ',a)
print('b = ',b)
print('c = ',c)
print('d = ',d)
# print('e = ',e)


# Pneumonia_Classifer:  predict x-ray
# Richard Scott McNew
# A02077329
# CS 6600: Intelligent Systems

from __future__ import absolute_import, division, print_function, unicode_literals
import os
import shutil
import tempfile
import sys
from time import sleep
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator

IMAGE_SIDE = 450 # We have to resize the dataset images to reduce memory consumption

# get the current working directory
current_dir = os.getcwd()

MODEL_PATH = os.path.join(current_dir, "pneumonia_classifier_model.h5")

def download_trained_model_from_google_drive_shared(download_anyway=False):
    if not os.path.exists(MODEL_PATH) or download_anyway:
        print("Downloading trained model from Google Drive shared link . . .")
        os.system("gdown https://drive.google.com/uc?id=1wOB-6Tn4-kexFliYaoO42Qvfneih81g7")
        print("Download completed!  Loading the model . . .")
    else:
        print("Using previously downloaded model")
    model = tf.keras.models.load_model(MODEL_PATH, custom_objects=None, compile=True)
    print("Model loaded.")
    return model

# create an image generator for the uploaded images
def create_image_generator(dir_name):
    print("Creating image generator for images in directory: ", dir_name)
    image_generator = ImageDataGenerator(rescale=1./255)
    data_gen = image_generator.flow_from_directory(
            directory=str(dir_name),
            target_size=(IMAGE_SIDE, IMAGE_SIDE),
            color_mode="grayscale",
            class_mode=None) # class_mode has to be None to indicate there are no data labels
    return data_gen

# Round the prediction to a human-readable interpretation
def interpret_prediction(prediction):
    print("Prediction is:  {}".format(prediction))
    pred_list = prediction[0].tolist()
    max_index = pred_list.index(max(pred_list))
    if max_index == 0:
        print("NORMAL")
    else:
        print("PNEUMONIA")

# print usage
def print_usage():
    print("predict_xray.py chest_xray_image")

# get the full path to the image file argument
def get_arg_path(image_file):
    if not os.path.exists(image_file):
        return os.path.join(current_dir, image_file)

##### Main section #####
# get the chest x-ray path and file
arg_count = len(sys.argv) - 1
if arg_count != 1:
    print_usage()
else:
    model = download_trained_model_from_google_drive_shared()
    # create temporary directory
    temp_dir_name = tempfile.mkdtemp()
    print('Created temporary directory: ', temp_dir_name)
    # cd to temporary directory
    os.chdir(temp_dir_name)
    # make subdirectory for image files;  per the Keras documentation:
    # "Please note that in case of class_mode None, the data still needs
    # to reside in a subdirectory of directory for it to work correctly."
    image_path = os.path.join(temp_dir_name, "images")
    os.mkdir(image_path)
    os.chdir(image_path)
    # move the chest x-ray image to the temporary directory
    shutil.copy(get_arg_path(sys.argv[1]), image_path)
    # preprocess uploaded images
    image_gen = create_image_generator(temp_dir_name)
    # run prediction
    prediction = model.predict(image_gen)
    # interpret and print out result
    interpret_prediction(prediction)
    # return to starting directory
    os.chdir(current_dir)
    # clean-up temporary directory
    shutil.rmtree(temp_dir_name)


#import

import random  #pour l'alétoire
import tkinter #pour créé des fenêtres
from tkinter import *
from tkinter.ttk import *
from tkinter import Text

#tkinter

root = Tk()                                    #créé une fenêtre
root.title("Dé")                               #nom d'affichage de la fenêtre
root.geometry("500x500")                       #dimension de la fenêtre
root.resizable(width=False, height=False)      #empêcher le redimensionnement de la fenêtre

#definir les actions

a = Label (root, font=("Helvetica", 300))     #préparer la zone de texte

def roll() :
    choix = ['\u2680','\u2681','\u2682','\u2683','\u2684','\u2685']                     #liste de caractères spéciaux du dé
    a.config(text = f"{random.choice(choix)}")                                          #zone de résultat du lancer, ainsi que choix du dé
    a.pack(side= "top")                                                                 #faire apparaitre le lancer

#bouton de lancer

boutton = Button(root, text = "Lancer le dé",         #créer le bouton
                          command = roll)             #action lors du clic
boutton.pack(side = "top")                            #le faire apparaitre

#lancer la fenêtre

root.mainloop()


from bs4 import BeautifulSoup
import requests
import pandas as pd
import json
from requests.compat import urljoin
from datetime import datetime
import re
import asyncio
from asyncio import AbstractEventLoop
import aiohttp
from colorama import Fore
from collections import defaultdict
import bs4
from unidecode import unidecode
from time import sleep

def main():
    # Create loop
    print(str(datetime.now().time())[:8])
    loop = asyncio.get_event_loop()
    try:
        with open('../data/game_info_190509.json', 'r') as fp:
            xml_data = json.load(fp)
    except:
        pass
        xml_data = []
    pg_rng = 20
    for i in range(int(len(xml_data) / 100) + 1, 151, pg_rng):
        xml_data += loop.run_until_complete(get_game_ids(loop, i, i + pg_rng))
        with open('../data/game_info_190509.json', 'w') as fp:
            json.dump(xml_data, fp)
        sleep(60)

async def get_game_ids(loop: AbstractEventLoop, start_pg: int, end_pg: int) -> list:
    pg_html = []
    pg_ids = []
    pg_urls = []
    xml_data = []
    for pg_rng in range(start_pg, end_pg):
        pg_html.append((loop.create_task(get_html(pg_rng)), pg_rng))

    pg_xml = []
    for pg, n in pg_html:
        html = await pg
        # print(Fore.GREEN + f"Starting HTML for page {n} at time {str(datetime.now().time())[:8]}", flush=True)
        pg_data = get_pg_ids(html)
        print(Fore.LIGHTGREEN_EX + f"Finished HTML for page {n} at time {str(datetime.now().time())[:8]}", flush=True)
        pg_ids += pg_data[0]
        pg_urls += pg_data[1]
        pg_xml.append((loop.create_task(get_xml(pg_data[0])), n))

    for pg_xml_data, n in pg_xml:
        xml = await pg_xml_data
        print(Fore.BLUE + f"Starting XML page {n} at time {str(datetime.now().time())[:8]}", flush=True)
        xml_data += extract_xml(xml)
        print(Fore.LIGHTBLUE_EX + f"Finished XML page {n} at time {str(datetime.now().time())[:8]}", flush=True)

    for idx, game_url in enumerate(pg_urls):
        xml_data[idx]['url'] = game_url
    print(str(datetime.now().time())[:8])

    return xml_data

async def get_html(pg_num: int):
    # print(Fore.YELLOW + f"Getting HTML for page number {pg_num}", flush=True)
    bs_url = 'https://boardgamegeek.com/browse/boardgame/page/'
    connector = aiohttp.TCPConnector(limit_per_host=2)
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get(f'{bs_url}{pg_num}') as resp:
            resp.raise_for_status()

            html = await resp.text()
            return html

async def get_xml(pg_ids):
    xml_bs = 'https://www.boardgamegeek.com/xmlapi2/thing?type=boardgame&stats=1&ratingcomments=1&page=1&pagesize=10&id='
    async with aiohttp.ClientSession() as session:
        async with session.get(f'{xml_bs}{",".join(pg_ids)}') as resp:
            resp.raise_for_status()

            xml = await resp.text()
            return xml

def get_pg_ids(html: str):
    # print(Fore.CYAN + f"Getting ids for page number {page_number}", flush=True)
    soup = BeautifulSoup(html, 'html.parser')
    bs_pg = 'https://boardgamegeek.com/'
    all_games = soup.find_all('td', {'class': 'collection_objectname'})
    game_ids = [x.find('a')['href'].split('/')[-2] for x in all_games]
    game_pages = [urljoin(bs_pg, x.find('a')['href']) for x in all_games]
    return game_ids, game_pages

def extract_xml(xml: str):
    item_list = []
    soup = BeautifulSoup(xml, "xml")
    items = soup.find_all('item')
    for idx, item in enumerate(items):
        item_list.append(extract_item_dict(item))
    return item_list

def extract_item_dict(game_item):
    item_dict = defaultdict(list)
    for x in range(len(game_item.contents)):
        if type(game_item.contents[x]) == bs4.element.Tag:
            itm = game_item.contents[x]
            item_dict[itm.name].append(itm.attrs)
    game_dict = {'name': item_dict['name'][0]['value'],
                 'game_id': game_item['id']}
    values_int = ['yearpublished', 'minplayers', 'maxplayers', 'playingtime', 'minplaytime', 'maxplaytime', 'minage']
    for vals in values_int:
        game_dict[vals] = item_dict[vals][0]['value']
    link_categ = ['boardgamecategory', 'boardgamemechanic', 'boardgamefamily', 'boardgameexpansion', 'boardgameartist',
                  'boardgamecompilation', 'boardgameimplementation', 'boardgamedesigner', 'boardgamepublisher',
                  'boardgameintegration']
    link_dict = defaultdict(list)
    for item_link in item_dict['link']:
        link_dict[item_link['type']].append(unidecode(item_link['value']))
    for categ in link_categ:
        game_dict[categ] = link_dict[categ]
    stats_float = ['average', 'bayesaverage', 'stddev', 'median', 'averageweight']
    for stat in stats_float:
        game_dict[stat] = float(eval(f'game_item.ratings.{stat}["value"]'))
    stats_int = ['usersrated', 'owned', 'trading', 'wanting', 'wishing', 'numcomments', 'numweights']
    for stat in stats_int:
        game_dict[stat] = int(eval(f'game_item.ratings.{stat}["value"]'))
    game_ranks = [x for x in game_item.ranks.contents if type(x) == bs4.element.Tag]
    for rnk in game_ranks:
        game_dict[rnk['friendlyname'].replace(' ', '')] = int(rnk['value'])
    return game_dict

if __name__ == '__main__':
    main()
    # game_items = game_data_async()
    # export_csv(game_items)
    # print(5)


# -*- coding: utf-8 -*-
"""
Created on Wed Sep 25 08:51:12 2019

@author: prnvb
"""

TWO_STAGE = True
IMG_SHAPE = (256, 256)

TRAIN_SIZE = 2100
TEST_SIZE = 900

COORD_CONV = True

#Stage 1 Hyperparameters
STAGE1_AUX_DECODER = True
STAGE1_ACTIVATION = 'sigmoid'
STAGE1_LOSS = 'wbce_stage1' #wbce_stage1/wbce_stage2/bce/mae

STAGE1_WBCE_BETA = 0.1
STAGE1_BALANCED = False

#Stage 2 Hyperparameters
STAGE2_AUX_DECODER = True
STAGE2_ACTIVATION = 'sigmoid'
STAGE2_LOSS = 'wbce_stage2' #wbce_stage1/wbce_stage2/bce/mae

STAGE2_WBCE_BETA = 0.1
STAGE2_BALANCED = True


# -*- coding:utf-8 -*-
# editor: zzh

import numpy as np
import pandas as pd
from keras.utils import np_utils
from sklearn import preprocessing

import keras.backend as k
from keras.layers import *
from keras.models import Model
from keras.optimizers import Adam
import os,shutil
from keras.callbacks import ModelCheckpoint

from char_vector.untils import *
import pickle

vectors = np.load("D:\MyProject\天气灾害分类及信息提取\灾害类别分类_cnn_rnn\char_vector\\vectors.npy")

def lables2onehot(data, num_class):
    """
            字符串标签类别转为one_hot类型数据
            :param data:
            :param num_class:
            :return:
            """
    le = preprocessing.LabelEncoder()
    target = le.fit_transform(data)
    target = np_utils.to_categorical(target, num_classes=num_class)
    return target

class BiLstmClf(object):
    def build_model(self,maxlen,num_class,vocab_len,dim,hidden_size):
        x_input = Input(shape=(maxlen,))
        x_embed = Embedding(input_dim=vocab_len, output_dim=dim, input_length=maxlen,weights=[vectors])(x_input)

        x_cov1 = Conv1D(filters=256, kernel_size=2, strides=1, activation='relu', padding='same')(x_embed)
        x_cov2= Conv1D(filters=256, kernel_size=3, strides=1, activation='relu', padding='same')(x_embed)
        x_cov3 = Conv1D(filters=256, kernel_size=4, strides=1, activation='relu', padding='same')(x_embed)

        x_cov = Concatenate(axis=-1)([x_cov1,x_cov2,x_cov3])
        print(x_cov.shape)
        x_masked = Masking(mask_value=0.,)(x_cov)

        hs = Bidirectional(LSTM(units=hidden_size,return_sequences=True,dropout=0.5))(x_masked)
        ms = Dense(1,activation='tanh')(hs)
        # print(ms.shape)
        alpha = Softmax()(ms)
        # print(alpha.shape)
        out = Multiply()([alpha,hs])
        # print(out.shape)
        out = Lambda(lambda x: k.sum(x,axis=1))(out)
        out = ReLU()(out)
        out = Dense(64)(out)
        out = Dropout(rate=0.2)(out)
        output = Dense(num_class,activation='softmax')(out)

        self.model = Model(x_input,output)

        self.model.compile(loss='categorical_crossentropy',
            optimizer=Adam(1e-5),  # 用足够小的学习率
            metrics=['accuracy'])

        self.model.summary()

    def __init__(self,num_class,maxlen = 15):
        self.build_model(maxlen,num_class,vocab_len=vectors.shape[0],dim = vectors.shape[1],hidden_size=256)
        self.maxlen = maxlen

    def sentences_encode(self,sentences):
        X = []
        for sentence in sentences:
            X.append(sentence2ids(sentence,self.maxlen))
        return np.array(X)

    def generater(self,x_train,y_train,batch_size,mask_rate=0.1):
        while True:
            len1 = len(x_train)
            len2 = len(y_train)
            if(len1 != len2):
                raise Exception("len1 != len2")
            i = 0
            while i*batch_size + batch_size < len1:
                x1_in = x_train[i*batch_size:i*batch_size + batch_size]
                y = y_train[i*batch_size:i*batch_size + batch_size]
                i+=1
                yield({'input_1':x1_in},{'dense_3':y})

if __name__ == '__main__':

    tcc = BiLstmClf(num_class=12,maxlen=20)
    train_data = pd.read_csv("..\\灾害类别分类\\DATAS\\DATA6\\train_data.csv")
    test_data = pd.read_csv("..\\灾害类别分类\\DATAS\\DATA6\\test_data.csv")
    test_data1 = test_data[:int(len(test_data) / 2)]
    test_data = test_data[int(len(test_data) / 2):]
    train_data = pd.concat([train_data, test_data1])

    # Xs = tcc.sentences_encode(train_data["title"])
    # Ys = lables2onehot(train_data["label"],num_class=12)
    #
    # checkpoint = ModelCheckpoint('models\\rnn_cnn\\rnn_cnn_clf_{epoch:03d}.h5', save_weights_only=True, period=10)
    # his = tcc.model.fit_generator(generator=tcc.generater(Xs,Ys,batch_size=16),epochs=300,steps_per_epoch=int(len(Ys)/16),callbacks=[checkpoint])
    # pickle.dump(his,open("models\\rnn_cnn\\history.pkl",'rb'))

    Xs = tcc.sentences_encode(test_data["title"])
    Ys = lables2onehot(test_data["label"], num_class=12)
    #
    for i in range(1,10):
        tcc.model.load_weights("models\\rnn_cnn\\rnn_cnn_clf_0{}0.h5".format(i))
        score = tcc.model.evaluate(Xs,Ys)
        print(score)


import os.path

import pytest

INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')

def compute(s: str) -> int:
    packet = s.strip()

    packet = "".join([hexadecimal_to_binary(c) for c in packet])
    versions = []

    _, value = parse_packet(versions, packet, 0)

    return value

def parse_packet(versions, packet, index):
    if "1" not in packet:
        return

    version = int(packet[index:index + 3], 2)
    versions.append(version)
    index += 3

    type_id = int(packet[index:index + 3], 2)
    index += 3

    if type_id == 4:
        value = ""
        while packet[index] == "1":
            value += packet[index + 1:index + 5]
            index += 5
        value += packet[index + 1:index + 5]
        index += 5

        return index, int(value, 2)

    else:
        values = []
        length_type_id = int(packet[index:index + 1], 2)
        index += 1

        if length_type_id == 0:
            length = int(packet[index:index + 15], 2)
            index += 15
            end = index + length

            while index < end:
                index, value = parse_packet(versions, packet, index)
                values.append(value)

        else:
            count = int(packet[index:index + 11], 2)
            index += 11

            for _ in range(count):
                index, value = parse_packet(versions, packet, index)
                values.append(value)

        if type_id == 0:
            value = sum(values)
        elif type_id == 1:
            value = 1
            for v in values:
                value *= v
        elif type_id == 2:
            value = min(values)
        elif type_id == 3:
            value = max(values)
        elif type_id == 5:
            value = 1 if values[0] > values[1] else 0
        elif type_id == 6:
            value = 1 if values[0] < values[1] else 0
        else:
            value = 1 if values[0] == values[1] else 0

        return index, value

def hexadecimal_to_binary(hexadecimal: str) -> str:
    return bin(int(hexadecimal, 16))[2:].zfill(4)

INPUT_S = '''\
9C0141080250320F1802104A08
'''
EXPECTED = 1

@pytest.mark.parametrize(
    ('input_s', 'expected'),
    (
        (INPUT_S, EXPECTED),
    ),
)
def test(input_s: str, expected: int) -> None:
    assert compute(input_s) == expected

def main() -> int:
    with open(INPUT_TXT, "r") as f:
        print(compute(f.read()))

    return 0

if __name__ == '__main__':
    raise SystemExit(main())


from typing import List

from werkzeug.exceptions import BadRequest

from app.calculations.allocation.convolution_methods import *
from app.calculations.allocation.optimization_algorithms import *
from app.calculations.allocation.valuation_methods import *
from app.utils.qc_strategy import QcStrategy

def allocate(components: Tuple[List[pd.DataFrame], List[pd.DataFrame]],
             qc_strategy: Optional[QcStrategy] = None,
             valuation_method: str = "mean", algorithm: str = "brute_force",
             settings_dict: Dict[str, Any] = None) -> Tuple[List[int], List[float]]:
    """
    Allocates all batches of two or more component types.

    Parameters
    ----------
    components
        Component types that should be allocated to each other.
        Every component type consists of a list of batches,
        and each batch consists of a list distributions for each test point.
    qc_strategy
        Tells how two distributions should be convoluted.
    valuation_method
        Tells how two distributions are converted into a single scalar value,
        i.e. how a given allocation should be valuated.
        One of "mean", "mean_std", "cpk", "qualityloss".
    algorithm
        Optimization algorithm.
        Currently, only "brute_force" is supported.
    settings_dict
        config name etc.

    Returns
    -------
    List[int]
        optimal allocation sequence.
    List[float]
        the optimal scalar values.
    """
    ####################################################################
    # INPUT VALIDATION                                                 #
    ####################################################################
    if algorithm == "brute_force" and len(components) > 2:
        raise BadRequest("Brute force algorithm only supports two components")
    if algorithm not in supported_algorithms:
        raise BadRequest(
            "Only " + str(supported_algorithms.keys) + " algorithms supported"
        )
    if qc_strategy not in supported_convolution_methods:
        raise BadRequest(
            "Only " + str(supported_convolution_methods.keys) + " convolution methods supported"
        )
    if valuation_method not in supported_valuation_methods:
        raise BadRequest("Only " + str(supported_valuation_methods.keys) + " valuation methods supported")

    ####################################################################
    # APPLY SELECTED ALGORITHM WITH THE SELECTED METHOD                #
    ####################################################################

    # optimization algorithm could be to try out all possible combinations,
    # or something more sophisticated like genetic optimization
    optimization_algorithm = supported_algorithms[algorithm]
    # tells how two components are assembled and what the
    # resulting functional fulfillment will be
    convolution_method = supported_convolution_methods[qc_strategy]
    # evaluates a given combination using mean, std, or something else
    valuation_method = supported_valuation_methods[valuation_method]

    # call optimization algorithm
    optimal_permutation, scalar = optimization_algorithm(components, convolution_method, valuation_method,
                                                         settings_dict or {})
    return optimal_permutation, scalar

def allocate_complete(components_batches: List[List[List[pd.DataFrame]]], qc_strategy: Optional[QcStrategy] = None,
                      valuation_method: str = "mean", algorithm: str = "brute_force",
                      settings_dict: Dict[str, Any] = None) -> List[Tuple[int, List[int]]]:
    """
    Iteratively allocates all batches and then for every batch all klts.

    Parameters
    ----------
    components_batches
        For every component, a list of batches, which consists of a list of klts,
        which consists of characteristic values.
    qc_strategy
        Tells how two distributions should be convoluted.
    valuation_method
        Tells how two distributions are converted into a single scalar value,
        i.e. how a given allocation should be valuated.
        One of "mean", "mean_std", "cpk", "qualityloss".
    algorithm
        Optimization algorithm.
        Currently, only "brute_force" is supported.
    settings_dict
        config name etc.

    Returns
    -------
    List[Tuple[int, List[int]]]
        Every entry of this list represents a) the allocated batch and b) the allocated klts for the allocated batch.
    """
    # concat data frames on batch level:
    components_concat = [[pd.concat(batch).reset_index(drop=True) for batch in component] for component in
                         components_batches]
    # calculate optimal batch allocation
    # noinspection PyTypeChecker
    optimal_permutation, _ = allocate(components_concat, qc_strategy, valuation_method, algorithm, settings_dict)
    # reorder second component according to optimal allocation
    components_batches[1] = [components_batches[1][index] for index in optimal_permutation]

    result = []
    for base_batch_idx, allocated_batch_idx in zip(range(len(optimal_permutation)), optimal_permutation):
        base_klts = components_batches[0][base_batch_idx]
        comparison_klts = components_batches[1][allocated_batch_idx]
        # calculate optimal klt allocation
        # noinspection PyTypeChecker
        optimal_klt_permutation, _ = allocate([base_klts, comparison_klts], qc_strategy, valuation_method, algorithm,
                                              settings_dict)
        result.append((allocated_batch_idx, optimal_klt_permutation))

    return result


import redis
import re
from datetime import datetime, timedelta
import time

r = redis.Redis(decode_responses=True)

recDateBeg = datetime(1989, 1, 9, 12, 0, 0)
recDateEnd = datetime(1989, 1, 9, 12, 0, 0)
minDateEnd = datetime(2010, 1, 9, 12, 0, 0)
zerDiff = recDateEnd - recDateBeg
maxDiff = minDateEnd - recDateBeg

plotDict = {}

allTeil = ["TEIL:A", "TEIL:B", "TEIL:C", "TEIL:D", "TEIL:E", "TEIL:F", "TEIL:G",
           "TEIL:H", "TEIL:I", "TEIL:J", "TEIL:K"]
diffFile = open("../AuswertungCSV/takt2.txt", "w")
# allTeil = ["TEIL:C"]

def sortListTime(givList):
    myDict = {}
    for el in givList:
        myDict[el] = r.hget(el, "Begin")
    sortedDict = dict(sorted(myDict.items(), key=lambda item: item[1]))
    return sortedDict

for teil in allTeil:
    allData = r.lrange(teil, 0, -1)
    snrDict = []
    allSnr = []
    maxDate = zerDiff
    minDate = maxDiff
    beforeEnd = recDateBeg

    plotList = []

    fail = 0

    numCounter = 0
    allDiffs = zerDiff

    for conDat in allData:
        datList = r.lrange(conDat, 0, -1)
        snr = r.hget(datList[0], "SNR")
        if len(r.lrange(snr, 0, -1)) > 1 and not snr in snrDict:
            snrDict.append(snr)
        if not snr in allSnr:
            allSnr.append(snr)

    """
    Für jede SNR (SNRs)
        Für jedes Element dieser SNR (Verknüpfungen)
            Datum des ersten Input merken
            Datum des letzten Output merken
            Wenn Differenzen entsprechend sind als Rekorde merken
    """
    for snrEl in snrDict:  # Für jede SNR
        snrElList = r.lrange(snrEl, 0, -1)
        firstCounter = 0

        fail = fail + (len(snrElList) - 1)

        beforeEnd = recDateBeg

        sortElList = sortListTime(snrElList)

        for inEl in sortElList:  # Für jeden Input-DS in SNR (sortiert)
            inCounter = inEl.partition(':')[2]
            datList = r.lrange(snrEl + ":" + inCounter, 0, -1)  # Verknüpfung zum Input
            datRange = len(datList)

            beginDate = r.hget(datList[0], "Begin")
            beginDateTime = datetime.strptime(beginDate, '%Y-%m-%dT%H:%M:%S.%f0')

            if datRange > 1:
                endDate = r.hget(datList[datRange - 1], "Date")
                endDateTime = datetime.strptime(endDate, '%Y-%m-%dT%H:%M:%S.%f0')

            if firstCounter:
                diffTime = beginDateTime - beforeEnd
                if (datRange > 1 or not beforeEnd == recDateEnd) and diffTime.total_seconds() > 0:

                    numCounter = numCounter + 1
                    allDiffs = allDiffs + diffTime
                    plotList.append(diffTime.total_seconds() / 60)

                    if diffTime < minDate:
                        minDate = diffTime

                    if diffTime > maxDate:
                        maxDate = diffTime

            beforeEnd = endDateTime

            firstCounter = 1

            if not datRange > 1:
                firstCounter = 0

    if not maxDate == zerDiff:
        print(teil)
        writer = teil + " " + str(maxDate) + " " +str(minDate) + " " + str(allDiffs / numCounter) + " " + str(fail / len(allSnr)) +"\n"
        diffFile.write(writer)


from .spherical_hmc import DualAveragingSphericalHMC, \
    cot, arccot, SphericalHMCState
import numpy as np

def integrator(q, pot_gradient, z, trafo, jac, stepsize, nsteps):
    cumsinq = np.cumprod(np.sin(q))
    v = z / np.concatenate(([1], cumsinq[:-1]))
    du = pot_gradient(trafo(q))[0] * jac

    # make a half step for velocity
    v = v - stepsize/2 * du/np.concatenate(([1], cumsinq[:-1]**2))

    # alternate full steps for position and momentum
    for l in range(nsteps):
        # make a full step for position
        # 1. map to augmented sphere
        x = np.concatenate((np.cos(q), [1])) * np.concatenate(([1], cumsinq))
        dx = (np.concatenate((-v*np.tan(q), [0])) +
              np.concatenate(([0], np.cumsum(v*cot(q))))) * x
        # 2. rotate on sphere
        x0 = x
        dx_nom = np.sqrt(np.sum(dx**2))
        costdx = np.cos(dx_nom*stepsize)
        sintdx = np.sin(dx_nom*stepsize)
        x = x0*costdx + dx/dx_nom*sintdx
        dx = -x0*dx_nom*sintdx + dx*costdx
        # 3. go back to hyper-rectangle
        cumx2 = np.cumsum(x**2)
        cotq = x[:-1] / np.sqrt(1-cumx2[:-1])
        q = arccot(cotq)
        q[-1] = np.pi + np.sign(x[-1])*(q[-1]-np.pi)
        v = -cotq*(dx[:-1]/x[:-1]+np.concatenate(([0], np.cumsum(x*dx)[:-2])) /
                   (1-np.concatenate(([0], cumx2[:-2]))))
        v[-1] = v[-1] * np.sign(x[-1])

        # make last half step for velocity
        cumsinq = np.cumprod(np.sin(q))
        du = pot_gradient(trafo(q))[0] * jac
        if l != nsteps-1:
            v = v - stepsize * du/np.concatenate(([1], cumsinq[:-1]**2))

    z = v*np.concatenate(([1], cumsinq[:-1])) - \
        stepsize/2 * du/np.concatenate(([1], cumsinq[:-1]))

    return q, z

class SphericalNUTS(DualAveragingSphericalHMC):
    """
    No-U-Turn Sampler with Dual Averaging for Box-Type Constraints
    """

    def __init__(self, target_density, adapt_schedule, lim_lower=None,
                 lim_upper=None, t0=10, stepsize_bar0=1, Hbar0=0, gamma=0.05,
                 kappa=0.75, delta=0.65, Emax=1000):

        super().__init__(target_density, 1., adapt_schedule,
                         lim_lower, lim_upper, t0, stepsize_bar0,
                         Hbar0, gamma, kappa, delta)
        self.Emax = Emax
        self.alpha = None
        self.n_alpha = None

    def proposal(self, current):
        # initialization
        try:
            q_minus = q_plus = q = current.theta
        except AttributeError:
            current = self.init_state(current)
            q_minus = q_plus = q = current.theta

        z0 = np.random.standard_normal(self.ndim)
        u = np.random.uniform()
        z_minus = z_plus = current.momentum = z0

        j, n, s = 0, 1, 1

        while s == 1:
            v = np.random.choice([-1, 1])
            if v == -1:
                (q_minus, z_minus, _, _, q_prime, n_prime, s_prime,
                 self.alpha, self.n_alpha) = self.build_tree(
                    q_minus, z_minus, u, v, j, self.stepsize, q, z0, self.Emax)
            else:
                (_, _, q_plus, z_plus, q_prime, n_prime, s_prime, self.alpha,
                 self.n_alpha) = self.build_tree(
                    q_plus, z_plus, u, v, j, self.stepsize, q, z0, self.Emax)

            if s_prime == 1 and np.random.uniform() < min(1, n_prime/n):
                q = q_prime

            dq = q_plus - q_minus
            n = n + n_prime
            s = s_prime * (np.dot(dq, z_minus) >= 0) * (np.dot(dq, z_plus) >= 0)
            j = j + 1

        x = self.theta_to_x(q)
        prob = self.target_density.pdf(x)
        return SphericalHMCState(x, tag=self.log_weight(q), pdf=prob, theta=q)

    def build_tree(self, q, z, u, v, j, stepsize, q0, z0, Emax):
        if j == 0:
            # Base case - take one leapfrog step in the direction v.
            q_prime, z_prime = integrator(
                q, self.target_density.pot_gradient, z, self.theta_to_x,
                self.J_xtheta, v*stepsize, nsteps=1)

            E = -self.target_density.pot(self.theta_to_x(q_prime)) - \
                .5*np.sum(z_prime**2)
            E0 = -self.target_density.pot(self.theta_to_x(q0)) - \
                 .5*np.sum(z0**2)
            dE = E - E0

            n_prime = (np.log(u) - dE <= 0)
            s_prime = (np.log(u) - dE < Emax)
            return (q_prime, z_prime, q_prime, z_prime, q_prime, n_prime,
                    s_prime, min(1, np.exp(dE)), 1)
        else:
            # Recursion - implicitly build the left and right subtrees.
            (q_minus, z_minus, q_plus, z_plus, q_prime, n_prime, s_prime,
             alpha_prime, n_alpha_prime) = self.build_tree(
                q, z, u, v, j - 1, stepsize, q0, z0, Emax)
            if s_prime == 1:
                if v == -1:
                    (q_minus, z_minus, _, _, q_2prime, n_2prime, s_2prime,
                     alpha_2prime, n_alpha_2prime) = self.build_tree(
                        q_minus, z_minus, u, v, j - 1, stepsize, q0, z0, Emax)
                else:
                    (_, _, q_plus, z_plus, q_2prime, n_2prime, s_2prime,
                     alpha_2prime, n_alpha_2prime) = self.build_tree(
                        q_plus, z_plus, u, v, j - 1, stepsize, q0, z0, Emax)
                if np.random.uniform() < n_2prime/max(n_prime + n_2prime, 1.):
                    q_prime = q_2prime

                alpha_prime = alpha_prime + alpha_2prime
                n_alpha_prime = n_alpha_prime + n_alpha_2prime

                dq = q_plus - q_minus
                s_prime = (s_2prime * (np.dot(dq, z_minus) >= 0) *
                           (np.dot(dq, z_plus) >= 0))
                n_prime = n_prime + n_2prime
            return (q_minus, z_minus, q_plus, z_plus, q_prime, n_prime,
                    s_prime, alpha_prime, n_alpha_prime)

    def accept(self, state, candidate):
        return 1  # accept all

    def adapt(self, iteration, prev, current, accept):
        super().adapt(iteration, prev, current, self.alpha / self.n_alpha)

    #
    # def sample(self, nsamples, start):
    #     samples = np.zeros([nsamples, self.ndim])
    #     weights = np.zeros(nsamples)
    #     current_q = self.x_to_theta(start)
    #     samples[0] = start
    #     weights[0] = (np.arange(1, self.ndim)-self.ndim).dot(np.log(np.sin(current_q[:-1]))) + np.sum(np.log(self.J_xtheta)) # log weight
    #     for t in range(1, nsamples):
    #         current_q = self.step(current_q)
    #         # back to constrained domain
    #         x = self.theta_to_x(current_q)
    #         weight = (np.arange(1, self.ndim)-self.ndim).dot(np.log(np.sin(current_q[:-1]))) + np.sum(np.log(self.J_xtheta)) # log weight
    #         samples[t] = x
    #         weights[t] = weight
    #
    #         self.adapt(t, aprob=self.alpha/self.n_alpha)
    #
    #         if (t+1)%1000 == 0:
    #             print('passed: ', t+1, 'samples')
    #
    #     #resample
    #     weights = np.exp(weights-weights.mean())
    #     weights = weights/weights.sum()
    #     resamp_idx = np.random.choice(np.arange(nsamples), nsamples, replace=True, p=weights)
    #     samples = samples[resamp_idx]
    #
    #     return samples, samples.mean(), samples.var()


from django.core.handlers.wsgi import WSGIRequest
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.contrib import messages
from django.views import View
from django.template import RequestContext

from TWT.context import get_discord_context
from ..models import Challenge
from TWT import discord

class DetailView(View):
    """Detailed view of a challenge."""

    @staticmethod
    def get(request: WSGIRequest, challenge_id: int) -> HttpResponse:
        if not request.user.is_authenticated:
            messages.add_message(request, messages.INFO, "You are not logged in!")
            return redirect("/")

        challenges = Challenge.objects.filter(id=challenge_id)
        print(len(challenges))
        if not len(challenges):
            return redirect("/")

        context = get_discord_context(request=request)
        context["challenge"] = challenges[0]

        if not challenges[0].posted:
            if not discord.is_staff(member_id=context["user_id"]):
                messages.add_message(
                    request, messages.INFO, "You do not have permission to view that!"
                )
                return redirect("/")

        return render(
            request=request, template_name="challenges/view.html", context=context
        )


# Template for code submission
# Name       :Alyssa Chonko
# Email      :alc258@pitt.edu
# Date       :09/06.16
# Class      :CS0008-f2016
# instructor : Max Novelli (man8@pitt.edu)
#
# Description:
# description of this file goes here
# Example: Starting with Python, Chapter 1, Exercise 3
#
# Notes:
# ch 3 exercise fromm recitation

# ...and now let's program with Python
#checking if a users input number is positive
x=input('what is your number? ')
if(x>0):
   print(x*3)
if(x==0):
    print('What a cool number!')
if(x<0):
    (x+5)


from tda_cola import Cola, cola_vacia, arribo, atencion
from tda_heap import Heap, arribo as arribo_h, heap_vacio, atencion as atencion_h
from tda_heap import cambiar_prioridad, buscar as buscar_h
from tda_pila_dinamico import Pila, apilar, pila_vacia, desapilar
from math import inf
from random import randint

class nodoArista(object):
    """Clase nodo vértice."""

    def __init__(self, info, destino):
        """Crea un nodo arista con la información cargada."""
        self.info = info
        self.destino = destino
        self.sig = None

class nodoVertice(object):
    """Clase nodo vértice."""

    def __init__(self, info, datos=None):
        """Crea un nodo vértice con la información cargada."""
        self.info = info
        self.datos = datos
        self.sig = None
        self.visitado = False
        self.adyacentes = Arista() # lista de aristas

class Grafo(object):
    """Clase grafo implementación lista de listas de adyacencia."""

    def __init__(self, dirigido=True):
        """Crea un grafo vacio."""
        self.inicio = None
        self.dirigido = dirigido
        self.tamanio = 0

class Arista(object):
    """Clase lista de arsitas implementación sobre lista."""

    def __init__(self):
        """Crea una lista de aristas vacia."""
        self.inicio = None
        self.tamanio = 0

def insertar_vertice(grafo, dato, datos=None):
    """Inserta un vértice al grafo."""
    nodo = nodoVertice(dato, datos)
    if (grafo.inicio is None or grafo.inicio.info > dato):
        nodo.sig = grafo.inicio
        grafo.inicio = nodo
    else:
        ant = grafo.inicio
        act = grafo.inicio.sig
        while(act is not None and act.info < nodo.info):
            ant = act
            act = act.sig
        nodo.sig = act
        ant.sig = nodo
    grafo.tamanio += 1

def insertar_arista(grafo, dato, origen, destino):
    """Inserta una arista desde el vértice origen al destino."""
    agregrar_arista(origen.adyacentes, dato, destino.info)
    if(not grafo.dirigido):
        agregrar_arista(destino.adyacentes, dato, origen.info)

def agregrar_arista(origen, dato, destino):
    """Agrega la arista desde el vértice origen al destino."""
    nodo = nodoArista(dato, destino)
    if (origen.inicio is None or origen.inicio.destino > destino):
        nodo.sig = origen.inicio
        origen.inicio = nodo
    else:
        ant = origen.inicio
        act = origen.inicio.sig
        while(act is not None and act.destino < nodo.destino):
            ant = act
            act = act.sig
        nodo.sig = act
        ant.sig = nodo
    origen.tamanio += 1

def eliminar_vertice(grafo, clave):
    """Elimina un vertice del grafo y lo devuelve si lo encuentra."""
    x = None
    if(grafo.inicio.info == clave):
        x = grafo.inicio.info
        grafo.inicio = grafo.inicio.sig
        grafo.tamanio -= 1
    else:
        ant = grafo.inicio
        act = grafo.inicio.sig
        while(act is not None and act.info != clave):
            ant = act
            act = act.sig
        if (act is not None):
            x = act.info
            ant.sig = act.sig
            grafo.tamanio -= 1
    if(x is not None):
        aux = grafo.inicio
        while(aux is not None):
            if(aux.adyacentes.inicio is not None):
                quitar_arista(aux.adyacentes, clave)
            aux = aux.sig
        # aca terminar eliminar aristas adyacenes grafo no dirigido
    return x

def quitar_arista(vertice, destino):
    x = None
    if(vertice.adyacentes.inicio.destino == destino):
        x = vertice.adyacentes.inicio.info
        vertice.adyacentes.inicio = vertice.adyacentes.inicio.sig
        vertice.adyacentes.tamanio -= 1
    else:
        ant = vertice.adyacentes.inicio
        act = vertice.adyacentes.inicio.sig
        while(act is not None and act.destino != destino):
            ant = act
            act = act.sig
        if (act is not None):
            x = act.info
            ant.sig = act.sig
            vertice.adyacentes.tamanio -= 1
    return x

def eliminar_arista(grafo, vertice, destino):
    """Elimina una arsita del vertice y lo devuelve si lo encuentra."""
    x = quitar_arista(vertice, destino)

    if(not grafo.dirigido):
        ori = buscar_vertice(grafo, destino)
        quitar_arista(ori, vertice.info)

    return x

def barrido_vertices(grafo):
    """Realiza un barrido de la grafo mostrando sus valores."""
    aux = grafo.inicio
    while(aux is not None):
        print('vertice:', aux.info)
        print('adyacentes:')
        adyacentes(aux)
        aux = aux.sig

def buscar_vertice(grafo, buscado):
    """Devuelve la direccion del elemento buscado."""
    aux = grafo.inicio
    while(aux is not None and aux.info != buscado):
        aux = aux.sig
    return aux

def buscar_arista(vertice, buscado):
    """Devuelve la direccion del elemento buscado."""
    aux = vertice.adyacentes.inicio
    while(aux is not None and aux.destino != buscado):
        aux = aux.sig
    return aux

def tamanio(grafo):
    """Devuelve el numero de vertices en el grafo."""
    return grafo.tamanio

def grafo_vacio(grafo):
    """Devuelve true si el grafo esta vacio."""
    return grafo.inicio is None

def adyacentes(vertice):
    """Muestra los adyacents del vertice."""
    aux = vertice.adyacentes.inicio
    while(aux is not None):
        print(aux.destino, aux.info)
        aux = aux.sig

def marcar_no_visitado(grafo):
    """Marca todos losvertices del grafo como no visitados."""
    aux = grafo.inicio
    while(aux is not None):
        aux.visitado = False
        aux = aux.sig

def barrido_profundidad(grafo, vertice):
    """Barrido en profundidad del grafo."""
    while(vertice is not None):
        if(not vertice.visitado):
            vertice.visitado = True
            print(vertice.info)
            adyacentes = vertice.adyacentes.inicio
            while(adyacentes is not None):
                adyacente = buscar_vertice(grafo, adyacentes.destino)
                if(not adyacente.visitado):
                    barrido_profundidad(grafo, adyacente)
                adyacentes = adyacentes.sig
        vertice = vertice.sig

def barrido_amplitud(grafo, vertice):
    """Barrido en amplitud del grafo."""
    cola = Cola()
    while(vertice is not None):
        if(not vertice.visitado):
            vertice.visitado = True
            arribo(cola, vertice)
            while(not cola_vacia(cola)):
                nodo = atencion(cola)
                print(nodo.info)
                adyacentes = nodo.adyacentes.inicio
                while(adyacentes is not None):
                    adyacente = buscar_vertice(grafo, adyacentes.destino)
                    if(not adyacente.visitado):
                        adyacente.visitado = True
                        arribo(cola, adyacente)
                    adyacentes = adyacentes.sig
        vertice = vertice.sig

def dijkstra(grafo, origen, destino):
    """Algoritmo de Dijkstra para hallar el camino mas corto."""
    no_visitados = Heap(tamanio(grafo))
    camino = Pila()
    aux = grafo.inicio
    while(aux is not None):
        if(aux.info == origen):
            arribo_h(no_visitados, [aux, None], 0)
        else:
            arribo_h(no_visitados, [aux, None], inf)
        aux = aux.sig

    while(not heap_vacio(no_visitados)):
        dato = atencion_h(no_visitados)
        apilar(camino, dato)
        aux = dato[1][0].adyacentes.inicio
        while(aux is not None):
            pos = buscar_h(no_visitados, aux.destino)
            if(no_visitados.vector[pos][0] > dato[0] + aux.info):
                no_visitados.vector[pos][1][1] = dato[1][0].info
                cambiar_prioridad(no_visitados, pos, dato[0] + aux.info)
            aux = aux.sig
    return camino

def prim(grafo):
    """Algoritmo de Prim para hallar el árbol de expansión mínimo."""
    bosque = []
    aristas = Heap(tamanio(grafo) ** 2)
    adyac = grafo.inicio.adyacentes.inicio
    while(adyac is not None):
        arribo_h(aristas, [grafo.inicio.info, adyac.destino], adyac.info)
        adyac = adyac.sig
    while(len(bosque) // 2 < tamanio(grafo) and not heap_vacio(aristas)):
        dato = atencion_h(aristas)
        if(len(bosque) == 0 or ((dato[1][0] not in bosque) ^ (dato[1][1] not in bosque))):
            bosque += dato[1]
            destino = buscar_vertice(grafo, dato[1][1])
            adyac = destino.adyacentes.inicio
            while(adyac is not None):
                arribo_h(aristas, [destino.info, adyac.destino], adyac.info)
                adyac = adyac.sig
    return bosque

def kruskal(grafo, tipo):
    """Algoritmo de Kruskal para hallar el árbol de expansión mínimo."""
    bosque = []
    aristas = Heap(tamanio(grafo) ** 2)
    aux = grafo.inicio
    while(aux is not None):
        if aux.datos[0] == tipo:
            bosque.append([aux.info])
            adyac = aux.adyacentes.inicio
            while(adyac is not None):
                arribo_h(aristas, [aux.info, adyac.destino], adyac.info)
                adyac = adyac.sig
            aux = aux.sig
        else:
            aux = aux.sig
    while(len(bosque) > 1 and not heap_vacio(aristas)):
        dato = atencion_h(aristas)
        origen = None
        for elemento in bosque:
            if(dato[1][0] in elemento):
                origen = bosque.pop(bosque.index(elemento))
                break
        destino = None
        for elemento in bosque:
            if(dato[1][1] in elemento):
                destino = bosque.pop(bosque.index(elemento))
                break
        if(origen is not None and destino is not None):
            if(len(origen) > 1 and len(destino) == 1):
                destino = [dato[1][0], dato[1][1]]
            elif(len(destino) > 1 and len(origen) == 1):
                origen = [dato[1][0], dato[1][1]]
            elif(len(destino) > 1 and len(origen) > 1):
                origen += [dato[1][0], dato[1][1]]
            bosque.append(origen + destino)
        else:
            bosque.append(origen)
    return bosque[0]

def existe_paso(grafo, origen, destino):
    """Barrido en profundidad del grafo."""
    resultado = False
    if(not origen.visitado):
        origen.visitado = True
        vadyacentes = origen.adyacentes.inicio
        while(vadyacentes is not None and not resultado):
            adyacente = buscar_vertice(grafo, vadyacentes.destino)
            if(adyacente.info == destino.info):
                return True
            elif(not adyacente.visitado):
                resultado = existe_paso(grafo, adyacente, destino)
            vadyacentes = vadyacentes.sig
    return resultado

def cantidad_maravilla(grafo, pais):
    cont_nat, cont_arq = 0, 0
    aux = grafo.inicio
    while (aux is not None):
        for p in aux.datos[1]:
            if p == pais:
                if aux.datos[0] == 'natural':
                    cont_nat += 1
                else:
                    cont_arq += 1
        aux = aux.sig
    return cont_nat, cont_arq

def maravillas_tipo(grafo, pais):
    naturales, arquitectonicas = cantidad_maravilla(grafo, pais)
    if naturales > 0 and arquitectonicas > 0:
        print("El pais " + pais + " tiene maravilla natural y arquitectonica")
    else:
        print("El pais " + pais + " no posee maravilla natural y arquitectonica")

def maravilla_mismo_tipo(grafo, pais):
    naturales, arquitectonicas = cantidad_maravilla(grafo, pais)
    if naturales > 1:
        print("El pais " + pais + " tiene mas de una maravillas naturales")
    elif arquitectonicas > 1:
        print("El pais " + pais + " tiene mas de una maravillas arquitectonicas")
    else:
        print("El pais " + pais + " no posse mas de una maravilla del mismo tipo")

g = Grafo(False)

maravillas = [
    ['Bahía de Ha Long', ['natural', ['Vietnam']]],
    ['Isla de Komodo', ['natural', ['Indonesia']]],
    ['Río subterráneo de Puerto Princesa', ['natural', ['Filipinas']]],
    ['Montaña de la Mesa', ['natural', ['Sudáfrica']]],
    ['Cataratas del Iguazú', ['natural', ['Argentina', 'Brasil']]],
    ['Río Amazonas', ['natural', ['Perú', 'Colombia', 'Brasil']]],
    ['Isla Jeju', ['natural', ['Corea del Sur']]],
    ['Chichén Itzá', ['arquitectonica', ['México']]],
    ['Coliseo de Roma', ['arquitectonica', ['Italia']]],
    ['Cristo Redentor', ['arquitectonica', ['Brasil']]],
    ['Muralla China', ['arquitectonica', ['China']]],
    ['Machu Picchu', ['arquitectonica', ['Perú']]],
    ['Petra', ['arquitectonica', ['Jordania']]],
    ['Taj Mahal', ['arquitectonica', ['India']]],
]

for m in maravillas:
    insertar_vertice(g, m[0], m[1])

for i in maravillas:
    ori = buscar_vertice(g, i[0])
    for j in maravillas:
        des = buscar_vertice(g, j[0])
        buscar = buscar_arista(ori, des.info)
        if(ori.info != des.info and ori.datos[0] == des.datos[0] and buscar is None):
            insertar_arista(g, randint(50, 150), ori, des)

barrido_vertices(g)

print()
print('kruskal')
bosque = kruskal(g, 'natural')
for i in range(0,len(bosque),2):
    print (bosque[i], bosque[i+1])

print()
print('kruskal')
bosque = kruskal(g, 'arquitectonica')
for i in range(0,len(bosque),2):
    print (bosque[i], bosque[i+1])

print()
maravillas_tipo(g, "Brasil")
print()
maravilla_mismo_tipo(g, "Brasil")

print()
maravillas_tipo(g, "Argentina")
print()
maravilla_mismo_tipo(g, "Argentina")


import os
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
from model import VAE

CUDA = torch.cuda.is_available()
device = torch.device("cuda" if CUDA else "cpu")
print(device)

def loss_fn(output, mu, log_var):
    kl_divergence = 0.5*torch.sum(-1-log_var+mu**2+log_var.exp())
    return F.binary_cross_entropy(output, size_average=False) + kl_divergence

def train_per_epoch(train_loader, model, loss_fn, optimizer, show_pred_result=False):
    # for one epoch, multiple batches
    model.train()   # assure Dropout, BatchNormalization... layers open in training step

    train_loss = 0
    true_rlt = []
    pred_rlt = []

    for batch_idx, (data, label) in enumerate(train_loader):
        if CUDA:
            data, label = data.cuda(), label.cuda()

        # reset previous gradient
        optimizer.zero_grad()

        # forward pass
        output, mu, log_var = model(data)
        loss_fn.cuda()  # if loss function have parameter, we need to add .cuda
        loss = loss_fn(output, mu, log_var)

        # compute gradient
        loss.backward()
        # update parameters
        optimizer.step()

        # compute train_loss (KL divergence)

    return train_loss

def predict_per_epoch(test_loader, model, loss_fn, optimizer, show_pred_result=False):
    # for one epoch, multiple batches
    model.eval()   # assure Dropout, BatchNormalization... layers open in training step

    pred_loss = 0
    true_rlt = []
    pred_rlt = []

    with torch.no_grad():
        for batch_idx, (data, label) in enumerate(test_loader):
            if CUDA:
                data, label = data.cuda(), label.cuda()

            # reset previous gradient
            optimizer.zero_grad()

            # forward pass
            output, mu, log_var = model(data)
            loss_fn.cuda()  # if loss function have parameter, we need to add .cuda
            loss = loss_fn(output, mu, log_var)

            # compute pred_loss (KL divergence)

    return pred_loss

##
batch_size = 128
learning_rate = 1e-3
num_epochs = 20
latent_dim = 20

train_loader = torch.utils.data.DataLoader(
    datasets.MNIST('data', train=True, download=True,
                    transform=transforms.ToTensor()),
    batch_size=batch_size, shuffle=True
)

test_loader = torch.utils.data.DataLoader(
    datasets.MNIST('data', train=False, transform=transforms.ToTensor()),
    batch_size=1, shuffle=False
)

model = VAE(latent_dim).to(device)

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

loss_fn = nn.KLDivLoss()

for epoch in range(num_epochs):
    train_per_epoch(train_loader, model, loss_fn, optimizer, show_pred_result=False)
    predict_per_epoch(test_loader, model, loss_fn, optimizer, show_pred_result=False)


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

import numpy as np
import ann

def find_optimal_model(parameters, val_errors, weight):

    # Compute model generalization error for each model s
    gen_errors = np.zeros(shape=(len(parameters)))
    for index in range(len(parameters)):
        p = parameters[index]

        errors = val_errors[:,index]

        gen_errors[index] =sum(weight*errors)

    # Find and select optimal model
    index = gen_errors.argmin()
    optimal_parameter = parameters[index]

    return optimal_parameter

    # gen_errors = np.zeros(shape=(len(hidden_units)))

    # for index in range(len(hidden_units)):
    #     h = hidden_units[index]

    #     errors = ann_val_errors[i,:,index]

    #     gen_error = (len(test_index2)/len(train_index1))*errors
    #     gen_errors[index] = gen_error.sum()

    # # Find and select optimal model
    # index = gen_errors.argmin()
    # optimal_hidden_units = hidden_units[index]