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

ReDKG: fix dependencies and add new tests #33

Merged
merged 17 commits into from
Jan 15, 2025
Merged
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
8 changes: 3 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9"]
python-version: ["3.10"]

steps:
- uses: actions/checkout@v3
Expand All @@ -25,10 +25,8 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov wheel
pip install torch==1.12.0+cpu torchvision==0.13.0+cpu torchaudio==0.12.0 --extra-index-url https://download.pytorch.org/whl/cpu
pip install pyg-lib -f https://data.pyg.org/whl/torch-1.12.0+cpu.html
pip install torch-scatter torch-sparse
pip install torch-geometric
pip install git+https://github.com/pyg-team/pytorch_geometric.git
pip install torch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 --extra-index-url https://download.pytorch.org/whl/cpu
pip install .
- name: Test with pytest
run: |
Expand Down
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,21 @@

На первом шаге необходимо выполнить установку библиотеки, [Pytorch Geometric](https://github.com/pyg-team/pytorch_geometric/) и Torch 1.1.2.

```
pip install -q git+https://github.com/pyg-team/pytorch_geometric.git
```

### PyTorch 1.12

```
# CUDA 10.2
conda install pytorch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 cudatoolkit=10.2 -c pytorch
# CUDA 11.3
conda install pytorch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 cudatoolkit=11.3 -c pytorch
# CUDA 11.6
conda install pytorch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 cudatoolkit=11.6 -c pytorch -c conda-forge
# CUDA 11.8
conda install pytorch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 pytorch-cuda=11.8 -c pytorch -c nvidia
# CUDA 12.1
conda install pytorch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 pytorch-cuda=12.1 -c pytorch -c nvidia
# CUDA 12.4
conda install pytorch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 pytorch-cuda=12.4 -c pytorch -c nvidia
# CPU Only
conda install pytorch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 cpuonly -c pytorch
conda install pytorch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 cpuonly -c pytorch
```

После установки необходимых библиотек необходимо скопировать репозиторий и выполнить следующую команду, находясь в
Expand Down Expand Up @@ -123,7 +127,7 @@ labels = torch.tensor(list(range(len(graph_data['nodes']))), dtype=torch.long)

large_dataset = Data(x=features, edge_index=edge_index, y=labels, node_mapping=node_mapping, node_index=node_index)
torch.save(large_dataset, 'large_dataset.pth')
large_dataset.cuda()
# large_dataset.cuda() # Если есть cuda ядра
```

Далее необходимо сгенерировать подграфы для обучения модели. Для этого можно использовать следующий код:
Expand Down
98 changes: 82 additions & 16 deletions raw_bellman_ford/algorithms/coverage_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@

import numpy as np


class HypergraphCoverageSolver:
"""
HypergraphCoverageSolver class.

Provides tools for working with hypergraphs, including distance computation, weight handling,
and coverage checks.

Attributes:
- nodes, edges, hyperedges: Lists of nodes, ordinary edges, and hyperedges.
- node_types, edge_weights, hyperedge_weights, hyperedge_types: Dictionaries for types and weights.

Methods:
- get_edge_weight(edge): Gets the weight of an edge.
- get_hyperedge_weight(hyperedge): Gets the weight of a hyperedge.
- compute_shortest_distances(): Returns the shortest distance matrix.
- print_distance_matrix(): Prints the distance matrix.
- can_cover_with_drone(drone_radius): Checks coverage feasibility for a given radius.
"""

def __init__(self, nodes, edges, hyperedges, node_types, edge_weights, hyperedge_weights, hyperedge_types):
"""
Initializes the HypergraphCoverageSolver object.
Expand Down Expand Up @@ -61,7 +80,7 @@ def compute_shortest_distances(self):
hyperedge_index = {hyperedge: num_nodes + i for i, hyperedge in enumerate(self.hyperedges)}

distance_matrix = np.zeros((num_nodes + num_hyperedges, num_nodes + num_hyperedges))
distance_matrix.fill(float('inf'))
distance_matrix.fill(float("inf"))
np.fill_diagonal(distance_matrix, 0)

for edge in self.edges:
Expand All @@ -70,8 +89,8 @@ def compute_shortest_distances(self):
u = hyperedge_index[u]
if isinstance(v, tuple):
v = hyperedge_index[v]
distance_matrix[u-1, v-1] = self.get_edge_weight(edge)
distance_matrix[v-1, u-1] = self.get_edge_weight(edge)
distance_matrix[u - 1, v - 1] = self.get_edge_weight(edge)
distance_matrix[v - 1, u - 1] = self.get_edge_weight(edge)

for hyperedge in self.hyperedges:
hyperedge_index_value = hyperedge_index[hyperedge]
Expand All @@ -89,9 +108,7 @@ def compute_shortest_distances(self):
return distance_matrix

def print_distance_matrix(self):
"""
Prints the matrix of shortest distances.
"""
"""Prints the matrix of shortest distances."""
print("Full Distance Matrix:")
for i, row in enumerate(self.compute_shortest_distances()):
node_or_hyperedge = f"gv{i + 1}" if i < len(self.nodes) else f"he{i + 1 - len(self.nodes)}"
Expand All @@ -110,7 +127,7 @@ def can_cover_with_drone(self, drone_radius):
distance_matrix = self.compute_shortest_distances()
for i, node in enumerate(self.nodes):
if self.node_types[node] == 1: # Hyper-hyperedge
diameter_within_hyperedge = np.max(distance_matrix[i, :len(self.nodes)])
diameter_within_hyperedge = np.max(distance_matrix[i, : len(self.nodes)])
if diameter_within_hyperedge > drone_radius:
return False
elif distance_matrix[i, i] > drone_radius:
Expand All @@ -119,6 +136,25 @@ def can_cover_with_drone(self, drone_radius):


class HypergraphMetricsCalculator:
"""
HypergraphMetricsCalculator class.

Calculates various metrics for a hypergraph based on its distance matrix.

Attributes:
- distance_matrix: Matrix representing distances in the hypergraph.

Methods:
- eccentricity(node): Calculates the eccentricity of a node.
- radius(): Computes the hypergraph radius.
- diameter(): Computes the hypergraph diameter.
- central_nodes(): Finds central nodes based on radius.
- peripheral_nodes(): Identifies peripheral nodes based on diameter.
- closeness_centrality(node): Computes the closeness centrality of a node.
- betweenness_centrality(node): Computes the betweenness centrality of a node.
- degree_centrality(node): Computes the degree centrality of a node.
"""

def __init__(self, distance_matrix):
"""
Initializes the HypergraphMetricsCalculator object.
Expand Down Expand Up @@ -171,7 +207,11 @@ def central_nodes(self):
- List of central nodes.
"""
min_eccentricity = self.radius()
central_nodes = [i + 1 for i, eccentricity in enumerate(np.max(self.distance_matrix, axis=1)) if eccentricity == min_eccentricity]
central_nodes = [
i + 1
for i, eccentricity in enumerate(np.max(self.distance_matrix, axis=1))
if eccentricity == min_eccentricity
]
return central_nodes

def peripheral_nodes(self):
Expand All @@ -182,7 +222,11 @@ def peripheral_nodes(self):
- List of peripheral nodes.
"""
max_eccentricity = np.max(np.max(self.distance_matrix, axis=1))
peripheral_nodes = [i + 1 for i, eccentricity in enumerate(np.max(self.distance_matrix, axis=1)) if eccentricity == max_eccentricity]
peripheral_nodes = [
i + 1
for i, eccentricity in enumerate(np.max(self.distance_matrix, axis=1))
if eccentricity == max_eccentricity
]
return peripheral_nodes

def closeness_centrality(self, node):
Expand Down Expand Up @@ -217,8 +261,17 @@ def betweenness_centrality(self, node):
for k in range(len(self.distance_matrix)):
for i in range(len(self.distance_matrix)):
for j in range(len(self.distance_matrix)):
if i != j and i != k and j != k and self.distance_matrix[i, j] != np.inf and self.distance_matrix[i, k] != 0 and self.distance_matrix[k, j] != 0:
betweenness_values[i, j] += (self.distance_matrix[i, k] + self.distance_matrix[k, j]) / self.distance_matrix[i, j]
if (
i != j
and i != k
and j != k
and self.distance_matrix[i, j] != np.inf
and self.distance_matrix[i, k] != 0
and self.distance_matrix[k, j] != 0
):
betweenness_values[i, j] += (
self.distance_matrix[i, k] + self.distance_matrix[k, j]
) / self.distance_matrix[i, j]

betweenness_centrality = np.sum(betweenness_values) / 2
return betweenness_centrality if not np.isinf(betweenness_centrality) else 0
Expand All @@ -234,17 +287,28 @@ def degree_centrality(self, node):
- Degree centrality value.
"""
return np.sum(self.distance_matrix[node - 1] != np.inf) / (len(self.distance_matrix) - 1)



if __name__ == "__main__":
nodes = [1, 2, 3, 4, 5, 6]
edges = [(1, 2), (2, 3),(1, 4), (3, 4), ((1, 2, 3, 4), 5), ((1, 2, 3, 4), 6), (5, 6)]
edges = [(1, 2), (2, 3), (1, 4), (3, 4), ((1, 2, 3, 4), 5), ((1, 2, 3, 4), 6), (5, 6)]
hyperedges = [(1, 2, 3, 4)]
node_types = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
edge_weights = {(1, 2): 0.6, (2, 3): 0.5, (3, 4): 0.6, (1, 4): 0.5, ((1, 2, 3, 4), 5): 0.2, ((1, 2, 3, 4), 6): 0.8, (5, 6): 0.7}
edge_weights = {
(1, 2): 0.6,
(2, 3): 0.5,
(3, 4): 0.6,
(1, 4): 0.5,
((1, 2, 3, 4), 5): 0.2,
((1, 2, 3, 4), 6): 0.8,
(5, 6): 0.7,
}
hyperedge_weights = {(1, 2, 3, 4): 0.6}
hyperedge_types = {(1, 2, 3, 4): 1}

hypergraph_solver = HypergraphCoverageSolver(nodes, edges, hyperedges, node_types, edge_weights, hyperedge_weights, hyperedge_types)
hypergraph_solver = HypergraphCoverageSolver(
nodes, edges, hyperedges, node_types, edge_weights, hyperedge_weights, hyperedge_types
)
hypergraph_solver.print_distance_matrix()

distance_matrix = hypergraph_solver.compute_shortest_distances()
Expand All @@ -266,7 +330,9 @@ def degree_centrality(self, node):
print(f"Peripheral Nodes: {metrics_calculator.peripheral_nodes()}")

drone_radius = 1.0 # Drone radius
coverage_solver = HypergraphCoverageSolver(nodes, edges, hyperedges, node_types, edge_weights, hyperedge_weights, hyperedge_types)
coverage_solver = HypergraphCoverageSolver(
nodes, edges, hyperedges, node_types, edge_weights, hyperedge_weights, hyperedge_types
)
can_cover = coverage_solver.can_cover_with_drone(drone_radius)

if can_cover:
Expand Down
Loading
Loading