(self, g)
| 1375 | return self.eps |
| 1376 | |
| 1377 | def __call__(self, g): |
| 1378 | # Step1: heat kernel diffusion |
| 1379 | # t A |
| 1380 | device = g.device |
| 1381 | eweight = self.t * g.edata.get( |
| 1382 | self.eweight_name, F.ones((g.num_edges(),), F.float32, device) |
| 1383 | ) |
| 1384 | num_nodes = g.num_nodes() |
| 1385 | mat = F.zeros((num_nodes, num_nodes), F.float32, device) |
| 1386 | src, dst = g.edges() |
| 1387 | src, dst = F.astype(src, F.int64), F.astype(dst, F.int64) |
| 1388 | mat[dst, src] = eweight |
| 1389 | # t (A - I_n) |
| 1390 | nids = F.astype(g.nodes(), F.int64) |
| 1391 | mat[nids, nids] = mat[nids, nids] - self.t |
| 1392 | |
| 1393 | if is_bidirected(g): |
| 1394 | e, V = torch.linalg.eigh(mat, UPLO="U") |
| 1395 | diff_mat = V @ torch.diag(e.exp()) @ V.t() |
| 1396 | else: |
| 1397 | diff_mat_np = expm(mat.cpu().numpy()) |
| 1398 | diff_mat = torch.Tensor(diff_mat_np).to(device) |
| 1399 | |
| 1400 | # Step2: sparsification |
| 1401 | num_nodes = g.num_nodes() |
| 1402 | eps = self.get_eps(num_nodes, diff_mat) |
| 1403 | dst, src = (diff_mat >= eps).nonzero(as_tuple=False).t() |
| 1404 | data_dict = {g.canonical_etypes[0]: (src, dst)} |
| 1405 | new_g = update_graph_structure(g, data_dict, copy_edata=False) |
| 1406 | new_g.edata[self.eweight_name] = diff_mat[dst, src] |
| 1407 | |
| 1408 | return new_g |
| 1409 | |
| 1410 | |
| 1411 | class GDC(BaseTransform): |
nothing calls this directly
no test coverage detected