Source code for synkit.Graph.Feature.path_fps

import networkx as nx
import hashlib
from typing import Any


[docs] class PathFPs: def __init__( self, graph: nx.Graph, max_length: int = 10, nBits: int = 1024, hash_alg: str = "sha256", ) -> None: """Initialize the PathFPs class to create a binary fingerprint based on paths in a graph. Parameters: - graph (nx.Graph): Graph on which to perform analysis. - max_length (int): Limit on path lengths considered in the fingerprint. - nBits (int): Size of the binary fingerprint in bits. - hash_alg (str): Cryptographic hash function used for path hashing. - hash_function (Callable): Hash function initialized from hashlib. """ self.graph = graph self.max_length = max_length self.nBits = nBits self.hash_alg = hash_alg self.hash_function = getattr(hashlib, self.hash_alg)
[docs] def generate_fingerprint(self) -> str: """Generate a binary string fingerprint of the graph by hashing paths up to a certain length and combining them. Returns: - str: A binary string of length `nBits` that represents the fingerprint of the graph. """ fingerprint = "" for node in self.graph.nodes(): for target in self.graph.nodes(): if node != target: for path in nx.all_simple_paths( self.graph, source=node, target=target, cutoff=self.max_length ): path_str = "-".join(map(str, path)) hash_obj = self.hash_function(path_str.encode()) path_hash = bin(int(hash_obj.hexdigest(), 16))[2:].zfill( hash_obj.digest_size * 8 ) if len(fingerprint) + len(path_hash) > self.nBits: needed_bits = self.nBits - len(fingerprint) path_hash = path_hash[:needed_bits] fingerprint += path_hash if len(fingerprint) == self.nBits: return fingerprint if len(fingerprint) < self.nBits: fingerprint += self.iterative_deepening( hash_obj, self.nBits - len(fingerprint) ) return fingerprint
[docs] def iterative_deepening(self, hash_object: Any, remaining_bits: int) -> str: """Extend the hash length using iterative hashing until the desired bit length is achieved. Parameters: - hash_object (hashlib._Hash): The hash object used for iterative deepening. - remaining_bits (int): Number of bits needed to complete the fingerprint to `nBits`. Returns: - str: Additional binary data to achieve the desired hash length. """ additional_data = "" while len(additional_data) * 4 < remaining_bits: hash_object.update(additional_data.encode()) additional_data += hash_object.hexdigest() return bin(int(additional_data, 16))[2:][:remaining_bits]