import tkinter
from tkinter import ttk
import time
from json.encoder import INFINITY as inf

graphe = {}
graphe_arc = {}

def d_sommet(x0, y0):
    rayon = 15
    id_sommet = zone_d.create_oval(
        x0 - rayon, y0 - rayon, x0 + rayon, y0 + rayon, fill="white", activefill="blue"
    )
    zone_d.create_text(
        x0,
        y0,
        text=str(id_sommet),
        justify="center",
        anchor="c",
        font=("courier", 10),
        fill="black",
    )
    graphe[id_sommet] = [id_sommet]
    graphe_arc[(id_sommet, id_sommet)] = [0, None]

def clic_cercle(event):
    clic_x, clic_y = event.x, event.y
    d_sommet(clic_x, clic_y)

def kalaba(*args):
    arr = int(entry_arr.get())
    etape_list = list()
    etape_dist = list()
    dist = {}
    succ = {}

    dist[arr] = 0
    succ[arr] = None

    for key in graphe:
        if key != arr:
            dist[key] = inf
            succ[key] = None
    etape_list.append(succ)
    etape_dist.append(dist)

    toDo = [arr]
    etape = 0
    while toDo != []:
        etape = etape + 1
        x = toDo.pop()
        zone_d.itemconfig(x, fill="yellow")
        for y in graphe[x]:
            if dist[x] + graphe_arc[(y, x)][0] < dist[y]:
                dist[y] = dist[x] + graphe_arc[(y, x)][0]
                succ[y] = x
                toDo.append(y)
        zone_d.itemconfig(x, fill="white")
        etape_list.append(succ)
        etape_dist.append(dist)

    key = 1
    while succ[key] != None:
        zone_d.itemconfig(key, fill="yellow")
        zone_d.itemconfig(graphe_arc[(key, succ[key])][1], fill="red")
        key = succ[key]
    zone_d.itemconfig(arr, fill="yellow")
    print("terminer")

    for k in range(etape):
        print(etape_list[k])
        print(etape_dist[k])

def arc(*arg):
    global v
    dep = int(entr_deb.get())
    arr = int(entr_arr.get())
    pds = eval(entr_poids.get())
    a = zone_d.coords(dep)
    b = zone_d.coords(arr)

    if pds == "":
        pds = 0
    else:
        pds = int(pds)

    dep_x = (a[0] + a[2]) // 2
    dep_y = (a[1] + a[3]) // 2

    arr_x = (b[0] + b[2]) // 2
    arr_y = (b[1] + b[3]) // 2

    arc = zone_d.create_line(
        dep_x, dep_y, arr_x, arr_y, fill="black", width=0.5, smooth=1, arrow="last"
    )
    zone_d.create_text(
        (arr_x + dep_x) // 2,
        (dep_y + arr_y) // 2,
        text=pds,
        justify="center",
        anchor="c",
        fill="white",
    )
    graphe_arc[dep, arr] = [pds, arc]
    graphe[arr].append(dep)

fen_p = tkinter.Tk()  # La fenetre principale

dessin_c = tkinter.LabelFrame(fen_p, text="Sommet")  # Cadre contenant la zone de dessin

zone_d = tkinter.Canvas(
    dessin_c, bg="gray", width=600, height=500
)  # Canvas pour dessiner le graphe
zone_d.bind("<Button-1>", clic_cercle)  # Binding : surveillance des clics

# Cadre permettant de saisir les arcs de la graphe
arc_entry = tkinter.LabelFrame(dessin_c, text="Arc")

entr_deb_l = tkinter.Label(arc_entry, text="Depart")
entr_arr_l = tkinter.Label(arc_entry, text="Arrive")
entr_poids_l = tkinter.Label(arc_entry, text="Poids")
entr_deb = tkinter.Entry(arc_entry, width=5)
entr_arr = tkinter.Entry(arc_entry, width=5)
entr_poids = tkinter.Entry(arc_entry, width=5)
btn_val = tkinter.Button(arc_entry, text="Valider", command=arc)
error_str = tkinter.StringVar()

entr_deb_l.grid(row=1, column=1)
entr_arr_l.grid(row=1, column=2)
entr_poids_l.grid(row=1, column=3)
entr_deb.grid(row=2, column=1)
entr_arr.grid(row=2, column=2)
entr_poids.grid(row=2, column=3)
btn_val.grid(row=2, column=4)

# Cadre pour demarre l'algorithme
debut = tkinter.LabelFrame(fen_p)
msg = tkinter.Label(debut, text="Saisir le but de votre graphe")

entry_arr = tkinter.Entry(debut)
kalaba_btn = tkinter.Button(debut, text="Demmrer l'algorithme", command=kalaba)
msg.pack()
entry_arr.pack()
kalaba_btn.pack()

dessin_c.pack()
zone_d.grid(row=1, column=1, sticky="nw")
arc_entry.grid(row=2, column=1, sticky="nw")

debut.pack()

fen_p.mainloop()


#修改了原SGC的forward，增加了relu
import torch
import torch.nn as nn
from torch.nn import Module
import torch.nn.functional as F
import math
from torch_geometric.nn import GCNConv

class SGC(nn.Module):
    """
    A Simple PyTorch Implementation of Logistic Regression.
    Assuming the features have been preprocessed with k-step graph propagation.
    """
    def __init__(self, nfeat, nclass):
        super(SGC, self).__init__()

        self.W = nn.Linear(nfeat, nclass)

    def forward(self, x):
        features = self.W(x)
        predictions = torch.nn.functional.log_softmax(features, dim=1)
        return predictions

class GraphConvolution(Module):
    """
    A Graph Convolution Layer (GCN)
    """

    def __init__(self, in_features, out_features, bias=True):
        super(GraphConvolution, self).__init__()
        self.in_features = in_features
        self.out_features = out_features
        self.W = nn.Linear(in_features, out_features, bias=bias)
        self.init()

    def init(self):
        stdv = 1. / math.sqrt(self.W.weight.size(1))
        self.W.weight.data.uniform_(-stdv, stdv)
    #GCN因为有多层，要一直保证系数矩阵的normal
    def forward(self, input, adj):
        support = self.W(input)
        output = torch.spmm(adj, support)
        return output

class GCN(nn.Module):
    """
    A Two-layer GCN.
    """
    def __init__(self, nfeat, nhid, nclass, dropout):
        super(GCN, self).__init__()

        self.gc1 = GraphConvolution(nfeat, nhid)
        self.gc2 = GraphConvolution(nhid, nclass)
        self.dropout = dropout

    def forward(self, x, adj, use_relu=True):
        x = self.gc1(x, adj)
        if use_relu:
            x = F.relu(x)
        x = F.dropout(x, self.dropout, training=self.training)
        x = self.gc2(x, adj)
        return x

class StackedGCN(torch.nn.Module):
    """
    Multi-layer GCN model.
    """
    def __init__(self, layers, dropout, input_channels, output_channels):
        """
        :input_channels: Number of features.
        :output_channels: Number of target features.
        """
        super(StackedGCN, self).__init__()
        self.layers_arg = layers
        self.dropout = dropout
        self.input_channels = input_channels
        self.output_channels = output_channels
        self.setup_layers()

    def setup_layers(self):
        self.layers = []
        self.layers_arg = [self.input_channels] + self.layers_arg + [self.output_channels]
        for i, _ in enumerate(self.layers_arg[:-1]):
            self.layers.append(GCNConv(self.layers_arg[i],self.layers_arg[i+1]))
        self.layers = ListModule(*self.layers)

    def forward(self, edges, features):
        """
        Making a forward pass.
        :param edges: Edge list LongTensor.
        :param features: Feature matrix input FLoatTensor.
        :return predictions: Prediction matrix output FLoatTensor.
        """
        for i, _ in enumerate(self.layers_arg[:-2]):
            features = torch.nn.functional.relu(self.layers[i](features, edges))
            if i>1:
                features = torch.nn.functional.dropout(features, p = self.dropout, training = self.training)
        features = self.layers[i+1](features, edges)
        predictions = torch.nn.functional.log_softmax(features, dim=1)
        return predictions

class ListModule(torch.nn.Module):
    """
    Abstract list layer class.
    """
    def __init__(self, *layers):
        """
        Module initializing.
        """
        super(ListModule, self).__init__()
        idx = 0
        for module in layers:
            self.add_module(str(idx), module)
            idx += 1

    def __getitem__(self, idx):
        """
        Getting the indexed layer.
        """
        if idx < 0 or idx >= len(self._modules):
            raise IndexError('index {} is out of range'.format(idx))
        it = iter(self._modules.values())
        for i in range(idx):
            next(it)
        return next(it)

    def __iter__(self):
        """
        Iterating on the layers.
        """
        return iter(self._modules.values())

    def __len__(self):
        """
        Number of layers.
        """
        return len(self._modules)

# def get_model(model_opt, nfeat, nclass, layers, dropout, device):
#     if model_opt == "GCN":
#         model = StackedGCN(layers, dropout, nfeat, nclass)
#     elif model_opt == "SGC":
#         model = SGC(nfeat=nfeat,
#                     nclass=nclass)
#     else:
#         raise NotImplementedError('model:{} is not implemented!'.format(model_opt))
#     return model


from datetime import date, timedelta

from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView

from meiduo_admin.serialziers.statistical import *
from users.models import User

class UserCountView(APIView):
    """
        用户总量统计
    """
    # 权限指定
    permission_classes = [IsAdminUser]

    def get(self, request):
        # 1. 获取当天时间
        now_date = date.today()
        # 2. 获取用户总量
        count = User.objects.all().count()
        # 3. 返回结果
        return Response({
            'date': now_date,
            'count': count
        })

class UserDayCountView(APIView):
    """
        日增用户统计
    """
    # 权限指定
    permission_classes = [IsAdminUser]

    def get(self, request):
        # 1. 获取当天时间
        now_date = date.today()
        # 2. 获取当天注册用户总量
        count = User.objects.filter(date_joined__gte=now_date).count()  # 这里会灵活取值
        # 3. 返回结果
        return Response({
            'date': now_date,
            'count': count
        })

class UserDayActivateView(APIView):
    """
        日增用户统计
    """
    # 权限指定
    permission_classes = [IsAdminUser]

    def get(self, request):
        # 1. 获取当天时间
        now_date = date.today()
        # 2. 获取当天注册用户总量
        count = User.objects.filter(last_login__gte=now_date).count()  # 这里会灵活取值
        # 3. 返回结果
        return Response({
            'date': now_date,
            'count': count
        })

class UserDayOrdersCountView(APIView):
    """
        当天下单用户统计
    """
    # 权限指定
    permission_classes = [IsAdminUser]

    def get(self, request):
        # 1. 获取当天时间
        now_date = date.today()
        # 2. 获取当天注册用户总量
        count = len(set(User.objects.filter(orders__create_time__gte=now_date)))  # 这里会灵活取值
        # 3. 返回结果
        return Response({
            'date': now_date,
            'count': count
        })

class UserMonthCountView(APIView):
    """
        月增用户统计
    """
    # 权限指定
    permission_classes = [IsAdminUser]

    def get(self, request):
        # 1. 获取当天时间
        now_date = date.today()
        # 2. 获取一个月之前的日期
        begin_date = now_date - timedelta(days=29)
        data_list = []
        for i in range(30):
            # 起始日期
            index_date = begin_date + timedelta(days=i)
            # 起始日期的下一天日期
            next_date = begin_date + timedelta(days=i + 1)
            count = User.objects.filter(date_joined__gte=index_date, date_joined__lt=next_date).count()
            data_list.append({
                'date': index_date,
                'count': count
            })
        # 3. 返回结果
        return Response(data_list)

class GoodsCountView(APIView):
    """
        日分类商品访问量
    """
    # 权限指定
    permission_classes = [IsAdminUser]

    def get(self, request):
        # 1. 获取当天时间
        now_date = date.today()
        # 2. 获取当天注册用户总量
        goods = GoodsVisitCount.objects.filter(date__gte=now_date)
        ser = GoodsCountSerializer(goods, many=True)
        # 3. 返回结果
        return Response(ser.data)


#by Bhuris Mun
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import time, json, math
from pymodbus.register_read_message import *

client = ModbusClient(method='rtu', port='/dev/ttyUSB0', timeout=0.3, baudrate=9600, stopbit=1, bytesize=8, parity='N')
client.connect()
#print(client.connect())

def main():
    value = client.read_input_registers(0, 10, unit=0x01) #read from unit 0x01
    #print(value.registers) #for prove test
    volt = value.registers[0]*0.1
    amp = value.registers[1]*0.001
    power = value.registers[3]*0.1
    energy = value.registers[5]*0.001
    freq = value.registers[7]*0.1
    pwfac = value.registers[8]*0.01
    alarm = value.registers[9]
    if alarm == 0x0000:
        alarmtran = 'NORMAL JA'
    elif alarm == 0xFFFF:
        alarmtran = 'ALARM'
    else:
        alarmtran = 'N/A'
    pwangle=math.acos(pwfac)
    apparent = power/math.cos(pwangle)
    reactive = apparent*math.sin(pwangle)
    impedance= apparent/(amp*amp)
    rinline = impedance*math.cos(pwangle)
    xinline = impedance*math.sin(pwangle)
    data={}
    data={
        "volt":volt,
        "amp":amp,
        "realpower":power,
        "energy":energy,
        "freq":freq,
        "pwfac":pwfac,
        "reactive":reactive,
        "apparent":apparent,
        "powerangle":pwangle,
        "impedance":impedance,
        "rinline":rinline,
        "xinline":xinline,
        "status":alarmtran
        }
    dataff=json.dumps(data) # format data to json
    print(dataff) # for stdout nodered


import csv
import random
import config
import utils
import rules
from rules import df_type
from rules import dm_type
from rules import conn_type
from rules import rec_def_type
from utils import ulogger as logger

import numpy as np

num_conn_types = len(conn_type)
num_rec_def_types = len(rec_def_type)

# this is not the right place for these functions. It is here because this module has the components it needs
def quality_of_el_set(glv_dict, els_set):
	vecs = []
	for name in els_set[2]:
		vecs.append(glv_dict[name])

	utils.get_avg_min_cd(vecs, len(vecs[0]))

def quality_of_els_sets(glv_dict, els_sets):
	# for ilen in range(5):
	# 	veclen = ilen * 100 + 4
	# 	vecs = [utils.vec_norm([random.uniform(-1.0, 1.0) for _ in range(veclen)]) for _ in range(20)]
	# 	utils.get_avg_min_cd(vecs, len(vecs[0]))
	#
	all_els = []
	for els_set in els_sets:
		quality_of_el_set(glv_dict, els_set)
		all_els += els_set[2][:5]

	vecs = []
	for name in all_els:
		vecs.append(glv_dict[name])

	utils.get_avg_min_cd(vecs, len(vecs[0]))

def create_actions_file():
	actions_fn = 'actions.txt'
	actions_fh = open(actions_fn, 'wb')
	actions_csvr = csv.writer(actions_fh, delimiter=',', quoting=csv.QUOTE_NONE)

	for action in config.actions:
		actions_csvr.writerow([str(action)])

	actions_fh.close()

# gels1 = []
# gels2 = []
# distinguishing between els and objects. The former is generic. The latter are things you pick up, take etc
def init_els(els_dict, els_arr, def_article, fname=None, alist=None, new_def_article=False, cap_first=False, max_new=5):
	num_els = len(els_arr)
	if fname:
		fh_names = open(fname, 'rb')
		fr_names = csv.reader(fh_names, delimiter=',')
		if cap_first:
			new_els = [lname[0].lower().title() for lname in fr_names]
		else:
			new_els = [lname[0].lower() for lname in fr_names]
		# fh_names.seek(0)
		# new_el_vecs = [[float(fs) for fs in glv_row[1:]] for glv_row in fr_names]

		if max_new < 0:
			max_new = len(new_els)

		# global gels1, gels2
		# if fname == 'objects.glv':
		# 	gels1 = new_el_vecs
		# elif fname == 'countries.glv':
		# 	gels2 = new_el_vecs

		shuffle_stick = range(len(new_els))
		random.shuffle(shuffle_stick)
		new_els = [new_els[i] for i in shuffle_stick]
		# new_el_vecs = [new_el_vecs[i] for i in shuffle_stick]
		new_els = new_els[0:min(max_new, len(new_els))]
		# new_el_vecs = new_el_vecs[0:min(max_new, len(new_els))]
		fh_names.close()
	else:
		new_els = alist

	els_arr += new_els
	for iel, el_name in enumerate(new_els):
		els_dict[el_name] = num_els + iel
		# glv_dict[el_name] = new_el_vecs[iel]
	def_article += [new_def_article for id in new_els]
	num_new_els = len(new_els)
	new_els_range = range(num_els, num_els+num_new_els)
	num_els += num_new_els
	return [new_els_range, num_new_els, new_els], num_els

def init_glv(fnames, cap_first_arr, def_article_arr, cascade_els_arr):
	# fnames = ['names.glv', 'objects.glv', 'countries.glv', 'actions.glv']
	# cap_first_arr = [True, False, True, False]
	# def_article_arr = [False, True, False, False]
	glv_dict = {}
	new_el_vecs = []
	new_els = []
	def_article_dict = {}
	cascade_dict = {}

	# return [new_els_range, num_new_els, new_els], num_els
	num_els = 0
	els_sets = []

	for ifname, fname in enumerate(fnames):
		fh_names = open(fname, 'rb')
		fr_names = csv.reader(fh_names, delimiter=',')
		if cap_first_arr[ifname]:
			all_names = [lname[0].lower().title() for lname in fr_names]
		else:
			all_names = [lname[0].lower() for lname in fr_names]
		num_new_els = len(all_names)
		# new_els_range = range(num_els, num_els + num_new_els)
		# num_els += num_new_els
		# els_sets.append([new_els_range, num_new_els, new_els])
		els_sets.append(all_names)

		new_els += all_names
		for name in all_names:
			def_article_dict[name] = def_article_arr[ifname]
			cascade_dict[name] = cascade_els_arr[ifname]

		fh_names.seek(0)
		new_el_vecs += [[float(fs) for fs in glv_row[1:]] for glv_row in fr_names]
		fh_names.close()

	for iitem, item in enumerate(new_el_vecs):
		glv_dict[new_els[iitem]] = item

	return glv_dict, def_article_dict, cascade_dict, els_sets

def init_objects():
	els_arr = []
	els_dict = {}
	def_article = []
	glv_dict = {}
	# name_ids, num_els, num_names, names = \
	name_set, num_els = \
		init_els(	fname='names.glv', cap_first=True, max_new=config.max_names,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)
	# object_ids, num_els, num_objects, objects = \
	object_set, num_els = \
		init_els(	fname='objects.glv', new_def_article=True, max_new=config.max_objects,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)
	place_set, num_els =\
		init_els(	fname='countries.glv', cap_first=True, max_new=config.max_countries,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)

	action_set, num_els =\
		init_els(	fname='actions.glv', max_new=-1,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)

	# utils.get_avg_min_cd(gels1+gels2, len(gels1[0]))

	els_sets = utils.nt_el_sets(names=name_set, objects=object_set, places=place_set, actions=action_set)
	# return els_arr, els_dict, def_article, num_els, name_set, object_set, place_set, action_set
	return els_arr, els_dict, def_article, num_els, els_sets

def init_ext_objects():
	els_arr = []
	els_dict = {}
	def_article = []
	glv_dict = {}
	# name_ids, num_els, num_names, names = \
	name_set, num_els = \
		init_els(	fname='names.glv', cap_first=True, max_new=config.max_names,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)
	# object_ids, num_els, num_objects, objects = \
	object_set, num_els = \
		init_els(	fname='objects.glv', new_def_article=True, max_new=config.max_objects,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)
	place_set, num_els =\
		init_els(	fname='countries.glv', cap_first=True, max_new=config.max_countries,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)

	action_set, num_els =\
		init_els(	fname='actions.glv', max_new=-1,
					els_dict=els_dict, els_arr=els_arr, def_article=def_article)

	# utils.get_avg_min_cd(gels1+gels2, len(gels1[0]))

	els_sets = utils.nt_el_sets(names=name_set, objects=object_set, places=place_set, actions=action_set)
	# return els_arr, els_dict, def_article, num_els, name_set, object_set, place_set, action_set
	return els_arr, els_dict, def_article, num_els, els_sets

def convert_list_to_phrases(statement_list):
	return [[[rec_def_type.obj, item] for item in statement] for statement in statement_list]

def convert_phrase_to_word_list(statement_list):
	return [[el[1] for el in statement] for statement in statement_list]

def make_obj_el_from_str(sobj):
	return [rec_def_type.obj, sobj]

def make_rec_list(phrase_list):
	return [rules.C_phrase_rec(phrase) for phrase in phrase_list]

def output_phrase(def_article_dict, out_str, phrase):
	b_first = True
	for iel, el in enumerate(phrase):
		if el[0] == rec_def_type.error:
			out_str += '<Error!> '
			# return out_str
		else:
			if len(el) > 2 and el[2]:
				out_str += '{search for: '
			if el[0] == rec_def_type.obj and def_article_dict.get(el[1], False):
				if b_first:
					out_str += 'The '
					b_first = False
				else:
					out_str += 'the '
			if b_first:
				out_str += el[1][:1].upper() + el[1][1:]
				b_first = False
			else:
				out_str += el[1]
			if len(el) > 2 and el[2]:
				out_str += '}'
			out_str += ' '

	return out_str

def complete_phrase(src_phrase,
					out_phrase,
					out_str, el_set_arr = None, glv_dict = None):
	filled_phrase = []
	for el in out_phrase:
		if el[0] == rec_def_type.conn:
			if el[1] == conn_type.AND:
				filled_phrase.append([el[0], 'AND'])
			elif el[1] == conn_type.OR:
				filled_phrase.append([el[0], 'OR'])
			elif el[1] == conn_type.start:
				filled_phrase.append([el[0], '('])
			elif el[1] == conn_type.end:
				filled_phrase.append([el[0], ')'])
			elif el[1] == conn_type.Modify:
				out_str = 'Modify: '
			elif el[1] == conn_type.Insert:
				out_str = 'Insert: '
			elif el[1] == conn_type.Remove:
				out_str = 'Remove: '
		elif el[0] == rec_def_type.var:
			# filled_phrase.append((src_phrase.phrase())[el[1]])
			filled_phrase.append([el[0], '{var:' + str(el[1]) + '}'])
			if len(el) > 2:
				filled_phrase[-1].append(el[2])
		elif el[0] == rec_def_type.obj:
			filled_phrase.append(el)
		elif el[0] == rec_def_type.set:
			# glv_dict must be passed as an actual value here and not default param
			# if you get an assert here, that is the reason why
			set_vec, set_cd, _ = el_set_arr[el[1]]
			best_cd = -1.0
			best_name = 'not found!'
			for sym, one_vec in glv_dict.iteritems():
				cd = sum([one_vec[i] * set_val for i, set_val in enumerate(set_vec)])
				if cd > best_cd:
					best_name, best_cd = sym, cd
			filled_phrase.append([el[0], '{set#' + str(len(filled_phrase)) + ':' + best_name + '-like (' + str(set_cd) + ')}'])
		elif el[0] == rec_def_type.like:
			filled_phrase.append([el[0], '{like#' + str(len(filled_phrase)) + ':' + el[1] + ' (' + str(el[2]) + ')}'])

	return filled_phrase, out_str

def print_phrase(src_phrase, out_phrase, out_str, def_article_dict, el_set_arr = None, glv_dict = None):

	filled_phrase, out_str = complete_phrase(src_phrase, out_phrase, out_str, el_set_arr, glv_dict)
	return output_phrase(def_article_dict, out_str, filled_phrase)

# This function may be one useful but it does no add starts, end and AND
def build_vars_dict(phrase_list):
	new_phrase_list, vars_dict = [], dict()
	for iel, el in enumerate(phrase_list):
		if el[0] == rec_def_type.var:
			print('Error! Assuming the input phrase list contains no vars. Exiting!')
			exit()
		if el[0] != rec_def_type.obj:
			new_phrase_list.append(el)
			continue
		word = el[1]
		idx = vars_dict.get(word, None)
		if idx == None:
			# new_phrase_list.append([rec_def_type.var, len(vars_dict)])
			new_phrase_list.append(el)
			vars_dict[word] = iel
		else:
			new_phrase_list.append([rec_def_type.var, idx])

	return new_phrase_list, vars_dict

def replace_with_vars_in_wlist(l_wlist_src, l_phrase_result):
	vars_dict, l_wlist_vars, l_wlist_lens = dict(), [], []
	for iwlist, wlist in enumerate(l_wlist_src):
		for iel, el in enumerate(wlist):
			iwlist_src, pos_src = vars_dict.get(el, (-1, -1))
			if iwlist_src == -1:
				vars_dict[el] = (iwlist, iel)
			else:
				l_wlist_vars.append((iwlist_src, pos_src, iwlist, iel))
		if iwlist == 0:
			l_wlist_lens.append(len(wlist))
		else:
			l_wlist_lens.append(l_wlist_lens[-1] + len(wlist))

	if l_phrase_result == []:
		return l_wlist_vars, []

	phrase_result = l_phrase_result[0]
	new_result = []
	for ielr, elr in enumerate(phrase_result):
		if elr[0] != rec_def_type.obj:
			new_result.append(elr)
			continue
		word = elr[1]
		iwlist_src, pos_src = vars_dict.get(word, (-1, -1))
		if iwlist_src == -1:
			# new_phrase_list.append([rec_def_type.var, len(vars_dict)])
			new_result.append(elr)
			vars_dict[word] = (len(l_wlist_src), ielr)
		else:
			if iwlist_src == 0:
				dest_pos = pos_src
			else:
				dest_pos = l_wlist_lens[iwlist_src-1] + pos_src
			new_result.append([rec_def_type.var, dest_pos])

	return l_wlist_vars, new_result

def make_vec(recs, glv_dict):
	# numrecs = len(recs)
	# num_els = len(els_dict)

	for irec, rec in enumerate(recs):
		for ifld, fld in enumerate(rec.phrase()):
			subvec0 = np.zeros(num_rec_def_types)
			subvec0[fld[0].value - 1] = 1
			if fld[0] == rec_def_type.conn:
				subvec1 = np.zeros(num_conn_types)
				subvec1[fld[1].value - 1] = 1
			elif fld[0]  == rec_def_type.obj:
				# subvec1 = np.zeros(num_els)
				# subvec1[els_dict[fld[1]]] = 1
				subvec1 = np.asarray(glv_dict[fld[1]])
			elif fld[0] == rec_def_type.var:
				subvec1 = np.zeros(config.c_max_vars)
				if fld[1] >= config.c_max_vars:
					print('More vars in the rule than we planned for. Exiting!')
					exit()
				subvec1[fld[1]] = 1

			subvec = np.concatenate((subvec0, subvec1), axis=0)

			if ifld == 0:
				vec = subvec
			else:
				vec = np.concatenate((vec, subvec), axis=0)

		if irec == 0:
			vecs = vec
		else:
			vecs = np.vstack((vecs, vec))

	if irec == 0: # i.e. there was only one record
		vecs = np.expand_dims(vecs, axis=0) # we need the putput to be consistent with multiple record outputs

	return vecs

def make_vec_old(recs, els_dict):
	# numrecs = len(recs)
	num_els = len(els_dict)

	for irec, rec in enumerate(recs):
		for ifld, fld in enumerate(rec.phrase()):
			subvec0 = np.zeros(num_rec_def_types)
			subvec0[fld[0].value - 1] = 1
			if fld[0] == rec_def_type.conn:
				subvec1 = np.zeros(num_conn_types)
				subvec1[fld[1].value - 1] = 1
			elif fld[0]  == rec_def_type.obj:
				subvec1 = np.zeros(num_els)
				subvec1[els_dict[fld[1]]] = 1
			elif fld[0] == rec_def_type.var:
				subvec1 = np.zeros(config.c_max_vars)
				subvec1[fld[1]] = 1

			subvec = np.concatenate((subvec0, subvec1), axis=0)

			if ifld == 0:
				vec = subvec
			else:
				vec = np.concatenate((vec, subvec), axis=0)

		if irec == 0:
			vecs = vec
		else:
			vecs = np.vstack((vecs, vec))

	if irec == 0: # i.e. there was only one record
		vecs = np.expand_dims(vecs, axis=0) # we need the putput to be consistent with multiple record outputs

	return vecs

def pad_ovec(vecs):
	numrecs = vecs.shape[0]
	pad_len = config.c_ovec_len - vecs.shape[1]
	vecs = np.concatenate((vecs, np.zeros((numrecs, pad_len), dtype=np.int32,)), axis=1)

	return vecs

def match_rec_to_templ(rec, template):
	for i, v in enumerate(template):
		if v == '?':
			continue
		if rec[i][0] != rules.rec_def_type.obj:
			return False
		if rec[i][1] != v:
			return False
	return True


import pandas as pd

import numpy as np

import seaborn as sns

import matplotlib.pyplot as plt
train = pd.read_csv("../input/widsdatathon2020/training_v2.csv")

test = pd.read_csv("../input/widsdatathon2020/unlabeled.csv")
train.shape, test.shape
train.head()
test.head()
train.describe()
test.describe()
train.isnull().sum()/len(train)*100
f,ax=plt.subplots(1,2,figsize=(18,8))

train['hospital_death'].value_counts().plot.pie(explode=[0,0.1],autopct='%1.1f%%',ax=ax[0],shadow=True)

ax[0].set_title('hospital_death')

ax[0].set_ylabel('')

sns.countplot('hospital_death',data=train,ax=ax[1])

ax[1].set_title('hospital_death')

plt.show()
train.drop("readmission_status",inplace=True,axis=1)

test.drop("readmission_status",inplace=True,axis=1)
test.drop("hospital_death",inplace=True,axis=1)

y_train = train[['encounter_id', 'patient_id', 'hospital_id',"hospital_death"]].copy()

train.drop("hospital_death",inplace=True,axis=1)
non_categorical = train.loc[:,train.dtypes!="object"].columns
categorical = [c for c in train[non_categorical].columns if (train[c].nunique()<10)]

non_categorical = [c for c in train[non_categorical].columns if (train[c].nunique()>=10)]
print(train[non_categorical].isnull().sum()/len(train))

a = train[non_categorical].isnull().sum()/len(train)>0.40 ## editable

missing_m40 = train[non_categorical].loc[:,a].columns

a = train[non_categorical].isnull().sum()/len(train)<=0.40 ## editable

missing_l40 = train[non_categorical].loc[:,a].columns

del a
a = train.isnull().sum()/len(train)!= 0 ## editable

missing = train.loc[:,a].columns

del a

for i in missing:

    train[str(i)+"_Na"]=pd.get_dummies(train[i].isnull(),prefix=i).iloc[:,0]

    test[str(i)+"_Na"]=pd.get_dummies(test[i].isnull(),prefix=i).iloc[:,0]

for i in missing_l40:

    for j in train.hospital_id.unique():

        train[i][train.hospital_id==j]=train[i][train.hospital_id==j].fillna(train[i][train.hospital_id==j].median())

    for k in test.hospital_id.unique():

        test[i][test.hospital_id==k]=test[i][test.hospital_id==k].fillna(test[i][test.hospital_id==k].median())
train["apache_4a_hospital_death_prob"]=train["apache_4a_hospital_death_prob"].replace({-1:np.nan})

test["apache_4a_hospital_death_prob"]=test["apache_4a_hospital_death_prob"].replace({-1:np.nan})

train["apache_4a_icu_death_prob"]=train["apache_4a_icu_death_prob"].replace({-1:np.nan})

test["apache_4a_icu_death_prob"]=test["apache_4a_icu_death_prob"].replace({-1:np.nan})
a = train[non_categorical].isnull().sum()/len(train)<=0.40 ## editable

missing_l40 = train[non_categorical].loc[:,a].columns

for i in missing_l40:

    train[i] = train[i].fillna(train[i].median())

a = test[non_categorical].isnull().sum()/len(test)<=0.40 ## editable

missing_l40 = test[non_categorical].loc[:,a].columns

for i in missing_l40:

    test[i] = test[i].fillna(train[i].median())

del a, missing_l40, missing_m40
categorical=np.concatenate([train.loc[:,train.dtypes=="object"].columns.tolist(),categorical])
train[categorical].isnull().sum()/len(train)
test[categorical].isnull().sum()/len(test)
train[categorical].nunique()
## imputador gender

train["gender"][train.height>167]=train["gender"][train.height>167].fillna("M")

train["gender"][train.height<=167]=train["gender"][train.height<=167].fillna("F")
for i in categorical:

    train[i] = train[i].fillna(train[i].value_counts().index[0])

    test[i] = test[i].fillna(train[i].value_counts().index[0])
categorical = train.loc[:,train.dtypes=="object"].columns.tolist()
train[categorical].nunique()
train["hospital_admit_source"]=train["hospital_admit_source"].replace({'Other ICU':"ICU",'ICU to SDU':"SDU",

                                       'Step-Down Unit (SDU)':"SDU",

                                      'Acute Care/Floor':"Floor",

                                      'Other Hospital':"Other"})

test["hospital_admit_source"]=test["hospital_admit_source"].replace({'Other ICU':"ICU",'ICU to SDU':"SDU",

                                       'Step-Down Unit (SDU)':"SDU",

                                      'Acute Care/Floor':"Floor",

                                      'Other Hospital':"Other"})

train["apache_2_bodysystem"] = train["apache_2_bodysystem"].replace({'Undefined Diagnoses':"UD",

                                                                    'Undefined diagnoses':"UD"})

test["apache_2_bodysystem"] = test["apache_2_bodysystem"].replace({'Undefined Diagnoses':"UD",

                                                                    'Undefined diagnoses':"UD"})
train = train.join(pd.get_dummies(train[categorical]).drop("gender_F",axis=1))

test = test.join(pd.get_dummies(test[categorical]).drop("gender_F",axis=1))

train.drop(categorical,axis=1,inplace=True)

test.drop(categorical,axis=1,inplace=True)
non = ['encounter_id', 'patient_id', 'hospital_id','icu_id']
correlated_features = set()

train1 = train.drop(non,axis=1)

correlation_matrix = train1.corr()

del train1
for i in range(len(correlation_matrix.columns)):

     for j in range(i):

            if abs(correlation_matrix.iloc[i, j]) ==  1:

                colname = correlation_matrix.columns[i]

                correlated_features.add(colname)

correlated_features=list(correlated_features)
train.drop(correlated_features,axis=1,inplace=True)

test.drop(correlated_features,axis=1,inplace=True)
train.shape, test.shape
train.drop("hospital_admit_source_Observation",axis=1,inplace=True)
train = train.set_index("encounter_id")

test = test.set_index("encounter_id")

y_train = y_train.set_index("encounter_id")
test = test.fillna(0)
from lightgbm import LGBMClassifier

from sklearn.model_selection import StratifiedKFold, GroupKFold

drop_cols = ['patient_id', 'hospital_id','icu_id']

#drop_cols = np.concatenate([drop_cols,perdidos])

gf = GroupKFold(n_splits=4)

groups = np.array(train.hospital_id)

test_probs = []

train_probs = []

for i,(a,b) in enumerate(gf.split(train,y_train.loc[train.index, "hospital_death"],groups)) :

    Xt = train.iloc[a,:]

    yt = y_train.loc[Xt.index, "hospital_death"]

    Xt = Xt.drop(drop_cols, axis=1)

    Xt = Xt.fillna(0)

    Xv = train.iloc[b,:]

    yv = y_train.loc[Xv.index, "hospital_death"]

    Xv = Xv.drop(drop_cols, axis=1)

    Xv = Xv.fillna(0)

    print("*+*+*+*+*entrenando fold: {} ".format(i+1))

    learner = LGBMClassifier(n_estimators=10,learning_rate=0.03,num_iterations=3400,lambda_l2=7 ,lambda_l1 =7

                                 ,num_leaves =7,max_depth=5,min_data_in_leaf =500,early_stopping_rounds=200,feature_fraction= 0.8

                            ,bagging_fraction=0.85,bagging_freq=10)

    learner.fit(Xt, yt  , eval_metric="auc",eval_set= [(Xt, yt),(Xv, yv)], verbose=50)

    train_probs.append(pd.Series(learner.predict_proba(Xv)[:, -1],

                                index=Xv.index, name="probs"+ str(i)))

    test_probs.append(pd.Series(learner.predict_proba(test.drop(drop_cols, axis=1))[:, -1],

                                index=test.index, name="fold_" + str(i)  ))

test_probs = pd.concat(test_probs, axis=1).mean(axis=1)

train_probs = pd.concat(train_probs, axis=1)
test_probs = pd.DataFrame(test_probs.rename("hospital_death"))

test_probs.to_csv("lightgbm_baseline.csv", header=True)


import logging

from django.utils import timezone

from dojo.models import Finding, Risk_Acceptance
from .importer import SonarQubeApiImporter
import dojo.risk_acceptance.helper as ra_helper

logger = logging.getLogger(__name__)

class SonarQubeApiUpdaterFromSource(object):
    """
    The responsibility of this class is to update the Finding status if current SonarQube issue status doesn't match.

    This way, findings will be updated based on SonarQube information when SonarQube is updated manually and
    already imported in DefectDojo.
    """

    @staticmethod
    def get_findings_to_update():
        return Finding.objects.filter(
            sonarqube_issue__isnull=False,
            active=True,
        ).select_related("sonarqube_issue")

    def update(self, finding):
        sonarqube_issue = finding.sonarqube_issue
        if not sonarqube_issue:
            return

        client, _ = SonarQubeApiImporter.prepare_client(finding.test)
        # we don't care about config, each finding knows which config was used
        # during import

        issue = client.get_issue(sonarqube_issue.key)
        if (
            issue
        ):  # Issue could have disappeared in SQ because a previous scan has resolved the issue as fixed
            current_status = issue.get("resolution") or issue.get("status")
            current_finding_status = self.get_sonarqube_status_for(finding)
            logger.debug(
                "--> SQ Current status: {}. Finding status: {}".format(
                    current_status, current_finding_status
                )
            )

            if (
                current_status != "OPEN"
                and current_finding_status != current_status
            ):
                logger.info(
                    "Original SonarQube issue '{}' has changed. Updating DefectDojo finding '{}'...".format(
                        sonarqube_issue, finding
                    )
                )
                self.update_finding_status(finding, current_status)

    @staticmethod
    def get_sonarqube_status_for(finding):
        target_status = None
        if finding.false_p:
            target_status = "FALSE-POSITIVE"
        elif finding.mitigated or finding.is_mitigated:
            target_status = "FIXED"
        elif finding.risk_accepted:
            target_status = "WONTFIX"
        elif finding.active:
            if finding.verified:
                target_status = "CONFIRMED"
            else:
                target_status = "REOPENED"
        return target_status

    @staticmethod
    def update_finding_status(finding, sonarqube_status):
        if sonarqube_status in ["OPEN", "REOPENED"]:
            finding.active = True
            finding.verified = False
            finding.false_p = False
            finding.mitigated = None
            finding.is_mitigated = False
            ra_helper.remove_finding.from_any_risk_acceptance(finding)

        elif sonarqube_status == "CONFIRMED":
            finding.active = True
            finding.verified = True
            finding.false_p = False
            finding.mitigated = None
            finding.is_mitigated = False
            ra_helper.remove_finding.from_any_risk_acceptance(finding)

        elif sonarqube_status == "FIXED":
            finding.active = False
            finding.verified = True
            finding.false_p = False
            finding.mitigated = timezone.now()
            finding.is_mitigated = True
            ra_helper.remove_finding.from_any_risk_acceptance(finding)

        elif sonarqube_status == "WONTFIX":
            finding.active = False
            finding.verified = True
            finding.false_p = False
            finding.mitigated = None
            finding.is_mitigated = False
            Risk_Acceptance.objects.create(
                owner=finding.reporter,
            ).accepted_findings.set([finding])

        elif sonarqube_status == "FALSE-POSITIVE":
            finding.active = False
            finding.verified = False
            finding.false_p = True
            finding.mitigated = None
            finding.is_mitigated = False
            ra_helper.remove_finding.from_any_risk_acceptance(finding)

        finding.save(issue_updater_option=False, dedupe_option=False)


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

import os
import collections
from logging import info
from util.global_def import DIR_DELIM

def get_temp_dir():
    import tempfile
    return tempfile.gettempdir()

TMP_DIR = "%(tmp_dir)s%(delim)s" % {'tmp_dir': get_temp_dir(), 'delim': DIR_DELIM}

DEFAULT_NAME = "BUFFY"

def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as exc:
        import errno
        if exc.errno != errno.EEXIST or not os.path.isdir(path):
            raise

def disk_write(filename, content, dry_run=False):
    if dry_run:
        return
    dirname, _ = os.path.split(filename)
    if not os.path.exists(dirname):
        mkdir_p(dirname)
    with open(filename, 'w') as fd:
        fd.write(content)

class MediaBase(object):
    def __init__(self, media_name, dst_root, setting, args):
        self.media_name = media_name
        self._dst_root = dst_root
        self.root = setting.src.root
        self.name = setting.name
        self.compress = setting.compress
        self.encoding_str = MediaBase.get_encoding(setting.encoding)
        self.dry = args.dry
        self.report_path = setting.rpt.path
        self.detail_report = setting.rpt.detail

    def exist(self):
        return False

    def create_path(self):
        info("[media] '%s' not support create path: %s" % (self.media_name, self._dst_root))

    def report(self, basename, content):
        if not self.report_path or not self.detail_report:
            return
        disk_write(self.report_path + basename, content, self.dry)

    def backup_compress(self, sources):
        is_disk = "disk" == self.media_name
        backup_name = self.encoding_str if not self.name else \
            self.name + ("_" + self.encoding_str if len(self.encoding_str) > 0 else "")
        if "" == backup_name:
            backup_name = DEFAULT_NAME
        dst_base = self._dst_root + backup_name
        non_disk_dst_base = (self.report_path if self.report_path else TMP_DIR) + backup_name
        tar_input_file = non_disk_dst_base + ".list"
        targz_file = "%s.tar.gz" % (dst_base if is_disk else non_disk_dst_base)
        if not self.dry:
            os.chdir(self.root)
            import tarfile
            with tarfile.open("%s" % targz_file, "w|gz") as tar:
                for src in sources:
                    tar.add(src.replace(self.root, ""))
            if self.detail_report:
                src_list_content = ""
                for src in sources:
                    src_list_content += (src.replace(self.root, "") + "\n")
                disk_write(tar_input_file, src_list_content, self.dry)
        if not is_disk:
            self.copyfile(targz_file, "%s.tar.gz" % dst_base)
            if not self.dry:
                os.remove(targz_file)
        compress_cmd = "tar zcvf %(dst)s -T %(src_list)s" % {'dst': targz_file, 'src_list': tar_input_file}
        reproduce_str = "cd %s\n%s\n" % (self.root, compress_cmd) + \
                        ("" if is_disk else "%s%s %s\n" % (self.cp_cmd, targz_file, "%s.tar.gz" % dst_base))
        size, timestamp = self.get_file_info_not_dry("%s.tar.gz" % dst_base)
        reproduce_file = backup_name + "_" + self.media_name + ".cmd"
        return "%s.tar.gz, size: %i, timestamp: %s" % (backup_name, size, timestamp), \
               reproduce_file, reproduce_str

    def backup_uncompress(self, sources, delim):
        backup_map = collections.OrderedDict()
        backup_name = self.encoding_str if not self.name else \
            self.name + ("_" + self.encoding_str if len(self.encoding_str) > 0 else "")
        dst_base = self._dst_root + backup_name + (delim if len(backup_name) > 0 else "")
        backuped_count = 0
        backuped_size = 0
        for src in sources:
            dirname, _ = os.path.split(src)
            dst_dir = (dirname + delim).replace(self.root, '')
            dst = dst_base + dst_dir + os.path.basename(src)
            backup_map[src] = dst
            assert not os.path.isdir(src)
            backuped, size = self.copyfile(src, dst)
            backuped_count += backuped
            backuped_size += size
        reproduce_file = (DEFAULT_NAME if "" == backup_name else backup_name) + "_" + self.media_name + ".cmd"
        return "file count: %i, size: %i" % (backuped_count, backuped_size), \
               reproduce_file, self.get_reproduce_str(backup_map)

    def back_up(self, sources):
        info("[%s] back up to dst: %s" % (self.media_name, self._dst_root))
        backup_ftor = self.backup_compress if self.compress else self.backup_uncompress
        backup_report, reproduce_file, reproduce_str = backup_ftor(sources)
        reproduce_str_max_length = 1024 * 1024  # 1MB
        if len(reproduce_str) > reproduce_str_max_length:
            message = "skip dump subsequent content for the total size (%s) is too large" % len(reproduce_str)
            info("[info] %s" % message)
            reproduce_str = reproduce_str[:reproduce_str_max_length] + "\n...\n" + message
        self.report(reproduce_file, reproduce_str)
        return backup_report

    @staticmethod
    def get_encoding(enable):
        if not enable:
            return ""
        from datetime import date
        return str(date.today()).replace("-", "")

    def get_reproduce_str(self, mapping):
        reproduce_str = "cd %s\n" % self.root
        for src_to_dst in mapping:
            reproduce_str += (self.cp_cmd + src_to_dst.replace(self.root, "") + " " + mapping[src_to_dst] + "\n")
        return reproduce_str


#!/usr/bin/python
# coding=utf-8
import requests
import unittest
import json
from common.public import *
import time
import random

class ICEM_MA_Interface(unittest.TestCase):

    @classmethod
    def setUpClass(self):
        self.headers = headers
        self.host = host
        self.path = "/api/icem-resource/coupon/add"
        self.random = random.randint(1000,99999)
        # self.temp = int(time.time())
        self.couponName = "自动化"+str(self.random)
        print("----------开始测试----------")

    #创建优惠券接口
    def test_createCoupon(self):
        self.url = self.host + self.path
        data = {
	"couponName": self.couponName,
	"overdueType": 2,
	"couponType": 2,
	"afterReceive": 0,
	"effective": 90,
	"couponCount": 100,
	"limitNumber": 1,
	"benefitStr": 10,
	"benefit": {
		"threshold": 90,
		"benefit": 10
	},
	"limitOfGoods": [100043, 100044],
	"limitOfShops": [100001, 100002],
	"storeName": "自动化商户",
	"storeLogo": "release/1000/storeLogo/2ba1bba07be6407781a97f127b52eb41.png",
	"cover": "release/1000/couponCover/c483256a755a4ea3aad62eb956460898.png",
	"notice": "使用须知",
	"discountExplain": "优惠说明",
	"customerServiceTel": "5522322",
	"images": [{
		"showUrl": "http://geek-icem.oss-cn-beijing.aliyuncs.com/release/1000/couponDetail/c329f2eaf54a480499761c7efc3fe4d9.jpg",
		"url": "release/1000/couponDetail/c329f2eaf54a480499761c7efc3fe4d9.jpg"
	}]
}
        print(self.url)
        response = requests.post(url=self.url,data= json.dumps(data), headers=self.headers)
        print (response.text)
        assert response.json()['error'] == 0

    def tearDown(self):
        pass

if __name__ == "__main__":
    sms = ICEM_MA_Interface()


from flask import Flask, redirect, url_for, request
app = Flask(__name__)

@app.route('/hello/<stdName>')
def hello(stdName):
    return 'Welcome %s!' %stdName
# login.html의 http://localhost:5000/login 은 login 함수로 mapping 됨
@app.route('/login', methods = ['POST', 'GET'])
def login():
    if request.method == 'POST':
        student = request.form['nm'] # form data에서 얻은 'nm' 매개변수 값을 student에 저장
        return redirect(url_for('hello', stdName = student)) # 변수 student는 '/hello' URL에 전달된다.
    else:
        student = request.args.get('nm') #args: form 매개변수 쌍과 해당 값의 목록을 포함하는 dictionary object
        return redirect(url_for('hello', stdName = student)) # 'nm' 매개변수에 해당하는 값은 '/hello' URL로 전달된다.

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

'''
<Form> 태그 : client에서 server로 데이터 전송하기 위한 방법😊
1. 기본구조
    - method 속성과 action 속성을 가짐
    - method 속성 : 데이터를 넘겨주는 방식 설정, post와 get 방식
    - action 속성 : 클라이언트로부터 전송된 데이터들을 처리할 ASP 문서 지정
    <form method="post" action="process.asp">
    (데이터 입력 양식들)
    </form>
2. 글 입력 상자(text input box)
    - name  속성 : 클라이언트 -> 서버 로 전송되었을 때, 서버측에서 사용할 변수 이름에 해당
3. Request와 Response 객체
    - 웹서비스는 HTTP 서비스 프로토콜을 통해 클라이언트와 서버가 통신을 한다.
    - 웹 서버는 클라이언트가 http를 통해 전송해온 요청을 받아 Request에 저장한다.
    - <form>..</form>을 통해 클라이언트에서 서버로 넘겨진 데이터는 request 객체 내에 저장이 되고, 서버는 request객체를 검색하여 해당 데이터 처리를 한다.
4. Request 객체
    - Form : 클라이언트가 전송한 Form 요소 값
5. HTTP 통신의 메시지 형식
    - 클라이언트에서 서버로 데이터 보낼 때, <form> 태그를 이용해 보냄
    - 이때, method="post"일 때와 method="get"일 때 통신 방법이 다름
    - method="get" : 입력 데이터들이 URL 뒤에 QueryString으로 추가되어 전송됨
    - method="post" : 입력 데이터들이 HTTP 메시지의 데이터 부분에 첨부되어 전송됨

출처 : https://m.blog.naver.com/PostView.nhn?blogId=starcast&logNo=60007341828&proxyReferer=https:%2F%2Fwww.google.com%2F
'''


"Runs the shocktube test problem with the Fortran Roe solver."

def test_shocktube():
    "Shock tube test (1D MHD with Roe solver)"
    import numpy as np
    import os
    from . import shocktube
    from clawpack.riemann.mhd_1D_constants import B_2, B_3

    claw = shocktube.setup(kernel_language='Fortran')
    claw.run()
    roe = claw.solution.state.get_q_global()

    if roe is not None:
        thisdir = os.path.dirname(__file__)
        expected_B2 = np.loadtxt(os.path.join(thisdir, 'shocktube_regression_B2.txt'))
        expected_B3 = np.loadtxt(os.path.join(thisdir, 'shocktube_regression_B3.txt'))
        test_B2 = roe[B_2, :]
        test_B3 = roe[B_3, :]
        test_err = np.linalg.norm(expected_B2 - test_B2) + np.linalg.norm(expected_B3 - test_B3)
        assert test_err < 1.e-4

if __name__=="__main__":
    import nose
    nose.main()


import random
import re
from sys import get_coroutine_origin_tracking_depth
from sys import exit
random.seed(101)
import matplotlib.pyplot as plt
import math
import matplotlib.patches as mpatches
#from scipy.linalg import svd
import itertools
import torch
import time
import numpy as np
from tqdm import tqdm
from evaluator import ProxyEvaluator
import collections
import os
from data import Data
from parse import parse_args
# need change 1
from model import CausE, IPS, LGN, MACR, INFONCE, INFONCE_linear, AdvInfoNCE, SAMREG, BC_LOSS, SimpleX, SGL, NCL, XSimGCL, PID, NBC_LOSS
from torch.utils.data import Dataset, DataLoader
from collect_log import read_log
import torch.nn.functional as F

def merge_user_list(user_lists):
    out = collections.defaultdict(list)
    # Loop over each user list
    for user_list in user_lists:
        # Loop over each user in the user list
        for key, item in user_list.items():
            out[key] = out[key] + item
    return out

def merge_user_list_no_dup(user_lists):
    out = collections.defaultdict(list)
    for user_list in user_lists:
        for key, item in user_list.items():
            out[key] = out[key] + item

    for key in out.keys():
        out[key]=list(set(out[key]))
    return out

def save_checkpoint(model, epoch, checkpoint_dir, buffer, max_to_keep=10):
    state = {
        'epoch': epoch,
        'state_dict': model.state_dict(),
    }

    filename = os.path.join(checkpoint_dir, 'epoch={}.checkpoint.pth.tar'.format(epoch))
    torch.save(state, filename)
    buffer.append(filename)
    if len(buffer)>max_to_keep:
        os.remove(buffer[0])
        del(buffer[0])

    return buffer

def restore_checkpoint(model, checkpoint_dir, device, force=False, pretrain=False):
    """
    If a checkpoint exists, restores the PyTorch model from the checkpoint.
    Returns the model and the current epoch.
    """
    cp_files = [file_ for file_ in os.listdir(checkpoint_dir)
                if file_.startswith('epoch=') and file_.endswith('.checkpoint.pth.tar')]

    if not cp_files:
        print('No saved model parameters found')
        if force:
            raise Exception("Checkpoint not found")
        else:
            return model, 0,

    epoch_list = []

    regex = re.compile(r'\d+')

    for cp in cp_files:
        epoch_list.append([int(x) for x in regex.findall(cp)][0])

    epoch = max(epoch_list)

    if not force:
        print("Which epoch to load from? Choose in range [0, {})."
              .format(epoch), "Enter 0 to train from scratch.")
        print(">> ", end = '')
        # inp_epoch = int(input())
        inp_epoch = epoch
        if inp_epoch not in range(epoch + 1):
            raise Exception("Invalid epoch number")
        if inp_epoch == 0:
            print("Checkpoint not loaded")
            clear_checkpoint(checkpoint_dir)
            return model, 0,
    else:
        print("Which epoch to load from? Choose in range [0, {}).".format(epoch))
        inp_epoch = int(input())
        if inp_epoch not in range(0, epoch):
            raise Exception("Invalid epoch number")

    filename = os.path.join(checkpoint_dir,
                            'epoch={}.checkpoint.pth.tar'.format(inp_epoch))

    print("Loading from checkpoint {}?".format(filename))

    checkpoint = torch.load(filename, map_location = str(device))

    try:
        if pretrain:
            model.load_state_dict(checkpoint['state_dict'], strict=False)
        else:
            model.load_state_dict(checkpoint['state_dict'])
        print("=> Successfully restored checkpoint (trained for {} epochs)"
              .format(checkpoint['epoch']))
    except:
        print("=> Checkpoint not successfully restored")
        raise

    return model, inp_epoch

def restore_best_checkpoint(epoch, model, checkpoint_dir, device):
    """
    Restore the best performance checkpoint
    """
    cp_files = [file_ for file_ in os.listdir(checkpoint_dir)
                if file_.startswith('epoch=') and file_.endswith('.checkpoint.pth.tar')]

    filename = os.path.join(checkpoint_dir,
                            'epoch={}.checkpoint.pth.tar'.format(epoch))

    print("Loading from checkpoint {}?".format(filename))

    checkpoint = torch.load(filename, map_location = str(device))

    model.load_state_dict(checkpoint['state_dict'])
    print("=> Successfully restored checkpoint (trained for {} epochs)"
          .format(checkpoint['epoch']))

    return model

def clear_checkpoint(checkpoint_dir):
    filelist = [f for f in os.listdir(checkpoint_dir) if f.endswith(".pth.tar")]
    for f in filelist:
        os.remove(os.path.join(checkpoint_dir, f))

    print("Checkpoint successfully removed")

def evaluation(args, data, model, epoch, base_path, evaluator, name="valid"):
    # Evaluate with given evaluator

    ret, _ = evaluator.evaluate(model)

    n_ret = {"recall": ret[1], "hit_ratio": ret[5], "precision": ret[0], "ndcg": ret[3], "mrr":ret[4], "map":ret[2]}

    perf_str = name+':{}'.format(n_ret)
    print(perf_str)
    with open(base_path + 'stats_{}.txt'.format(args.saveID), 'a') as f:
        f.write(perf_str + "\n")
    # Check if need to early stop (on validation)
    is_best=False
    early_stop=False
    if name=="valid":
        if ret[1] > data.best_valid_recall:
            data.best_valid_epoch = epoch
            data.best_valid_recall = ret[1]
            data.patience = 0
            is_best=True
        else:
            data.patience += 1
            if data.patience >= args.patience:
                print_str = "The best performance epoch is % d " % data.best_valid_epoch
                print(print_str)
                early_stop=True

    return is_best, early_stop

def Item_pop(args, data, model):

    for K in range(5):

        eval_pop = ProxyEvaluator(data, data.train_user_list, data.pop_dict_list[K], top_k=[(K+1)*10],
                                   dump_dict=merge_user_list([data.train_user_list, data.valid_user_list]))

        ret, _ = eval_pop.evaluate(model)

        print_str = "Overlap for K = % d is % f" % ( (K+1)*10, ret[1] )

        print(print_str)

        with open('stats_{}.txt'.format(args.saveID), 'a') as f:
            f.write(print_str + "\n")

def ensureDir(dir_path):

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

def split_grp_view(data,grp_idx):
    n=len(grp_view)
    split_data=[{} for _ in range(n)]

    for key,item in data.items():
        for it in item:
            if key not in split_data[grp_idx[it]].keys():
                split_data[grp_idx[it]][key]=[]
            split_data[grp_idx[it]][key].append(it)
    return split_data

def checktensor(tensor):
    t=tensor.detach().cpu().numpy()
    if np.max(np.isnan(t)):
        idx=np.argmax(np.isnan(t))
        return idx
    else:
        return -1

def get_rotation_matrix(axis, theta):
    """
    Find the rotation matrix associated with counterclockwise rotation
    about the given axis by theta radians.
    Credit: http://stackoverflow.com/users/190597/unutbu

    Args:
        axis (list): rotation axis of the form [x, y, z]
        theta (float): rotational angle in radians

    Returns:
        array. Rotation matrix.
    """

    axis = np.asarray(axis)
    theta = np.asarray(theta)
    axis = axis/math.sqrt(np.dot(axis, axis))
    a = math.cos(theta/2.0)
    b, c, d = -axis*math.sin(theta/2.0)
    aa, bb, cc, dd = a*a, b*b, c*c, d*d
    bc, ad, ac, ab, bd, cd = b*c, a*d, a*c, a*b, b*d, c*d
    return np.array([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)],
                     [2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)],
                     [2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]])

grads = {}
def save_grad(name):
    def hook(grad):
        torch.clamp(grad, -1, 1)
        grads[name] = grad
    return hook

"""
It takes in the embeddings of users and items, the popularity of users and items, and the data, and
plots the embeddings of users and items in 3D space, and plots the angular distribution of the
embeddings of items.

The embeddings of users and items are plotted in 3D space, and the angular distribution of the
embeddings of items are plotted in 2D space.

:param items: the item embeddings
:param users: the user embeddings
:param data: the data object
:param p_item: the popularity of each item
:param p_user: the popularity of each user
:param name: the name of the dataset
"""
def visulization(items,users,data,p_item,p_user,name):
    test_ood_user_list=data.test_ood_user_list
    test_id_user_list=data.test_id_user_list
    train_user_list=data.train_user_list

    def split_grp_view(data,grp_idx):
        n=len(grp_view)
        split_data=[collections.defaultdict(list) for _ in range(n)]

        for key,item in data.items():
            for it in item:
                if key not in split_data[grp_idx[it]].keys():
                    split_data[grp_idx[it]][key]=[]
                split_data[grp_idx[it]][key].append(it)
        return split_data

    pop_sorted=np.sort(p_item)
    n_items=p_item.shape[0]

    n_groups=3
    grp_view=[]
    for grp in range(n_groups):
        split=int((n_items-1)*(grp+1)/n_groups)
        grp_view.append(pop_sorted[split])
    #print("group_view:",grp_view)
    idx=np.searchsorted(grp_view,p_item)

    pop_group=[[] for _ in range(n_groups)]
    for i in range(n_items):
        pop_group[idx[i]].append(i)

    eval_test_ood_split=split_grp_view(test_ood_user_list,idx)
    eval_test_id_split=split_grp_view(test_id_user_list,idx)
    eval_train_split=split_grp_view(train_user_list,idx)

    pop_users=p_user.tolist()

    u_pop_sorted=np.sort(p_user)
    print(u_pop_sorted[-10:])

    fig = plt.figure(constrained_layout=True,figsize=(12,6))

    def plot_embed(ax1,ax2,idx):
        u, v = np.mgrid[0:2*np.pi:20j, 0:2*np.pi:20j]
        x1 = np.cos(u)*np.sin(v)
        y1 = np.sin(u)*np.sin(v)
        z1 = np.cos(v)
        ax1.plot_wireframe(x1, y1, z1, color="0.5",linewidth=0.1)
        user_idx=pop_users.index(idx)
        m_user=users[user_idx]
        target=np.array([1,-1,1])
        r_theta=np.arccos(np.dot(m_user,target)/(np.linalg.norm(m_user)*np.linalg.norm(target)))
        axis=np.cross(m_user,target)
        R=get_rotation_matrix(axis,r_theta)
        grp_theta=[]
        grp_r=[]
        sizes=[10,10,10]

        cmap_b = 'b'
        cmap_r = 'r'
        cmaps=[cmap_b,cmap_r]

        norm = plt.Normalize(vmin=-3, vmax=3)

        all_sampled=set([])
        all_pos=set([])
        for i,grp in enumerate(pop_group):
            sampled_group=set(np.random.choice(np.array(grp),50,replace=False).tolist())
            if user_idx in eval_test_id_split[i].keys():
                for item in eval_test_id_split[i][user_idx]:
                    sampled_group.add(item)
                    all_pos.add(item)
            for item in eval_train_split[i][user_idx]:
                sampled_group.add(item)
                all_pos.add(item)
            if user_idx in eval_test_ood_split[i].keys():
                for item in eval_test_ood_split[i][user_idx]:
                    sampled_group.add(item)
                    all_pos.add(item)

            all_sampled=all_sampled.union(sampled_group)

        all_neg=all_sampled.difference(all_pos)
        #print(all_neg)
        all_pos=np.array(list(all_pos),dtype=int)
        all_neg=np.array(list(all_neg),dtype=int)
        nor = plt.Normalize(vmin=-3, vmax=3)
        r=np.linalg.norm(target)

        lab=["neg","pos"]
        for i,idx in enumerate([all_neg,all_pos]):
            g_item=items[idx]
            g_item=np.matmul(g_item,R.T)
            norm=np.linalg.norm(g_item,axis=1)
            x=g_item[:,0]/norm#*r
            y=g_item[:,1]/norm#*r
            z=g_item[:,2]/norm#*r

            for j in range(len(idx)):
                ax1.plot([0,g_item[j][0]/norm[j]],[0,g_item[j][1]/norm[j]],[0,g_item[j][2]/norm[j]],color = cmaps[i],alpha=0.1)

            ax1.scatter(x, y, z, c = cmaps[i], marker =".",s=10,label=lab[i])

        #print("V^{T}",V_transpose)

        ax1.scatter(target[0]/r, target[1]/r, target[2]/r, c = 'g', marker ="*",s=120,label="user")
        ax1.plot([0,target[0]/r],[0,target[1]/r],[0,target[2]/r],color = 'g',alpha=0.1)
        ax1.legend()

        all_items=set([i for i in range(n_items)])
        all_neg=all_items.difference(all_pos)
        all_neg=np.array(list(all_neg),dtype=int)

        grp=["(neg):","(pos):"]
        txt=""

        for i,idx in enumerate([all_neg,all_pos]):
            g_item=items[idx]
            g_item=np.matmul(g_item,R.T)
            norm=np.linalg.norm(g_item,axis=1)
            cos=np.arccos(np.matmul(target,g_item.T)/norm/r)
            me=float(np.mean(cos))
            me=round(me,3)
            if i==1:
                txt="mean angle"+grp[i]+str(me)+"\n"+txt
            else:
                txt="mean angle"+grp[i]+str(me)+txt

            ax2.hist(cos,50,range=[0,np.pi],color=cmaps[i],weights=np.zeros_like(cos) + 1. / cos.size,edgecolor='black',alpha=0.6)
            mi_x,ma_x=ax2.get_xlim()
            mi_y,ma_y=ax2.get_ylim()
        ax2.text(mi_x+(ma_x-mi_x)*0.45, mi_y+(ma_y-mi_y)*0.75,txt , style ='italic')
        red_patch = mpatches.Patch(color='red', alpha=0.6, label='pos')
        blue_patch = mpatches.Patch(color='blue', alpha=0.6,label='neg')
        ax2.legend(handles=[red_patch,blue_patch])

    pops=[205,30,10]

    fig = plt.figure(figsize=(6,8),constrained_layout=True)
    gs = fig.add_gridspec(3, 2)
    ax1 = fig.add_subplot(gs[0:2, 0:2],projection='3d')
    ax2 = fig.add_subplot(gs[2,0:2])
    ax1.set_xticks([-1,-0.5,0,0.5,1])
    ax1.set_yticks([-1,-0.5,0,0.5,1])
    ax1.set_zticks([-1,-0.5,0,0.5,1])
    ax1.grid(False)

    plot_embed(ax1,ax2,pops[0])
    #ax1.set_title("High Pop User(p=205)")
    #ax2.set_title("Angular Distribution(High Pop)")

    plt.savefig(name+"high_pop_"+str(pops[0])+".png",bbox_inches='tight')
    plt.close()

    fig = plt.figure(figsize=(6,8),constrained_layout=True)
    gs = fig.add_gridspec(3, 2)
    ax3 = fig.add_subplot(gs[0:2, 0:2],projection='3d')
    ax4 = fig.add_subplot(gs[2,0:2])
    ax3.set_xticks([-1,-0.5,0,0.5,1])
    ax3.set_yticks([-1,-0.5,0,0.5,1])
    ax3.set_zticks([-1,-0.5,0,0.5,1])
    ax3.grid(False)
    plot_embed(ax3,ax4,pops[1])
    #ax3.set_title("Mid Pop User(p=30)")
    #ax4.set_title("Angular Distribution(Mid Pop)")

    plt.savefig(name+"mid_pop_"+str(pops[1])+".png",bbox_inches='tight')
    plt.close()

    fig = plt.figure(figsize=(6,8),constrained_layout=True)
    gs = fig.add_gridspec(3, 2)
    ax5 = fig.add_subplot(gs[0:2, 0:2],projection='3d')
    ax6 = fig.add_subplot(gs[2,0:2])
    ax5.set_xticks([-1,-0.5,0,0.5,1])
    ax5.set_yticks([-1,-0.5,0,0.5,1])
    ax5.set_zticks([-1,-0.5,0,0.5,1])
    ax5.grid(False)
    plot_embed(ax5,ax6,pops[2])
    #ax5.set_title("Low Pop User(p=10)")
    #ax6.set_title("Angular Distribution(Low Pop)")

    plt.savefig(name+"low_pop_"+str(pops[2])+".png",bbox_inches='tight')
    plt.close()

def seed_torch(seed=101):
	random.seed(seed)
	os.environ['PYTHONHASHSEED'] = str(seed) # 为了禁止hash随机化，使得实验可复现
	np.random.seed(seed)
	torch.manual_seed(seed)
	torch.cuda.manual_seed(seed)
	torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
	torch.backends.cudnn.benchmark = False
	torch.backends.cudnn.deterministic = True

def align_loss(x, y, alpha=2):
    return (x - y).norm(p=2, dim=1).pow(alpha).mean()

def uniform_loss(x, t=2):
    return torch.pdist(x, p=2).pow(2).mul(-t).exp().mean().log()

if __name__ == '__main__':

    start = time.time()

    args = parse_args()
    seed_torch(args.seed)
    print(args)
    data = Data(args)
    data.load_data()
    device="cuda:"+str(args.cuda)
    device = torch.device(args.cuda)
    saveID = args.saveID
    saveID += str(args.dsc)
    #@ 保存的目录
    # need change 2
    if args.modeltype == "INFONCE":
        saveID += "_INFONCE_" + "n_layers=" + str(args.n_layers) + "tau=" + str(args.tau) + "batch_size=" + str(args.batch_size) + "neg_sample=" + str(args.neg_sample) + "lr=" + str(args.lr)
    if args.modeltype == "INFONCE_linear":
        saveID += "_INFONCE_linear_" + "n_layers=" + str(args.n_layers) + "tau=" + str(args.tau) + "batch_size=" + str(args.batch_size) + "neg_sample=" + str(args.neg_sample) + "lr=" + str(args.lr)

    if args.modeltype == "BC_LOSS":
        saveID += "n_layers=" + str(args.n_layers) + "tau1=" + str(args.tau1) + "tau2=" + str(args.tau2) + "w=" + str(args.w_lambda)

    if args.modeltype == "NBC_Loss":
        saveID += "n_layers=" + str(args.n_layers) + "tau1=" + str(args.tau1) + "tau2=" + str(args.tau2) + "w=" + str(args.w_lambda) + "k_score=" + str(args.k_score)

    if args.modeltype == "SimpleX":
        saveID += "_SimpleX_" + "n_layers=" + str(args.n_layers) + "tau=" + str(args.tau) + "batch_size=" + str(args.batch_size) + "neg_sample=" + str(args.neg_sample) + "lr=" + str(args.lr) + "w=" + str(args.w_neg) + "m=" + str(args.neg_margin)

    if args.modeltype == "XSimGCL":
        saveID += "_XSimGCL_" + "n_layers=" + str(args.n_layers) + "batch_size=" + str(args.batch_size) + "lr=" + str(args.lr) + "temp=" + str(args.temp_cl) + "layer_cl=" + str(args.layer_cl) + "lambda_cl=" + str(args.lambda_cl)+ "eps_XSimGCL=" + str(args.eps_XSimGCL)

    if args.modeltype == "SGL":
        saveID += "_SGL_" + "n_layers=" + str(args.n_layers) + "batch_size=" + str(args.batch_size) + "lr=" + str(args.lr) + "temp=" + str(args.temp_cl) + "lambda_cl=" + str(args.lambda_cl)+ "droprate=" + str(args.droprate)

    if args.modeltype == "NCL":
        saveID += "_NCL_" + "n_layers=" + str(args.n_layers) + "batch_size=" + str(args.batch_size) + "lr=" + str(args.lr) + "temp=" + str(args.temp_cl) + "lambda_cl=" + str(args.lambda_cl)+ "proto_reg=" + str(args.proto_reg) + "n_clusters=" + str(args.num_clusters) + "alpha=" + str(args.ncl_alpha)

    if args.n_layers > 0 and args.modeltype != "LGN":
        base_path = './weights/{}/{}-LGN/{}'.format(args.dataset, args.modeltype, saveID)
    else:
        base_path = './weights/{}/{}/{}'.format(args.dataset, args.modeltype, saveID)

    if args.modeltype == 'LGN':
        saveID += "n_layers=" + str(args.n_layers) + "lr=" + str(args.lr) + "batch_size=" + str(args.batch_size)
        base_path = './weights/{}/{}/{}'.format(args.dataset, args.modeltype, saveID)

    checkpoint_buffer=[]
    #@ epochs for training the margin for BC Loss
    freeze_epoch=args.freeze_epoch if (args.modeltype=="BC_LOSS") else 0
    ensureDir(base_path)

    perf_str = str(args)
    with open(base_path + 'stats_{}.txt'.format(args.saveID),'a') as f:
            f.write(perf_str+"\n")

    #@ calculate the popularity (not used in the paper)
    p_item = np.array([len(data.train_item_list[u]) if u in data.train_item_list else 0 for u in range(data.n_items)])
    p_user = np.array([len(data.train_user_list[u]) if u in data.train_user_list else 0 for u in range(data.n_users)])
    m_user=np.argmax(p_user)

    pop_sorted=np.sort(p_item)
    n_groups=3
    grp_view=[]
    for grp in range(n_groups):
        split=int((data.n_items-1)*(grp+1)/n_groups)
        grp_view.append(pop_sorted[split])
    print("group_view:",grp_view)
    idx=np.searchsorted(grp_view,p_item)

    if(args.dataset != "tencent_synthetic" and args.dataset != "kuairec_ood"):
        eval_test_ood_split=split_grp_view(data.test_ood_user_list,idx)
        eval_test_id_split=split_grp_view(data.test_id_user_list,idx)

    grp_view=[0]+grp_view

    pop_dict={}
    for user,items in data.train_user_list.items():
        for item in items:
            if item not in pop_dict:
                pop_dict[item]=0
            pop_dict[item]+=1
    # The key of pop_dict is item, and the value is the popularity of item

    sort_pop=sorted(pop_dict.items(), key=lambda item: item[1],reverse=True)

    # sort_pop is a list, the elements in the list are tuples, the first element of the tuple is item, and the second element is the popularity of the item
    pop_mask=[item[0] for item in sort_pop[:20]]
    print(pop_mask)

    if "kuairec" in args.dataset:
        with open("data/" + args.dataset + '/not_candidate.txt', 'r') as f:
            not_candidate = f.readlines()
            not_candidate = [int(item.strip()) for item in not_candidate]
            not_candidate_dict = {u:not_candidate for u in data.users}

    if not args.pop_test:

        if(args.dataset == "tencent_synthetic"):
            eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20])
            eval_test_ood_1 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_1,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list_2,data.test_ood_user_list_3]))
            eval_test_ood_2 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_2,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list_1,data.test_ood_user_list_3]))
            eval_test_ood_3 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_3,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list_1,data.test_ood_user_list_2]))
        elif(args.dataset == "kuairec_ood"):
            eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,not_candidate_dict]))
            eval_test_ood_1 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_1,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,not_candidate_dict]))
            eval_test_ood_2 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_2,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,not_candidate_dict, data.test_ood_user_list_1]))
            eval_test_ood_3 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_3,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,not_candidate_dict, data.test_ood_user_list_1, data.test_ood_user_list_2]))
        else:
            if "kuairec" in args.dataset:
                eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,not_candidate_dict]))
                eval_test_ood = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_id_user_list,not_candidate_dict]))
                eval_test_id = ProxyEvaluator(data,data.train_user_list,data.test_id_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list,not_candidate_dict]))
            else:
                eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20])
                eval_test_ood = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_id_user_list]))
                eval_test_id = ProxyEvaluator(data,data.train_user_list,data.test_id_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list]))

    else:
        if(args.dataset == "tencent_synthetic"):
            eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20],pop_mask=pop_mask)
            eval_test_ood_1 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_1,top_k=[20],\
                            dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list_2,data.test_ood_user_list_3]),pop_mask=pop_mask)
            eval_test_ood_2 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_2,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list_1,data.test_ood_user_list_3]),pop_mask=pop_mask)
            eval_test_ood_3 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_3,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list_1,data.test_ood_user_list_2]),pop_mask=pop_mask)
        elif(args.dataset == "kuairec_ood"):
            eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,not_candidate_dict]),pop_mask=pop_mask)
            eval_test_ood_1 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_1,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,not_candidate_dict]),pop_mask=pop_mask)
            eval_test_ood_2 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_2,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,not_candidate_dict,data.test_ood_user_list_1]),pop_mask=pop_mask)
            eval_test_ood_3 = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list_3,top_k=[20],\
                                dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,not_candidate_dict,data.test_ood_user_list_1,data.test_ood_user_list_2]),pop_mask=pop_mask)
        else:
            if "kuairec" in args.dataset:
                eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,not_candidate_dict]),pop_mask=pop_mask)
                eval_test_ood = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_id_user_list,not_candidate_dict]),pop_mask=pop_mask)
                eval_test_id = ProxyEvaluator(data,data.train_user_list,data.test_id_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list,not_candidate_dict]),pop_mask=pop_mask)
            else:
                eval_valid = ProxyEvaluator(data,data.train_user_list,data.valid_user_list,top_k=[20],pop_mask=pop_mask)
                eval_test_ood = ProxyEvaluator(data,data.train_user_list,data.test_ood_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_id_user_list]),pop_mask=pop_mask)
                eval_test_id = ProxyEvaluator(data,data.train_user_list,data.test_id_user_list,top_k=[20],dump_dict=merge_user_list([data.train_user_list,data.valid_user_list,data.test_ood_user_list]),pop_mask=pop_mask)

    if(args.dataset == "tencent_synthetic" or args.dataset == "kuairec_ood"):
        evaluators=[eval_valid, eval_test_ood_1, eval_test_ood_2, eval_test_ood_3]
        eval_names=["valid","test_ood_1", "test_ood_2", "test_ood_3"]
    else:
        evaluators=[ eval_valid,eval_test_id, eval_test_ood]
        eval_names=["valid","test_id", "test_ood" ]

    # need change 3
    if args.modeltype == 'LGN':
        model = LGN(args, data)
    if args.modeltype == 'INFONCE':
        model = INFONCE(args, data)
    if args.modeltype == 'INFONCE_linear':
        model = INFONCE_linear(args, data)
    if args.modeltype == 'IPS':
        model = IPS(args, data)
    if args.modeltype == 'CausE':
        model = CausE(args, data)
    if args.modeltype == 'BC_LOSS':
        model = BC_LOSS(args, data)
    if args.modeltype == 'MACR':
        model = MACR(args, data)
    if args.modeltype == 'SAMREG':
        model = SAMREG(args, data)
    if args.modeltype == "SimpleX":
        model = SimpleX(args,data)
    if args.modeltype == "SGL":
        model = SGL(args,data)
    if args.modeltype == "NCL":
        model = NCL(args,data)
    if args.modeltype == "XSimGCL":
        model = XSimGCL(args,data)
    if args.modeltype == "PID":
        model = PID(args,data)
    if args.modeltype == "NBC_LOSS":
        model = NBC_LOSS(args, data)

#    b=args.sample_beta

    model.cuda(device)

    #@ load the model
    model, start_epoch = restore_checkpoint(model, base_path, device)

    if args.test_only:

        for i,evaluator in enumerate(evaluators):
            is_best, temp_flag = evaluation(args, data, model, start_epoch, base_path, evaluator,eval_names[i])

        exit()

    flag = False

    # for param in model.named_parameters():
        # print(param)
    if args.modeltype == "PID":
        optimizer = torch.optim.Adam(model.parameters(), lr=model.lr, weight_decay=5e-6)
    else:
        optimizer = torch.optim.Adam([param for param in model.parameters() if param.requires_grad == True], lr=model.lr)

    #item_pop_idx = torch.tensor(data.item_pop_idx).cuda(device)

    for epoch in range(start_epoch, args.epoch):
        print(f"current epoch: {epoch}/{args.epoch}")

        # If the early stopping has been reached, restore to the best performance model
        if flag:
            break

        # need change 4
        # All models
        running_loss, running_mf_loss, running_reg_loss, num_batches = 0, 0, 0, 0
        # CausE
        running_cf_loss = 0
        # BC_LOSS
        running_loss1, running_loss2 = 0, 0
        # XSimGCL
        running_cl_loss = 0
        # NCL
        running_proto_loss = 0
        # PID
        running_pid_loss = 0

        if args.modeltype == "SGL":
            print("get enhanced graph")
            dropped_adj1 = model.get_enhanced_adj(data.ui_mat, args.droprate)
            dropped_adj2 = model.get_enhanced_adj(data.ui_mat, args.droprate)

        if args.modeltype == "NCL" and epoch >= args.ncl_start_epoch:
            model.e_step()

        t1=time.time()

        pbar = tqdm(enumerate(data.train_loader), mininterval=2, total = len(data.train_loader))

        for batch_i, batch in pbar:
            # print(batch_i, batch)

            batch = [x.cuda(device) for x in batch]

            users = batch[0]
            pos_items = batch[1]

            if args.modeltype != 'CausE':
                users_pop = batch[2]
                pos_items_pop = batch[3]
                pos_weights = batch[4]
                if args.infonce == 0 or args.neg_sample != -1:
                    neg_items = batch[5]
                    neg_items_pop = batch[6]

            model.train()

            # need change 5

            if args.modeltype == 'INFONCE':

                mf_loss, reg_loss = model(users, pos_items, neg_items)
                loss = mf_loss + reg_loss

            elif args.modeltype == 'INFONCE_linear':

                mf_loss, reg_loss = model(users, pos_items, neg_items, neg_items_pop)
                loss = mf_loss + reg_loss

            elif args.modeltype == 'BC_LOSS':
                loss1, loss2, reg_loss, reg_loss_freeze, reg_loss_norm  = model(users, pos_items, neg_items, \
                                                                                users_pop, pos_items_pop, neg_items_pop)

                if epoch < args.freeze_epoch:
                    loss =  loss2 + reg_loss_freeze #@ loss2是poplarity bias loss
                else:
                    model.freeze_pop()
                    loss = loss1 + loss2 + reg_loss

            elif args.modeltype == 'NBC_LOSS':
                loss1, loss2, reg_loss, reg_loss_freeze, reg_loss_norm  = model(users, pos_items, neg_items, \
                                                                                users_pop, pos_items_pop, neg_items_pop)

                if epoch < args.freeze_epoch:
                    loss = loss1 + loss2 + reg_loss_freeze
                else:
                    model.freeze_pop()
                    loss = loss1 + loss2 + reg_loss

            elif args.modeltype == 'IPS' or args.modeltype =='SAMREG':

                mf_loss, reg_loss = model(users, pos_items, neg_items, pos_weights)
                loss = mf_loss + reg_loss

            elif args.modeltype == 'CausE':
                neg_items = batch[2]
                all_reg = torch.squeeze(batch[3].T.reshape([1, -1]))
                all_ctrl = torch.squeeze(batch[4].T.reshape([1, -1]))
                mf_loss, reg_loss, cf_loss = model(users, pos_items, neg_items, all_reg, all_ctrl)
                loss = mf_loss + reg_loss + cf_loss

            elif args.modeltype == "SimpleX":
                mf_loss, reg_loss = model(users, pos_items, neg_items)
                loss = mf_loss + reg_loss

            elif args.modeltype == "XSimGCL":
                mf_loss, cl_loss, reg_loss = model(users, pos_items, neg_items)
                loss = mf_loss + cl_loss + reg_loss

            elif args.modeltype == "SGL":
                mf_loss, cl_loss, reg_loss = model(users, pos_items, neg_items, dropped_adj1, dropped_adj2)
                loss = mf_loss + cl_loss + reg_loss

            elif args.modeltype == "NCL":
                mf_loss, cl_loss, proto_loss, reg_loss = model(users, pos_items, neg_items, epoch)
                if(epoch >= args.ncl_start_epoch):
                    loss = mf_loss + cl_loss + proto_loss + reg_loss
                else:
                    loss = mf_loss + cl_loss + reg_loss

            elif args.modeltype == "PID":
                mf_loss, pid_loss, reg_loss = model(users, pos_items, neg_items)
                loss = mf_loss + pid_loss + reg_loss
                # loss = mf_loss + reg_loss

            else:
                mf_loss, reg_loss = model(users, pos_items, neg_items)
                loss = mf_loss + reg_loss

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            running_loss += loss.detach().item()
            running_reg_loss += reg_loss.detach().item()

            # need change 6
            if args.modeltype != 'BC_LOSS' and args.modeltype != 'NBC_LOSS':
                running_mf_loss += mf_loss.detach().item()

            if args.modeltype == 'CausE':
                running_cf_loss += cf_loss.detach().item()

            if args.modeltype == 'BC_LOSS' or args.modeltype == 'NBC_LOSS':
                running_loss1 += loss1.detach().item()
                running_loss2 += loss2.detach().item()

            if args.modeltype == 'XSimGCL' or args.modeltype == 'SGL':
                running_cl_loss += cl_loss.detach().item()

            if args.modeltype == 'NCL':
                running_cl_loss += cl_loss.detach().item()
                running_proto_loss += proto_loss.detach().item()

            if args.modeltype == 'PID':
                running_pid_loss += pid_loss.detach().item()

            num_batches += 1

        t2=time.time()

        # need change 7
        # Training data for one epoch
        if args.modeltype == "CausE":
            perf_str = 'Epoch %d [%.1fs]: train==[%.5f=%.5f + %.5f + %.5f]' % (
                epoch, t2 - t1, running_loss / num_batches,
                running_mf_loss / num_batches, running_reg_loss / num_batches, running_cf_loss / num_batches)

        elif args.modeltype=="BC_LOSS" or args.modeltype=="NBC_LOSS":
            perf_str = 'Epoch %d [%.1fs]: train==[%.5f=%.5f + %.5f + %.5f]' % (
                epoch, t2 - t1, running_loss / num_batches,
                running_loss1 / num_batches, running_loss2 / num_batches, running_reg_loss / num_batches)
                #@ 1 for main branch 2 for popularity branch reg for reg branch

        elif args.modeltype == "XSimGCL" or args.modeltype == "SGL":
            perf_str = 'Epoch %d [%.1fs]: train==[%.5f=%.5f + %.5f + %.5f]' % (
                epoch, t2 - t1, running_loss / num_batches,
                running_mf_loss / num_batches, running_cl_loss / num_batches, running_reg_loss / num_batches)

        elif args.modeltype == "NCL":
            perf_str = 'Epoch %d [%.1fs]: train==[%.5f=%.5f + %.5f + %.5f + %.5f]' % (
                epoch, t2 - t1, running_loss / num_batches,
                running_mf_loss / num_batches, running_cl_loss / num_batches, running_proto_loss / num_batches, running_reg_loss / num_batches)

        elif args.modeltype == "PID":
            perf_str = 'Epoch %d [%.1fs]: train==[%.5f=%.5f + %.5f + %.5f]' % (
                epoch, t2 - t1, running_loss / num_batches,
                running_mf_loss / num_batches, running_pid_loss / num_batches, running_reg_loss / num_batches)

        else:
            perf_str = 'Epoch %d [%.1fs]: train==[%.5f=%.5f + %.5f]' % (
                epoch, t2 - t1, running_loss / num_batches,
                running_mf_loss / num_batches, running_reg_loss / num_batches)

        #@ 表现写入txt文件
        with open(base_path + 'stats_{}.txt'.format(args.saveID),'a') as f:
            f.write(perf_str+"\n")

        # Evaluate the trained model
        if (epoch + 1) % args.verbose == 0 and epoch >= freeze_epoch:
            model.eval()

            for i,evaluator in enumerate(evaluators):
                is_best, temp_flag = evaluation(args, data, model, epoch, base_path, evaluator,eval_names[i])

                if is_best:
                    checkpoint_buffer=save_checkpoint(model, epoch, base_path, checkpoint_buffer, args.max2keep)

                #@ early stop?
                if temp_flag:
                    flag = True

            all_users, all_items = model.compute()
            users_emb = all_users[users]
            pos_emb = all_items[pos_items]
            users_emb = F.normalize(users_emb, dim = -1)
            pos_emb = F.normalize(pos_emb, dim = -1)
            aloss = align_loss(users_emb, pos_emb)
            uloss = uniform_loss(users_emb)
            uloss += uniform_loss(pos_emb)

            with open(base_path + '/2loss.txt','a') as f:
                f.write(str(aloss.item())+"\t"+str(uloss.item())+"\n")

            model.train()

    # Get result
    model = restore_best_checkpoint(data.best_valid_epoch, model, base_path, device)
    print_str = "The best epoch is % d" % data.best_valid_epoch
    with open(base_path +'stats_{}.txt'.format(args.saveID), 'a') as f:
        f.write(print_str + "\n")

    for i,evaluator in enumerate(evaluators[:]):
        evaluation(args, data, model, epoch, base_path, evaluator, eval_names[i])
    with open(base_path +'stats_{}.txt'.format(args.saveID), 'a') as f:
        f.write(print_str + "\n")

    read_log(base_path +'stats_{}.txt'.format(args.saveID))


import copy
from functools import partial
from collections import OrderedDict

import torch
from torch import nn

from efficientnetv2 import get_efficientnet_v2_structure
from efficientnetv2 import load_from_zoo

class ConvBNAct(nn.Sequential):
    """Convolution-Normalization-Activation Module"""
    def __init__(self, in_channel, out_channel, kernel_size, stride, groups, norm_layer, act, conv_layer=nn.Conv2d):
        super(ConvBNAct, self).__init__(
            conv_layer(in_channel, out_channel, kernel_size, stride=stride, padding=(kernel_size-1)//2, groups=groups, bias=False),
            norm_layer(out_channel),
            act()
        )

class SEUnit(nn.Module):
    """Squeeze-Excitation Unit

    paper: https://openaccess.thecvf.com/content_cvpr_2018/html/Hu_Squeeze-and-Excitation_Networks_CVPR_2018_paper

    """
    def __init__(self, in_channel, reduction_ratio=4, act1=partial(nn.SiLU, inplace=True), act2=nn.Sigmoid):
        super(SEUnit, self).__init__()
        hidden_dim = in_channel // reduction_ratio
        self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc1 = nn.Conv2d(in_channel, hidden_dim, (1, 1), bias=True)
        self.fc2 = nn.Conv2d(hidden_dim, in_channel, (1, 1), bias=True)
        self.act1 = act1()
        self.act2 = act2()

    def forward(self, x):
        return x * self.act2(self.fc2(self.act1(self.fc1(self.avg_pool(x)))))

class StochasticDepth(nn.Module):
    """StochasticDepth

    paper: https://link.springer.com/chapter/10.1007/978-3-319-46493-0_39

    :arg
        - prob: Probability of dying
        - mode: "row" or "all". "row" means that each row survives with different probability
    """
    def __init__(self, prob, mode):
        super(StochasticDepth, self).__init__()
        self.prob = prob
        self.survival = 1.0 - prob
        self.mode = mode

    def forward(self, x):
        if self.prob == 0.0 or not self.training:
            return x
        else:
            shape = [x.size(0)] + [1] * (x.ndim - 1) if self.mode == 'row' else [1]
            return x * torch.empty(shape).bernoulli_(self.survival).div_(self.survival).to(x.device)

class MBConvConfig:
    """EfficientNet Building block configuration"""
    def __init__(self, expand_ratio: float, kernel: int, stride: int, in_ch: int, out_ch: int, layers: int,
                 use_se: bool, fused: bool, act=nn.SiLU, norm_layer=nn.BatchNorm2d):
        self.expand_ratio = expand_ratio
        self.kernel = kernel
        self.stride = stride
        self.in_ch = in_ch
        self.out_ch = out_ch
        self.num_layers = layers
        self.act = act
        self.norm_layer = norm_layer
        self.use_se = use_se
        self.fused = fused

    @staticmethod
    def adjust_channels(channel, factor, divisible=8):
        new_channel = channel * factor
        divisible_channel = max(divisible, (int(new_channel + divisible / 2) // divisible) * divisible)
        divisible_channel += divisible if divisible_channel < 0.9 * new_channel else 0
        return divisible_channel

class MBConv(nn.Module):
    """EfficientNet main building blocks

    :arg
        - c: MBConvConfig instance
        - sd_prob: stochastic path probability
    """
    def __init__(self, c, sd_prob=0.0):
        super(MBConv, self).__init__()
        inter_channel = c.adjust_channels(c.in_ch, c.expand_ratio)
        block = []

        if c.expand_ratio == 1:
            block.append(('fused', ConvBNAct(c.in_ch, inter_channel, c.kernel, c.stride, 1, c.norm_layer, c.act)))
        elif c.fused:
            block.append(('fused', ConvBNAct(c.in_ch, inter_channel, c.kernel, c.stride, 1, c.norm_layer, c.act)))
            block.append(('fused_point_wise', ConvBNAct(inter_channel, c.out_ch, 1, 1, 1, c.norm_layer, nn.Identity)))
        else:
            block.append(('linear_bottleneck', ConvBNAct(c.in_ch, inter_channel, 1, 1, 1, c.norm_layer, c.act)))
            block.append(('depth_wise', ConvBNAct(inter_channel, inter_channel, c.kernel, c.stride, inter_channel, c.norm_layer, c.act)))
            block.append(('se', SEUnit(inter_channel, 4 * c.expand_ratio)))
            block.append(('point_wise', ConvBNAct(inter_channel, c.out_ch, 1, 1, 1, c.norm_layer, nn.Identity)))

        self.block = nn.Sequential(OrderedDict(block))
        self.use_skip_connection = c.stride == 1 and c.in_ch == c.out_ch
        self.stochastic_path = StochasticDepth(sd_prob, "row")

    def forward(self, x):
        out = self.block(x)
        if self.use_skip_connection:
            out = x + self.stochastic_path(out)
        return out

class EfficientNetV2(nn.Module):
    """Pytorch Implementation of EfficientNetV2

    paper: https://arxiv.org/abs/2104.00298

    - reference 1 (pytorch): https://github.com/d-li14/efficientnetv2.pytorch/blob/main/effnetv2.py
    - reference 2 (official): https://github.com/google/automl/blob/master/efficientnetv2/effnetv2_configs.py

    :arg
        - layer_infos: list of MBConvConfig
        - out_channels: bottleneck channel
        - nlcass: number of class
        - dropout: dropout probability before classifier layer
        - stochastic depth: stochastic depth probability
    """
    def __init__(self, layer_infos, out_channels=1280, nclass=0, dropout=0.2, stochastic_depth=0.0,
                 block=MBConv, act_layer=nn.SiLU, norm_layer=nn.BatchNorm2d):
        super(EfficientNetV2, self).__init__()
        self.layer_infos = layer_infos
        self.norm_layer = norm_layer
        self.act = act_layer

        self.in_channel = layer_infos[0].in_ch
        self.final_stage_channel = layer_infos[-1].out_ch
        self.out_channels = out_channels

        self.cur_block = 0
        self.num_block = sum(stage.num_layers for stage in layer_infos)
        self.stochastic_depth = stochastic_depth

        self.stem = ConvBNAct(3, self.in_channel, 3, 2, 1, self.norm_layer, self.act)
        self.blocks = nn.Sequential(*self.make_stages(layer_infos, block))
        self.head = nn.Sequential(OrderedDict([
            ('bottleneck', ConvBNAct(self.final_stage_channel, out_channels, 1, 1, 1, self.norm_layer, self.act)),
            ('avgpool', nn.AdaptiveAvgPool2d((1, 1))),
            ('flatten', nn.Flatten()),
            ('dropout', nn.Dropout(p=dropout, inplace=True)),
            ('classifier', nn.Linear(out_channels, nclass) if nclass else nn.Identity())
        ]))

    def make_stages(self, layer_infos, block):
        return [layer for layer_info in layer_infos for layer in self.make_layers(copy.copy(layer_info), block)]

    def make_layers(self, layer_info, block):
        layers = []
        for i in range(layer_info.num_layers):
            layers.append(block(layer_info, sd_prob=self.get_sd_prob()))
            layer_info.in_ch = layer_info.out_ch
            layer_info.stride = 1
        return layers

    def get_sd_prob(self):
        sd_prob = self.stochastic_depth * (self.cur_block / self.num_block)
        self.cur_block += 1
        return sd_prob

    def forward(self, x):
        return self.head(self.blocks(self.stem(x)))

    def change_dropout_rate(self, p):
        self.head[-2] = nn.Dropout(p=p, inplace=True)

def efficientnet_v2_init(model):
    for m in model.modules():
        if isinstance(m, nn.Conv2d):
            nn.init.kaiming_normal_(m.weight, mode='fan_out')
            if m.bias is not None:
                nn.init.zeros_(m.bias)
        elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
            nn.init.ones_(m.weight)
            nn.init.zeros_(m.bias)
        elif isinstance(m, nn.Linear):
            nn.init.normal_(m.weight, mean=0.0, std=0.01)
            nn.init.zeros_(m.bias)

def get_efficientnet_v2(model_name, pretrained, nclass=0, dropout=0.1, stochastic_depth=0.2, **kwargs):
    residual_config = [MBConvConfig(*layer_config) for layer_config in get_efficientnet_v2_structure(model_name)]
    model = EfficientNetV2(residual_config, 1280, nclass, dropout=dropout, stochastic_depth=stochastic_depth, block=MBConv, act_layer=nn.SiLU)
    efficientnet_v2_init(model)

    if pretrained:
        load_from_zoo(model, model_name)

    return model