| 178 | |
| 179 | @staticmethod |
| 180 | def from_hypergraph_hypergcn( |
| 181 | hypergraph, |
| 182 | feature, |
| 183 | with_mediator=False, |
| 184 | remove_selfloop=True, |
| 185 | ): |
| 186 | import torch |
| 187 | |
| 188 | r"""Construct a graph from a hypergraph with methods proposed in `HyperGCN: A New Method of Training Graph Convolutional Networks on Hypergraphs <https://arxiv.org/pdf/1809.02589.pdf>`_ paper . |
| 189 | |
| 190 | Args: |
| 191 | ``hypergraph`` (``Hypergraph``): The source hypergraph. |
| 192 | ``feature`` (``torch.Tensor``): The feature of the vertices. |
| 193 | ``with_mediator`` (``str``): Whether to use mediator to transform the hyperedges to edges in the graph. Defaults to ``False``. |
| 194 | ``remove_selfloop`` (``bool``): Whether to remove self-loop. Defaults to ``True``. |
| 195 | ``device`` (``torch.device``): The device to store the graph. Defaults to ``torch.device("cpu")``. |
| 196 | """ |
| 197 | num_v = hypergraph.num_v |
| 198 | assert ( |
| 199 | num_v == feature.shape[0] |
| 200 | ), "The number of vertices in hypergraph and feature.shape[0] must be equal!" |
| 201 | e_list, new_e_list, new_e_weight = hypergraph.e[0], [], [] |
| 202 | rv = torch.rand((feature.shape[1], 1), device=feature.device) |
| 203 | for e in e_list: |
| 204 | num_v_in_e = len(e) |
| 205 | assert ( |
| 206 | num_v_in_e >= 2 |
| 207 | ), "The number of vertices in an edge must be greater than or equal to 2!" |
| 208 | p = torch.mm(feature[e, :], rv).squeeze() |
| 209 | v_a_idx, v_b_idx = torch.argmax(p), torch.argmin(p) |
| 210 | if not with_mediator: |
| 211 | new_e_list.append([e[v_a_idx], e[v_b_idx]]) |
| 212 | new_e_weight.append(1.0 / num_v_in_e) |
| 213 | else: |
| 214 | w = 1.0 / (2 * num_v_in_e - 3) |
| 215 | for mid_v_idx in range(num_v_in_e): |
| 216 | if mid_v_idx != v_a_idx and mid_v_idx != v_b_idx: |
| 217 | new_e_list.append([e[v_a_idx], e[mid_v_idx]]) |
| 218 | new_e_weight.append(w) |
| 219 | new_e_list.append([e[v_b_idx], e[mid_v_idx]]) |
| 220 | new_e_weight.append(w) |
| 221 | # remove selfloop |
| 222 | if remove_selfloop: |
| 223 | new_e_list = torch.tensor(new_e_list, dtype=torch.long) |
| 224 | new_e_weight = torch.tensor(new_e_weight, dtype=torch.float) |
| 225 | e_mask = (new_e_list[:, 0] != new_e_list[:, 1]).bool() |
| 226 | new_e_list = new_e_list[e_mask].numpy().tolist() |
| 227 | new_e_weight = new_e_weight[e_mask].numpy().tolist() |
| 228 | |
| 229 | _g = Graph() |
| 230 | _g.add_nodes(list(range(0, num_v))) |
| 231 | for ( |
| 232 | e, |
| 233 | w, |
| 234 | ) in zip(new_e_list, new_e_weight): |
| 235 | if _g.has_edge(e[0], e[1]): |
| 236 | _g.add_edge(e[0], e[1], weight=(w + _g.adj[e[0]][e[1]]["weight"])) |
| 237 | else: |