(self)
| 461 | ) |
| 462 | |
| 463 | def process(self): |
| 464 | if self.seed is not None: |
| 465 | np.random.seed(self.seed) |
| 466 | |
| 467 | g = nx.balanced_tree(r=2, h=self.tree_height) |
| 468 | edges = list(g.edges()) |
| 469 | src, dst = map(list, zip(*edges)) |
| 470 | n = nx.number_of_nodes(g) |
| 471 | |
| 472 | # Nodes in the base tree graph belong to class 0 |
| 473 | node_labels = [0] * n |
| 474 | # The motifs will be evenly attached to the nodes in the base graph. |
| 475 | spacing = math.floor(n / self.num_motifs) |
| 476 | |
| 477 | for motif_id in range(self.num_motifs): |
| 478 | # Construct a six-node cycle |
| 479 | motif_edges = [(n + i, n + i + 1) for i in range(5)] |
| 480 | motif_edges.append((n + 5, n)) |
| 481 | motif_src, motif_dst = map(list, zip(*motif_edges)) |
| 482 | src.extend(motif_src) |
| 483 | dst.extend(motif_dst) |
| 484 | |
| 485 | # Nodes in cycles belong to class 1 |
| 486 | node_labels.extend([1] * self.cycle_size) |
| 487 | |
| 488 | # Attach the motif to the base tree graph |
| 489 | anchor = int(motif_id * spacing) |
| 490 | src.append(n) |
| 491 | dst.append(anchor) |
| 492 | |
| 493 | if np.random.random() > 0.5: |
| 494 | a = np.random.randint(1, 4) |
| 495 | b = np.random.randint(1, 4) |
| 496 | src.append(n + a) |
| 497 | dst.append(anchor + b) |
| 498 | |
| 499 | n += self.cycle_size |
| 500 | |
| 501 | g = graph((src, dst), num_nodes=n) |
| 502 | |
| 503 | # Perturb the graph by adding non-self-loop random edges |
| 504 | num_real_edges = g.num_edges() |
| 505 | max_ratio = (n * (n - 1) - num_real_edges) / num_real_edges |
| 506 | assert ( |
| 507 | self.perturb_ratio <= max_ratio |
| 508 | ), "perturb_ratio cannot exceed {:.4f}".format(max_ratio) |
| 509 | num_random_edges = int(num_real_edges * self.perturb_ratio) |
| 510 | |
| 511 | for _ in range(num_random_edges): |
| 512 | while True: |
| 513 | u = np.random.randint(0, n) |
| 514 | v = np.random.randint(0, n) |
| 515 | if (not g.has_edges_between(u, v)) and (u != v): |
| 516 | break |
| 517 | g.add_edges(u, v) |
| 518 | |
| 519 | g.ndata["label"] = F.tensor(node_labels, F.int64) |
| 520 | g.ndata["feat"] = F.ones((n, 1), F.float32, F.cpu()) |
nothing calls this directly
no test coverage detected