diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 1e57682f255..5079283e8ec 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -27,7 +27,7 @@ from sage.rings.fraction_field import FractionField from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from itertools import product -from sage.misc.misc import powerset +from sage.combinat.subset import powerset class QuantumCliffordAlgebra(CombinatorialFreeModule): r""" diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index d3b5d164054..c29005e03ba 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -20,7 +20,6 @@ import math from collections.abc import Iterable -from sage.misc.misc import powerset from sage.misc.misc_c import prod from sage.structure.element import parent @@ -6042,6 +6041,8 @@ def squarefree_divisors(x): sage: list(squarefree_divisors(mpz(12))) [1, 2, 3, 6] """ + from sage.combinat.subset import powerset + for a in powerset(prime_divisors(x)): yield prod(a, ZZ.one()) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 95c31d20695..4cb0b21d7a1 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -1327,7 +1327,10 @@ def _test_coxeter_relations(self, **options): one = self.one() for si in s: tester.assertEqual(si**2, one) - cox_mat = self.coxeter_matrix() + try: + cox_mat = self.coxeter_matrix() + except ImportError: + return I = cox_mat.index_set() for ii, i in enumerate(I): for j in I[ii + 1:]: diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 0ec68ca2b99..a03a7ca5495 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -10,6 +10,8 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** +import sage.rings.abc + from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.misc.lazy_attribute import lazy_attribute from sage.categories.category_with_axiom import CategoryWithAxiom @@ -746,13 +748,14 @@ def permutahedron(self, point=None, base_ring=None): from sage.rings.integer_ring import ZZ point = [ZZ.one()] * n v = sum(point[i-1] * weights[i] for i in weights.keys()) - from sage.geometry.polyhedron.constructor import Polyhedron - from sage.rings.qqbar import AA, QQbar - from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField vertices = [v*w for w in self] - if base_ring is None and v.base_ring() in [UniversalCyclotomicField(), QQbar]: - vertices = [v.change_ring(AA) for v in vertices] - base_ring = AA + if base_ring is None: + if isinstance(v.base_ring(), (sage.rings.abc.UniversalCyclotomicField, + sage.rings.abc.AlgebraicField_common)): + from sage.rings.qqbar import AA + vertices = [v.change_ring(AA) for v in vertices] + base_ring = AA + from sage.geometry.polyhedron.constructor import Polyhedron return Polyhedron(vertices=vertices, base_ring=base_ring) class ElementMethods: diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index b7dbd37a3c6..2d5f1ca1914 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -968,7 +968,7 @@ def energy_function(self, algorithm=None): ....: for b in hw) True """ - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil C = self.parent().crystals[0] ell = ceil(C.s()/C.cartan_type().c()[C.r()]) @@ -1101,7 +1101,7 @@ def e_string_to_ground_state(self): ....: for elt in hw) True """ - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil ell = max(ceil(K.s()/K.cartan_type().c()[K.r()]) for K in self.parent().crystals) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 2206ea2873a..0f43e6bbcfe 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -218,7 +218,7 @@ lazy_import('sage.combinat.multiset_partition_into_sets_ordered', ['OrderedMultisetPartitionIntoSets', 'OrderedMultisetPartitionsIntoSets']) -from .subset import Subsets +from .subset import Subsets, subsets, powerset, uniq from .necklace import Necklaces lazy_import('sage.combinat.dyck_word', ('DyckWords', 'DyckWord')) lazy_import('sage.combinat.nu_dyck_word', ('NuDyckWords', 'NuDyckWord')) diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 95899fd66a6..657c70a5c0e 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -23,7 +23,7 @@ from sage.structure.richcmp import richcmp #from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.cachefunc import cached_method -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.arith.misc import binomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.algebras import Algebras diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 195ff344e50..5d27891dee0 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -64,18 +64,12 @@ **Implemented in other modules (listed for completeness):** -The ``sage.arith.all`` module contains the following +The package :mod:`sage.arith` contains the following combinatorial functions: -- binomial the binomial coefficient (wrapped from PARI) +- :func:`binomial` the binomial coefficient (wrapped from PARI) -- factorial (wrapped from PARI) - -- partition (from the Python Cookbook) Generator of the list of - all the partitions of the integer `n`. - -- :func:`number_of_partitions` (wrapped from PARI) the - *number* of partitions: +- :func:`factorial` (wrapped from PARI) - :func:`falling_factorial` Definition: for integer `a \ge 0` we have `x(x-1) \cdots (x-a+1)`. In all @@ -87,7 +81,12 @@ other cases we use the GAMMA-function: `\frac {\Gamma(x+a)} {\Gamma(x)}`. -- gaussian_binomial the gaussian binomial +From other modules: + +- :func:`number_of_partitions` (wrapped from PARI) the + *number* of partitions: + +- :func:`sage.combinat.q_analogues.gaussian_binomial` the Gaussian binomial .. MATH:: @@ -174,8 +173,6 @@ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.libs.pari.all import pari -from sage.misc.prandom import randint from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function from sage.structure.sage_object import SageObject @@ -187,7 +184,10 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.element import Element + lazy_import('sage.interfaces.maxima_lib', 'maxima') +lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.misc.prandom', 'randint') def bell_number(n, algorithm='flint', **options) -> Integer: @@ -2892,7 +2892,7 @@ def unshuffle_iterator(a, one=1) -> Iterator: [(((), (3, 1)), 3/2), (((3,), (1,)), 3/2), (((1,), (3,)), -3/2), (((3, 1), ()), 3/2)] """ - from sage.misc.misc import powerset + from sage.combinat.subset import powerset n = len(a) for I in powerset(range(n)): sorted_I = tuple(sorted(I)) diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 2265e113040..071c1db387e 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -50,12 +50,16 @@ --------- """ +from sage.arith.misc import binomial, is_prime_power, is_square from sage.categories.sets_cat import EmptySetError +from sage.misc.lazy_import import lazy_import from sage.misc.unknown import Unknown + from .design_catalog import transversal_design # type:ignore -from sage.arith.misc import binomial, is_prime_power -from .group_divisible_designs import GroupDivisibleDesign from .designs_pyx import is_pairwise_balanced_design +from .group_divisible_designs import GroupDivisibleDesign + +lazy_import('sage.schemes.plane_conics.constructor', 'Conic') def biplane(n, existence=False): @@ -413,8 +417,6 @@ def BruckRyserChowla_check(v, k, lambd): True """ - from sage.arith.misc import is_square - from sage.schemes.plane_conics.constructor import Conic from sage.rings.rational_field import QQ # design is not symmetric diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 52a95805ea5..fb510a83b0e 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -1530,7 +1530,6 @@ def relative_difference_set_from_homomorphism(q, N, d, check=True, return_group= return G2, second_diff_set return second_diff_set - def is_relative_difference_set(R, G, H, params, verbose=False): r""" Check if ``R`` is a difference set of ``G`` relative to ``H``, with the given parameters. @@ -2040,9 +2039,6 @@ def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, c ... NotImplementedError: skew SDS of order 7 not yet implemented """ - from sage.symbolic.ring import SymbolicRing - from sage.rings.finite_rings.integer_mod_ring import Zmod - data = { 81: (3, lambda x: x**4 - x**3 - 1, 16, 5, [1, 2, 4, 6, 8, 10, 12, 14], [1, 2, 3, 4, 10, 11, 13], @@ -2060,9 +2056,11 @@ def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, c mod, poly, exp, order, ind1, ind2, ind3, ind4 = data[n] + from sage.rings.finite_rings.integer_mod_ring import Zmod + Z3 = Zmod(mod) - R = SymbolicRing() - x = R.var('x') + R = ZZ['x'] + x = R.gen() F = Z3.extension(poly(x)) H = [F.gen() ** (exp * i) for i in range(order)] diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 1aa6c34d733..fbb003122ab 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -39,10 +39,13 @@ # https://www.gnu.org/licenses/ # # ************************************************************************** from __future__ import annotations -from sage.rings.integer import Integer + from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import +from sage.rings.integer import Integer from sage.sets.set import Set -from sage.libs.gap.libgap import libgap + +lazy_import('sage.libs.gap.libgap', 'libgap') class IncidenceStructure(): @@ -173,7 +176,6 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, sage: IncidenceStructure([]) Incidence structure with 0 points and 0 blocks """ - from sage.matrix.constructor import matrix from sage.structure.element import Matrix # Reformatting input @@ -189,6 +191,7 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, assert incidence_matrix is None, "'incidence_matrix' cannot be defined when 'points' is defined" if incidence_matrix: + from sage.matrix.constructor import matrix M = matrix(incidence_matrix) v = M.nrows() self._points = list(range(v)) diff --git a/src/sage/combinat/diagram.py b/src/sage/combinat/diagram.py index dcde71bff63..ed32713b5c2 100644 --- a/src/sage/combinat/diagram.py +++ b/src/sage/combinat/diagram.py @@ -615,7 +615,7 @@ def __iter__(self): """ from sage.sets.non_negative_integers import NonNegativeIntegers from sage.categories.cartesian_product import cartesian_product - from sage.misc.misc import subsets + from sage.combinat.subset import subsets # the product of positive integers automatically implements an # an enumeration which allows us to get out of the first column N = NonNegativeIntegers() diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index bd281fdbb77..da6628ed840 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -231,7 +231,7 @@ def planar_partitions_rec(X): if len(X) > 1: yield ([X[0]], [X[1]]) return - from sage.misc.misc import powerset + from sage.combinat.subset import powerset from itertools import product for S in powerset(range(len(X)-1)): if not S: diff --git a/src/sage/combinat/integer_vector_weighted.py b/src/sage/combinat/integer_vector_weighted.py index 1b110c34140..071c814f3bb 100644 --- a/src/sage/combinat/integer_vector_weighted.py +++ b/src/sage/combinat/integer_vector_weighted.py @@ -20,13 +20,15 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_with_grading import SetsWithGrading +from sage.misc.lazy_import import lazy_import from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.combinat.integer_vector import IntegerVector -from sage.combinat.words.word import Word from sage.combinat.permutation import Permutation +lazy_import('sage.combinat.words.word', 'Word') + class WeightedIntegerVectors(Parent, UniqueRepresentation): r""" diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index a2d4f6e607c..70b165befee 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -3042,7 +3042,13 @@ def final_forest(element) -> TIP: """ if isinstance(element, TamariIntervalPoset): return element.final_forest() - if element in DyckWords(): + + try: + DW = DyckWords() + except ImportError: + DW = () + + if element in DW: binary_tree = element.to_binary_tree_tamari() elif element in BinaryTrees() or element in LabelledBinaryTrees(): binary_tree = element @@ -3149,7 +3155,13 @@ def initial_forest(element) -> TIP: """ if isinstance(element, TamariIntervalPoset): return element.initial_forest() - if element in DyckWords(): + + try: + DW = DyckWords() + except ImportError: + DW = () + + if element in DW: binary_tree = element.to_binary_tree_tamari() elif element in BinaryTrees() or element in LabelledBinaryTrees(): binary_tree = element diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 9593055e9ed..4d7b3d09923 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -242,6 +242,7 @@ from __future__ import annotations from typing import Iterator import itertools +import operator from sage.arith.misc import factorial, multinomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -256,16 +257,10 @@ from sage.combinat.permutation_cython import (left_action_product, right_action_product, left_action_same_n, right_action_same_n, map_to_list, next_perm) -from sage.combinat.rsk import RSK, RSK_inverse from sage.combinat.tools import transitive_ideal -from sage.graphs.digraph import DiGraph -from sage.groups.perm_gps.permgroup_element import PermutationGroupElement -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.libs.gap.libgap import libgap -from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method from sage.misc.decorators import rename_keyword -from sage.misc.prandom import sample +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -274,7 +269,18 @@ from sage.structure.parent import Parent from sage.structure.element import Element, get_coercion_model from sage.structure.unique_representation import UniqueRepresentation -import operator + +lazy_import('sage.combinat.rsk', ['RSK', 'RSK_inverse']) +lazy_import('sage.combinat.tableau', 'Tableau') +lazy_import('sage.combinat.words.finite_word', 'evaluation_dict') +lazy_import('sage.graphs.digraph', 'DiGraph') +lazy_import('sage.groups.cactus_group', 'CactusGroup') +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') +lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup') +lazy_import('sage.libs.gap.libgap', 'libgap') +lazy_import('sage.matrix.matrix_space', 'MatrixSpace') +lazy_import('sage.misc.prandom', 'sample') + class Permutation(CombinatorialElement): r""" @@ -441,7 +447,6 @@ def __classcall_private__(cls, l, check=True): sage: P.parent() Standard permutations """ - import sage.combinat.tableau as tableau if isinstance(l, Permutation): return l elif isinstance(l, PermutationGroupElement): @@ -461,11 +466,11 @@ def __classcall_private__(cls, l, check=True): #if l is a pair of standard tableaux or a pair of lists elif isinstance(l, (tuple, list)) and len(l) == 2 and \ - all(isinstance(x, tableau.Tableau) for x in l): + all(isinstance(x, Tableau) for x in l): return RSK_inverse(*l, output='permutation') elif isinstance(l, (tuple, list)) and len(l) == 2 and \ all(isinstance(x, list) for x in l): - P,Q = [tableau.Tableau(_) for _ in l] + P,Q = [Tableau(_) for _ in l] return RSK_inverse(P, Q, 'permutation') # if it's a tuple or nonempty list of tuples, also assume cycle # notation @@ -870,7 +875,6 @@ def to_tableau_by_shape(self, shape): sage: Permutation([3,4,1,2,5]).to_tableau_by_shape([3,2]).reading_word_permutation() [3, 4, 1, 2, 5] """ - import sage.combinat.tableau as tableau if sum(shape) != len(self): raise ValueError("the size of the partition must be the size of self") @@ -879,7 +883,7 @@ def to_tableau_by_shape(self, shape): for i in reversed(shape): t = [w[:i]] + t w = w[i:] - return tableau.Tableau(t) + return Tableau(t) def to_cycles(self, singletons=True, use_min=True): """ @@ -6924,7 +6928,6 @@ def _coerce_map_from_(self, G): return self._from_permutation_group_element if isinstance(G, StandardPermutations_n) and G.n <= self.n: return True - from sage.groups.cactus_group import CactusGroup if isinstance(G, CactusGroup) and G.n() <= self.n: return self._from_cactus_group_element return super()._coerce_map_from_(G) @@ -8682,8 +8685,6 @@ def permutohedron_lequal(p1, p2, side="right"): ############ # Patterns # ############ -from sage.combinat.words.finite_word import evaluation_dict - def to_standard(p, key=None): r""" diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 3a26227b4f1..77f175f0364 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -32,7 +32,7 @@ from sage.matrix.matrix_space import MatrixSpace from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.classcall_metaclass import typecall -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.matrix.matrix_integer_sparse import Matrix_integer_sparse from sage.rings.integer_ring import ZZ from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 39fa6ca0d01..cad3482bb17 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -17,17 +17,20 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import sage.rings.abc + +from sage.combinat.root_system.cartan_type import CartanType from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.classcall_metaclass import ClasscallMetaclass -from sage.combinat.root_system.cartan_type import CartanType -import sage.rings.abc from sage.matrix.args import SparseEntry from sage.matrix.constructor import Matrix -from sage.symbolic.ring import SR +from sage.misc.lazy_import import lazy_import from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject +lazy_import('sage.rings.universal_cyclotomic_field', 'UniversalCyclotomicField') + class CoxeterType(SageObject, metaclass=ClasscallMetaclass): """ @@ -372,19 +375,12 @@ def bilinear_form(self, R=None): n = self.rank() mat = self.coxeter_matrix()._matrix - from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField - UCF = UniversalCyclotomicField() - if R is None: - R = UCF - # if UCF.has_coerce_map_from(base_ring): - # R = UCF - # else: - # R = base_ring + R = UniversalCyclotomicField() # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. - E = UCF.gen - if R is UCF: + if isinstance(R, sage.rings.abc.UniversalCyclotomicField): + E = R.gen def val(x): if x > -1: @@ -392,6 +388,7 @@ def val(x): else: return R(x) elif isinstance(R, sage.rings.abc.NumberField_quadratic): + E = UniversalCyclotomicField().gen def val(x): if x > -1: @@ -401,6 +398,7 @@ def val(x): else: from sage.functions.trig import cos from sage.symbolic.constants import pi + from sage.symbolic.ring import SR def val(x): if x > -1: diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index 6edf7d963da..3c3acef4299 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -40,6 +40,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import infinity from sage.rings.integer import Integer from sage.combinat.combinatorial_map import combinatorial_map @@ -50,9 +51,10 @@ from sage.combinat.permutation import Permutation from sage.arith.misc import factorial from sage.misc.prandom import random, randint, sample -from sage.probability.probability_distribution import GeneralDiscreteDistribution from sage.sets.disjoint_set import DisjointSet -from sage.combinat.posets.hasse_diagram import HasseDiagram + +lazy_import('sage.combinat.posets.hasse_diagram', 'HasseDiagram') +lazy_import('sage.probability.probability_distribution', 'GeneralDiscreteDistribution') class AbstractSetPartition(ClonableArray, diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index c27b1eb04ed..a08a5474cae 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -39,7 +39,6 @@ from sage.sets.set import Set, Set_object_enumerated from sage.arith.misc import binomial -from sage.misc.misc import _stable_uniq as uniq from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from . import combination @@ -1471,3 +1470,93 @@ def _element_constructor_(self, x): [(), (0,), (1,), (2,), (0, 1), (0, 2), (1, 2), (0, 1, 2)] """ return self.element_class(sorted(set(x))) + + +def powerset(X): + r""" + Iterator over the *list* of all subsets of the iterable ``X``, in no + particular order. Each list appears exactly once, up to order. + + INPUT: + + - ``X`` - an iterable + + OUTPUT: iterator of lists + + EXAMPLES:: + + sage: list(powerset([1,2,3])) + [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] + sage: [z for z in powerset([0,[1,2]])] + [[], [0], [[1, 2]], [0, [1, 2]]] + + Iterating over the power set of an infinite set is also allowed:: + + sage: i = 0 + sage: L = [] + sage: for x in powerset(ZZ): + ....: if i > 10: + ....: break + ....: else: + ....: i += 1 + ....: L.append(x) + sage: print(" ".join(str(x) for x in L)) + [] [0] [1] [0, 1] [-1] [0, -1] [1, -1] [0, 1, -1] [2] [0, 2] [1, 2] + + You may also use subsets as an alias for powerset:: + + sage: subsets([1,2,3]) + + sage: list(subsets([1,2,3])) + [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] + + The reason we return lists instead of sets is that the elements of + sets must be hashable and many structures on which one wants the + powerset consist of non-hashable objects. + + AUTHORS: + + - William Stein + + - Nils Bruin (2006-12-19): rewrite to work for not-necessarily + finite objects X. + """ + yield [] + pairs = [] + power2 = 1 + for x in X: + pairs.append((power2, x)) + next_power2 = power2 << 1 + for w in range(power2, next_power2): + yield [x for m, x in pairs if m & w] + power2 = next_power2 + + +subsets = powerset + + +def uniq(L): + """ + Iterate over the elements of ``L``, yielding every element at most + once: keep only the first occurrence of any item. + + The items must be hashable. + + INPUT: + + - ``L`` -- iterable + + EXAMPLES:: + + sage: L = [1, 1, 8, -5, 3, -5, 'a', 'x', 'a'] + sage: it = uniq(L); it + + sage: list(it) + [1, 8, -5, 3, 'a', 'x'] + """ + seen = set() + for x in L: + if x in seen: + continue + yield x + seen.add(x) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 4df26efd41d..c33a09fd483 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -100,7 +100,7 @@ from sage.combinat.posets.posets import Poset from sage.groups.perm_gps.permgroup import PermutationGroup from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.misc.misc_c import prod from sage.misc.persist import register_unpickle_override from sage.rings.finite_rings.integer_mod_ring import IntegerModRing diff --git a/src/sage/databases/jones.py b/src/sage/databases/jones.py index 6f6318d0c2d..5afcaaa3f6b 100644 --- a/src/sage/databases/jones.py +++ b/src/sage/databases/jones.py @@ -71,7 +71,7 @@ from sage.rings.number_field.number_field import NumberField from sage.rings.rational_field import RationalField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.env import SAGE_SHARE from sage.misc.persist import load, save diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx b/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx index dcb12407b7a..3d40d748a17 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx @@ -21,7 +21,7 @@ AUTHORS: from sage.arith.functions cimport LCM_list from sage.rings.finite_rings.finite_field_constructor import GF -from sage.misc.misc import subsets +from sage.combinat.subset import subsets cpdef _fast_possible_periods(self, return_points=False): diff --git a/src/sage/game_theory/cooperative_game.py b/src/sage/game_theory/cooperative_game.py index 0cb18189191..b95ba0f655a 100644 --- a/src/sage/game_theory/cooperative_game.py +++ b/src/sage/game_theory/cooperative_game.py @@ -21,7 +21,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from itertools import permutations, combinations -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.rings.integer import Integer from sage.structure.sage_object import SageObject diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index 5068c8e10e3..cd6e371eeb2 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -635,7 +635,7 @@ from itertools import product from .parser import Parser from sage.misc.latex import latex -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 629a4f9ba2a..cff7b73c94e 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -117,7 +117,7 @@ from sage.rings.integer_ring import ZZ from sage.graphs.graph import Graph from sage.combinat.posets.posets import Poset -from sage.misc.misc import powerset +from sage.combinat.subset import powerset class PolyhedralComplex(GenericCellComplex): diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index b351b8501c0..8aa4efbce0f 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -3946,7 +3946,7 @@ def chromatic_symmetric_function(self, R=None): """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import _Partitions - from sage.misc.misc import powerset + from sage.combinat.subset import powerset if R is None: R = ZZ p = SymmetricFunctions(R).p() diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 8fea19524eb..b58c90e5c22 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -7,7 +7,6 @@ from .misc import (BackslashOperator, cputime, - union, uniq, powerset, subsets, exists, forall, is_iterator, random_sublist, walltime, pad_zeros, diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index f263f53bad3..ac285817431 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -48,6 +48,9 @@ from sage.env import DOT_SAGE, HOSTNAME from sage.misc.lazy_import import lazy_import +lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"], + deprecation=35564) + lazy_import("sage.misc.call", ["AttrCallObject", "attrcall", "call_method"], deprecation=29869) @@ -554,53 +557,6 @@ def union(x, y=None): return list(set(x).union(y)) -def uniq(x): - """ - Return the sublist of all elements in the list x that is sorted and - is such that the entries in the sublist are unique. - - EXAMPLES:: - - sage: uniq([1, 1, 8, -5, 3, -5, -13, 13, -13]) - doctest:...: DeprecationWarning: the output of uniq(X) being sorted is deprecated; use sorted(set(X)) instead if you want sorted output - See https://github.com/sagemath/sage/issues/27014 for details. - [-13, -5, 1, 3, 8, 13] - """ - # After deprecation period, rename _stable_uniq -> uniq - from sage.misc.superseded import deprecation - deprecation(27014, "the output of uniq(X) being sorted is deprecated; use sorted(set(X)) instead if you want sorted output") - return sorted(set(x)) - - -def _stable_uniq(L): - """ - Iterate over the elements of ``L``, yielding every element at most - once: keep only the first occurrence of any item. - - The items must be hashable. - - INPUT: - - - ``L`` -- iterable - - EXAMPLES:: - - sage: from sage.misc.misc import _stable_uniq - sage: L = [1, 1, 8, -5, 3, -5, 'a', 'x', 'a'] - sage: it = _stable_uniq(L) - sage: it - - sage: list(it) - [1, 8, -5, 3, 'a', 'x'] - """ - seen = set() - for x in L: - if x in seen: - continue - yield x - seen.add(x) - - def exactly_one_is_true(iterable): r""" Return whether exactly one element of ``iterable`` evaluates ``True``. @@ -1056,69 +1012,6 @@ def _some_tuples_sampling(elements, repeat, max_samples, n): yield tuple(elements[j] for j in Integer(a).digits(n, padto=repeat)) -def powerset(X): - r""" - Iterator over the *list* of all subsets of the iterable X, in no - particular order. Each list appears exactly once, up to order. - - INPUT: - - - ``X`` - an iterable - - OUTPUT: iterator of lists - - EXAMPLES:: - - sage: list(powerset([1,2,3])) - [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] - sage: [z for z in powerset([0,[1,2]])] - [[], [0], [[1, 2]], [0, [1, 2]]] - - Iterating over the power set of an infinite set is also allowed:: - - sage: i = 0 - sage: L = [] - sage: for x in powerset(ZZ): - ....: if i > 10: - ....: break - ....: else: - ....: i += 1 - ....: L.append(x) - sage: print(" ".join(str(x) for x in L)) - [] [0] [1] [0, 1] [-1] [0, -1] [1, -1] [0, 1, -1] [2] [0, 2] [1, 2] - - You may also use subsets as an alias for powerset:: - - sage: subsets([1,2,3]) - - sage: list(subsets([1,2,3])) - [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] - - The reason we return lists instead of sets is that the elements of - sets must be hashable and many structures on which one wants the - powerset consist of non-hashable objects. - - AUTHORS: - - - William Stein - - - Nils Bruin (2006-12-19): rewrite to work for not-necessarily - finite objects X. - """ - yield [] - pairs = [] - power2 = 1 - for x in X: - pairs.append((power2, x)) - next_power2 = power2 << 1 - for w in range(power2, next_power2): - yield [x for m, x in pairs if m & w] - power2 = next_power2 - - -subsets = powerset - - ################################################################# # Misc. ################################################################# diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 2aa3421721d..d967cfbb95c 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -56,6 +56,32 @@ class NumberField_cyclotomic(Field): pass +class UniversalCyclotomicField(Field): + r""" + Abstract base class for :class:`~sage.rings.universal_cyclotomic_field.UniversalCyclotomicField`. + + This class is defined for the purpose of :func:`isinstance` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: K = UniversalCyclotomicField() # optional - sage.rings.number_field + sage: isinstance(K, sage.rings.abc.UniversalCyclotomicField) # optional - sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.UniversalCyclotomicField.__subclasses__() # optional - sage.rings.number_field + [] + + sage: len(sage.rings.abc.NumberField_cyclotomic.__subclasses__()) <= 1 + True + """ + + pass + + class AlgebraicField_common(Field): r""" Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 8d203e9f019..25317e4d80c 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -93,7 +93,7 @@ # **************************************************************************** from sage.misc.latex import latex -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.richcmp import richcmp diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index c4594dba8ad..ed0558413ea 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -35,7 +35,7 @@ from sage.structure.element cimport parent from sage.arith.misc import factor from sage.rings.integer_ring import ZZ from sage.misc.misc_c import prod -from sage.misc.misc import subsets +from sage.combinat.subset import subsets from sage.libs.pari.all import pari diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 2c6097e74e8..173224323ce 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -163,6 +163,8 @@ - Sebastian Oehms (2019): add :meth:`_factor_univariate_polynomial` (see :trac:`28631`) """ +import sage.rings.abc + from sage.misc.cachefunc import cached_method from sage.structure.richcmp import rich_to_bool @@ -1281,7 +1283,7 @@ def minpoly(self, var='x'): return QQ[var](QQ['x_1'](str(gap_p))) -class UniversalCyclotomicField(UniqueRepresentation, Field): +class UniversalCyclotomicField(UniqueRepresentation, sage.rings.abc.UniversalCyclotomicField): r""" The universal cyclotomic field. diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index 34265775dd3..de33e6f655e 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -18,7 +18,7 @@ from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets from sage.misc.cachefunc import cached_method -from sage.misc.misc import _stable_uniq +from sage.combinat.subset import uniq from sage.structure.element import Expression from .set import Set, Set_base, Set_boolean_operators, Set_add_sub_operators @@ -173,7 +173,7 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat else: other_predicates.append(predicate) - predicates = list(_stable_uniq(callable_symbolic_predicates + other_predicates)) + predicates = list(uniq(callable_symbolic_predicates + other_predicates)) if not other_predicates and not callable_symbolic_predicates: if names is None and category is None: