# this was to test webscraping.
# Program contains way to many returns and spaghetti code
# This scrapes all users who follow an account - Wattcat 2021-04-10
from bs4 import BeautifulSoup
import requests
import os

# Checks if supplied username is valid. Otherwise returns false
def isValid(username):
    isValidUser = True
    privateexeption = ["The owner of this page has elected to make it available to registered users only.",
                       "Provided username not found in the database."]
    url = "https://www.furaffinity.net/watchlist/to/{}/".format(username)
    currentpage = requests.get(url)
    soup = BeautifulSoup(currentpage.content, 'html.parser')  # sorts with bs4
    private = soup.find_all('div', {"class": "section-body alignleft"})
    # This is to check if a profile is private or non existent
    if privateexeption[0] in str(private) or privateexeption[1] in str(private):
        isValidUser = False
    return isValidUser

# Returns a list of unique user accounts
def pageScraper(select, username):
    users = []
    pos = 0
    while True:
        url = 'https://www.furaffinity.net/watchlist/{}/{}/{}/?'.format(
            select, username, pos)
        currentpage = requests.get(url)
        soup = BeautifulSoup(currentpage.content,
                             'html.parser')  # sorts with bs4
        betterdivs = soup.find_all('a', href=True)
        print("scraping users at page:", url)
        try:  # this is to catch out of range errors
            contentlist = str(betterdivs).split("</a>")
            for i in range(len(contentlist)):
                scrapedusername = contentlist[i].split(">")[1]  # Usernames
                if scrapedusername not in users:
                    users.append(scrapedusername)

        except Exception as e:
            # print(e)
            pass

            if (len(str(soup)) < 4500):
                print("End of the line!")
                return users
                break
            pos += 1

# This is used by UI for user selection
def selector():
    selection = input(
        "Select mode:\n1. Get what user is Watching \n2. Get Watchers/followers \n3. Get both \n")
    selection = selection.strip()
    if selection == "1":
        return "by"
    elif selection == "2":
        return "to"
    elif selection == "3":
        return "both"
    else:
        print("Please enter a valid number")
        selection()

# used for writing everything to a file
def writer(path, lists):
    with open(path, 'a') as a_writer:
        for s in lists:
            a_writer.write(str(s) + "\n")
        a_writer.close
        return "Done"

# simple user interface in terminal
def UI():
    username = input("Enter a non private Username:\n")
    if isValid(username) == True:
        mypath = os.path.join(os.getcwd(), input(
            "Please enter output file name:\n(Note: Will output in current working folder) \n"))
        selected = selector()
        if selected == "both":
            followers = pageScraper("to", username)
            following = pageScraper("by", username)
            users = (
                followers + ["\nAll {} is watching".format(username)] + following)
        else:
            users = pageScraper(selected, username)
        writer(mypath, users)
    else:
        print("Error username is not valid")
        return UI()

UI()


# Silver 3 - 수 이어 쓰기

from collections import deque
import sys
input = sys.stdin.readline

s = deque(input().rstrip())
i = 0

while True:
    i += 1
    num = deque(str(i))

    while num and s:
        if s[0] == num[0]:
            s.popleft()
        num.popleft()

    if not s:
        print(i)
        break


# https://adventofcode.com/2020/day/10
#%%

with open("sample1.txt") as f:
    numbers = [int(n) for n in f.read().split("\n")]

#%%

with open("sample2.txt") as f:
    numbers = [int(n) for n in f.read().split("\n")]

#%%

with open("input.txt") as f:
    numbers = [int(n) for n in f.read().split("\n")]

#%%

def part_one(numbers):
    # We need to start from 0
    numbers = sorted(numbers + [0])

    one_diff = 0
    three_diff = 0

    for i in range(len(numbers) - 1):
        diff = numbers[i + 1] - numbers[i]

        if diff > 3:
            break
        if diff == 3:
            three_diff += 1
        if diff == 1:
            one_diff += 1

    # builtin difference
    three_diff += 1

    return one_diff * three_diff

part_one(numbers)

# %%
from functools import cache  # Python 3.9

def part_two(numbers):
    # We need to start from 0
    numbers = sorted(numbers + [0])

    @cache
    def possible_paths(index):
        paths = 0

        for i in range(index + 1, len(numbers)):
            if numbers[i] - numbers[index] > 3:
                break

            paths += possible_paths(i)

        if paths == 0:
            # if no possible paths, we arrived to the end
            return 1

        return paths

    return possible_paths(0)

part_two(numbers)
# %%


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

def add_phones(apps, schema_editor):
    Quest = apps.get_model("main", "Quest")
    for quest in Quest.objects.all():
        if quest.address == 'Алтайская 8/3':
            quest.phone = "94-29-10"
        else:
            quest.phone = "54-06-04"
        quest.save()

class Migration(migrations.Migration):

    dependencies = [
        ('main', '0014_auto_20151111_2324'),
    ]

    operations = [
        migrations.AddField(
            model_name='quest',
            name='phone',
            field=models.CharField(verbose_name='Телефон', null=True, blank=True, max_length=255),
            preserve_default=True,
        ),
        migrations.RunPython(add_phones),
    ]


# -*- coding: utf-8 -*-
# @Time : 2023/5/8 16:35
# @Author : xxxx-2
# @E-mail : xxxx-1@gmail.com
# @Site :
# @project: vehicle_dispatch
# @File : pre_training_test.py
# @Software: PyCharm

import logging
import random
import time

import torch
from tensorboardX import SummaryWriter
from torch import nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
import numpy as np
import pickle as pkl
from config import parser
from model.DSEmb.graphbase import NCModel
from model.RL.DDT_v2 import DDT
from model.RL.layers import Reward, Actor, Critic
from utils.clear_model_logs import clear
from utils.data_utils import DS_data, TrajData, TrajAllData
from utils.eval_utils import acc_f1, action_accuracy
from utils.train_utils import format_metrics, select_action

if __name__ == "__main__":
    tmp_path = './'

    clear(tmp_path)

    logging.getLogger().setLevel(logging.ERROR)

    args = parser.parse_args()

    args.log_dir = tmp_path + args.log_dir
    args.trajectory_pos = tmp_path + args.trajectory_pos
    args.trajectory_neg = tmp_path + args.trajectory_neg
    args.trajectory_all = tmp_path + args.trajectory_all
    args.multigraph_adj = tmp_path + args.multigraph_adj
    args.multigraph_fea = tmp_path + args.multigraph_fea

    args.device = torch.device("cpu")
    if args.cuda >= 0:
        args.device = torch.device("cuda:" + str(args.cuda))

    ID = 0
    # tensorboardX logbook
    Writer = SummaryWriter(args.log_dir + '/tensorboard/' +  str(ID) + '/')

    # read data
    ## graph data ##
    DSDATA = DS_data(args)
    DS_dataloader = DataLoader(DSDATA, batch_size=4, shuffle=True, num_workers=1)
    ### get node number, node feature dimension
    for i, batch in enumerate(DS_dataloader):
        a, b, c, a_label, b_label, c_label = batch
        args.n_nodes = a.shape[1]
        args.feat_dim = a.shape[2]
        break
    adj_G2, adj_G5, adj_G10 = DSDATA.get_adj()
    fea_G2, fea_G5, fea_G10 = DSDATA.get_all_fea()
    ## trajectory data
    contrast_mode_str = 'all'
    trajdata = TrajAllData(args)
    Traj_dataloader = DataLoader(trajdata, batch_size=args.batch_size, shuffle=True, num_workers=1)
    ### get feature dimension, contrast output dimension
    args.in_dim = -1
    if contrast_mode_str == 'all':
        args.out_dim = 50
        args.avg = 'micro'
    else:
        args.out_dim = 2
        args.avg = 'binary'
    for i, batch in enumerate(Traj_dataloader):
        vid, state, action, reward = batch
        args.in_dim = state.shape[2] + action.shape[2]
        break
    ## positive Trajectory data
    f = open(args.trajectory_pos, 'rb')
    pos_list = pkl.load(f)
    f.close()
    MAX_FEE = 1.0
    for i in range(len(pos_list)):
        if i == 0:
            data = pos_list[i]['data']
            label = pos_list[i]['label']
            static_reward = pos_list[i]['reward']
            MAX_FEE = max(static_reward)
        else:
            data = np.r_[data, pos_list[i]['data']]
            label = np.r_[label, pos_list[i]['label']]
            static_reward = np.r_[static_reward, pos_list[i]['reward']]
            if MAX_FEE < max(static_reward):
                MAX_FEE = max(static_reward)
    # print('MAX_FEE:', MAX_FEE)
    # print('data shape:', data.shape)
    # print('label shape:', label.shape)
    # print('static_reward shape:', static_reward.shape)
    data = torch.tensor(data)
    label = torch.tensor(label)
    static_reward = torch.tensor(static_reward)
    args.num_state = int(data.shape[-1] + args.graph_dim * (adj_G2.shape[0] + adj_G5.shape[0] + adj_G10.shape[0]))
    args.num_ation = int(label.shape[-1] - 1)
    print('num state:', args.num_state)
    print('num ation:', args.num_ation)

    traj_data_list = []
    label_list = []
    static_reward_list = []
    MAX_FEE_list = []
    # multicar trajectory data
    for carid in range(args.max_car_num):
        ## positive Trajectory data
        f = open(tmp_path+'data/hangzhou/one_traj/' + str(carid) + '.pkl', 'rb')
        data_list = pkl.load(f)
        f.close()
        MAX_FEE = 1.0
        for i in range(len(data_list)):
            if i == 0:
                tmp_data = data_list[i]['data']
                tmp_label = data_list[i]['label']
                tmp_static_reward = data_list[i]['reward']
                tmp_MAX_FEE = max(tmp_static_reward)
            else:
                tmp_data = np.r_[tmp_data, data_list[i]['data']]
                tmp_label = np.r_[tmp_label, data_list[i]['label']]
                tmp_static_reward = np.r_[tmp_static_reward, data_list[i]['reward']]
                if tmp_MAX_FEE < max(tmp_static_reward):
                    tmp_MAX_FEE = max(tmp_static_reward)
        tmp_data = torch.tensor(tmp_data)
        tmp_label = torch.tensor(tmp_label)
        tmp_static_reward = torch.tensor(tmp_static_reward)

        if not args.cuda == -1:
            tmp_data = tmp_data.to(args.device)
            tmp_label = tmp_label.to(args.device)
            tmp_static_reward = tmp_static_reward.to(args.device)
        traj_data_list.append(tmp_data)
        label_list.append(tmp_label)
        static_reward_list.append(tmp_static_reward)
        MAX_FEE_list.append(tmp_MAX_FEE)

    # define graph embedding model
    model_G2 = NCModel(args)
    model_G5 = NCModel(args)
    model_G10 = NCModel(args)
    model_r = Reward(args.in_dim, args.dim, args.out_dim, batch_size=args.batch_size)
    model_ddt = DDT(state_dim=args.num_state,
                    act_dim=args.num_ation,
                    max_length=args.max_len,
                    max_ep_len=150, # maximum length of a trajectory
                    hidden_size=args.dim,
                    n_layer=args.num_layers,
                    n_head=args.n_heads,
                    n_inner=4 * args.dim,
                    activation_function=args.act_gpt,
                    n_positions=256,
                    resid_pdrop=args.dropout,
                    attn_pdrop=args.dropout,
                    )

    # model & data to device
    if not args.cuda == -1:
        model_G2 = model_G2.to(args.device)
        model_G5 = model_G5.to(args.device)
        model_G10 = model_G10.to(args.device)
        model_r = model_r.to(args.device)
        model_ddt = model_ddt.to(args.device)

        adj_G2 = adj_G2.to(args.device)
        adj_G5 = adj_G5.to(args.device)
        adj_G10 = adj_G10.to(args.device)
        fea_G2 = fea_G2.to(args.device)
        fea_G5 = fea_G5.to(args.device)
        fea_G10 = fea_G10.to(args.device)

    # define learning rate reduce frequency
    if not args.lr_reduce_freq:
        args.lr_reduce_freq = args.epochs

    # define optimizer
    opt_G2 = torch.optim.Adam(params=model_G2.parameters(), lr=args.lr, weight_decay=args.weight_decay)
    opt_G5 = torch.optim.Adam(params=model_G5.parameters(), lr=args.lr, weight_decay=args.weight_decay)
    opt_G10 = torch.optim.Adam(params=model_G10.parameters(), lr=args.lr, weight_decay=args.weight_decay)
    opt_r = torch.optim.Adam(params=model_r.parameters(), lr=args.lr, weight_decay=args.weight_decay)
    opt_ddt = torch.optim.Adam(params=model_ddt.parameters(), lr=args.lr, weight_decay=args.weight_decay)

    lr_scheduler_G2 = torch.optim.lr_scheduler.StepLR(opt_G2,step_size=int(args.lr_reduce_freq),gamma=float(args.gamma))
    lr_scheduler_G5 = torch.optim.lr_scheduler.StepLR(opt_G5,step_size=int(args.lr_reduce_freq),gamma=float(args.gamma))
    lr_scheduler_G10 = torch.optim.lr_scheduler.StepLR(opt_G10,step_size=int(args.lr_reduce_freq),gamma=float(args.gamma))
    lr_scheduler_r = torch.optim.lr_scheduler.StepLR(opt_r,step_size=int(args.lr_reduce_freq),gamma=float(args.gamma))
    lr_scheduler_ddt = torch.optim.lr_scheduler.LambdaLR(opt_ddt, lambda steps: min((steps + 1) / args.warm_steps, 1))

    # define loss function
    CEloss = nn.CrossEntropyLoss()
    BCEloss = nn.BCELoss()
    MSEloss = nn.MSELoss()
    # action_loss = lambda s_hat, a_hat, r_hat, s, a, r: torch.mean((a_hat - a) ** 2) # MSEloss(a_hat[:,1], a[:,1]) + BCEloss(a_hat[:,0], torch.round(a[:,0]))
    # action_loss = lambda s_hat, a_hat, r_hat, s, a, r: torch.mean(torch.minimum(torch.minimum( (a_hat - a) ** 2, ((a_hat+1) - a) ** 2 ), (a_hat - (a+1)) ** 2))
    action_loss = lambda s_hat, a_hat, r_hat, s, a, r: torch.mean(
        torch.minimum(torch.minimum((a_hat[:,1] - a[:,1]) ** 2, ((a_hat[:,1] + 1) - a[:,1]) ** 2), (a_hat[:,1] - (a[:,1] + 1)) ** 2) + (a_hat[:,0] - a[:,0]) ** 2)

    global_training_step = 0
    tmp_losses = []
    tmp_accs = []
    for ep in range(args.epochs):
        print('Epoch:', str(ep+1).zfill(4))

        # graph embedding part
        print('Graph embedding...')
        for i, batch in enumerate(DS_dataloader):
            t = time.time()
            a, b, c, a_label, b_label, c_label = batch
            if not args.cuda == -1:
                a = a.to(args.device)
                b = b.to(args.device)
                c = c.to(args.device)
                a_label = a_label.to(args.device)
                b_label = b_label.to(args.device)
                c_label = c_label.to(args.device)

            model_G2.train()
            opt_G2.zero_grad()
            embeddings_G2 = model_G2.encode(a, adj_G2)
            # print('test train emb shape:', embeddings.shape)
            train_metrics_g2 = model_G2.compute_metrics(embeddings_G2, adj_G2, a_label)
            train_metrics_g2['loss'].backward()
            if args.grad_clip is not None:
                max_norm = float(args.grad_clip)
                all_params = list(model_G2.parameters())
                for param in all_params:
                    torch.nn.utils.clip_grad_norm_(param, max_norm)
            opt_G2.step()
            lr_scheduler_G2.step()

            model_G5.train()
            opt_G5.zero_grad()
            embeddings_G5 = model_G5.encode(b, adj_G5)
            # print('test train emb shape:', embeddings.shape)
            train_metrics_g5 = model_G5.compute_metrics(embeddings_G5, adj_G5, b_label)
            train_metrics_g5['loss'].backward()
            if args.grad_clip is not None:
                max_norm = float(args.grad_clip)
                all_params = list(model_G5.parameters())
                for param in all_params:
                    torch.nn.utils.clip_grad_norm_(param, max_norm)
            opt_G5.step()
            lr_scheduler_G5.step()

            model_G10.train()
            opt_G10.zero_grad()
            embeddings_G10 = model_G10.encode(c, adj_G10)
            # print('test train emb shape:', embeddings.shape)
            train_metrics_g10 = model_G10.compute_metrics(embeddings_G10, adj_G10, c_label)
            train_metrics_g10['loss'].backward()
            if args.grad_clip is not None:
                max_norm = float(args.grad_clip)
                all_params = list(model_G10.parameters())
                for param in all_params:
                    torch.nn.utils.clip_grad_norm_(param, max_norm)
            opt_G10.step()
            lr_scheduler_G10.step()

            if (i + 1) % args.log_freq == 0:
                logging.info(" ".join(['Epoch: {:04d}'.format(i + 1),
                                       'lr_G2: {}'.format(lr_scheduler_G2.get_last_lr()[0]),
                                       'lr_G5: {}'.format(lr_scheduler_G5.get_last_lr()[0]),
                                       'lr_G10: {}'.format(lr_scheduler_G10.get_last_lr()[0]),
                                       format_metrics(train_metrics_g2, 'train'),
                                       format_metrics(train_metrics_g5, 'train'),
                                       format_metrics(train_metrics_g10, 'train'),
                                       'time: {:.4f}s'.format(time.time() - t)
                                       ]))
        model_G10.eval()
        model_G5.eval()
        model_G2.eval()
        print('Graph embedding finished!')
        # got embeddings_G2, embeddings_G5 and embeddings_G10
        # print('embedding G2 shape:', embeddings_G2.shape)
        # print('embedding G5 shape:', embeddings_G5.shape)
        # print('embedding G10 shape:', embeddings_G10.shape)

        # dynamic reward part
        print('Dynamic reward function updating...')
        loss = 0
        acc = 0
        f1 = 0
        cnt = 0
        for i, batch in enumerate(Traj_dataloader):
            t = time.time()
            vid, state, action, reward = batch
            # print('vid:', vid)
            if state.shape[0] < args.batch_size:
                continue
            hidden = model_r.init_hidden()
            if not args.cuda == -1:
                vid = vid.to(args.device)
                state = state.to(args.device)
                action = action.to(args.device)
                hidden = hidden.to(args.device)
            x = torch.cat([state, action], dim=2).float()
            vid = vid.long()

            model_r.train()
            opt_r.zero_grad()
            pred, _ = model_r.forward(x, hidden)
            tmp_loss = CEloss(pred, vid)
            tmp_acc, tmp_f1 = acc_f1(pred, vid, average=args.avg)
            loss += tmp_loss
            acc += tmp_acc
            f1 += tmp_f1
            cnt += 1
            loss.backward()
            if args.grad_clip is not None:
                max_norm = float(args.grad_clip)
                all_params = list(model_r.parameters())
                for param in all_params:
                    torch.nn.utils.clip_grad_norm_(param, max_norm)
            opt_r.step()
            lr_scheduler_r.step()

            if (i + 1) % args.log_freq == 0:
                Writer.add_scalar('Dynamic Reward Accuracy', f1/cnt, global_step=global_training_step)
                Writer.add_scalar('Dynamic Reward loss', loss / cnt, global_step=global_training_step)
                logging.info(" ".join(['Epoch: {:04d}'.format(i + 1),
                                       'lr: {}'.format(lr_scheduler_r.get_last_lr()[0]),
                                       'loss: {}'.format(loss / cnt),
                                       'acc: {}'.format(acc / cnt),
                                       'f1: {}'.format(f1 / cnt),
                                       'time: {:.4f}s'.format(time.time() - t)
                                       ]))
                acc = 0
                f1 = 0
                loss = 0
                cnt = 0
        print('Dynamic reward function updated!')

        for carid in range(args.max_car_num):
            data = traj_data_list[carid]
            # print(data.shape)
            label = label_list[carid]
            static_reward = static_reward_list[carid]
            MAX_FEE = MAX_FEE_list[carid]

            # get dynamcic reward
            model_r.eval()
            print('Batch data calculating...')
            R = 0
            Gt = []
            for ind in range(len(static_reward)-1, -1, -1):
                state = data[ind].unsqueeze(0).unsqueeze(0)
                # print('test state shape:', state.shape)
                true_action = label[ind].unsqueeze(0).unsqueeze(0)
                # print('test action shape:', true_action.shape)
                x = torch.cat([state, true_action], dim=2).float()
                hidden = model_r.init_hidden(1).to(args.device)
                pred, _ = model_r.forward(x, hidden)
                pred = pred.squeeze()
                # print('test pred shape:', pred.shape)
                alpha = 0.05
                R = alpha * (static_reward[ind] / MAX_FEE) + (1 - alpha) * pred[carid] + args.reward_gamma * R
                Gt.insert(0, torch.nan_to_num(R))
            Gt = torch.tensor(Gt, dtype=torch.float).to(args.device)
            # print('R shape:', Gt.shape)

            T_MAX = 144 # Gt.shape[0]
            t_start = random.randint(0, T_MAX - 1)
            print('t_start:', t_start)
            state_dim = -1
            action_vec_dim = -1
            TMOD = T_MAX
            for tt in range(args.update_freq):
                for bs in range(args.batch_size):
                    timestep = []
                    attention_mask = []
                    for ind in range(args.max_len):
                        t = t_start + ind
                        if t % TMOD < T_MAX:
                            tt = time.time()
                            graph_fea_G2 = fea_G2[t].unsqueeze(0)
                            graph_fea_G5 = fea_G5[t].unsqueeze(0)
                            graph_fea_G10 = fea_G10[t].unsqueeze(0)

                            G2_emb = model_G2.encode(graph_fea_G2, adj_G2).detach()
                            G5_emb = model_G5.encode(graph_fea_G5, adj_G5).detach()
                            G10_emb = model_G10.encode(graph_fea_G10, adj_G10).detach()
                            G2_emb = G2_emb.view(1, -1)
                            G5_emb = G5_emb.view(1, -1)
                            G10_emb = G10_emb.view(1, -1)

                            tmp_state = data[t].unsqueeze(0).to(torch.float32)

                            if ind == 0:
                                true_action_vec = label[t][:2].unsqueeze(0)
                                true_action = label[t][2].unsqueeze(0)
                                state = torch.concatenate([tmp_state, G2_emb, G5_emb, G10_emb], dim=1)
                                # state = torch.concatenate([tmp_state, G2_emb], dim=1)
                                R = Gt[t].view(-1, 1)

                                # print('state shape:', state.shape)
                                state_dim = state.shape[1]
                                # print('R shape:', R.shape)
                                # print('action shape:', true_action_vec.shape)
                                action_vec_dim = true_action_vec.shape[1]
                                # print('action shape:', true_action.shape)
                                timestep.append(t % TMOD)
                                attention_mask.append(1.0)
                            else:
                                true_action_vec = torch.concatenate([true_action_vec, label[t][:2].unsqueeze(0)], dim=0)
                                true_action = torch.concatenate([true_action, label[t][2].unsqueeze(0)], dim=0)
                                tmp_state2 = torch.concatenate([tmp_state, G2_emb, G5_emb, G10_emb], dim=1)
                                # tmp_state2 = torch.concatenate([tmp_state, G2_emb], dim=1)
                                state = torch.concatenate([state, tmp_state2], dim=0)
                                R = torch.concatenate([R, Gt[t].view(-1, 1)], dim=0)
                                timestep.append(t % TMOD)
                                attention_mask.append(1.0)

                                # print('state shape (add):', state.shape)
                                # print('R shape (add):', R.shape)
                                # print('action shape (add):', true_action.shape)
                        else:
                            tmp_len = int(args.max_len - ind)
                            true_action_vec = torch.concatenate([true_action_vec, torch.zeros(tmp_len,action_vec_dim).to(args.device)], dim=0)
                            true_action = torch.concatenate([true_action, torch.zeros(tmp_len).to(args.device)], dim=0)
                            state = torch.concatenate([state, torch.zeros(tmp_len, state_dim).to(args.device)], dim=0)
                            R = torch.concatenate([R, torch.zeros(tmp_len,1).to(args.device)], dim=0)
                            for _ in range(tmp_len):
                                timestep.append(0)
                                attention_mask.append(0.0)

                            # print('state shape (else):', state.shape)
                            # print('R shape (else):', R.shape)
                            # print('action shape (else):', true_action_vec.shape)
                            break
                    if bs == 0:
                        bs_state = state.unsqueeze(0)
                        bs_R = R.unsqueeze(0)
                        bs_true_action_vec = true_action_vec.unsqueeze(0)
                        bs_true_action = true_action.unsqueeze(0)
                        bs_timestep = torch.tensor(timestep).unsqueeze(0).to(args.device)
                        bs_attention_mask = torch.tensor(attention_mask).unsqueeze(0).to(args.device)
                    else:
                        bs_state = torch.concatenate([bs_state, state.unsqueeze(0)], dim=0)
                        bs_R = torch.concatenate([bs_R, R.unsqueeze(0)], dim=0)
                        bs_true_action_vec = torch.concatenate([bs_true_action_vec, true_action_vec.unsqueeze(0)], dim=0).float()
                        bs_true_action = torch.concatenate([bs_true_action, true_action.unsqueeze(0)], dim=0)
                        bs_timestep = torch.concatenate([bs_timestep, torch.tensor(timestep).unsqueeze(0).to(args.device)], dim=0)
                        bs_attention_mask = torch.concatenate([bs_attention_mask, torch.tensor(attention_mask).unsqueeze(0).to(args.device)], dim=0)

                t = time.time()

                action_target = torch.clone(bs_true_action_vec)
                action_compare = torch.clone(bs_true_action)

                state_preds, action_preds, reward_preds = model_ddt.forward(
                    bs_state, bs_true_action_vec, bs_R, bs_timestep, attention_mask=bs_attention_mask
                )

                # print('pre_traininig_test action compare:', action_preds[0, 0], action_target[0, 0])

                action_preds = action_preds.reshape(-1, args.num_ation)[bs_attention_mask.reshape(-1) > 0]
                action_target = action_target.reshape(-1, args.num_ation)[bs_attention_mask.reshape(-1) > 0]
                action_compare = action_compare.reshape(-1)[bs_attention_mask.reshape(-1) > 0]

                loss = action_loss(
                    None, action_preds, None,
                    None, action_target, None,
                )

                opt_ddt.zero_grad()
                loss.backward()
                torch.nn.utils.clip_grad_norm_(model_ddt.parameters(), .25)
                opt_ddt.step()

                with torch.no_grad():
                    loss_value = loss.detach().cpu().item()
                    tmp_losses.append(loss_value)
                    Writer.add_scalar('DDT loss:', loss_value, global_step=global_training_step)
                    if (i + 1) % args.log_freq == 0:
                        logging.info(" ".join(['Epoch: {:04d}'.format(global_training_step + 1),
                                               'DDT Loss: {}'.format(loss_value),
                                               'time: {:.4f}s'.format(time.time() - t)
                                               ]))

                global_training_step += 1
            print('DDT loss mean:', np.mean(tmp_losses))
            print('DDT loss std:', np.std(tmp_losses))


import math
import torch
import torch.nn as nn

class ClusterLoss(nn.Module):
    def __init__(self, class_num, corr_mask_clust_num, temperature=1.0, device="cuda"):
        super(ClusterLoss, self).__init__()
        self.class_num = class_num
        self.temperature = temperature
        self.device = device

        self.mask = corr_mask_clust_num
        self.criterion = nn.CrossEntropyLoss(reduction="sum")
        self.similarity_f = nn.CosineSimilarity(dim=2)

    def forward(self, c_i, c_j):
        p_i = c_i.sum(0).view(-1)
        p_i /= p_i.sum()
        ne_i = math.log(p_i.size(0)) + (p_i * torch.log(p_i)).sum()
        p_j = c_j.sum(0).view(-1)
        p_j /= p_j.sum()
        ne_j = math.log(p_j.size(0)) + (p_j * torch.log(p_j)).sum()
        ne_loss = ne_i + ne_j

        c_i = c_i.t()
        c_j = c_j.t()
        N = 2 * self.class_num
        c = torch.cat((c_i, c_j), dim=0)

        sim = self.similarity_f(c.unsqueeze(1), c.unsqueeze(0)) / self.temperature
        sim_i_j = torch.diag(sim, self.class_num)
        sim_j_i = torch.diag(sim, -self.class_num)

        positive_clusters = torch.cat((sim_i_j, sim_j_i), dim=0).reshape(N, 1)
        negative_clusters = sim[self.mask].reshape(N, -1)

        labels = torch.zeros(N).to(positive_clusters.device).long()
        logits = torch.cat((positive_clusters, negative_clusters), dim=1)
        loss = self.criterion(logits, labels)
        loss /= N

        return loss + ne_loss


def cal(v1, v2, o):
    if o == '+':
        return v1 + v2
    elif o == '-':
        return v1 - v2
    elif o == '*':
        return v1 * v2
    else:
        return v1 // v2

for test_case in range(1, 11):
    n = int(input())
    tree = [[] for _ in range(n + 1)]
    dic = {}
    res = []
    for _ in range(n):
        lst = list(map(str, input().split()))
        if lst[1].isdigit():
            dic[int(lst[0])] = int(lst[1])
        else:
            dic[int(lst[0])] = lst[1]

        if len(lst) > 2:
            tree[int(lst[0])].append(int(lst[2]))
        if len(lst) == 4:
            tree[int(lst[0])].append(int(lst[3]))

    def inorder(n):
        if tree[n]:
            inorder(tree[n][0])
        if tree[n]:
            inorder(tree[n][1])
        res.append(dic[n])
        if res[-1] == '+' or res[-1] == '-' or res[-1] == '*' or res[-1] == '/':
            o = res.pop()
            v2 = res.pop()
            v1 = res.pop()
            res.append(cal(v1, v2, o))

    inorder(1)

    print(f'#{test_case}', res[0])


import datetime as dt
from dateutil.relativedelta import relativedelta
import pandas as pd
from xmlrpc import client

def replace(cell, index=1):
    '''
    to replace many2one fields that
    return a list of the id and name
    with just the id of the related field
    '''
    if cell:
        cell = list(cell)
        try:
            cell = cell[index]
        except:
            try:
                cell = cell[0]
            except:
                return None
    return cell

def get_options():
    options={}
    return options

def chunks():
    chunk_interval = int(options['chunk_interval'])
    date = options['inception']

    next_date = dt.datetime.strptime(date, '%Y-%m-%d %H:%M:%S')
    datediff = dt.datetime.today() - next_date
    df = pd.DataFrame()

    while datediff.days > chunk_interval:
        start_date = f'{next_date:%Y-%m-%d %H:%M:%S}'
        next_date = next_date+relativedelta(days=+chunk_interval)
        end_date = f'{next_date:%Y-%m-%d %H:%M:%S}'
        pos_order_lines = get_data(start_date, end_date)
        datediff = dt.datetime.today() - next_date
        df = pd.concat([df, pos_order_lines], ignore_index=True)
    else:
        start_date = f'{next_date:%Y-%m-%d %H:%M:%S}'
        end_date = f'{dt.datetime.today():%Y-%m-%d %H:%M:%S}'
        pos_order_lines = get_data(start_date, end_date)
        df = pd.concat([df, pos_order_lines], ignore_index=True)
    return df

def connect():
    common = client.ServerProxy("%s/xmlrpc/2/common" % options['url'])
    uid = common.authenticate(options['db'], options['user'], options['password'], {})
    if not uid:
        raise NameError
    return uid

def get_payment_data(api, start_date, end_date):
    domain = [
        ('payment_date', '>=', start_date),
        ('payment_date', '<=', end_date),
        ]
    fields = [
        'id',
        'pos_order_id',
        'amount',
        'payment_method_id',
    ]
    data = api.execute_kw(options['db'], uid, options['password'], "pos.payment", "search_read", [], {"domain": domain, "fields": fields}) # get all orders within specified period
    payments = pd.DataFrame(data)

    # modify many2one fields that return a list
    payments['pos_order_id'] = payments['pos_order_id'].apply(replace, args=[0])
    payments['payment_method_id'] = payments['payment_method_id'].apply(replace)
    payments.rename(columns={
        'id': 'payment_id',
        },
        inplace=True)
    return payments

def get_data(start_date, end_date):
    api = client.ServerProxy("%s/xmlrpc/2/object" % options['url'])
    payments = get_payment_data(api, start_date, end_date)
    return payments

options = get_options()
if not options:
    options = {
        'url': '"&Url&"',
        'db': '"&DatabaseName&"',
        'user': '"&User&"',
        'password': '"&Password&"',
        'chunk_interval': '"&ChunkInterval&"',
        'inception': '"&StartDate&"'
    }
uid = connect()
FactPosPayments = chunks()


import os
import reads_pb2
from ont_fast5_api.fast5_interface import get_fast5_file
from os import path
from zlib import compress
import sys

# Run 'protoc --python_out=. reads.proto'  to produce up-to-date reads_pb2 file if edit proto file

filenames = []

# Identify fast5 files in the directory of interest

all_files = os.listdir()
for entry in all_files:
    if ".fast5" in entry:
        filenames.append(entry)

print(filenames)
print(len(filenames))

# Check if any fast5 files were found and only continue if some were

if len(filenames) == 0:
    print("Error: Filenames length is zero")
    sys.exit()

# Iterate through a list of filenames of the fast5 files currently in the directory

for file in filenames:
    reads = reads_pb2.FakReads()
    file = file.split('.')[0]
    print(file)
    count_fast5 = 0
    count_proto = 0

    with get_fast5_file(file + ".fast5") as f5:
        count_fast5 = len(f5.get_read_ids())

        for read_id in f5.get_read_ids():
            read = f5.get_read(read_id)
            latest_basecall = read.get_latest_analysis("Basecall_1D")
            mod_base_table = read.get_analysis_dataset(latest_basecall, "BaseCalled_template/ModBaseProbs")
            read = reads.reads.add()
            read.uuid = read_id
            read.mod_base_probs = compress(mod_base_table.tobytes())

    with open(file + ".protobuf", "wb") as f:
        f.write(reads.SerializeToString())

    # Check if protobuf file exists
    if path.exists(file + ".protobuf") == False:
        # If .protobuf file does not exist exit the program and leave the .fast5 file present
        print("Protobuf file not found")
        sys.exit()

    # Check the number of reads in the protobuf file matches the number of reads in the original fast5 file
    reads2 = reads_pb2.FakReads()

    # Open protobuffer file and read the data
    with open(file + ".protobuf", "rb") as f:
        reads2.ParseFromString(f.read())

    # Count number of reads in protobuffer file
    count_proto = len(reads2.reads)

    # If the number of reads differs, exit the program and leave the .fast5 file present
    if count_fast5 != count_proto:
        print("Mismatching number of reads!")
        sys.exit()

    # If .protobuf file does exist and the number of reads is consistent between fast5 and protobuf files, delete the fast5 file
    os.remove(file + ".fast5")


from typing import Dict
from statistics import mean
from gsy_framework.utils import key_in_dict_and_not_none, limit_float_precision
from gsy_framework.sim_results.results_abc import ResultsBaseClass
from gsy_framework.sim_results import is_trade_external

class MarketSummaryInfo(ResultsBaseClass):

    def __init__(self, should_export_plots):
        self._should_export_plots = should_export_plots
        self._market_summary = {}

    @staticmethod
    def merge_results_to_global(market_results: Dict, global_results: Dict, *_):
        if not global_results:
            global_results = {
                area_uuid: [results]
                for area_uuid, results in market_results.items()
                if results
            }
            return global_results
        for area_uuid in market_results:
            if area_uuid not in global_results:
                global_results[area_uuid] = [market_results[area_uuid]]
            else:
                global_results[area_uuid].append(market_results[area_uuid])
        return global_results

    def update(self, area_result_dict, core_stats, current_market_slot):
        if not self._has_update_parameters(
                area_result_dict, core_stats, current_market_slot):
            return
        if self._should_export_plots:
            # Do not run this
            return
        self._update_results(area_result_dict, core_stats, current_market_slot)

    def _update_results(self, area_dict, core_stats, current_market_slot):
        if not key_in_dict_and_not_none(area_dict, 'children'):
            return
        self._calculate_market_summary_for_area(area_dict, core_stats, current_market_slot)
        for child in area_dict['children']:
            self._update_results(child, core_stats, current_market_slot)

    def _calculate_market_summary_for_area(self, area_dict, core_stats, current_market_slot):
        price_list = []
        volume_kWh = 0.0
        external_traded_volume_kWh = 0.0
        child_names = [c["name"] for c in area_dict["children"]]
        for trade in core_stats.get(area_dict['uuid'], {}).get('trades', []):
            price_list.append(trade["energy_rate"])
            volume_kWh += trade["energy"]
            if is_trade_external(trade, area_dict["name"], child_names):
                external_traded_volume_kWh += trade["energy"]

        self._market_summary[area_dict["uuid"]] = {
            "average_energy_rate": limit_float_precision(mean(price_list)) if price_list else None,
            "external_traded_volume": external_traded_volume_kWh,
            "traded_volume": volume_kWh,
            "timestamp": current_market_slot
        }

    def restore_area_results_state(self, area_uuid, last_known_state_data):
        pass

    @property
    def raw_results(self):
        return self._market_summary

    def memory_allocation_size_kb(self):
        return self._calculate_memory_allocated_by_objects([
            self._market_summary
        ])


import configparser
import pkg_resources

class ConfigBase(object):
    def __init__(self,config_type,exchange=None,test_mode=False):
        if test_mode:
            self._resource_path = pkg_resources.resource_filename("tests", "test_config.ini")
        else:
            self._resource_path = pkg_resources.resource_filename("src","config.ini")
            self._load_config(config_type,exchange)

    def _streamer_section(self,section_name):
        config = configparser.ConfigParser()
        config.read(self._resource_path)

        self._url = config.get(section_name,'url',
                                fallback="{0} Section does not have {1} variable\n".format(section_name,"url"))

        symbols_to_test = config.get(section_name,"symbols",
                                     fallback=None)
        if symbols_to_test:

            if Helpers.ensure_correct_symbols_bitmex(symbols_to_test.split(',')):
                self._symbols = symbols_to_test.split(',')

            else:
                print("Not Supported Symbols Found\nCould be Formatting\nExiting...")

        self._retry_connections = config.get(section_name,'max_retry_connections',
                                              fallback="{0} Section does not have {1} variable\n"
                                              .format(section_name,"max_retry_connections"))

        try:
            self._retry_connections = int(self._retry_connections)
        except Exception as error:
            print(error)

    def _processor_section(self,section_name):
        config = configparser.ConfigParser()
        config.read(self._resource_path)

        self._batch_size = config.get(section_name,'batch_size',
                                       fallback="")

        try:
            self._batch_size = int(self._batch_size)
        except Exception as error:
            print(error)

        self._use_compression = \
            True if config.get(section_name,"use_compression",fallback="false").upper() == "TRUE" else False
        self._aggregation_interval = config.get(section_name,"data_aggregation_interval",
                                                fallback=24)

        try:
            self._aggregation_interval = int(self._aggregation_interval)
        except Exception as error:
            print(error)

    def _zeromq_section(self):
        config = configparser.ConfigParser()
        config.read(self._resource_path)

        self._port = config.get("ZEROMQ","port",
                                fallback="No valid port for ZeroMQ")

    def _load_config(self,c_type,exchange):

        try:
            if c_type.upper() == "STREAM":
                if exchange:
                    self._streamer_section("STREAM."+exchange.upper())

            elif c_type.upper() == "PROCESS":
                if exchange:
                    self._processor_section("DP."+exchange.upper())
            elif c_type.upper() == "ZEROMQ":
                self._zeromq_section()

        except Exception as error:
            print("{0}: {1}".format(type(error).__name__,error))

class Helpers:

    @classmethod
    def ensure_correct_symbols_bitmex(cls,symbols_list):
        supported_symbols = ["XBTUSD", "ETHUSD", "XRPUSD", "ADAU20", "BCHUSD", "EOSU20", "LTCU20", "TRXU20"]

        return all(symbol in supported_symbols for symbol in symbols_list)


import pandas as pd
import numpy as np

'''
https://adventofcode.com/2020/day/1

'''

# Part 1

file_loc = r'aoc_1_input.txt'
expense_list = []

with open(file_loc,'r') as fp:
    for line in fp:
        expense_list.append(int(line))

flag = 0

for exp in expense_list:
    list_b = list(set(expense_list) - set([exp]))
    if flag == 1:
        break
    for exp_b in list_b:
        if exp + exp_b == 2020:
            flag = 1
            print('Part-1')
            print(' {} + {} = {} '.format(exp, exp_b, exp + exp_b))
            print(' {} * {} = {} '.format(exp, exp_b, exp * exp_b))
            break

# Part 2
flag = 0
for exp in expense_list:
    list_b = list(set(expense_list) - set([exp]))
    if flag == 1:
        break
    for exp_b in list_b:
        list_c = list(set(list_b) - set([exp_b]))
        if flag == 1:
            break
        for exp_c in list_c:
            if exp + exp_b + exp_c == 2020:
                flag = 1
                print('Part-2')
                print(' {} + {} + {}= {} '.format(exp, exp_b,exp_c, exp + exp_b + exp_c))
                print(' {} * {} * {}= {} '.format(exp, exp_b, exp_c,exp * exp_b * exp_c))
                break


# Complicated objects in the real world (like cars) are never designed from scratch.
# They reiterate existing designs.
# This design pattern similarly, uses an existing (partially or fully constructed)
# design (also called a Prototype) and customizes it for use.
# We make a 'deep copy' (clone) of the Prototype and customize it.
# We also make the cloning convenient (eg: by using a Prototype Factory - Ask a Factory to customize
# a pre-defined Prototype design)

# To implement this design pattern, create a Prototype (partially constructed Object) and store
# it somewhere. Deep copy this Prototype and then customize the resulting instance (Object).
# A Factory (any class, method or component that creates a new object) provides a convenient
# API for customizing and using Prototypes (create customized clones)!

import copy  # for deep-copying objects

class Address:
    def __init__(self, street_address, city, country):
        self.street_address = street_address
        self.city = city
        self.country = country

    def __str__(self):
        return f'{self.street_address}, {self.city}, {self.country}'

class Person:
    def __init__(self, name, address):
        self.name = name
        self.address = address

    def __str__(self):
        return f'{self.name} lives at {self.address}'

address = Address('123 London Road', 'London', 'UK')
# A Prototype
john = Person('John', address)
print(john)
# Unfortunately here, 'john' and 'jane' refer to the same object (this is not a deep copy)
# jane = john
# jane.name = 'Jane'
# We can try to fix this by doing something like this:
# But this too has repercussions like below (any change in the 'address' of 'jane' is reflected in 'john'):
# jane = Person('Jane', address)
# jane.address.street_address = '123B London Road'

# Perform a shallow-copy causes any reference to another object to be copied over as a reference
# Thus, the following shallow-copy will lead to carry-over effect on the 'address' object since it
# is referenced in the 'john' object and the same reference is copied over to the 'jane' object
# jane = copy.copy(john)
# Performing a Deep-copy of a Prototype object
jane = copy.deepcopy(john)
jane.name = 'Jane'
jane.address.street_address = '124 London Road'
print("---")
# Due to lack of deep-copy, the change in 'jane' is actually a change in 'john' as well
print(john)
print(jane)

# PROTOTYPE FACTORY

# It is quite often inconvenient to make deep-copies of instances (Objects) manually using 'copy.deepcopy()'
# It would be nice to have a Factory to package pre-defined Prototypes rather than performing deep-copies
# and customizations on the Prototype manually.

class OfficialAddress:
    def __init__(self, street_address, city, suite):
        self.street_address = street_address
        self.city = city
        self.suite = suite

    def __str__(self):
        return f'{self.street_address}, Suite #{self.suite}, {self.city}'

class Employee:
    def __init__(self, name, address):
        self.address = address
        self.name = name

    def __str__(self):
        return f'{self.name} works at {self.address}'

# Prototype Factory class
class EmployeeFactory:
    # Two Prototypes (static objects)
    main_office_employee = Employee(
        '', OfficialAddress('123 East Drive', 0, 'London'))
    aux_office_employee = Employee(
        '', OfficialAddress('123B East Drive', 0, 'London'))

    # Factory Methods for creating copies (cloning) of 'Employee' objects
    # We are creating Factory methods for a main office employee and an auxillary
    # office employee here.
    @staticmethod
    # This is a utility method to perform deep-copy!
    # This dunder method (double underscores at the start of method name) is not
    # supposed to be consumed (invoked) from outside the EmployeeFactory class.
    def __new_employee(proto, name, suite):
        result = copy.deepcopy(proto)
        result.name = name
        result.address.suite = suite
        return result

    # These two are Factory methods that make use of the utility method above to create
    # customized copies of the 'Employee' Prototype.
    # Prototype Factory method 1
    @staticmethod
    def new_main_office_employee(name, suite):
        return EmployeeFactory.__new_employee(
            EmployeeFactory.main_office_employee,
            name, suite
        )
    # Prototype Factory methods 2
    @staticmethod
    def new_aux_office_employee(name, suite):
        return EmployeeFactory.__new_employee(
            EmployeeFactory.aux_office_employee,
            name, suite
        )

# Create objects using the Prototype Factory methods
john = EmployeeFactory.new_main_office_employee('John', 101)
jane = EmployeeFactory.new_aux_office_employee('Jane', 500)

print(john)
print(jane)

# EXERCISE

# implement Line.deep_copy()  to perform a deep copy of the given Line  object.
# This method should return a copy of a Line that contains copies of its start/end points.

import copy

class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

class Line:
    def __init__(self, start=Point(), end=Point()):
        self.start = start
        self.end = end

    def deep_copy(self):
        new_starting_point = Point(self.start.x, self.start.y)
        new_ending_point = Point(self.end.x, self.end.y)
        return Line(new_starting_point, new_ending_point)


# -*- coding: utf-8 -*-
"""
Created on Thu May 16 10:44:11 2019

@author: Administrator
"""

import numpy as np
import edge

class SparseGraph:

    def __init__(self, n, directed):
        self.__n = n
        self.__m = 0
        self.__directed = directed
        self.g = [[] for i in range(n)]

    def v(self):
        return self.__n

    def e(self):
        return self.__m

    def add_edge(self, v, w, weight):
        assert 0 <= v < self.__n
        assert 0 <= w < self.__n

        self.g[v].append(edge.Edge(v, w, weight))
        if not self.__directed:
            self.g[w].append(edge.Edge(w, v, weight))

        self.__m += 1

    def has_edge(self, v, w):
        assert 0 <= v < self.__n
        assert 0 <= w < self.__n

        for i in range(len(self.g[v])):
            if self.g[v][i].other(v) == w:
                return True
            return False

    def show(self):
        for i in range(self.__n):
            print('vertex %d: ' % i, end = ' ')
            for j in range(len(self.g[i])):
                print('( to: %d, wt: %f)' % (self.g[i][j].w(),
                                            self.g[i][j].wt()), end = ' ')
            print('\n')
    class adjIterator:

        def __init__(self, graph, v):
            self.__graph = graph
            self.__v = v
            self.__index = 0

        def begin(self):
            self.__index = 0
            if len(self.__graph.g[self.__v]):
                return self.__graph.g[self.__v][self.__index]
            return None

        def next_item(self):
            self.__index += 1
            if self.__index < len(self.__graph.g[self.__v]):
                return self.__graph.g[self.__v][self.__index]
            return None

        def end(self):
            return self.__index >= len(self.__graph.g[self.__v])

if __name__ == '__main__':
    n, m = 20, 100

    g1 = SparseGraph(n, False)
    np.random.seed(1023)
    for i in range(m):
        a = np.random.randint(0, 20)
        b = np.random.randint(0, 20)
        g1.add_edge(a, b)

    print(g1.g)

    for v in range(n):
        print('\n%d : ' % v, end = '')
        adj = SparseGraph.adjIterator(g1, v)
        w = adj.begin()
        while not adj.end():
            print('%d ' % w, end = '')
            w = adj.next_item()


# Importing dependencies
import numpy as np
import cv2
import pandas as pd
from sklearn.preprocessing import LabelEncoder,OneHotEncoder,StandardScaler
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten

#loading dataset
train = pd.read_csv('train.csv')
X_train = train.iloc[0:40000,1:785].values
Y_train = train.iloc[0:40000,0:1].values
X_test = train.iloc[40000:42000,1:785].values
Y_test = train.iloc[40000:42000,0:1].values

#one hot encoding labels

onehotencoder = OneHotEncoder(categorical_features=[0])
Y_train = onehotencoder.fit_transform(Y_train).toarray()

#creating 4-d varriables for image data
Xtrain = [1] * 31360000
Xtrain = np.reshape(Xtrain,(40000,28,28,1))
Xtest = [1] * 1568000
X1 = [1]*784

sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.fit_transform(X_test)

Xtest = np.reshape(Xtest,(2000,28,28,1))

for i in range(0,40000):
    X1 = X_train[i,:]
    X1 = np.reshape(X1,(28,28,1))
    Xtrain[i,:,:] = X1
for i in range(0,2000):
    X1 = X_test[i,:]
    X1 = np.reshape(X1,(28,28,1))
    Xtest[i,:,:] = X1

#creating sequential cnn model
classifier = Sequential()
classifier.add(Conv2D(32,3,3,input_shape = (28,28,1),activation = 'relu'))

classifier.add(MaxPooling2D(pool_size=(2,2)))
classifier.add(Conv2D(16,3,3,input_shape = (28,28,1),activation = 'relu'))

classifier.add(MaxPooling2D(pool_size=(2,2)))

classifier.add(Flatten())

classifier.add(Dense(output_dim = 800, init = 'uniform' , activation ='relu',input_dim = 784))
classifier.add(Dense(output_dim = 400, init = 'uniform' , activation ='relu'))
classifier.add(Dense(output_dim = 200, init = 'uniform' , activation ='relu'))

classifier.add(Dense(output_dim = 100, init = 'uniform' , activation ='relu'))
classifier.add(Dense(output_dim = 50, init = 'uniform' , activation ='relu'))
classifier.add(Dense(output_dim = 20, init = 'uniform' , activation ='relu'))
classifier.add(Dense(output_dim = 10, init = 'uniform' , activation ='sigmoid'))

#compiling model
classifier.compile(optimizer = 'adam',loss = 'binary_crossentropy' , metrics = ['accuracy'])

#fitting cnn to training set
classifier.fit(X_train,Y_train, batch_size=10 , nb_epoch = 10)

#predicting results
y_pred = classifier.predict(X_test)

# reversing process of one hot encoding
for i in range(0,2000):
    for j in range(0,10):
        if(y_pred[i,j]<0.5):
            y_pred[i,j]=0
        if(y_pred[i,j]>0.5):
            y_pred[i,j]=1
for i in range(0,2000):
    for j in range(0,10):
        if(y_pred[i,j]==1):
            y_pred[i,0] = j

y_pred = np.delete(y_pred,np.s_[1:10],axis = 1)

#creating confusion matrix
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(Y_test,y_pred)

#getting accuracy score
from sklearn.metrics import accuracy_score
a = accuracy_score(Y_test,y_pred)

#checking model on random images
image = cv2.imread('download.png')
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
image1 = cv2.resize(image,(28,28))
for i in range(0,28):
    for j in range(0,28):
        image1[i,j] = 255-image1[i,j]
#image1 = np.reshape(image1,(1,784))
image1 = np.reshape(image1,(1,28,28,1))
y_pred1 = classifier.predict(image1)

#For importing model from saved weights
'''from keras.models import model_from_json
model_json = classifier.to_json()
with open("classifier.json", "w") as json_file:
    json_file.write(model_json)
# serialize weights to HDF5
classifier.save_weights("classifier.h5")
print("Saved model to disk")
from keras.models import model_from_json
json_file = open('classifier.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# load weights into new model
loaded_model.load_weights("classifier.h5")
print("Loaded model from disk")
loaded_model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])'''


import arn_loops as al
import numpy as np
import scipy.linalg as sl
import scipy.stats as ss
import warnings

r"""A model based on CAR processes for fitting the properties of noise.
Our model is that the measured zero-mean noise, :math:`y_i = y\left(
t_i \right) - \mu` obeys the stochastic differential equation

.. math::

  \left[ \prod_{i = 1}^p \frac{d}{dt} - r_i \right] y(t) = \eta(t)

where :math:`\eta(t)` is a white-noise process with

.. math::

  \left\langle \eta(t) \right \rangle = 0

and

.. math::

  \left\langle \eta(t) \eta(t') \right\rangle = \sigma^2 \delta(t-t')

The parameters of our model are the p "roots" :math:`r_i`, the noise
amplitude :math:`\sigma`, and the mean :math:`\mu`.  We use the
measured times and values :math:`y_i = y(t_i) - \mu` to constrain
these parameters.  Note that the roots can be complex, but if so must
occur in complex-conjugate pairs so that the noise remains real.

The roots have dimensions of inverse time, and correspond to the
reciprocal of the decay timescale of an eigenmode of the process (real
part) and/or to an angular frequency of an eigenmode of the process
(imaginary part).

The power spectrum of the noise process described by our model is

.. math::

  \left\langle \tilde{y}(f) \tilde{y}(f') \right\rangle = \frac{\sigma^2}{\prod_{j=1}^p \left| 2 \pi i f - r_j \right|^2} \delta(f - f')

"""

def greens_coefficients(roots):
    r"""Returns the coefficients of the Green's function for the given
    roots of the ODE characteristic equation.

    The Green's function can always be written as

    .. math::

      G(t; \xi) = \sum_i g_i \exp\left(r_i (t-\xi)\right)

    This function returns the :math:`g_i`.

    """
    roots = np.atleast_1d(roots)
    n = roots.shape[0]

    m = np.zeros((n,n), dtype=roots.dtype) # complex if necessary

    m[0,:] = np.ones(n)
    for i in range(1,n):
        m[i,:] = m[i-1,:]*roots

    b = np.zeros(n, dtype=roots.dtype)
    b[-1] = 1.0

    return np.linalg.solve(m, b)

def covariance_matrix(roots, ts, beta_roots = None):
    r"""Returns the covariance matrix of the stochastic solution to the ODE

    .. math::

      \left[ \prod_i \frac{d}{dt} - r_i \right] y(t) = \left[ \prod_j \frac{d}{dt} - b_j \right] \frac{1}{\prod_j -b_j} \eta(t),

    with

    .. math::

      \left\langle \eta(s) \eta(t) \right\rangle = \delta(s-t),

    at the indicated times.  In other words, returns

    .. math::

      C_{ij} = \left\langle y\left(t_i\right) y\left(t_j \right) \right\rangle.

    """
    roots = np.atleast_1d(roots)
    ts = np.atleast_1d(ts)

    gc = greens_coefficients(roots)

    if beta_roots is None:
        gg = gc
    else:
        gg = []
        for g, r in zip(gc, roots):
            gg.append(g*np.prod(r - beta_roots)/np.prod(-beta_roots))
        gg = np.array(gg)

    dts = np.abs(ts.reshape((-1, 1)) - ts.reshape((1, -1)))

    m = np.zeros(dts.shape, dtype=roots.dtype)

    for ri, gi in zip(roots, gg):
        for rj, gj in zip(roots, gg):
            m -= gi*gj*np.exp(dts*rj)/(ri + rj)

    return np.real(m) # Covariance is always real

def banded_covariance(roots, ts, beta_roots = None):
    """Returns only the terms in the covariance matrix that one might need
    to calculate the covariance of the reduced data:

    .. math::

      x_i = y_i - \sum_{k=1}^p \alpha_k y_{i-k}

    Only the upper :math:`p+1` diagonals of the covariance matrix will
    be returned.

    """

    roots = np.atleast_1d(roots)
    ts = np.atleast_1d(ts)

    n = ts.shape[0]
    p = roots.shape[0]

    gc = greens_coefficients(roots)

    if beta_roots is None:
        gg = gc
    else:
        gg = []
        for g, r in zip(gc, roots):
            gg.append(g*np.prod(r - beta_roots)/np.prod(-beta_roots))
        gg = np.array(gg)

    dts = np.zeros((2*p+1, n))
    for i in range(1, 2*p+1):
        j = 2*p - i
        dts[j, i:] = np.abs(ts[:-i] - ts[i:])

    m = np.zeros(dts.shape, dtype=roots.dtype)

    for ri, gi in zip(roots, gg):
        for rj, gj in zip(roots, gg):
            m -= gi*gj*np.exp(dts*rj)/(ri + rj)

    for i in range(2*p):
        m[i, :(2*p-i)] = 0.0

    return np.real(m)

def generate_data(sigma, roots, ts, beta_roots = None):
    r"""Returns a sample from the stochastic process described by

    .. math::

      \left[ \prod_i \frac{d}{dt} - r_i \right] y(t) = \sigma \left[ \prod_j \frac{d}{dt} - b_j \right] \frac{1}{\prod_j -b_j} \eta(t)

    with

    .. math::

      \left\langle \eta(t) \eta(s) \right\rangle = \delta(s - t)

    at the indicated times.

    """

    ts = np.atleast_1d(ts)

    m = covariance_matrix(roots, ts, beta_roots)*sigma*sigma

    return np.random.multivariate_normal(np.zeros(ts.shape[0]), m)

def psd(sigma, roots, fs, beta_roots = None):
    r"""Returns the power spectral density of the stochastic process

    .. math::

      \left\langle \tilde{y}\left(f_1\right) \tilde{y}\left(f_2\right) \right\rangle = P\left(f_1\right) \delta\left( f_1 - f_2 \right)

    """

    fs = np.atleast_1d(fs)
    roots = np.atleast_1d(roots)

    denom = (2.0*np.pi*1j*fs.reshape((-1, 1)) - roots.reshape((1, -1)))
    denom = np.prod(denom, axis=1)
    denom = np.abs(denom)
    denom = denom*denom

    if beta_roots is None:
        numer = 1.0
    else:
        numer = np.prod(2.0*np.pi*1j*fs.reshape((-1, 1)) - beta_roots.reshape((1, -1)), axis=1) / np.prod(-beta_roots)
        numer = np.abs(numer)
        numer = numer*numer

    return sigma*sigma*numer/denom

def alpha(roots, ts):
    r"""Returns the weights in the difference equation that the homogeneous
    solution at times ``ts`` satisfies:

    .. math::

      y_h\left( t_p \right) = \sum_{i = 0}^{p-1} \alpha_i y_h\left( t_i \right)

    """
    roots = np.atleast_1d(roots)
    ts = np.atleast_1d(ts)

    n = ts.shape[0]
    p = roots.shape[0]

    many_ts = np.zeros((n-p, p+1))
    for j in range(p+1):
        many_ts[:,j] = ts[j:n-p+j]
    many_ts = many_ts - many_ts[:,0].reshape((-1, 1))

    m = np.exp(roots.reshape((1, -1, 1))*many_ts[:,:-1].reshape((n-p, 1, -1)))
    b = np.exp(roots.reshape((1, -1))*many_ts[:, -1].reshape((n-p, 1)))

    m[:,:,:p] += 1e-8*np.eye(p) # Stabilise in the presence of long gaps

    return np.real(np.linalg.solve(m,b))

def variance(roots, beta_roots = None):
    r"""Returns the variance of the stochastic process

    .. math::

      \prod_i \left[ \frac{d}{dt} - r_i \right] y(t) = \eta(t)

    with

    .. math::

      \left\langle \eta(t) \eta(t') \right\rangle = \delta(t-t')

    """

    roots = np.atleast_1d(roots)

    gc = greens_coefficients(roots)

    if beta_roots is None:
        gg = gc
    else:
        gg = []
        for g, r in zip(gc, roots):
            gg.append(g*np.prod(r - beta_roots)/np.prod(-beta_roots))
        gg = np.array(gg)

    m = 0.0
    for ri, gi in zip(roots, gg):
        for rj, gj in zip(roots, gg):
            m -= gi*gj/(ri + rj)

    return np.real(m) # Variance is always real

class BadParameterWarning(Warning):
    """Used to indicate a bad region of parameter space in the likelihood.

    """

    pass

class Posterior(object):
    """A posterior for the AR(n) process.

    """

    def __init__(self, ts, ys, p, q = 1, ncomplex=0):
        """Initialise the posterior with the given times and data.  If given,
        ``ncomplex`` indicates the number of complex roots
        (i.e. oscillatory components) in the process.  ``p`` is the
        order of the process.

        """

        self._ts = ts
        self._ys = ys
        self._p = p
        self._q = q
        self._nc = ncomplex

    @property
    def ts(self):
        """Sample times.

        """
        return self._ts

    @property
    def ys(self):
        """Sample values

        """
        return self._ys

    @property
    def p(self):
        """The order of the CAR process.

        """
        return self._p

    @property
    def q(self):
        """The order of the MA part of the process.

        """
        return self._q

    @property
    def n(self):
        """The number of data points.

        """
        return self.ts.shape[0]

    @property
    def nc(self):
        """The number of complex roots (should always be even).

        """
        return self._nc

    @property
    def dtype(self):
        """A named-field data type for model parameters.

        """
        return np.dtype([('mu', np.float),
                         ('log_sigma', np.float),
                         ('root_params', np.float, self.p)])

    @property
    def nparams(self):
        """The number of parameters in the model.

        """
        return 2 + self.p

    def to_params(self, p):
        r"""Returns a view of ``p`` with named fields for the parameters.  Our
        parameterisation uses :math:`\log \sigma` and treats the roots
        as follows.  For the real roots, the roots are sorted from
        smallest to largest, and

        .. math::

          p_0 = - \log\left( -r_0 \right)

        .. math::

          p_i = \log\left( r_i - r_{i-1} \right) - \log\left( -r_i \right)

        In this way, :math:`-\infty < p_j < \infty` generates all
        possible sorted sets of negative roots.

        We use the same parameterisation for the real parts of the
        complex roots.  For the imaginary parts, we use the log of the
        positive angular frequency as a parameter, again generating
        all possible complex conjugate pairs of roots (sorted in
        increasing order of real part) as the parameters range over
        the real line.

        """
        return np.atleast_1d(p).view(self.dtype).squeeze()

    def _real_roots(self, rp):
        rp = np.atleast_1d(rp)

        rs = np.zeros(rp.shape[0])

        rs[0] = -np.exp(-rp[0])
        for i in range(1, rp.shape[0]):
            rs[i] = rs[i-1]/(1.0 + np.exp(rp[i]))

        return rs

    def _complex_roots(self, rp):
        rp = np.atleast_1d(rp)
        realp = rp[::2]
        imagp = rp[1::2]

        # The real parts of the complex roots are stored in the same
        # way as the real roots
        reals = self._real_roots(realp)
        imags = np.exp(imagp)*1j

        roots = np.zeros(rp.shape[0], dtype=np.complex)
        roots[::2] = reals + imags
        roots[1::2] = reals - imags

        return roots

    def roots(self, p):
        """Returns the roots of the characteristic polynomial given the model
        parameters.

        """

        p = self.to_params(p)

        if self.nc == 0:
            return self._real_roots(p['root_params'])
        elif self.nc == self.p:
            return self._complex_roots(p['root_params'])
        else:
            rp = p['root_params']
            # Complex roots stored first
            crs = self._complex_roots(rp[:self.nc])
            rrs = self._real_roots(rp[self.nc:])

            return np.concatenate((crs, rrs))

    def _real_params(self, roots):
        roots = np.sort(roots)

        ps = np.zeros(roots.shape[0])

        ps[0] = -np.log(-roots[0])
        for i in range(1, roots.shape[0]):
            ps[i] = np.log(roots[i] - roots[i-1]) - np.log(-roots[i])

        return ps

    def _complex_params(self, roots):
        roots = roots[np.argsort(np.real(roots))]
        ps = np.zeros(roots.shape[0])

        ps[::2] = self._real_params(np.real(roots[::2]))
        ps[1::2] = np.log(np.abs(np.imag(roots[::2])))

        return ps

    def parameters(self, roots):
        """Returns the root parameters associated with the given roots.

        """

        if self.nc == 0:
            return self._real_params(roots)
        elif self.nc == self.p:
            return self._complex_params(roots)
        else:
            return np.concatenate((self._complex_params(roots[:self.nc]), self._real_params(roots[self.nc:])))

    def _real_roots_log_jacobian(self, p, r):
        p = np.atleast_1d(p)

        lj = -p[0]
        for i in range(1, p.shape[0]):
            lj += np.log(-r[i-1]) + p[i] - 2.0*np.log1p(np.exp(p[i]))

        return lj

    def _complex_roots_log_jacobian(self, p, r):
        p = np.atleast_1d(p)

        real_lj = self._real_roots_log_jacobian(p[::2], np.real(r))
        imag_lj = np.sum(p[1::2])

        return real_lj + imag_lj

    def roots_log_jacobian(self, p, r):
        r"""Given parameters ``p`` and associated roots ``r``, return the log
        of the jacobian transformation

        .. math::

          \left| \frac{\partial r}{\partial p} \right|

        """

        p = self.to_params(p)
        r = np.atleast_1d(r)

        if self.nc == 0:
            return self._real_roots_log_jacobian(p['root_params'], r)
        elif self.nc == self.p:
            return np.real(self._complex_roots_log_jacobian(p['root_params'], r))
        else:
            ljc = self._complex_roots_log_jacobian(p['root_params'][:self.nc], r[:self.nc])
            ljr = self._real_roots_log_jacobian(p['root_params'][self.nc:], r[self.nc:])
            return np.real(ljc + ljr)

    def _complex_roots_log_prior(self, croots, tau_min, tau_max):
        omega_min = 2.0*np.pi/tau_max
        omega_max = 2.0*np.pi/tau_min

        root_min = -1.0/tau_min
        root_max = -1.0/tau_max

        if np.any(np.real(croots) < root_min) or np.any(np.real(croots) > root_max) or \
           np.any(np.abs(np.imag(croots)) < omega_min) or \
           np.any(np.abs(np.imag(croots)) > omega_max):
            return np.NINF
        else:
            return -np.sum(np.log(np.abs(np.real(croots[::2])))) - np.sum(np.log(np.abs(np.imag(croots[1::2]))))

    def _real_roots_log_prior(self, rroots, tau_min, tau_max):
        root_min = -1.0 / tau_min
        root_max = -1.0 / tau_max

        if np.any(rroots < root_min) or np.any(rroots > root_max):
            return np.NINF
        else:
            return -np.sum(np.log(-rroots))

    def log_prior(self, p):
        r"""The prior on parameters.  Our prior is flat in :math:`\log \sigma`,
        and flat in :math:`\log r_i` (or :math:`\log \Re r_i` and
        :math:`\log \Im r_i` if complex) between

        .. math::

          r_\mathrm{min} = \frac{1}{10T}

        and

        .. math:

          r_\mathrm{max} = \frac{10}{\delta t_\mathrm{min}}

        where :math:`T` is the total observation time and
        :math:`\delta t_\mathrm{min}` is the smallest time spacing
        between samples.

        """

        p = self.to_params(p)

        # Flat prior on the mean between min and max
        if p['mu'] < np.min(self.ys) or p['mu'] > np.max(self.ys):
            return np.NINF

        roots = self.roots(p)

        unit_std = np.sqrt(covariance_matrix(roots, [0.0, 1.0])[0,0])
        sigma_max = (np.max(self.ys) - np.min(self.ys))/unit_std
        sigma_min = np.min(np.abs(np.diff(self.ys)))/unit_std

        sigma = np.exp(p['log_sigma'])

        if sigma < sigma_min or sigma > sigma_max:
            return np.NINF

        tau_min = np.min(np.diff(self.ts))/10.0
        tau_max = (self.ts[-1] - self.ts[0])*10.0

        if self.nc == 0:
            return self._real_roots_log_prior(roots, tau_min, tau_max) + self.roots_log_jacobian(p, roots)
        elif self.nc == self.p:
            return np.real(self._complex_roots_log_prior(roots, tau_min, tau_max) + self.roots_log_jacobian(p, roots))
        else:
            return np.real(self._complex_roots_log_prior(roots[:self.nc], tau_min, tau_max) + self._real_roots_log_prior(roots[self.nc:], tau_min, tau_max) + self.roots_log_jacobian(p, roots))

    def full_log_likelihood(self, p):
        """Returns the log-likelihood for the data under the model by
        explicitly constructing the data covariance matrix.  This is
        foolproof, but very slow, and so probably only useful for
        testing.

        """
        p = self.to_params(p)
        roots = self.roots(p)

        sigma = np.exp(p['log_sigma'])

        cov = sigma*sigma*covariance_matrix(roots, self.ts)

        try:
            return ss.multivariate_normal.logpdf(self.ys-p['mu'], np.zeros(self.ys.shape[0]), cov)
        except:
            warnings.warn('exception in multivariate_normal (probably singular cov)',
                          BadParameterWarning)
            return np.NINF

    def log_likelihood(self, p):
        """Returns the log-likelihood of the data under the model, but
        efficiently.

        """
        p = self.to_params(p)

        try:
            alpha = self._alpha_matrix(p)
            beta = self._beta_matrix(p, alpha=alpha)
        except np.linalg.LinAlgError:
            warnings.warn('exception in alpha/beta computation, probably too-small timescales',
                          BadParameterWarning)
            return np.NINF

        xs = np.zeros(self.n)

        al.log_likelihood_xs_loop(self.n, self.p, alpha, self.ys - p['mu'], xs)

        try:
            evals = sl.eigvals_banded(beta, lower=False)
            if np.any(evals <= 0):
                warnings.warn('found non-positive-definite transformed covariance',
                              BadParameterWarning)
                return np.NINF

            log_evals = np.log(evals)

            return -0.5*self.n*np.log(2.0*np.pi) - 0.5*np.sum(log_evals) - 0.5*np.dot(xs, sl.solveh_banded(beta, xs, lower=False))
        except sl.LinAlgError:
            warnings.warn('exception in log-likelihood computation, probably singular cov',
                          BadParameterWarning)
            return np.NINF

    def __call__(self, p):
        """Returns the log-posterior at parameters ``p``.

        """
        lp = self.log_prior(p)

        if lp == np.NINF:
            return lp
        else:
            return lp + self.log_likelihood(p)

    def _alpha_matrix(self, p):
        p = self.to_params(p)

        roots = self.roots(p)

        n = self.ts.shape[0]
        pp = roots.shape[0]

        am = np.zeros((pp+1, n))
        alp = alpha(roots, self.ts)

        al.fill_alpha_loop(n, pp, alp, am)

        return am

    def _beta_matrix(self, p, alpha=None):
        p = self.to_params(p)

        sigma = np.exp(p['log_sigma'])

        roots = self.roots(p)

        n = self.ts.shape[0]
        pp = roots.shape[0]

        if alpha is None:
            alpha = self._alpha_matrix(p)

        cov = sigma*sigma*banded_covariance(self.roots(p), self.ts)

        beta = np.zeros((pp, n))

        al.beta_matrix_loop(n, pp, alpha, cov, beta)

        return beta

    def whitened_residuals(self, p):
        r"""Returns an array of the same shape as the input data, but whose
        values are indepenent :math:`N(0,1)` variables under the model
        with parameters ``p``.

        """
        p = self.to_params(p)

        alpha = self._alpha_matrix(p)
        beta = self._beta_matrix(p)

        xs = np.zeros(self.n)

        al.log_likelihood_xs_loop(self.n, self.p, alpha, self.ys - p['mu'], xs)

        beta12 = sl.cholesky_banded(beta, lower=False)
        beta12T = np.zeros((self.p, self.n))

        for i in range(self.p):
            beta12T[-(i+1), :self.n-self.p+1+i] = beta12[i, self.p-1-i:]

        return sl.solve_banded((self.p-1, 0), beta12T, xs)

    def power_spectrum(self, p, fs):
        r"""The power spectrum for the model with parameters ``p`` at the
        frequencies ``fs``.

        .. math::

          \left\langle \tilde{y}(f) \tilde{y}(f') \right\rangle = \frac{\sigma^2}{\prod_{j=1}^p \left| 2 \pi i f - r_j \right|^2} \delta(f - f')

        """
        p = self.to_params(p)

        roots = self.roots(p)

        return np.exp(2.0*p['log_sigma'])/np.prod(np.square(np.abs(2.0*np.pi*1j*fs.reshape((-1, 1)) - roots.reshape((1, -1)))), axis=1)

    def residuals(self, p):
        r"""Returns ``x, sigma``, where

        .. math::

          x_i = y_i - \sum_{k=1}^p \alpha_{ik} y_{i-k}

        is the error in the model prediction for :math:`y_i` and

        .. math::

          \sigma_i^2 = \mathrm{var}\left( x_i \right)

        is the variance of this quantity predicted by the model.  Note
        that the :math:`x_i` are not statistically independent, so one
        should not, e.g., form a chi-squared out of these quantities.
        For independent residuals, see the
        :method:`Posterior.whitened_residuals` method.

        """

        p = self.to_params(p)

        alpha = self._alpha_matrix(p)
        beta = self._beta_matrix(p)

        xs = np.zeros(self.n)

        al.log_likelihood_xs_loop(self.n, self.p, alpha, self.ys - p['mu'], xs)

        return xs, np.sqrt(beta[-1,:])

    def frequency_parameters(self, p):
        r"""Returns an array of more physically meaningful parameters,

        .. math::

          \left\{ \sigma, \Re r_0, \Im r_0, \Re r_2, \Im r_2, \ldots,
          r_{N_c}, \ldots \right\}

        where :math:`\sigma` is the standard deviation of the process,
        and the following :math:`2N_c` values are the real (decay
        rate) and imaginary (oscillation frequency) parts of the
        complex roots, followed by the real roots (decay rate).

        """

        p = self.to_params(p)

        roots = self.roots(p)

        sigma = np.exp(p['log_sigma'])*np.sqrt(variance(self.roots(p)))

        if self.nc == 0:
            return np.concatenate(([sigma], roots))
        elif self.nc == self.p:
            rp = np.zeros(self.nparams)
            rp[0] = sigma
            rp[1::2] = np.real(roots[::2])
            rp[2::2] = np.imag(roots[::2])

            return rp
        else:
            rp = np.zeros(self.nparams)
            rp[0] = sigma
            rp[1:nc:2] = np.real(roots[:nc:2])
            rp[2:nc:2] = np.imag(roots[:nc:2])
            rp[nc:] = np.real(roots[nc:])

            return rp

    def time_parameters(self, p):
        r"""Returns an array of more physically meaningful parameters,

        .. math::

          \left\{ \sigma, 1/\Re r_0, 2\pi/\Im r_0, 1/\Re r_2, 2\pi/\Im
          r_2, \ldots, 1/r_{N_c}, \ldots \right\}

        where :math:`\sigma` is the standard deviation of the process,
        and the following :math:`2N_c` values are the inverse of the
        real (decay timescale) and imaginary (oscillation period)
        parts of the complex roots, followed by the real roots (decay
        timescale)."""

        rp = self.frequency_parameters(p)

        if self.nc == 0:
            rp[1:] = -1.0/rp[1:]
            return rp
        elif self.nc == self.p:
            rp[1::2] = -1.0/rp[1::2]
            rp[2::2] = 2.0*np.pi/rp[2::2]

            return rp
        else:
            rp[1:nc:2] = -1.0/rp[1:nc:2]
            rp[2:nc:2] = 2.0*np.pi/rp[2:nc:2]
            rp[nc:] = -1.0/rp[nc:]

            return rp


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def getMinimumDifference(self, root: TreeNode) -> int:
        if not root: return 0

        stack = []

        def dfs(root):
            if not root: return
            stack.append(root.val)
            dfs(root.left)
            dfs(root.right)
        dfs(root)

        stack.sort()
        result = stack[1] - stack[0]
        for i in range(1, len(stack)):
            diff = stack[i] - stack[i-1]
            if diff < result:
                result = diff

        return result


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
from model import ConditionalGAN
from datetime import datetime
import os, time
import logging
import ops
from importdata import read_data_sets
import numpy as np
import scipy.io as scio

FLAGS = tf.flags.FLAGS

tf.flags.DEFINE_integer('batch_size', 256, 'batch size, default: 256')
tf.flags.DEFINE_integer('num_ant', 64, 'number of antennas, default: 32')
tf.flags.DEFINE_integer('layers', 1, 'real and imaginary parts, default: 2')
tf.flags.DEFINE_integer('omni_size', 512, 'length of omni training sequence, default: 512')
tf.flags.DEFINE_integer('z_size', 100, 'length of random vector z')
tf.flags.DEFINE_float('learning_rate', 2e-4,
                      'initial learning rate for Adam, default: 0.0002')
tf.flags.DEFINE_string('filename_db_tr', 'Datasets/ML_input_street_LOS_training_n21.mat',
                       'file for training, default: num_ant=32, 50k samples')
tf.flags.DEFINE_string('filename_db_test', 'Datasets/ML_input_street_LOS_test_n21.mat',
                       'file for testing, default: num_ant=32, 1k samples')
tf.flags.DEFINE_float('db_size_percent', 1, 'Percentage of dataset used in training, default: 1')
tf.flags.DEFINE_bool('HDF5file', False, 'Dataset file is HDF5 format, default: True')
tf.flags.DEFINE_string('load_model', None,
                        'folder of saved model that you wish to continue training (e.g. 20170602-1936), default: None')

def train():
  if FLAGS.load_model is not None:
    checkpoints_dir = "checkpoints/" + FLAGS.load_model.lstrip("checkpoints/")
  else:
    current_time = datetime.now().strftime("%Y%m%d-%H%M")
    checkpoints_dir = "checkpoints/{}".format(current_time)
    try:
      os.makedirs(checkpoints_dir)
    except os.error:
      pass

  graph = tf.Graph()
  with graph.as_default():
    cgan = ConditionalGAN(
        batch_size=FLAGS.batch_size,
        num_ant=FLAGS.num_ant,
        layers=FLAGS.layers,
        learning_rate=FLAGS.learning_rate,
        omni_size=FLAGS.omni_size,
        z_size=FLAGS.z_size
    )
    G_loss, D_loss, fake_x, mse = cgan.model()
    optimizersG = cgan.G_optimize(G_loss)
    optimizersD = cgan.D_optimize(D_loss)

    summary_op = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter(checkpoints_dir, graph)
    saver = tf.train.Saver()
  train, testset = read_data_sets(FLAGS.filename_db_tr, FLAGS.filename_db_test, FLAGS.db_size_percent, FLAGS.HDF5file)
  test_size = testset.omni.shape[0]
  test_nmse = 1

  with tf.Session(graph=graph) as sess:
    if FLAGS.load_model is not None:
      checkpoint = tf.train.get_checkpoint_state(checkpoints_dir)
      meta_graph_path = checkpoint.model_checkpoint_path + ".meta"
      restore = tf.train.import_meta_graph(meta_graph_path)
      restore.restore(sess, tf.train.latest_checkpoint(checkpoints_dir))
      step = int(meta_graph_path.split("-")[2].split(".")[0])
    else:
      sess.run(tf.global_variables_initializer())
      step = 0

    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(sess=sess, coord=coord)

    try:

      while not coord.should_stop():
        # train
        rg, _, omni = train.next_batch(FLAGS.batch_size)
        if FLAGS.layers == 2:
          rg_r = np.reshape(rg, [FLAGS.batch_size, FLAGS.num_ant, FLAGS.num_ant, FLAGS.layers])
        else:
          rg_r = rg[:, ::2]
          rg_r = np.reshape(rg_r, [-1, FLAGS.num_ant, FLAGS.num_ant, 1])
        omni_real_reshaped = ops.omni_reshape(omni, FLAGS.batch_size, FLAGS.omni_size)
        _, _, fake_omni = train.next_batch(FLAGS.batch_size)
        omni_fake_reshaped = ops.omni_reshape(fake_omni, FLAGS.batch_size, FLAGS.omni_size)
        omni = np.reshape(omni, [-1, 1, 1, FLAGS.omni_size])
        z_value = np.random.uniform(-1., 1., size=(FLAGS.batch_size, FLAGS.z_size)).astype(np.float32)
        z_value = np.reshape(z_value, [-1, 1, 1, FLAGS.z_size])

        _, D_loss_val, summary = (
              sess.run(
                  [optimizersD, D_loss, summary_op],
                  feed_dict={cgan.z: z_value, cgan.x: rg_r, cgan.y: omni,
                             cgan.y1: omni_real_reshaped, cgan.y2: omni_fake_reshaped}
              )
        )
        rg, _, omni = train.next_batch(FLAGS.batch_size)
        if FLAGS.layers == 2:
          rg_r = np.reshape(rg, [FLAGS.batch_size, FLAGS.num_ant, FLAGS.num_ant, FLAGS.layers])
        else:
          rg_r = rg[:, ::2]
          rg_r = np.reshape(rg_r, [-1, FLAGS.num_ant, FLAGS.num_ant, 1])
        omni_real_reshaped = ops.omni_reshape(omni, FLAGS.batch_size, FLAGS.omni_size)
        omni = np.reshape(omni, [-1, 1, 1, FLAGS.omni_size])
        z_value = np.random.uniform(-1., 1., size=(FLAGS.batch_size, FLAGS.z_size)).astype(np.float32)
        z_value = np.reshape(z_value, [-1, 1, 1, FLAGS.z_size])
        _, G_loss_val = (
          sess.run(
            [optimizersG, G_loss],
            feed_dict={cgan.z: z_value, cgan.x: rg_r, cgan.y: omni,
                       cgan.y1: omni_real_reshaped}
          )
        )
        train_writer.add_summary(summary, step)
        train_writer.flush()
        if step % 5 == 0:
          train_mse = mse.eval(feed_dict={cgan.x: rg_r, cgan.z: z_value, cgan.y: omni})
          z_value = np.random.uniform(-1., 1., size=(test_size, FLAGS.z_size)).astype(np.float32)
          z_value = np.reshape(z_value, [-1, 1, 1, FLAGS.z_size])
          omni_test = np.reshape(testset.omni, [-1, 1, 1, FLAGS.omni_size])
          samples = sess.run(fake_x, feed_dict={cgan.z: z_value, cgan.y: omni_test, cgan.is_training: False})
          if FLAGS.layers == 2:
            rg_test = np.reshape(testset.rg, [test_size, FLAGS.num_ant, FLAGS.num_ant, 2])
          else:
            rg_test = testset.rg[:, ::2]
            rg_test = np.reshape(rg_test, [test_size, FLAGS.num_ant, FLAGS.num_ant, 1])
          nmse = np.zeros([test_size, 1], dtype=np.float64)
          for i2 in range(test_size):
            nmse[i2] = np.sum(np.square(np.abs(rg_test[i2, :, :, :] - samples[i2, :, :, :]))) / np.sum(
              np.square(np.abs(rg_test[i2, :, :, :])))
          test_nmse = np.sum(nmse) / test_size
          if test_nmse < 0.0008:
            filename_db_save = 'Estimated_results/Estimated_cov_mat_%d_mse_%g.mat' % (step, test_nmse)
            scio.savemat(filename_db_save,
                         {'R_estimated': samples, 'saved_omni_test': testset.omni, 'test_nmse': test_nmse,
                          'D_loss': G_loss_val,
                          'G_loss': G_loss_val})
          print("step %d, training_MSE %g, test_NMSE %g, D_loss %g, G_loss %g" % (
          step, train_mse, test_nmse, D_loss_val, G_loss_val))

        if step % 100 == 0:
          logging.info('-----------Step %d:-------------' % step)
          logging.info('  G_loss   : {}'.format(G_loss_val))
          logging.info('  D_loss   : {}'.format(D_loss_val))

        if step % 10000 == 0:
          save_path = saver.save(sess, checkpoints_dir + "/model.ckpt", global_step=step)
          logging.info("Model saved in file: %s" % save_path)

        step += 1

    except KeyboardInterrupt:
      logging.info('Interrupted')
      coord.request_stop()
    except Exception as e:
      coord.request_stop(e)
    finally:
      save_path = saver.save(sess, checkpoints_dir + "/model.ckpt", global_step=step)
      logging.info("Model saved in file: %s" % save_path)
      # When done, ask the threads to stop.
      coord.request_stop()
      coord.join(threads)

def main(unused_argv):
  train()

if __name__ == '__main__':
  logging.basicConfig(level=logging.INFO)
  tf.app.run()


import numpy as np
import sympy
import sys
matrix = np.array([
    [6, -3, 4, 10],
    [10, 6, 11, 20],
    [-9, 10, 55, 21],
    [-6, -3, 12, 3]
])

matrixB = np.array([
    [4, 1, 2, 0],
    [21, 44, 1, -20],
    [-9, 0, 5, 100],
    [-6, 3, 12, 30]
])
rows = len(matrix)
cols = len(matrix[0])

def Print(matrix):
    print(matrix)

# Tính tổng tất cả các phần tử trên mảng.

def sommeDeMatrice(matrix):
    # cách 1: dùng thuật toán bình thường
    # sum = 0
    # for i in range(rows):
    #     for j in range(cols):
    #         sum += matrix[i][j]
    # print(sum)

    # cách 2: dùng numpy
    print("Somme de tous les elements de la matrice: ", np.sum(matrix))

# Đếm số lần xuất hiện một phần tử x bất kỳ.
def nombre_De_Occurrences(matrix, x):
    count = 0
    for i in range(rows):
        for j in range(cols):
            if matrix[i][j] == x:
                count += 1
    print("Le nombre d'occurrences du ", x, "est ", count, "fois")

# Đếm số lần xuất hiện của các số nguyên tố.
def nombrePremier_Occurrences(matrix):

    listPremier = [matrix[i][j] for i in range(rows) for j in range(cols) if sympy.isprime(
        matrix[i][j])]  # sympy.isprime est methode pour chercher nombre premier (je veux tester au lieu d'ecrire la fonction de test principale)
    list = np.unique(listPremier)   # np.unique: values uniques du listPremier
    print('Nombres premiers sont: ', list)
    for i in list:
        nombre_De_Occurrences(matrix, i)

# Tính tổng tất cả các phần tử không âm.

def sommeNonNegatifs(matrix):
    sum = 0
    for i in range(rows):
        for j in range(cols):
            if matrix[i][j] >= 0:
                sum += matrix[i][j]
    print("Somme des non nombres negatifs dans la matrice est: ", sum)

# Tính tổng các phần tử trên đường chéo chính.

def sommeDiagonale_Principale(matrix):
    if rows != cols:
        print("Ce n'est pas une matrice, entrez une matrice (tableaux a 2 dimensions avec lignes = columnes)")
        exit()

    # si utilise numpy
    diagonal_1 = sum(np.diagonal(matrix))

    # utilise l'algorithme
    # diagonal_1 = sum(matrix[i][i] for i in range(rows))  # các phần tử theo đường chéo chính\

    print("Somme des nombres sur la matrice principale en diagonale est: ", diagonal_1)

# Kiểm tra các phần tử trên đường chéo chính có tăng hay không.

def verifierTri_diaPrin(matrix):
    if rows != cols:
        print("Ce n'est pas une matrice, entrez une matrice (tableaux a 2 dimensions avec lignes = columnes)")
        exit()

    flag = False
    diagonal_1 = np.diagonal(matrix)
    for i in range(len(diagonal_1)-1):
        if diagonal_1[i+1] >= diagonal_1[i]:
            flag = True
        else:
            flag = False
    if flag:
        print('Nombres sur la matrice principale en diagonale sont disposes par ordre croissant')
    else:
        print("Nombres sur la matrice principale en diagonale ne sont pas par ordre croissant")

# Tính tổng các phần tử trên đường chéo phụ.
def sommeDiagonale_Secondaire(matrix):
    if rows != cols:
        print("Ce n'est pas une matrice, entrez une matrice (tableaux a 2 dimensions avec lignes = columnes)")
        exit()
    #diagonale_2 = [matrix[i][rows-1-i] for i in range(rows)] #utilise l'algorithme
    diagonale_2 = np.diag(np.fliplr(matrix)) #utilise numpy
    print("Nomme des nombres sur la matrice en diagonale secondaire est: ", sum(diagonale_2))

#Sắp xếp các phần tử trên mảng tăng dần trên từng dòng.
def triElements_Lignes(matrix):
    for i in range(rows):
        matrix[i].sort()
    print('Nouvelle matrice: ')
    Print(matrix)

#Tìm giá phần tử lớn nhất và nhỏ nhất trên từng dòng, từng cột, và trên toàn ma trận.
def minMax(matrix):
    minLigne , maxLigne , minCol , maxCol = [], [], [], []

    # dans chaque ligne
    for i in range(rows):
        minLigne.append(min(matrix[i]))
        maxLigne.append(max(matrix[i]))

    print("Nombres minimum dans lignes de matrice: ", minLigne)
    print("Nombre maximum dans lignes de matrice: ", maxLigne)

    #dans chaque comlumne
    for i in range(cols):
        minCol.append(min(matrix[:,i]))
        maxCol.append(max(matrix[:,i]))
    print("Nombres minimum dans columnes de matrice: ",  minCol)
    print("Nombres maximum dans columnes de matrice: ", maxCol)

    #max et min dans matrix: C'est le plus peptit nombre dans le tableau des plus petits nombres a des lignes (ou colume) de la matrice, idem pour trover max
    print("Nombre maximum dans cette matrice: ", max(maxLigne))
    print("Nombre minimum dans cette matrice: ", min(minLigne))

#Tìm và đưa phần tử lớn nhất trên mỗi dòng về vị trí nằm trên đường chéo chính.
def remplacerDiagonale(matrix):
    if rows != cols:
        print("Ce n'est pas une matrice, entrez une matrice (tableaux a 2 dimensions avec lignes = columnes)")
        exit()

    for i in range(rows):
        maxi = max(matrix[i])
        if matrix[i][i] == maxi:
            continue
        else:
            for j in range(cols):
                if matrix[i][j] == maxi:
                    matrix[i][j], matrix[i][i] = matrix[i][i], matrix[i][j]

    print('\nNouvelle matrice: ')
    Print(matrix)

#Tính tổng và tích 2 ma trận vuông n x n.
def additionMatrices(matrixA, matrixB):
    if len(matrixA) != len(matrixB) or len(matrixA[0]) != len(matrixB[0]):
        print('2 matrices ne sont pas de la meme taille')
        exit()

    #utilise l'algorithme
    # result = np.zeros((len(matrixA),len(matrixA)))
    # for i in range(rows):
    #     for j in range(cols):
    #         result[i][j] = matrixA[i][j] + matrixB[i][j]
    # print(result)

    #utilise numpy
    print('addition des 2 matrices: ')
    print(matrixA + matrixB)
    print('Multiplicaton des 2 matrices: ')
    print(matrixA * matrixB)

#Hãy sắp xếp ma trận A(m x n) sao cho dòng có tổng nhỏ hơn nằm ở trên và dòng có tổng lớn hơn nằm ở dưới.
def swapLignes(matrix):
    sommeLigne = []
    for i in range(rows):
        sommeLigne.append(sum(matrix[i]))
    print(sommeLigne)
    i = 0
    while (i < rows):
        maxIndex = sommeLigne.index(max(sommeLigne))

        matrix[[i, maxIndex]] = matrix[[maxIndex, i]]
        sommeLigne.remove(max(sommeLigne))
        i +=1

    print('Nouvelle matrice: ')
    Print(matrix)

def main():
    Print(matrix)

    # Tính tổng tất cả các phần tử trên mảng.
    # sommeDeMatrice(matrix)

    # Đếm số lần xuất hiện một phần tử x bất kỳ.
    #nombre_De_Occurrences(matrix, 10)

    # Đếm số lần xuất hiện của các số nguyên tố.
    # nombrePremier_Occurrences(matrix)

    # Tính tổng tất cả các phần tử không âm.
    # sommeNonNegatifs(matrix)

    # Tính tổng các phần tử trên đường chéo chính.
    # sommeDiagonale_Principale(matrix)

    # Kiểm tra các phần tử trên đường chéo chính có tăng hay không.
    #verifierTri_diaPrin(matrix)

    # Tính tổng các phần tử trên đường chéo phụ.
    #sommeDiagonale_Secondaire(matrix)

    #Sắp xếp các phần tử trên mảng tăng dần trên từng dòng.
    #triElements_Lignes(matrix)

    #Tìm giá phần tử lớn nhất và nhỏ nhất trên từng dòng, từng cột, và trên toàn ma trận.
    #minMax(matrix)

    #Tìm và đưa phần tử lớn nhất trên mỗi dòng về vị trí nằm trên đường chéo chính.
    #remplacerDiagonale(matrix)

    #Tính tổng và tích 2 ma trận vuông n x n.
    #additionMatrices(matrix, matrixB)

    #Hãy sắp xếp ma trận A(m x n) sao cho dòng có tổng nhỏ hơn nằm ở trên và dòng có tổng lớn hơn nằm ở dưới.
    #swapLignes(matrix)

if __name__ == "__main__":
    main()


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

# DS = np.array([89.22, 88.04, 89.11, 88.64, 88.94])
#
# kernel_3 = np.array([90.13, 90.59, 91.51, 90.43, 90.26])
#
# # kernel_5 = np.array([91.05, 91.97, 91.57, 92.43, 91.84])
#
# mean, std = JH_utile.meanstd2(kernel_5)
# print()

True_label = ["Baseline", "Loaded", "Rapid"]

predicted_class = ["Baseline", "Loaded", "Rapid"]

conf_matrix = np.array([[0.92, 0.06, 0.03],
                        [0.10, 0.81, 0.10],
                        [0.02, 0.02, 0.96],
                        ])

fig, ax = plt.subplots()

im, cbar = JH_utile.heatmap(conf_matrix, True_label, predicted_class, ax=ax,
                   cmap="jet", cbarlabel="data range")
texts = JH_utile.annotate_heatmap(im, valfmt="{x:.2f}", threshold=0.5)

fig.tight_layout()
plt.show()

fig.savefig('data_plot')