@@ -723,6 +723,81 @@ def kernel(self):
723723 """Synonym for K"""
724724 return self .K
725725
726+ @property
727+ def n_connected_components (self ):
728+ """Number of connected components in the graph (cached)
729+
730+ A connected component is a maximal set of nodes where there is a path
731+ between every pair of nodes in the set. This property uses scipy's
732+ connected_components function on the kernel matrix to count components.
733+
734+ Returns
735+ -------
736+ n_components : int
737+ Number of connected components in the graph
738+
739+ Examples
740+ --------
741+ >>> G = graphtools.Graph(data)
742+ >>> print(G.n_connected_components)
743+ 1
744+ """
745+ try :
746+ return self ._n_connected_components
747+ except AttributeError :
748+ from scipy .sparse .csgraph import connected_components
749+
750+ self ._n_connected_components , self ._component_labels = connected_components (
751+ csgraph = self .kernel , directed = False , return_labels = True
752+ )
753+ return self ._n_connected_components
754+
755+ @property
756+ def component_labels (self ):
757+ """Component label for each node (cached)
758+
759+ Returns the connected component index for each node in the graph.
760+ Nodes with the same label belong to the same connected component.
761+
762+ Returns
763+ -------
764+ labels : np.ndarray, shape=[n_samples]
765+ Component index for each node (0 to n_connected_components - 1)
766+
767+ Examples
768+ --------
769+ >>> G = graphtools.Graph(data)
770+ >>> labels = G.component_labels
771+ >>> # Find nodes in component 0
772+ >>> component_0_nodes = np.where(labels == 0)[0]
773+ """
774+ try :
775+ return self ._component_labels
776+ except AttributeError :
777+ # Trigger computation via n_connected_components
778+ _ = self .n_connected_components
779+ return self ._component_labels
780+
781+ @property
782+ def is_connected (self ):
783+ """Check if the graph is connected (cached)
784+
785+ A graph is connected if there is a path between every pair of nodes,
786+ i.e., if it has exactly one connected component.
787+
788+ Returns
789+ -------
790+ connected : bool
791+ True if graph has exactly 1 connected component, False otherwise
792+
793+ Examples
794+ --------
795+ >>> G = graphtools.Graph(data)
796+ >>> if not G.is_connected:
797+ ... print(f"Warning: Graph has {G.n_connected_components} components")
798+ """
799+ return self .n_connected_components == 1
800+
726801 @property
727802 def weighted (self ):
728803 return self .decay is not None
0 commit comments