# ---------------------------------------------------------------
# transformer_croattn_relcaption_head.py
# Set-up time: 2021/3/11 10:39
# Copyright (c) 2020 ICT
# Licensed under The MIT License [see LICENSE for details]
# Written by Kenneth-Wong (Wenbin-Wang) @ VIPL.ICT
# Contact: wenbin.wang@vipl.ict.ac.cn [OR] nkwangwenbin@gmail.com
# ---------------------------------------------------------------

from ..registry import HEADS
import torch
import torch.nn as nn
import torch.nn.functional as F
from .. import builder
from ..losses import accuracy
from mmdet.datasets import build_dataset
import numpy as np
import mmcv

from .relational_caption_head import RelationalCaptionHead
from mmdet.models.captioners.utils import LowRankBilinearEncBlock, LowRankBilinearDecBlock, FeedForwardBlock
from mmdet.models.captioners.utils import activation, expand_tensor, decode_sequence
import nltk
import copy
import math
from .approaches import MultiHeadedAttention, PositionalEncoding, PositionwiseFeedForward, EncoderDecoder, Encoder, \
    EncoderLayer, Decoder, DecoderLayer, Embeddings, Generator, subsequent_mask

@HEADS.register_module
class TransformerCrossAttnRelationalCaptionHead(RelationalCaptionHead):
    def __init__(self, **kwargs):
        super(TransformerCrossAttnRelationalCaptionHead, self).__init__(**kwargs)

        self.att_dim = self.attention_feat_config.att_feats_embed_dim \
            if self.attention_feat_config.att_feats_embed_dim > 0 else self.attention_feat_config.att_feats_dim

        # union feat embed
        sequential = []
        if self.union_feat_config.union_feats_embed_dim > 0:
            sequential.append(
                nn.Linear(self.union_feat_config.union_feats_dim + self.union_feat_config.union_spatial_dim,
                          self.union_feat_config.union_feats_embed_dim))
        sequential.append(activation(self.union_feat_config.union_feats_embed_act,
                                     elu_alpha=self.captioner_config.elu_alpha))
        if self.union_feat_config.dropout_union_embed > 0:
            sequential.append(nn.Dropout(self.union_feat_config.dropout_union_embed))
        if self.union_feat_config.union_feats_norm:
            sequential.append(torch.nn.LayerNorm(self.union_feat_config.union_feats_embed_dim))
        self.union_embed = nn.Sequential(*sequential) if len(sequential) > 0 else None

        # attention feats embed
        sequential = []
        if self.attention_feat_config.att_feats_embed_dim > 0:
            sequential.append(nn.Linear(self.attention_feat_config.att_feats_dim,
                                        self.attention_feat_config.att_feats_embed_dim))
        sequential.append(activation(self.attention_feat_config.att_feats_embed_act,
                                     elu_alpha=self.captioner_config.elu_alpha))
        if self.attention_feat_config.dropout_att_embed > 0:
            sequential.append(nn.Dropout(self.attention_feat_config.dropout_att_embed))
        if self.attention_feat_config.att_feats_norm:
            sequential.append(torch.nn.LayerNorm(self.attention_feat_config.att_feats_embed_dim))
        self.att_embed = nn.Sequential(*sequential) if len(sequential) > 0 else None

        # encoder-decoder
        self.N_enc = self.captioner_config.N_enc
        self.N_dec = self.captioner_config.N_dec
        self.d_model = self.captioner_config.input_encoding_size  # 512
        self.d_ff = self.captioner_config.d_ff  # 512
        self.h = self.captioner_config.num_att_heads
        self.dropout = self.captioner_config.dropout  # 0.1

        self.model = self.make_model(0, self.vocab_size,
                                     N_enc=self.N_enc,
                                     N_dec=self.N_dec,
                                     d_model=self.d_model,
                                     d_ff=self.d_ff,
                                     h=self.h,
                                     dropout=self.dropout)

        # ipt estmiate
        if self.cross_attn:
            self.gather_attention = self.head_config.gather_attention
            self.ipt_estimate = self.head_config.ipt_estimate
            self.mask_obj_word = self.head_config.mask_obj_word
            self.soft_supervised = self.head_config.soft_supervised

            ipt_estm_dim = 512
            if self.ipt_estimate == 'so':
                input_dim = self.attention_feat_config.att_feats_embed_dim * 2
            elif self.ipt_estimate == 'sou':
                input_dim = self.attention_feat_config.att_feats_embed_dim * 2 + self.union_feat_config.union_feats_embed_dim
            elif self.ipt_estimate == 'u':
                input_dim = self.union_feat_config.union_feats_embed_dim
            elif self.ipt_estimate == 'sous':
                input_dim = self.attention_feat_config.att_feats_embed_dim * 2 \
                            + self.union_feat_config.union_feats_embed_dim + \
                            self.union_feat_config.union_feats_semantic_dim * 2
                self.semantic_embedding = nn.Embedding(self.num_classes,
                                                       self.union_feat_config.union_feats_semantic_dim)
            else:
                raise NotImplementedError
            self.global_feat_embed = nn.Sequential(*[
                nn.Linear(self.attention_feat_config.att_feats_embed_dim, ipt_estm_dim),
                activation('CeLU'),
                nn.Dropout(0.5),
                nn.LayerNorm(ipt_estm_dim)])
            self.local_feat_embed = nn.Sequential(*[nn.Linear(input_dim, ipt_estm_dim),
                                                    activation('CeLU'),
                                                    nn.Dropout(0.5),
                                                    nn.LayerNorm(ipt_estm_dim)])

            self.attn_loss_weight = self.head_config.attn_loss_weight

    def make_model(self, src_vocab, tgt_vocab, N_enc=6, N_dec=6,
                   d_model=512, d_ff=2048, h=8, dropout=0.1):
        "Helper: Construct a model from hyperparameters."
        c = copy.deepcopy
        attn = MultiHeadedAttention(h, d_model, dropout)
        ff = PositionwiseFeedForward(d_model, d_ff, dropout)
        position = PositionalEncoding(d_model, dropout)
        model = EncoderDecoder(
            Encoder(EncoderLayer(d_model, c(attn), c(ff), dropout), N_enc),
            Decoder(DecoderLayer(d_model, c(attn), c(attn),
                                 c(ff), dropout), N_dec),
            lambda x: x,
            nn.Sequential(Embeddings(d_model, tgt_vocab), c(position)),
            Generator(d_model, tgt_vocab))

        # This was important from their code.
        # Initialize parameters with Glorot / fan_avg.
        for p in model.parameters():
            if p.dim() > 1:
                nn.init.xavier_uniform_(p)
        return model

    def padded_att(self, roi_feats, num_rois):
        bs = len(num_rois)
        max_num = max(num_rois)
        num_atts = torch.LongTensor(num_rois).to(roi_feats.device)
        split_roi_feats = roi_feats.split(num_rois)
        padded_att_feats = torch.zeros(bs, max_num, roi_feats.size(-1)).to(roi_feats)
        for i in range(bs):
            padded_att_feats[i, :num_rois[i], :] = split_roi_feats[i][:, :]
        att_mask = torch.arange(0, max_num, device=roi_feats.device).long().unsqueeze(0).expand(bs, max_num).lt(
            num_atts.unsqueeze(1)).long()
        return padded_att_feats, att_mask

    def gather_att_region(self, padded_feats, num_rois, dim):
        return padded_feats.split(num_rois, dim=dim)

    def preproj_feats(self, roi_feats, union_feats):
        return self.att_embed(roi_feats), self.union_embed(union_feats)

    def preprocess_seq(self, input_seq, target_seq):
        # process the input_seq, target_seq for training
        input_seq = input_seq.view(-1, input_seq.size(-1))
        target_seq = target_seq.view(-1, target_seq.size(-1))
        seq_mask = (input_seq > 0).long()
        seq_mask[:, 0] += 1
        seq_mask_sum = seq_mask.sum(-1)
        max_len = int(seq_mask_sum.max())
        input_seq = input_seq[:, 0:max_len].contiguous()
        target_seq = target_seq[:, 0:max_len].contiguous()
        seq_mask = seq_mask[:, 0:max_len].contiguous()

        seq_mask = seq_mask.unsqueeze(-2)
        seq_mask = seq_mask & subsequent_mask(input_seq.size(-1)).to(seq_mask)
        return input_seq, target_seq, seq_mask

    def get_logprobs_state(self, state, wt, p_att_feats, att_mask):
        if len(state) == 0:
            ys = wt.unsqueeze(1)
        else:
            ys = torch.cat([state[0][0], wt.unsqueeze(1)], dim=1)
        out = self.model.decode(p_att_feats, att_mask, ys, subsequent_mask(ys.size(1)).to(p_att_feats.device))
        # use the last region-word atttention (ie, src attention) of the last decoder layer in the decoder, average
        # over the multi-heads (dimension 1),
        # the first time step: attn is 1 * num_head * 1 * num_region
        # the t time step: attn is 1 * num_head * t * num_region
        alpha = self.model.decoder.layers[-1].src_attn.attn.mean(1)[:, -1]
        return F.log_softmax(self.model.generator(out[:, -1])), [ys.unsqueeze(0)], alpha

    def init_cap_hidden(self, batch_size, device):
        return []

    def forward(self,
                img,
                img_meta,
                det_result,
                gt_result=None,
                is_testing=False,
                beam_size=3):
        """
        Obtain the relation prediction results based on detection results.
        Args:
            img (Tensor): of shape (N, C, H, W) encoding input images.
                Typically these should be mean centered and std scaled.

            img_meta (list[dict]): list of image info dict where each dict has:
                'img_shape', 'scale_factor', 'flip', and may also contain
                'filename', 'ori_shape', 'pad_shape', and 'img_norm_cfg'.
                For details on the values of these keys see
                `mmdet/datasets/pipelines/formatting.py:Collect`.
            det_result: (Result): Result containing bbox, label, mask, point, rels,
                etc. According to different mode, all the contents have been
                set correctly. Feel free to  use it.
            gt_result : (Result): The ground truth information.
            is_testing:

        Returns:
            det_result with the following newly added keys:
                refine_scores (list[Tensor]): logits of object
                rel_scores (list[Tensor]): logits of relation
                rel_pair_idxes (list[Tensor]): (num_rel, 2) index of subject and object
                relmaps (list[Tensor]): (num_obj, num_obj):
                target_rel_labels (list[Tensor]): the target relation label.
        """
        # roi_feats: N * 4,096; union_feats: N * 512
        roi_feats, union_feats, det_result = self.frontend_features(img, det_result, gt_result)
        if roi_feats.shape[0] == 0:
            return det_result

        num_rels = [r.shape[0] for r in det_result.rel_pair_idxes]
        num_objs = [len(b) for b in det_result.bboxes]

        num_images = img[0].size(0)
        assert num_images == len(det_result.rel_pair_idxes)
        rel_pair_index = []
        acc_obj = 0
        for i, num_obj in enumerate(num_objs):
            rel_pair_idx_i = det_result.rel_pair_idxes[i].clone()
            rel_pair_idx_i[:, 0] += acc_obj
            rel_pair_idx_i[:, 1] += acc_obj
            acc_obj += num_obj
            rel_pair_index.append(rel_pair_idx_i)
        rel_pair_index = torch.cat(rel_pair_index, 0)

        # pre encode: 512
        roi_feats, union_feats = self.preproj_feats(roi_feats, union_feats)

        # get global feats:
        split_roi_feats = roi_feats.detach().split(num_objs)
        if self.cross_attn:
            global_feats = []
            for i, srf in enumerate(split_roi_feats):
                global_feats += [self.global_feat_embed(torch.mean(srf, dim=0, keepdim=True))] * num_rels[i]
            global_feats = torch.cat(global_feats)

        # captioning part
        if self.with_caption:
            # padded feats and forward the encoder: each single roi
            padded_att_feats, att_mask = self.padded_att(roi_feats, num_objs)
            att_mask = att_mask.unsqueeze(-2)

            # training or val:
            if not is_testing:
                # training: each image have 5 captions, expand the visual features
                padded_att_feats = expand_tensor(padded_att_feats, self.seq_per_img)
                att_mask = expand_tensor(att_mask, self.seq_per_img)
                batch_size = padded_att_feats.size(0)

                cap_inputs, cap_targets = gt_result.cap_inputs, gt_result.cap_targets
                cap_inputs = torch.stack(cap_inputs)
                cap_targets = torch.stack(cap_targets)
                cap_inputs, cap_targets, seq_mask = self.preprocess_seq(cap_inputs, cap_targets)
                gt_result.cap_inputs = cap_inputs
                gt_result.cap_targets = cap_targets
                det_result.cap_targets = cap_targets
                out = self.model(padded_att_feats, cap_inputs, att_mask, seq_mask)
                cap_scores = self.model.generator(out)
                alphas = self.model.decoder.layers[-1].src_attn.attn.mean(1)  # do not need softmax
                det_result.cap_scores = cap_scores
            else:
                # beam search
                batch_size = padded_att_feats.size(0)
                # encode:
                memory = self.model.encode(padded_att_feats, att_mask)
                outputs, log_probs, alphas = self.decode_beam(beam_size, batch_size, padded_att_feats.device,
                                                              self.get_logprobs_state,
                                                              p_att_feats=memory,
                                                              att_mask=att_mask)
                det_result.cap_seqs = outputs
                det_result.cap_scores = log_probs

        # Relational Captioning Part
        if self.with_relcaption:
            roi_subj_feats, roi_obj_feats = roi_feats[rel_pair_index[:, 0], :], roi_feats[rel_pair_index[:, 1], :]
            # here the triplet features are used as the att feats in captions

            triplet_att_feats = torch.stack((roi_subj_feats, roi_obj_feats, union_feats), 1)  # N, 3, D
            batch_size = triplet_att_feats.size(0)
            num_rois = [3] * batch_size
            num_atts = torch.LongTensor(num_rois).to(triplet_att_feats.device)
            triplet_att_mask = torch.arange(0, 3, device=triplet_att_feats.device).long().unsqueeze(0).expand(
                batch_size, 3).lt(
                num_atts.unsqueeze(1)).long()
            triplet_att_mask = triplet_att_mask.unsqueeze(-2)

            if not is_testing:
                tgt_rel_inputs, tgt_rel_targets, tgt_rel_ipts = det_result.tgt_rel_cap_inputs, det_result.tgt_rel_cap_targets, det_result.tgt_rel_ipts
                tgt_rel_inputs = torch.cat(tgt_rel_inputs, 0)
                tgt_rel_targets = torch.cat(tgt_rel_targets, 0)

                assert tgt_rel_inputs is not None and tgt_rel_targets is not None
                tgt_rel_inputs, tgt_rel_targets, rel_seq_mask = self.preprocess_seq(tgt_rel_inputs, tgt_rel_targets)
                det_result.tgt_rel_cap_inputs = tgt_rel_inputs
                det_result.tgt_rel_cap_targets = tgt_rel_targets

                out = self.model(triplet_att_feats, tgt_rel_inputs, triplet_att_mask, rel_seq_mask)
                rel_cap_scores = self.model.generator(out)
                det_result.rel_cap_scores = rel_cap_scores

            else:
                # beam search
                # encode:
                triplet_memory = self.model.encode(triplet_att_feats, triplet_att_mask)
                outputs, log_probs, _ = self.decode_beam(beam_size, batch_size, roi_subj_feats.device,
                                                         self.get_logprobs_state,
                                                         att_mask=triplet_att_mask,
                                                         p_att_feats=triplet_memory)
                det_result.rel_cap_scores = log_probs
                det_result.rel_cap_seqs = outputs

        # cross attention part
        if self.cross_attn:
            assert self.with_caption and self.with_relcaption, 'No captioner! or no relational captioner!'

            # use the last hidden state to evaluate the rel_ipt_score:
            if self.ipt_estimate == 'so':
                ipt_estm_feats = torch.cat((roi_subj_feats.detach(), roi_obj_feats.detach()), -1)
            elif self.ipt_estimate == 'sou':
                ipt_estm_feats = torch.cat((roi_subj_feats.detach(), roi_obj_feats.detach(), union_feats.detach()), -1)
            elif self.ipt_estimate == 'u':
                ipt_estm_feats = union_feats.detach()
            elif self.ipt_estimate == 'sous':
                if self.mode == 'predcls':
                    labels = det_result.labels
                    if isinstance(labels, (list, tuple)):
                        labels = torch.cat(labels, 0)
                    else:
                        labels = labels.view(-1)
                    dist = torch.zeros(labels.size(0), self.num_classes).to(labels.device)
                    dist[torch.arange(labels.size(0)).to(dist.device).long(), labels] = 1
                else:
                    dist = torch.cat(det_result.dist, 0)
                semantic_feats = dist @ self.semantic_embedding.weight
                roi_subj_sem_feats, roi_obj_sem_feats = semantic_feats[rel_pair_index[:, 0], :], \
                                                        semantic_feats[rel_pair_index[:, 1]]
                ipt_estm_feats = torch.cat((roi_subj_feats.detach(), roi_obj_feats.detach(),
                                            union_feats.detach(), roi_subj_sem_feats, roi_obj_sem_feats), -1)
            else:
                raise NotImplementedError
            ipt_estm_feats = self.local_feat_embed(ipt_estm_feats)
            factor = np.sqrt(ipt_estm_feats.size(1))
            rel_ipt_scores = torch.sum(torch.mul(ipt_estm_feats, global_feats), -1) / factor
            rel_ipt_scores = rel_ipt_scores.split(num_rels)

            det_result.rel_ipt_scores = rel_ipt_scores

            if self.soft_supervised:
                # randomly select one caption and use its attention
                batch_size = alphas.size(0)  # (5B) * T * Nr (train/val) or 1 * T * Nr (test)
                att_mask = att_mask.squeeze(-2)
                num_img = batch_size // self.seq_per_img if not is_testing else batch_size
                if not is_testing:
                    sel_idx = torch.from_numpy(
                        np.arange(num_img, dtype=int) * self.seq_per_img +
                        np.random.randint(self.seq_per_img, size=num_img)).to(alphas.device).long()
                    alphas = alphas[sel_idx, :]  # B * T * Nr
                    att_mask = att_mask[sel_idx, :]  # B * Nr

                # generate the timestep mask:
                timestep_mask = torch.zeros(num_img, alphas.size(1), 1).to(att_mask)  # B * T * 1
                cap_sentences = decode_sequence(self.vocab, det_result.cap_targets[sel_idx, :]) if not is_testing \
                    else decode_sequence(self.vocab, det_result.cap_seqs)  # B * MAXT
                for i, sent in enumerate(cap_sentences):
                    tokens = sent.split(' ')  # do not use tokenize
                    if self.mask_obj_word:
                        tags = nltk.pos_tag(tokens)
                        for j, (word, tag) in enumerate(tags):
                            if tag in ['NN', 'NNS', 'NNP', 'NNPS']:
                                timestep_mask[i, j, :] = 1
                        if torch.sum(timestep_mask[i]) == 0:
                            timestep_mask[i, :len(tokens)] = 1
                    else:
                        timestep_mask[i, :len(tokens)] = 1

                alphas = alphas * timestep_mask
                # collect this info for visualization
                det_result.word_obj_distribution = alphas

                if self.gather_attention == 'mean':
                    alphas = torch.sum(alphas, dim=1) / torch.sum(timestep_mask, dim=1)
                elif self.gather_attention == 'max':
                    alphas = torch.max(alphas, dim=1)[0]
                else:
                    raise NotImplementedError

                if not is_testing:
                    # perform softmax again and got the final object-wise attention
                    alphas = alphas.masked_fill(att_mask == 0,
                                                -1e9)  # put a large negative value, so that the exp() is almost 0
                # collect this info for visualization
                det_result.obj_distribution = F.softmax(alphas, dim=-1)

                # use the rel pair idx to construct the pair attention
                rel_pair_idxes = det_result.rel_pair_idxes
                alphas_pairs = []
                for i, rel_pair_idx in enumerate(rel_pair_idxes):
                    alphas_pairs.append(
                        F.softmax(alphas[i, rel_pair_idx[:, 0]] + alphas[i, rel_pair_idx[:, 1]], dim=-1))

                det_result.rel_distribution = alphas_pairs
            else:
                if not is_testing:
                    det_result.rel_distribution = tgt_rel_ipts
                else:
                    det_result.rel_distribution = None

        return det_result


# make sure you're logged in with `huggingface-cli login`
import os
from pathlib import Path

from diffusers import StableDiffusionPipeline

token = os.environ.get("HUGGING_FACE_TOKEN")
output_dir = Path("./artefacts")
output_dir.mkdir(parents=True,exist_ok=True)
output_dir = output_dir.resolve().absolute()

pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", use_auth_token=token)
pipe = pipe.to("mps")

prompt = "a hamster is cleaning the floor with a broom"

# First-time "warmup" pass (see explanation above)
_ = pipe(prompt, num_inference_steps=1)

# Results match those from the CPU device after the warmup pass.
images = pipe(prompt).images
for i,image in enumerate(images):
    prompt_combined = prompt.replace(" ","_")
    output_dir_string = str(output_dir)
    image.save(f"{output_dir_string}/{prompt_combined}_{i}.png")


from tkinter import *
from func import *
from fileFunc import *
from navFunc import *

# Atribuindo à variável screen a tela do tkinter
screen = Tk()

# Titulo da tela
screen.title("Formulário Python")

# Tamanho da tela
screen.geometry('700x500')
screen.configure(bg='white')
screen.resizable(False, False)

# Configurando um cabeçalho
heading = Label(screen, text='Formulário Python', fg='#6E326B',
                height='2', font=("Roboto", "20", "bold"), bg='white')
heading.pack()

# Tela de cadastro do usuário
register_screen = Frame(screen)
register_screen.configure(bg='white')

# Tela de usuários do sistema
users_screen = Frame(screen)
users_screen.configure(bg='white')

# Tela inicial
home = Frame(screen)
home.configure(bg='white')

delete_screen = Frame(screen)
delete_screen.configure(bg='white')

# Botão cadastrar da tela inicial
user_register = Button(home, text="Cadastrar usuário",  width='30',
                       bg='white', fg='#6E326B', bd=3, font=("Roboto", "14", "bold"), command=load_register_screen)
user_register.place(x=163, y=10)

# Botão, para procurar usuários, da tela inicial
system_users = Button(home, text="Usuários do sistema",  width='30',
                      bg='white', fg='#6E326B', bd=3, font=("Roboto", "14", "bold"), command=load_users_screen)
system_users.place(x=163, y=80)

# Botão, para procurar usuários, da tela inicial
delete_users = Button(home, text="Remover usuários",  width='30',
                      bg='white', fg='#6E326B', bd=3, font=("Roboto", "14", "bold"), command=load_delete_screen)
delete_users.place(x=163, y=150)

# Label com os textos das variáveis
name_text = Label(register_screen, text='Nome', bd='1', bg='white',
                  fg='#6E326B', font=("Roboto", "11"))
cpf_text = Label(register_screen, text='CPF', bd='1', bg='white',
                 fg='#6E326B', font=("Roboto", "11"))
registration_text = Label(register_screen, text='Matrícula', bd='1',
                          bg='white', fg='#6E326B', font=("Roboto", "11"))
birth_date_text = Label(register_screen, text='Data de nascimento',
                        bd='1', bg='white', fg='#6E326B', font=("Roboto", "11"))

# Posicionando as Labels com place, x afasta da lateral e y do topo
name_text.place(x=80, y=30)
cpf_text.place(x=370, y=30)
registration_text.place(x=80, y=140)
birth_date_text.place(x=370, y=140)

# Variáveis (com seus tipos) para armazenamento dos dados das entradas
name = StringVar(register_screen)
cpf = StringVar(register_screen)
registration = StringVar(register_screen)
birth_date = StringVar(register_screen)

# Recebendo as entradas e armazenando nas variáveis
name_entry = Entry(register_screen, textvariable=name, width='28',
                   bg='#D461CE', fg='white', bd=1, font='14')
cpf_entry = Entry(register_screen, textvariable=cpf, width='28', bg='#D461CE',
                  fg='white', bd=1, font='14')
registration_entry = Entry(register_screen, textvariable=registration,
                           width='28', bg='#D461CE', fg='white', bd=1, font='14')
birth_date_entry = Entry(register_screen, textvariable=birth_date,
                         width='28', bg='#D461CE', fg='white', bd=1, font='14')

# Posicionando as entradas
name_entry.place(x=82, y=55, height='60')
cpf_entry.place(x=372, y=55, height='60')
registration_entry.place(x=82, y=165, height='60')
birth_date_entry.place(x=372, y=165, height='60')

# Botão para registrar as entradas
register = Button(register_screen, text='Cadastrar',
                  width='40', bg='white', fg='#6E326B', cursor="hand2", command=save_info, bd=2)
register.place(x=208, y=255, height='40')

# Botão para voltar para a tela inicial
button_home(register_screen, back_to_home)
button_home(users_screen, back_to_home)
button_home(delete_screen, back_to_home)

# Inicia o programa chamando a tela inicial
home.pack(fill="both", expand=True)
screen.mainloop()


import csv
import os
import itertools
import ast
import pandas as pd
from sklearn.metrics.pairwise import pairwise_distances
import pickle
from sklearn import metrics
import numpy as np

# similarity based (noaudio)
# popular rec (pop)
# greatest artist (sagh)
# collocation artist (cagh) - similarity based (noaudio - artist-level)

# What's missing in here.
# similarity based (audio) - should be matched with mixset sequencing
# audio based EDM artist classifier (feature) similarity based vs Rachel's shortest path

# read sequencing.csv
playlists = {}
with open('sequencing.csv', mode='r') as infile:
    reader = csv.DictReader(infile)
    for row in reader:
        data = dict(row)
        playlist_id = data['id']
        tracks_in_playlist = ast.literal_eval(data['track_id'])
        playlists[playlist_id] = tracks_in_playlist

print(len(playlists))

tracks = playlists.values()
seed_list = [x[0] for x in tracks]
tracks = list(itertools.chain(*tracks))
tracks = list(set(tracks))
print(len(playlists))
print(len(tracks))
print(seed_list)
print(len(seed_list))

# total songs / binary matrix
df = pd.concat([pd.Series(v, name=k).astype(str) for k, v in playlists.items()], axis=1)
df = pd.get_dummies(df.stack()).sum(level=1).clip_upper(1)
print(df.shape)

# replace playlist index to the first item id of playlists
org_list = df.index.tolist()
df = df.rename(index=dict(zip(org_list,seed_list)))

print(df.head())
# for cagh, artist level playlist sim mat
# co-occur hammming distance similarity matrix (songXsong)
jac_sim = 1 - pairwise_distances(df.T, metric = "hamming")
# optionally convert it to a DataFrame
jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
print(jac_sim.shape)
print(jac_sim.head)
store = pd.HDFStore('jac_sim.h5')
store['jac_sim'] = jac_sim
store.close()

# greatest artist pop_seed
# read track_sub, find matching artist - artist-track dictionary - set used artist's tracks to 1 similarity score followed by popularity ranking
artist_to_track = {}
track_to_artist = {}
with open('track_subsub.csv', mode='r') as infile:
    reader = csv.DictReader(infile)
    for row in reader:
        data = dict(row)
        track_id = data['track_id']
        artist_id = data['artist_id']
        artist_to_track.setdefault(artist_id, []).append(track_id)
        track_to_artist[track_id] = artist_id

# sim mat based ranking for each seed (up to 300, 50 interval?) / df: ground truth
# AUC and mAP
jac_sim = pd.read_hdf('jac_sim.h5')

# set diagonal term to 0 to avoid self recommendation
jac_sim.values[[np.arange(jac_sim.shape[0])]*2] = 0

# set groundtruth self to 0
for i,row in df.iterrows():
    df.set_value(i, i, 0)
print(df.head())

# popularity based
pops = df.sum(axis=0) # np.max(pop_seed) = 32
pop_seed = pops.values

auc_noaudio = []
auc_pop = []
auc_sagh = []
for iter in range(len(seed_list)):
    # ground truth
    gt_seed = df.iloc[iter,:].values

    # jaccard similarity based
    noaudio_seed = jac_sim.loc[seed_list[iter],:].values

    # greatest artist pop seed
    seed_artist_tracks = artist_to_track[track_to_artist[seed_list[iter]]]
    sagh = pops.copy()
    for iter2 in range(len(seed_artist_tracks)):
        if seed_artist_tracks[iter2] in sagh.index:
            sagh.loc[seed_artist_tracks[iter2]] = 100 * sagh.loc[seed_artist_tracks[iter2]] # 100 * previous values
        else:
            continue
    sagh_seed = sagh.values

    auc_noaudio_seed = metrics.roc_auc_score(gt_seed,noaudio_seed)
    auc_noaudio.append(auc_noaudio_seed)
    print('auc_noaudio: ', np.mean(np.asarray(auc_noaudio)))

    auc_pop_seed = metrics.roc_auc_score(gt_seed,pop_seed)
    auc_pop.append(auc_pop_seed)
    print('auc_pop: ', np.mean(np.asarray(auc_pop)))

    auc_sagh_seed = metrics.roc_auc_score(gt_seed,sagh_seed)
    auc_sagh.append(auc_sagh_seed)
    print('auc_sagh: ', np.mean(np.asarray(auc_sagh)))


from sympy import *
from IPython.display import display, Latex
import control.matlab as ml

def printer(var_name, var_value, unit):
     return display(Latex("${name} = {var:.4f}\ {unit}$".format(var=var_value,name=var_name,unit=unit)))

# Approximation for Eckfreq for PT1 TF #
def find_eckfreq_PT1(mag,omega):
    index = 0

    for i in ml.mag2db(mag):
        if i <= (max(ml.mag2db(mag))-3):
            display(Latex(f"""$$\\text{{at index: }} {index}$$
                                $$\\text{{mag is: }} {ml.mag2db(mag[index])}\ dB$$
                                $$\\text{{freq is: }} {omega[index]}\ Hz$$"""))
            break
        index+=1
    return index, ml.mag2db(mag[index]), omega[index]

# Approximation for Eckfreq for PT2 TF #
def find_eckfreq_PT2(tf):
    eck = sqrt(tf.pole()[1]*tf.pole()[0]).evalf()
    return display(Latex("$\\omega_0 = {eck:.4f}\ 1/s$".format(eck=eck)))

# Analyzes TF and gets Eckfreq D and K parameters #
def analyze_tf(tf):
    den = tf.den[0][0]
    num = tf.num[0][0]
    if len(den) == 3:
        type_ = "PT2"
        if den[0] == 1:
            omega_calc = sqrt(den[2])
            daempfung = den[1]/(omega_calc*2)
        else:
            vorfaktor = den[0]
            omega_calc = sqrt(den[2]/vorfaktor)
            daempfung = den[1]/(omega_calc*2)
        if len(num) == 1:
            K = num[0]/omega_calc**2
        return omega_calc, K, daempfung

    if len(den) == 2:
        type_ = "PT1"
        daempfung = None
        if den[1] == 1:
            omega_calc = 1/(den[0])
        else:
            vorfaktor = den[1]
            omega_calc = 1/(den[1]/vorfaktor)
        if len(num) == 1:
            K = num[0]
        return omega_calc, K
    # printer("\\omega_0", omega_calc, "1/s")
    # return {
    #         type_:
    #             {
    #                 "omega_0":omega_calc,
    #                 "D":daempfung,
    #                 "K":K
    #             }
    #         }


"""
homeassistant.components.sensor.forecast
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Forecast.io weather service.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.forecast/
"""
import logging
from datetime import timedelta

from homeassistant.util import Throttle
from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS)
from homeassistant.helpers.entity import Entity

REQUIREMENTS = ['python-forecastio==1.3.3']
_LOGGER = logging.getLogger(__name__)

# Sensor types are defined like so:
# Name, si unit, us unit, ca unit, uk unit, uk2 unit
SENSOR_TYPES = {
    'summary': ['Summary', '', '', '', '', ''],
    'icon': ['Icon', '', '', '', '', ''],
    'nearest_storm_distance': ['Nearest Storm Distance',
                               'km', 'm', 'km', 'km', 'm'],
    'nearest_storm_bearing': ['Nearest Storm Bearing',
                              '°', '°', '°', '°', '°'],
    'precip_type': ['Precip', '', '', '', '', ''],
    'precip_intensity': ['Precip Intensity', 'mm', 'in', 'mm', 'mm', 'mm'],
    'precip_probability': ['Precip Probability', '%', '%', '%', '%', '%'],
    'temperature': ['Temperature', '°C', '°F', '°C', '°C', '°C'],
    'apparent_temperature': ['Apparent Temperature',
                             '°C', '°F', '°C', '°C', '°C'],
    'dew_point': ['Dew point', '°C', '°F', '°C', '°C', '°C'],
    'wind_speed': ['Wind Speed', 'm/s', 'mph', 'km/h', 'mph', 'mph'],
    'wind_bearing': ['Wind Bearing', '°', '°', '°', '°', '°'],
    'cloud_cover': ['Cloud Coverage', '%', '%', '%', '%', '%'],
    'humidity': ['Humidity', '%', '%', '%', '%', '%'],
    'pressure': ['Pressure', 'mBar', 'mBar', 'mBar', 'mBar', 'mBar'],
    'visibility': ['Visibility', 'km', 'm', 'km', 'km', 'm'],
    'ozone': ['Ozone', 'DU', 'DU', 'DU', 'DU', 'DU'],
}

# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=120)

def setup_platform(hass, config, add_devices, discovery_info=None):
    """ Get the Forecast.io sensor. """
    import forecastio

    if None in (hass.config.latitude, hass.config.longitude):
        _LOGGER.error("Latitude or longitude not set in Home Assistant config")
        return False

    try:
        forecast = forecastio.load_forecast(config.get(CONF_API_KEY, None),
                                            hass.config.latitude,
                                            hass.config.longitude)
        forecast.currently()
    except ValueError:
        _LOGGER.error(
            "Connection error "
            "Please check your settings for Forecast.io.")
        return False

    if 'units' in config:
        units = config['units']
    elif hass.config.temperature_unit == TEMP_CELCIUS:
        units = 'si'
    else:
        units = 'us'

    data = ForeCastData(config.get(CONF_API_KEY, None),
                        hass.config.latitude,
                        hass.config.longitude,
                        units)

    dev = []
    for variable in config['monitored_conditions']:
        if variable not in SENSOR_TYPES:
            _LOGGER.error('Sensor type: "%s" does not exist', variable)
        else:
            dev.append(ForeCastSensor(data, variable))

    add_devices(dev)

# pylint: disable=too-few-public-methods
class ForeCastSensor(Entity):
    """ Implements an Forecast.io sensor. """

    def __init__(self, weather_data, sensor_type):
        self.client_name = 'Weather'
        self._name = SENSOR_TYPES[sensor_type][0]
        self.forecast_client = weather_data
        self.type = sensor_type
        self._state = None
        self._unit_system = self.forecast_client.unit_system
        if self._unit_system == 'si':
            self._unit_of_measurement = SENSOR_TYPES[self.type][1]
        elif self._unit_system == 'us':
            self._unit_of_measurement = SENSOR_TYPES[self.type][2]
        elif self._unit_system == 'ca':
            self._unit_of_measurement = SENSOR_TYPES[self.type][3]
        elif self._unit_system == 'uk':
            self._unit_of_measurement = SENSOR_TYPES[self.type][4]
        elif self._unit_system == 'uk2':
            self._unit_of_measurement = SENSOR_TYPES[self.type][5]
        self.update()

    @property
    def name(self):
        return '{} {}'.format(self.client_name, self._name)

    @property
    def state(self):
        """ Returns the state of the device. """
        return self._state

    @property
    def unit_of_measurement(self):
        """ Unit of measurement of this entity, if any. """
        return self._unit_of_measurement

    @property
    def unit_system(self):
        """ Unit system of this entity. """
        return self._unit_system

    # pylint: disable=too-many-branches
    def update(self):
        """ Gets the latest data from Forecast.io and updates the states. """
        import forecastio

        self.forecast_client.update()
        data = self.forecast_client.data

        try:
            if self.type == 'summary':
                self._state = data.summary
            elif self.type == 'icon':
                self._state = data.icon
            elif self.type == 'nearest_storm_distance':
                self._state = data.nearestStormDistance
            elif self.type == 'nearest_storm_bearing':
                self._state = data.nearestStormBearing
            elif self.type == 'precip_intensity':
                self._state = data.precipIntensity
            elif self.type == 'precip_type':
                self._state = data.precipType
            elif self.type == 'precip_probability':
                self._state = round(data.precipProbability * 100, 1)
            elif self.type == 'dew_point':
                self._state = round(data.dewPoint, 1)
            elif self.type == 'temperature':
                self._state = round(data.temperature, 1)
            elif self.type == 'apparent_temperature':
                self._state = round(data.apparentTemperature, 1)
            elif self.type == 'wind_speed':
                self._state = data.windSpeed
            elif self.type == 'wind_bearing':
                self._state = data.windBearing
            elif self.type == 'cloud_cover':
                self._state = round(data.cloudCover * 100, 1)
            elif self.type == 'humidity':
                self._state = round(data.humidity * 100, 1)
            elif self.type == 'pressure':
                self._state = round(data.pressure, 1)
            elif self.type == 'visibility':
                self._state = data.visibility
            elif self.type == 'ozone':
                self._state = round(data.ozone, 1)

        except forecastio.utils.PropertyUnavailable:
            pass

class ForeCastData(object):
    """ Gets the latest data from Forecast.io. """

    def __init__(self, api_key, latitude, longitude, units):
        self._api_key = api_key
        self.latitude = latitude
        self.longitude = longitude
        self.data = None
        self.unit_system = None
        self.units = units
        self.update()

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self):
        """ Gets the latest data from Forecast.io. """
        import forecastio

        forecast = forecastio.load_forecast(self._api_key,
                                            self.latitude,
                                            self.longitude,
                                            units=self.units)
        self.data = forecast.currently()
        self.unit_system = forecast.json['flags']['units']


from copy import deepcopy

import torch
import torch.nn as nn
from torch.nn.parallel.distributed import _find_tensors

from ..builder import MODELS, build_module
from ..common import set_requires_grad
from .base_gan import BaseGAN

# _SUPPORT_METHODS_ = ['DCGAN', 'STYLEGANv2']

# @MODELS.register_module(_SUPPORT_METHODS_)
@MODELS.register_module()
class StaticUnconditionalGAN(BaseGAN):
    """Unconditional GANs with static architecture in training.

    This is the standard GAN model containing standard adversarial training
    schedule. To fulfill the requirements of various GAN algorithms,
    ``disc_auxiliary_loss`` and ``gen_auxiliary_loss`` are provided to
    customize auxiliary losses, e.g., gradient penalty loss, and discriminator
    shift loss. In addition, ``train_cfg`` and ``test_cfg`` aims at setuping
    training schedule.

    Args:
        generator (dict): Config for generator.
        discriminator (dict): Config for discriminator.
        gan_loss (dict): Config for generative adversarial loss.
        disc_auxiliary_loss (dict): Config for auxiliary loss to
            discriminator.
        gen_auxiliary_loss (dict | None, optional): Config for auxiliary loss
            to generator. Defaults to None.
        train_cfg (dict | None, optional): Config for training schedule.
            Defaults to None.
        test_cfg (dict | None, optional): Config for testing schedule. Defaults
            to None.
    """

    def __init__(self,
                 generator,
                 discriminator,
                 gan_loss,
                 disc_auxiliary_loss=None,
                 gen_auxiliary_loss=None,
                 train_cfg=None,
                 test_cfg=None):
        """ 最基礎的GAN模型
        Args:
            generator: 生成器相關配置設定
            discriminator: 鑑別器相關配置設定
            gan_loss: 損失計算相關配置設定
            disc_auxiliary_loss: 鑑別器的輔助訓練設定
            gen_auxiliary_loss: 生成器的輔助訓練設定
            train_cfg: 訓練模式下的流程設定
            test_cfg: 測試模式下的流程設定
        """
        # 繼承自BaseGAN，對繼承對象進行初始化
        super().__init__()
        # 深拷貝一份生成器的config資料到self當中
        self._gen_cfg = deepcopy(generator)
        # 實例化生成器實例對象
        self.generator = build_module(generator)

        # 在驗證模式下可以不用指定鑑別器，因為我們也不會需要用到
        # support no discriminator in testing
        if discriminator is not None:
            # 實例化鑑別器實例對象
            self.discriminator = build_module(discriminator)
        else:
            # 如果沒有指定配置文件就會是None
            self.discriminator = None

        # support no gan_loss in testing
        # 在測試模式下可以不用構建損失計算方式
        if gan_loss is not None:
            # 如果有指定損失計算方式就會到這裡進行實例化
            self.gan_loss = build_module(gan_loss)
        else:
            # 如果沒有指定就會是None
            self.gan_loss = None

        if disc_auxiliary_loss:
            # 如果有使用鑑別器輔助訓練就會到這裡進行實例化
            self.disc_auxiliary_losses = build_module(disc_auxiliary_loss)
            if not isinstance(self.disc_auxiliary_losses, nn.ModuleList):
                # 因為輔助方始可能會有多個，所以會用ModuleList進行包裝
                self.disc_auxiliary_losses = nn.ModuleList(
                    [self.disc_auxiliary_losses])
        else:
            # 如果沒有指定就會設定成None
            self.disc_auxiliary_loss = None

        if gen_auxiliary_loss:
            # 如果有使用生成器輔助訓練就會到這裡進行實例化
            self.gen_auxiliary_losses = build_module(gen_auxiliary_loss)
            if not isinstance(self.gen_auxiliary_losses, nn.ModuleList):
                # 因為輔助方始可能會有多個，所以會用ModuleList進行包裝
                self.gen_auxiliary_losses = nn.ModuleList([self.gen_auxiliary_losses])
        else:
            # 如果沒有指定就會設定成None
            self.gen_auxiliary_losses = None

        # 拷貝train以及test的config資料
        self.train_cfg = deepcopy(train_cfg) if train_cfg else None
        self.test_cfg = deepcopy(test_cfg) if test_cfg else None

        # 解析train_cfg資料
        self._parse_train_cfg()
        if test_cfg is not None:
            # 如果有設定test_cfg就進行解析
            self._parse_test_cfg()

    def _parse_train_cfg(self):
        """Parsing train config and set some attributes for training."""
        # 解析train_cfg當中資料
        if self.train_cfg is None:
            # 如果train_cfg是None就構建一個空的dict
            self.train_cfg = dict()
        # control the work flow in train step
        # 獲取train_cfg當中的disc_steps資料，如果沒有就是預設為1
        self.disc_steps = self.train_cfg.get('disc_steps', 1)

        # whether to use exponential moving average for training
        # 獲取train_cfg當中的use_ema資料，如果沒有就會是False
        self.use_ema = self.train_cfg.get('use_ema', False)
        if self.use_ema:
            # 如果使用ema就會到這裡
            # use deepcopy to guarantee the consistency
            self.generator_ema = deepcopy(self.generator)

        # 獲取real_img_key資料
        self.real_img_key = self.train_cfg.get('real_img_key', 'real_img')

    def _parse_test_cfg(self):
        """Parsing test config and set some attributes for testing."""
        if self.test_cfg is None:
            self.test_cfg = dict()

        # basic testing information
        self.batch_size = self.test_cfg.get('batch_size', 1)

        # whether to use exponential moving average for testing
        self.use_ema = self.test_cfg.get('use_ema', False)
        # TODO: finish ema part

    def train_step(self,
                   data_batch,
                   optimizer,
                   ddp_reducer=None,
                   loss_scaler=None,
                   use_apex_amp=False,
                   running_status=None):
        """Train step function.

        This function implements the standard training iteration for
        asynchronous adversarial training. Namely, in each iteration, we first
        update discriminator and then compute loss for generator with the newly
        updated discriminator.

        As for distributed training, we use the ``reducer`` from ddp to
        synchronize the necessary params in current computational graph.

        Args:
            data_batch (dict): Input data from dataloader.
            optimizer (dict): Dict contains optimizer for generator and
                discriminator.
            ddp_reducer (:obj:`Reducer` | None, optional): Reducer from ddp.
                It is used to prepare for ``backward()`` in ddp. Defaults to
                None.
            loss_scaler (:obj:`torch.cuda.amp.GradScaler` | None, optional):
                The loss/gradient scaler used for auto mixed-precision
                training. Defaults to ``None``.
            use_apex_amp (bool, optional). Whether to use apex.amp. Defaults to
                ``False``.
            running_status (dict | None, optional): Contains necessary basic
                information for training, e.g., iteration number. Defaults to
                None.

        Returns:
            dict: Contains 'log_vars', 'num_samples', and 'results'.
        """
        # get data from data_batch
        # 獲取真實圖像資料，tensor shape [batch_size, channel, height, width]
        real_imgs = data_batch[self.real_img_key]
        # If you adopt ddp, this batch size is local batch size for each GPU.
        # If you adopt dp, this batch size is the global batch size as usual.
        # 獲取圖像的batch_size
        batch_size = real_imgs.shape[0]

        # get running status
        if running_status is not None:
            # 如果有傳入running_status就會獲取當前是第幾個batch
            curr_iter = running_status['iteration']
        else:
            # 如果沒有給定running_status就自己瞎搞一個
            # dirty walk round for not providing running status
            if not hasattr(self, 'iteration'):
                self.iteration = 0
            curr_iter = self.iteration

        # disc training
        # 將self.discriminator的反向傳遞開啟
        set_requires_grad(self.discriminator, True)
        # 將鑑別器的優化器進行反向清空
        optimizer['discriminator'].zero_grad()
        # TODO: add noise sampler to customize noise sampling

        # pass model specific training kwargs
        # 保存生成器的相關參數
        g_training_kwargs = {}
        if hasattr(self.generator, 'get_training_kwargs'):
            # 如果在generator當中有get_training_kwargs就會到這裡，將資料放到g_training_kwargs當中
            g_training_kwargs.update(self.generator.get_training_kwargs(phase='disc'))

        with torch.no_grad():
            # 進行生成圖像，這裡會將反向傳遞進行關閉，fake_imgs = tensor shape [batch_size, channel, height, width]
            fake_imgs = self.generator(None, num_batches=batch_size, **g_training_kwargs)

        # disc pred for fake imgs and real_imgs
        # 將假的圖像放到鑑別器模型當中進行正向推理，disc_pred_fake = tensor shape [batch_size, channel=1]
        disc_pred_fake = self.discriminator(fake_imgs)
        # 將資料集的圖像放到鑑別器當中進行正向推理，disc_pred_real = tensor shape [batch_size, channel=1]
        disc_pred_real = self.discriminator(real_imgs)
        # get data dict to compute losses for disc
        # 構建一個data_dict_用來計算損失用的
        data_dict_ = dict(
            # 將生成器模型
            gen=self.generator,
            # 將鑑別器模型
            disc=self.discriminator,
            # 預測生成圖結果資料
            disc_pred_fake=disc_pred_fake,
            # 預測真實圖結果資料
            disc_pred_real=disc_pred_real,
            # 假圖資料
            fake_imgs=fake_imgs,
            # 真圖資料
            real_imgs=real_imgs,
            # 當前是第幾個batch
            iteration=curr_iter,
            # batch大小
            batch_size=batch_size,
            loss_scaler=loss_scaler)

        # 將data_dict_傳入進行計算損失值
        # loss_disc = 損失總和，tensor float
        # log_vars_disc = 個別損失資料，dict
        loss_disc, log_vars_disc = self._get_disc_loss(data_dict_)

        # prepare for backward in ddp. If you do not call this function before
        # back propagation, the ddp will not dynamically find the used params
        # in current computation.
        if ddp_reducer is not None:
            # 準備進行反向傳遞，在使用分布式訓練時會需要的動作
            ddp_reducer.prepare_for_backward(_find_tensors(loss_disc))

        if loss_scaler:
            # add support for fp16
            loss_scaler.scale(loss_disc).backward()
        elif use_apex_amp:
            from apex import amp
            with amp.scale_loss(
                    loss_disc, optimizer['discriminator'],
                    loss_id=0) as scaled_loss_disc:
                scaled_loss_disc.backward()
        else:
            # 進行loss反向傳遞
            loss_disc.backward()

        if loss_scaler:
            loss_scaler.unscale_(optimizer['discriminator'])
            # note that we do not contain clip_grad procedure
            loss_scaler.step(optimizer['discriminator'])
            # loss_scaler.update will be called in runner.train()
        else:
            # 將優化器進行step操作，到這裡就算將鑑別器進行一次訓練
            optimizer['discriminator'].step()

        # skip generator training if only train discriminator for current iteration
        if (curr_iter + 1) % self.disc_steps != 0:
            # 可以透過設定disc_steps讓某幾個batch只會訓練鑑別器
            # 構建results，裡面就會有創建的假圖以及真圖
            results = dict(fake_imgs=fake_imgs.cpu(), real_imgs=real_imgs.cpu())
            # 構建最終回傳的資料
            outputs = dict(
                log_vars=log_vars_disc,
                num_samples=batch_size,
                results=results)
            if hasattr(self, 'iteration'):
                # 將iteration加一
                self.iteration += 1
            # 最終回傳結果
            return outputs

        # generator training
        # 將鑑別器的反向傳遞關閉
        set_requires_grad(self.discriminator, False)
        # 將生成器的優化器反向傳遞值進行清空
        optimizer['generator'].zero_grad()

        # TODO: add noise sampler to customize noise sampling

        # pass model specific training kwargs
        g_training_kwargs = {}
        if hasattr(self.generator, 'get_training_kwargs'):
            # 如果generator當中有get_trainging_kwargs就會存到g_training_kwargs當中
            g_training_kwargs.update(self.generator.get_training_kwargs(phase='gen'))

        # 透過generator創造出假圖，tensor shape [batch_size, channel, height, width]
        fake_imgs = self.generator(None, num_batches=batch_size, **g_training_kwargs)
        # 對假圖進行預測
        disc_pred_fake_g = self.discriminator(fake_imgs)

        # 構建計算損失需要使用的字典
        data_dict_ = dict(
            # 生成器模型
            gen=self.generator,
            # 鑑別器模型
            disc=self.discriminator,
            # 假圖資料
            fake_imgs=fake_imgs,
            # 鑑別器辨識結果
            disc_pred_fake_g=disc_pred_fake_g,
            # 當前第幾個batch
            iteration=curr_iter,
            # batch大小
            batch_size=batch_size,
            loss_scaler=loss_scaler)

        # 進行損失計算
        loss_gen, log_vars_g = self._get_gen_loss(data_dict_)

        # prepare for backward in ddp. If you do not call this function before
        # back propagation, the ddp will not dynamically find the used params
        # in current computation.
        if ddp_reducer is not None:
            # 如果在分布式訓練上會需要
            ddp_reducer.prepare_for_backward(_find_tensors(loss_gen))

        if loss_scaler:
            loss_scaler.scale(loss_gen).backward()
        elif use_apex_amp:
            from apex import amp
            with amp.scale_loss(
                    loss_gen, optimizer['generator'],
                    loss_id=1) as scaled_loss_disc:
                scaled_loss_disc.backward()
        else:
            # 進行損失的反向傳遞
            loss_gen.backward()

        if loss_scaler:
            loss_scaler.unscale_(optimizer['generator'])
            # note that we do not contain clip_grad procedure
            loss_scaler.step(optimizer['generator'])
            # loss_scaler.update will be called in runner.train()
        else:
            # 透過優化器進行權重更新
            optimizer['generator'].step()

        # update ada p
        if hasattr(self.discriminator, 'with_ada') and self.discriminator.with_ada:
            # 如果discriminator有with_ada就會到這裡
            self.discriminator.ada_aug.log_buffer[0] += batch_size
            self.discriminator.ada_aug.log_buffer[1] += disc_pred_real.sign().sum()
            self.discriminator.ada_aug.update(iteration=curr_iter, num_batches=batch_size)
            log_vars_disc['augment'] = (self.discriminator.ada_aug.aug_pipeline.p.data.cpu())

        # 構建log所需的字典
        log_vars = {}
        # 生成器的損失資訊
        log_vars.update(log_vars_g)
        # 鑑別器的損失資訊
        log_vars.update(log_vars_disc)

        # 最終的results資訊，這裡會有假圖以及真圖的資訊
        results = dict(fake_imgs=fake_imgs.cpu(), real_imgs=real_imgs.cpu())
        # 將資料用dict包裝其來放到outputs當中
        outputs = dict(log_vars=log_vars, num_samples=batch_size, results=results)

        if hasattr(self, 'iteration'):
            # 更新iteration
            self.iteration += 1
        # 回傳outputs
        return outputs


#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the chocolateFeast function below.
def chocolateFeast(n, c, m):
    # n = budget;
    # c = chocolate cost
    # m = the number of wrapper
    ans=0;
    ans+= n//c
    p = ans;
    while p//m != 0:
        a= p // m;
        b= p % m;
        p= a+b;
        ans+= a;

    return ans;

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    t = int(input())

    for t_itr in range(t):
        ncm = input().split()

        n = int(ncm[0])

        c = int(ncm[1])

        m = int(ncm[2])

        result = chocolateFeast(n, c, m)

        fptr.write(str(result) + '\n')

    fptr.close()


import tensorflow as tf

tf.app.flags.DEFINE_string("job_name",
                           "worker",
                           "ps or worker")
tf.app.flags.DEFINE_integer("task_index",
                            0,
                            "task index within a job")
tf.app.flags.DEFINE_string("ps_hosts",
                           "localhost:50001",
                           "ps list like 'localhost:50001,localhost:50002'")
tf.app.flags.DEFINE_string("worker_hosts",
                           "localhost:60001,localhost:60002",
                           "worker list like 'localhost:60001,localhost:60002'")
FLAGS = tf.app.flags.FLAGS

def main(_):
    ps_hosts = FLAGS.ps_hosts.split(',')
    worker_hosts = FLAGS.worker_hosts.split(',')
    cluster = tf.train.ClusterSpec({
        "ps": ps_hosts,
        "worker": worker_hosts})
    server = tf.train.Server(cluster,
                             job_name=FLAGS.job_name,
                             task_index=FLAGS.task_index)
    server.join()

if __name__ == "__main__":
    tf.app.run()


import turtle as t
from random import randint, choice

# STARRY NIGHT
# we will have a "night theme" -> dark background color
# we are going to have multiple stars in the sky
# 4 differences between the stars: points / color / size / position
t.bgcolor("dark blue")

def star(points, color, size):
    t.speed(6000)
    t.color(color)
    t.begin_fill()

    for i in range(points):
        t.forward(size)
        t.right(180-(180/points))
    t.end_fill()

#we want to make an infinite loop that each time (each iteration),
# draws one star with a random color, a random size, a random points and a random position

while True:
    #geenrade a random odd number for the variable points
    rand_points = randint(3, 6) * 2 + 1

    colors_list = ["red", "orange","hot pink", "pink", "seashell","white","green", "yellow", "light blue", "light green"]
    #generate a random color
    rand_color = choice(colors_list)

    #generate a random size (30-60)
    rand_size = randint(30,60)

    #generate a random position (a random x(-300,300), and a random y(-300,300) )
    rand_x= randint(-300,300)
    rand_y= randint(-300,300)

    #tell the turtle to go to the random position you generated
    t.penup()
    t.goto(rand_x, rand_y)
    t.pendown()

    #call the functionn star() with the  random arguments that you just generated

    star(rand_points, rand_color, rand_size)


# -*- coding: utf-8 -*-
"""
Created on Tue Nov 26 19:58:52 2019

@author: Mark
"""

in_file = 'entries/agëëm.json'

def main():
    with open(in_file, 'rb') as f:
        for line in f:
            print(line.decode('unicode_escape'))

if __name__ == '__main__':
    main()


import torch
import onmt
from onmt.Utils import use_gpu

SRC_TMP = ""
TRG_TMP = ""

def load_model(opt):
    checkpoint = torch.load(opt.model, map_location=lambda storage, loc: storage)
    fields = onmt.IO.load_fields(checkpoint['vocab'])
    model_opt = checkpoint['opt']

    model = onmt.ModelConstructor.make_base_model(
                                model_opt, fields, use_gpu(opt), checkpoint)
    return model, fields

def load_batch(fields, opt):
    data = onmt.IO.ONMTDataset(
        TRG_TMP, SRC_TMP, fields,
        use_filter_pred=False)

    data_iter = onmt.IO.OrderedIterator(
        dataset=data, device=opt.gpu,
        batch_size=opt.batch_size * opt.n_best, shuffle=False, repeat=False)

    for batch in data_iter:
        return batch


#Name: Russell Sammut-Bonnici
#ID: 0426299(M)
#Task: 1

import random #used for choosing random pivot

#class for storing pair's details
class Pair:

    #initialises product pair
    def __init__(self,a,b):
        self.a = a
        self.b = b
        self.product = a*b

#recursive method for sorting pairs by products
def sortByProduct(objList):

    #base case for when segment's length is less than or equal to one
    if(len(objList)<=1):
        return objList

    smaller=[] #initialized for storing the smaller segment of the list
    equivalent=[] #initialized for storing the element at the pivot
    greater=[] #initialized for storing the greater segment of the list

    #randomly chosen pivot selected from list of pairs
    pivot = objList[random.randint(0,len(objList)-1)]

    #for loop to go through the list of pairs
    for x in objList:

        #when x is less, append to smaller segment
        if(x.product < pivot.product):
            smaller.append(x)

        #when x is at the pivot, store element into equivalent
        elif(x.product==pivot.product):
            equivalent.append(x)

        #when x is greater, append to greater segment
        elif(x.product > pivot.product):
            greater.append(x)

        else:
            print("An unknown error has occurred during sorting by Product")

    #recursively calls method to work on the smaller and greater segment, then returns on backtracking
    return sortByProduct(smaller) + equivalent + sortByProduct(greater)

#method for finding product matches
def findProductMatches(rangeList):

    pairList = [] #initialized for storing products pairs and their components

    # outer loop for a equivalent
    for x in rangeList:

        # inner loop for b equivalent
        for y in rangeList:

            if(y>x): #condition to avoid repeated a*b combinations
                pairList.append(Pair(x,y))

    pairList = sortByProduct(pairList) #sorts by product using quick sort

    i = 0 #initialized index to 0

    #goes through every index in the pairList array
    while(i<len(pairList)):

        #Accesses this during the last iteration when the last index has no matching products. Avoids OutOfIndex exception, iterates to exit loop
        if(i==len(pairList)-1):
            i+=1

        #If pair at index has a unique product, skips cause no matches
        elif(pairList[i].product != pairList[i+1].product):
            i+=1

        #If current pair is seen to have at least one match, access while loop
        elif(pairList[i].product == pairList[i+1].product):

            print("The pair [%d*%d = %d] matches with"%(pairList[i].a, pairList[i].b, pairList[i].product)),

            #traverses through products, displaying the matches until there are no more (stops when at the end)
            while(i!=len(pairList)-1 and pairList[i].product == pairList[i+1].product):
                print("[%d*%d = %d] and"%(pairList[i+1].a, pairList[i+1].b, pairList[i+1].product)),
                i+=1

            print(",") #prints comma indicating end of line

        #else statement used for unconsidered scenarios
        else:
            print("Error: something wrong has occurred during printing.")

    return 0

print("Matching products from 1 to 1024 are;")
findProductMatches(range(1, 1025)) #or (range(1,26))


#
# LED Voltage Drop Calculator
# 04-14-2023 10:56
# PeetHobby @PeetGaming
#

# Inputs
led_voltage_in = float(input("Enter the LED voltage (in volts): "))
num_leds = int(input("Enter the number of LEDs in series: "))
supply_voltage = float(input("Enter the power supply voltage (in volts): "))
led_current = float(input("Enter the desired LED current (in milliamps): "))

# Calculations
led_voltage = num_leds * led_voltage_in
resistor_value = (supply_voltage - led_voltage) / (led_current / 1000) # Drop resistor vales
resistor_power = (supply_voltage - led_voltage) * (led_current / 1000) # Power disipation in resistor
led_power = led_voltage * (led_current / 1000) # Power consumption of the led

# Results
print("")
print(f"For {num_leds} x {led_voltage_in}V LED(s) with a {supply_voltage}V power supply and the desired {led_current}mA current, you need to use a {round(resistor_value)} ohm resistor.")
print(f"The resistor will dissipate {round(resistor_power, 3)} mW of power.")
print(f"The voltage drop across the resistor will be {round(supply_voltage - led_voltage, 2)}V.")
print(f"The {num_leds} x LED(s) will consume a total of {round(led_power, 3)} mW of power.")


from src import util
from src import eval
import numpy as np
import pyflux as pf

if __name__ == '__main__':

    p = 4
    q = 4
    h_test = 6

    ts, data = util.load_data("../data/NSW2013.csv", columnName="TOTALDEMAND")
    # ts, data = util.load_data("../data/bike_hour.csv", columnName="cnt")
    # ts, data = util.load_data("../data/TAS2016.csv", columnName="TOTALDEMAND")
    # ts, data = util.load_data("../data/traffic_data_in_bits.csv", columnName="value")
    # ts, data = util.load_data("../data/beijing_pm25.csv", columnName="pm2.5")
    # ts, data = util.load_data("../data/pollution.csv", columnName="Ozone")

    train, test = util.divideTrainTest(data)
    # train = train[:1000]
    # test = test[:14]
    print("train shape is", train.shape)
    print("test shape is", test.shape)
    history = [x[0] for x in train]
    predictions = []
    realTestY = []

    for t in range(len(test) - h_test):

        model = pf.ARIMA(data=np.array(history), ar=p, ma=q, family=pf.Normal())
        model.fit(method="MLE")

        output = model.predict(h_test, intervals=False)

        yhat = output.values.flatten().tolist()

        obs = test[t : t + h_test].flatten()

        realTestY.append(obs)
        predictions.append(yhat)
        history.extend(test[t])
        print("t:", t+1)
        print("predict:", yhat)
        print('expected:', obs)

    realTestY = np.array(realTestY).reshape(-1, h_test)
    predictions = np.array(predictions).reshape(-1, h_test)
    MAE = eval.calcMAE(realTestY, predictions)
    RMSE = eval.calcRMSE(realTestY, predictions)
    MAPE = eval.calcSMAPE(realTestY, predictions)
    print('Test MAE: %.8f' % MAE)
    print('Test RMSE: %.8f' % RMSE)
    print('Test SMAPE: %.8f' % MAPE)

    # plot
    # pyplot.plot(test)
    # pyplot.plot(predictions, color='red')
    # pyplot.show()


import game_of_life_interface
import numpy as np
import matplotlib.pyplot as plt

class GameOfLife(game_of_life_interface.GameOfLife):  # This is the way you construct a class that heritage properties

    def __init__ (self, size_of_board, board_start_mode, rules, rle, pattern_position) :  # constructor
        # declare and initialize variables
        self.size_of_board = size_of_board
        self.board_start_mode = board_start_mode
        self.board = np.zeros ((size_of_board, size_of_board))
        self.rules = rules
        self.B = list (map (int, rules.split ("/") [ 0 ] [ 1 : ]))
        self.S = list (map (int, rules.split ("/") [ 1 ] [ 1 : ]))
        self.pattern_position = pattern_position
        self.rle = rle
        self.alive = 255
        self.dead = 0
        if board_start_mode == 1 and self.rle == "" :

            self.board = np.random.choice ([ 0, 255 ], (size_of_board, size_of_board), p=[ 0.5, 0.5 ]).reshape (
                self.size_of_board, self.size_of_board)
        elif board_start_mode == 2 and self.rle == "" :
            self.board = np.random.choice ([ 255, 0 ], (size_of_board, size_of_board), p=[ 0.8, 0.2 ]).reshape (
                self.size_of_board, self.size_of_board)

        elif board_start_mode == 3 and self.rle == "" :
            self.board = np.random.choice ([ 0, 255 ], (size_of_board, size_of_board), p=[ 0.2, 0.8 ]).reshape (
                self.size_of_board, self.size_of_board)

        elif board_start_mode == 4 and self.rle == "" :  # glider gun board
            self.board = np.zeros ((self.size_of_board, self.size_of_board), dtype=int)
            self.board [ 14, 11 ] = 255
            self.board [ 15, 11 ] = 255
            self.board [ 14, 10 ] = 255
            self.board [ 15, 10 ] = 255
            self.board [ 14, 20 ] = 255
            self.board [ 15, 20 ] = 255
            self.board [ 16, 20 ] = 255
            self.board [ 13, 21 ] = 255
            self.board [ 17, 21 ] = 255
            self.board [ 12, 22 ] = 255
            self.board [ 18, 22 ] = 255
            self.board [ 12, 23 ] = 255
            self.board [ 18, 23 ] = 255
            self.board [ 15, 24 ] = 255
            self.board [ 13, 25 ] = 255
            self.board [ 17, 25 ] = 255
            self.board [ 14 :17, 26 ] = 255
            self.board [ 15, 27 ] = 255
            self.board [ 12 :15, 30 ] = 255
            self.board [ 12 :15, 31 ] = 255
            self.board [ 11, 32 ] = 255
            self.board [ 15, 32 ] = 255
            self.board [ 10 :12, 34 ] = 255
            self.board [ 15 :17, 34 ] = 255
            self.board [ 12 :14, 44 ] = 255
            self.board [ 12 :14, 45 ] = 255
        else :
            self.transform_rle_to_matrix (self.rle)
    def if_check (self, k, m, board) :#checks the index in some board insert returns true or false
        return 1 if board [ k ] [ m ] == self.alive else 0
    def check_neighbours (self,i, j,current_board) :#checks the neighbors val according to the rules
        count = 0
        size = self.size_of_board
        count = count + self.if_check((i - 1) % size, (j - 1) % size,current_board)  # left-upper1
        count = count + self.if_check((i - 1) % size, j,current_board )  # upper1
        count = count + self.if_check((i - 1) % size, (j + 1) % size,current_board)  # right-upper1
        count = count + self.if_check(i , (j - 1) % size,current_board)  # left1
        count = count + self.if_check(i, (j + 1) % size,current_board)  # right1
        count = count + self.if_check((i + 1) % size, (j - 1) % size,current_board)  # left-down1
        count = count + self.if_check((i + 1) % size, j,current_board)  # down1
        count = count + self.if_check((i + 1) % size, (j + 1) % size,current_board)  # right down1
        if (current_board[i][j]==0 and count in self.B) or (current_board[i][j]==255 and count in self.S):
            return True
        else:
            return False
    def copy_board(self):#this function makes a deep copy of a board
        list_to_ret = []
        for i in range (self.size_of_board) :
            temp_list = []
            for j in range (self.size_of_board) :
                temp_list.append(self.board[i][j])
            list_to_ret.append(temp_list)
        return list_to_ret
    def update(self): # update the board based on given rules
        current_board = self.copy_board()
        for i in range(self.size_of_board):
            for j in range(self.size_of_board):
                if self.check_neighbours(i,j,current_board) == True:
                    self.board[i][j] = self.alive # 255
                else:
                    self.board[i][j] = self.dead # 0

        #  wrote many lines to update ,but changed it according to study about modulo.
        #RuleBook - Main interface for game rules
#GOLRuleBook - Regular Game of Life rules implementing RuleBook
#Cell - An interface for a living organism :) Which lives or dies according to the rules in rulebook. A cell can answer are you alive question.
#AliveCell - Represents a living cell
#DeadCell - Represents a dead cell
#Board - The game world. Holds all the cells, and their locations. Can tell each cells number of neighbours.
#Player - The player of the game. Player is just responsible for generation change of the board.
#CellFactory - Responsible for cell creation (Gives the same instance for all the alive cells, and gives the same instance for all the dead cells)
#Populator - Cell generators
#StrLoadingPopulator - Load initial cells from new line delimited string such as [A D A]\n[D D D]
#RandomPopulator - Given number of rows and number of columns randomly generate cells
#Main - Main class. Number of rows, number of columns and number of generations are collecte

    def transform_rle_to_matrix (self, rle) :#this function goes threw the list of rle on the insert and describes it on the board

        z, w = self.pattern_position  # position tupple for w,z axis
        space = ""
        self.board = [ [ 0 for i in range (self.size_of_board) ] for j in range (self.size_of_board) ]

        for i in rle :
            if i != "!" :
                if i != "$" :
                    if str (i).isdigit ( ) :
                        space += i
                    if i == "o" :
                        if space == "" :
                            space = 1
                        for j in range (w, w + int (space)) :
                            self.board [ z ] [ j ] = self.alive
                        w = w + int (space)
                        space = ""
                    if i == "b" :
                        if space == "" :
                            space = 1
                        for j in range (w, w + int (space)) :
                            self.board [ z ] [ j ] = self.dead
                        w = w + int (space)
                        space = ""
                else :
                    if space == "" :
                        space = 1
                    z = z + int (space)
                    space = ""
                    w = self.pattern_position [ 1 ]

        # initialize board based on starting position
    def save_board_to_file(self, file_name):#this function saves the board files each iteration
        plt.imsave(file_name, self.board)
    def display_board(self):#this function make a display of the board
       plt.imshow(self.board)
       plt.pause(0.0001)
    def return_board (self): #this function returns a list of the board position after checking if it is a list
        if type(self.board)==list:
            return self.board
        else:
            return self.board.tolist ( )

if __name__ == '__main__':
    # You should keep this line for our auto-grading code.
    # game = GameOfLife(120 , 4,"b3/s23","","")
    game = GameOfLife (100, 4, "b3/s23",
                       "5b3o11b3o5b$4bo3bo9bo3bo4b$3b2o4bo7bo4b2o3b$2bobob2ob2o5b2ob2obobo2b$b2obo4bob2ob2obo4bob2ob$o4bo3bo2bobo2bo3bo4bo$12bobo12b$2o7b2obobob2o7b2o$12bobo12b$6b3o9b3o6b$6bo3bo9bo6b$6bobo4b3o11b$12bo2bo4b2o5b$15bo11b$11bo3bo11b$11bo3bo11b$15bo11b$12bobo!",
                       (40, 40))
    for i in range (180) :
        print ("updating iteration number " + str (i))
        game.update ( )
        game.display_board ( )

    game = GameOfLife(100 , 4,"b3/s23", "5b3o11b3o5b$4bo3bo9bo3bo4b$3b2o4bo7bo4b2o3b$2bobob2ob2o5b2ob2obobo2b$b2obo4bob2ob2obo4bob2ob$o4bo3bo2bobo2bo3bo4bo$12bobo12b$2o7b2obobob2o7b2o$12bobo12b$6b3o9b3o6b$6bo3bo9bo6b$6bobo4b3o11b$12bo2bo4b2o5b$15bo11b$11bo3bo11b$11bo3bo11b$15bo11b$12bobo!",(40,40))
    # game = GameOfLife(100 , 4,"b3/s23", "5b3o11b3o5b$4bo3bo9bo3bo4b$3b2o4bo7bo4b2o3b$2bobob2ob2o5b2ob2obobo2b$b2obo4bob2ob2obo4bob2ob$o4bo3bo2bobo2bo3bo4bo$12bobo12b$2o7b2obobob2o7b2o$12bobo12b$6b3o9b3o6b$6bo3bo9bo6b$6bobo4b3o11b$12bo2bo4b2o5b$15bo11b$11bo3bo11b$11bo3bo11b$15bo11b$12bobo!",(40,40))


from connexion.resolver import Resolver
from connexion.operations import AbstractOperation
import os, traceback
from flask import Flask, Response
import connexion, json, logging
from stratus.handlers.manager import Handlers
from functools import partial
from stratus_endpoint.util.config import Config, StratusLogger
from flask_sqlalchemy import SQLAlchemy
from celery import Celery

class StratusResolver(Resolver):

    def __init__(self, api: str  ):
        Resolver.__init__( self, self.function_resolver )
        self.api = api

    def resolve_operation_id(self, operation: AbstractOperation) -> str:
        return '{}:{}'.format( self.api, operation.operation_id )

    def function_resolver( self, operation_id: str ) :
        return partial( Handlers.processRequest, operation_id )

class StratusApp:
    HERE = os.path.dirname(__file__)
    SETTINGS = os.path.join( HERE, 'settings.ini')

    def __init__(self):
        self.logger = StratusLogger.getLogger()
        self.app = connexion.FlaskApp("stratus", specification_dir='api/', debug=True )
        self.app.add_error_handler( 500, self.render_server_error )
        self.app.app.register_error_handler( TypeError, self.render_server_error )
        settings = os.environ.get( 'STRATUS_SETTINGS', self.SETTINGS )
        config_file = Config(settings)
        flask_parms = config_file.get_map('flask')
        flask_parms[ 'SQLALCHEMY_DATABASE_URI' ] = flask_parms['DATABASE_URI']
        self.app.app.config.update( flask_parms )
        self.parms = config_file.get_map('stratus')
        api = self.getParameter( 'API' )
        handler = self.getParameter( 'HANDLER' )
        celery_parms = config_file.get_map('celery')
        self.app.app.config.update( celery_parms )
        self.celery = self.make_celery( self.app.app )
        self.db = SQLAlchemy( self.app.app )
        self.app.add_api( api + ".yaml", resolver=StratusResolver( api ) )

    def run(self):
        port = self.getParameter( 'PORT', 5000 )
        self.db.create_all( )
        return self.app.run( int( port ) )

    def getParameter(self, name: str, default = None ) -> str:
        parm = self.parms.get( name, default )
        if parm is None: raise Exception( "Missing required stratus parameter in settings.ini: " + name )
        return parm

    @staticmethod
    def render_server_error( ex: Exception ):
        print( str( ex ) )
        traceback.print_exc()
        return Response(response=json.dumps({ 'message': getattr(ex, 'message', repr(ex)), "code": 500, "rid": "", "status": "error" } ), status=500, mimetype="application/json")

    def make_celery( self, app: Flask ):
        celery = Celery( app.import_name, backend=app.config['DATABASE_URI'], broker=app.config['CELERY_BROKER_URL'] )
        celery.conf.update(app.config)

        class ContextTask(celery.TaskHandle):
            def __call__(self, *args, **kwargs):
                with app.app_context():
                    return self.run(*args, **kwargs)

        celery.TaskHandle = ContextTask
        return celery

app = StratusApp()

if __name__ == "__main__":
    app.run()


import torch
import numpy as np

def reservoir(seen_examples, buffer_size):
    if seen_examples < buffer_size:
        return seen_examples

    rand = np.random.randint(0, seen_examples + 1)
    if rand < buffer_size:
        return rand
    else:
        return -1

class Buffer:
    def __init__(self, buffer_size, device):
        self.buffer_size = buffer_size
        self.device = device
        self.seen_examples = 0
        self.attributes = ['examples', 'labels']
        self.examples = [None] * self.buffer_size
        self.labels = [None] * self.buffer_size
        self.logits = [None] * self.buffer_size
        self.task_number = [None] * self.buffer_size

    def add_data(self, examples, task=None, labels=None,logits=None):
        for i in range(examples.shape[0]):
            index = reservoir(self.seen_examples, self.buffer_size)
            self.seen_examples += 1
            if index >= 0:
                self.examples[index] = examples[i].to(self.device)
                self.task_number[index] = task
                if labels is not None:
                    self.labels[index] = labels[i].to(self.device)
                if logits is not None:
                    self.logits[index] = logits[i].to(self.device)

    def get_data(self, size,task_labels=False):
        if size > min(self.seen_examples, len([x for x in self.examples if x is not None])):
            size = min(self.seen_examples, len([x for x in self.examples if x is not None]))

        choice = np.random.choice(min(self.seen_examples, len([x for x in self.examples if x is not None])),
                                  size=size, replace=False)

        ret_examples = [self.examples[idx] for idx in choice]
        ret_labels = [self.labels[idx] for idx in choice]
        ret_logits = [self.logits[idx] for idx in choice]

        if task_labels:
            ret_task_labels = [self.task_number[idx] for idx in choice]
            return ret_examples, ret_labels, ret_task_labels

        return ret_examples, ret_labels, ret_logits

    def is_empty(self):
        if self.seen_examples == 0:
            return True
        else:
            return False

    def get_all_data(self):
        ret_tuple = (torch.stack([ee.cpu()
                                  for ee in self.examples]).to(self.device),)
        for attr_str in self.attributes[1:]:
            if hasattr(self, attr_str):
                attr = getattr(self, attr_str)
                ret_tuple += (attr,)

        return ret_tuple

    def clear(self):
        for attr_str in self.attributes:
            if hasattr(self, attr_str):
                delattr(self, attr_str)
        self.seen_examples = 0


#! -*-encoding:utf-8-*-

from get_all_links import get_all_links
from get_all_infomation import get_all_commodity_info

def start():
    print('欢迎使用本程序')
    print('输入a或A:获取所有二手商品的url链接')
    print('输入b或B,获取商品的详细信息')
    print('输入q或Q,退出程序')
    selection = input('请输入你的选择：')
    while True:
        if selection.lower() == 'a':
            # 获取所有二手商品详细信息
            get_all_links()
            print('保存完毕,请查看')
            input('按任意键退出程序')
            return None
        if selection.lower() == 'b':
            # 获取商品详细信息
            get_all_commodity_info()
            print('保存完毕,请查看')
            input('按任意键退出程序')
            return None
        if selection.lower() == 'q':
            # 退出程序
            print('谢谢使用')
            return None
        else:
            selection = input('请输入你的选择：')

if __name__ == '__main__':
    start()


"""
strategy to solve the problem
    problem:
        find all unique combinations in candidates where combination sum to target
        each number use one
        possible duplicates in canidate
    why:
        dfs(i, container, total)
            i (int): index of element
            container (list): a combination
            total: sum of current combination
        sort numbs to know where is duplicates in candidates
        if duplicates skip it
"""
class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res, com = [], []
        candidates.sort()

        def dfs(i, com, total):
            #base case
            if total == target:
                res.append(com[:])
                return
            if total > target or i > len(candidates):
                return

            #normal case
            prev = None #init prev with None
            for j in range(i, len(candidates)):
                if candidates[j] == prev:
                    continue
                com.append(candidates[j])
                dfs(j+1, com, total+candidates[j])
                prev = candidates[j]
                com.pop()

        dfs(0, com, 0)
        return res


"""
-------------------------------------------------------------------------------
Created on April,27, 2020
author: Suksmono@{STEI-ITB, MDR Inc.}
Find a Hadamard matrix using QA Computer/DWave
\-------------------------------------------------------------------------------
"""
# from sympy import *
# #from prb_symbolic import *
# from prb_williamson import *
import neal
import numpy as np
###
import pandas as pd
import matplotlib.pyplot as plt
##
# from prb_small_williamson import *
from prb_turyn import *
#
def writeHMatrix(fname, matx):
   # df=pd.DataFrame(data=matx.astype(int))
    df=pd.DataFrame(data=matx)
    df.to_csv(fname,sep=',', header=False, index=False)

def readHMatrix(fname):
    data=pd.read_csv(fname,sep=',', header=None )
    # return data.as_matrix() #.tolist()
    return data.values #.tolist()
#
def construct_XYZW_normal(v):
    # corr are taken from ABCD, not XYZW
    Nr=len(v)
    N=int((Nr+11)/4)
#    print('N=',N)
    #-- init XYZW
    X=np.zeros([N,1])
    Y=np.zeros([N,1])
    Z=np.zeros([N,1])
    W=np.zeros([N-1,1])
    #
    stX=0
    edX=N-4
    #
    stY=edX #+1
    edY=2*N-7
    stZ=edY#+1
    edZ=3*N-9
    stW=edZ#+1
    edW=4*N-1-10
#    print('stX:',stX,'stY:',stY,'stZ:',stZ,'stW:',stW)
#    print('edX:',edX,'edY:',edY,'edZ:',edZ,'edW:',edW)
    #
    if (edX>0):
        tX=v[stX: edX] # ;%get ss0(1) of  %X=[1; 1; 1; -1];
    else:
        tX=[]
    #--
    # --
    tY=v[stY:edY] #; %;  % get ss0(1) of Y=[1; ss0(0); -ss0(0); -1];
    tZ=v[stZ:edZ] #; %; % Z=[1; ss0(1); ss0(2); 1];
    tW=v[stW:edW] #; %;      %W =[1; ss0(3); ss0(4)];
    #
    if edX>0:
        NX=len(tX)
        for m in range(NX):
            X[m+2]=tX[m] #; !!!!!!!!
    else:
        tX=[]
    #--
    NY=len(tY)
    for m in range(NY):
        Y[m+1]=tY[m]
    #
    Y[N-2]= -Y[1] #enforcing constraint to Y
#    %

    NZ=len(tZ);
    for m in range(NZ):
        Z[m+1]=tZ[m]
#    #
    NW=len(tW)
    for m in range(NW):
        W[m+1]=tW[m]
    #
#    %---
    X[0]= 1
    Y[0]= 1
    Z[0]= 1
    W[0]= 1
    #
    X[N-1]= -1
    Y[N-1]= -1
    Z[N-1]= 1
    #
    X[1] = 1
    X[N-2]=1
    #
    return(X,Y,Z,W)
###
def contruct_XXYY(vSol, X,Y,N_XTD):
    N_ORG=len(X)
    sSol=vSol[0:NQ0]
    N_ORG05=int(N_ORG/2)
    # X->XX
    XX=np.zeros(N_ORG+N_XTD)
    XX[0:N_ORG05]=X[0:N_ORG05] #[x0,x1,*...]
    XX[N_ORG05:N_ORG05+N_XTD]=sSol[0:N_XTD]
    XX[N_ORG05+N_XTD:N_ORG+N_XTD]=X[N_ORG05:N_ORG]
    # Y->YY
    YY=np.zeros(N_ORG+N_XTD)
    YY[0:N_ORG05]=Y[0:N_ORG05] #[x0,x1,*...]
    YY[N_ORG05:N_ORG05+N_XTD]=sSol[N_XTD:2*N_XTD]
    YY[N_ORG05+N_XTD:N_ORG+N_XTD]=X[N_ORG05:N_ORG]
    return(XX,YY)

# ---
if __name__ == '__main__':
    # order definition
    N_ORG=4
    N_XTD=8
    #--
    N=N_ORG+N_XTD # final order
    #    P=N-1
    M=4*(3*N-1) # order of H-matrix
    #
    #    Nr=4*N-11 # length of random vector
    #
    NQ0=2*N_XTD
    idx=0
    ## 4->8: 4,7,18 corret
    idx_f=3 # idx file to read (+1 from the displaye idx in step-6)

    # --
    # read an entry of filled zw and incomplete xy
    path_name0='..\\py_src\\DATA\\'
    zzww_name= 'XYZW_star_xy_zzww_fill_'+str(N_ORG)+'_'+str(N_ORG+N_XTD)+ '.txt'
    fname_zzww=path_name0+zzww_name
    #
    in_file = open(fname_zzww, "r")
    #num_lines = sum(1 for line in open(fname_zzww))
    # read
    for m in range(idx_f):
        t_hex=in_file.readline()
#        print(t_hex)
        m+=1
    #--
    in_file.close()
    # convert into spin
    NHO=int(np.ceil(N_ORG/4)) #hex length of  originalspin
    NHX=int(np.ceil((N_XTD+N_ORG)/4)) #hex length of  extended spin
    #
    hX=t_hex[0:NHO]
    dX=int(hX,16)
    X=int_to_spin(dX,N_ORG)
    #
    hY=t_hex[NHO:NHO+1]
    dY=int(hY,16)
    Y=int_to_spin(dY,N_ORG)
    #
    hZZ=t_hex[2*NHO:2*NHO+NHX]
    dZZ=int(hZZ,16)
    ZZ=int_to_spin(dZZ,N_ORG+N_XTD)
    #
    hWW=t_hex[2*NHO+NHX:2*NHO+2*NHX]
    dWW=int(hWW,16)
    WW0=int_to_spin(dWW,N_ORG+N_XTD)
    WW=WW0[1:N_ORG+N_XTD]

    # ------------------------------------------------------------
    #    number of required qubits
    # ------------------------------------------------------------

    print('Finding Turyn Goethals-Siedel matrix of order:', M)
    print('Reading Ising coefficients from file ...')
    #    hi_complete_XY_4_2_1
    path_name='..\\Jij_DATA\\'
    Jij_name=path_name+'Jij_complete_XY_'+str(N_ORG)+\
    '_'+str(N_XTD)+ '_'+str(idx_f)+ '.txt'
    hi_name= path_name+'hi_complete_XY_'+str(N_ORG)+'_'+str(N_XTD)+ '_'+str(idx_f)+ '.txt'
    b_name= path_name +'b_complete_XY_'+str(N_ORG)+'_'+str(N_XTD)+ '_'+str(idx_f)+ '.txt'
    #
    Jij=readHMatrix(Jij_name)
    hiA=readHMatrix(hi_name)
    hi=hiA[:,0]
    bA=readHMatrix(b_name)
    b=bA[0][0]

    #normalize
    maxCoeff=np.max([np.max(abs(hi)), np.max(abs(Jij)),b])
    hi=hi/maxCoeff
    Jij=Jij/maxCoeff
    # measure of energy minimum
    b=b/maxCoeff

    '''
    # -----------------------------------------------------------------------------
    #     Convert Ising coefficients into data of Neal's format
    # -----------------------------------------------------------------------------
    '''
    #in dictionary format
    h={0:0}
    J={(0,1):1}

    for m in range(0,len(hi)):
        h[m]=hi[m]
        for n in range (m+1,len(hi)):
            J[m,n]=Jij[m,n]
        # --
    # --- end of filling h and J

    '''
    -----------------------------------------------------------------------------
    4. SOLVE THE PROBLEM
    -----------------------------------------------------------------------------
    '''
    #
    print('Solving the problem using Neal  ...')
    solver=neal.SimulatedAnnealingSampler()
    NSWEEPS=1*M*M #1*1*10*1000 #1000*1000
    NR=10*1000 #*1000 #*10 #25 #100
    response = solver.sample_ising(h, J, sweeps=NSWEEPS, num_reads=NR)
    #
    vE=response.data_vectors['energy']
    aSol=response.record['sample']
    #
    print('Configurations:\n', aSol)
    print('Energy:\n',vE)
    #
    idxMinE=np.argmin(vE)
    print('Minimum Energy:',vE[idxMinE])#, 'supposed to be', -b)
    print('Minimum Configurations:',aSol[idxMinE])
    tSol=aSol[idxMinE]
    vSol=tSol#[0]
    #
    XX,YY=contruct_XXYY(vSol, X,Y,N_XTD)
    H=construct_hadamard(XX,YY,ZZ,WW)
    DG=np.matmul(H, H.transpose())
    # display indicator
    plt.imshow(DG.astype(float), cmap="gray")
    plt.show()
    # display H-matrix
    plt.imshow(H.astype(float), cmap="gray")
    plt.show()
    if is_hadamard(H):
        print('Hadamard matrix is found ...!!!')
    else:
        print('Hadamard matrix is NOT found in minimum Energy...!!!')
    ## check all solutions
    NR,NC=aSol.shape
    idx=0
    vIdx=[]
    for m in range(NR):
        tt=aSol[m,:]
        vtt=tt#[0]
        #--
        XX,YY=contruct_XXYY(tt[0:NQ0], X,Y,N_XTD)
        H=construct_hadamard(XX,YY,ZZ,WW)
        if is_hadamard(H):
            vIdx.append(m)
            idx=idx+1
    #--
    if(len(vIdx)>0):
        print('Solutions found: ',len(vIdx))
        tSol=aSol[vIdx[0],:]
        vSol=tSol#[0]
        #--
        XX,YY=contruct_XXYY(vSol[0:NQ0], X,Y,N_XTD)
        H=construct_hadamard(XX,YY,ZZ,WW)
        DG=np.matmul(H, H.transpose())
        plt.imshow(DG.astype(float), cmap="gray")
        plt.show()


import torch

from survboard.python.utils.utils import neg_par_log_likelihood

class intermediate_fusion_mean_criterion(torch.nn.Module):
    def forward(
        self,
        predictions,
        target,
        alpha=0,
    ):
        joint_log_hazard, unimodal_log_hazards = predictions
        time, event = target[:, 0], target[:, 1]
        unicox = 0
        for i in range(len(unimodal_log_hazards)):
            unicox += neg_par_log_likelihood(
                unimodal_log_hazards[i],
                torch.unsqueeze(time, 1).float(),
                torch.unsqueeze(event, 1).float(),
            )
        joint_cox = neg_par_log_likelihood(
            joint_log_hazard,
            torch.unsqueeze(time, 1).float(),
            torch.unsqueeze(event, 1).float(),
        )
        return joint_cox + alpha * unicox

class naive_neural_criterion(torch.nn.Module):
    def forward(self, predicted, target):
        time, event = target[:, 0], target[:, 1]
        cox_loss = neg_par_log_likelihood(
            predicted,
            torch.unsqueeze(time, 1).float(),
            torch.unsqueeze(event, 1).float(),
        )
        return cox_loss


class Solution:
    def maxScore(self, cp: List[int], k: int) -> int:
        n,tot = len(cp),sum(cp)
        k = n-k
        running = 0
        ans = inf
        if k==0:return tot
        for r in range(n):
            running += cp[r]
            if r>=k-1:
                ans = min(ans,running)
                running -= cp[r-k+1]
        return tot-ans


# https://www.acmicpc.net/problem/2162 문제 제목 : 선분 그룹 , 언어 : Python, 날짜 : 2020-05-19, 결과 : 성공
"""
    회고:
    맨 처음에 두 선분이 만난다는걸 어떻게 판단을 할까 하다가 ccw알고리즘을 이용하면 될거같았다.
    그래서 대충 생각을 해보다가 몇가지 반례에 대해서 도저히 풀이를 못하겠어서 인터넷에 검색을 해 보았다.
    그런데 ccw알고리즘을 사용하면 편하다는 글을 보았고, 그 글에서 나온 알고리즘을 이용했다.
    선분이 교차하는지 판정하는 함수를 만든 후 유니온 파인드를 이용해 선분의 그룹을 만들어 주었다.
    그런데 사실 내가 맨 처음 생각한 방법은 유니온을 해주며 노드의 개수가 가장 많은 그룹을 뽑아 주려 했는데, 계속 틀렸었다..
    그래서 혹시몰라 가장 마지막 for문에서 최대값을 구해 주었더니 맞았다. 이런 문제를 풀때 시간제한이 있었다면 절대 못풀거 같다..ㅠㅠ
"""

import sys
def ccw(a, b, c):
    return (b[0] - a[0])*(c[1]-a[1])-(b[1]-a[1])*(c[0]-a[0])

def isCross(line1, line2):
    s1, s2 = line1
    s3, s4 = line2
    r1 = ccw(s1, s2, s3) * ccw(s1, s2, s4)
    r2 = ccw(s3, s4, s1) * ccw(s3, s4, s2)
    if (r1==0 and r2==0):
        if s1>s2:
            s1, s2 = s2, s1
        if s3>s4:
            s3, s4 = s4, s3
        return not (s2<s3 or s4<s1)
    return (r1 <=0 and r2<=0)

def find(node):
    if node == list_parent[node][0]:
        return node
    list_parent[node][0] = find(list_parent[node][0])
    return list_parent[node][0]

def union(node1, node2):
    node1 = find(node1)
    node2 = find(node2)
    if node1==node2:
        return
    if list_parent[node1][1] > list_parent[node2][1]:
        list_parent[list_parent[node1][0]][1] += list_parent[node2][1]
        list_parent[node2][1] = 0
        list_parent[node2][0] = list_parent[node1][0]
    else:
        list_parent[list_parent[node2][0]][1] += list_parent[node1][1]
        list_parent[node1][1] = 0
        list_parent[node1][0] = list_parent[node2][0]

N = int(sys.stdin.readline())
m = 0
list_parent = [[i, 1] for i in range(N)]
list_n=[0 for _ in range(N)]
list_line = []
for _ in range(N):
    x1, y1, x2, y2=map(int, sys.stdin.readline().split())
    list_line.append(((x1,y1),(x2, y2)))

for i in range(N-1):
    for j in range(i+1, N):
        if isCross(list_line[i], list_line[j]):
            union(i, j)
count = 0
#print(list_parent)
for i in range(N):
    i=find(i)
    if not list_n[i]:
        count+=1
    list_n[i]+=1
    m=max(m, list_n[i])
print(count)
print(m)


import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
import numpy as np
from pathlib import Path
from IPython.core.pylabtools import figsize
import matplotlib.pyplot as plt

from net import GlobalCoarseNet, LocalFineNet
from loss import ScaleInvariantLoss
import util

# ignore stupid warning
import warnings
warnings.filterwarnings('ignore')

# training device
device = torch.device('cuda')

# hyperparameter
epochs_num = 4
rate = 1 # rate = 5 in paper; but result is bad so it is tuned by hand

# specifed in paper
batch_size = 32

# load dataset
dataloader_train, dataloader_valid, train_num, val_num = util.load_train(Path('nyu/train'), Path('nyu/val'), batch_size)

print("training number:{}, validation number:{}".format(train_num, val_num))

#########################################################
#              initializing the model                   #
#########################################################

# initialize and parallize the models
global_net = GlobalCoarseNet().to(device)
local_net = LocalFineNet().to(device)

# loss
global_loss = ScaleInvariantLoss()
local_loss = ScaleInvariantLoss()

# optimizer
global_optimizer = torch.optim.SGD([{'params': global_net.coarse6.parameters(), 'lr': 0.1*rate},
                                    {'params': global_net.coarse7.parameters(), 'lr': 0.1*rate}],
                                    lr = 0.001*rate, momentum = 0.9, weight_decay = 0.1)

local_optimizer = torch.optim.SGD([{'params': local_net.fine2.parameters(), 'lr': 0.01*rate}],
                                    lr = 0.001*rate, momentum = 0.9, weight_decay = 0.1)

# parallel
global_net = nn.DataParallel(global_net)
local_net = nn.DataParallel(local_net)

##########################################################
#       training global coarse net with validation       #
##########################################################

print("=============global coarse net training===============")

train_losses = []
val_losses = []

for e in range(epochs_num):
    # train
    train_loss = 0
    global_net.train()
    for i, sample in enumerate(dataloader_train):
        rgb = sample[0].float().to(device)
        depth = sample[1].float().to(device)

        # forward pass
        output = global_net(rgb)
        loss = global_loss(output, depth)

        # back propagate
        global_net.zero_grad()
        loss.backward()

        # optimization
        global_optimizer.step()
        train_loss += loss.item()

    train_losses.append(train_loss / train_num)

    # validation - evaluation mode
    val_loss = 0
    global_net.eval()
    with torch.no_grad():
        for i, sample in enumerate(dataloader_valid):
            rgb = sample[0].float().to(device)
            depth = sample[1].float().to(device)

            # forward pass
            output = global_net(rgb)
            loss = global_loss(output, depth)
            val_loss += loss.item()

    val_losses.append(val_loss / val_num)

    # save model
    torch.save(global_net, './models/global_net.pt')

    print(('epoch {}: train_loss = {}, validation loss = {}').format(e, train_loss, val_loss))

########################################################
#        training local fine net with validation       #
########################################################

print("=============local fine net training===============")

train_losses_ = []
val_losses_ = []

for e in range(epochs_num):
    # train
    train_loss = 0
    local_net.train()
    for i, sample in enumerate(dataloader_train):
        rgb = sample[0].float().to(device)
        depth = sample[1].float().to(device)

        # results from global coarse network
        global_net.eval()
        with torch.no_grad():
            global_output = global_net(rgb).unsqueeze(1)

        # forward pass
        output = local_net(rgb, global_output).squeeze(1)
        loss = local_loss(output, depth)

        # back propagate
        local_net.zero_grad()
        loss.backward()

        # optimization
        local_optimizer.step()
        train_loss += loss.item()

    train_losses_.append(train_loss / train_num)

    # valid
    val_loss = 0
    local_net.eval()
    with torch.no_grad():
        for i, sample in enumerate(dataloader_valid):
            rgb = sample[0].float().to(device)
            depth = sample[1].float().to(device)

            # results from global coarse network
            global_net.eval()
            with torch.no_grad():
                global_output = global_net(rgb).unsqueeze(1)

            # forward pass
            output = local_net(rgb, global_output).squeeze(1)
            loss = local_loss(output, depth)

            val_loss += loss.item()
    val_losses_.append(val_loss / val_num)

    # save model
    torch.save(local_net, './models/local_net.pt')

    print(('epoch {}: train_loss = {}, validation loss = {}').format(e, train_loss, val_loss))

######################################################
#      visulizing the training result on val set     #
######################################################

util.plot_loss(train_losses, val_losses)
util.plot_loss(train_losses_, val_losses_)

print("==========result visualized on validation set=============")
rgb = list(dataloader_valid)[0][0].float().to(device)
depth = list(dataloader_valid)[0][1].float().to(device)

# results from global coarse network
global_net.eval()
with torch.no_grad():
    global_output = global_net(rgb).unsqueeze(1)

# results from local fine network
local_net.eval()
with torch.no_grad():
    local_output = local_net(rgb, global_output)

for i in range(5):
    depth_g = global_output[i].view(74, 55)
    depth_l = local_output[i].view(74, 55)

    r = transforms.ToPILImage()((rgb[i]).cpu())
    gt = depth[i]

    figsize(12,4)
    plt.subplot(141); plt.title('RGB input'); plt.imshow(r)
    plt.subplot(142); plt.title('ground truth'); plt.imshow(gt.cpu())
    plt.subplot(143); plt.title('global coarse result'); plt.imshow(torch.exp(depth_g).cpu())
    plt.subplot(144); plt.title('local fine result'); plt.imshow(torch.exp(depth_l).cpu())

    plt.show()


def find_combinations(arr, target):
    complements = {}
    first_combination = []

    # Step 1: Find pairs that sum up to the target value
    for num in arr:
        complement = target - num
        if complement in complements:
            first_combination.append([num, complement])
        complements[num] = complement

    # Step 4: Sort the first combination in ascending order
    first_combination.sort()

    # Step 5: Merge the first combination into a single array
    merged_array = [num for pair in first_combination for num in pair]

    # Step 6: Double the target value
    target *= 2

    # Step 7: Find pairs that sum up to the doubled target value
    second_combination = []
    for num in merged_array:
        complement = target - num
        if complement in complements:
            second_combination.append([num, complement])

    # Step 9: Sort the second combination in ascending order
    second_combination.sort()

    return first_combination, second_combination