Source code for multilevelgraphs.contraction_schemes.edge_based_contraction_scheme
from abc import ABC, abstractmethod
from typing import Callable, Dict, Any, Set
from multilevelgraphs.dec_graphs import DecGraph, Supernode, Superedge
from multilevelgraphs.contraction_schemes import ContractionScheme, CompTable, ComponentSet
[docs]class EdgeBasedContractionScheme(ContractionScheme, ABC):
"""
An abstract class for edge-based contraction schemes.
An EdgeBasedContractionScheme is a ContractionScheme where two supernodes being part of the same connected component
is a necessary condition for them to be part of the same component set.
In other words, in an edge-based contraction scheme, if a single node has no incident edges, it must reside in
a singleton component set.
Examples of edge-based contraction schemes are the SCCs, Cycles and Cliques contraction schemes, where
component sets are formed based on the connection between supernodes.
Example of non-edge-based contraction schemes are the independent sets contraction scheme, where component sets
are formed based on the absence of edges between supernodes.
This abstract class provides implementations for two of the update procedures defined in the ContractionScheme
class: ``_update_added_node`` and ``_update_removed_node``. The other update procedures, ``_update_added_edge``
and ``_update_removed_edge``, are abstract and should be implemented by the subclasses as they depend on the
specific contraction scheme.
"""
[docs] def __init__(self,
supernode_attr_function: Callable[[Supernode], Dict[str, Any]] = None,
superedge_attr_function: Callable[[Superedge], Dict[str, Any]] = None,
c_set_attr_function: Callable[[Set[Supernode]], Dict[str, Any]] = None):
super().__init__(supernode_attr_function, superedge_attr_function, c_set_attr_function)
[docs] @abstractmethod
def contraction_name(self) -> str:
pass
[docs] @abstractmethod
def clone(self):
pass
[docs] @abstractmethod
def contraction_function(self, dec_graph: DecGraph) -> CompTable:
pass
def _update_added_node(self, node: Supernode):
# A new dummy supernode is created for the new node, in order to provide a temporary supernode for the new node
# during following update procedures before the _update_graph procedure.
new_c_set = ComponentSet(self._get_component_set_id(), {node}, **(self._c_set_attr_function({node})))
self.component_sets_table.add_set(new_c_set)
f_c_set = frozenset(self.component_sets_table[node])
dummy_supernode = Supernode(self._get_supernode_id(), level=self.level, component_sets=f_c_set)
dummy_supernode.add_node(node)
node.supernode = dummy_supernode
self.update_quadruple.add_v_plus(dummy_supernode)
self.dec_graph.add_node(dummy_supernode)
# The supernode is intentionally not added to the supernode_table, as it is a dummy node, and it should not be
# maintained during the _update_graph procedure.
def _update_removed_node(self, node: Supernode):
# We can assume the node has no incident edges in the complete decontraction of this contraction scheme graph.
# So, since this contraction scheme is edge-based, we can assume the node resides in a single component set,
# composed only by this node.
if len(self.component_sets_table[node]) != 1 or len(next(iter(self.component_sets_table[node]))) != 1:
raise ValueError("The deleted node should be in a singleton component set.")
del self.component_sets_table[node]
if node in self.component_sets_table.modified:
self.component_sets_table.modified.remove(node)
self._deleted_subnodes.setdefault(node.supernode, set()).add(node)
node.supernode = None
@abstractmethod
def _update_added_edge(self, superedge: Superedge):
pass
@abstractmethod
def _update_removed_edge(self, superedge: Superedge):
pass