import copy
from typing import Optional, List
import math
import warnings

import torch
import torch.nn.functional as F
from torch import nn, Tensor
from torch.nn.init import xavier_uniform_, constant_, uniform_, normal_
from torch.autograd import Function
from torch.autograd.function import once_differentiable

import MultiScaleDeformableAttention as MSDA

def inverse_sigmoid(x, eps=1e-5):
    x = x.clamp(min=0, max=1)
    x1 = x.clamp(min=eps)
    x2 = (1 - x).clamp(min=eps)
    return torch.log(x1/x2)

class MSDeformAttnFunction(Function):
    @staticmethod
    def forward(ctx, value, value_spatial_shapes, value_level_start_index, sampling_locations, attention_weights, im2col_step):
        ctx.im2col_step = im2col_step
        output = MSDA.ms_deform_attn_forward(
            value, value_spatial_shapes, value_level_start_index, sampling_locations, attention_weights, ctx.im2col_step)
        ctx.save_for_backward(value, value_spatial_shapes, value_level_start_index, sampling_locations, attention_weights)
        return output

    @staticmethod
    @once_differentiable
    def backward(ctx, grad_output):
        value, value_spatial_shapes, value_level_start_index, sampling_locations, attention_weights = ctx.saved_tensors
        grad_value, grad_sampling_loc, grad_attn_weight = \
            MSDA.ms_deform_attn_backward(
                value, value_spatial_shapes, value_level_start_index, sampling_locations, attention_weights, grad_output, ctx.im2col_step)

        return grad_value, None, None, grad_sampling_loc, grad_attn_weight, None

def _is_power_of_2(n):
    if (not isinstance(n, int)) or (n < 0):
        raise ValueError("invalid input for _is_power_of_2: {} (type: {})".format(n, type(n)))
    return (n & (n-1) == 0) and n != 0

class MSDeformAttn(nn.Module):
    def __init__(self, d_model=256, n_levels=4, n_heads=8, n_points=4):
        """
        Multi-Scale Deformable Attention Module
        :param d_model      hidden dimension
        :param n_levels     number of feature levels
        :param n_heads      number of attention heads
        :param n_points     number of sampling points per attention head per feature level
        """
        super().__init__()
        if d_model % n_heads != 0:
            raise ValueError('d_model must be divisible by n_heads, but got {} and {}'.format(d_model, n_heads))
        _d_per_head = d_model // n_heads
        # you'd better set _d_per_head to a power of 2 which is more efficient in our CUDA implementation
        if not _is_power_of_2(_d_per_head):
            warnings.warn("You'd better set d_model in MSDeformAttn to make the dimension of each attention head a power of 2 "
                          "which is more efficient in our CUDA implementation.")

        self.im2col_step = 64

        self.d_model = d_model
        self.n_levels = n_levels
        self.n_heads = n_heads
        self.n_points = n_points

        self.sampling_offsets = nn.Linear(d_model, n_heads * n_levels * n_points * 2)
        self.attention_weights = nn.Linear(d_model, n_heads * n_levels * n_points)
        self.value_proj = nn.Linear(d_model, d_model)
        self.output_proj = nn.Linear(d_model, d_model)

        self._reset_parameters()

    def _reset_parameters(self):
        constant_(self.sampling_offsets.weight.data, 0.)
        thetas = torch.arange(self.n_heads, dtype=torch.float32) * (2.0 * math.pi / self.n_heads)
        grid_init = torch.stack([thetas.cos(), thetas.sin()], -1)
        grid_init = (grid_init / grid_init.abs().max(-1, keepdim=True)[0]).view(self.n_heads, 1, 1, 2).repeat(1, self.n_levels, self.n_points, 1)
        for i in range(self.n_points):
            grid_init[:, :, i, :] *= i + 1
        with torch.no_grad():
            self.sampling_offsets.bias = nn.Parameter(grid_init.view(-1))
        constant_(self.attention_weights.weight.data, 0.)
        constant_(self.attention_weights.bias.data, 0.)
        xavier_uniform_(self.value_proj.weight.data)
        constant_(self.value_proj.bias.data, 0.)
        xavier_uniform_(self.output_proj.weight.data)
        constant_(self.output_proj.bias.data, 0.)

    def forward(self, query, reference_points, input_flatten, input_spatial_shapes, input_level_start_index, input_padding_mask=None):
        """
        :param query                       (N, Length_{query}, C)
        :param reference_points            (N, Length_{query}, n_levels, 2), range in [0, 1], top-left (0,0), bottom-right (1, 1), including padding area
                                        or (N, Length_{query}, n_levels, 4), add additional (w, h) to form reference boxes
        :param input_flatten               (N, \sum_{l=0}^{L-1} H_l \cdot W_l, C)
        :param input_spatial_shapes        (n_levels, 2), [(H_0, W_0), (H_1, W_1), ..., (H_{L-1}, W_{L-1})]
        :param input_level_start_index     (n_levels, ), [0, H_0*W_0, H_0*W_0+H_1*W_1, H_0*W_0+H_1*W_1+H_2*W_2, ..., H_0*W_0+H_1*W_1+...+H_{L-1}*W_{L-1}]
        :param input_padding_mask          (N, \sum_{l=0}^{L-1} H_l \cdot W_l), True for padding elements, False for non-padding elements

        :return output                     (N, Length_{query}, C)
        """
        N, Len_q, _ = query.shape
        N, Len_in, _ = input_flatten.shape
        assert (input_spatial_shapes[:, 0] * input_spatial_shapes[:, 1]).sum() == Len_in

        value = self.value_proj(input_flatten)
        if input_padding_mask is not None:
            value = value.masked_fill(input_padding_mask[..., None], float(0))
        value = value.view(N, Len_in, self.n_heads, self.d_model // self.n_heads)
        sampling_offsets = self.sampling_offsets(query).view(N, Len_q, self.n_heads, self.n_levels, self.n_points, 2)
        attention_weights = self.attention_weights(query).view(N, Len_q, self.n_heads, self.n_levels * self.n_points)
        attention_weights = F.softmax(attention_weights, -1).view(N, Len_q, self.n_heads, self.n_levels, self.n_points)
        # N, Len_q, n_heads, n_levels, n_points, 2
        if reference_points.shape[-1] == 2:
            offset_normalizer = torch.stack([input_spatial_shapes[..., 1], input_spatial_shapes[..., 0]], -1)
            sampling_locations = reference_points[:, :, None, :, None, :] \
                                 + sampling_offsets / offset_normalizer[None, None, None, :, None, :]
        elif reference_points.shape[-1] == 4:
            sampling_locations = reference_points[:, :, None, :, None, :2] \
                                 + sampling_offsets / self.n_points * reference_points[:, :, None, :, None, 2:] * 0.5
        else:
            raise ValueError(
                'Last dim of reference_points must be 2 or 4, but get {} instead.'.format(reference_points.shape[-1]))
        output = MSDeformAttnFunction.apply(
            value, input_spatial_shapes, input_level_start_index, sampling_locations, attention_weights, self.im2col_step)
        output = self.output_proj(output)
        return output

class DeformableTransformer(nn.Module):
    def __init__(self, d_model=256, nhead=8,
                 num_encoder_layers=6, num_decoder_layers=6, dim_feedforward=1024, dropout=0.1,
                 activation="relu", return_intermediate_dec=False,
                 num_feature_levels=4, dec_n_points=4,  enc_n_points=4,
                 two_stage=False, two_stage_num_proposals=300):
        super().__init__()

        self.d_model = d_model
        self.nhead = nhead
        self.two_stage = two_stage
        self.two_stage_num_proposals = two_stage_num_proposals

        encoder_layer = DeformableTransformerEncoderLayer(d_model, dim_feedforward,
                                                          dropout, activation,
                                                          num_feature_levels, nhead, enc_n_points)
        self.encoder = DeformableTransformerEncoder(encoder_layer, num_encoder_layers)

        decoder_layer = DeformableTransformerDecoderLayer(d_model, dim_feedforward,
                                                          dropout, activation,
                                                          num_feature_levels, nhead, dec_n_points)
        self.decoder = DeformableTransformerDecoder(decoder_layer, num_decoder_layers, return_intermediate_dec)

        self.level_embed = nn.Parameter(torch.Tensor(num_feature_levels, d_model))

        if two_stage:
            self.enc_output = nn.Linear(d_model, d_model)
            self.enc_output_norm = nn.LayerNorm(d_model)
            self.pos_trans = nn.Linear(d_model * 2, d_model * 2)
            self.pos_trans_norm = nn.LayerNorm(d_model * 2)
        else:
            self.reference_points = nn.Linear(d_model, 2)

        self._reset_parameters()

    def _reset_parameters(self):
        for p in self.parameters():
            if p.dim() > 1:
                nn.init.xavier_uniform_(p)
        for m in self.modules():
            if isinstance(m, MSDeformAttn):
                m._reset_parameters()
        if not self.two_stage:
            xavier_uniform_(self.reference_points.weight.data, gain=1.0)
            constant_(self.reference_points.bias.data, 0.)
        normal_(self.level_embed)

    def get_proposal_pos_embed(self, proposals):
        num_pos_feats = 128
        temperature = 10000
        scale = 2 * math.pi

        dim_t = torch.arange(num_pos_feats, dtype=torch.float32, device=proposals.device)
        dim_t = temperature ** (2 * (dim_t // 2) / num_pos_feats)
        # N, L, 4
        proposals = proposals.sigmoid() * scale
        # N, L, 4, 128
        pos = proposals[:, :, :, None] / dim_t
        # N, L, 4, 64, 2
        pos = torch.stack((pos[:, :, :, 0::2].sin(), pos[:, :, :, 1::2].cos()), dim=4).flatten(2)
        return pos

    def gen_encoder_output_proposals(self, memory, memory_padding_mask, spatial_shapes):
        N_, S_, C_ = memory.shape
        base_scale = 4.0
        proposals = []
        _cur = 0
        for lvl, (H_, W_) in enumerate(spatial_shapes):
            mask_flatten_ = memory_padding_mask[:, _cur:(_cur + H_ * W_)].view(N_, H_, W_, 1)
            valid_H = torch.sum(~mask_flatten_[:, :, 0, 0], 1)
            valid_W = torch.sum(~mask_flatten_[:, 0, :, 0], 1)

            grid_y, grid_x = torch.meshgrid(torch.linspace(0, H_ - 1, H_, dtype=torch.float32, device=memory.device),
                                            torch.linspace(0, W_ - 1, W_, dtype=torch.float32, device=memory.device))
            grid = torch.cat([grid_x.unsqueeze(-1), grid_y.unsqueeze(-1)], -1)

            scale = torch.cat([valid_W.unsqueeze(-1), valid_H.unsqueeze(-1)], 1).view(N_, 1, 1, 2)
            grid = (grid.unsqueeze(0).expand(N_, -1, -1, -1) + 0.5) / scale
            wh = torch.ones_like(grid) * 0.05 * (2.0 ** lvl)
            proposal = torch.cat((grid, wh), -1).view(N_, -1, 4)
            proposals.append(proposal)
            _cur += (H_ * W_)
        output_proposals = torch.cat(proposals, 1)
        output_proposals_valid = ((output_proposals > 0.01) & (output_proposals < 0.99)).all(-1, keepdim=True)
        output_proposals = torch.log(output_proposals / (1 - output_proposals))
        output_proposals = output_proposals.masked_fill(memory_padding_mask.unsqueeze(-1), float('inf'))
        output_proposals = output_proposals.masked_fill(~output_proposals_valid, float('inf'))

        output_memory = memory
        output_memory = output_memory.masked_fill(memory_padding_mask.unsqueeze(-1), float(0))
        output_memory = output_memory.masked_fill(~output_proposals_valid, float(0))
        output_memory = self.enc_output_norm(self.enc_output(output_memory))
        return output_memory, output_proposals

    def get_valid_ratio(self, mask):
        _, H, W = mask.shape
        valid_H = torch.sum(~mask[:, :, 0], 1)
        valid_W = torch.sum(~mask[:, 0, :], 1)
        valid_ratio_h = valid_H.float() / H
        valid_ratio_w = valid_W.float() / W
        valid_ratio = torch.stack([valid_ratio_w, valid_ratio_h], -1)
        return valid_ratio

    def forward(self, srcs, masks, pos_embeds, query_embed=None, da=False):
        assert self.two_stage or query_embed is not None

        # prepare input for encoder
        src_flatten = []
        mask_flatten = []
        lvl_pos_embed_flatten = []
        spatial_shapes = []
        for lvl, (src, mask, pos_embed) in enumerate(zip(srcs, masks, pos_embeds)):
            bs, c, h, w = src.shape
            spatial_shape = (h, w)
            spatial_shapes.append(spatial_shape)
            src = src.flatten(2).transpose(1, 2)
            mask = mask.flatten(1)
            pos_embed = pos_embed.flatten(2).transpose(1, 2)
            lvl_pos_embed = pos_embed + self.level_embed[lvl].view(1, 1, -1)
            lvl_pos_embed_flatten.append(lvl_pos_embed)
            src_flatten.append(src)
            mask_flatten.append(mask)
        src_flatten = torch.cat(src_flatten, 1)
        mask_flatten = torch.cat(mask_flatten, 1)
        lvl_pos_embed_flatten = torch.cat(lvl_pos_embed_flatten, 1)
        spatial_shapes = torch.as_tensor(spatial_shapes, dtype=torch.long, device=src_flatten.device)
        level_start_index = torch.cat((spatial_shapes.new_zeros((1, )), spatial_shapes.prod(1).cumsum(0)[:-1]))
        valid_ratios = torch.stack([self.get_valid_ratio(m) for m in masks], 1)

        # encoder
        memory = self.encoder(src_flatten, spatial_shapes, level_start_index, valid_ratios, lvl_pos_embed_flatten, mask_flatten)
        if da:
            da_meta = []
            sizes = [(ss[0]*ss[1]).item() for ss in spatial_shapes]
            mem_split = memory.permute(0, 2, 1).split(sizes, dim=-1)
            feats = []
            for shapes, mem in zip(spatial_shapes, mem_split):
                feats.append(mem.view(bs, c, shapes[0], shapes[1]))
            da_meta.append(feats)
        else:
            da_meta = None

        # prepare input for decoder
        bs, _, c = memory.shape
        if self.two_stage:
            output_memory, output_proposals = self.gen_encoder_output_proposals(memory, mask_flatten, spatial_shapes)

            # hack implementation for two-stage Deformable DETR
            enc_outputs_class = self.decoder.class_embed[self.decoder.num_layers](output_memory)
            enc_outputs_coord_unact = self.decoder.bbox_embed[self.decoder.num_layers](output_memory) + output_proposals

            topk = self.two_stage_num_proposals
            topk_proposals = torch.topk(enc_outputs_class[..., 0], topk, dim=1)[1]
            topk_coords_unact = torch.gather(enc_outputs_coord_unact, 1, topk_proposals.unsqueeze(-1).repeat(1, 1, 4))
            topk_coords_unact = topk_coords_unact.detach()
            reference_points = topk_coords_unact.sigmoid()
            init_reference_out = reference_points
            pos_trans_out = self.pos_trans_norm(self.pos_trans(self.get_proposal_pos_embed(topk_coords_unact)))
            query_embed, tgt = torch.split(pos_trans_out, c, dim=2)
        else:
            query_embed, tgt = torch.split(query_embed, c, dim=1)
            query_embed = query_embed.unsqueeze(0).expand(bs, -1, -1)
            tgt = tgt.unsqueeze(0).expand(bs, -1, -1)
            reference_points = self.reference_points(query_embed).sigmoid()
            init_reference_out = reference_points

        # decoder
        hs, inter_references = self.decoder(tgt, reference_points, memory,
                                            spatial_shapes, level_start_index, valid_ratios, query_embed, mask_flatten)

        inter_references_out = inter_references
        if self.two_stage:
            return hs, init_reference_out, inter_references_out, enc_outputs_class, enc_outputs_coord_unact, da_meta
        return hs, init_reference_out, inter_references_out, None, None, da_meta

class DeformableTransformerEncoderLayer(nn.Module):
    def __init__(self,
                 d_model=256, d_ffn=1024,
                 dropout=0.1, activation="relu",
                 n_levels=4, n_heads=8, n_points=4):
        super().__init__()

        # self attention
        self.self_attn = MSDeformAttn(d_model, n_levels, n_heads, n_points)
        self.dropout1 = nn.Dropout(dropout)
        self.norm1 = nn.LayerNorm(d_model)

        # ffn
        self.linear1 = nn.Linear(d_model, d_ffn)
        self.activation = _get_activation_fn(activation)
        self.dropout2 = nn.Dropout(dropout)
        self.linear2 = nn.Linear(d_ffn, d_model)
        self.dropout3 = nn.Dropout(dropout)
        self.norm2 = nn.LayerNorm(d_model)

    @staticmethod
    def with_pos_embed(tensor, pos):
        return tensor if pos is None else tensor + pos

    def forward_ffn(self, src):
        src2 = self.linear2(self.dropout2(self.activation(self.linear1(src))))
        src = src + self.dropout3(src2)
        src = self.norm2(src)
        return src

    def forward(self, src, pos, reference_points, spatial_shapes, level_start_index, padding_mask=None):
        # self attention
        src2 = self.self_attn(self.with_pos_embed(src, pos), reference_points, src, spatial_shapes, level_start_index, padding_mask)
        src = src + self.dropout1(src2)
        src = self.norm1(src)

        # ffn
        src = self.forward_ffn(src)

        return src

class DeformableTransformerEncoder(nn.Module):
    def __init__(self, encoder_layer, num_layers):
        super().__init__()
        self.layers = _get_clones(encoder_layer, num_layers)
        self.num_layers = num_layers

    @staticmethod
    def get_reference_points(spatial_shapes, valid_ratios, device):
        reference_points_list = []
        for lvl, (H_, W_) in enumerate(spatial_shapes):

            ref_y, ref_x = torch.meshgrid(torch.linspace(0.5, H_ - 0.5, H_, dtype=torch.float32, device=device),
                                          torch.linspace(0.5, W_ - 0.5, W_, dtype=torch.float32, device=device))
            ref_y = ref_y.reshape(-1)[None] / (valid_ratios[:, None, lvl, 1] * H_)
            ref_x = ref_x.reshape(-1)[None] / (valid_ratios[:, None, lvl, 0] * W_)
            ref = torch.stack((ref_x, ref_y), -1)
            reference_points_list.append(ref)
        reference_points = torch.cat(reference_points_list, 1)
        reference_points = reference_points[:, :, None] * valid_ratios[:, None]
        return reference_points

    def forward(self, src, spatial_shapes, level_start_index, valid_ratios, pos=None, padding_mask=None):
        output = src
        reference_points = self.get_reference_points(spatial_shapes, valid_ratios, device=src.device)
        for _, layer in enumerate(self.layers):
            output = layer(output, pos, reference_points, spatial_shapes, level_start_index, padding_mask)

        return output

class DeformableTransformerDecoderLayer(nn.Module):
    def __init__(self, d_model=256, d_ffn=1024,
                 dropout=0.1, activation="relu",
                 n_levels=4, n_heads=8, n_points=4):
        super().__init__()

        # cross attention
        self.cross_attn = MSDeformAttn(d_model, n_levels, n_heads, n_points)
        self.dropout1 = nn.Dropout(dropout)
        self.norm1 = nn.LayerNorm(d_model)

        # self attention
        self.self_attn = nn.MultiheadAttention(d_model, n_heads, dropout=dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.norm2 = nn.LayerNorm(d_model)

        # ffn
        self.linear1 = nn.Linear(d_model, d_ffn)
        self.activation = _get_activation_fn(activation)
        self.dropout3 = nn.Dropout(dropout)
        self.linear2 = nn.Linear(d_ffn, d_model)
        self.dropout4 = nn.Dropout(dropout)
        self.norm3 = nn.LayerNorm(d_model)

    @staticmethod
    def with_pos_embed(tensor, pos):
        return tensor if pos is None else tensor + pos

    def forward_ffn(self, tgt):
        tgt2 = self.linear2(self.dropout3(self.activation(self.linear1(tgt))))
        tgt = tgt + self.dropout4(tgt2)
        tgt = self.norm3(tgt)
        return tgt

    def forward(self, tgt, query_pos, reference_points, src, src_spatial_shapes, level_start_index, src_padding_mask=None):
        # self attention
        q = k = self.with_pos_embed(tgt, query_pos)
        tgt2 = self.self_attn(q.transpose(0, 1), k.transpose(0, 1), tgt.transpose(0, 1))[0].transpose(0, 1)
        tgt = tgt + self.dropout2(tgt2)
        tgt = self.norm2(tgt)

        # cross attention
        tgt2 = self.cross_attn(self.with_pos_embed(tgt, query_pos),
                               reference_points,
                               src, src_spatial_shapes, level_start_index, src_padding_mask)
        tgt = tgt + self.dropout1(tgt2)
        tgt = self.norm1(tgt)

        # ffn
        tgt = self.forward_ffn(tgt)

        return tgt

class DeformableTransformerDecoder(nn.Module):
    def __init__(self, decoder_layer, num_layers, return_intermediate=False):
        super().__init__()
        self.layers = _get_clones(decoder_layer, num_layers)
        self.num_layers = num_layers
        self.return_intermediate = return_intermediate
        # hack implementation for iterative bounding box refinement and two-stage Deformable DETR
        self.bbox_embed = None
        self.class_embed = None

    def forward(self, tgt, reference_points, src, src_spatial_shapes, src_level_start_index, src_valid_ratios,
                query_pos=None, src_padding_mask=None):
        output = tgt

        intermediate = []
        intermediate_reference_points = []
        for lid, layer in enumerate(self.layers):
            if reference_points.shape[-1] == 4:
                reference_points_input = reference_points[:, :, None] \
                                         * torch.cat([src_valid_ratios, src_valid_ratios], -1)[:, None]
            else:
                assert reference_points.shape[-1] == 2
                reference_points_input = reference_points[:, :, None] * src_valid_ratios[:, None]
            output = layer(output, query_pos, reference_points_input, src, src_spatial_shapes, src_level_start_index, src_padding_mask)

            # hack implementation for iterative bounding box refinement
            if self.bbox_embed is not None:
                tmp = self.bbox_embed[lid](output)
                if reference_points.shape[-1] == 4:
                    new_reference_points = tmp + inverse_sigmoid(reference_points)
                    new_reference_points = new_reference_points.sigmoid()
                else:
                    assert reference_points.shape[-1] == 2
                    new_reference_points = tmp
                    new_reference_points[..., :2] = tmp[..., :2] + inverse_sigmoid(reference_points)
                    new_reference_points = new_reference_points.sigmoid()
                reference_points = new_reference_points.detach()

            if self.return_intermediate:
                intermediate.append(output)
                intermediate_reference_points.append(reference_points)

        if self.return_intermediate:
            return torch.stack(intermediate), torch.stack(intermediate_reference_points)

        return output, reference_points

def _get_clones(module, N):
    return nn.ModuleList([copy.deepcopy(module) for i in range(N)])

def _get_activation_fn(activation):
    """Return an activation function given a string"""
    if activation == "relu":
        return F.relu
    if activation == "gelu":
        return F.gelu
    if activation == "glu":
        return F.glu
    raise RuntimeError(F"activation should be relu/gelu, not {activation}.")

def build_deforamble_transformer(args):
    return DeformableTransformer(
        d_model=args.hidden_dim,
        nhead=args.nheads,
        num_encoder_layers=args.enc_layers,
        num_decoder_layers=args.dec_layers,
        dim_feedforward=args.dim_feedforward,
        dropout=args.dropout,
        activation="relu",
        return_intermediate_dec=True,
        num_feature_levels=args.num_feature_levels,
        dec_n_points=args.dec_n_points,
        enc_n_points=args.enc_n_points,
        two_stage=args.two_stage,
        two_stage_num_proposals=args.num_queries)

class NestedTensor(object):
    def __init__(self, tensors, mask: Optional[Tensor]):
        self.tensors = tensors
        self.mask = mask

    def to(self, device, non_blocking=False):
        cast_tensor = self.tensors.to(device, non_blocking=non_blocking)
        mask = self.mask
        if mask is not None:
            assert mask is not None
            cast_mask = mask.to(device, non_blocking=non_blocking)
        else:
            cast_mask = None
        return NestedTensor(cast_tensor, cast_mask)

    def record_stream(self, *args, **kwargs):
        self.tensors.record_stream(*args, **kwargs)
        if self.mask is not None:
            self.mask.record_stream(*args, **kwargs)

    def decompose(self):
        return self.tensors, self.mask

    def __repr__(self):
        return str(self.tensors)

def nested_tensor_from_tensor_list(tensor_list: List[Tensor]):
    def _max_by_axis(the_list):
        # type: (List[List[int]]) -> List[int]
        maxes = the_list[0]
        for sublist in the_list[1:]:
            for index, item in enumerate(sublist):
                maxes[index] = max(maxes[index], item)
        return maxes
    # TODO make this more general
    if tensor_list[0].ndim == 3:
        # TODO make it support different-sized images
        max_size = _max_by_axis([list(img.shape) for img in tensor_list])
        # min_size = tuple(min(s) for s in zip(*[img.shape for img in tensor_list]))
        batch_shape = [len(tensor_list)] + max_size
        b, c, h, w = batch_shape
        dtype = tensor_list[0].dtype
        device = tensor_list[0].device
        tensor = torch.zeros(batch_shape, dtype=dtype, device=device)
        mask = torch.ones((b, h, w), dtype=torch.bool, device=device)
        for img, pad_img, m in zip(tensor_list, tensor, mask):
            pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img)
            m[: img.shape[1], :img.shape[2]] = False
    else:
        raise ValueError('not supported')
    return NestedTensor(tensor, mask)

class MLP(nn.Module):
    """ Very simple multi-layer perceptron (also called FFN)"""

    def __init__(self, input_dim, hidden_dim, output_dim, num_layers):
        super().__init__()
        self.num_layers = num_layers
        h = [hidden_dim] * (num_layers - 1)
        self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim] + h, h + [output_dim]))

    def forward(self, x):
        for i, layer in enumerate(self.layers):
            x = F.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
        return x

class DeformableDETR(nn.Module):
    """ This is the Deformable DETR module that performs object detection """
    def __init__(self, backbone, transformer, num_classes, num_queries, num_feature_levels,
                 aux_loss=True, with_box_refine=False, two_stage=False, object_embedding_loss=False,
                 obj_embedding_head=None):
        """ Initializes the model.
        Parameters:
            backbone: torch module of the backbone to be used. See backbone.py
            transformer: torch module of the transformer architecture. See transformer.py
            num_classes: number of object classes
            num_queries: number of object queries, ie detection slot. This is the maximal number of objects
                         DETR can detect in a single image. For COCO, we recommend 100 queries.
            aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used.
            with_box_refine: iterative bounding box refinement
            two_stage: two-stage Deformable DETR
        """
        super().__init__()
        self.num_queries = num_queries
        self.transformer = transformer
        self.object_embedding_loss = object_embedding_loss
        hidden_dim = transformer.d_model
        self.class_embed = nn.Linear(hidden_dim, num_classes)
        if self.object_embedding_loss:
            if obj_embedding_head == 'intermediate':
                last_channel_size = 2*hidden_dim
            elif obj_embedding_head == 'head':
                last_channel_size = hidden_dim//2
            self.feature_embed = MLP(hidden_dim, hidden_dim, last_channel_size, 2)
        self.bbox_embed = MLP(hidden_dim, hidden_dim, 4, 3)
        self.num_feature_levels = num_feature_levels
        if not two_stage:
            self.query_embed = nn.Embedding(num_queries, hidden_dim*2)
        if num_feature_levels > 1:
            num_backbone_outs = len(backbone.strides)
            input_proj_list = []
            for _ in range(num_backbone_outs):
                in_channels = backbone.num_channels[_]
                input_proj_list.append(nn.Sequential(
                    nn.Conv2d(in_channels, hidden_dim, kernel_size=1),
                    nn.GroupNorm(32, hidden_dim),
                ))
            for _ in range(num_feature_levels - num_backbone_outs):
                input_proj_list.append(nn.Sequential(
                    nn.Conv2d(in_channels, hidden_dim, kernel_size=3, stride=2, padding=1),
                    nn.GroupNorm(32, hidden_dim),
                ))
                in_channels = hidden_dim
            self.input_proj = nn.ModuleList(input_proj_list)
        else:
            self.input_proj = nn.ModuleList([
                nn.Sequential(
                    nn.Conv2d(backbone.num_channels[0], hidden_dim, kernel_size=1),
                    nn.GroupNorm(32, hidden_dim),
                )])
        self.backbone = backbone
        self.aux_loss = aux_loss
        self.with_box_refine = with_box_refine
        self.two_stage = two_stage

        prior_prob = 0.01
        bias_value = -math.log((1 - prior_prob) / prior_prob)
        self.class_embed.bias.data = torch.ones(num_classes) * bias_value
        nn.init.constant_(self.bbox_embed.layers[-1].weight.data, 0)
        nn.init.constant_(self.bbox_embed.layers[-1].bias.data, 0)
        for proj in self.input_proj:
            nn.init.xavier_uniform_(proj[0].weight, gain=1)
            nn.init.constant_(proj[0].bias, 0)

        # if two-stage, the last class_embed and bbox_embed is for region proposal generation
        num_pred = (transformer.decoder.num_layers + 1) if two_stage else transformer.decoder.num_layers
        if with_box_refine:
            self.class_embed = _get_clones(self.class_embed, num_pred)
            # if self.object_embedding_loss:
            #     self.feature_embed = _get_clones(self.feature_embed, num_pred)
            self.bbox_embed = _get_clones(self.bbox_embed, num_pred)
            nn.init.constant_(self.bbox_embed[0].layers[-1].bias.data[2:], -2.0)
            # hack implementation for iterative bounding box refinement
            self.transformer.decoder.bbox_embed = self.bbox_embed
        else:
            nn.init.constant_(self.bbox_embed.layers[-1].bias.data[2:], -2.0)
            self.class_embed = nn.ModuleList([self.class_embed for _ in range(num_pred)])
            # if self.object_embedding_loss:
            #     self.feature_embed = nn.ModuleList([self.feature_embed for _ in range(num_pred)])
            self.bbox_embed = nn.ModuleList([self.bbox_embed for _ in range(num_pred)])
            self.transformer.decoder.bbox_embed = None
        if two_stage:
            # hack implementation for two-stage
            self.transformer.decoder.class_embed = self.class_embed
            for box_embed in self.bbox_embed:
                nn.init.constant_(box_embed.layers[-1].bias.data[2:], 0.0)

    def forward(self, samples, da=False):
        """ The forward expects a NestedTensor, which consists of:
               - samples.tensor: batched images, of shape [batch_size x 3 x H x W]
               - samples.mask: a binary mask of shape [batch_size x H x W], containing 1 on padded pixels

            It returns a dict with the following elements:
               - "pred_logits": the classification logits (including no-object) for all queries.
                                Shape= [batch_size x num_queries x (num_classes + 1)]
               - "pred_boxes": The normalized boxes coordinates for all queries, represented as
                               (center_x, center_y, height, width). These values are normalized in [0, 1],
                               relative to the size of each individual image (disregarding possible padding).
                               See PostProcess for information on how to retrieve the unnormalized bounding box.
               - "aux_outputs": Optional, only returned when auxilary losses are activated. It is a list of
                                dictionnaries containing the two above keys for each decoder layer.
        """
        if not isinstance(samples, NestedTensor):
            samples = nested_tensor_from_tensor_list(samples)
        return self.forward_samples(samples, da=da)

    def forward_samples(self, samples, da=False):
        features, pos = self.backbone(samples)
        srcs = []
        masks = []
        for l, feat in enumerate(features):
            src, mask = feat.decompose()
            srcs.append(self.input_proj[l](src))
            masks.append(mask)
            assert mask is not None
        if self.num_feature_levels > len(srcs):
            _len_srcs = len(srcs)
            for l in range(_len_srcs, self.num_feature_levels):
                if l == _len_srcs:
                    src = self.input_proj[l](features[-1].tensors)
                else:
                    src = self.input_proj[l](srcs[-1])
                m = samples.mask
                mask = F.interpolate(m[None].float(), size=src.shape[-2:]).to(torch.bool)[0]
                pos_l = self.backbone[1](NestedTensor(src, mask)).to(src.dtype)
                srcs.append(src)
                masks.append(mask)
                pos.append(pos_l)
        query_embeds = None
        if not self.two_stage:
            query_embeds = self.query_embed.weight
        hs, init_reference, inter_references, enc_outputs_class, enc_outputs_coord_unact, da_features = self.transformer(srcs, masks, pos, query_embeds, da=da)
        outputs_classes = []
        outputs_coords = []
        outputs_features = []
        for lvl in range(hs.shape[0]):
            if lvl == 0:
                reference = init_reference
            else:
                reference = inter_references[lvl - 1]
            reference = inverse_sigmoid(reference)
            outputs_class = self.class_embed[lvl](hs[lvl])
            tmp = self.bbox_embed[lvl](hs[lvl])
            if reference.shape[-1] == 4:
                tmp += reference
            else:
                assert reference.shape[-1] == 2
                tmp[..., :2] += reference
            outputs_coord = tmp.sigmoid()
            outputs_classes.append(outputs_class)
            outputs_coords.append(outputs_coord)
            # if self.object_embedding_loss:
            #     outputs_features.append(outputs_feat)
        outputs_class = torch.stack(outputs_classes)
        outputs_coord = torch.stack(outputs_coords)
        # if self.object_embedding_loss:
        #     outputs_features = torch.stack(outputs_features)

        out = {'pred_logits': outputs_class[-1], 'pred_boxes': outputs_coord[-1]}
        if self.object_embedding_loss:
            out['pred_features'] = self.feature_embed(hs[-1])

        if self.aux_loss:
            out['aux_outputs'] = self._set_aux_loss(outputs_class, outputs_coord) #, outputs_features)
        if self.two_stage:
            enc_outputs_coord = enc_outputs_coord_unact.sigmoid()
            out['enc_outputs'] = {'pred_logits': enc_outputs_class, 'pred_boxes': enc_outputs_coord}
            if self.object_embedding_loss:
                out['pred_features'] = outputs_features
        if da:
            return out, da_features
        else:
            return out

    @torch.jit.unused
    def _set_aux_loss(self, outputs_class, outputs_coord):#, outputs_features):
        # this is a workaround to make torchscript happy, as torchscript
        # doesn't support dictionary with non-homogeneous values, such
        # as a dict having both a Tensor and a list.
        return [{'pred_logits': a, 'pred_boxes': b}#, 'pred_features': c}
                for a, b in zip(outputs_class[:-1], outputs_coord[:-1])] #, outputs_features[:-1])]


import sys
sys.path.append('/home/aistudio/package')

import torch
import torch.nn.functional as F
from torch.optim import lr_scheduler
from torch import nn, optim
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
import torch_optimizer as newoptim

from sklearn.model_selection import KFold
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
import numpy as np
from tqdm import tqdm

from utils import models

print('loading data')
train_path = './data/train_data_180.csv'
test_path = './data/test_data_180.csv'

train = pd.read_csv(train_path)
print('data loaded')

y = np.expm1(train['price'])
x = train.drop(['price', 'SaleID', 'regDate'], axis=1)
tags = x.columns
print(len(tags))
# test = pd.read_csv(test_path)

#归一化
min_max_scaler = MinMaxScaler()
min_max_scaler.fit(x[tags].values)
x = min_max_scaler.transform(x[tags].values)

kfold = KFold(10, shuffle=True, random_state=233)

class MyDataset(Dataset):
    def __init__(self, X, y):
        self.X = X
        self.y = y

    def __len__(self):
        return self.X.shape[0]

    def __getitem__(self, idx):
        batch_x = torch.from_numpy(np.array(self.X[idx]))
        batch_x = batch_x.float()
        batch_y = torch.from_numpy(np.array(self.y.iloc[idx]))
        batch_y = batch_y.float()

        return batch_x, batch_y

def train(model, epoch, train_loader, criterion):
    model.train()
    running_loss = 0.0
    total_size = 0
    for i, (input, target) in tqdm(enumerate(train_loader)):
        input = input.cuda(non_blocking=True)
        target = target.view(-1, 1)
        target = target.cuda(non_blocking=True)

        optimizer.zero_grad()
        # compute output
        output = model(input)
        loss = criterion(output, target)
        running_loss += loss.data
        total_size += input.shape[0]

        # compute gradient and do SGD step
        loss.backward()
        optimizer.step()

    return running_loss / total_size

def validate(model, epoch, val_loader, criterion):
    model.eval()
    running_loss = 0.0
    total_size = 0
    with torch.no_grad():
        for i, (input, target) in enumerate(val_loader):
            input = input.cuda(non_blocking=True)
            target = target.view(-1, 1)
            target = target.cuda(non_blocking=True)

            # compute output
            output = model(input)
            loss = criterion(output, target)
            running_loss += loss.data
            total_size += input.shape[0]

    return running_loss / total_size

train_batch_size = 2048
val_batch_size = 1024
epochs = 150
restart = epochs//3
lr = 1e-1
best_losses = {}

for fold_idx, (train_idx, val_idx) in enumerate(kfold.split(x)):
    if fold_idx < 7:
        continue
    if fold_idx > 7:
        break
    print('*******************fold {}*****************'.format(fold_idx))
    train_x = x[train_idx]
    train_y = y.iloc[train_idx]
    val_x = x[val_idx]
    val_y = y.iloc[val_idx]

    train_loader = torch.utils.data.DataLoader(MyDataset(train_x, train_y), batch_size=train_batch_size, shuffle=True)
    val_loader = torch.utils.data.DataLoader(MyDataset(val_x, val_y), batch_size=val_batch_size, shuffle=False)
    model = models.MyResnet(len(tags))
    model.cuda()

    criterion = nn.L1Loss(reduction='sum')
    optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=1e-2)
    # optimizer = newoptim.RAdam(model.parameters(), lr=lr)

    # scheduler = optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=restart)
    scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, verbose=True, cooldown=1, factor=0.7, min_lr=1e-5)

    best_loss = 10000
    snapshot = 0
    count = 0

    for epoch in range(epochs):
        print('Epoch: ', epoch)
        train_loss = train(model, epoch, train_loader, criterion)
        val_loss = validate(model, epoch, val_loader, criterion)
        scheduler.step(val_loss)

        if val_loss <= best_loss:
            best_loss = val_loss
            torch.save(model.state_dict(), './checkpoint/fold{}_snap{}.pth'.format(fold_idx, snapshot))
            count = 0
        else:
            count += 1
        print('train_loss: {:4f}  val_loss: {:4f}  best_loss: {:4f}  lr: {}'.format(train_loss, val_loss, best_loss, optimizer.param_groups[0]['lr']))

        if count > 20:
            print('early stop at epoch {}'.format(epoch))
            count = 0
            break

    best_losses['fold{}'.format(fold_idx)] = best_loss.data.item()
    print(best_losses)
print(best_losses)


"""
test_adaptive_transition_system.py
Description:
    Testing that the adaptive transition system works.
"""
import unittest
from itertools import chain, combinations

from kltl.automata import DeterministicRabinAutomaton
from kltl.systems import AdaptiveTransitionSystem
class TestAdaptiveTransitionSystem(unittest.TestCase):
    def powerset(self, iterable):
        "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
        s = list(iterable)
        return list(chain.from_iterable(combinations(s, r) for r in range(len(s) + 1)))

    def test_product1(self):
        """
        Description:
            Test that the product of a transition and an automaton is correct.
        :return:
        """
        # Constants

        # Create dummy transition system
        ts1 = AdaptiveTransitionSystem(
            ["red", "red/yellow", "green", "yellow"],
            ["switch"],
            ["red", "green", "yellow"],
            I=["green"],
        )
        ts1.add_transition("red", "switch", "red/yellow")
        ts1.add_transition("red/yellow", "switch", "green")
        ts1.add_transition("green", "switch", "yellow")
        ts1.add_transition("yellow", "switch", "red")

        ts1.add_label("red", "red")
        ts1.add_label("red/yellow", "red")
        ts1.add_label("red/yellow", "yellow")
        ts1.add_label("green", "green")
        ts1.add_label("yellow", "yellow")

        # Create dummy automaton
        aut1 = DeterministicRabinAutomaton(
            ["q0", "q1", "qF"],
            [set(elt) for elt in self.powerset(["red", "green", "yellow"])],
            ["q0"],
            F=[(set(["qF"]), set(["qF"]))],
        )
        # Add transitions for q0
        for sigma in aut1.Sigma:
            if ("yellow" in sigma) and ("red" not in sigma):
                aut1.add_transition("q0", sigma, "q1")
            if ("red" not in sigma) and ("yellow" not in sigma):
                aut1.add_transition("q0", sigma, "q0")
            if "red" in sigma:
                aut1.add_transition("q0", sigma, "qF")

        # Add transitions from q1
        for sigma in aut1.Sigma:
            if "yellow" in sigma:
                aut1.add_transition("q1", sigma, "q1")
            else:
                aut1.add_transition("q1", sigma, "q0")

        # Attempt to compute product
        product_ts = ts1.product(aut1)
        # print(product_ts.S)
        # assert len(product_ts.S) == 4
        assert len(product_ts.Act) == 1
        # for transition in product_ts.transitions:
        #     #print(transition)
        #     print((product_ts.S[transition[0]], product_ts.Act[transition[1]], product_ts.S[transition[2]]))
        assert len(product_ts.reachable_states_from(product_ts.I)) == 4, f"Expected 4 transitions, got {len(product_ts.transitions)} transitions."

if __name__ == "__main__":
    unittest.main()


# %%
from MyxoNutrient_agent import Myxo, Nutrient
from MyxoNutrient_model import MyxoModel
from matplotlib import pyplot as plt
import numpy as np
from os import path
import cv2
import pandas as pd

# %%
x_ini, y_ini = 50, 50
N = 1
dt = 0.1
width = 100
height = 100
v_mu, v_std = 2.3, 0
angleLow, angleHigh = 0.5, 0.5
white_angle_mu, white_angle_std = 0, 0.4
reversal = [8.6]
nutrient_range = 10
initx, inity = 50, 50

# %%
model = MyxoModel(x=x_ini, y=y_ini, N=N, width=width, height=height, v_mu=v_mu,
                    v_std=v_std, angleLow=angleLow, angleHigh=angleHigh, white_angle_mu=white_angle_mu,
                    white_angle_std=white_angle_std, reversal = reversal, clock=0, dt=dt, initx=50,
                    inity=50, nutrient_range =10, OPTION =1)

res  = []
for j in range(50):
    for i in range(6000):
        model.step()
    agent_pos = model.datacollector.get_model_vars_dataframe()
    agent_counts = agent_pos.iloc[-1]['Nutrient']
    res_ = (2*nutrient_range)**2 - np.sum(agent_counts[initx-nutrient_range:initx+nutrient_range, \
        inity-nutrient_range:inity+nutrient_range])
    res.append(res_)
# %%
agent_pos = model.datacollector.get_model_vars_dataframe()
agent_pos.head()
# # %%
from matplotlib import pyplot as plt
agent_counts = agent_pos.iloc[-1]['Nutrient']
fig = plt.imshow(agent_counts, interpolation = 'nearest')
plt.colorbar()

# %%
(2*nutrient_range)**2 - np.sum(agent_counts[initx-nutrient_range:initx+nutrient_range, \
        inity-nutrient_range:inity+nutrient_range])
# %%


# -*- coding: utf-8 -*-
__author__ = 'xwj'
__date__ = '2019/3/18 0018 21:21'

import MySQLdb

conn = MySQLdb.connect('127.0.0.1', 'root', 'woshinibaba', 'biquge', charset="utf8", use_unicode=True)
cursor = conn.cursor()

insert_sql = """
            insert into books_book (book_id, title, author, tag)
            VALUES (%s, %s, %s, %s)
        """
cursor.execute(insert_sql, ("book_id", "title", "author", "tag"))
conn.commit()
print(1)
print(len('333906e2a9f58927412540da3eae47c204bc45e1.jpg'))


from flask import Flask, request
import whatismyip
import socket

app = Flask(__name__)

@app.route('/')
def get_client_ip():
    # Try to get the client's IP address from the X-Forwarded-For header
    client_ip = request.headers.get('X-Real-IP')
    ip = whatismyip.whatismyip()
    print(f"I am a string yay {ip}")
    # ip = requests.get('https://checkip.amazonaws.com').text.strip()
    #  print("ip:", ip)
    # hostname = socket.gethostname()
    # ip_address = socket.gethostbyname(hostname)
    # print(f"Hostname: {hostname}, ip:{ip_address}  ")
    #  print(f"IP Address: {ip}")

## getting the hostname by socket.gethostname() method

## getting the IP address using socket.gethostbyname() method
# ip_address = socket.gethostbyname(hostname)
## printing the hostname and ip_address

# print(f"IP Address: {ip_address}")

    # If X-Forwarded-For header is not present, get the IP address from remote_addr
    if client_ip is None:
        client_ip = ip

    return f"Client's IP address: {client_ip}"

if __name__ == '__main__':
    app.run(debug=True)

    # To run the App:-  python app.py


from .import views
from django.conf.urls import url,include
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
app_name='dpyApp'

urlpatterns = [
    url(r'^$', views.home),
    url(r'^home/$', views.home),
    url(r'^login/$', views.login),
    url(r'^signup/$', views.signup),
    url(r'^ajax/validate_username/$', views.validate_username, name='validate_username'),
    url(r'^ajax/insert_user/$', views.insert_user, name='insert_user'),
    url(r'^update_user/$', views.update_user, name='update_user'),
    url(r'^validate_login/', views.validate_login, name='validate_login'),
    url(r'^logout/', views.logout, name='logout'),
]

urlpatterns += staticfiles_urlpatterns()


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

from tqdm import tqdm

import torch
import torch.nn.functional as F

__author__ = ['chaonan99', 'yixin1']

def hidden_eval(model, data_iter, dev_data_list):
    # select < (-.-) > 0
    # non-select < (-.-) > 1
    # hidden < (-.-) > -2

    with torch.no_grad():
        id2label = {
            0: "true",
            1: "false",
            -2: "hidden"
        }

        print("Evaluating ...")
        model.eval()
        totoal_size = 0
        y_pred_logits_list, y_pred_prob_list, y_id_list = [], [], []

        for batch_idx, batch in enumerate(tqdm(data_iter)):
            out = model(batch)
            prob = F.softmax(out, dim=1)

            y = batch['selection_label']
            y_id_list.extend(list(batch['pid']))

            y_pred_logits_list.extend(out[:, 0].tolist())
            y_pred_prob_list.extend(prob[:, 0].tolist())

            totoal_size += y.size(0)

        assert len(y_id_list) == len(dev_data_list)
        assert len(y_pred_logits_list) == len(dev_data_list)

        for i in range(len(dev_data_list)):
            assert str(y_id_list[i]) == str(dev_data_list[i]['selection_id'])
            # Matching id

            dev_data_list[i]['score'] = y_pred_logits_list[i]
            dev_data_list[i]['prob'] = y_pred_prob_list[i]
            # Reset neural set

        print('total_size:', totoal_size)

    return dev_data_list

def toy_test():
    import config
    import nn_doc_retrieval.disabuigation_training as disamb
    from utils import c_scorer
    from data import DocIDCorpus
    from model import Model

    dev_upstream_file = config.RESULT_PATH / \
                        "doc_retri_bls/docretri.basic.nopageview/dev_toy.jsonl"
    corpus = DocIDCorpus(dev_upstream_file, train=False)
    corpus.initialize()

    model = Model(weight=corpus.weight_dict['glove.840B.300d'],
                  vocab_size=corpus.vocab.get_vocab_size('tokens'),
                  embedding_dim=300, max_l=160, num_of_class=2)

    eval_iter = corpus.get_batch(10)
    complete_upstream_data = hidden_eval(model,
                                         eval_iter,
                                         corpus.complete_upstream_data)
    disamb.enforce_disabuigation_into_retrieval_result_v0( \
        complete_upstream_data, corpus.d_list)
    oracle_score, pr, rec, f1 = c_scorer.fever_doc_only(corpus.d_list,
                                                        corpus.d_list,
                                                        max_evidence=5)

    from IPython import embed; embed(); import os; os._exit(1)

def main():
    toy_test()

if __name__ == '__main__':
    main()


# coding: utf-8
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import os

def Game(img):
    dimy, dimx = img.shape
    # 1: Vivo
    # 0: Muerto
    img_aux = img.copy()
    for y in range(dimy):
        for x in range(dimx):
            suma = np.sum(img[max(y - 1, 0):min(y + 2, dimy), max(x - 1, 0):min(x + 2, dimx)]) - img[y, x]
            if img[y,x] == 1:
                # Está vivo
                if suma < 2 or suma > 3:
                    # Si hay menos de 2 vivos alrededor, muere por soledad
                    # Si hay más de 3 vivos alrededor, muere por sobrepoblación
                    img_aux[y,x] = 0
                    # Si hay 2 o 3 vivos alrededor, sobrevive
            elif suma == 3:
                # Está muerto
                # Si hay exactamente 3 vivos alrededor, nace "por reproducción"
                img_aux[y,x] = 1
    return img_aux

def CreateNumbers(ax, img):
    dimy, dimx = img.shape
    for y in range(dimy):
        for x in range(dimx):
            if img[y, x]==1:
                ax.text(x - 0.5, y + 0.5, str(1), color="lime", fontsize=8)#, fontweight='bold')

# BEGIN

path = './GOF_figures'
if not os.path.exists(path):
    os.makedirs(path)

# Frames number
frames = 40

# Grid dimensions
dimx = 50
dimy = 25

# Null matrix for dark background
img_null = np.zeros((dimy,dimx))

# Initial conditions
img = np.random.randint(2, size=(dimy,dimx))

# Init file names
files = []

for i in range(frames):
    plt.style.use('dark_background')
    plt.delaxes()
    fig = plt.figure()#figsize=(10,15), dpi=90)
    ax = fig.add_subplot(111)
    plt.axis('off')
    plt.subplots_adjust(left=-0.4, bottom=-0.2, right=1.4, top=1.2)
    plt.tight_layout()
    ax.imshow(img_null, cmap=plt.get_cmap('gray'), vmin=0, vmax=1, animated=True)
    img = Game(img)
    CreateNumbers(ax, img)
    fname = str(100 + i)
    plt.savefig(fname, bbox_inches='tight')
    files.append(fname)
    plt.close('all')
    print(i)


from django import forms
from vimarsh18 import models as v18
#from django.contrib.auth.forms import UserCreationForm, PasswordChangeForm
#from django.contrib.auth.models import User

year_choice = (
    ('','Select Course Year (currently studying)'),
    ('1','1'),
    ('2','2'),
    ('3','3'),
    ('4','4'),
    ('5','5'),
    )

ratings = (
    ('10', '10'),
    ('9', '9'),
    ('8', '8'),
    ('7', '7'),
    ('6', '6'),
    ('5', '5'),
    ('4', '4'),
    ('3', '3'),
    ('2', '2'),
    ('1', '1'),
    )

areaOfInterest = (
    ('','Select area of Interest'),
    ('Law and Polity', 'Law and Polity'),
                                  ('Science and Technology', 'Science and Technology'),
                                  ('Language Literature and Journalism', 'Language, Literature and Journalism'),
                                  ('General Awareness', 'General Awareness'))

pay_mode_choices = (
    ('',' Select Payment Method'),
    ('pay_online', 'Pay Online'),
    ('pay_venue','Will pay at venue during the time of Vimarsh')
    )

class volunteer_form(forms.ModelForm):
    course = forms.CharField(required=True, widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Course'}))
    branch = forms.CharField(required=True, widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Branch'}))
    year = forms.ChoiceField(choices=year_choice, required=True, widget=forms.Select(attrs={'class':'js-example-basic-single form-control', 'data-placeholder':'Select Course Year (currently studying)'}))
    interest = forms.ChoiceField(choices=areaOfInterest, required=True, widget=forms.Select(attrs={'class':'js-example-basic-single form-control', 'data-placeholder':'Select area of Interest'}))
    class Meta:
        model = v18.volunteer
        fields = {
            'course',
            'branch',
            'year',
            'interest',
            }

class multiple_choice_form(forms.Form):
    choice = forms.MultipleChoiceField(choices = areaOfInterest, required = True, widget  = forms.SelectMultiple(attrs={'class':'js-example-basic-multiple form-control', 'data-placeholder':'Select area of Interest'}))
    pay_choice = forms.ChoiceField(choices=pay_mode_choices, required=True, widget=forms.Select(attrs={'class':'js-example-basic-single form-control', 'data-placeholder':'Select Payment Method'}))

class single_field_form(forms.Form):
    field1 = forms.CharField()

class single_choice_form(forms.Form):
    pay_choice = forms.ChoiceField(choices=pay_mode_choices, required=True, widget=forms.Select(attrs={'class':'js-example-basic-single form-control', 'data-placeholder':'Select Payment Method'}))

class volunteer_certi_form(forms.Form):
    reg_no = forms.CharField(required=True, widget=forms.TextInput(attrs={'class':'form-control'}))
    email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'class':'form-control'}))
    def clean_reg_no(self):
        reg_no = self.cleaned_data['reg_no'].upper()
        if not v18.volunteer.objects.filter(reg_no = reg_no).exists():
            raise forms.ValidationError('There is no volunteer with registration number '+reg_no+'. Please enter valid registration number')
        return reg_no

class feedback_form(forms.ModelForm):
    reg_no = forms.CharField(required=True, widget=forms.TextInput(attrs={'class':'form-control'}))
    content_use = forms.ChoiceField(choices=ratings, widget=forms.Select(attrs={'class':'form-control selectpicker', 'data-style':'btn btn-link'}))
    admin_satisfaction  = forms.ChoiceField(choices=ratings,  widget=forms.Select(attrs={'class':'form-control selectpicker', 'data-style':'btn btn-link'}))
    overall_satisfaction = forms.ChoiceField(choices=ratings,  widget=forms.Select(attrs={'class':'form-control selectpicker', 'data-style':'btn btn-link'}))
    comment = forms.CharField(required = False, widget=forms.Textarea(attrs={'class':'form-control', 'rows':'3'}))

    def clean_reg_no(self):
        reg_no = self.cleaned_data['reg_no'].upper()
        if not v18.participant.objects.filter(reg_no = reg_no).exists():
            raise forms.ValidationError('There is no participant with registration number '+reg_no+'. Please enter valid registration number')
        return reg_no

    class Meta:
        model = v18.feedback
        fields = {
            'reg_no',
            'content_use',
            'admin_satisfaction',
            'overall_satisfaction',
            'comment',
            }


# Import MNIST data
import input_data
import numpy as np
import matplotlib.pyplot as plt
import random as rand
import time

mnist = input_data.read_data_sets("D:\Studia\Inne\TensorFlow_Demo\data", one_hot=True)

import tensorflow as tf

# Set parameters
learning_rate = 0.01
training_iteration = 30
batch_size = 100

# TF graph input
x = tf.placeholder("float", [None, 784], name='input') # mnist data image of shape 28*28=784
y = tf.placeholder("float", [None, 10], name='output') # 0-9 digits recognition => 10 classes

# Create a model

# Set model weights
W1 = tf.Variable(tf.random_normal([784, 784], stddev=0.1), name='weight_1')
W2 = tf.Variable(tf.zeros([784, 10]), name='weight_2')
b = tf.Variable(tf.zeros([10]), name='bias')

with tf.variable_scope("W2W1x_b"):
    # Construct a linear model
    h = tf.nn.relu(tf.matmul(x, W1))
    model = tf.nn.softmax(tf.matmul(h, W2) + b) # Softmax

# Add summary ops to collect data
w1_h = tf.summary.histogram(W1.op.name, W1)
w2_h = tf.summary.histogram(W2.op.name, W2)
b_h = tf.summary.histogram(b.op.name, b)

# Create loss function
with tf.variable_scope("cost_function"):
    # Minimize error using cross entropy
    cost_function = -tf.reduce_sum(y*tf.log(model))
    # Create a summary to monitor the cost function
    tf.summary.scalar(cost_function.op.name, cost_function)

with tf.variable_scope("train"):
    # Gradient descent
    optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost_function)

# Initializing the variables
init = tf.global_variables_initializer()

# Merge all summaries into a single operator
merged_summary_op = tf.summary.merge_all()

# Launch the graph
# with tf.Session(config=tf.ConfigProto(device_count={'GPU': 0})) as sess: # don't use GPU
with tf.Session() as sess: # use GPU
    sess.run(init)

    # Set the logs writer
    # summary_writer = tf.summary.FileWriter('D:\Studia\Inne\TensorFlow_Demo', graph=sess.graph)
    summary_writer = tf.summary.FileWriter('board_log', sess.graph)

    print("Training started...")
    start_time = time.time()

    # Training cycle
    for iteration in range(training_iteration):
        avg_cost = 0.
        total_batch = int(mnist.train.num_examples/batch_size)
        # Loop over all batches
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            # Fit training using batch data
            sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})
            # Compute the average loss
            avg_cost += sess.run(cost_function, feed_dict={x: batch_xs, y: batch_ys})/total_batch
            # Write logs for each iteration
            summary_str = sess.run(merged_summary_op, feed_dict={x: batch_xs, y: batch_ys})
            summary_writer.add_summary(summary_str, iteration*total_batch + i)
        # Display logs per iteration step
        print("Iteration:", '%04d' % (iteration + 1), "cost=", "{:.9f}".format(avg_cost))

    elapsed_time = time.time() - start_time
    print("Training completed! (" +str(time.strftime("%H:%M:%S", time.gmtime(elapsed_time))) + ")")

    # Test the model
    predictions = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1))
    # Calculate accuracy
    accuracy = tf.reduce_mean(tf.cast(predictions, "float"))
    print("Accuracy:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))

    # present 9 random testing examples
    plt.figure(figsize=(15, 7.5))
    for p in range(9):
        # get number of random image
        k = rand.randrange(mnist.test.num_examples)
        # get actual label
        label = np.nonzero(mnist.test.labels[k])[0][0]

        # plot the image
        s1 = plt.subplot(3,6,2*p+1)
        s1.axis('off')
        img = (np.reshape(mnist.test.images[k], (28, 28)) * 255).astype(np.uint8)
        plt.imshow(img)

        # calculate classification
        img = np.array([mnist.test.images[k]])
        prob = sess.run(model, feed_dict={x: img})
        # plot the probabilities
        s2 = plt.subplot(3,6,2*p+2)
        plt.barh(range(10),prob[0])
        plt.title("actual label: " + str(label))
        plt.yticks(range(10))

    plt.tight_layout()
    plt.show()

# tensorboard --logdir=D:\Studia\Inne\TensorFlow_Demo


import sys

import csv
import datetime

class Hospitalizations:
    def __init__(self, path) -> None:
        self.path = path

        with open("hospitalizations.csv", "r", newline="") as csvfile:
            reader = csv.DictReader(csvfile)
            self.fieldnames = reader.fieldnames

            month, day, year = map(int, self.fieldnames[-1].split('/'))

            if year < 1900:
                year += 2000

            self.rows = list(reader)

            self.cur = datetime.date(day=day, month=month, year=year)

    def __next__(self) -> str:
        self.cur += datetime.timedelta(days=1)

        return self.cur

    def update(self, then, counties):
        key = f"{then.month}/{then.day}/{then.year - 2000}"

        if key not in self.fieldnames:
            self.fieldnames.append(key)

        for r in self.rows:
            county = r['Admin2']

            if county in counties:
                count = counties[county]

                print(f"{key}: {county} = {count}")
                r[key] = str(count)
            else:
                print(f"{key}: {county} = ??")
                r[key] = "0"

    def save(self):
        with open("h2.csv", "w", newline="") as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=self.fieldnames)

            writer.writeheader()

            for r in self.rows:
                writer.writerow(r)


from .base import ImageFormat
from . import (
    ResizeConfig,
    UnencodedEncoding,
    ThumbnailEncoding
)
from dataclasses import dataclass
from typing import Union

@dataclass
class WEBPImageFormat(ImageFormat):
    "Encode as a .webp image"
    resize: "ResizeConfig | None" = None
    quality: int = 85
    "The webp quality"
    lossless: bool = False
    "Should the image be lossless?"

    def __repr__(self) -> str:
        if self.lossless:
            quality = f"lossless"
        else:
            quality = f"quality={self.quality}"

        return f"Webp({self.resize} {quality})"

@dataclass
class PNGFormat(ImageFormat):
    "Encode as a .png image"
    resize: "ResizeConfig | None" = None

    def __repr__(self) -> str:
        return f"PNG({self.resize})"

@dataclass
class JPEGFormat(ImageFormat):
    "Encode as a .jpg image"
    resize: "ResizeConfig | None" = None
    quality: int = 85
    "The JPEG quality option"
    progressive: bool = True
    "Encode in a way that allows it to be displayed in low quality before it is fully downloaded."

    def __repr__(self) -> str:
        if self.progressive:
            return f"JPEG({self.resize} quality={self.quality} progressive)"
        else:
            return f"JPEG({self.resize} quality={self.quality})"

ImageEncodingType = Union[
    ImageFormat,
    UnencodedEncoding,
    ThumbnailEncoding,
]


import csv
import paho.mqtt.client as mqtt
import json
from time import asctime, time, sleep
from math import exp

# MQTT info
broker_addr = "10.40.10.18"
broker_port = 1883
topic_smoke = "esp32/smoke"
topic_temp = "esp32/temp"

def on_publish(client, userdata, result):  # create function for callback
    print("data published \n")
    pass

# Create MQTT client instance and connect to broker
client = mqtt.Client("esp32")
client.on_publish = on_publish
client.connect(broker_addr, broker_port)
print("Connected to broker")

# # Listen for messages
# client.on_message = on_message
# client.loop_start()
count = 1
smokeReadings = []  # smokesensor readings
tempReadings = []  # temp readings
with open("model.csv", 'r') as file:
    csvreader = csv.DictReader(file)

    for row in csvreader:
        #         print(row['readings'])
        i = row['gas']
        smokeReadings.append(i)
        j = row['temp']
        tempReadings.append(j)
        # count = count + 1
        # if (count >= 50):  # size of count
        #     break

#  print(rows)

for k in range(0, len(smokeReadings)):
    smoke = {
        "time": asctime(),
        "smoke_Reading": smokeReadings[k]
    }
    payload_smoke = json.dumps(smoke)
    client.publish(topic_smoke, payload=payload_smoke, qos=0, retain=False)
    sleep(1)
    temp = {
        "time": asctime(),
        "temperature": tempReadings[k]

    }
    payload_temp = json.dumps(temp)
    client.publish(topic_temp, payload_temp, qos=0, retain=False)
    sleep(1)


import pytest

from typing import Callable
from fibonacci.my_decorator import my_parametrized
from fibonacci import naive, cached
from fixtures import time_tracker

@my_parametrized(identifiers="n,expected", values=[(0, 0), (1, 1), (2, 1), (20, 6765)])
def test_fib_naive(n: int, expected: int) -> None:
    res = naive.fibonacci_naive(n=n)
    assert res == expected

@pytest.mark.parametrize(
    "fib_func",
    [naive.fibonacci_naive, cached.fibonacci_cached, cached.fibonacci_lru_cached],
)
@pytest.mark.parametrize("n,expected", [(0, 0), (1, 1), (2, 1), (20, 6765)])
def test_cached(
    time_tracker, fib_func: Callable[[int], int], n: int, expected: int
) -> None:
    res = fib_func(n)
    assert res == expected


from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

def paddingPKCS7(bytestr, size):
    i = size - (len(bytestr) % size)
    return bytestr + bytes([i] * i)

def padding_validation(text):
    i = text[-1]
    if bytes([i] * i) != text[-i:]:
        raise ValueError('{} bad padding'.format(text))
    return text[:-i]

def encrypt_ecb(plaintext, key, pad = True):
    if pad:
        plaintext = paddingPKCS7(plaintext, len(key))
    encrypt= Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()).encryptor()
    return encrypt.update(plaintext)

def decrypt_ecb(cipertext, key):
    decrypt = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()).decryptor()
    return padding_validation(decrypt.update(cipertext))

def test():
    key = b"YELLOW SUBMARINE"
    plaintext = b"this is a test"
    ciphertext = encrypt_ecb(plaintext, key)
    print(decrypt_ecb(ciphertext, key) == plaintext)

if __name__ == "__main__":
    test()


##******************* Import libaries *******************##
import imageio
import numpy as np
import matplotlib.pyplot as plt
import scipy
import scipy.signal
import math
import time

## ****************** Function ***********************##
# Function rgb to gray
# convert a RGB image to gray image
# Lizhong Wang 6 Feb
def rgb2gray(rgb_image):
    gray_image=1/3*rgb_image[:,:,0]+1/3*rgb_image[:,:,1]+1/3*rgb_image[:,:,2]
    #gray_image=1/3*gray_image;
    return gray_image

# Function 1 dimensional Gaussian filter generator(sigma)
# sigma is the size of Gaussian filter, larger sigma cause image more blurred
# Design the Gaussian filter
# Lizhong Wang 6 Feb
def gaussian_filter_1d(sigma):
    # sigma: the parameter sigma in the Gaussian kernel (unit: pixel)
    #
    # return: a 1D array for the Gaussian kernel
    N = 3*sigma*2+1
    pi = math.pi
    h = np.zeros([1,N])
    for i in range(N):
        h[0,i] = 1/((2*pi)**(1/2)*sigma)*math.exp(-((i-(N-1)/2)**2)/(2*sigma**2));
    h = h/np.sum(h)
    return h

# Function Canny edge detection(gray image input, sigma, threshold)
# Implementation of Canny edge detection
# gray image is size M x N x 1
# sigma is the size of Gaussian filter, larger sigma cause less details in coloring image
# threshold controls the noisy line, low value cause more noisy line
# Lizhong Wang 6 Feb
def Canny(input_directory, output_directory, sigma, threshold=5):
    # input image file
    image = imageio.imread(input_directory)
    image = rgb2gray(image)

    # Design the Prewitt filters
    prewitt_x = np.array([[1,0,-1],[1,0,-1],[1,0,-1]])
    prewitt_y = np.array([[1,1,1],[0,0,0],[-1,-1,-1]])

    # The Gaussian filter along x-axis. Its shape is (1, sz).
    h_x = gaussian_filter_1d(sigma)

    # The Gaussian filter along y-axis. Its shape is (sz, 1).
    h_y = gaussian_filter_1d(sigma).T

    # Perform separable Gaussian smoothing
    image_smoothed = scipy.signal.convolve2d(image,h_x,mode='same',boundary='symm')
    image_smoothed = scipy.signal.convolve2d(image_smoothed,h_y,mode='same',boundary='symm')

    # Prewitt filtering
    image_filtered_x = scipy.signal.convolve2d(image_smoothed,prewitt_x,mode='same',boundary='symm')
    image_filtered_y = scipy.signal.convolve2d(image_smoothed,prewitt_y,mode='same',boundary='symm')

    # Calculate the gradient magnitude
    grad_mag = (image_filtered_x**2+image_filtered_y**2)**(1/2)

    coloring_image=np.zeros(grad_mag.shape)
    cos_thresh=math.cos(22.5/180*math.pi)
    for i in range(1,image.shape[0]-1):
        for j in range(1,image.shape[1]-1):
            vector=np.array([image_filtered_x[i,j],image_filtered_y[i,j]])
            vector=vector/(grad_mag[i,j]+0.0000001)
            if(~(vector[0]>=cos_thresh or vector[0]<=-cos_thresh)):
                if(grad_mag[i,j]>grad_mag[i+1,j] and grad_mag[i,j]>grad_mag[i-1,j]):
                    coloring_image[i,j]=grad_mag[i,j]
            elif(~(vector[1]>=cos_thresh or vector[1]<=-cos_thresh)):
                if(grad_mag[i,j]>grad_mag[i,j+1] and grad_mag[i,j]>grad_mag[i,j-1]):
                    coloring_image[i,j]=grad_mag[i,j]
            elif(~((vector[0]<=cos_thresh and vector[1]<=cos_thresh)or(vector[0]>=-cos_thresh and vector[1]>=-cos_thresh))):
                if(grad_mag[i,j]>grad_mag[i+1,j+1] and grad_mag[i,j]>grad_mag[i-1,j-1]):
                    coloring_image[i,j]=grad_mag[i,j]
            else:
                if(grad_mag[i,j]>grad_mag[i+1,j-1] and grad_mag[i,j]>grad_mag[i-1,j+1]):
                    coloring_image[i,j]=grad_mag[i,j]

    #inverse image binaryzation with user specified threshold

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            if(coloring_image[i,j]>threshold):
                coloring_image[i,j]=0
            else:
                coloring_image[i,j]=255

    # Display the gradient magnitude image
    # plt.imshow(coloring_image, cmap='gray')
    # plt.gcf().set_size_inches(10, 8)
    # plt.show()
    # return image
    # plt.savefig('logo2.png')
    imageio.imsave(output_directory, coloring_image)

##********************** Example Main *************************##

# if __name__ == "__main__":
#     # # Read the image
#     # image = imageio.imread('Logo.png')
#     # image = rgb2gray(image)
#     # # plt.imshow(image, cmap='gray')
#     # # plt.gcf().set_size_inches(10, 8)
#     # # plt.show()
#     # sigma = 5
#     # threshold = 5
#     Canny('Logo.png','Logo2.png',5)


from pydantic import BaseModel
from ai2_kit.core.executor import BaseExecutorConfig, ExecutorManager, Slurm, Lsf, SshConnector, HpcExecutor
from ai2_kit.core.util import load_yaml_file
from ai2_kit.core.artifact import Artifact
from typing import Dict
from unittest import TestCase
from pathlib import Path

class SimpleConfig(BaseModel):
    executors: Dict[str, BaseExecutorConfig]

class TestConfig(TestCase):

    def setUp(self):
        self.config_file = Path(__file__).parent / 'all-in-one.yaml'

    def test_load_config(self):
        data = load_yaml_file(self.config_file)
        config = SimpleConfig.parse_obj(data)

        self.assertIsNone(config.executors['slurm-hpc'].queue_system.lsf)
        self.assertIsNotNone(config.executors['slurm-hpc'].queue_system.slurm)

        self.assertIsNone(config.executors['lsf-hpc'].queue_system.slurm)
        self.assertIsNotNone(config.executors['lsf-hpc'].queue_system.lsf)
        self.assertIsNotNone(config.executors['lsf-hpc'].ssh.gateway)  # type: ignore

class TestExecutor(TestCase):

    def setUp(self):
        self.config_file = Path(__file__).parent / 'all-in-one.yaml'

    def test_executor_manager(self):
        data = load_yaml_file(self.config_file)
        config = SimpleConfig.parse_obj(data)

        executor_manager = ExecutorManager(config.executors)

        executor: HpcExecutor = executor_manager.get_executor('slurm-hpc')  # type: ignore
        self.assertIsInstance(executor, HpcExecutor)
        self.assertIsInstance(executor.queue_system, Slurm)
        self.assertIsInstance(executor.connector, SshConnector)

        executor: HpcExecutor = executor_manager.get_executor('lsf-hpc')  # type: ignore
        self.assertIsInstance(executor, HpcExecutor)
        self.assertIsInstance(executor.queue_system, Lsf)
        self.assertIsInstance(executor.connector, SshConnector)

class TestArtifact(TestCase):

    def test_artifact_transform(self):
        artifact = Artifact(
            url='to/data/path',
            executor='hpc01',
            attrs={'a': 1, 'b': 2},
            includes=None,
            format='',
        )
        dict_obj = artifact.to_dict()
        Artifact.of(**dict_obj)


import numpy as np
import matplotlib.pyplot as plt

A = np.array([[1, 2], [3, 4]])
s0 = np.array([[1], [0]])
s1 = np.array([[0], [1]])

num_points = 100
n1 = np.random.normal(0, 1, (num_points, 1))
n2 = np.random.normal(0, 1, (num_points, 1))
n = np.hstack((n1, n2))

y_s0 = A @ s0 + n
y_s1 = A @ s1 + n

plt.scatter(y_s0[:,0], y_s0[:,1], c='red', label='$\mathbf{y}|\mathbf{s}_0$')
plt.scatter(y_s1[:,0], y_s1[:,1], c='blue', label='$\mathbf{y}|\mathbf{s}_1$')
plt.legend()
plt.xlabel('$y_1$')
plt.ylabel('$y_2$')
plt.savefig('./5.1.1.pdf')
plt.show()


from numpy import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import LDA
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']#使可视化可以显示中文

def getdata(filename1,classnumber):
    '''
    导入单个txt文件，将其转成列表
    :param filename1: 文件名
    :param classnumber: 将其判为哪一类，0or1
    :return: 生成好的data,labels
    '''
    f  = open(filename1)
    lines  = f.readlines()
    mansls= []
    for line in lines:
        a=line.split()
        a= [float(i) for i in a ]
        mansls.append(a)

    manslabels= [classnumber]*shape(mansls)[0]
    return mansls,manslabels

def pca_new(dataMat,n):
    '''

    :param dataMat: 待降维的数据集（已转成矩阵）
    :param n: 需降到的维度
    :return: 降维后的数据集，排序后的特征值，排序后的特征向量
    '''

    meanVals = mean(dataMat, axis=0)
    meanRemoved = dataMat - meanVals
    covMat = cov(meanRemoved, rowvar=0)
    eigvals, eigVects = linalg.eig(mat(covMat))
    eigValInd = argsort(-eigvals)
    taken_eigVects=eigVects[eigValInd[:n],:]#取前N个特征向量
    dataMat = dot(dataMat, taken_eigVects.T)
    final_eigvals=eigvals[eigValInd]
    final_eigVects=eigVects[eigValInd,:]

    return dataMat,final_eigvals,final_eigVects

#读入数据
mansls,manslabels1=getdata('boy.txt',0)
girlsls,girlslabels1=getdata('girl.txt',1)
m=mansls.copy()
g=girlsls.copy()
ml=manslabels1.copy()
gl=girlslabels1.copy()
ml.extend(gl)
alllabels = ml
m.extend(g)
alldatas = mat(m)
#训练集降维
down_Mat,eigvals,eigVects=pca_new(alldatas,2)
eigVects[:2]=eigVects[:2]*300#为了看得见投影面和数据点

#可视化
ax=plt.subplot(223,projection='3d')
plt.title('均一化')
ax.scatter(array((mansls-mean(mansls))/sum(mansls))[:, 0], array((mansls-mean(mansls))/sum(mansls))[:, 1], array((mansls-mean(mansls))/sum(mansls))[:, 2], c='red')
ax.scatter(array((girlsls-mean(girlsls))/sum(girlsls))[:, 0], array((girlsls-mean(girlsls))/sum(girlsls))[:, 1], array((girlsls-mean(girlsls))/sum(girlsls))[:, 2], c='green')

ax=plt.subplot(221,projection='3d')
plt.title('原始数据')
ax.scatter(array(mansls)[:, 0], array(mansls)[:, 1], array(mansls)[:, 2], c='red')
ax.scatter(array(girlsls)[:, 0], array(girlsls)[:, 1], array(girlsls)[:, 2], c='green')

ax=plt.subplot(222,projection='3d')
plt.title('投影平面')
plt.xlim(150,200)
plt.ylim(40,90)

ax.scatter(array(mansls)[:, 0], array(mansls)[:, 1], array(mansls)[:, 2], c='red')
ax.scatter(array(girlsls)[:, 0], array(girlsls)[:, 1], array(girlsls)[:, 2], c='green')
ax.plot_trisurf([0,eigVects[:2][0,0],eigVects[:2][1,0]], [0,eigVects[:2][0,1],eigVects[:2][1,1]],[0,eigVects[:2][0,2],eigVects[:2][1,2]])

plt.subplot(224)
plt.title('投影之后')
plt.scatter(array(down_Mat)[:len(mansls), 0],array(down_Mat)[:len(mansls), 1], c='red')
plt.scatter(array(down_Mat)[len(mansls):, 0], array(down_Mat)[len(mansls):, 1], c='green')

plt.show()

#--------------降维后再使用LDA----------------------
#用降维的数据测试LDA
w,mean1,mean2,group1,group2= LDA.train(down_Mat[:len(mansls), :],down_Mat[len(mansls):, :])
#将测试集降维
testboy,labels=LDA.getdata('boy82.txt',0)
testboy = mat(testboy)
#训练集降维
test_Mat,test_eigvals,test_eigVects=pca_new(testboy,2)
group3=test_Mat.T
count=0
for i in range(shape(group3)[1]):
    if (LDA.predict(group3[:,i].T,w,mean1,mean2))[0,0]>=0:#这里要注意和测试数据对应
        count = count+1
print('降维后的准确率：',count/shape(group3)[1])#降维后有0.96准确率，而没降维只有0.84(用身高，体重)


from tkinter import *
from tkinter import ttk
import sqlite3
root= Tk()
root.state('zoomed')

#table1
s= ttk.Style()
s.theme_use('clam')
tree = ttk.Treeview(root, columns=("c1","c2","c3","c4","c5"),show='headings',height=8)
tree.column("#1",anchor=CENTER)
tree.heading("#1",text='Fname')
tree.column("#2",anchor=CENTER)
tree.heading("#2",text='Lname')
tree.column("#3",anchor=CENTER)
tree.heading("#3",text='Mob Number')
tree.column("#4",anchor=CENTER)
tree.heading("#4",text='Address')
tree.column("#5",anchor=CENTER)
tree.heading("#5",text='Date')
tree.pack()

# date real,id real,subject real,discription real

def insert():
    conn= sqlite3.connect('admin.db')
    c= conn.cursor()
    c.execute("select * from appoint ")
    rows=c.fetchall()
    print(rows)
    for row in rows:
        tree.insert('','end',values=row)

tree.config(height=20)
l1= Label(root,text='Appoinment Details',font=('calibri',51)).place(x=500,y=470)
b1= Button(root,text='SELECT DATA',font=('calibri',18,),border=1,bg='#FFC95C',relief=SOLID,activebackground='#FFC95C',fg='white',width=32,command=insert).place(x=580,y=670)
b2= Button(root,text='UPDATE',font=('calibri',18,),border=1,bg='#FFC95C',relief=SOLID,activebackground='#FFC95C',fg='white',width=32,command=insert).place(x=80,y=670)
b3= Button(root,text='DELETE',font=('calibri',18,),border=1,bg='#FFC95C',relief=SOLID,activebackground='#FFC95C',fg='white',width=32,command=insert).place(x=1080,y=670)

root.mainloop()


import sys
sys.path.append("C:/Users/41774/Desktop/game folder/util")
import pygame
from block import block
import mesh

pygame.init()

screenWidth = 900
screenHeight = 900
win =  pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Tron Game")
clock = pygame.time.Clock()

run = True

Right = 1
Down = 2
Left = 3
Up = 4
blue = (0, 0, 255)
red = (255, 0, 0)
timeCount = 0
hit1 = False
hit2 = False
computer = True
snake2_newblock = block(810, 450)

foo = False

all_blocks = [[foo for i in range(900 // 15)] for j in range(900 // 15)]
block_num = 10

def judge(direct1, direct2, x, y):
    num1 = 0
    num2 = 0
    if direct2 == Right:
        for i in range(900 // 15):
            for j in range(900 // 15):
                if i < (x // 15):
                    if all_blocks[i][j]:
                        num1 += 1
                if i > (x // 15):
                     if all_blocks[i][j]:
                        num2 += 1

    else:
        for i in range(900 // 15):
            for j in range(900 // 15):
                if j < (y // 15):
                    if all_blocks[i][j]:
                        num1 += 1
                if j > (y // 15):
                     if all_blocks[i][j]:
                        num2 += 1
    if num1 > num2:
        return direct2
    else:
        return direct1

class snake(object):
    def __init__(self, x, y, vel, direction):
        self.x = x
        self.y = y
        self.vel = vel
        self.blocks = []
        self.direction = direction

    def move(self, snake_other, num):
        global snake2_newblock
        if not self.blocks:
            new_block = block(self.x, self.y)

        else:
            if self.direction == Right:
                new_block = block(self.blocks[-1].x + 15, self.blocks[-1].y)
                if new_block.x >= screenWidth:
                    return True
            elif self.direction == Left:
                new_block = block(self.blocks[-1].x - 15, self.blocks[-1].y)
                if new_block.x < 0:
                    return True
            elif self.direction == Up:
                new_block = block(self.blocks[-1].x , self.blocks[-1].y - 15)
                if new_block.y < 0:
                    return True
            elif self.direction == Down:
                new_block = block(self.blocks[-1].x, self.blocks[-1].y + 15)
                if new_block.y >= screenHeight:
                    return True

        for i in self.blocks:

            if new_block.x == i.x and new_block.y == i.y:
                return True
        for i in snake_other.blocks:

            if new_block.x == i.x and new_block.y == i.y:
                return True

        all_blocks[new_block.x // 15][new_block.y // 15] = True
        if num == 2:
            snake2_newblock = new_block
        self.blocks.append(new_block)

        return False

    def draw(self, win, color):
        for i in self.blocks:
            i.draw(win, color)

snake1 = snake(90, 450, 15, Right)
snake2 = snake(810, 450, 15, Left)

def redraw():
    win.fill((255, 255, 255))

    snake1.draw(win, red)
    snake2.draw(win, blue)
    mesh.draw_mesh(win, 0, 0, 900, 900, 15, 15)
    pygame.display.update()

while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()
    if snake1.direction != Down and keys[pygame.K_w]:
        snake1.direction = Up
    elif snake1.direction != Up and keys[pygame.K_s]:
        snake1.direction = Down
    elif snake1.direction != Left and keys[pygame.K_d]:
        snake1.direction = Right
    elif snake1.direction != Right and keys[pygame.K_a]:
        snake1.direction = Left

    left_block = False
    right_block = False
    down_block = False
    up_block = False

    if computer:
        for i in range (1, block_num):
            if snake2_newblock.x - i * 15 <= 0:
                left_block = True
            else:
                if all_blocks[(snake2_newblock.x - i * 15) // 15][snake2_newblock.y // 15]:
                    left_block = True
            if snake2_newblock.x + i * 15 >= 900:
                right_block = True
            else:
                if all_blocks[(snake2_newblock.x + i * 15) // 15][snake2_newblock.y // 15]:
                    right_block = True
            if snake2_newblock.y - i * 15 <= 0:
                up_block = True
            else:
                if all_blocks[snake2_newblock.x // 15][(snake2_newblock.y - i * 15) // 15]:
                    up_block = True
            if snake2_newblock.y + i * 15 >= 900:
                down_block = True
            else:
                if all_blocks[snake2_newblock.x // 15][(snake2_newblock.y + i * 15) // 15]:
                    down_block = True

        if snake2.direction == Left:
            if left_block:
                if not up_block and not down_block:
                    snake2.direction = judge(Up, Down, snake2_newblock.x, snake2_newblock.y)
                elif up_block and not down_block:
                    snake2.direction = Down
                elif down_block and not up_block:
                    snake2.direction = Up
                else:
                    block_num -= 1
        if snake2.direction == Up:
            if up_block:
                if not left_block and not right_block:
                    snake2.direction = judge(Left, Right, snake2_newblock.x, snake2_newblock.y)
                elif left_block and not right_block:
                    snake2.direction = Right
                elif right_block and not left_block:
                    snake2.direction = Left
                else:
                    block_num -= 1
        if snake2.direction == Right:
            if right_block:
                if not up_block and not down_block:
                    snake2.direction = judge(Up, Down, snake2_newblock.x, snake2_newblock.y)
                elif up_block and not down_block:
                    snake2.direction = Down
                elif down_block and not up_block:
                    snake2.direction = Up
                else:
                    block_num -= 1
        if snake2.direction == Down:
            if down_block:
                if not left_block and not right_block:
                    snake2.direction = judge(Left, Right, snake2_newblock.x, snake2_newblock.y)
                elif left_block and not right_block:
                    snake2.direction = Right
                elif right_block and not left_block:
                    snake2.direction = Left
                else:
                    block_num -= 1

    else:
        if snake2.direction != Down and keys[pygame.K_UP]:
            snake2.direction = Up
        elif snake2.direction != Up and keys[pygame.K_DOWN]:
            snake2.direction = Down
        elif snake2.direction != Left and keys[pygame.K_RIGHT]:
            snake2.direction = Right
        elif snake2.direction != Right and keys[pygame.K_LEFT]:
            snake2.direction = Left

    if timeCount == 100:
        hit1 = snake1.move(snake2, 1)
        hit2 = snake2.move(snake1, 2)
        timeCount = 0

    redraw()
    timeCount += 1

    if hit1 or hit2:

        if hit1 and hit2:
            text = "tie"
        elif hit1:
            text = "red player lose"
        elif hit2:
            text = "blue player lose"

        font = pygame.font.Font("freesansbold.ttf", 32)

        end_l = font.render(text, True, (255, 0, 0))

        textRect = end_l.get_rect()

        textRect.center = (screenWidth / 2, screenHeight / 2)

        win.blit(end_l, textRect)

        pygame.display.update()

        pygame.time.wait(5000)

        run = False


import time
import sys
import re
import random
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.stem import PorterStemmer
import kb_manager as kbm

# it infers tokens from user input
def tokenize(sentence):
    sentence = sentence.lower()
    word_tokens = word_tokenize(sentence)
    tokenized_sentence = [w for w in word_tokens if w not in stopwords.words('english')]
    return tokenized_sentence

# it replaces the star * with the string in replacement
def replace_a_star(sentence, replacement):
    return sentence.replace("*", replacement)

# it takes the words next to the keyword until it finds an "and", a comma, or a dot
def complete_keywords(sentence, keyword):
    to_add = (sentence.split(keyword)[1]).split("and")[0]
    to_add = to_add.split(",")[0]
    to_add = to_add.split(".")[0]
    modified = keyword + to_add
    return modified

# if the flag is slow, it prints the sentences as if someone was typing
# otherwise it prints the file normally
def my_print_file(file, flag):
    if flag == "slow":
        lines = file.readlines()
        for line in lines:
            for char in line:
                sys.stdout.write(char)
                sys.stdout.flush()
                time.sleep(0.09)
        print("\n")
    else:
        print(file.read())

# if the flag is slow, it prints the sentences as if someone was typing
# otherwise it prints the string normally
def my_print_string(sentence, flag):
    if flag == "slow":
        for char in sentence:
            sys.stdout.write(char)
            sys.stdout.flush()
            time.sleep(0.09)
        print()
    else:
        print(sentence)

# it creates the summary that must be printed in session 2
def create_string_list(list):
    string_list = list[0]
    if len(list) != 1:
        i = 1
        while i < len(list)-1:  # all elements but the last one
            string_list = string_list + ", " + list[i]
            i += 1
        string_list = string_list + ", and " + list[i]
    return string_list

# it adds the needed particles to the given reactions
def add_particles(reaction, keyword):
    composed_sentence = ""
    if "thoughts1" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you are worried they " + reaction
    elif "thoughts2" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you are worried to seem " + reaction
    elif "thoughts3" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you are worried that " + reaction
    elif "phys1" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you become " + reaction
    elif "phys2" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you start " + reaction
    elif "phys3" in keyword or "sft" in keyword or "focus" in keyword or "sit" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you " + reaction
    return composed_sentence

def add_particles_from_topic(reaction):
    typology = kbm.find_typology(reaction)
    replacement = ""
    if typology == "phys1":
        replacement = "become " + reaction
    elif typology == "phys2":
        replacement = "start " + reaction
    elif typology == "phys3":
        replacement = reaction
    return replacement

# it changes the first person in user's sentence to the second person
def to_second_person(reaction):
    reaction = reaction.replace("I ", "you ")
    reaction = reaction.replace(" me", " you")
    reaction = reaction.replace(" my", " your")
    return reaction

# it returns sentence stems
def find_stems(sentence):
    ps = PorterStemmer()
    sentence = sentence.lower()
    words = sentence.split()
    sentence_stems = ""
    for word in words:
        if sentence_stems:
            sentence_stems = sentence_stems + " " + ps.stem(word)
        else:  # the first time the white space must not be present
            sentence_stems = sentence_stems + ps.stem(word)
    print("find_stems:", sentence_stems)
    return sentence_stems

# it takes a sentence from the given topic
def choose_sentence(topic):
    grm = open("data/grammar/" + topic + ".grm", "r")
    topic_file = grm.read()
    grm.close()
    sentences = (topic_file.split(";")[1])
    sentences_list = re.findall("{topic}.+", sentences)
    # . -> Any character (except newline character)
    # + -> One or more occurrences
    sentence = sentences_list[random.randint(0, len(sentences_list)-1)]
    sentence = sentence[7:len(sentence)]  # remove {topic}
    sentence = choose_optional(sentence)
    sentence = choose_slots(sentence)
    sentence = choose_pipe(sentence)
    return sentence

# it decides whether to keep the string between the brackets
def choose_optional(sentence):
    while "[" in sentence:
        index_left_bracket = sentence.find("[")
        index_right_bracket = sentence.find("]")
        in_brackets = sentence[index_left_bracket+1:index_right_bracket]
        include = random.randint(0, 1)
        if include:
            sentence = sentence.replace("[" + in_brackets + "]", in_brackets)
        else:
            sentence = sentence.replace("[" + in_brackets + "]", "")
    return sentence

# it chooses an appropriate slot to be replaced
def choose_slots(sentence):
    system_file = open("data/sistemi.igrm", "r")
    system = system_file.read()
    system_file.close()
    while "{" in sentence:
        index_left_bracket = sentence.find("{")
        index_right_bracket = sentence.find("}")
        slot = sentence[index_left_bracket:index_right_bracket+1]
        synonyms = (system.split(slot+" =\n")[1]).split("\n;")[0]
        syn_list = (synonyms.split("\n"))
        sentence = sentence.replace(slot, syn_list[random.randint(0, len(syn_list)-1)])
    return sentence

# it chooses which part of the string in brackets to keep
def choose_pipe(sentence):
    while "(" in sentence:
        index_left_bracket = sentence.find("(")
        index_right_bracket = sentence.find(")")
        in_brackets = sentence[index_left_bracket+1:index_right_bracket]
        in_brackets_list = in_brackets.split("|")
        chosen = in_brackets_list[random.randint(0, len(in_brackets_list)-1)]
        sentence = sentence.replace("("+in_brackets+")", chosen)
    return sentence


from spotipy import Spotify, CacheFileHandler
from flask import request, session, url_for, redirect, render_template, flash, jsonify
from .helpers import CACHE_FOLDER, create_spotify_oauth, get_recommended_tracks, create_playlist
from . import app
import os

track_list = []

@app.before_request
def make_session_permanent():
    session.permanent = True

# route for login page
@app.route('/', methods=('GET', 'POST'))
def login():

    if request.method == 'GET':

        # retrieve user ID from session
        if session.get("user_id"):
            user_id = session.get("user_id")

            # create SpotifyOAuth pbject for user
            oauth_obj = create_spotify_oauth(user_id)

            # get the user cache file
            cache_file = CacheFileHandler(cache_path=os.path.join(CACHE_FOLDER, f".cache-{user_id}"))

            # get access token from user if applicable
            token = cache_file.get_cached_token()

            if token:
                # refreshes token
                if oauth_obj.is_token_expired(token):
                    oauth_obj.refresh_access_token(token['refresh_token'])

                flash(f"Welcome back {user_id}!", category="info")

                # user is authenticated and redirected to home page
                return redirect(url_for("home"))

            # redirect user to Spotify Auth Page
            else:
                return redirect(oauth_obj.get_authorize_url(state=user_id))

        # return login page if no user ID
        else:
            return render_template("base.html")

    # create OAuth object and redirect to Spotify Auth Page
    if request.method == 'POST':
        # get user ID from forms
        input_id = request.form.get("user_id").strip()
        oauth_obj = create_spotify_oauth()

        return redirect(oauth_obj.get_authorize_url(state=input_id))

# route to handle Spotify API callback
@app.route('/callback/')
def callback():
    # prevent direct access to the route
    if not request.args.get("code"):
        flash("Can't access this URL directly.", category="danger")
        return redirect('/')

    # retrieve the value from state parameter
    state = request.args.get("state")
    oauth_obj = create_spotify_oauth(state)
    token_info = oauth_obj.get_access_token(request.args.get('code'))
    spotify_API = Spotify(auth=token_info['access_token'], auth_manager=oauth_obj)

    # get Spotify User ID of current user
    user_id = spotify_API.current_user()['id']

    if user_id == state:
        # create cache file and write token information for current user
        cache_file = CacheFileHandler(cache_path=os.path.join(CACHE_FOLDER, f".cache-{state}"))
        cache_file.save_token_to_cache(token_info)

        # store user ID in session
        session['user_id'] = state
        flash(f"Logged in as {user_id}", category="info")
        return redirect(url_for('home'))

    else:
        os.remove(os.path.join(CACHE_FOLDER, f".cache-{state}"))
        flash(f"{state} does not exist", category="danger")
        return redirect(url_for('login'))

# route for main page
@app.route('/home', methods=('GET', 'POST'))
def home():
    tracks = None

    # prevent unauthorized users
    if not session.get("user_id"):
        flash(f"Please log in first", category='danger')
        return redirect('/')

    if request.method == 'POST':
        oauth_obj = create_spotify_oauth(session.get("user_id"))
        count = request.form.get("count")
        playlist = request.form.get("playlist")

        # validate input
        if count:
            # input contains alphabetical characters
            if not all(char.isdigit() for char in count):
                flash("You did not enter a number", category='danger')

            elif int(count) not in range(1, 51):
                flash("Number out of range", category='danger')

            else:
                track_list.clear()

                # create a connection to Spotify API
                spotify_API = Spotify(auth_manager=oauth_obj)

                # get recommended tracks for user
                tracks, genre = get_recommended_tracks(spotify_API, int(count))
                if not tracks:
                    flash("We couldn't generate recommendations based on your recent listening history. Try to listen to more songs!", category='danger')
                else:
                    for track in tracks['tracks']:
                        track_list.append(track['id'])
                    flash(f"Recommendations generated! You listened to {genre} the most!", category='info')

        if playlist:
            playlist = create_playlist(playlist, track_list, session.get("user_id"))
            track_list.clear()
            tracks = None
            flash(f"Playlist {playlist} created successfully!", category='info')

    # get request
    return render_template("search.html", tracks=tracks)

# route for handling user logout
@app.route('/logout')
def logout():
    # check if incoming request is AJAX request
    is_ajax = request.headers.get('X-Requested-With')

    # AJAX request
    if is_ajax:
        user_id = session.get("user_id")
        session.clear()
        os.remove(os.path.join(CACHE_FOLDER, f".cache-{user_id}")) if user_id is not None else None

        # return successful log out in JSON
        return jsonify(success=True)

    else:
        if not session.get("user_id"):
            flash(f"Please log in first", category='danger')
            return redirect('/')

@app.route('/post_spotify_logout')
def post_spotify_logout():
    is_ajax = request.headers.get('X-Requested-With')
    if is_ajax:
        flash("You have been logged out!", category='info')

        # return redirect URL in JSON
        return jsonify(redirect_url="/")

    else:
        if not session.get("user_id"):
            flash(f"Unauthorized access", category='danger')
            return redirect('/')