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

KeyError in Edge Categorical and Edge Numerical Compartments #253

Closed
neserende opened this issue Mar 25, 2024 · 0 comments
Closed

KeyError in Edge Categorical and Edge Numerical Compartments #253

neserende opened this issue Mar 25, 2024 · 0 comments

Comments

@neserende
Copy link
Contributor

Describe the bug
When working with a random regular graph generated by networkx, sometimes edges are listed as (large number, small number). Example: (30, 5) instead of (5, 30). This type of data can also come when network is read from a file input. In the edge categorical attribute and edge numerical attribute compartments, a key error occurs when this case happens.

In edge categorical attribute:

def execute(self, node, graph, status, status_map, *args, **kwargs):
        neighbors = list(graph.neighbors(node))
        if isinstance(graph, nx.DiGraph):
            neighbors = list(graph.predecessors(node))

        edge_attr = graph.get_edge_attributes(self.attribute)

        if self.trigger is not None:
            triggered = [v for v in neighbors if status[v] == status_map[self.trigger] and
                         edge_attr[(min([node, v]), max([node, v]))] == self.attribute_value]

Here, edge_attr holds a category ('co-worker') for (30, 5) but edge_attr[(min([node, v]), max([node, v]))] tries to reach (5, 30) which does not exist and results in the following key error:

File "C:\Users\NESE\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\ndlib\models\compartments\EdgeCategoricalAttribute.py", line 32, in
edge_attr[(min([node, v]), max([node, v]))] == self.attribute_value]
KeyError: (5, 30)

In node categorical attribute:


    def execute(self, node, graph, status, status_map, *args, **kwargs):

        neighbors = list(graph.neighbors(node))
        if isinstance(graph, nx.DiGraph):
            neighbors = list(graph.predecessors(node))

        edge_attr = graph.get_edge_attributes(self.attribute)

        triggered = []

        if self.trigger is not None:
            for v in neighbors:
                if status[v] == status_map[self.trigger]:
                    val = edge_attr[(min([node, v]), max([node, v]))]
                    if self.operator == "IN":
                        if self.__available_operators[self.operator][0](val, self.attribute_range[0]) and \
                                    self.__available_operators[self.operator][1](val, self.attribute_range[1]):
                            triggered.append(v)
                    else:
                        if self.__available_operators[self.operator](val, self.attribute_range):
                            triggered.append(v)
        else:
            for v in neighbors:
                val = edge_attr[(min([node, v]), max([node, v]))]

Here, edge_attr dictionary is accessed in a similar manner and a key error occurs again:

File "C:\Users\NESE\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\ndlib\models\compartments\EdgeNumericalAttribute.py", line 63, in execute
val = edge_attr[(min([node, v]), max([node, v]))]
KeyError: (23, 68)

To Reproduce
Steps to reproduce the behavior:

  • NDlib version: v5.1.1
  • Operating System: Windows
  • Python version: 3.9
  • Version(s) of NDlib required libraries: Version installed with ndlib v5.1.1

Expected behavior
Before accessing edge_attr dictionary, if (5, 30) key does not exist, we should access (30, 5) instead.

Additional context
The code I used to test edge categorical compartments:

import random
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments as cpm
import networkx as nx
import ndlib.models.ModelConfig as mc


# Network generation
#A regular graph is a graph where each node has the same number of neighbors.
#Here we create a random graph with 100 nodes where each node has a degree of 4
g = nx.random_regular_graph(4, 100) 

# Setting edge attribute
attr = {(u, v): {"type": random.choice(['co-worker', 'family'])} for (u, v) in g.edges()}
nx.set_edge_attributes(g, attr)

# Composite Model instantiation
model = gc.CompositeModel(g)

# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")

# Compartment definition
c1 = cpm.EdgeCategoricalAttribute("type", "family", probability = 0.06, triggering_status="Susceptible")

# Rule definition
model.add_rule("Susceptible", "Infected", c1)

# Model initial status configurations
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)

# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(10)

trends = model.build_trends(iterations)

print(trends)

The code I used to test edge numerical compartments:


import random
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments as cpm
import networkx as nx
import ndlib.models.ModelConfig as mc


# Network generation
#A regular graph is a graph where each node has the same number of neighbors.
#Here we create a random graph with 100 nodes where each node has a degree of 4
g = nx.random_regular_graph(4, 100) 

# Setting edge attribute
attr = {(u, v): {"weight": int((u+v) % 10)} for (u, v) in g.edges()}
nx.set_edge_attributes(g, attr)

# Composite Model instantiation
model = gc.CompositeModel(g)

# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")

# Compartment definition
c1 = cpm.EdgeNumericalAttribute("weight", value=4, op="==", probability=0.6)

# Rule definition
model.add_rule("Susceptible", "Infected", c1)

# Model initial status configurations
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)

# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(10)

trends = model.build_trends(iterations)

print(trends)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant