# -*- coding: utf-8 -*-
print('03、python中的装饰器与迭代器:')

def addTips(fun):
	def warp(*args, **kwargs):
		print('这是操作之前：')
		result = fun(*args, **kwargs)
		print('这是操作之后：');
		return result
	return warp

@addTips
def add(x, y):
	return x+y

print('add(2, 3) = ', add(2, 3))

#fortest2
def addTips(i):
    def wrap1(fun):
        def wrap(*args, **kwargs):
            print('这是操作之前')
            result = 0
            if i > 10:
                result = fun(*args, **kwargs)
            else:
                print('对不起，没有执行fun的权限')
            print('操作结束啦！')
            return result
        return wrap
    return wrap1

@addTips(11)
def add(x, y):
    return x+y

print(add(2, 3))

# 迭代器（iterator）
# 可迭代的对象：如果一个对象可以用for in 的方式遍历其内容 就是一个可迭代的对象 list tuple 字典
# 迭代器：遍历可迭代对象内容的方式
# 常见的迭代器：组合 排列 笛卡尔积  串联迭代器
# 排列 组合 笛卡尔积 串联迭代器
import itertools
x = range(1, 5)
y = list('abc')
#排列
com1 = itertools.combinations(x, 3)
#组合
com2 = itertools.permutations(x, 3)
#笛卡尔积
com3 = itertools.product(x, y)
#串联迭代器
com4 = itertools.chain(com1, com2, com3)
print('for in com4')
for i in com4:
	print(i)


# 跟第7题想法类似
class Solution:
    def myAtoi(self, str: str) -> int:
        num = ['0','1','2','3','4','5','6','7','8','9']
        flag = 0
        sub = 0
        pn = 0
        bond = (1<<31)-1
        for i in range(len(str)):
            if str[i] == ' ' and flag == 0:
                continue
            if str[i] == '+' and flag == 0:
                flag = 1
                continue
            if str[i] == '-' and flag == 0:
                pn = 1
                bond = bond+1
                flag = 1
                continue
            if str[i] not in num:
                break
            flag = 1
            sub = sub*10 + int(str[i])
            if sub > bond:
                sub = bond
                break
        return sub if pn == 0 else -sub

# 正则化表达式：
import re
class Solution:
    def myAtoi(self, str: str) -> int:
        INT_MAX = 2147483647
        INT_MIN = -2147483648
        str = str.lstrip()      #清除左边多余的空格
        num_re = re.compile(r'^[\+\-]?\d+')   #设置正则规则
        num = num_re.findall(str)   #查找匹配的内容
        num = int(*num) #由于返回的是个列表，解包并且转换成整数
        return max(min(num,INT_MAX),INT_MIN)    #返回值

# 简化后
class Solution:
    def myAtoi(self, s: str) -> int:
        return max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2**31 - 1), -2**31)


for i in range(10):
    print(i, end=" ")

    if i == 6:
        break
print()

i=0
while i<10:
    if i==6:
        i+=1
        continue
    else:
        print(i, end= ' ')
    i +=1

print('\r')
j=20
if  j==10:
    print('j is 10')
elif j==20:
    print('j is 20')
else:
    print('j is not present')


UNDEFINED = "/UNDEFINED/"
UNDEFINEDINT = -10086
MSGTYPES = ["text", "audio", "document", "photo", "sticker", "video", "contact", "location", "new_chat_participant", "left_chat_participant", "new_chat_title", "new_chat_photo", "delete_chat_photo", "group_chat_created"]
# Here are origin classes in telegram robot API

class Update:
    def __init__(self, update_id, message):
        self.update_id = int(update_id)
        if message.__class__ != Message:
            raise TypeError
        self.message = message

class User:
    def __init__(self, id, firstname, lastname=UNDEFINED, username=UNDEFINED):
        self.id = int(id)
        self.firstname = str(firstname)
        self.lastname = str(lastname)
        self.username = str(username)

class GroupChat:
    def __init__(self, id, title):
        self.id = int(id)
        self.title = str(title)

class PhotoSize:
    def __init__(self, file_id, width, height, file_size=UNDEFINEDINT):
        self.file_id = file_id
        self.width = int(width)
        self.height = int(height)
        self.file_size = int(file_size)

class Audio:
    def __init__(self, file_id, duration, mime_type=UNDEFINED, file_size=UNDEFINEDINT):
        self.file_id = str(file_id)
        self.duration = str(duration)
        self.mime_type = str(mime_type)
        self.file_size = int(file_size)

class Document:
    def __init__(self, file_id, thumb, file_name = UNDEFINED, mime_type = UNDEFINED, file_size = UNDEFINEDINT):
        self.file_id = file_id
        if thumb.__class__ != PhotoSize:
            raise TypeError
        else:
            self.thumb = thumb
            self.file_name = str(file_name)
            self.mime_type = str(mime_type)
            self.file_size = int(file_size)

class Sticker:
    def __init__(self, file_id, width, height, thumb, file_size=UNDEFINEDINT):
        self.file_id = str(file_id)
        self.width = int(width)
        self.height = int(height)
        if thumb.__class__ != PhotoSize:
            raise TypeError
        else:
            self.thumb = thumb
            self.file_size = int(file_size)

class Video:
    def __init__(self, file_id, width, height, duration, thumb, mime_type=UNDEFINED, file_size=UNDEFINEDINT, caption=UNDEFINED):
        self.file_id = str(file_id)
        self.width = int(width)
        self.height = int(height)
        self.duration = int(duration)
        if thumb.__class__ != PhotoSize:
            raise TypeError
        else:
            self.thumb = thumb
            self.file_name = str(caption)
            self.mime_type = str(mime_type)
            self.file_size = int(file_size)

class Contact:
    def __init__(self, phone_number, first_name, last_name=UNDEFINED, user_id = UNDEFINED):
        self.phone_number = str(phone_number)
        self.first_name = str(first_name)
        self.last_name = str(last_name)
        self.user_id = str(user_id)

class Location:
    def __init__(self, longitude, latitude):
        self.longitude = float(longitude)
        self.latitude = float(latitude)

class UserProfilePhotos:
    def __init__(self, total_count, photos):
        self.total_count = int(total_count)
        self.photos = photos

class ReplyKeyboardMarkup:
    def __init__(self, keyboard, resize_keyboard, one_time_keyboard=False, selective=False):
        self.keyboard = keyboard
        self.resize_keyboard = bool(resize_keyboard)
        self.one_time_keyboard = bool(one_time_keyboard)
        self.selective = bool(selective)

class ReplyKeyboardHide:
    def __init__(self, hide_keyboard=True, selective=False):
        self.hide_keyboard = bool(hide_keyboard)
        self.selevtive = bool(selective)

class Message:
    def __init__(self, message_id, sender, date, chat, contain, msgtype=MSGTYPES[0], foward_from=None, foward_date=UNDEFINEDINT, reply_to_message=None):
        self.message_id = int(message_id)
        if sender.__class__ != User:
            raise TypeError
        self.sender = sender
        self.date = int(date)
        if chat.__class__ != User and chat.__class__ != GroupChat:
            raise TypeError
        self.chat = chat
        self.contain = contain
        if foward_from.__class__ != User and foward_from is not None:
            raise TypeError
        self.foward_from = foward_from
        self.foward_date = int(foward_date)
        if reply_to_message.__class__ != Message and reply_to_message is not None:
            raise TypeError
        self.reply_to_message = reply_to_message
        self.msgtype = msgtype

class ForceReply:
    def __init__(self, selective = False):
        self.force_reply = True
        self.selective = bool(selective)


# -*- coding: utf-8 -*-
"""
Created on Thu Jan 20 16:19:30 2022

@author: Lab User
"""

#%% Import libraries

import beepy
from calc_ds import *
from compartment import Compartment
import fireSpreadMain as fs
from GMprocessing import *
import igraph as ig
import intensity as im
from loadall import *
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import pickle
from pytictoc import TicToc; t = TicToc()
import random
import seaborn as sns
from scipy import stats, optimize
import sprinkler_hydraulics as spr
import sys
from wall import Wall
from window import Window, Door
import wntr

#%% Toggles and Options
toggle_read = False
toggle_plot = False
toggle_plot_old = True
toggle_plot_Sa = False
pickleOut = 'outputDict1'
pickleIn = 'outputDict1'

#%% Some set up

nSamples = 100

# earthquake records path
username = "Lab User"
pathER = r"C:/Users/"+username+r"/OneDrive/Documents/OpenSees/9st_mrf_mwc/GMs_Full_Suite/"

# fire spread samples path
pathBC = r"C:/Users/"+username+r"/OneDrive/Documents/OpenSees/PythonFiles-OS/BCpickle1/"

# water network samples path
pathWN = r"C:/Users/"+username+r"/OneDrive/Documents/OpenSees/PythonFiles-OS/WNpickle1/"

# main path
pathMAIN = r"C:/Users/"+username+r"/OneDrive/Documents/OpenSees/PythonFiles-OS/"

# Grab all directory names in the burning compartment path
dn = []
fn = []
for (dirpath, dirnames, filenames) in os.walk(pathBC):
    dn.extend(dirnames)
    fn.extend(filenames)
    break

# Split the directories into lagrande and seattle
def splitList(x,a=0,b=8):
    recdict = dict()
    for recname in x:
        rec = recname[a:b]
        if rec in recdict.keys():
            recdict[rec].append(recname)
        else:
            recdict[rec] = [recname]
    return recdict

fd = splitList(fn)
shapeErrorList = []

# Define a function to grab PGA from file
def getPGA(PATHIN):
    with open(PATHIN,'r') as f:
        data = [float(val) for val in f]
        PGA = max(data, key=abs)
    return PGA

LOCd = {}

#%% Main Reader

if toggle_read:
    # Loop through locations
    for fk, fi in fd.items():
        print('==============================================')
        print('|       Record Set: {}                 |'.format(fk))
        print('==============================================')
        print()
        rd = splitList(fi,0,-13)
        RECd = {}
        # Loop through earthquake records at location
        for rk, ri in rd.items():
            print('  ==============================================')
            print('  |       Record: {}             |'.format(rk))
            print('  ==============================================')
            print()
            recname = rk[3::]+'.txt'
            PGA = abs(getPGA(pathER+recname))
            IMcomb,IMdetails = get_IMcomb(rk[3::],T1=1.75,plot=toggle_plot_Sa,toggle_print=False)
            nSIM = 0
            nBClist = []
            nLEAKlist = []
            # Loop through MC sims
            for r in ri:
                nSIM += 1
                print('    MC sim: {:s}'.format(r[-12:-7]))
                print('    PGA: {:0.3f} [g]'.format(PGA))
                print('    IMcomb: {:0.3f}'.format(IMcomb))
                # Load the pickled fire sim results
                with open(pathBC+r,'rb') as f:
                    bc = pickle.load(f)

                    nBC = len(bc)
                    nBClist.append(nBC)
                    print('     No. of burning compartments: {:d}'.format(nBC))
                    # Loop through compartments
                    for ck, ci in bc.items():
                        try:
                            print('      {0:s} began burning at time {1:0.1f} and decayed at time {2:0.1f}'.format(ci.get_name(),ci.time_of_ignition,ci.time_of_ignition+ci.time_of_decay))
                        except TypeError:
                            print('      {0:s} began burning, (warning: TypeError)'.format(ci.get_name()))
                    print()
                # Load the pickled hydraulic sim results
                w = r.replace('BC_','wn-')
                try:
                    with open(pathWN+w,'rb') as f:
                        wn = pickle.load(f)
                        wn_ds = wn[2][0]
                        nleaks = sum(wn_ds[2:4])
                        nLEAKlist.append(nleaks)

                        print('      No. of leaks: {}'.format(nleaks))
                except:
                    print('      No hydraulic data for this sim')
                    nLEAKlist.append(-1.)
                    print()
                    continue
                print()

        # lndist = stats.lognorm.fit(nBClist,loc=0)
        # print('      '+str(lndist))
            print()
            RECd[rk] = {'Loc':fk,'nSIM':nSIM,'PGA_g':PGA,'IMcomb':IMcomb,'nBC':nBClist,'nLEAK':nLEAKlist}

        LOCd[fk] = RECd
        f=open(pathMAIN+pickleOut+".pickle",'wb')
        pickle.dump(LOCd,f)
        f.close()

#%% FORMATTING RESULTS
# Grab the pickled output file if not generated
if not toggle_read:
    with open(pathMAIN+pickleIn+".pickle",'rb') as f:
        LOCd = pickle.load(f)
frames = []
for lk, li in LOCd.items():
    frames.append(pd.DataFrame(li).transpose())
df = pd.concat(frames)
dfex = df.set_index(['Loc','nSIM','PGA_g','IMcomb']).apply(pd.Series.explode).reset_index()
# df = df.explode(["nBC","nLEAK"])
pd.set_option('display.max_columns',None)

ds0 = 1
ds1 = 4
ds2 = 8
ds3 = 100

ds = [ds0,ds1,ds2,ds3]

df.sort_values(by='PGA_g',inplace=True)

# df['ds0'] = df.apply(lambda row: sum((x == ds0) for x in row.nBC)/row.nSIM,axis=1)
df['ds1'] = df.apply(lambda row: sum((x > ds0) for x in row.nBC)/row.nSIM,axis=1)
df['ds2'] = df.apply(lambda row: sum((x > ds1) for x in row.nBC)/row.nSIM,axis=1)
df['ds3'] = df.apply(lambda row: sum((x > ds2) for x in row.nBC)/row.nSIM,axis=1)

#%% Fit Data
# Set up lognormal function - note, scipy has a weird formulation for this. Look it up.
f_ln = lambda x,mu,sigma: stats.lognorm(s=sigma, scale=np.exp(mu)).cdf(x)
f_norm = lambda x,mu,sigma: stats.norm(loc=sigma,scale=mu).cdf(x)
f_gamma = lambda x,a,b: stats.gamma(a=a,scale=1/b).cdf(x)
f_weibull_min = lambda x,c,s: stats.weibull_min(c=c,scale=s).cdf(x)
f_weibull_max = lambda x,c,s: stats.weibull_max(c=c,scale=s).cdf(x)
f_log = lambda x,th1,th2: np.exp(th1+th2*x)/(1+np.exp(th1+th2*x))

f = {'Norm':f_norm,
     'Lognorm':f_ln,
     # 'Gamma':f_gamma,
     # 'Weibull_min':f_weibull_min,
     # 'Weibull_max':f_weibull_max,
     'Logistic': f_log
     }

# PGA
for k, func in f.items():
    # LaGrande
    LGx1 = df['PGA_g'].loc[df['Loc']=='BC_LaGra'].to_list()
    LGy1 = df['ds1'].loc[df['Loc']=='BC_LaGra'].to_list()
    mu1_lg, sigma1_lg = optimize.curve_fit(func,LGx1,LGy1)[0]
    # _,_,r_lg1,_,_ = stats.linregress(LGy1,func(LGx1,mu1_lg,sigma1_lg))
    _,_,r_lg1,_,_ = stats.linregress(LGy1,[func(x,mu1_lg,sigma1_lg) for x in LGx1])
    r2_lg1 = r_lg1**2

    LGx2 = df['PGA_g'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
    LGy2 = df['ds2'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
    mu2_lg, sigma2_lg = optimize.curve_fit(func,LGx2,LGy2)[0]
    _,_,r_lg2,_,_ = stats.linregress(LGy2,[func(x,mu2_lg,sigma2_lg) for x in LGx2])
    r2_lg2 = r_lg2**2

    LGx3 = df['PGA_g'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
    LGy3 = df['ds3'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
    mu3_lg, sigma3_lg = optimize.curve_fit(func,LGx3,LGy3)[0]
    _,_,r_lg3,_,_ = stats.linregress(LGy3,[func(x,mu3_lg,sigma3_lg) for x in LGx3])
    r2_lg3 = r_lg3**2

    # Seattle
    SEx1 = df['PGA_g'].loc[df['Loc']=='BC_Seatt'].to_list()#[1:-1]
    SEy1 = df['ds1'].loc[df['Loc']=='BC_Seatt'].to_list()#[1:-1]
    mu1_se, sigma1_se = optimize.curve_fit(func,SEx1,SEy1)[0]
    # _,_,r_se1,_,_ = stats.linregress(SEy1,func(SEx1,mu1_se,sigma1_se))
    _,_,r_se1,_,_ = stats.linregress(SEy1,[func(x,mu1_se,sigma1_se) for x in SEx1])
    r2_se1 = r_se1**2

    SEx2 = df['PGA_g'].loc[df['Loc']=='BC_Seatt'].to_list()#[1:-1]
    SEy2 = df['ds2'].loc[df['Loc']=='BC_Seatt'].to_list()#[1:-1]
    mu2_se, sigma2_se = optimize.curve_fit(func,SEx2,SEy2)[0]
    _,_,r_se2,_,_ = stats.linregress(SEy2,[func(x,mu2_se,sigma2_se) for x in SEx2])
    r2_se2 = r_se2**2

    SEx3 = df['PGA_g'].loc[df['Loc']=='BC_Seatt'].to_list()#[1:-1]
    SEy3 = df['ds3'].loc[df['Loc']=='BC_Seatt'].to_list()#[1:-1]
    mu3_se, sigma3_se = optimize.curve_fit(func,SEx3,SEy3)[0]
    _,_,r_se3,_,_ = stats.linregress(SEy3,[func(x,mu3_se,sigma3_se) for x in SEx3])
    r2_se3 = r_se3**2

    # BOTH
    BOx1 = df['PGA_g'].to_list()[:] #[1:-1]
    BOy1 = df['ds1'].to_list()[:] #[1:-1]
    mu1_bo, sigma1_bo = optimize.curve_fit(func,BOx1,BOy1)[0]
    _,_,r_bo1,_,_ = stats.linregress(BOy1,[func(x,mu1_bo,sigma1_bo) for x in BOx1])
    r2_bo1 = r_bo1**2

    BOx2 = df['PGA_g'].to_list()[:] #[1:-1]
    BOy2 = df['ds2'].to_list()[:] #[1:-1]
    mu2_bo, sigma2_bo = optimize.curve_fit(func,BOx2,BOy2)[0]
    _,_,r_bo2,_,_ = stats.linregress(BOy2,[func(x,mu2_bo,sigma2_bo) for x in BOx2])
    r2_bo2 = r_bo2**2

    BOx3 = df['PGA_g'].to_list()[:] #[1:-1]
    BOy3 = df['ds3'].to_list()[:] #[1:-1]
    mu3_bo, sigma3_bo = optimize.curve_fit(func,BOx3,BOy3)[0]
    _,_,r_bo3,_,_ = stats.linregress(BOy3,[func(x,mu3_bo,sigma3_bo) for x in BOx3])
    r2_bo3 = r_bo3**2

    print()
    print('========================')
    print('Curve type: {:s}, IM = PGA (g)'.format(k))
    print('  LaGrande')
    print('    ds1:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu1_lg,sigma1_lg,r2_lg1))
    print('    ds2:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu2_lg,sigma2_lg,r2_lg2))
    print('    ds3:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu3_lg,sigma3_lg,r2_lg3))
    print('  Seattle')
    print('    ds1:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu1_se,sigma1_se,r2_se1))
    print('    ds2:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu2_se,sigma2_se,r2_se2))
    print('    ds3:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu3_se,sigma3_se,r2_se3))
    print('  Both')
    print('    ds1:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu1_bo,sigma1_bo,r2_bo1))
    print('    ds2:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu2_bo,sigma2_bo,r2_bo2))
    print('    ds3:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu3_bo,sigma3_bo,r2_bo3))

    #%% PLOTTING
    if toggle_plot:
        x = np.linspace(0,0.5,100)

        plt.figure(11)
        ax11 = df.loc[df['Loc']=='BC_LaGra'].plot(x="PGA_g",y="ds1",kind="scatter", color='r', marker='d', s=20, label="ds1")
        ax11 = df.loc[df['Loc']=='BC_LaGra'].plot(x="PGA_g",y="ds2",kind="scatter", color='g', marker='s', s=10, label="ds2",ax=ax11)
        ax11 = df.loc[df['Loc']=='BC_LaGra'].plot(x="PGA_g",y="ds3",kind="scatter", color='b', marker='o', s=10, label="ds3",ax=ax11)
        ax11.plot(x,func(x,mu1_lg,sigma1_lg),'r--',label='ds1_fit, $r^2$={0:0.3f}'.format(r2_lg1))
        ax11.plot(x,func(x,mu2_lg,sigma2_lg),'g--',label='ds2_fit, $r^2$={0:0.3f}'.format(r2_lg2))
        ax11.plot(x,func(x,mu3_lg,sigma3_lg),'b--',label='ds3_fit, $r^2$={0:0.3f}'.format(r2_lg2))
        ax11.legend(loc="upper left")
        ax11.grid(visible=True)
        ax11.set_xlim(0.0,0.4)
        ax11.set_ylim(-0.05,1.1)
        ax11.set_xlabel("PGA (g)")
        ax11.set_ylabel("Likelihood")
        title = '{:s} CDF, LaGrande'.format(k)
        ax11.set_title(title)
        plt.show()

        plt.figure(12)
        ax12 = df.loc[df['Loc']=='BC_Seatt'].plot(x="PGA_g",y="ds1",kind="scatter", color='r', marker='d', s=20, label="ds1")
        ax12 = df.loc[df['Loc']=='BC_Seatt'].plot(x="PGA_g",y="ds2",kind="scatter", color='g', marker='s', s=10, label="ds2",ax=ax12)
        ax12 = df.loc[df['Loc']=='BC_Seatt'].plot(x="PGA_g",y="ds3",kind="scatter", color='b', marker='o', s=10,  label="ds3",ax=ax12)
        ax12.plot(x,func(x,mu1_se,sigma1_se),'r--',label='ds1_fit, $r^2$={0:0.3f}'.format(r2_se1))
        ax12.plot(x,func(x,mu2_se,sigma2_se),'g--',label='ds2_fit, $r^2$={0:0.3f}'.format(r2_se2))
        ax12.plot(x,func(x,mu3_se,sigma3_se),'b--',label='ds3_fit, $r^2$={0:0.3f}'.format(r2_se3))
        ax12.legend(loc="upper left")
        ax12.grid(visible=True)
        ax12.set_xlim(0.0,0.4)
        ax12.set_ylim(-0.05,1.1)
        ax12.set_xlabel("PGA (g)")
        ax12.set_ylabel("Likelihood")
        title = '{:s} CDF, Seattle'.format(k)
        ax12.set_title(title)
        plt.show()

        plt.figure(13)
        ax13 = df.plot(x="PGA_g",y="ds1",kind="scatter", color='r', marker='d', s=20, label="ds1")
        ax13 = df.plot(x="PGA_g",y="ds2",kind="scatter", color='g', marker='s', s=10, label="ds2",ax=ax13)
        ax13 = df.plot(x="PGA_g",y="ds3",kind="scatter", color='b', marker='o', s=10,  label="ds3",ax=ax13)
        ax13.plot(x,func(x,mu1_bo,sigma1_bo),'r--',label='ds1_fit, $r^2$={0:0.3f}'.format(r2_bo1))
        ax13.plot(x,func(x,mu2_bo,sigma2_bo),'g--',label='ds2_fit, $r^2$={0:0.3f}'.format(r2_bo2))
        ax13.plot(x,func(x,mu3_bo,sigma3_bo),'b--',label='ds3_fit, $r^2$={0:0.3f}'.format(r2_bo3))
        ax13.legend(loc="upper left")
        ax13.grid(visible=True)
        ax13.set_xlim(0.0,0.4)
        ax13.set_ylim(-0.05,1.1)
        ax13.set_xlabel("PGA (g)")
        ax13.set_ylabel("Likelihood")
        title = '{:s} CDF, Both Locations'.format(k)
        ax13.set_title(title)
        plt.show()

# IMcomb
for k, func in f.items():
    try:
        # LaGrande
        LGx1 = df['IMcomb'].loc[df['Loc']=='BC_LaGra'].to_list()[:]
        LGy1 = df['ds1'].loc[df['Loc']=='BC_LaGra'].to_list()[:]
        mu1_lg, sigma1_lg = optimize.curve_fit(func,LGx1,LGy1)[0]
        _,_,r_lg1,_,_ = stats.linregress(LGy1,[func(x,mu1_lg,sigma1_lg) for x in LGx1])
        r2_lg1 = r_lg1**2

        LGx2 = df['IMcomb'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
        LGy2 = df['ds2'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
        mu2_lg, sigma2_lg = optimize.curve_fit(func,LGx2,LGy2)[0]
        _,_,r_lg2,_,_ = stats.linregress(LGy2,[func(x,mu2_lg,sigma2_lg) for x in LGx2])
        r2_lg2 = r_lg2**2

        LGx3 = df['IMcomb'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
        LGy3 = df['ds3'].loc[df['Loc']=='BC_LaGra'].to_list()#[1:-1]
        mu3_lg, sigma3_lg = optimize.curve_fit(func,LGx3,LGy3)[0]
        _,_,r_lg3,_,_ = stats.linregress(LGy3,[func(x,mu3_lg,sigma3_lg) for x in LGx3])
        r2_lg3 = r_lg3**2

        # Seattle
        SEx1 = df['IMcomb'].loc[df['Loc']=='BC_Seatt'].to_list()[1:-1]
        SEy1 = df['ds1'].loc[df['Loc']=='BC_Seatt'].to_list()[1:-1]
        mu1_se, sigma1_se = optimize.curve_fit(func,SEx1,SEy1)[0]
        _,_,r_se1,_,_ = stats.linregress(SEy1,[func(x,mu1_se,sigma1_se) for x in SEx1])
        r2_se1 = r_se1**2

        SEx2 = df['IMcomb'].loc[df['Loc']=='BC_Seatt'].to_list()[:] #[1:-1]
        SEy2 = df['ds2'].loc[df['Loc']=='BC_Seatt'].to_list()[:] #[1:-1]
        mu2_se, sigma2_se = optimize.curve_fit(func,SEx2,SEy2)[0]
        _,_,r_se2,_,_ = stats.linregress(SEy2,[func(x,mu2_se,sigma2_se) for x in SEx2])
        r2_se2 = r_se2**2

        SEx3 = df['IMcomb'].loc[df['Loc']=='BC_Seatt'].to_list()[:] #[1:-1]
        SEy3 = df['ds3'].loc[df['Loc']=='BC_Seatt'].to_list()[:] #[1:-1]
        mu3_se, sigma3_se = optimize.curve_fit(func,SEx3,SEy3)[0]
        _,_,r_se3,_,_ = stats.linregress(SEy3,[func(x,mu3_se,sigma3_se) for x in SEx3])
        r2_se3 = r_se3**2

        # BOTH
        BOx1 = df['IMcomb'].to_list()[:] #[1:-1]
        BOy1 = df['ds1'].to_list()[:] #[1:-1]
        mu1_bo, sigma1_bo = optimize.curve_fit(func,BOx1,BOy1)[0]
        _,_,r_bo1,_,_ = stats.linregress(BOy1,[func(x,mu1_bo,sigma1_bo) for x in BOx1])
        r2_bo1 = r_bo1**2

        BOx2 = df['IMcomb'].to_list()[:] #[1:-1]
        BOy2 = df['ds2'].to_list()[:] #[1:-1]
        mu2_bo, sigma2_bo = optimize.curve_fit(func,BOx2,BOy2)[0]
        _,_,r_bo2,_,_ = stats.linregress(BOy2,[func(x,mu2_bo,sigma2_bo) for x in BOx2])
        r2_bo2 = r_bo2**2

        BOx3 = df['IMcomb'].to_list()[:] #[1:-1]
        BOy3 = df['ds3'].to_list()[:] #[1:-1]
        mu3_bo, sigma3_bo = optimize.curve_fit(func,BOx3,BOy3)[0]
        _,_,r_bo3,_,_ = stats.linregress(BOy3,[func(x,mu3_bo,sigma3_bo) for x in BOx3])
        r2_bo3 = r_bo3**2

        print()
        print('========================')
        print('Curve type: {:s}, IM: IMcomb'.format(k))
        print('  LaGrande')
        print('    ds1:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu1_lg,sigma1_lg,r2_lg1))
        print('    ds2:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu2_lg,sigma2_lg,r2_lg2))
        print('    ds3:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu3_lg,sigma3_lg,r2_lg3))
        print('  Seattle')
        print('    ds1:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu1_se,sigma1_se,r2_se1))
        print('    ds2:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu2_se,sigma2_se,r2_se2))
        print('    ds3:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu3_se,sigma3_se,r2_se3))
        print('  Seattle')
        print('    ds1:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu1_bo,sigma1_bo,r2_bo1))
        print('    ds2:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu2_bo,sigma2_bo,r2_bo2))
        print('    ds3:: p1: {0:0.3f}, p2: {1:0.3f}, r2: {2:0.3f}'.format(mu3_bo,sigma3_bo,r2_bo3))

    except RuntimeError:
        print('Curve {:s}, parameters not found'.format(k))

    #%% PLOTTING
    if toggle_plot:
        x = np.linspace(0,0.5,100)

        plt.figure(21)
        ax21 = df.loc[df['Loc']=='BC_LaGra'].plot(x="IMcomb",y="ds1",kind="scatter", color='r', marker='d', s=20, label="ds1")
        ax21 = df.loc[df['Loc']=='BC_LaGra'].plot(x="IMcomb",y="ds2",kind="scatter", color='g', marker='s', s=10, label="ds2",ax=ax21)
        ax21 = df.loc[df['Loc']=='BC_LaGra'].plot(x="IMcomb",y="ds3",kind="scatter", color='b', marker='o', s=10, label="ds3",ax=ax21)
        ax21.plot(x,func(x,mu1_lg,sigma1_lg),'r--',label='ds1_fit, $r^2$={0:0.3f}'.format(r2_lg1))
        ax21.plot(x,func(x,mu2_lg,sigma2_lg),'g--',label='ds2_fit, $r^2$={0:0.3f}'.format(r2_lg2))
        ax21.plot(x,func(x,mu3_lg,sigma3_lg),'b--',label='ds3_fit, $r^2$={0:0.3f}'.format(r2_lg2))
        ax21.legend(loc="upper left")
        ax21.grid(visible=True)
        ax21.set_xlim(0.0,0.025)
        ax21.set_ylim(-0.05,1.1)
        ax21.set_xlabel("IMcomb")
        ax21.set_ylabel("Likelihood")
        title = '{:s} CDF, LaGrande'.format(k)
        ax21.set_title(title)
        plt.show()

        plt.figure(22)
        ax22 = df.loc[df['Loc']=='BC_Seatt'].plot(x="IMcomb",y="ds1",kind="scatter", color='r', marker='d', s=20, label="ds1")
        ax22 = df.loc[df['Loc']=='BC_Seatt'].plot(x="IMcomb",y="ds2",kind="scatter", color='g', marker='s', s=10, label="ds2",ax=ax22)
        ax22 = df.loc[df['Loc']=='BC_Seatt'].plot(x="IMcomb",y="ds3",kind="scatter", color='b', marker='o', s=10, label="ds3",ax=ax22)
        ax22.plot(x,func(x,mu1_se,sigma1_se),'r--',label='ds1_fit, $r^2$={0:0.3f}'.format(r2_se1))
        ax22.plot(x,func(x,mu2_se,sigma2_se),'g--',label='ds2_fit, $r^2$={0:0.3f}'.format(r2_se2))
        ax22.plot(x,func(x,mu3_se,sigma3_se),'b--',label='ds3_fit, $r^2$={0:0.3f}'.format(r2_se3))
        ax22.legend(loc="upper left")
        ax22.grid(visible=True)
        ax22.set_xlim(0.0,0.025)
        ax22.set_ylim(-0.05,1.1)
        ax22.set_xlabel("IMcomb")
        ax22.set_ylabel("Likelihood")
        title = '{:s} CDF, Seattle'.format(k)
        ax22.set_title(title)
        plt.show()

        plt.figure(23)
        ax23 = df.plot(x="IMcomb",y="ds1",kind="scatter", color='r', marker='d', s=20, label="ds1")
        ax23 = df.plot(x="IMcomb",y="ds2",kind="scatter", color='g', marker='s', s=10, label="ds2",ax=ax23)
        ax23 = df.plot(x="IMcomb",y="ds3",kind="scatter", color='b', marker='o', s=10, label="ds3",ax=ax23)
        ax23.plot(x,func(x,mu1_bo,sigma1_bo),'r--',label='ds1_fit, $r^2$={0:0.3f}'.format(r2_bo1))
        ax23.plot(x,func(x,mu2_bo,sigma2_bo),'g--',label='ds2_fit, $r^2$={0:0.3f}'.format(r2_bo2))
        ax23.plot(x,func(x,mu3_bo,sigma3_bo),'b--',label='ds3_fit, $r^2$={0:0.3f}'.format(r2_bo3))
        ax23.legend(loc="upper left")
        ax23.grid(visible=True)
        ax23.set_xlim(0.0,0.025)
        ax23.set_ylim(-0.05,1.1)
        ax23.set_xlabel("IMcomb")
        ax23.set_ylabel("Likelihood")
        title = '{:s} CDF, Both Locations'.format(k)
        ax23.set_title(title)
        plt.show()

        # print(df)

if toggle_plot_old:
    # sns.scatterplot(data=df, x="PGA_g", y="nLEAK")
    new_title = 'Location'
    new_labels = ['LaGrande','Seattle']
    dfex['nLEAKnorm'] = dfex['nLEAK']/1414.
    dfex['nBCnorm'] = dfex['nBC']/36.
    plt.figure(1)
    plt.grid()
    # ax1 = plt.axis([0,0.5,0,50])
    g= sns.scatterplot(data=dfex, x="PGA_g", y="nBCnorm", hue="Loc", style="Loc",facet_kws={'legend_out':True}).set(title = 'No. of burning compartments vs. PGA', xlabel = 'PGA (g)', ylabel = 'Burning Compartments (Normalized, N=36)')
    plt.legend(loc='upper left')
    # g._legend.set_title(new_title)
    # for t, l in zip(g._legend.texts, new_labels):
    #     t.set_text(l)
    plt.figure(2)
    plt.grid()
    # ax2 = plt.axis([0,0.3,0,50])
    sns.scatterplot(data=dfex, x="IMcomb", y="nBCnorm", hue="Loc", style="Loc").set(title = 'No. of burning compartments vs. $IM_{comb}$', xlabel = '$IM_{comb}$', ylabel = 'Burning Compartments (Normalized, N=36)')
    plt.legend(loc='upper left')
    # plt.figure(2)
    plt.figure(3)
    plt.grid()
    # ax3 = plt.axis([0,1500,0,50])
    sns.scatterplot(data=dfex, x="nLEAK", y="nBC", hue="Loc", style="Loc").set(title = 'No. of burning compartments vs. No. of leaking pipes',xlabel = 'Number of Leaking Pipes', ylabel = 'Number of Burning Compartments')
    plt.legend(loc='upper left')
    # plt.figure(4)
    # ax3 = plt.axis([0,50,0,50])
    # sns.histplot(data=dfex, x="PGA_g",y="nBC",hue="Loc")

    # nLEAK vs. IM
    plt.figure(6)
    plt.grid()
    sns.scatterplot(data=dfex,x="PGA_g",y="nLEAKnorm",hue="Loc",style="Loc").set(title = 'No. of leaking pipes vs. PGA', xlabel = 'PGA (g)', ylabel = 'Leaking pipes (Normalized, N=1414)')
    plt.figure(7)
    plt.grid()
    sns.scatterplot(data=dfex,x="IMcomb",y="nLEAKnorm",hue="Loc",style="Loc").set(title = 'No. of leaking pipes vs. $IM_{comb}$', xlabel = '$IM_{comb}$', ylabel = 'Leaking pipes (Normalized, N=1414)')

    # plt.figure(8)
    # sns.jointplot(data=dfex,x="nLEAK",y="nBC",kind="hex",)
    # df.sort_values(by='IMcomb',inplace=True)

    # plt.figure(13)
    # ax13 = df.loc[df['Loc']=='BC_LaGra'].plot(x="IMcomb",y="ds1",kind="scatter", color='r',label="ds1 (>1 BC)")
    # ax13 = df.loc[df['Loc']=='BC_LaGra'].plot(x="IMcomb",y="ds2",kind="scatter", color='g',label="ds2 (>4 BC)",ax=ax13)
    # ax13 = df.loc[df['Loc']=='BC_LaGra'].plot(x="IMcomb",y="ds3",kind="scatter", color='b',label="ds3 (>8 BC)",ax=ax13)
    # ax13.grid(visible=True)
    # ax13.set_xlim(0.0,0.02)
    # ax13.set_ylim(-0.1,1.1)
    # ax13.set_xlabel("IM$_{comb}$")
    # ax13.set_ylabel("Likelihood")
    # ax13.set_title("Empirical CDF, LaGrande (IMcomb)")
    # plt.show()

    # plt.figure(14)
    # ax14 = df.loc[df['Loc']=='BC_Seatt'].plot(x="IMcomb",y="ds1",kind="scatter", color='r',label="ds1 (>1 BC)")
    # ax14 = df.loc[df['Loc']=='BC_Seatt'].plot(x="IMcomb",y="ds2",kind="scatter", color='g',label="ds2 (>4 BC)",ax=ax14)
    # ax14 = df.loc[df['Loc']=='BC_Seatt'].plot(x="IMcomb",y="ds3",kind="scatter", color='b',label="ds3 (>8 BC)",ax=ax14)
    # ax14.grid(visible=True)
    # ax14.set_xlim(0.0,0.25)
    # ax14.set_ylim(-0.1,1.1)
    # ax14.set_xlabel("IM$_{comb}$")
    # ax14.set_ylabel("Likelihood")
    # ax14.set_title("Empirical CDF, Seattle (IMcomb)")
    # plt.show()

# beepy.beep(sound="coin")


# import requests
#
# response = requests.get('https://')
# data = response.json()
# x = 'jakies slowo'
# x = str('jakies slowo')
# x.capitalize()
#
# print(x.replace('slowo', 'cos innego'))

# 1. dane <----- name, age, grade_average
# 2. zachowania
class Teacher:
    def __init__(self, name, age, grade_average):
        self.name = name
        self.age = age
        self.grade_average = grade_average

# class list:
#     def __eq__(self, other):
#         for i in range(len(self)):
#             if self[i] != other[i]:
#                 return False
#             return True

class Student:
    def __init__(self, name, age, grade_average):
        self.name = name
        self.age = age
        self.grade_average = grade_average

    def __eq__(self, other):
        if self.name == other.name and self.age == other.age and self.grade_average == other.grade_average:
            return True
        return False

    def is_over_18(self):
        if self.age >= 18:
            return True
        else:
            return False

    def is_valedictorian(self):
        if self.grade_average == 100:
            return True
        else:
            return False

student_maciek = Student('Maciek', 18, 88)

polish_students = [
    Student(name="Aleksandra Nowak", age=17, grade_average=81.5),
    Student(name="Michał Kowalski", age=16, grade_average=92.0),
    Student(name="Katarzyna Wiśniewska", age=18, grade_average=78.3),
]

abroad_students = [
    Student(name="John Smith", age=17, grade_average=85.5),
    Student(name="Emily Johnson", age=16, grade_average=92.0),
    Student(name="Michael Williams", age=18, grade_average=78.3),
]

def average_grade(students):
    sum_of_averages = 0
    for student in students:
        sum_of_averages = sum_of_averages + student.grade_average
    return sum_of_averages / len(students)

print(average_grade(polish_students))

average_of_abroad = average_grade(abroad_students)
print(average_of_abroad)

def get_best_student(students):
    best_student = students[0]
    for student in students[1:]:
        if student.grade_average > best_student.grade_average:
            best_student = student
    return best_student

best_of_polish = get_best_student(polish_students)
print(f'Najlepszy student to {best_of_polish}')

def get_worst_student(students):
    worst_student = students[0]
    for student in students[1:100]:
        if student.grade_average < worst_student.grade_average:
            worst_student = student
    return worst_student

worst_of_polish = get_worst_student(polish_students)
print(f'Najgorszy student to {worst_of_polish.name}')

def students_with_name_starting_with(letter, all_students):
    filtered_students = []
    for student in all_students:
        if student.name[0] == letter:
            filtered_students.append(student)
    return filtered_students

def get_all_underage_students(students):
    ...

def test_students_with_name_starting_with_A_letter():
    test_students = [
        Student('Paweł', 18, 88),
        Student('Agata', 18, 88),
        Student('Andrzej', 18, 88),
    ]
    expected_students = [
        Student('Agata', 18, 88),
        Student('Andrzej', 18, 88),
    ]

    result = students_with_name_starting_with("A", test_students)

    if result == expected_students:
        print('test A OK')
    else:
        raise Exception("test A nie przechodzi")

test_students_with_name_starting_with_A_letter()


from utilities.errors import WrongInputFormat

class FileUtil:
    """ Utility class which has member functions that will be used for parsing inputPS4.txt, outputting to outputPS4.txt and has some exception handling. """
    def __init__(self):
        super().__init__()

    def _is_integer(self, number):
        """ Private utility method to check whether a string is an integer or not """
        try:
            int(number)
            return True
        except ValueError:
            return False

    def _parse(self, line):
        """ Private utiltiy method to parse through a line from the input file and return an array of integers
            Throws error for the following reasons:-
              1.) Wrong input format
              2.) Type casting errors
        """
        data = line.split(' ')
        data = list(filter(lambda x: x != ' ', data))
        for i in range(len(data)):
            data[i] = data[i].rstrip("\n")
            if(self._is_integer(data[i])):
                data[i] = int(data[i]) # Assuming the input is only integer and not float
            else:
                raise WrongInputFormat(f"Wrong input format as it is not an integer for {data[i]} in the input list: {data}")
        return data

    def readAndParseInput(self, file_name):
        """ Method that reads the input file and parses the input and if all ok it returns an array of each input case """
        final_list = []
        try:
            file = open(file_name, "r")
            lines = file.readlines()
            for line in lines:
                if line.strip() == '':
                    continue
                val = self._parse(line)
                final_list.append(val)
        except WrongInputFormat as e:
            print(f"ERROR: {e.args[0]} at file:- {file_name}")
            final_list = None
        except IOError:
            print(f"Error while reading/opening into the file :- {file_name}")
            final_list = None
        except ValueError:
            print(f"ERROR: Could not parse the file {file_name} because of type casting")
            final_list = None
        finally:
            file.close()
            return final_list

    def writeOutput(self, file_name, out_list):
        """ Utility method to write the string into the output file """
        try:
            file = open(file_name, "w")
            out_string = ""
            for data in out_list:
                out_string += f"{data[0]} {data[1]}\n"
            file.write(out_string)
        except IOError:
            print("ERROR: Outputting into the file failed")
        finally:
            file.close()


from django import forms

TEST_VALUES_CHOICES = [(i, str(i)) for i in range(1, 2)]

class CartAddTestForm(forms.Form):
    correct = forms.TypedChoiceField(
                                choices=TEST_VALUES_CHOICES,
                                coerce=int,
                                widget=forms.HiddenInput,
                                initial = '1'
                                )
    update = forms.BooleanField(required=False,
                                initial=False,
                                widget=forms.HiddenInput)


from django.http import HttpResponse
from openpyxl import Workbook
from django.forms import modelform_factory
from django.shortcuts import render, get_object_or_404, redirect

# Create your views here.
from persona.forms import PersonaFormulario
from persona.models import Persona

def detalle_persona(request, id):
    # persona = Persona.objects.get(pk=id)
    persona = get_object_or_404(Persona, pk=id)
    mensaje = {'persona':persona}
    return render(request, 'detalle.html', mensaje)

#PersonaFormulario = modelform_factory(Persona, exclude=[])
def nueva_persona(request):
    if request.POST:
        formPersona = PersonaFormulario(request.POST)
        if formPersona.is_valid():
            formPersona.save()
            return redirect('inicio')
    else:
        formPersona = PersonaFormulario()
    return render(request, 'nueva.html', {'formPersona': formPersona})

def modificar_persona(request, id):
    persona = get_object_or_404(Persona, pk=id)
    if request.method == 'POST':
        formPersona = PersonaFormulario(request.POST, instance=persona)
        if formPersona.is_valid():
            formPersona.save()
            return redirect('inicio')
    else:
        formPersona = PersonaFormulario(instance=persona)
    mensaje = {'formPersona': formPersona}
    return render(request, 'modificar.html', context=mensaje)

def eliminar_persona(request, id):
    persona = get_object_or_404(Persona, pk=id)
    if persona:
        persona.delete()
    return redirect('inicio')

def reporte_personas(request):
    # Obtenemos todas las personas de nuestra base de datos
    personas = Persona.objects.order_by('apellido')
    # Creamos el libro de trabajo
    wb = Workbook()
    # Definimos como nuestra hoja de trabajo, la hoja activa, por defecto la primera del libro
    ws = wb.active
    # En la celda B1 ponemos el texto 'REPORTE DE PERSONAS'
    ws['B1'] = 'REPORTE DE PERSONAS'
    # Juntamos las celdas desde la B1 hasta la E1, formando una sola celda
    ws.merge_cells('B1:E1')
    ws.title = 'Reporte'
    # Creamos los encabezados desde la celda B3 hasta la E3
    ws['B3'] = 'ID'
    ws['C3'] = 'NOMBRE'
    ws['D3'] = 'APELLIDO'
    ws['E3'] = 'EMAIL'
    cont = 4
    # Recorremos el conjunto de personas y vamos escribiendo cada uno de los datos en las celdas
    for persona in personas:
        ws.cell(row=cont, column=2).value = persona.id
        ws.cell(row=cont, column=3).value = persona.nombre
        ws.cell(row=cont, column=4).value = persona.apellido
        ws.cell(row=cont, column=5).value = persona.email
        cont = cont + 1
    # Establecemos el nombre del archivo
    nombre_archivo = "ReportePersonas.xlsx"
    # Definimos que el tipo de respuesta a devolver es un archivo de microsoft excel
    response = HttpResponse(content_type="application/ms-excel")
    contenido = "attachment; filename={0}".format(nombre_archivo)
    response["Content-Disposition"] = contenido
    wb.save(response)
    return response


#이진탐색의 기본은 그 중간부터 시작하는것

finding_target = 14
finding_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

#    [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
# 1단계 : 최소값 - 최대값을 더해서 그 절반인 8(시도값으로 정의)부터 시작한다.
# 2단계 : 9부터 16으로 되고, 시도값은 12임
# 3단계 : 13부터 16으로 되고, 시도값은 14임, 함수 끝

def is_existing_target_number_binary(target, array):
    current_min = 0
    current_max = len(array)-1 #array 배열 index 마지막 값
    current_guess = (current_max + current_min) // 2

    while current_min <= current_max:
        if array[current_guess] == target:
            return True
        elif array[current_guess] < target:
            current_min = current_guess + 1 #범위를 위로
        else:
            current_max = current_guess -1 #범위를 아래로

        current_guess = (current_max + current_min) // 2

    return False

result = is_existing_target_number_binary(finding_target, finding_numbers)
print(result)


import os
import subprocess

def scanDevices():
	os.system("ifconfig -a | sed 's/[ \t].*//;/^$/d' > deviceList")

	f = open("deviceList", "r")

	devices = ""
	for line in f:
		if ":" in line:
			devices += line.replace(":","")
		else:
			devices += line

	g = open ("dev2", "w")
	g.write(devices)

scanDevices()


from flask import Flask, render_template, request, redirect
import utils

app = Flask(__name__)

@app.route('/order', methods=["GET", "POST"])
def order():
    # 1.如果是GET请求，就看到新建订单的页面
    if request.method == "GET":
        return render_template('order.html')

    # 2.如果是POST请求，提交携带 数量+视频的URL
    count = request.form.get('count')
    video_url = request.form.get('url')

    # 订单号
    oid = utils.gen_oid()

    # 3.写入数据库（库 & 表结构）【MySQL数据库】
    utils.db_create_task(count, video_url, oid)

    # 4.写入队列【Redis】
    utils.redis_push_task(oid)

    return redirect("/order/list")

@app.route('/order/list')
def order_list():
    """ 获取所有订单列表 """

    # 去数据库获取所有的订单信息
    res = utils.db_fetch_all_task()

    # 展示在页面上
    return render_template("order_list.html", res=res)

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


UNBOXED_PRIMITIVE_DEFAULT_EMPTY = "__prim_empty_slot"
UNBOXED_PRIMITIVE_DEFAULT_ZERO = "__prim_zero_slot"
IO_CLASS = "IO"
OBJECT_CLASS = "Object"
INTEGER_CLASS = "Int"
BOOLEAN_CLASS = "Bool"
STRING_CLASS = "String"

BUILT_IN_CLASSES = [
	IO_CLASS,
	OBJECT_CLASS,
	INTEGER_CLASS,
	BOOLEAN_CLASS,
	STRING_CLASS
]

VOID_TYPE = "Void"

LOCAL_SELF_NAME = "__self"
INIT_CIL_SUFFIX = "_init"

# Built in CIL functions

CONFORMS_FUNC = "__conforms"
ISVOID_FUNC = "_isvoid"

# MIPS names

VOID_MIPS_NAME = "type_void"


'''Given a tuple of elements, write a python program to create
a dictionary with tuple elements as a key and its count in
tuple as value e.g t = (4,5,6,2,3,4,5,1,2,6,4) then output
should be d = {4:3,5:2,2:2,3:1,1:1}
'''

t = (4,5,6,2,3,4,5,1,2,6,4)
keys = []
values = []
d1 = {}
for i in t:
    if i not in keys:
        keys.append(i)

for j in keys:
    n = t.count(j)
    values.append(n)

for i in range(len(keys)):
    d1[keys[i]] = values[i]
print(d1)

''' output
{4: 3, 5: 2, 6: 2, 2: 2, 3: 1, 1: 1}
'''

'''Write a python program to print tuple of website suffixes
from given dictionary
{ 1:"www.yahoo.com",
  2:"www.tsec.edu",
  3:"www.asp.net",
  4:"www.abcd.in"}
'''

d2 = {
  1:"www.yahoo.com",
  2:"www.tsec.edu",
  3:"www.asp.net",
  4:"www.abcd.in"}

suffixes = []

for url in d2.values():
    suffix = url.split(".")[-1]
    suffixes.append(suffix)
print(tuple(suffixes))

''' output
('com', 'edu', 'net', 'in')
'''


import xlrd
from lib.plugins.dataReaders.BaseDataReader import BaseDataReader
from lib.exceptions.FileError import FileError
import re

class XLSDataReader(BaseDataReader):
  name = "XLS Data Reader"
  description = "Reads Excel (XLS and XLSX) formattted data"
  type = "Excel"

  priority = 10

  def __init__(self, filepath=None):
    super(XLSDataReader, self).__init__(filepath)

  #
  @classmethod
  def identify(cls, filepath):
    try:
      book = xlrd.open_workbook(filepath)
      return True
    except:
      return False

  #
  def read(self, filepath):
    self.input_file = None

    try:
      book = xlrd.open_workbook(filepath)
      self.input_file = book.sheet_by_index(0)
    except:
      pass

    super(XLSDataReader, self).read(filepath)

    h = self.input_file.row(0)

    h = [str(a.value) for a in h]
    if len(filter(lambda x: re.match(r'^[\d]$', x), h)) > 0 or len(set(h)) < len(h):
      # no headers
      self.headers = [str(x) for x in range(1, len(h))]
    else:
      self.headers = h

    if self.input_file:
      return True
    else:
      return False

  #
  def getRows(self, rows=None, start=0):
    if self.input_file is None:
      raise FileError("No file loaded", "XLSDataReader.getRows")

    nrows = self.input_file.nrows
    if rows is not None and rows < nrows:
      nrows = rows
    ncols = self.input_file.ncols

    file_data = []

    for rx in range(start, nrows):

      row = []
      for cx in range(ncols):
        cell = self.input_file.cell_value(rowx=rx, colx=cx)
        if isinstance(cell, float):
          if int(cell) == cell:
              cell = int(cell)

        row.append(cell)
      if row == self.headers:
        continue
      file_data.append(row)

    return file_data


# DataLogger_ARDTimed
# Gray Theobald, Tecknosys Ltd.
# WORKING - as of 17.04.20.
# CSV datalogger for Arduino / IIS3DHHC_Time_Interval sketch: 3 Axis accelerometer with millis timestamp (for lack of RTC with required accuracy for data rate)
# 4 column (t,x,y,z) CSV data output file can then be analysed for acceleration (each axis), RMS and fast-fourier transform for vibration frequency using Matplotlb_CSVDataProcessing.py script.
# Intent will be to integrate this functionality to the data processing script.

import serial
import keyboard
import csv
import time

try:
    ser = serial.Serial('COM14',115200)								# open com port 4 at baudrate of 115200
    time.sleep(1)
    ser.flushInput()
    print('logging...... - press "esc" to quit')

    while True:
        ser_bytes = (ser.readline().decode('utf-8'))				# read serial and decode to unicode (issue with '-' character otherwise)
        ser_bytes = ser_bytes.rstrip('\n')							# remove any line feeds at end of data
        ser_bytes = ser_bytes.rstrip('\r')							# remove carriage returns at end of data
        dataArray = ser_bytes.split(',')							# parse the data to a list

        #timestampedData = [time.time()]+dataArray					# concatenate timestamp to serial data **** Use millis / micros function from arduino until milli / micro second RTC available

        #print(dataArray)											# print data to serial monitor (testing purposes only)

        with open('kst2_Test.csv', 'a', newline='', encoding='utf-8') as file:		# create csv file, remove newlines, write CSV data
        	writer = csv.writer(file, delimiter=',')								# ** 'a'= create new or append to existing, 'w'= create new or overwrite existing
        	writer.writerow(dataArray)

       	if keyboard.is_pressed('esc'):								# 'escape' button exits (breaks out of while loop) and closes serial port
           break;
    ser.close
except:
    print("Unexpected error:")
    print("Unexpected error:")


import math
import pygame
from math import pi,sin,cos,tan,sqrt,atan,degrees,radians
from time import sleep
from _momentum_sliders import *
def momentum_run():
    #-=-=-=-=Impulse and momnetum =-=-=-=-#
    '''
    Do not type anything for the variable we need to solve for

    ##Example:

    >>> acceleration:
    >>> Force1: 2
    >>> Force2: 2
    >>> Mass: 1.3

    3.08 is the acceleration
    '''
    WIDTH, HEIGHT = 900, 650
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)
    GREY = (200, 200, 200)      #----------------------------------------------------------------------------------------------# Colors
    ORANGE = (200, 100, 50)
    RED = (255,0,0)
    GREEN = (0,255,0)
    TRANS = (1, 1, 1)
    WHITE = (255,255,255)

    center=(int(WIDTH/2),int(HEIGHT/2))
    full_screen_radius=sqrt((WIDTH/2)**2+(HEIGHT/2)**2)#---------------------------------------------------------------# Screen setting

    font = pygame.font.SysFont("Arial",int(16))
    font2 = pygame.font.SysFont("Arial",int(21))#--------------------------------------------------------------------------# Font setting

    choose_image = pygame.image.load('_momentum_choose_image.png')
    twoD_click = pygame.image.load('_momentum_2d_click.png')
    oneD_click = pygame.image.load('_momentum_1d_click.png')
    up=pygame.transform.scale(pygame.image.load("_momentum_arrow_up.png").convert_alpha(),(35,35))
    down=pygame.image.load("_momentum_arrow_down.png")
    down=down.convert_alpha()
    down=pygame.transform.scale(down,(35,35))#-----------------------------------------------------------------------# Images imported
    right=pygame.image.load("_momentum_arrow_right.png")
    right=right.convert_alpha()
    right=pygame.transform.scale(right,(35,35))
    left=pygame.image.load("_momentum_arrow_left.png")
    left=left.convert_alpha()
    left=pygame.transform.scale(left,(35,35))

    def ratio_conversion(lst):#----------------------------------------------------------------------------------------------# Function that change the speed of the ball to have noticeable velocity difference
        v_max=max([abs(i) for i in lst if i!=0])
        v_min=min([abs(i) for i in lst if i!=0])                                                                                # Velocity maximum and minimum are chosen from a list of variables
        if v_max>5:
            ratio=4/v_max                                                                                # If the max velocity if bigger than 5, then find the ratio between the value and 5
            for i in range(len(lst)):
                lst[i]= lst[i]*ratio
        elif v_min<0.7:
            ratio=0.7/v_min                                                                                # If the min velocity is smaller than 0.7, then find the ration between the two values
            for i in range(len(lst)):
                lst[i]= lst[i]*ratio                                                                                # Apply the obtained ratio and apply it to all variables in the list imported
        return lst

    def initial_pos(v1x,v1y,v2x,v2y,ang1,ang2):#------------------------------------------------------------------------# Function that always center the location of collision while inputted variables are reasonable
        ang1=radians(ang1)+pi
        ang2=radians(ang2)+pi                                                                                # The angle formed with the horizontal at which the balls will collide in the center
        if v1y==0 and v1x!=0:
            if v1x>0:
                ang1=2*pi+pi
            elif v1x<0:
                ang1=2*pi
        if v2y==0 and v2x!=0:                                                                                # Six if statements to check special cases which can cause multiple possibilities
            if v2x>0:
                ang2=2*pi+pi
            elif v2x<0:
                ang2=2*pi

        if v1x==0 and v1y!=0:
            if v1y>0:
                ang1=3*pi/2+pi
            elif v1y<0:                                                                                # Explanation: if any vector has 0, meaning the combined vector is only going vertical or horizontal
                ang1=pi/2+pi                                                                                # Since trignomitry is used, multiple answer can be abstracted vertical or horizontal angles
        if v2x== 0 and v2y!=0:                                                                                # Therefore, each case must be studied separately
            if v2y>0:
                ang2=3*pi/2+pi
            elif v2y<0:
                ang2=pi/2+pi

        if v1y==0 and v1x==0:
            ang1=0
        if v2y==0 and v2x==0:
            ang2=0

        v1=sqrt(v1x**2+v1y**2)                                                                                # Find the combined vector
        v2=sqrt(v2x**2+v2y**2)

        ratio=v1/v2                                                                                # Find the ratio between the combined vectors
        d1=full_screen_radius*ratio                                                                                # A distance defined by using the corner of screen and the screen center, and the ratio of two velocities
        d2=full_screen_radius
        d1x,d1y=d1*cos(ang1),d1*sin(ang1)                                                                                # separate the component into x and y so it can be used in drawing functions
        d2x,d2y=d2*cos(ang2),d2*sin(ang2)
        return d1x,d1y,d2x,d2y

    def legend(screen,variables):#------------------------------------------------------------------------------------# Function that print message on pygame screen
        myfont = pygame.font.SysFont('Arial', 19)
        font = pygame.font.SysFont('Arial', 23)
        m1_text = myfont.render('Mass 1: '+str(round(variables['mass1'],2))+'kg', False, WHITE)
        screen.blit(m1_text,(45, 10))
        v1_text = myfont.render('Velocity 1: '+str(round(variables['vel1'],2))+'m/s', False, WHITE)
        screen.blit(v1_text,(45, 30))
        m2_text = myfont.render('Mass 2: '+str(round(variables['mass2'],2))+'kg', False, WHITE)
        screen.blit(m2_text,(45, 50))
        v2_text = myfont.render('Velocity 2: '+str(round(variables['vel2'],2))+'m/s', False, WHITE)
        screen.blit(v2_text,(45, 70))
        if int(variables['collision_type'])==1 or int(variables['collision_type'])==2:
            v1f_text = myfont.render('Velocity 1 prime: '+str(round(variables['vel1f'],2))+'m/s', False, WHITE) # WIth different type of collision, different message will be printed
            screen.blit(v1f_text,(45, 90))
            v2f_text = myfont.render('Velocity 2 prime: '+str(round(variables['vel2f'],2))+'m/s', False, WHITE)
            screen.blit(v2f_text,(45, 110))
        else:
            vf_text = myfont.render('Velocity prime: '+str(round(variables['velf'],2))+'m/s', False, WHITE)
            screen.blit(vf_text,(45, 90))
                                                                                # If a velocity value is much more than the others, message will be shown
        if abs(variables['vel1'])>abs(10*variables['vel2']) or abs(variables['vel2'])>abs(10*variables['vel1']):
            print(variables['vel1'],variables['vel2'])
            DIfference_txt = font.render('Difference between veolcities are too big', False, RED)
            screen.blit(DIfference_txt,(300, 400))

    def distance(x,y,x2,y2):#-------------------------------------------------------------------------------------------# Distance function
        return (round(sqrt((x2-x)**2+(y2-y)**2)))

    #Momentum in one dimention
    def ask_for_input(lst,collision_type):#-----------------------------------------------------------------------------# Function that collect inputted data , rearrange data and return the data along with the variable to be solved
        collision_type=collision_type
        vel1= lst[0]
        mass1 =  lst[1]                                                                                # Values are abstracted from the imported list
        vel2= lst[2]
        mass2 = lst[3]
        if int(collision_type) ==1 or int(collision_type) ==2:                                                                      # Different type of collision can lead to different final values
            vel1f= lst[4]
            vel2f= lst[5]
            variables={'collision_type':collision_type,'mass1':mass1,'vel1':vel1,'mass2':mass2,'vel2':vel2,'vel1f':vel1f,'vel2f':vel2f}
        if int(collision_type)==3:
            velf = lst[4]
            variables={'collision_type':collision_type,'mass1':mass1,'vel1':vel1,'mass2':mass2,'vel2':vel2,'velf':velf}# All the values are arranged into a dictionary
        count_of_empty=0
        for i in variables:
            if len(variables.get(i))==0:                                                                                # If any value of dictionary keys is empty string, then it will become the one to be solved
                solve=i
                count_of_empty+=1
            else:                                                                                # At the same time, all string values are change into float to allow calculations
                variables[i]=float(variables.get(i))
        if count_of_empty>1 and collision_type!=1:
            return 'ERROR: Too many empty variables'
        if collision_type==1 and count_of_empty>2:                                                                                # If there are too many missing variables or none, then a message will be returned
            return 'ERROR: Too many empty variables'
        if count_of_empty==0:
            return 'EXCEPT: All variables found'
        return variables,solve

    def find_missing_momentum1D(variables,solve):#--------------------------------------------------------------# Function that take the values and what is to be solved, to calculate the missing value
        conservation_violated=False
        negative_mass=False                                                                                # Two unrealistic cases: negative mass and unconserved energy, two boolean values to be modified
        collision_type=variables['collision_type']
        if collision_type==1:  # elastic and unelastic                                                                              Elastic collision, where kinetic energy and momentum are all conserved
            mass1,vel1,mass2,vel2,vel1f,vel2f= variables['mass1'],variables['vel1'],variables['mass2'],variables['vel2'],variables['vel1f'],variables['vel2f']
            if solve == 'mass1':
                variables['mass1']=round((mass2*(vel1f+vel1)-2*mass2*vel2)/(vel1-vel1f),2)
                mass1=variables['mass1']
                variables['vel2f']=round(vel2+(mass1*(vel1-vel1f)/mass2),2)
            if solve == 'vel1':
                variables['vel1']=( round((vel1f*(mass1+mass2)-2*mass2*vel2)/(mass1-mass2),2))  #needed to be modified
                vel1=variables['vel1']
                variables['vel2f']=round(vel2+(mass1*(vel1-vel1f)/mass2),2)
            if solve =='mass2':
                variables['mass2']=( round(mass1*(vel1f-vel1)/(2*vel2-vel1f-vel1),2))
                mass2=variables['mass2']
                variables['vel2f']=round(vel2+(mass1*(vel1-vel1f)/mass2),2)
            if solve == 'vel2':
                variables['vel2']=( round((mass1*(vel1f-vel1)+mass2*(vel1f+vel1))/2*mass2,2))                                                                                # Equation rearranged in all cases
                vel2=variables['vel2']
                variables['vel2f']=round(vel2+(mass1*(vel1-vel1f)/mass2),2)
            if solve == 'vel1f':
                variables['vel1f']=( round(vel1*(mass1-mass2)/(mass1+mass2)+vel2*2*mass2/(mass1+mass2),2))
                vel1f=variables['vel1f']
                variables['vel2f']=round(vel2+(mass1*(vel1-vel1f)/mass2),2)
            if solve == 'vel2f':
                variables['vel2f']=( round(vel2*(mass2-mass1)/(mass1+mass2)+vel1*2*mass1/(mass1+mass2),2))
                vel2f=variables['vel2f']
                variables['vel1f']=round(vel1+(mass2*(vel2-vel2f)/mass1),2)
            mass1,vel1,mass2,vel2,vel1f,vel2f= variables['mass1'],variables['vel1'],variables['mass2'],variables['vel2'],variables['vel1f'],variables['vel2f']

        if collision_type==2:  #                                                                                Inelastic, kinetic energy not conserved, momentum conserved
            mass1,vel1,mass2,vel2,vel1f,vel2f= variables['mass1'],variables['vel1'],variables['mass2'],variables['vel2'],variables['vel1f'],variables['vel2f']
            if solve == 'mass1':
                variables['mass1']=round(mass2*(vel2f-vel2)/(vel1-vel1f),2)
            if solve == 'vel1':
                variables['vel1']=round(vel1f+(mass2*(vel2f-vel2)/mass1),2)
            if solve =='mass2':
                variables['mass2']=round(mass1*(vel1-vel1f)/(vel2f-vel2),2)
            if solve == 'vel2':
                variables['vel2']=round(vel2f+(mass1*(vel1f-vel1)/mass2),2)
            if solve == 'vel1f':
                variables['vel1f']=round(vel1+(mass2*(vel2-vel2f)/mass1),2)
            if solve == 'vel2f':
                variables['vel2f']=round(vel2+(mass1*(vel1-vel1f)/mass2),2)
            mass1,vel1,mass2,vel2,vel1f,vel2f= variables['mass1'],variables['vel1'],variables['mass2'],variables['vel2'],variables['vel1f'],variables['vel2f']
            if (1/2*((mass1*vel1**2+mass2*vel2**2)-(mass1*vel1f**2+mass2*vel2f**2)))<0 and 'component_cal' not in variables:
                conservation_violated=True

        if collision_type== 3: # completely unelastic                                                                                Inelastic, kinetic energy not conserved, momentum conserved
            mass1,vel1,mass2,vel2,velf= variables['mass1'],variables['vel1'],variables['mass2'],variables['vel2'],variables['velf']
            if solve == 'mass1':
                variables['mass1']=( round((mass2*(velf-vel2))/(vel1-velf),2))
            if solve == 'vel1':
                variables['vel1']=( round((mass2*(velf-vel2))/mass1+velf,2))
            if solve == 'mass2':
                variables['mass2']=( round((mass1*(vel1-velf))/(velf-vel2),2))
            if solve == 'vel2':
                variables['vel2']=( round((velf-mass1*(vel1-velf))/mass2,2))
            if solve == 'velf':
                variables['velf']=(round((mass1*vel1+mass2*vel2)/(mass1+mass2),2))
        if variables['mass1']<0 or variables['mass2']<0:
            negative_mass=True
        if conservation_violated==True or negative_mass==True:
            if conservation_violated==True:                                                                                # When law of physics is violated, no true value will be returned, instead it will be None
                variables=None
                print("Re-enter values, total kinetic energy is not conserved")
            else:
                print("Re-enter values, unrealistic mass occurred")
                variables=None

        return (variables)
    def redraw_1d(variables):#--------------------------------------------------------------------------------------------# Function to draw animation
        pygame.init()
        screen=pygame.display.set_mode((WIDTH, HEIGHT))
        if len(variables)==7:                                                                                # Check the number of keys in a dictionary, to determine how many variables are needed to be defined
            m1,m2,v1,v2,v1f,v2f= variables['mass1'],variables['mass2'],variables['vel1'],variables['vel2'],variables['vel1f'],variables['vel2f']
        else:
            m1,m2,v1,v2,v1f,v2f= variables['mass1'],variables['mass2'],variables['vel1'],variables['vel2'],variables['velf'],variables['velf']
        lst_values=[v1,v2,v1f,v2f]
        display=True
        post_col=False                                                                                # A boolean variable that determine when the collision happen
        press=0
        if v1>=0:
            ang1=0                                                                                # SInce it is 1d, no angles are inputted by user, but the negative/positive sign determine the direction of the velocity
        else:
            ang1=pi
        if v2>=0:
            ang2=0                                                                                # When velocity is bigger than 0, direction becomes 0 degree; when it is smaller than 0, direction becomes 180 degree

        else:
            ang2=pi
        d1x,d1y,d2x,d2y=initial_pos(v1,0,v2,0,ang1,ang2)                                                                            # initial_pos() is called to determine the initial position of of two ball so that they collide at the very center
        x1=WIDTH/2+d1x
        x2=WIDTH/2+d2x                                                                                # Values returned by the function is added to the center coordinate and initial position determined
        y=HEIGHT/2
        lst=ratio_conversion(lst_values)                                                                                # ratio_conversion() is called to recalculate relative velocity
        v1,v2,v1f,v2f=lst[0],lst[1],lst[2],lst[3]

        while display:                                                                                # While loop called to display and redraw the animation
            screen.fill(BLACK)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:                                                                                # When space is pressed, slow down the animation
                    pygame.quit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_SPACE:
                        press+=3
                    if event.key == pygame.K_r:                                                                                # When r is pressed, the program returns to the value selection
                        fade(WIDTH,HEIGHT)
                        main()

            if distance(x1,y,x2,y)<20:                                                                                # If the object did not touch, they will have the initial velocities
                post_col=True
            if post_col==True:                                                                                # When they collide, the pre-set boolean variable becomes False

                act_vel1=v1f
                act_vel2=v2f
            else:
                act_vel1=v1
                act_vel2=v2

            x1+=act_vel1
            x2+=act_vel2
            indication(x1,y,WHITE)
            indication(x2,y,GREY)
            if m1>m2:
                pygame.draw.circle(screen,WHITE, (int(x1),int(y)), int(12),0)
                pygame.draw.circle(screen,GREY, (int(x2),int(y)), int(8),0)
            if m1<m2:
                pygame.draw.circle(screen,WHITE, (int(x1),int(y)), int(8),0)
                pygame.draw.circle(screen,GREY, (int(x2),int(y)), int(12),0)
            legend(screen,variables)                                                                                # Legend function is called to update the velocity and mass
            pygame.display.update()
            pygame.time.delay(press)

    print('-'*30)

    def find_missing_momentum2D(lst,collision_type):#-----------------------------------------------------------------# The main function that collects data and calculates the variables for 2d collisions
        collision_type= collision_type
        print("All angles are mandatory to be input")
        vel1= lst[0]
        angle1= lst[1]
        mass1 = lst[2]
        vel2= lst[3]                                                                                # Variables inside of the function is defined using the imported list of values
        angle2=lst[4]
        mass2 = lst[5]
        if collision_type =='1' or  collision_type =='2':
            vel1f= lst[6]
            angle1f=lst[7]                                                                                # Separate the cases of elastic, inelastic and completely inelastic
            vel2f= lst[8]
            angle2f=lst[9]
            variables={'collision_type':collision_type,'mass1':mass1,'vel1':vel1,'angle1':angle1,'mass2':mass2,'vel2':vel2,'angle2':angle2,'vel1f':vel1f,'angle1f':angle1f,'vel2f':vel2f,'angle2f':angle2f}
        if collision_type=='3':
            velf =lst[6]
            anglef=lst[7]
            variables={'collision_type':collision_type,'mass1':mass1,'vel1':vel1,'angle1':angle1,'mass2':mass2,'vel2':vel2,'angle2':angle2,'velf':velf,'anglef':anglef}

        count_of_empty=0
        vel_variables={}
        ang=[]
        for i in variables:
            if len(variables.get(i))==0:                                                                                # Run through the similar procedure to check the unknown variable
                solve=i                                                                                # if the value is empty string then it becomes the unknown to be solved
                count_of_empty+=1
            else:                                                                                # Otherwise it will be convert into float
                variables[i]=float(variables[i])

            if 'v' in i :                                                                                # Make copies of all velocity variables of the dictionary that consist of only velocities
                vel_variables[i]=variables.get(i)
            if 'g' in i :
                ang.append(variables.get(i))                                                                                # Makes copies of all angles variables of the dictionary that consist of only velocities
        for i in vel_variables:
            for p in reversed(ang):
                vel_variables[i]=(variables.get(i),p)                                                                                # Create a dictionary that consists of tuples containing velocities and their corresponding angles
            ang.remove(p)
        if count_of_empty>2:
            return 'ERROR: Too many empty variables'
        if count_of_empty==0:                                                                                # If too much missing values or none, print message
            return 'EXCEPT: All variables found'

        velx_variables={}
        vely_variables={}                                                                                # Create two empty dictionary reserved for velocities of different axis
        xy_axis=(velx_variables,vely_variables,variables)
        for i in vel_variables:
            if i!=solve:

                velx_variables[i]=round((vel_variables[i][0])*cos(vel_variables[i][1]*pi/180),2)                                # Velocities of each axis is being calculated using the angle assigned and being added into the two dictionary
                vely_variables[i]=round((vel_variables[i][0])*sin(vel_variables[i][1]*pi/180),2)
            else:
                velx_variables[i]=''
                vely_variables[i]=''                                                                                # If the any variable is solve, a empty string is assgned as the value of the corresponding key
        for i in xy_axis:
            i['collision_type']=variables['collision_type']                                                                                # Two new keys assigned to indicate that it is calculate a component
            i['component_cal']=True
        for i in xy_axis:
            for p in variables:
                if 'mass' in p:
                    i[p]=variables[p]
        if find_missing_momentum1D(vely_variables,solve)!=None or find_missing_momentum1D(velx_variables,solve)!= None:# If mass variable becomes negative or conservation of energy is false as calculated previously
            vely_variables[solve]=find_missing_momentum1D(vely_variables,solve)[solve]
            velx_variables[solve]=find_missing_momentum1D(velx_variables,solve)[solve]                                                      # No real values is returned if one of the two conditions is met
            if 'mass' not in solve:
                variables[solve]=sqrt(vely_variables[solve]**2+velx_variables[solve]**2)
            if 'mass' in solve:
                variables[solve]=vely_variables[solve]                                                                                # None s will be returned to re-ask the user to input values
            return(xy_axis)
        else:
            xy_axis=(None,None,None)
            return xy_axis

    def ratio_conversion2d(lstx,lsty):#------------------------------------------------------------------------------------------------------# Ratio conversion of 2d version , takes two parameter instead of one
        v_max=max([abs(i) for i in lstx+lsty if i!=0])
        v_min=min([abs(i) for i in lstx+lsty if i!=0])
        if v_max>1.3:
            ratio=1.3/v_max
            for i in range(len(lstx)):
                lstx[i]= lstx[i]*ratio
                lsty[i]= lsty[i]*ratio                                                                                # Go through the same procedure as the 1d ratio conversion, see previous code to relate
        elif v_min<0.1:
            ratio=0.1/v_min
            for i in range(len(lstx)):
                lstx[i]= lstx[i]*ratio
                lsty[i]= lsty[i]*ratio
        return (lstx,lsty)

    def redraw_2d(variable_x,variable_y,variables):                                                                                # The function that update screen and show animation
        if None in (variable_x,variable_y,variables):
            pass
        else:
            xy=[variable_x,variable_y]
            pygame.init()
            screen=pygame.display.set_mode((WIDTH, HEIGHT))
            display=True                                                                                # The boolean value to set the while loop to keep the game going
            post_col=False                                                                                # Boolean value that check if it's before or after the collision
            press=0
            m1,m2=variable_x['mass1'],variable_x['mass2']
            if len(variable_x)==8:
                v1x,v2x,v1fx,v2fx= variable_x['vel1'],variable_x['vel2'],variable_x['vel1f'],variable_x['vel2f']
            else:
                v1x,v2x,v1fx,v2fx= variable_x['vel1'],variable_x['vel2'],variable_x['velf'],variable_x['velf']                              # Variables will be different if the type of collision is different
            if len(variable_y)==8:
                v1y,v2y,v1fy,v2fy= variable_y['vel1'],variable_y['vel2'],variable_y['vel1f'],variable_y['vel2f']
            else:
                v1y,v2y,v1fy,v2fy= variable_y['vel1'],variable_y['vel2'],variable_y['velf'],variable_y['velf']
            d1x,d1y,d2x,d2y=initial_pos(v1x,v1y,v2x,v2y,variables['angle1'],variables['angle2'])                                            # Use initial_pos function to determine the location to start so they can meet at the center
            print(d1x,d1y,d2x,d2y)
            x1=WIDTH/2+d1x
            y1=HEIGHT/2-d1y
            x2=WIDTH/2+d2x                                                                                # the distance is applied to the initial x, y values of the balls
            y2=HEIGHT/2-d2y
            print('x1:',x1,'y1',y1,'x2',x2,'y2',y2)
            lstx=[v1x,v2x,v1fx,v2fx]
            lsty=[v1y,v2y,v1fy,v2fy]
            ratio_conversion2d(lstx,lsty)                                                                                # Velocity ratio conversion function is applied so that the balls travels at the observable speed
            nlx,nly=ratio_conversion2d(lstx,lsty)
            v1x,v2x,v1fx,v2fx=nlx[0],nlx[1],nlx[2],nlx[3]
            v1y,v2y,v1fy,v2fy=nly[0],nly[1],nly[2],nly[3]

            while display:
                screen.fill(BLACK)
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        pygame.quit()                                                                                # If quit hit, quit the screen
                    if event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_SPACE:
                            press+=3                                                                                # If space pressed, the display time becomes slower
                        if event.key == pygame.K_r:
                            fade(WIDTH,HEIGHT)                                                                                # If r pressed, use returns to the variables input screen
                            main()

                if distance(x1,y1,x2,y2)<20:
                    post_col=True
                if post_col==True:
                    velx1,vely1,velx2,vely2=v1fx,v1fy,v2fx,v2fy                                                                                # Before or after collision is detected so new velocities can be assigned

                else:
                    velx1,vely1,velx2,vely2=v1x,v1y,v2x,v2y
        ##        print( velx1,vely1,velx2,vely2)
                x1+=velx1
                x2+=velx2
                y1-=vely1
                y2-=vely2
                indication(x1,y1,WHITE)
                indication(x2,y2,GREY)                                                                                # Indicator are called here
                if m1>m2:
                    pygame.draw.circle(screen,WHITE, (int(x1),int(y1)), int(12),0)
                    pygame.draw.circle(screen,GREY, (int(x2),int(y2)), int(8),0)
                if m1<m2:
                    pygame.draw.circle(screen,WHITE, (int(x1),int(y1)), int(8),0)
                    pygame.draw.circle(screen,GREY, (int(x2),int(y2)), int(12),0)
                pygame.draw.circle(screen,RED, center, 4,0)
                legend(screen,variables)
                pygame.display.update()                                                                                #
                pygame.time.delay(press)

    def indication(x,y,color):
        if x>WIDTH:
            ratio=abs(WIDTH/x)
            ind=right
            indicator=ind.get_rect(center=(WIDTH-18,int(y)))                                                                                # Indicator function helps to indicate the position of the ball when they are outside of the screen
            pygame.draw.circle(screen,color, (WIDTH-48,int(y)), int(7*ratio),0)
            screen.blit(ind,indicator)
        if x<0:
            ratio=(WIDTH/(WIDTH+abs(x)))                                                                                # General concept: When the x or y of ball is bigger or smaller than the limit of the screen, a triangle indicator will be shown ,and a ball will be shown with a changing size that depends on the how far away the ball is from the screen
            ind=left
            indicator=ind.get_rect(center=(18,int(y)))
            pygame.draw.circle(screen,color, (48,int(y)), int(7*ratio),0)
            screen.blit(ind,indicator)
        if y>HEIGHT:
            ratio=abs(HEIGHT/y)
            ind=down
            indicator=ind.get_rect(center=(int(x),(HEIGHT-18)))
            pygame.draw.circle(screen,color, (int(x),HEIGHT-48), int(7*ratio),0)
            screen.blit(ind,indicator)
        if y<0:
            ratio=(HEIGHT/(HEIGHT+abs(Y)))
            ind=up
            indicator=ind.get_rect(center=(int(x),(18)))
            pygame.draw.circle(screen,color, (int(x),48), int(7*ratio),0)
            screen.blit(ind,indicator)

    def choose_component():#-----------------------------------------------------------------------------------------------------------# A function that sets the screen for the user to be abl eto choose which dimension of animation is to be shown

        while True:
            event = pygame.event.poll()
            mousex, mousey = pygame.mouse.get_pos()
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            twoD_width=233                                                                                # Dimension of each button is defined here
            twoD_x=239
            oneD_width=233
            oneD_x=497
            h=351
            y=137
            if oneD_x <= mousex <= oneD_x+oneD_width and y <= mousey <= y+h and event.type == pygame.MOUSEBUTTONDOWN:# If the mouse is clicked with a certain location, the type of visualization will be shown
                return '1d'
            elif twoD_x <= mousex <= twoD_x+twoD_width and y <= mousey < y+h and event.type == pygame.MOUSEBUTTONDOWN:
                return '2d'

            screen.blit(choose_image,(0,0))
            if oneD_x <= mousex <= oneD_x+oneD_width and y <= mousey <= y+h :                                                           # In order to make the visual effect better, when mouse is positioned over a certain area, it will increase the visual attribute of the product
                screen.blit(oneD_click,(0,0))
            elif twoD_x <= mousex <= twoD_x+twoD_width and y <= mousey < y+h:
                screen.blit(twoD_click,(0,0))

            pygame.display.update()
    def choose_collision():
        myfont = pygame.font.SysFont('Arial', 36)
        ELASTIC_txt = myfont.render('ELASTIC', False, WHITE)

        INELASTIC_txt = myfont.render('INELASTIC', False, ORANGE)                                                                                # Indication to be shown on each section of the screen

        CE_txt = myfont.render('COMPLETELY', False, BLACK)
        CE_txt2=myfont.render('INELASTIC', False, BLACK)
        while True:
            event = pygame.event.poll()
            mousex, mousey = pygame.mouse.get_pos()
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            elastic_width=WIDTH/3
            elastic_x=0
            inelatic_width=WIDTH/3                                                                                # The three sections of the screen on which if clicked, will lead to different type of collision
            inelastic_x=WIDTH/3
            CE_width=WIDTH/3
            CE_x=2*WIDTH/3
            h=HEIGHT
            y=0
            if elastic_x <= mousex <=elastic_width and y <= mousey <= y+h and event.type == pygame.MOUSEBUTTONDOWN:
                return '1'
            elif inelastic_x <= mousex <= inelastic_x+inelatic_width and y <= mousey < y+h and event.type == pygame.MOUSEBUTTONDOWN:# If mouse is clicked  within a certain area, the type of collision will be chosen
                return '2'
            elif CE_x <= mousex <= CE_x+CE_width and y <= mousey < y+h and event.type == pygame.MOUSEBUTTONDOWN:
                return '3'

            screen.fill(BLACK)
            if elastic_x <= mousex <=elastic_width and y <= mousey <= y+h:
                pygame.draw.rect(screen, ORANGE, (elastic_x,y,elastic_width,HEIGHT), 0)
                screen.blit(ELASTIC_txt,(WIDTH/6-75, h/2))
            elif inelastic_x <= mousex <= inelastic_x+inelatic_width and y <= mousey < y+h:
                pygame.draw.rect(screen, GREY, (inelastic_x,y,inelatic_width,HEIGHT), 0)                                                                        # Visual attributes of the button, when mouse is positioned on a certain are, color will be changed
                screen.blit(INELASTIC_txt,(3*WIDTH/6-75, h/2))
            elif CE_x <= mousex <= CE_x+CE_width and y <= mousey < y+h:
                pygame.draw.rect(screen, WHITE, (CE_x,y,CE_width,HEIGHT), 0)
                screen.blit(CE_txt,(5*WIDTH/6-75, h/2))
                screen.blit(CE_txt2,(5*WIDTH/6-75, h/2+50))

            pygame.display.update()
    def fade(width,height):                                                                                # Function that will make the screen to fade into a certain color
        fade=pygame.Surface((width,height))
        fade.fill(BLACK)
        for alpha in range(0,300):
            fade.set_alpha(alpha)
            screen.blit(fade,(0,0))
            pygame.display.update()
            pygame.time.delay(3)

    def Rfade(width,height):                                                                                # Function that will make the screen to inversely fade into a certain color

        fade=pygame.Surface((width,height))
        fade.fill(WHITE)
        for alpha in reversed(range(0,300)):
            fade.set_alpha(alpha)
            screen.blit(fade,(0,0))
            pygame.display.update()
            pygame.time.delay(3)

    def main(case='2d',collision='1'):                                                                                # Main function that contained all the little functions
        case=choose_component()
        collision_type=choose_collision()
        a,b=slider_set(case,collision_type)
        fade(WIDTH,HEIGHT)                                                                                ### Firstly, the choose cases functions are called to determine the dimension and the type of the collision
        if case=='1d':                                                                                ### Determine the type values b using sliders
            a,b=ask_for_input(a,b)
            print(a)                                                                                ### The sliders value are inputted into functions to rearrange and calculate the missing data to finalize the visualization
            print(find_missing_momentum1D(a,b))
            while None == find_missing_momentum1D(a,b):
                a,b=slider_set(case,collision_type)
                print(a)                                                                                ### If special cases are met, re ask the using input more valid values, and run through the process again
                a,b=ask_for_input(a,b)
                find_missing_momentum1D(a,b)

        if case=='2d':
            a,b,c=find_missing_momentum2D(a,b)
            print(a,b,c)
            while None in find_missing_momentum1D(a,b):                                                         # Same scenario applies for 2d collision
                print('fuck meeee')
                a,b=slider_set(case,collision_type)
                a,b,c=find_missing_momentum1D(a,b)

        if case=='1d':

            print(redraw_1d(find_missing_momentum1D(a,b)))                                                  # Draw the 1d scenario
        if case=='2d':
            redraw_2d(a,b,c)                                                                                # Draw the 2d scenario
    main()
    unit=''                                                                                # Main functions calling


from __future__ import print_function
from __future__ import division
import pickle
import numpy as np
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
import torch.optim as optim
from joblib import Parallel, delayed
import multiprocessing as mp
from tqdm import tqdm

classes_c2f_map = [['beaver', 'dolphin', 'otter', 'seal', 'whale'],
                   ['aquarium_fish', 'flatfish', 'ray', 'shark', 'trout'],
                   ['orchid', 'poppy', 'rose', 'sunflower', 'tulip'],
                   ['bottle', 'bowl', 'can', 'cup', 'plate'],
                   ['apple', 'mushroom', 'orange', 'pear', 'sweet_pepper'],
                   ['clock', 'keyboard', 'lamp', 'telephone', 'television'],
                   ['bed', 'chair', 'couch', 'table', 'wardrobe'],
                   ['bee', 'beetle', 'butterfly', 'caterpillar', 'cockroach'],
                   ['bear', 'leopard', 'lion', 'tiger', 'wolf'],
                   ['bridge', 'castle', 'house', 'road', 'skyscraper'],
                   ['cloud', 'forest', 'mountain', 'plain', 'sea'],
                   ['camel', 'cattle', 'chimpanzee', 'elephant', 'kangaroo'],
                   ['fox', 'porcupine', 'possum', 'raccoon', 'skunk'],
                   ['crab', 'lobster', 'snail', 'spider', 'worm'],
                   ['baby', 'boy', 'girl', 'man', 'woman'],
                   ['crocodile', 'dinosaur', 'lizard', 'snake', 'turtle'],
                   ['hamster', 'mouse', 'rabbit', 'shrew', 'squirrel'],
                   ['maple_tree', 'oak_tree', 'palm_tree', 'pine_tree', 'willow_tree'],
                   ['bicycle', 'bus', 'motorcycle', 'pickup_truck', 'train'],
                   ['lawn_mower', 'rocket', 'streetcar', 'tank', 'tractor']]
mmap = None

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # auxiliary
        self.dropout_conv = nn.Dropout(p=0.15)
        self.dropout_fc = nn.Dropout(p=0.25)
        # block 1
        self.conv_b1_1 = nn.Conv2d(3, 32, 3, padding=1)
        self.conv_b1_bn1 = nn.BatchNorm2d(32)
        self.conv_b1_2 = nn.Conv2d(32, 32, 3, padding=1)
        self.conv_b1_bn2 = nn.BatchNorm2d(32)
        self.conv_b1_3 = nn.Conv2d(32, 32, 3, padding=1)
        self.conv_b1_bn3 = nn.BatchNorm2d(32)
        self.pool_b1 = nn.MaxPool2d(2, 2)
        # block 2
        self.conv_b2_1 = nn.Conv2d(32, 64, 3, padding=1)
        self.conv_b2_bn1 = nn.BatchNorm2d(64)
        self.conv_b2_2 = nn.Conv2d(64, 64, 3, padding=1)
        self.conv_b2_bn2 = nn.BatchNorm2d(64)
        self.conv_b2_3 = nn.Conv2d(64, 64, 3, padding=1)
        self.conv_b2_bn3 = nn.BatchNorm2d(64)
        self.pool_b2 = nn.MaxPool2d(2, 2)
        # block 3
        self.conv_b3_1 = nn.Conv2d(64, 128, 3, padding=1)
        self.conv_b3_bn1 = nn.BatchNorm2d(128)
        self.conv_b3_2 = nn.Conv2d(128, 128, 3, padding=1)
        self.conv_b3_bn2 = nn.BatchNorm2d(128)
        self.conv_b3_3 = nn.Conv2d(128, 128, 3, padding=1)
        self.conv_b3_bn3 = nn.BatchNorm2d(128)
        self.pool_b3 = nn.MaxPool2d(2, 2)
        # block 4
        self.conv_b4_1 = nn.Conv2d(128, 256, 3, padding=1)
        self.conv_b4_bn1 = nn.BatchNorm2d(256)
        self.conv_b4_2 = nn.Conv2d(256, 256, 3, padding=1)
        self.conv_b4_bn2 = nn.BatchNorm2d(256)
        self.conv_b4_3 = nn.Conv2d(256, 256, 3, padding=1)
        self.conv_b4_bn3 = nn.BatchNorm2d(256)
        self.pool_b4 = nn.MaxPool2d(2, 2)
        # block 5
        self.conv_b5_1 = nn.Conv2d(256, 512, 3, padding=1)
        self.conv_b5_bn1 = nn.BatchNorm2d(512)
        self.conv_b5_2 = nn.Conv2d(512, 512, 3, padding=1)
        self.conv_b5_bn2 = nn.BatchNorm2d(512)
        self.conv_b5_3 = nn.Conv2d(512, 512, 3, padding=1)
        self.conv_b5_bn3 = nn.BatchNorm2d(512)
        self.pool_b5 = nn.MaxPool2d(2, 2)

        # coarse branch 1 -> generalized classes
        self.br1_fc1 = nn.Linear(512, 4096)
        self.br1_bn1 = nn.BatchNorm1d(4096)
        self.br1_fc2 = nn.Linear(4096, 4096)
        self.br1_bn2 = nn.BatchNorm1d(4096)
        self.br1_fc3 = nn.Linear(4096, 20)
        self.br1_sm = nn.Softmax(dim=1)
        # branch 2 -> Fine layers
        self.br2_fc1 = nn.Linear(512, 4096)
        self.br2_bn1 = nn.BatchNorm1d(4096)
        self.br2_fc2 = nn.Linear(4096, 4096)
        self.br2_bn2 = nn.BatchNorm1d(4096)
        self.br2_fc3 = nn.Linear(4096, 100)
        self.br2_sm = nn.Softmax(dim=1)

    def forward(self, x):
        # block 1 forward prop
        x = F.leaky_relu(self.conv_b1_bn1(self.conv_b1_1(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b1_bn2(self.conv_b1_2(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b1_bn3(self.conv_b1_3(x)))
        x = self.dropout_conv(x)
        x = self.pool_b1(x)
        # block 2 forward prop
        x = F.leaky_relu(self.conv_b2_bn1(self.conv_b2_1(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b2_bn2(self.conv_b2_2(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b2_bn3(self.conv_b2_3(x)))
        x = self.dropout_conv(x)
        x = self.pool_b2(x)
        # block 3 forward prop
        x = F.leaky_relu(self.conv_b3_bn1(self.conv_b3_1(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b3_bn2(self.conv_b3_2(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b3_bn3(self.conv_b3_3(x)))
        x = self.dropout_conv(x)
        x = self.pool_b3(x)
        # block 3 forward prop
        x = F.leaky_relu(self.conv_b4_bn1(self.conv_b4_1(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b4_bn2(self.conv_b4_2(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b4_bn3(self.conv_b4_3(x)))
        x = self.dropout_conv(x)
        x = self.pool_b4(x)
        # block 3 forward prop
        x = F.leaky_relu(self.conv_b5_bn1(self.conv_b5_1(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b5_bn2(self.conv_b5_2(x)))
        x = self.dropout_conv(x)
        x = F.leaky_relu(self.conv_b5_bn3(self.conv_b5_3(x)))
        x = self.dropout_conv(x)
        x = self.pool_b5(x)
        # offshoot branch 1
        br1_x = x.view(-1, self.num_flat_features(x))
        br1_x = self.br1_fc1(br1_x)
        br1_x = self.br1_bn1(br1_x)
        br1_x = F.leaky_relu(br1_x)
        br1_x = self.dropout_fc(br1_x)
        br1_x = self.br1_fc2(br1_x)
        br1_x = self.br1_bn2(br1_x)
        br1_x = F.leaky_relu(br1_x)
        br1_x = self.dropout_fc(br1_x)
        br1_x = self.br1_fc3(br1_x)
        br1_out = self.br1_sm(br1_x)
        # offshoot branch 2
        br2_x = x.view(-1, self.num_flat_features(x))
        br2_x = self.br2_fc1(br2_x)
        br2_x = self.br2_bn1(br2_x)
        br2_x = F.leaky_relu(br2_x)
        br2_x = self.dropout_fc(br2_x)
        br2_x = self.br2_fc2(br2_x)
        br2_x = self.br2_bn2(br2_x)
        br2_x = F.leaky_relu(br2_x)
        br2_x = self.dropout_fc(br2_x)
        br2_x = self.br2_fc3(br2_x)
        br2_out = self.br2_sm(br2_x)
        return(br1_out, br2_out)

    def num_flat_features(self, x):
        size = x.size()[1:]  # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

def map_subclasses(array):
    for i in range(0, len(array)):
        array[i] = mmap[array[i]]
    return(array)

def eval_net(dataloader):
    correct_coarse = 0
    correct_fine = 0
    total = 0
    total_loss_coarse = 0
    total_loss_fine = 0
    net.eval()
    criterion1 = nn.CrossEntropyLoss(reduction='mean')
    criterion2 = nn.CrossEntropyLoss(reduction='mean')
    for data in dataloader:
        images, labels = data
        coarse_labels = np.copy(labels.numpy())
        coarse_labels = map_subclasses(coarse_labels)
        coarse_labels = torch.from_numpy(coarse_labels)
        images = Variable(images).cuda()
        labels = Variable(labels).cuda()
        coarse_labels = Variable(coarse_labels).cuda()
        coarse_out, fine_out = net(images)
        _, predicted_coarse = torch.max(coarse_out.data, 1)
        _, predicted_fine = torch.max(fine_out.data, 1)
        total += labels.size(0)
        correct_coarse += (predicted_coarse == coarse_labels.data).sum()
        correct_fine += (predicted_fine == labels.data).sum()
        fine_loss = criterion1(fine_out, labels)
        coarse_loss = criterion2(coarse_out, coarse_labels)
        total_loss_fine += fine_loss.item()
        total_loss_coarse += coarse_loss.item()
    net.train()
    return (total_loss_coarse / total, correct_coarse.float() / total,
            total_loss_fine / total, correct_fine.float() / total)

def objective(model, input, coarse_label, fine_labels):
    coarse_out, fine_out = model(input)
    # return torch.max(fine_out[0, fine_labels])
    return 2 * torch.max(fine_out[0, fine_labels]) - coarse_out[0, coarse_label]

def objective_gradient(objective, model, input, coarse_label, fine_labels):
    x = input.detach().clone()
    x.requires_grad = True
    output = objective(model, x, coarse_label, fine_labels)
    output.backward()
    grad = x.grad.clone()
    return grad

def projection(input):
    input = input
    input[input > 1] = 1
    input[input < -1] = -1
    return input

def attack(model, input, coarse_label, fine_labels, epsilon):
    curr = input.clone()
    curr.requires_grad = True

    for iter in range(30):

        grad = objective_gradient(objective, model, curr,
                                  coarse_label, fine_labels)
        grad = epsilon * grad / torch.norm(grad, p="fro")
        next = curr - grad

        curr.data = next.clone()

    return projection(curr.detach())

def job(i, model, images, labels):
    image = images[i, :, :, :].unsqueeze(0)
    label = labels[i]
    coarse_label = map_subclasses(np.array(label, ndmin=2))
    fine_labels = np.flatnonzero(mmap == coarse_label)
    coarse_label = torch.from_numpy(coarse_label)
    fine_labels = torch.from_numpy(fine_labels)

    output_image = attack(net, image, coarse_label, fine_labels, 1)

    return (output_image, coarse_label)

if __name__ == "__main__":
    BATCH_SIZE = 32  # mini_batch size

    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
    train_transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

    trainset = torchvision.datasets.CIFAR100(root='./data', train=True,
                                             download=True, transform=train_transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE,
                                              shuffle=True, num_workers=2)

    testset = torchvision.datasets.CIFAR100(root='./data', train=False,
                                            download=True, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE,
                                             shuffle=False, num_workers=2)

    classes = pickle.load(open('./data/cifar-100-python/meta', 'rb'))
    fine = classes['fine_label_names']
    coarse = classes['coarse_label_names']
    a = []
    for name in fine:
        i = 0
        for sublist in classes_c2f_map:
            if name in sublist:
                a.append(i)
            i = i + 1
    mmap = np.array(a)
    net = Net().cpu()
    optimizer = optim.SGD(net.parameters(), lr=0.005, momentum=0.85)
    pretrained = torch.load('block5_branch.pth', map_location=torch.device('cpu'))
    net.load_state_dict(pretrained['state_dict'])
    net.eval()

    output_labels = np.empty((0, 1))
    output_images = np.empty((0, 3, 32, 32))

    # set up multiprocessing
    num_cores = mp.cpu_count()

    ctr = 0
    for data in trainloader:
        images, labels = data
        n_items = len(labels)
        idxs = tqdm(range(n_items))
        results = (Parallel(n_jobs=num_cores)(delayed(job)(i, net, images, labels) for i in idxs))

        for i in range(n_items):
            output_images = np.append(output_images, results[i][0].numpy(), axis=0)
            output_labels = np.append(output_labels, results[i][1].numpy(), axis=0)

        np.save("attacked_images.npy", output_images)
        np.save("attacked_image_labels.npy", output_labels)