1+ from .unionfind import UnionFind
2+ from ..reeb .lowerstarSC import LowerStarSC
3+ import numpy as np
4+
5+
6+
7+ def is_face (sigma , tau ):
8+ '''
9+ Check if tau is a face of sigma
10+
11+ Args:
12+ sigma: A simplicial complex (a list of simplices).
13+ tau: A simplex (a list of vertices).
14+
15+ Returns:
16+ bool: True if tau is a face of sigma, False otherwise.
17+ '''
18+ return set (tau ).issubset (set (sigma ))
19+
20+ def get_levelset_components (L ):
21+ '''
22+ Given a list of simplices L representing a level set, compute the connected components. This function is really only helpful inside of reeb_of_lower_star.
23+
24+ Args:
25+ L: A list of simplices (each simplex is a list of vertices).
26+
27+ Returns:
28+ dict: A dictionary where keys are representative simplices and values are lists of simplices in the same connected component.
29+ '''
30+
31+ UF = UnionFind (range (len (L )))
32+ for i , simplex1 in enumerate (L ):
33+ for j , simplex2 in enumerate (L ):
34+ if i < j :
35+ # Check if they share a vertex
36+ if is_face (simplex1 , simplex2 ) or is_face (simplex2 , simplex1 ):
37+ UF .union (i , j )
38+
39+ # Replace indices with simplices
40+ components_index = UF .components_dict ()
41+ components = {}
42+ for key in components_index :
43+ components [tuple (L [key ])] = [L [i ] for i in components_index [key ]]
44+
45+
46+ return components
47+
48+
49+ def reeb_of_lower_star (K : LowerStarSC , verbose = False ):
50+ """Computes the Reeb graph of a Lower Star Simplicial Complex K.
51+
52+ Args:
53+ K (LowerStarSC): A Lower Star Simplicial Complex with assigned filtration values.
54+ verbose (boolean): Make it True if you want lots of printouts.
55+
56+ Returns:
57+ ReebGraph: The computed Reeb graph.
58+
59+ Example:
60+ >>> from cereeberus.reeb.lowerstarSC import LowerStarSC
61+ >>> K = LowerStarSC()
62+ >>> K.insert([0, 1, 2])
63+ >>> K.insert([1, 3])
64+ >>> K.insert([2,3])
65+ >>> K.assign_filtration([0], 0.0)
66+ >>> K.assign_filtration([1], 3.0)
67+ >>> K.assign_filtration([2], 5.0)
68+ >>> K.assign_filtration([3], 7)
69+ >>> R = reeb_of_lower_star(K)
70+ >>> R.draw()
71+ """
72+ from ..reeb .reebgraph import ReebGraph
73+
74+ funcVals = [(i ,K .filtration ([i ])) for i in K .iter_vertices ()]
75+ funcVals .sort (key = lambda x : x [1 ]) # Sort by filtration value
76+
77+ R = ReebGraph ()
78+
79+ currentLevelSet = []
80+ components = {}
81+ half_edge_index = 0
82+
83+ # This will keep track of the components represented by every vertex in the graph so far.
84+ # It will be vertName: connected_component (given as a list of lists) represented by that vertex
85+ vert_to_component = {}
86+
87+ edges_at_prev_level = []
88+
89+
90+ for i , (vert , filt ) in enumerate (funcVals ):
91+ if verbose :
92+ print (f"\n ---\n Processing { vert } at func val { filt :.2f} " )
93+ now_min = filt
94+ now_max = funcVals [i + 1 ][1 ] if i + 1 < len (funcVals ) else np .inf
95+ star = K .get_star ([vert ])
96+ lower_star = [s [0 ] for s in star if s [1 ] <= filt and len (s [0 ]) > 1 ]
97+ upper_star = [s [0 ] for s in star if s [1 ] > filt and len (s [0 ]) > 1 ]
98+
99+ if verbose :
100+ print (f" Lower star simplices: { lower_star } " )
101+ print (f" Upper star simplices: { upper_star } " )
102+
103+ #----
104+ # Update the levelset list
105+ #----
106+
107+ for s in lower_star :
108+ # Remove from current level set
109+ if s in currentLevelSet :
110+ currentLevelSet .remove (s )
111+
112+ currentLevelSet .append ([vert ]) # Add the vertex itself to the level set
113+ components_at_vertex = get_levelset_components (currentLevelSet )
114+
115+ if verbose :
116+ print (f" Current level set simplices: { currentLevelSet } " )
117+ print (f" Level set components at vertex { vert } (func val { filt :.2f} ):" )
118+ for comp in components_at_vertex .values ():
119+ print (f" Component: { comp } " )
120+
121+ verts_at_level = []
122+ for rep , comp in components_at_vertex .items ():
123+ # Add a vertex for each component in this levelset
124+ nextNodeName = R .get_next_vert_name ()
125+ R .add_node (nextNodeName , now_min )
126+ vert_to_component [nextNodeName ] = comp # Store the component represented by this vertex
127+ verts_at_level .append (nextNodeName )
128+
129+ # Check if any simplex in vertex component is a subset of any of simplices in a previous edge's component
130+ for e in edges_at_prev_level :
131+ prev_comp = vert_to_component [e ]
132+ if any ([is_face (prev_simp , simp ) for simp in comp for prev_simp in prev_comp ]):
133+ R .add_edge (e , nextNodeName )
134+
135+ #----
136+ # Add the edge vertices for after the vertex is passed
137+ #----
138+
139+ # Remove the vertex from the level set
140+ if [vert ] in currentLevelSet :
141+ currentLevelSet .remove ([vert ])
142+
143+ # Add the upper star to the current level set
144+ for s in upper_star :
145+ if s not in currentLevelSet :
146+ currentLevelSet .append (s )
147+
148+ components = get_levelset_components (currentLevelSet )
149+ if verbose :
150+ print (f"\n Updated current level set simplices: { currentLevelSet } " )
151+ print (f" Level set components after vertex { vert } (func val { filt :.2f} ):" )
152+ for comp in components .values ():
153+ print (f" Component: { comp } " )
154+ #----
155+ # Set up a vertex in the Reeb graph for each connected component
156+ # These will represent edges
157+ # These are at height (now_min + now_max)/2
158+ #----
159+ edges_at_prev_level = []
160+ for comp in components .values ():
161+ # Create a new vertex in the Reeb graph
162+ e_name = 'e_' + str (half_edge_index )
163+ R .add_node (e_name , (now_min + now_max ) / 2 )
164+ vert_to_component [e_name ] = comp # Store the component represented by this half edge top
165+ half_edge_index += 1
166+ edges_at_prev_level .append (e_name )
167+
168+ # Now connect to the vertices at this level
169+ for v in verts_at_level :
170+
171+ # Get the component represented by vertex v
172+ prev_comp = vert_to_component [v ]
173+
174+ if any ([is_face (simp , prev_simp ) for simp in comp for prev_simp in prev_comp ]):
175+ R .add_edge (v , e_name )
176+
177+ return R
178+
0 commit comments