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

# 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 KnowledgeIncor(Module):
    def __init__(self, config: TextEncoderConfig, tip_vec, triplet_vec, emb_size_global=768, emb_size_convert=300):
        super(KnowledgeIncor, self).__init__()
        tip_vec1 = torch.stack([torch.LongTensor(each_repre1) for each_repre1 in tip_vec])
        triplet_vec1 = torch.stack([torch.LongTensor(each_repre2) for each_repre2 in triplet_vec])
        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.emb_size_global = emb_size_global
        self.emb_size_convert = emb_size_convert
        self.glu1_know = nn.Linear(self.emb_size_global, self.emb_size_convert)
        self.glu2_know = nn.Linear(self.emb_size_global, self.emb_size_convert)
        self.glu3_know = nn.Linear(self.emb_size_convert, 2)

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


    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 = 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)
        # print('triplet_vec1:', triplet_vec1[0])
        # print('triplet_vec1:', np.shape(triplet_vec1))        
        nh_know = torch.sigmoid(tip_vec1 + triplet_vec1) 
        # print('nh_know:', nh_know[0])        
        # print('nh_know:', np.shape(nh_know))  
        beta_know = torch.softmax(self.glu3_know(nh_know), dim=-1)      
        # beta_know = torch.softmax(torch.matmul(nh_know, self.w_know), dim=-1)
        # print('beta_know:', beta_know[0])        
        # print('beta_know:', np.shape(beta_know))        
        tip_beta = beta_know[:,0]
        triplet_beta = beta_know[:,1]
        # print('tip_beta:', tip_beta[0])        
        # print('triplet_beta:', triplet_beta[0])       
        # print('tip_beta:', np.shape(tip_beta))        
        # print('triplet_beta:', np.shape(triplet_beta))        
        tip_beta2 = tip_beta[:, None]
        triplet_beta2 = triplet_beta[:, None]
        # print('tip_beta2:', np.shape(tip_beta2))        
        # print('triplet_beta2:', np.shape(triplet_beta2))        
        tip_beta3 = tip_beta2.repeat(1, 300)
        triplet_beta3 = triplet_beta2.repeat(1, 300)
        # print('tip_beta3:', np.shape(tip_beta3))        
        # print('triplet_beta3:', np.shape(triplet_beta3))        
        # knowledge
        know_fusion1 = torch.mul(tip_vec1, tip_beta3) +  torch.mul(triplet_vec1, triplet_beta3)
        # print('know_fusion1:', know_fusion1[0])
        # print('know_fusion1:', np.shape(know_fusion1))
        # exit()
        # context_know
        # 300,1024
        know_fusion1_tran = know_fusion1.transpose(1,0)
        # print('know_fusion1_tran:', np.shape(know_fusion1_tran))
        # 32, 1024
        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.matmul(context_know_score, know_fusion1) 
        # print('context_know_repre:', context_know_repre[0])
        # print('context_know_repre:', np.shape(context_know_repre))

        return context_know_repre

class HyperConv(Module):
    def __init__(self, config: TextEncoderConfig, emb_size=300):
        super(HyperConv, self).__init__()
        self.emb_size = emb_size
        self.layers = config.num_layers
        # 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.subgraphs_G = {}
        # 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, index_list, subgraphs_G1, reversed_subgraphs_mapping_w1, context_len):
        # 这控制了context的len，所以可以放心的把每个save成一个文件
        # for i in range(context_len):
        for i1 in index_list:
            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'])
            # print('Success! ' +str(i))
        # self.subgraphs_G = self.subgraphs_G.to(GlobalConfig.device)
        # self.subgraphs_G = self.subgraphs_G.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)
        # embedding_word: torch.Size([4892, 300])
        # embedding_img_2: torch.Size([113561, 300])
        # embedding: torch.Size([118453, 300])
        # print('embedding_word:', np.shape(self.embedding_word))
        # print('embedding_img_2:', np.shape(self.embedding_img_2))
        # print('embedding:', np.shape(self.embedding))

        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 = []
        
        for context_index1 in index_list:
            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']
            # word_num = np.shape(adjacency_E)[1]
            # utt_num = np.shape(adjacency_E)[0]
            # print('word_num: ', self.reversed_subgraphs_mapping_w[context_index])
            # print('adjacency_G: ', np.shape(adjacency_G))
            # print('adjacency_E: ', np.shape(adjacency_E))
            # exit()
            word_index_list = torch.tensor(self.reversed_subgraphs_mapping_w[context_index])
            word_index_list = word_index_list.to(GlobalConfig.device)
            # print('word_index_list: ', np.shape(word_index_list))
            # word_index_list:  torch.Size([17])
            # print('-----adjacency_word_success!-----')
            # 获取单词初始embedding
            # word_embeddings = torch.take(self.embedding, torch.tensor(word_index_list))
            word_embeddings0 =torch.index_select(self.embedding, 0, word_index_list)

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

            if index_hy == 0:
                # batch_edge_hyrepre = edge_embeddings
                # batch_node_hyrepre = word_embeddings
                batch_edge_hyrepre = torch.unsqueeze(edge_embeddings, 0)
                # batch_node_hyrepre = torch.unsqueeze(word_embeddings, 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_node_hyrepre = torch.cat((batch_node_hyrepre, torch.unsqueeze(word_embeddings, 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)
        # return batch_edge_hyrepre, batch_node_hyrepre, batch_len_utt, batch_len_word
        return 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)
    
    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(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_update = torch.index_select(global_repre3, 0, index1)
        # print('content_update:', content_update[0])
        # print('content_update:', np.shape(content_update))
        return content_update

class UtterFusion(Module):
    # def __init__(self, config: TextEncoderConfig, batch_size =64, emb_size_local=768, emb_size_global=300):
    # def __init__(self, config: TextEncoderConfig, batch_size =64, emb_size_local=2816, emb_size_global=300):
    def __init__(self, config: TextEncoderConfig, batch_size =32, emb_size_local=2816, emb_size_global=300):
    # def __init__(self, config: TextEncoderConfig, batch_size =16, emb_size_local=2816, emb_size_global=300):
        super(UtterFusion, self).__init__()
        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.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 forward(self, local_texts_vec3, edge_embeddings3):
        # 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).view(-1, 10, self.emb_size_global)
        # print('local_texts_vec1:', np.shape(local_texts_vec1))

        # positonal encoding
        len_utter = local_texts_vec1.shape[1]
        # print('len_utter:', np.shape(len_utter))
        # pos_emb1: torch.Size([10, 300])
        pos_emb1 = self.pos_embedding.weight[:len_utter] 
        # print('pos_emb1:', np.shape(pos_emb1))

        batch_len = local_texts_vec1.shape[0]  
        # print('batch_len:', np.shape(batch_len))

        # 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))

        # position和embedding拼接之后，是600--再映射成300--64，10，300
        # utter_fusion2 = torch.matmul(torch.cat([pos_emb, utter_fusion1], -1), self.w_1)
        # 64, 10, 300
        local_texts_vec2 = self.glu_w1(torch.cat([pos_emb, local_texts_vec1], -1))
        # print('local_texts_vec2:', np.shape(local_texts_vec2))

        # utter_fusion3 = utter_fusion2.sum(axis=1)
        local_texts_vec4 = local_texts_vec2.view(-1, 10*self.emb_size_global)
        # print('local_texts_vec4:', np.shape(local_texts_vec4))

        # 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_vec4 + 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]  
        # print('local_texts_vec2:', np.shape(local_texts_vec2))
        # print('local_beta3:', np.shape(local_beta3))
        # print('edge_embeddings2:', np.shape(edge_embeddings2))
        # print('edge_beta3:', np.shape(edge_beta3))
        # print('torch.mul(local_texts_vec2, local_beta3):', np.shape(torch.mul(local_texts_vec2, local_beta3)))
        # print('torch.mul(edge_embeddings2, edge_beta3):', np.shape(torch.mul(edge_embeddings2, edge_beta3)))

        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)

        # 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)
        # # pos_emb: torch.Size([16, 10, 300])
        # pos_emb = pos_emb2.repeat(batch_len, 1, 1)
        # # 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))
        # utter_fusion3 = utter_fusion2.sum(axis=1)
        # beta = torch.matmul(nh, self.w_2)
        return utter_fusion2

class TextEncoder(nn.Module):
    """ Text encoder."""
    # 这里的cofig指的是TextEncoderConfig
    def __init__(self, config: TextEncoderConfig):
        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
