def _compute_gate_value(self, adj, feat, adj_sp_csr):
        """
        See equation (3) of the GaAN paper. Gate value is applied in front of each head.
        Symbols such as zj follows the equations in the paper.
        """
        zj = feat.mm(self.weight_pool_gate)
        neigh_zj = []
        # use loop instead since torch does not support sparse tensor slice
        for i in range(adj.shape[0]):
            if adj_sp_csr.indptr[i] < adj_sp_csr.indptr[i + 1]:
                neigh_zj.append(
                    torch.max(
                        zj[
                            adj_sp_csr.indices[
                                adj_sp_csr.indptr[i] : adj_sp_csr.indptr[i + 1]
                            ]
                        ],
                        0,
                    )[0].unsqueeze(0)
                )
            else:
                if zj.is_cuda:
                    neigh_zj.append(torch.zeros(1, self.dim_gate).cuda())
                else:
                    neigh_zj.append(torch.zeros(1, self.dim_gate))
        neigh_zj = torch.cat(neigh_zj, 0)
        neigh_mean = self._spmm(adj, feat)
        gate_feat = torch.cat([feat, neigh_zj, neigh_mean], 1)
        return gate_feat.mm(self.weight_gate)

        See equation (3) of the GaAN paper. Gate value is applied in front of each head.
        Symbols such as zj follows the equations in the paper.
        
graphsaint/pytorch_version/layers.py