def attack(self, num_budgets=0.05, dim=32, window_size=5, K=100, attack_type="add_by_remove", structure_attack=True, feature_attack=False): if not attack_type in ["remove", "add", "add_by_remove"]: raise RuntimeError( 'attack_type should be one of "remove", "add", "add_by_remove".' ) super().attack(num_budgets, structure_attack, feature_attack) num_budgets = self.num_budgets adj = self.graph.adj_matrix if attack_type.startswith("add"): num_candidates = min(5 * num_budgets, self.num_edges) # num_candidates = 10000 candidates = self.generate_candidates_addition(adj, num_candidates) else: candidates = self.generate_candidates_removal(adj) if attack_type == "add_by_remove": adj = gf.flip_adj(adj, candidates) deg_matrix = sp.diags(adj.sum(1).A1, dtype=adj.dtype) if K: vals_org, vecs_org = sp.linalg.eigsh(adj, k=K, M=deg_matrix) else: vals_org, vecs_org = spl.eigh(adj.toarray(), deg_matrix.toarray()) delta_w = 1. - 2 * adj[candidates[:, 0], candidates[:, 1]].A1 loss_for_candidates = estimate_loss_with_delta_eigenvals( candidates, delta_w, vals_org, vecs_org, self.num_nodes, dim, window_size) self.adj_flips = candidates[loss_for_candidates.argsort() [:num_budgets]] else: # vector indicating whether we are adding an edge (+1) or removing an edge (-1) delta_w = 1. - 2 * adj[candidates[:, 0], candidates[:, 1]].A1 deg_matrix = sp.diags(adj.sum(1).A1, dtype=adj.dtype) if K: vals_org, vecs_org = sp.linalg.eigsh(adj, k=K, M=deg_matrix) else: vals_org, vecs_org = spl.eigh(adj.toarray(), deg_matrix.toarray()) loss_for_candidates = estimate_loss_with_delta_eigenvals( candidates, delta_w, vals_org, vecs_org, self.num_nodes, dim, window_size) self.adj_flips = candidates[loss_for_candidates.argsort() [-num_budgets:]] return self
def from_flips(self, **flips): """Return a new graph from: 'edge_flips' or 'feat_flips' """ allowed = ("edge_flips", "feat_flips") g = self.copy() for k, v in flips.items(): if v is None: continue if k == "edge_flips": g.update(adj_matrix=gf.flip_adj(g.adj_matrix, v)) elif k == "feat_flips": g.update(attr_matrix=gf.flip_attr(g.attr_matrix, v)) else: raise ValueError(f"Unrecognized key {k}, allowed: {allowed}.") return g
def A(self): adj_flips = self.edge_flips if self.modified_adj is None: if adj_flips is not None: self.modified_adj = gf.flip_adj(self.graph.adj_matrix, adj_flips) else: self.modified_adj = self.graph.adj_matrix adj = self.modified_adj if gf.is_anytensor(adj): adj = gf.tensoras(adj) if isinstance(adj, np.ndarray): adj = sp.csr_matrix(adj) elif sp.isspmatrix(adj): adj = adj.tocsr(copy=False) else: raise TypeError(adj) return adj