import torch
import torch.nn as nn
from config.global_config import GlobalConfig
from config.model_config import TextEncoderConfig
from torch.nn import Module, Parameter
import numpy as np
from constant import PAD_ID
import math
import warnings
warnings.filterwarnings('ignore')
import torch.nn.functional as F
from collections import OrderedDict
from model.InteractionModule import InteractionModule

know_dir = '/home/share/chenxiaolin/MultimodalDialogSystem/Dataset/MMConv/dataset/knowledge_extract/triplet/'
# path_domain_index = know_dir + 'domain_index_dict.npy'

# domain_index_total = np.load(path_domain_index)
# domain_food_index = domain_index_total['food']
# domain_sightseeing_index = domain_index_total['sightseeing']
# domain_mall_index = domain_index_total['mall']
# domain_nightlife_index = domain_index_total['nightlife']
# domain_hotel_index = domain_index_total['hotel']

# from layers import HGNN_conv

def trans_to_cuda(variable):
    if torch.cuda.is_available():
        return variable.cuda()
    else:
        return variable

def _convert_sp_mat_to_sp_tensor(X):
    # coo = X.tocoo().astype(np.float32)
    coo = X.tocoo()
    # 按垂直方向（行顺序）堆叠数组构成一个新的数组
    # 堆叠的数组需要具有相同的维度
    indices = np.vstack((coo.row, coo.col))
    # print('indices: ', indices)
    # indices = np.mat([coo.row, coo.col]).transpose()
    i = torch.LongTensor(indices)
    # print('i', np.shape(i))
    v = torch.FloatTensor(coo.data) 
    # shape = torch.Size(coo)
    shape = coo.shape
    # print('shape: ', shape)
    sp_tensor = torch.sparse.FloatTensor(i, v, torch.Size(shape))
    # 第三个参数不能是shape--应该是原始矩阵coo
    # sp_tensor = torch.sparse.FloatTensor(i, v, shape)
    # print('----sp_tensor---------')
    # return tf.SparseTensor(indices, coo.data, coo.shape)
    # return torch.sparse.FloatTensor(indices, coo.data, coo.shape)
    return sp_tensor

class BatchNorm1dNoBias(nn.BatchNorm1d):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.bias.requires_grad = False


class DynamicCorrelation(Module):
    def __init__(self, config, tip_vec, triplet_vec, emb_size_global=768, emb_size_convert=300, emb_size_triplet=200, emb_size=300):
        super(DynamicCorrelation, self).__init__()
        know_dir = '/home/share/chenxiaolin/MultimodalDialogSystem/Dataset/MMConv/dataset/knowledge_extract/triplet/'
        path_domain_index = know_dir + 'domain_index_dict.npy'
        # 没有tolist会报load的错误
        domain_index_total = np.load(path_domain_index, allow_pickle=True).tolist()
        domain_food_index = domain_index_total['food']
        domain_sightseeing_index = domain_index_total['sightseeing']
        domain_mall_index = domain_index_total['mall']
        domain_nightlife_index = domain_index_total['nightlife']
        domain_hotel_index = domain_index_total['hotel']

        self.emb_size_global = emb_size_global
        self.emb_size_convert = emb_size_convert
        self.emb_size_triplet = emb_size_triplet

        self.emb_size = emb_size
        self.layers = config.num_layers
        self.itr_module = InteractionModule(config)
        # knowledge
        tip_vec1 = torch.stack([torch.tensor(each_repre1, requires_grad=True) for each_repre1 in tip_vec])
        triplet_vec1 = torch.stack([torch.tensor(each_repre2, requires_grad=True) for each_repre2 in triplet_vec])   
        self.domain_food_index = torch.tensor(domain_food_index)
        self.domain_sightseeing_index = torch.tensor(domain_sightseeing_index)
        self.domain_mall_index = torch.tensor(domain_mall_index)
        self.domain_nightlife_index = torch.tensor(domain_nightlife_index)
        self.domain_hotel_index = torch.tensor(domain_hotel_index)

        self.tip_vec = tip_vec1.float()
        self.triplet_vec = triplet_vec1.float()

        self.tip_vec = self.tip_vec.to(GlobalConfig.device)
        self.triplet_vec = self.triplet_vec.to(GlobalConfig.device)

        self.domain_food_index = self.domain_food_index.to(GlobalConfig.device)
        self.domain_sightseeing_index = self.domain_sightseeing_index.to(GlobalConfig.device)
        self.domain_mall_index = self.domain_mall_index.to(GlobalConfig.device)
        self.domain_nightlife_index = self.domain_nightlife_index.to(GlobalConfig.device)
        self.domain_hotel_index = self.domain_hotel_index.to(GlobalConfig.device)

        self.glu1_know = nn.Linear(self.emb_size_global, self.emb_size_convert)
        self.glu2_know = nn.Linear(self.emb_size_triplet, self.emb_size_convert)
        self.glu3_know = nn.Linear(self.emb_size_convert, 2)
        self.glu4_know = nn.Linear(self.emb_size_convert*2, self.emb_size_convert)

    def forward(self, utter_fusion, domain_label):
        tip_vec1 = self.glu1_know(self.tip_vec)
        # print('tip_vec1:', tip_vec1[0])
        # print('tip_vec1:', np.shape(tip_vec1))
        # triplet_vec1 = self.glu2_know(self.triplet_vec)
        # triplet_vec0: torch.Size([8734, 300])
        triplet_vec1 = self.glu2_know(self.triplet_vec)

        # nh_know: torch.Size([1771, 300])
        nh_know = torch.sigmoid(tip_vec1 + triplet_vec1) 

        beta_know = torch.softmax(self.glu3_know(nh_know), dim=-1)      
   
        # tip_beta: torch.Size([1771])
        tip_beta = beta_know[:,0]
        # triplet_beta: torch.Size([1771])
        triplet_beta = beta_know[:,1]
      
        # tip_beta2: torch.Size([1771, 1])
        tip_beta2 = tip_beta[:, None]
        # triplet_beta2: torch.Size([1771, 1])
        triplet_beta2 = triplet_beta[:, None]
    
        # tip_beta3: torch.Size([1771, 300])
        tip_beta3 = tip_beta2.repeat(1, 300)
        # triplet_beta3: torch.Size([1771, 300])
        triplet_beta3 = triplet_beta2.repeat(1, 300)
        # knowledge
        # know_fusion1: torch.Size([1771, 300])
        # gate机制融合
        know_fusion1 = torch.mul(tip_vec1, tip_beta3) +  torch.mul(triplet_vec1, triplet_beta3)
        # select specific_domain_knowledge
        # know2repre_food:  torch.Size([1162, 300])
        # know2repre_sightseeing:  torch.Size([302, 300])
        # know2repre_mall:  torch.Size([96, 300])
        # know2repre_nightlife:  torch.Size([128, 300])
        # know2repre_hotel:  torch.Size([83, 300])    
        know2repre_food = torch.index_select(know_fusion1, 0, self.domain_food_index)  
        know2repre_sightseeing = torch.index_select(know_fusion1, 0, self.domain_sightseeing_index)  
        know2repre_mall = torch.index_select(know_fusion1, 0, self.domain_mall_index)  
        know2repre_nightlife = torch.index_select(know_fusion1, 0, self.domain_nightlife_index)  
        know2repre_hotel = torch.index_select(know_fusion1, 0, self.domain_hotel_index)  
        # print('know2repre_food: ', np.shape(know2repre_food))
        # print('know2repre_sightseeing: ', np.shape(know2repre_sightseeing))
        # print('know2repre_mall: ', np.shape(know2repre_mall))
        # print('know2repre_nightlife: ', np.shape(know2repre_nightlife))
        # print('know2repre_hotel: ', np.shape(know2repre_hotel))
        # exit()
        final_repre_update, loss_return = self.itr_module(utter_fusion, domain_label, know2repre_food, know2repre_sightseeing, know2repre_mall, know2repre_nightlife, know2repre_hotel)
        return final_repre_update, loss_return


class KnowledgeIncor(Module):
    # def __init__(self, config, tip_vec, triplet_vec, emb_size_global=768, emb_size_convert=300):
    def __init__(self, config, tip_vec, triplet_vec, emb_size_global=768, emb_size_convert=300, emb_size_triplet=200):

        super(KnowledgeIncor, self).__init__()
        # tip_vec1 = torch.stack([torch.LongTensor(each_repre1, requires_grad=True) for each_repre1 in tip_vec])
        # triplet_vec1 = torch.stack([torch.LongTensor(each_repre2, requires_grad=True) for each_repre2 in triplet_vec])
        # tip_vec1 = torch.stack([torch.long(torch.tensor(each_repre1, requires_grad=True)) for each_repre1 in tip_vec])
        # triplet_vec1 = torch.stack([torch.long(torch.tensor(each_repre2, requires_grad=True)) for each_repre2 in triplet_vec])        
        # tip_vec1 = torch.stack([torch.tensor(each_repre1, dtype=torch.long, requires_grad=True) for each_repre1 in tip_vec])
        # triplet_vec1 = torch.stack([torch.tensor(each_repre2, dtype=torch.long, requires_grad=True) for each_repre2 in triplet_vec])          
        tip_vec1 = torch.stack([torch.tensor(each_repre1, requires_grad=True) for each_repre1 in tip_vec])
        triplet_vec1 = torch.stack([torch.tensor(each_repre2, requires_grad=True) for each_repre2 in triplet_vec])   
        # triplet_vec1 = torch.tensor(triplet_vec)
        self.temperature = 1.0

        self.tip_vec = tip_vec1.float()
        self.triplet_vec = triplet_vec1.float()
        self.tip_vec = self.tip_vec.to(GlobalConfig.device)
        self.triplet_vec = self.triplet_vec.to(GlobalConfig.device)

        self.projhead = nn.Sequential(OrderedDict([
            ('fc1', nn.Linear(emb_size_convert, emb_size_convert, bias=False)),
            ('bn1', nn.BatchNorm1d(emb_size_convert)),
            ('relu1', nn.ReLU()),
            ('fc2', nn.Linear(emb_size_convert, emb_size_convert, bias=False)),
            ('bn2', BatchNorm1dNoBias(emb_size_convert)),
        ]))

        # self.projhead = nn.Sequential(OrderedDict([
        #     ('fc1', nn.Linear(hidden_size, hidden_size, bias=False)),
        #     ('bn1', nn.BatchNorm1d(hidden_size)),
        #     ('relu1', nn.ReLU()),
        #     ('fc2', nn.Linear(hidden_size, hidden_size, bias=False)),
        #     ('bn2', BatchNorm1dNoBias(hidden_size)),
        # ]))

        self.emb_size_global = emb_size_global
        self.emb_size_convert = emb_size_convert
        self.emb_size_triplet = emb_size_triplet

        self.glu1_know = nn.Linear(self.emb_size_global, self.emb_size_convert)
        self.glu2_know = nn.Linear(self.emb_size_triplet, self.emb_size_convert)
        self.glu3_know = nn.Linear(self.emb_size_convert, 2)
        self.glu4_know = nn.Linear(self.emb_size_convert*2, self.emb_size_convert)

        # self.num_relations = 24
        # self.num_nodes = 8734

        # self.all_triplets = torch.tensor(all_triplets)
        # self.etype = torch.tensor(edge_list)
        # self.head_list = torch.tensor(head_list)

        # self.all_triplets = self.all_triplets.to(GlobalConfig.device)
        # self.etype = self.etype.to(GlobalConfig.device)
        # self.head_list = self.head_list.to(GlobalConfig.device)


        # self.conv = RelGraphConv(self.emb_size_global, self.emb_size_convert, self.num_relations, regularizer='basis', num_bases=2)
        # self.g = dgl.graph((self.all_triplets[:,0], self.all_triplets[:,2]), num_nodes=self.num_nodes)
        self.g_MIMscore1 = nn.Linear(self.emb_size_convert, 1)

        # self.w_know = nn.Parameter(torch.Tensor(self.emb_size_convert, 2))

    def MIM_reg(self, venue_related_repre1, know2repre1):
        venue_related_repre2 = self.projhead(venue_related_repre1)
        know2repre2 = self.projhead(know2repre1)
        z_i = F.normalize(venue_related_repre2)
        z_j = F.normalize(know2repre2)

        B_size, dim_size = z_i.size()
        # print(B_size)
        N = B_size * 2
        # [2*B, D]
        out = torch.cat((z_i, z_j), dim=0)
        # print(out)
        # [2*B, 2*B]
        mm_out = torch.mm(out, out.t().contiguous())
        # print(mm_out)
        sim_matrix = torch.exp(mm_out / self.temperature)
        mask = (torch.ones_like(sim_matrix) - torch.eye(N, device=sim_matrix.device)).bool()

        # [2*B, 2*B-1]
        sim_matrix = sim_matrix.masked_select(mask).view(N, -1)

        # compute loss
        pos_sim = torch.exp(torch.sum(z_i * z_j, dim=-1) / self.temperature)
        # [2*B]
        pos_sim = torch.cat([pos_sim, pos_sim], dim=0)
        loss = (- torch.log(pos_sim / sim_matrix.sum(dim=-1))).mean()

        # # 原始注释开始
        # score1_1 = self.g_MIMscore1(torch.mul(venue_related_repre, know2repre))
        # # score1_1: torch.Size([31, 1])
        # # print('score1_1:', np.shape(score1_1))
        # # print('score1_1:', score1_1)

        # # negative
        # know2repre2 = know2repre.transpose(1,0)
        # # print('know2repre2:', np.shape(know2repre2))
        # # know2repre2: torch.Size([300, 31])
        # # print('know2repre2:', np.shape(know2repre2))

        # # 31,31
        # score2_1 = torch.matmul(venue_related_repre, know2repre2)
        # # score2_1: torch.Size([31, 31])
        # # print('score2_1:', np.shape(score2_1))
        # # mask_matrix = score2_1.size(0)
        # diag = torch.diag(score2_1)
        # # diag: torch.Size([31])
        # # print('diag:', np.shape(diag))
        # a_diag = torch.diag_embed(diag)
        # # a_diag: torch.Size([31, 31])
        # # print('a_diag:', np.shape(a_diag))
        # # 对角线为0，其余的为正常数值
        # score2_2 = score2_1-a_diag
        # # score2_2: torch.Size([31, 31])
        # # print('score2_2:', np.shape(score2_2))
        # # score2_3 = torch.sigmoid(torch.mean(score2_2, dim=0))
        # score2_3 = torch.mean(score2_2, dim=1, keepdim=True)
        # # score2_3: torch.Size([31, 1])
        # # print('score2_3:', np.shape(score2_3))
        # # score_total: tensor(0.6895, grad_fn=<NegBackward>)
        # score_total = -torch.log(torch.sigmoid(torch.mean(score1_1-score2_3)))
        # # print('score_total:', score_total)
        # # print('score_total:', np.shape(score_total))

        # return score_total
        # # 原始注释结束

        return loss

    def forward(self, context_vec):
        # print('self.tip_vec:', np.shape(self.tip_vec))
        # print('self.triplet_vec:', np.shape(self.triplet_vec))
        # tip_vec1: torch.Size([1771, 300])
        path_venue2knowledge_id = know_dir + 'venue2knowledge_id_2.npy'
        self.venue2knowledge_id = np.load(path_venue2knowledge_id, allow_pickle=True).tolist()
        # know2id_list = []
        # for each_venue in value_list_extend2:
        #     know2id = self.venue2knowledge_id[each_venue]
        #     know2id_list.extend([know2id])
        # print('know2id_list:', know2id_list)
        # know2id_list2 = torch.tensor(know2id_list)
        # know2id_list2 = know2id_list2.to(GlobalConfig.device)

        tip_vec1 = self.glu1_know(self.tip_vec)
        # print('tip_vec1:', tip_vec1[0])
        # print('tip_vec1:', np.shape(tip_vec1))
        # triplet_vec1 = self.glu2_know(self.triplet_vec)
        # triplet_vec0: torch.Size([8734, 300])
        triplet_vec1 = self.glu2_know(self.triplet_vec)

        # nh_know: torch.Size([1771, 300])
        nh_know = torch.sigmoid(tip_vec1 + triplet_vec1) 

        beta_know = torch.softmax(self.glu3_know(nh_know), dim=-1)      
   
        # tip_beta: torch.Size([1771])
        tip_beta = beta_know[:,0]
        # triplet_beta: torch.Size([1771])
        triplet_beta = beta_know[:,1]
      
        # tip_beta2: torch.Size([1771, 1])
        tip_beta2 = tip_beta[:, None]
        # triplet_beta2: torch.Size([1771, 1])
        triplet_beta2 = triplet_beta[:, None]
    
        # tip_beta3: torch.Size([1771, 300])
        tip_beta3 = tip_beta2.repeat(1, 300)
        # triplet_beta3: torch.Size([1771, 300])
        triplet_beta3 = triplet_beta2.repeat(1, 300)
        # knowledge
        # know_fusion1: torch.Size([1771, 300])
        # gate机制融合
        know_fusion1 = torch.mul(tip_vec1, tip_beta3) +  torch.mul(triplet_vec1, triplet_beta3)
        # know2repre = torch.index_select(know_fusion1, 0, know2id_list2)  #venue_related_repre,  know2repre
        know2repre = know_fusion1
        # score_MIM = self.MIM_reg(venue_related_repre, know2repre)
        score_MIM = 0

        # 仅使用context中提到的entity的knowledge
        know2repre_tran = know2repre.transpose(1,0)
        context_know_score = torch.softmax(torch.matmul(context_vec, know2repre_tran), dim=-1)
        context_know_repre1 = torch.matmul(context_know_score, know2repre) 
        context_know_repre = self.glu4_know(torch.cat([context_vec, context_know_repre1], dim=1))

        # 以下代码[从这一行到return之前]是原始给全部knowledge分配权重的
        # print('know_fusion1:', know_fusion1[0])
        # print('know_fusion1:', np.shape(know_fusion1))
        # exit()
        # context_know
        # 300,1024
        # know_fusion1_tran: torch.Size([300, 1771])
        # know_fusion1_tran = know_fusion1.transpose(1,0)
        # # print('know_fusion1_tran:', np.shape(know_fusion1_tran))
        # # 32, 1024
        # # context_know_score: torch.Size([32, 1771])
        # context_know_score = torch.softmax(torch.matmul(context_vec, know_fusion1_tran), dim=-1)
        # # print('context_know_score:', context_know_score[0])
        # # print('context_know_score:', np.shape(context_know_score))
        # # 32, 1024---1024, 300----32,300
        # # context_know_repre: torch.Size([32, 300])
        # context_know_repre1 = torch.matmul(context_know_score, know_fusion1) 
        # # print('context_know_repre:', context_know_repre[0])
        # # print('context_know_repre:', np.shape(context_know_repre))
        # # context+knowledge fusion
        # context_know_repre = self.glu4_know(torch.cat([context_vec, context_know_repre1], dim=1))


        return context_know_repre, score_MIM

class HyperConv(Module):
    def __init__(self, config, emb_size_global=2816,  emb_size=300):
        super(HyperConv, self).__init__()
        self.emb_size = emb_size
        # 2
        self.layers = config.num_layers
        self.emb_size_global = emb_size_global
        # self.emb_size = emb_size
        # self.embedding_word = nn.Embedding(
        #     config.word_size,
        #     config.embed_size,
        #     padding_idx=PAD_ID)
        # # 注意每一条都要to到对应的device
        # self.embedding_word = self.embedding_word.to(GlobalConfig.device)

        # self.embedding_img = nn.Embedding(
        #     config.img_size,
        #     config.embed_img_size)
        # # 注意每一条都要to到对应的device
        # self.embedding_img = self.embedding_img.to(GlobalConfig.device)
        # ==原始
        # self.embedding_word = config.embed_init
        # self.embedding_word = self.embedding_word.to(GlobalConfig.device)

        # self.embedding_img = config.embed_img
        # self.embedding_img = self.embedding_img.to(GlobalConfig.device)
        # ==原始
        self.glu_utt = nn.Linear(emb_size_global, emb_size)
        self.glu_utt1 = nn.Linear(emb_size_global, emb_size)


        self.subgraphs_G = {}
        path_err_id = know_dir + 'err_id.npy'
        self.err_id = np.load(path_err_id).tolist()    
        self.utter_res = nn.Linear(self.emb_size*2, self.emb_size)
        self.utter_gate = nn.Linear(self.emb_size, 2)

        # Initial embedding.---text
        # if config.embed_init is not None:
        #     # 加载预训练好的模型，freeze：若为True，表示训练过程不更新，默认为True，False表示表征随着训练过程一起更新
        #     self.embedding_word = self.embedding_word.from_pretrained(
        #         config.embed_init, freeze=False)

        # if config.embed_img is not None:
        #     # 加载预训练好的模型，freeze：若为True，表示训练过程不更新，默认为True，False表示表征随着训练过程一起更新
        #     self.embedding_img = self.embedding_img.from_pretrained(
        #         config.embed_img.float(), freeze=False)        
        # 原始注释
        # self.img_text = nn.Linear(2048, 300)


        # 数据集中的全部context都被转换了---接下来使用index取出每个context对应的邻接矩阵
        # self.context_len = config.train_len

    # def forward(self, texts_vec, index_list, subgraphs_G1, reversed_subgraphs_mapping_w1, context_len):
    #     batch_size = texts_vec.size(0)
    #     texts_vec1 = texts_vec.view(-1, self.emb_size_global)
    #     texts_vec2 = self.glu_utt(texts_vec1.float())
    #     texts_vec3 = texts_vec2.view(batch_size, 10, self.emb_size)
    #     return texts_vec3
# ===origin===
    def forward(self, texts_vec, index_list, subgraphs_G1, reversed_subgraphs_mapping_w1, context_len):
        # 这控制了context的len，所以可以放心的把每个save成一个文件
        # for i in range(context_len):
        value_list_append = []
        value_list_extend = []        
        for i in index_list:
            # i = int(i1)
            # i = int(i1)
            self.subgraphs_G[i] = {}
            self.subgraphs_G[i]['G'] = _convert_sp_mat_to_sp_tensor(subgraphs_G1[i]['G'])
            self.subgraphs_G[i]['E'] = _convert_sp_mat_to_sp_tensor(subgraphs_G1[i]['E'])
            # 只获取到对应的venue
            # each_venue = reversed_subgraphs_mapping_w1[i]
            # value_list_extend.extend(each_venue)
            # value_list_append.append(each_venue)
        # print('value_list_extend: ', value_list_extend) 
        # print('value_list_append: ', value_list_append) 
        # print('value_list_append: ', np.shape(value_list_append)) 
        # print('value_list_append: ', len(value_list_append))     
        # print('value_list_extend: ', np.shape(value_list_extend))   
        # print('value_list_append: ', len(value_list_append))         
        # filter之后的venue
        # value_list_extend2 = []
        # # index
        # value2id = []
        # for venue_index in range(len(value_list_extend)):
        #     each_venue = value_list_extend[venue_index]
        #     if each_venue not in self.err_id:
        #         value_list_extend2.extend([each_venue])
        #         value2id.extend([venue_index])
        # print('value_list_extend2:', value_list_extend2)
        # print('value2id:', value2id)
        # print('value_list_extend2:', len(value_list_extend2))
        # print('value2id:', len(value2id))
        # value2id2 = torch.tensor(value2id)
        # value2id2 = value2id2.to(GlobalConfig.device)               
        # self.embedding_img_2 = self.img_text(self.embedding_img.float())
        # self.embedding = torch.cat([self.embedding_word, self.embedding_img_2], dim=0)
        # self.embedding = self.embedding.to(GlobalConfig.device)


        # self.reversed_subgraphs_mapping_w = reversed_subgraphs_mapping_w1        
        # print('HyperConv-index_list:', index_list)
        # print('HyperConv-index_list_len:', len(index_list))

        # batch_context_hyrepre = []
        # btach_index---对于每个context取出包含单词的embedding以及邻接矩阵
        index_hy = 0
        batch_len_utt = []
        batch_len_word = []
        
        texts_vec1 = torch.reshape(texts_vec, [-1, self.emb_size_global])
        texts_vec2 = self.glu_utt1(texts_vec1.float())
        texts_vec3 = torch.reshape(texts_vec2, [-1, 10, self.emb_size])


        # for context_index in index_list:
        for context_index_index in range(len(index_list)):
            # print('-----'+str(context_index_index)+'-----')
            context_index = index_list[context_index_index]
            # context_index = int(context_index1)
            # print('context_index:', context_index)
            adjacency_G = self.subgraphs_G[context_index]['G']
            adjacency_E = self.subgraphs_G[context_index]['E']
            # adjacency_G: torch.Size([10, 10])
            # adjacency_E: torch.Size([2, 10])
            # print('adjacency_G:', np.shape(adjacency_G))
            # print('adjacency_E:', np.shape(adjacency_E))

            # context_index1 = int(context_index)
            # 10, 2816
            # 10, 2816
            word_embeddings0 = texts_vec[context_index_index,:,:]
            # print('word_embeddings0:', np.shape(word_embeddings0))
            # 10, 300
            # word_embeddings1: torch.Size([10, 300])
            word_embeddings1 = self.glu_utt(word_embeddings0.float())
            # print('word_embeddings1:', np.shape(word_embeddings1))

            # ==之前的版本
            # word_index_list = torch.tensor(self.reversed_subgraphs_mapping_w[context_index])
            # word_index_list = word_index_list.to(GlobalConfig.device)

            # word_embeddings0 =torch.index_select(self.embedding, 0, word_index_list)
            # ===之前的版本
            for i in range(self.layers):
                # word_embeddings = torch.sparse.mm(trans_to_cuda(adjacency_G), word_embeddings)
                # edge_embeddings = torch.sparse.mm(trans_to_cuda(adjacency_E), word_embeddings)
                word_embeddings1 = torch.sparse.mm(trans_to_cuda(adjacency_G), word_embeddings1)
                edge_embeddings = torch.sparse.mm(trans_to_cuda(adjacency_E), word_embeddings1)
            # print('edge_embeddings:', np.shape(edge_embeddings))
            # edge_embedding肯定是10个---每个context最多有10个--如果不够10个，则补全，不然的话，则截断
            # 每个utterance中最多有30个单词
            # print('word_embeddings:', np.shape(word_embeddings))
            # print('edge_embeddings:', np.shape(edge_embeddings))
            # 10, 300
            # print('word_embeddings1:', np.shape(word_embeddings1))

            if index_hy == 0:
                # batch_edge_hyrepre = edge_embeddings
                # batch_node_hyrepre = word_embeddings
                # batch_edge_hyrepre = torch.unsqueeze(edge_embeddings, 0)
                # batch_edge_hyrepre = torch.unsqueeze(edge_embeddings, 0)
                batch_edge_hyrepre = edge_embeddings
                batch_node_hyrepre = torch.unsqueeze(word_embeddings1, 0) 
                # print('batch_node_hyrepre:', np.shape(batch_node_hyrepre))
                # print('batch_edge_hyrepre:', np.shape(batch_edge_hyrepre))
            else:
                # batch_edge_hyrepre = torch.cat((batch_edge_hyrepre, edge_embeddings), 0)
                # batch_node_hyrepre = torch.cat((batch_node_hyrepre, word_embeddings), 0)
                # batch_edge_hyrepre = torch.cat((batch_edge_hyrepre, torch.unsqueeze(edge_embeddings, 0)), 0)
                batch_edge_hyrepre = torch.cat((batch_edge_hyrepre, edge_embeddings), 0)                
                batch_node_hyrepre = torch.cat((batch_node_hyrepre, torch.unsqueeze(word_embeddings1, 0)), 0)
                # print('batch_node_hyrepre:', np.shape(batch_node_hyrepre))
                # print('batch_edge_hyrepre:', np.shape(batch_edge_hyrepre))
            index_hy = index_hy + 1
            # exit()
            # batch_len_utt.append(utt_num)
            # batch_len_word.append(word_num)
        # select_veneu
        # venue_related_repre = torch.index_select(batch_edge_hyrepre, 0, value2id2)
        # batch_node_hyrepre1 = torch.cat((batch_node_hyrepre, texts_vec3), dim=-1)
        # batch_node_hyrepre2 = torch.reshape(batch_node_hyrepre1, [-1, self.emb_size*2])
        # batch_node_hyrepre3 = torch.reshape(self.utter_res(batch_node_hyrepre2), [-1, 10, self.emb_size])
        # print('venue_related_repre:', np.shape(venue_related_repre))            
        # return batch_edge_hyrepre, batch_node_hyrepre, batch_len_utt, batch_len_word
        # return batch_edge_hyreprebatch_node_hyrepre
        # 64, 10, 300
        # utterance_level gate 融合
        nh_utter = torch.sigmoid(batch_node_hyrepre + texts_vec3) 
        # print('nh_utter: ', np.shape(nh_utter))
        beta_utter = torch.softmax(self.utter_gate(nh_utter), dim=-1)      
        # print('beta_utter: ', np.shape(beta_utter))
        hyrepre_beta = beta_utter[:,:,0]
        # print('hyrepre_beta: ', np.shape(hyrepre_beta))
        texts_beta = beta_utter[:,:,1]
        # print('texts_beta: ', np.shape(texts_beta))
        hyrepre_beta2 = hyrepre_beta[:,:,None]
        # print('hyrepre_beta2: ', np.shape(hyrepre_beta2))
        texts_beta2 = texts_beta[:,:,None]
        # print('texts_beta2: ', np.shape(texts_beta2))
        hyrepre_beta3 = hyrepre_beta2.repeat(1, 1, 300)
        # print('hyrepre_beta3: ', np.shape(hyrepre_beta3))
        # repeat需要对应维度
        texts_beta3 = texts_beta2.repeat(1, 1, 300)
        # print('texts_beta3: ', np.shape(texts_beta3))
        batch_node_hyrepre1 = torch.mul(batch_node_hyrepre, hyrepre_beta3) +  torch.mul(texts_vec3, texts_beta3)        
        # print('batch_node_hyrepre1: ', np.shape(batch_node_hyrepre1))

        return batch_node_hyrepre1, batch_edge_hyrepre


class domainHyper(Module):
    def __init__(self, config:TextEncoderConfig, emb_size_global=2816, emb_size_utter=300):
        super(domainHyper, self).__init__()
        self.emb_size_global = emb_size_global
        self.emb_size_utter = emb_size_utter
        self.domain_layers = config.num_layers
        # self.subgraphs_domain_node = _convert_sp_mat_to_sp_tensor(subgraphs_domain_node)
        # self.subgraphs_domain_edge = subgraphs_domain_edge
        # self.train_global_repre = torch.stack([torch.LongTensor(each_repre) for each_repre in train_global_repre])
        # self.train_global_repre = self.train_global_repre.float()
        # self.train_global_repre = self.train_global_repre.to(GlobalConfig.device)
        # self.subgraphs_domain_node = self.subgraphs_domain_node.to(GlobalConfig.device)
        self.glu_domain = nn.Linear(self.emb_size_global, self.emb_size_utter)
        self.domain_fusion = nn.Linear(self.emb_size_utter*2, self.emb_size_utter)
        self.domain_fusion1 = nn.Linear(self.emb_size_utter, self.emb_size_utter)
        self.domain_fusion2 = nn.Linear(self.emb_size_utter, self.emb_size_utter)
        self.domain_fusion3 = nn.Linear(self.emb_size_utter, 2)

    
    def forward(self, global_repre, fusion_repre, index_list1, subgraphs_domain_node1, domain_node_dict):
        # 768--300
        # 23369, 300
        self.subgraphs_domain_node = _convert_sp_mat_to_sp_tensor(subgraphs_domain_node1)
        self.subgraphs_domain_node = self.subgraphs_domain_node.to(GlobalConfig.device)
        # print('subgraphs_domain_node:', subgraphs_domain_node[0][:100])
        # print('subgraphs_domain_node:', np.shape(self.subgraphs_domain_node))        
        global_repre1 = self.glu_domain(global_repre)
        # print('global_repre2:', global_repre2[0])
        # print('global_repre1:', np.shape(global_repre1))
        # 替换值
        index_list = [domain_node_dict[i] for i in index_list1]
        # index = torch.LongTensor(index_list)
        index1 = torch.tensor(index_list)
        # index = index.unsqueeze(1)
        index1 = index1.to(GlobalConfig.device)
        # index1: torch.Size([16])
        # fusion_repre: torch.Size([16, 300])
        # global_repre2: torch.Size([3121, 300])
        # print('index1:', np.shape(index1))
        # print('fusion_repre:', np.shape(fusion_repre))
        # print('global_repre1:', np.shape(global_repre1))
        
        index2 = torch.unsqueeze(index1, 1)
        index_list2 = index2.repeat(1, 300)
        # print('index_list2', np.shape(index_list2))
        # a = a.scatter_add_(0, torch.tensor([[0, 0, 0], [2, 2, 2]]), b)
        global_repre2 = global_repre1.scatter_add_(0, index_list2, fusion_repre)
        # print('global_repre2', np.shape(global_repre2))

        # 使用fusion的feature替换原始数据中的表示
        # for i in range(len(index_list)):
        # # for context_index in index_list:
        #     context_index = index_list[i]
        #     fusion_repre_specific = fusion_repre[i]
        #     # global_repre2[context_index] = fusion_repre_specific
        #     global_repre2[context_index] = fusion_repre_specific
        # global_repre2 = global_repre2.to(GlobalConfig.device)
        # print('global_repre2:', global_repre2[0])
        # print('global_repre2:', np.shape(global_repre2))

        # print('global_repre2:', np.shape(global_repre2))

        # print('index:', index)
        # content_select1 = torch.index_select(global_repre2, 0, index)
        # print('content_select1_before_replace:', np.shape(content_select1))
        # 23369, 300
        # global_repre2.scatter(0, index, fusion_repre)
        # global_repre2 = global_repre2.to(GlobalConfig.device)
        # content_select2 = torch.index_select(global_repre2, 0, index)
        # print('content_select1_after_replace:', np.shape(content_select2))
        # print(np.shape(global_repre2))
        # exit()
        # 超图卷积
        # for i in range(self.domain_layers):--1层
            # self.global_repre2 = torch.sparse.mm(trans_to_cuda(self.subgraphs_domain_node), self.global_repre2)
        global_repre3 = torch.sparse.mm(self.subgraphs_domain_node, global_repre2)
        # print('global_repre2:', global_repre2[0])
        # print('global_repre3:', np.shape(global_repre3))            
        # 更新之后的dialogue的表征
        # 64, 300
        content_update1 = torch.index_select(global_repre3, 0, index1)

        # 将原始和content融合
        # out = torch.cat((z_i, z_j), dim=0)
        # 级联融合
        # content_update = self.domain_fusion(torch.cat((fusion_repre, content_update1), dim=1))
        # gate融合
        # tip_vec1 = self.glu1_know(self.tip_vec)
        # # triplet_vec0: torch.Size([8734, 300])
        # triplet_vec1 = self.glu2_know(self.triplet_vec)
        # # nh_know: torch.Size([1771, 300])
        # nh_know = torch.sigmoid(tip_vec1 + triplet_vec1) 
        # beta_know = torch.softmax(self.glu3_know(nh_know), dim=-1)      
        # # tip_beta: torch.Size([1771])
        # tip_beta = beta_know[:,0]
        # # triplet_beta: torch.Size([1771])
        # triplet_beta = beta_know[:,1]
        # # tip_beta2: torch.Size([1771, 1])
        # tip_beta2 = tip_beta[:, None]
        # # triplet_beta2: torch.Size([1771, 1])
        # triplet_beta2 = triplet_beta[:, None]
        # # tip_beta3: torch.Size([1771, 300])
        # tip_beta3 = tip_beta2.repeat(1, 300)
        # # triplet_beta3: torch.Size([1771, 300])
        # triplet_beta3 = triplet_beta2.repeat(1, 300)
        # # knowledge
        # # know_fusion1: torch.Size([1771, 300])
        # # gate机制融合
        # know_fusion1 = torch.mul(tip_vec1, tip_beta3) +  torch.mul(triplet_vec1, triplet_beta3)        
        fusion_repre1 = self.domain_fusion1(fusion_repre)
        content_update2 = self.domain_fusion2(content_update1)
        nh_domain = torch.sigmoid(fusion_repre1 + content_update2) 
        beta_domain = torch.softmax(self.domain_fusion3(nh_domain), dim=-1)      
        fusion_beta = beta_domain[:,0]
        content_beta = beta_domain[:,1]
        fusion_beta2 = fusion_beta[:, None]
        content_beta2 = content_beta[:, None]
        fusion_beta3 = fusion_beta2.repeat(1, 300)
        content_beta3 = content_beta2.repeat(1, 300)
        content_update = torch.mul(fusion_repre1, fusion_beta3) +  torch.mul(content_update2, content_beta3)        

        # print('content_update:', content_update[0])
        # print('content_update:', np.shape(content_update))
        return content_update

class UtterFusion(Module):
    # def __init__(self, config, batch_size =64, emb_size_local=768, emb_size_global=300):
    # def __init__(self, config, batch_size =64, emb_size_local=2816, emb_size_global=300):
    # def __init__(self, config, batch_size =32, emb_size_local=2816, emb_size_global=300):
    def __init__(self, config, batch_size =64, emb_size_local=2816, emb_size_global=300):
    # def __init__(self, config, batch_size =16, emb_size_local=2816, emb_size_global=300):
        super(UtterFusion, self).__init__()
        # embed_size = 512
        # hidden_size = 1024
        # 一层RNN
        # self.rnn = nn.LSTM(input_size=config.embed_size_RNN,
        #                    hidden_size=config.hidden_size_RNN,
        #                    num_layers=config.num_layers_RNN,
        #                    bidirectional=config.num_directions_RNN == 2,
        #                    batch_first=False).to(GlobalConfig.device)
        # domain_specific encoder
        self.rnn1 = nn.GRU(input_size=config.embed_size_RNN,
                           hidden_size=config.hidden_size_RNN,
                           num_layers=config.num_layers_RNN,
                           bidirectional=config.num_directions_RNN == 2,
                           batch_first=False).to(GlobalConfig.device)        
        self.rnn2 = nn.GRU(input_size=config.embed_size_RNN,
                           hidden_size=config.hidden_size_RNN,
                           num_layers=config.num_layers_RNN,
                           bidirectional=config.num_directions_RNN == 2,
                           batch_first=False).to(GlobalConfig.device) 
        self.rnn3 = nn.GRU(input_size=config.embed_size_RNN,
                           hidden_size=config.hidden_size_RNN,
                           num_layers=config.num_layers_RNN,
                           bidirectional=config.num_directions_RNN == 2,
                           batch_first=False).to(GlobalConfig.device) 
        self.rnn4 = nn.GRU(input_size=config.embed_size_RNN,
                           hidden_size=config.hidden_size_RNN,
                           num_layers=config.num_layers_RNN,
                           bidirectional=config.num_directions_RNN == 2,
                           batch_first=False).to(GlobalConfig.device) 
        self.rnn5 = nn.GRU(input_size=config.embed_size_RNN,
                           hidden_size=config.hidden_size_RNN,
                           num_layers=config.num_layers_RNN,
                           bidirectional=config.num_directions_RNN == 2,
                           batch_first=False).to(GlobalConfig.device) 
        self.rnn6 = nn.GRU(input_size=config.embed_size_RNN,
                           hidden_size=config.hidden_size_RNN,
                           num_layers=config.num_layers_RNN,
                           bidirectional=config.num_directions_RNN == 2,
                           batch_first=False).to(GlobalConfig.device)                                                                                                                                        
        self.rnn1 = self.rnn1.to(GlobalConfig.device)
        self.rnn2 = self.rnn2.to(GlobalConfig.device)
        self.rnn3 = self.rnn3.to(GlobalConfig.device)
        self.rnn4 = self.rnn4.to(GlobalConfig.device)
        self.rnn5 = self.rnn5.to(GlobalConfig.device)
        self.rnn6 = self.rnn6.to(GlobalConfig.device)

        
        
        # self.linear = nn.Linear(emb_size_global, config.embed_size_RNN)
        self.linear = nn.Linear(emb_size_global, emb_size_global)
        self.linear = self.linear.to(GlobalConfig.device)  
        # # ==before做法      
        # self.emb_size_local = emb_size_local
        # self.emb_size_global = emb_size_global
        # # self.batch_size = batch_size
        # #为什么是200呢
        # self.pos_embedding = nn.Embedding(200, self.emb_size_global)
        # # self.w_2 = nn.Parameter(torch.Tensor(self.emb_size_global, 1))
        # self.glu_w1 = nn.Linear(2 * self.emb_size_global, self.emb_size_global)
        # self.glu_w2 = nn.Linear(self.emb_size_global, 2)
        # self.max_len = 10
        # self.d_model = 300
        # # self.w_1 = nn.Parameter(torch.Tensor(2 * self.emb_size_global, self.emb_size_global))
        # # self.w_2 = nn.Parameter(torch.Tensor(self.emb_size_global, 2))
        # # self.w_2 = self.w_2.to(GlobalConfig.device)
        # # self.w_2 = trans_to_cuda(self.w_2)
        # self.glu1 = nn.Linear(10*self.emb_size_local, 10*self.emb_size_global)
        # # self.glu1 = self.glu1.to(GlobalConfig.device)
        # # self.glu1 = trans_to_cuda(self.glu1)
        # self.glu2 = nn.Linear(10*self.emb_size_global, 10*self.emb_size_global) 
        # ==以上
        # self.local_texts_vec1 = 0.0
        # self.edge_embeddings1 = 0.0

        # self.glu2 = self.glu2.to(GlobalConfig.device)
        # self.glu2 = trans_to_cuda(self.glu2)
    
    def postion_fuc(self, max_len, d_model):
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1)
        # div_term = torch.exp(torch.arange(0, d_model, 2) *
        #                             -(math.log(10000.0) / d_model))
        div_term = torch.exp(torch.arange(0, d_model, 2) * torch.tensor(-(math.log(torch.tensor(10000.0 / d_model)))))        
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        # pe1 = pe.unsqueeze(0)
        return pe


    # def forward(self, local_texts_vec3, edge_embeddings3):
    def forward(self, context):
        batch_size = context.size(1)
        # context:  torch.Size([10, 32, 300])
        # print('context: ', np.shape(context))
        context1 = torch.stack([self.linear(x) for x in context])
        # context1:  torch.Size([10, 32, 512])
        # print('context1: ', np.shape(context1))
        context1 = context1.to(GlobalConfig.device)
        # origin1
        # _, (h_n, _) = self.rnn(context1)
        _, (h_n1, _) = self.rnn1(context1)
        _, (h_n2, _) = self.rnn2(context1)
        _, (h_n3, _) = self.rnn3(context1)
        _, (h_n4, _) = self.rnn4(context1)
        _, (h_n5, _) = self.rnn5(context1)
        _, (h_n6, _) = self.rnn6(context1)

        output1 = torch.unsqueeze(h_n1, 1)
        output2 = torch.unsqueeze(h_n2, 1)
        output3 = torch.unsqueeze(h_n3, 1)
        output4 = torch.unsqueeze(h_n4, 1)
        output5 = torch.unsqueeze(h_n5, 1)
        output6 = torch.unsqueeze(h_n6, 1)

        output_concat = torch.cat([output1, output2, output3, output4, output5, output6], dim=1)
        # print('h_n6: ', np.shape(h_n6))
        # print('output_concat: ', np.shape(output_concat))
        # exit()
        # print('h_n: ', np.shape(h_n))
        # h_n:  torch.Size([32, 1024])
        # output1:  torch.Size([32, 1024])
        # ===注释掉以下两行
        # output = h_n.transpose(0, 1)
        # output1 = output.contiguous().view(batch_size, -1)
        # ===注释掉以上两行
        # print('output1: ', np.shape(output1))

        # ==以下全部注释
        # # 16, 10, 2816
        # local_texts_vec = local_texts_vec3.view(-1, 10*self.emb_size_local)
        # # 16, 10, 300
        # local_texts_vec1 = self.glu1(local_texts_vec)

        # # 16, 10, 300
        # edge_embeddings = edge_embeddings3.view(-1, 10*self.emb_size_global)
        # # print('edge_embeddings:', np.shape(edge_embeddings))

        # # 16, 10, 300
        # edge_embeddings1 = self.glu2(edge_embeddings)
        # # print('edge_embeddings1:', np.shape(edge_embeddings1))

        # nh1 = torch.tanh(local_texts_vec1 + edge_embeddings1) #激活函数与论文中的tanh不是一个
        # # print('nh1:', np.shape(nh1))

        # # 64,10,2 --- 64,10,300/64,10,300
        # # nh = nh.view(self.batch_size, 10 , -1)
        # # 16, 10, 300
        # nh = nh1.view(-1, 10, self.emb_size_global)
        # # 64, 10, 2

        # beta = torch.sigmoid(self.glu_w2(nh))
        # # print('beta:', np.shape(beta))
        # # local_beta: torch.Size([16, 10])
        # local_beta =beta[:,:,0]
        # # print('local_beta:', np.shape(local_beta))
        # # edge_beta: torch.Size([16, 10])
        # edge_beta = beta[:,:,1]
        # # print('edge_beta:', np.shape(edge_beta))
        # # 64,10,30
        # # local_texts_vec2 = local_texts_vec1.view(self.batch_size, 10, -1)
        # local_texts_vec2 = local_texts_vec1.view(-1, 10, 300)
        # edge_embeddings2 = edge_embeddings1.view(-1, 10, 300)
        # # edge_embeddings2 = edge_embeddings1.view(self.batch_size, 10, -1)
        # # 64, 10, 1
        # # local_beta2 = local_beta[:, :, None]
        # # edge_beta2 = edge_beta[:, :, None]
        # # local_beta2: torch.Size([16, 10, 1])
        # # edge_beta2: torch.Size([16, 10, 1])
        # local_beta2 = local_beta.unsqueeze(-1)
        # edge_beta2 = edge_beta.unsqueeze(-1)   
        # # print('local_beta2:', np.shape(local_beta2))
        # # print('edge_beta2:', np.shape(edge_beta2))
        # # local_beta3: torch.Size([16, 10, 300])
        # # edge_beta3: torch.Size([16, 10, 300])
        # local_beta3 = local_beta2.repeat(1, 1, 300)
        # # local_beta3 = local_beta2.repeat(1, 1, 30)
        # # edge_beta3 = edge_beta2.repeat(1, 1, 30)
        # edge_beta3 = edge_beta2.repeat(1, 1, 300)
        # # print('local_beta3:', np.shape(local_beta3))
        # # print('edge_beta3:', np.shape(edge_beta3))

        # # utter_fusion1 = local_texts_vec1*local_beta[:, :, None] + edge_embeddings1*edge_beta[:, :, None]  
        # # utter_fusion1 = local_texts_vec2*local_beta[:, :, None] + edge_embeddings2*edge_beta[:, :, None]  


        # utter_fusion1 = torch.mul(local_texts_vec2, local_beta3) +  torch.mul(edge_embeddings2, edge_beta3)
        # # print('utter_fusion1: ', np.shape(utter_fusion1))
        # # utter_fusion2 = utter_fusion1.sum(axis=1)
        # pos_emb1 = self.postion_fuc(self.max_len, self.d_model)
        # print('pos_emb1:', np.shape(pos_emb1))
        # # len_utter = utter_fusion1.shape[1]
        # # # pos_emb1: torch.Size([10, 300])
        # # pos_emb1 = self.pos_embedding.weight[:len_utter]   
        # batch_len = utter_fusion1.shape[0]  
        # # # pos_emb2: torch.Size([1, 10, 300])
        # pos_emb2 = pos_emb1.unsqueeze(0)
        # print('pos_emb2:', np.shape(pos_emb2))

        # # # pos_emb: torch.Size([16, 10, 300])
        # pos_emb = pos_emb2.repeat(batch_len, 1, 1)
        # print('pos_emb:', np.shape(pos_emb))
        # pos_emb = pos_emb.to(GlobalConfig.device)
        # # # position和embedding拼接之后，是600--再映射成300--64，10，300
        # # # utter_fusion2 = torch.matmul(torch.cat([pos_emb, utter_fusion1], -1), self.w_1)
        # utter_fusion2 = self.glu_w1(torch.cat([pos_emb, utter_fusion1], -1))
        # print('utter_fusion2:', np.shape(utter_fusion2))
        # # utter_fusion3 = utter_fusion2.sum(axis=1)
        # utter_fusion3 = utter_fusion2.mean(axis=1)
        # print('utter_fusion3:', np.shape(utter_fusion3))

        # beta = torch.matmul(nh, self.w_2)
        # ==以上全部注释

        return output_concat

class TextEncoder(nn.Module):
    """ Text encoder."""
    # 这里的cofig指的是TextEncoderConfig
    def __init__(self, config):
        super(TextEncoder, self).__init__()

        # torch.nn.Embedding(numembeddings,embeddingdim)是创建一个词嵌入模型，numembeddings代表一共有多少个词, embedding_dim代表你想要为每个词创建一个多少维的向量来表示它
        # 所有vocab中为pad_index的词对应的词向量都是0
        # self.embedding = nn.Embedding(
        #     config.vocab_size,
        #     config.embed_size,
        #     padding_idx=config.pad_index)
        self.embedding = nn.Embedding(
            config.word_size,
            config.embed_size,
            padding_idx=PAD_ID)        
        # 注意每一条都要to到对应的device
        self.embedding = self.embedding.to(GlobalConfig.device)

        # Initial embedding.
        if config.embed_init is not None:
            # 加载预训练好的模型，freeze：若为True，表示训练过程不更新，默认为True，False表示表征随着训练过程一起更新
            self.embedding = self.embedding.from_pretrained(
                config.embed_init, freeze=False)

        # LSTM.
        self.rnn = nn.LSTM(
            input_size=config.embed_size,
            hidden_size=config.hidden_size,
            num_layers=config.num_layers,
            bidirectional=config.num_directions == 2,
            batch_first=False,
            dropout=config.dropout)
        self.rnn = self.rnn.to(GlobalConfig.device)
        # self.HyperGraph = HyperConv(config.n_hyper)

        # 根据index--抽取每个context中每条utterance中对应单词的表征
        # self.xx = torch.take(self.embedding, config.reversed_subgraphs_mapping_w) 

        # HGNN
        # 输入：300 / 输出：300

        # self.nodes, self.edges = HGNN_conv(input_dim = 300,
        #                         output_dim = 300,
        #                         adj = config.subgraphs_G, n_hyper = config.n_hyper,  dropout = config.dropout, act = nn.ReLU)(xx)   
        # self.nodes = self.nodes.to(GlobalConfig.device)
        # self.edges = self.edges.to(GlobalConfig.device)
                 
        # nodes, edges = HGNN_conv(input_dim = self.args.emsize,
        #                         output_dim = self.args.emsize,
        #                         adj = self.subgraphs_G[i],
        #                         act = tf.nn.relu,
        #                         dropout = self.dropout_graph,
        #                         n_hyper = self.n_hyper)(xx)        


    #怎么对它调用呢，是直接使用TextEncoder类，就可以调用了吗
    # BiLSTM编码每一条utterance
    def forward(self, input_seq, input_lengths):
        """Forward.

        Args:
            input_seq: (batch_size, seq_len)
            input_lengths: (batch_size, )

        Returns:
            output: (batch_size, num_layers * num_directions * hidden_size)

        """
        batch_size = input_lengths.size(0)

        input_seq = input_seq.transpose(0, 1)
        # (seq_len, batch_size)

        # 取出embedding
        # 取出邻接矩阵
        embedded = self.embedding(input_seq)
        # (seq_len, batch_size, embed_size)

        hiddens, (h_n, _) = self.rnn(embedded)
        # hiddens: (seq_len, batch, num_directions * hidden_size)
        # h_n: (num_layers * num_directions, batch_size, hidden_size)
        h_n = h_n.transpose(0, 1)
        # h_n: (batch_size, num_layers * num_directions, hidden_size)
        # view函数相当于reshape
        output = h_n.contiguous().view(batch_size, -1)
        # (batch_size, num_layers * num_directions * hidden_size)

        return output, hiddens
