Skip to content

Commit

Permalink
candidate_selection (#4)
Browse files Browse the repository at this point in the history
* nodes selection algorithm

* nodes selection algorithm, added new centrality based on netcenlib

* code cleanup
  • Loading branch information
damianfraszczak authored Oct 11, 2024
1 parent 465a71b commit 5628dc4
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 13 deletions.
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def find_version(*path_parts):
version=find_version("src", "nsdlib", "version.py"),
license="MIT",
description="Network source detection library",
url="https://github.com/damianfraszczak/nclib",
url="https://github.com/damianfraszczak/nsdlib",
author="Damian Frąszczak, Edyta Frąszczak",
author_email="[email protected]",
classifiers=[
Expand All @@ -41,7 +41,7 @@ def find_version(*path_parts):
"Programming Language :: Python",
"Programming Language :: Python :: 3",
],
keywords="node_importance centrality_measures centrality complex-networks",
keywords="propagation-source-detection outbreaks-detection propagation-reconstruction complex-networks",
install_requires=[
"networkx>=3.0",
"numpy",
Expand Down
2 changes: 1 addition & 1 deletion src/nsdlib/algorithms/evaluation/jordan_center.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def jordan_center(network: Graph) -> Dict[int, float]:
----------
- [1] L. Ying and K. Zhu,
"On the Universality of Jordan Centers for Estimating Infection Sources
in Tree Networks" IEEE Transactions of Information Theory, 2017
in Tree Networks" IEEE Transactions of Information Theory, 2014
- [2] L. Ying and K. Zhu,
"Diffusion Source Localization in Large Networks"
Synthesis Lectures on Communication Networks, 2018
Expand Down
25 changes: 19 additions & 6 deletions src/nsdlib/common/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,38 @@
NODE_TYPE = Union[int, str]


@dataclass
class SelectionAlgorithm:
selection_method: Optional[NodeEvaluationAlgorithm] = None
selection_threshold: Optional[float] = None

def __post_init__(self):
if self.selection_threshold is not None and not (
0 <= self.selection_threshold <= 1
):
raise ValueError("selection_threshold must be None or between 0 and 1.")
if self.selection_method and self.selection_threshold:
raise ValueError(
"selection_method and selection_threshold cannot be used together."
)


@dataclass
class SourceDetectionConfig:
"""Source detection configuration."""

# for None, only one with the highest score will be selected
selection_threshold: Optional[float] = None
node_evaluation_algorithm: NodeEvaluationAlgorithm = (
NodeEvaluationAlgorithm.CENTRALITY_DEGREE
)
selection_algorithm: Optional[SelectionAlgorithm] = None
outbreaks_detection_algorithm: Optional[OutbreaksDetectionAlgorithm] = None
propagation_reconstruction_algorithm: Optional[
PropagationReconstructionAlgorithm
] = None

def __post_init__(self):
if self.selection_threshold is not None and not (
0 <= self.selection_threshold <= 1
):
raise ValueError("selection_threshold must be None or between 0 and 1.")
if not self.selection_algorithm:
self.selection_algorithm = SelectionAlgorithm()


@dataclass
Expand Down
41 changes: 37 additions & 4 deletions src/nsdlib/source_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def detect_sources(self, IG: Graph, G: Graph) -> SourceDetectionResult:
outbreaks = self._detect_outbreaks(IG)
scores_in_outbreaks = self._evaluate_outbreaks(outbreaks)
global_scores = self._get_global_scores(scores_in_outbreaks)
detected_sources = self._select_sources(scores_in_outbreaks)
detected_sources = self._select_sources(IG, scores_in_outbreaks)
return SourceDetectionResult(
config=self.config,
G=G,
Expand Down Expand Up @@ -102,10 +102,41 @@ def _evaluate_outbreaks(
)
return scores

def _select_sources(self, outbreaks_evaluation: List[Dict[NODE_TYPE, float]]):
def _select_sources(
self, IG: Graph, outbreaks_evaluation: List[Dict[NODE_TYPE, float]]
):
sources = []
for outbreak_evaluation in outbreaks_evaluation:
if self.config.selection_threshold is None:
if self.config.selection_algorithm.selection_method:
max_score = max(outbreak_evaluation.values())
nodes_with_higher_score = [
node
for node, score in outbreak_evaluation.items()
if score == max_score
]
if len(nodes_with_higher_score) == 1:
sources.append(nodes_with_higher_score[0])
else:
outbreak_nodes = list(outbreak_evaluation.keys())
subgraph = IG.subgraph(outbreak_nodes)
selection_evaluation = evaluate_nodes_cached(
network=subgraph,
evaluation_alg=self.config.selection_algorithm.selection_method,
)
filtered_second_evaluation = {
node: selection_evaluation[node]
for node in nodes_with_higher_score
}
max_second_score = max(filtered_second_evaluation.values())
sources.extend(
[
node
for node, score in filtered_second_evaluation.items()
if score == max_second_score
]
)

elif self.config.selection_algorithm.selection_threshold is None:
sources.append(max(outbreak_evaluation, key=outbreak_evaluation.get))
else:
outbreaks_evaluation_normalized = normalize_dict_values(
Expand All @@ -116,9 +147,11 @@ def _select_sources(self, outbreaks_evaluation: List[Dict[NODE_TYPE, float]]):
[
node
for node, evaluation in outbreaks_evaluation_normalized.items()
if evaluation >= self.config.selection_threshold
if evaluation
>= self.config.selection_algorithm.selection_threshold
]
)

return sources


Expand Down
1 change: 1 addition & 0 deletions src/nsdlib/taxonomies.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class NodeEvaluationAlgorithm(Enum):
CENTRALITY_DECAY = "decay_centrality"
CENTRALITY_DEGREE = "degree_centrality"
CENTRALITY_DIFFUSION_DEGREE = "diffusion_degree_centrality"
CENTRALITY_ECCENTRICITY = "eccentricity_centrality"
CENTRALITY_EIGENVECTOR = "eigenvector_centrality"
CENTRALITY_ENTROPY = "entropy_centrality"
CENTRALITY_GEODESTIC_K_PATH = "geodestic_k_path_centrality"
Expand Down

0 comments on commit 5628dc4

Please sign in to comment.