diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 4c2d05b1ec7..a59d85a8ecb 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -5881,6 +5881,10 @@ REFERENCES: Journal of Algorithms, Volume 26, Issue 2, Pages 275 - 290, 1998. (https://doi.org/10.1006/jagm.1997.0891) +.. [Sq2002] Matthew B. Squire. + *Enumerating the Ideals of a Poset*. + (https://citeseer.ist.psu.edu/465417.html) + .. [SS1983] Shorey and Stewart. "On the Diophantine equation a x^{2t} + b x^t y + c y^2 = d and pure powers in recurrence sequences." Mathematica Scandinavica, 1983. diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index 0d846648e6f..b11d5e6ad77 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -305,6 +305,56 @@ def order_filter(self, elements): [3, 7, 8, 9, 10, 11, 12, 13, 14, 15] """ + def generate_upsets(U, Y, Poset): + r""" + Enumerates the ideals (upsets) of a given poset. + + ALGORITHM: + + The algorithm is based on [Sq2002]_. + Current algorithms for genertating ideals require an amortized + time of `O(n)` per ideal in the worst case, where `n` is the number + of elements in the poset. This algorithm generates ideals in an + amortized time of `O(log n)` per ideal. + + The function recursively generates all possible upsets (subsets) of + a given set `Y` based on a partially ordered set (Poset), ensuring that + if `Xi < Xm < Xj`, then Xi must also be less than `Xj`. It iterates through + `Y`, partitioning it into two subsets based on the relationship between + elements and yields the resulting upsets. + + INPUT: + + - ``U`` -- a list of the current upset being constructed. + - ``Y`` -- a list of remaining elements to be considered for inclusion. + - ``Poset`` -- a dictionary representing the partial order. + + OUTPUT: + + - A subset of `Y` that satisfies the upset condition. + + EXAMPLES:: + + """ + if not Y: + yield U + else: + Xm = Y[len(Y) // 2] + Y1 = [] + Y2 = [] + for i, Xi in enumerate(Y): + if Poset[(Xi, Xm)] == 1: + U[i] = 0 + else: + Y1.append(Xi) + yield from Posets.generate_upsets(U.copy(), Y1, Poset) + for j, Xj in enumerate(Y): + if Poset[(Xm, Xj)] == 1: + U[j] = 1 + else: + Y2.append(Xj) + yield from Posets.generate_upsets(U.copy(), Y2, Poset) + def directed_subset(self, elements, direction): r""" Return the order filter or the order ideal generated by a