@@ -5232,7 +5232,7 @@ def factor(self):
52325232 """
52335233 Factor the poset as a Cartesian product of smaller posets.
52345234
5235- This only works for connected posets for the moment .
5235+ This only works for connected posets.
52365236
52375237 The decomposition of a connected poset as a Cartesian product
52385238 of posets (prime in the sense that they cannot be written as
@@ -5270,19 +5270,24 @@ def factor(self):
52705270 sage: P.factor()
52715271 Traceback (most recent call last):
52725272 ...
5273- NotImplementedError: the poset is not connected
5273+ NotImplementedError: the poset is empty or not connected
52745274
52755275 sage: P = posets.Crown(2)
52765276 sage: P.factor()
52775277 [Finite poset containing 4 elements]
52785278
52795279 sage: Poset().factor()
5280- [Finite poset containing 0 elements]
5280+ Traceback (most recent call last):
5281+ ...
5282+ NotImplementedError: the poset is empty or not connected
52815283
52825284 sage: factor(posets.BooleanLattice(2))
52835285 [Finite poset containing 2 elements,
52845286 Finite poset containing 2 elements]
52855287
5288+ sage: factor(Poset(DiGraph([[0,1],[1,2],[0,3]])))
5289+ [Finite poset containing 4 elements]
5290+
52865291 REFERENCES:
52875292
52885293 .. [Feig1986] Joan Feigenbaum, *Directed Cartesian-Product Graphs
@@ -5293,49 +5298,57 @@ def factor(self):
52935298 from sage .graphs .graph import Graph
52945299 from sage .misc .flatten import flatten
52955300 dg = self ._hasse_diagram
5296- if not dg .is_connected ():
5297- raise NotImplementedError ('the poset is not connected' )
5301+ if not dg .is_connected () or not dg . order () :
5302+ raise NotImplementedError ('the poset is empty or not connected' )
52985303 if Integer (dg .num_verts ()).is_prime ():
52995304 return [self ]
5305+ if sum (e for _ , e in self .degree_polynomial ().factor ()) == 1 :
5306+ return [self ]
5307+
53005308 G = dg .to_undirected ()
53015309 is_product , dic = G .is_cartesian_product (relabeling = True )
53025310 if not is_product :
53035311 return [self ]
5304- dic = {key : tuple (flatten (dic [ key ] )) for key in dic }
5312+ dic = {key : tuple (flatten (val )) for key , val in dic . items () }
53055313
53065314 prod_dg = dg .relabel (dic , inplace = False )
53075315 v0 = next (iter (dic .values ()))
53085316 n = len (v0 )
53095317 factors_range = range (n )
5310- fusion = Graph (n )
53115318
53125319 def edge_color (va , vb ):
5313- for i in range (n ):
5314- if va [i ] != vb [i ]:
5315- return i
5320+ return next (i for i , (vai , vbi ) in enumerate (zip (va , vb ))
5321+ if vai != vbi )
5322+
5323+ neighbors_table = {}
5324+ for x in prod_dg :
5325+ z = [[] for _ in range (n )]
5326+ for y in prod_dg .neighbor_iterator (x ):
5327+ z [edge_color (x , y )].append (y )
5328+ neighbors_table [x ] = z
53165329
5330+ fusion_edges = []
53175331 for i0 , i1 in Subsets (factors_range , 2 ):
53185332 for x in prod_dg :
5319- neigh0 = [y for y in prod_dg .neighbor_iterator (x )
5320- if edge_color (x , y ) == i0 ]
5321- neigh1 = [z for z in prod_dg .neighbor_iterator (x )
5322- if edge_color (x , z ) == i1 ]
5333+ neigh0 = neighbors_table [x ][i0 ]
5334+ neigh1 = neighbors_table [x ][i1 ]
53235335 for x0 , x1 in product (neigh0 , neigh1 ):
53245336 _x2 = list (x0 )
53255337 _x2 [i1 ] = x1 [i1 ]
53265338 x2 = tuple (_x2 )
53275339 A0 = prod_dg .has_edge (x , x0 )
53285340 B0 = prod_dg .has_edge (x1 , x2 )
53295341 if A0 != B0 :
5330- fusion . add_edge ([i0 , i1 ])
5342+ fusion_edges . append ([i0 , i1 ])
53315343 break
53325344 A1 = prod_dg .has_edge (x , x1 )
53335345 B1 = prod_dg .has_edge (x0 , x2 )
53345346 if A1 != B1 :
5335- fusion . add_edge ([i0 , i1 ])
5347+ fusion_edges . append ([i0 , i1 ])
53365348 break
53375349
5338- fusion = fusion .transitive_closure ()
5350+ fusion = Graph ([list (range (n )), fusion_edges ],
5351+ format = "vertices_and_edges" )
53395352 resu = []
53405353 for s in fusion .connected_components (sort = False ):
53415354 subg = [x for x in prod_dg if all (x [i ] == v0 [i ] for i in factors_range
0 commit comments