Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using graph-tool #1

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 4 additions & 83 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# network-dismantling

`network-dismantling` is a library for network dismantling, which refers to the process of strategically removing nodes from a network to disrupt its functionality. This repository provides implementations of various network dismantling algorithms, leveraging the power of PyTorch for efficient computation and flexibility.
`network-dismantling` is a framework for network dismantling, which refers to the process of strategically removing nodes from a network to disrupt its functionality. This repository provides implementations of various network dismantling algorithms, leveraging the power of PyTorch for efficient computation and flexibility.

## Installation

Expand All @@ -10,14 +10,11 @@ To install the dependencies, easily install from PyPI:
pip install network-dismantling
```

Make sure you have PyTorch installed if you want to run a neural-network model.
Make sure you have PyTorch and graph-tool installed if you want to run a neural-network model.

You can install PyTorch from [here](https://pytorch.org/get-started/locally/).

Or directly using conda:

```bash
conda install network-dismantling
```
You can install graph-tool from [here](https://graph-tool.skewed.de/installation.html).

Alternatively, you can clone the repository and install it locally:

Expand All @@ -29,83 +26,7 @@ pip install -e .

## Usage

```python
# Create a test graph
G = nx.karate_club_graph()

# Initialize CoreHD strategies
corehd_strategy = CoreHDDismantling()

# Create NetworkDismantlers with different strategies
corehd_dismantler = NetworkDismantler(corehd_strategy)

# Dismantle the graph using both strategies
num_nodes_to_remove = int(G.number_of_nodes() * 0.1) # Remove 10% of nodes

dismantled_G_corehd, removed_nodes_corehd = corehd_dismantler.dismantle(G, num_nodes_to_remove)

print(f"Original graph: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges")
print(f"CoreHD dismantled graph: {dismantled_G_corehd.number_of_nodes()} nodes, {dismantled_G_corehd.number_of_edges()} edges")
print(f"CoreHD removed nodes: {removed_nodes_corehd}")
```

```python
G = nx.karate_club_graph()

# Initialize CoreGDM strategy
coregdm_strategy = CoreGDMDismantling()

# Create NetworkDismantler with CoreGDM strategy
coregdm_dismantler = NetworkDismantler(coregdm_strategy)

# Dismantle the graph using CoreGDM
num_nodes_to_remove = int(G.number_of_nodes() * 0.1) # Remove 10% of nodes

dismantled_G_coregdm, removed_nodes_coregdm = coregdm_dismantler.dismantle(G, num_nodes_to_remove)

print(f"Original graph: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges")
print(f"CoreGDM dismantled graph: {dismantled_G_coregdm.number_of_nodes()} nodes, {dismantled_G_coregdm.number_of_edges()} edges")
print(f"CoreGDM removed nodes: {removed_nodes_coregdm}")
```

```python
# Create a test graph
G = nx.karate_club_graph()

# Initialize different dismantling strategies
dismantling_strategies = [
CollectiveInfluenceDismantling(l=2),
ExplosiveImmunizationDismantling(q=0.1, num_iterations=10),
CoreGDMDismantling(),
GNDDismantling(),
CoreHDDismantling()
]

# Initialize evaluation metrics
metrics = [
LCCSizeMetric(),
NumComponentsMetric(),
AvgPathLengthMetric(),
GlobalEfficiencyMetric(),
AvgClusteringMetric()
]

# Choose evaluation strategy
evaluation_strategy = RelativeChangeStrategy()

# Create evaluator
evaluator = DismantlingEvaluator(metrics, evaluation_strategy)

# Compare strategies
num_nodes_to_remove = int(G.number_of_nodes() * 0.1) # Remove 10% of nodes
comparison_results = DismantlingEvaluator.compare_strategies(G, dismantling_strategies, num_nodes_to_remove, evaluator)

# Print detailed results
for strategy_name, metrics in comparison_results.items():
print(f"\n{strategy_name}:")
for metric, value in metrics.items():
print(f" {metric}: {value:.4f}")
```

## Documentation

Expand Down
7 changes: 4 additions & 3 deletions examples/heuristic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import networkx as nx
import graph_tool.all as gt

from network_dismantling.node_selectors import (
CollectiveInfluence,
ExplosiveImmunization,
Expand All @@ -19,7 +20,7 @@
# Example usage
if __name__ == "__main__":
# Create a test graph
G = nx.karate_club_graph()
G = gt.collection.data["karate"]

# Initialize different dismantling strategies
dismantlers = [
Expand Down Expand Up @@ -48,7 +49,7 @@
evaluator = DismantlingEvaluator(metrics, evaluation_strategy)

# Compare strategies
num_nodes_to_remove = int(G.number_of_nodes() * 0.1) # Remove 10% of nodes
num_nodes_to_remove = int(G.num_vertices() * 0.1) # Remove 10% of nodes
comparison_results = DismantlingEvaluator.compare_strategies(
G, dismantlers, num_nodes_to_remove, evaluator
)
Expand Down
55 changes: 50 additions & 5 deletions network_dismantling/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
from .dismantler import DismantlingStrategy, NetworkDismantler
from .operators.operator import DismantlingOperator
from .selector import ElementSelector
from network_dismantling.dismantler import DismantlingStrategy, NetworkDismantler
from network_dismantling.operators.operator import DismantlingOperator
from network_dismantling.selector import ElementSelector


def require_gt():
"""
Check graph-tool is installed
"""
try:
import graph_tool.all as gt

_ = gt
except ImportError as exc:
raise ImportError(
"Please install graph-tool to use network_dismantling. You can install it as the instructions in https://graph-tool.skewed.de/installation.html"
) from exc


def require_pytorch():
"""
Check PyTorch is installed
"""
try:
import torch

_ = torch
except ImportError as exc:
raise ImportError(
"Please install PyTorch to use network_dismantling. You can install it as the instructions in https://pytorch.org/get-started/locally/"
) from exc


def require_pyg():
"""
Check PyTorch Geometric is installed
"""
try:
import torch_geometric

_ = torch_geometric
except ImportError as exc:
raise ImportError(
"Please install PyTorch Geometric to use network_dismantling. You can install it as the instructions in https://pytorch-geometric.readthedocs.io/en/latest/notes/installation.html"
) from exc


require_gt()
require_pytorch()
require_pyg()

__all__ = [
"DismantlingStrategy",
"NetworkDismantler",
"EvaluationMetric",
"EvaluationStrategy",
"DismantlingOperator",
"ElementSelector",
]
7 changes: 3 additions & 4 deletions network_dismantling/dismantler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import networkx as nx
import graph_tool.all as gt
from abc import abstractmethod
from typing import Any, List, Tuple
import torch.nn as nn
Expand All @@ -15,15 +15,14 @@ class DismantlingStrategy(nn.Module):
"""

@abstractmethod
def dismantle(self, G: nx.Graph, num_nodes: int) -> List[int]:
def dismantle(self, G: gt.Graph, num_nodes: int) -> List[int]:
"""
Dismantle the graph by removing nodes.

:param G: The input graph
:param num_nodes: Number of nodes to remove
:return: List of node IDs to remove
"""
pass


class NetworkDismantler:
Expand All @@ -44,7 +43,7 @@ def __init__(self, selector: ElementSelector, operator: DismantlingOperator):
self.selector = selector
self.operator = operator

def dismantle(self, G: nx.Graph, num_elements: int) -> Tuple[nx.Graph, List[Any]]:
def dismantle(self, G: gt.Graph, num_elements: int) -> Tuple[gt.Graph, List[Any]]:
"""
Dismantle the graph by removing elements.

Expand Down
2 changes: 1 addition & 1 deletion network_dismantling/edge_selectors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .edge_selector import EdgeSelector
from network_dismantling.edge_selectors.edge_selector import EdgeSelector

__all__ = ["EdgeSelector"]
8 changes: 3 additions & 5 deletions network_dismantling/edge_selectors/edge_selector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import networkx as nx

import graph_tool.all as gt
from abc import abstractmethod
from typing import Any, List, Tuple
from network_dismantling.selector import ElementSelector
Expand All @@ -13,12 +12,11 @@ class EdgeSelector(ElementSelector):
"""

@abstractmethod
def select(self, G: nx.Graph, num_edges: int) -> List[Tuple[Any, Any]]:
def select(self, G: gt.Graph, num_elements: int) -> List[Tuple[Any, Any]]:
"""
Select edges from the graph.

:param G: The input graph
:param num_edges: Number of edges to select
:param num_elements: Number of edges to select
:return: List of selected edges
"""
pass
8 changes: 4 additions & 4 deletions network_dismantling/evaluators/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .avg_clustering import AvgClusteringMetric
from .avg_path_length import AvgPathLengthMetric
from .global_effiency import GlobalEfficiencyMetric
from .evaluator import (
from network_dismantling.evaluators.avg_clustering import AvgClusteringMetric
from network_dismantling.evaluators.avg_path_length import AvgPathLengthMetric
from network_dismantling.evaluators.global_effiency import GlobalEfficiencyMetric
from network_dismantling.evaluators.evaluator import (
EvaluationMetric,
EvaluationStrategy,
RelativeChangeStrategy,
Expand Down
8 changes: 4 additions & 4 deletions network_dismantling/evaluators/avg_clustering.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import networkx as nx

import graph_tool.all as gt

from network_dismantling.evaluators.evaluator import EvaluationMetric

Expand All @@ -12,14 +11,15 @@ class AvgClusteringMetric(EvaluationMetric):
The average clustering coefficient is the average of the clustering coefficients of all nodes in the graph.
"""

def compute(self, G: nx.Graph) -> float:
def compute(self, G: gt.Graph) -> float:
"""
Compute the average clustering coefficient of the graph.

:param G: The graph.
:return: The average clustering coefficient of the graph.
"""
return nx.average_clustering(G)
clustering = gt.local_clustering(G)
return clustering.a.mean()

@property
def name(self) -> str:
Expand Down
9 changes: 5 additions & 4 deletions network_dismantling/evaluators/avg_path_length.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import networkx as nx
import graph_tool.all as gt


from network_dismantling.evaluators.evaluator import EvaluationMetric
Expand All @@ -12,15 +12,16 @@ class AvgPathLengthMetric(EvaluationMetric):
length is the average of the shortest path lengths between all pairs of nodes in the graph.
"""

def compute(self, G: nx.Graph) -> float:
def compute(self, G: gt.Graph) -> float:
"""
Compute the average path length of the graph.

:param G: The graph.
:return: The average path length of the graph.
"""
lcc = max(nx.connected_components(G), key=len)
return nx.average_shortest_path_length(G.subgraph(lcc))
lcc = gt.extract_largest_component(G)
distances = gt.shortest_distance(lcc)
return distances[distances != float("inf")].a.mean()

@property
def name(self) -> str:
Expand Down
Loading