Skip to content

Commit

Permalink
preliminary support for generating structures of a composition
Browse files Browse the repository at this point in the history
  • Loading branch information
mantepse committed Nov 14, 2024
1 parent 92ba51f commit 84086df
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 32 deletions.
26 changes: 21 additions & 5 deletions src/sage/combinat/set_partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ def _repr_(self):
sage: S([[1,3],[2,4]])
{{1, 3}, {2, 4}}
"""
return '{' + ', '.join('{' + repr(sorted(x))[1:-1] + '}' for x in self) + '}'
try:
s = [sorted(x) for x in self]
except TypeError:
s = [sorted(x, key=str) for x in self]
return '{' + ', '.join('{' + repr(x)[1:-1] + '}' for x in s) + '}'

def __hash__(self):
"""
Expand Down Expand Up @@ -532,7 +536,7 @@ def pre_conjugate(sp):


class SetPartition(AbstractSetPartition,
metaclass=InheritComparisonClasscallMetaclass):
metaclass=InheritComparisonClasscallMetaclass):
r"""
A partition of a set.
Expand Down Expand Up @@ -620,7 +624,11 @@ def __init__(self, parent, s, check=True):
{}
"""
self._latex_options = {}
ClonableArray.__init__(self, parent, sorted(map(frozenset, s), key=min), check=check)
try:
s = sorted(map(frozenset, s), key=min)
except TypeError:
s = sorted(map(frozenset, s), key=lambda b: min(str(b)))
ClonableArray.__init__(self, parent, s, check=check)

def check(self):
"""
Expand Down Expand Up @@ -2821,7 +2829,11 @@ def __iter__(self):
sage: SetPartitions(["a", "b"]).list()
[{{'a', 'b'}}, {{'a'}, {'b'}}]
"""
for sp in set_partition_iterator(sorted(self._set)):
try:
s = sorted(self._set)
except TypeError:
s = sorted(self._set, key=str)
for sp in set_partition_iterator(s):
yield self.element_class(self, sp, check=False)

def base_set(self):
Expand Down Expand Up @@ -3179,7 +3191,11 @@ def __iter__(self):
sage: SetPartitions(["a", "b", "c"], 2).list()
[{{'a', 'c'}, {'b'}}, {{'a'}, {'b', 'c'}}, {{'a', 'b'}, {'c'}}]
"""
for sp in set_partition_iterator_blocks(sorted(self._set), self._k):
try:
s = sorted(self._set)
except TypeError:
s = sorted(self._set, key=str)
for sp in set_partition_iterator_blocks(s, self._k):
yield self.element_class(self, sp, check=False)

def __contains__(self, x):
Expand Down
106 changes: 79 additions & 27 deletions src/sage/rings/lazy_species.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,15 +468,13 @@ def __call__(self, *args):
sage: from sage.rings.species import PolynomialSpecies
sage: P = PolynomialSpecies(QQ, "X")
sage: Gc = L(lambda n: sum(P(G.automorphism_group()) for G in graphs(n) if G.is_connected()) if n else 0)
sage: E = L(lambda n: SymmetricGroup(n))
sage: G = L(lambda n: sum(P(G.automorphism_group()) for G in graphs(n)))
sage: E = L.Sets()
sage: G = L.Graphs()
sage: E(Gc) - G
O^7
sage: L = LazySpecies(QQ, "X")
sage: X = L(SymmetricGroup(1))
sage: E = L(lambda n: SymmetricGroup(n))
sage: L.<X> = LazySpecies(QQ)
sage: E = L.Sets()
sage: A = L.undefined(1)
sage: A.define(X*E(A))
sage: A[5]
Expand All @@ -487,8 +485,8 @@ def __call__(self, *args):
sage: [sum(F[n].monomial_coefficients().values()) for n in range(1, 7)]
[1, 3, 7, 19, 47, 130]
sage: oeis(_)
0: A001372: Number of unlabeled mappings (or mapping patterns) from n points to themselves; number of unlabeled endofunctions.
0: A001372: Number of unlabeled mappings (or mapping patterns)
from n points to themselves; number of unlabeled endofunctions.
sage: R.<q> = QQ[]
sage: L = LazySpecies(R, "X")
Expand All @@ -499,8 +497,7 @@ def __call__(self, *args):
TESTS::
sage: L = LazySpecies(QQ, "X")
sage: X = L(SymmetricGroup(1))
sage: L.<X> = LazySpecies(QQ)
sage: E2 = L(SymmetricGroup(2))
sage: X(X + E2)
X + E_2 + O^8
Expand All @@ -510,18 +507,13 @@ def __call__(self, *args):
sage: (1+E2)(X)
1 + E_2 + O^7
sage: L = LazySpecies(QQ, "X, Y")
sage: P = PolynomialSpecies(QQ, "X, Y")
sage: X = L(P(SymmetricGroup(1), {0: [1]}))
sage: Y = L(P(SymmetricGroup(1), {1: [1]}))
sage: L.<X,Y> = LazySpecies(QQ)
sage: X(Y, 0)
Y + O^8
sage: L1 = LazySpecies(QQ, "X")
sage: L = LazySpecies(QQ, "X, Y")
sage: P = PolynomialSpecies(QQ, "X, Y")
sage: X = L(P(SymmetricGroup(1), {0: [1]}))
sage: E = L1(lambda n: SymmetricGroup(n))
sage: E = L1.Sets()
sage: L.<X,Y> = LazySpecies(QQ)
sage: E(X)
1 + X + E_2(X) + E_3(X) + E_4(X) + E_5(X) + E_6(X) + O^7
"""
Expand All @@ -530,10 +522,10 @@ def __call__(self, *args):

class SumSpeciesElement(LazySpeciesElement):
def __init__(self, left, right):
self._left = left
self._right = right
F = super(LazySpeciesElement, type(left))._add_(left, right)
super().__init__(F.parent(), F._coeff_stream)
self._left = left
self._right = right

def structures(self, *labels):
labels = label_sets(self.parent()._arity, labels)
Expand All @@ -543,10 +535,10 @@ def structures(self, *labels):

class ProductSpeciesElement(LazySpeciesElement):
def __init__(self, left, right):
self._left = left
self._right = right
F = super(LazySpeciesElement, type(left))._mul_(left, right)
super().__init__(F.parent(), F._coeff_stream)
self._left = left
self._right = right

def structures(self, *labels):
"""
Expand Down Expand Up @@ -652,6 +644,66 @@ def coefficient(n):

coeff_stream = Stream_function(coefficient, P._sparse, sorder * gv)
super().__init__(P, coeff_stream)
self._left = left
self._args = args

def structures(self, *labels):
r"""
EXAMPLES::
sage: from sage.rings.lazy_species import LazySpecies
sage: L = LazySpecies(QQ, "X")
sage: E = L.Sets()
sage: E1 = L.Sets(min=1)
sage: list(E(E1).structures([1,2,3]))
[({((1, 0), (2, 0), (3, 0))}, ({1, 2, 3},)),
({((1, 0), (2, 0)), ((3, 0),)}, ({1, 2}, {3})),
({((1, 0), (3, 0)), ((2, 0),)}, ({1, 3}, {2})),
({((1, 0),), ((2, 0), (3, 0))}, ({1}, {2, 3})),
({((1, 0),), ((2, 0),), ((3, 0),)}, ({1}, {2}, {3}))]
sage: C = L.Cycles()
sage: L.<X, Y> = LazySpecies(QQ)
sage: sum(1 for s in C(X*Y).structures([1,2,3], [1,2,3]))

Check failure on line 668 in src/sage/rings/lazy_species.py

View workflow job for this annotation

GitHub Actions / test-new

Failed example:

Failed example:: Got: 12
sage: C(X*Y).generating_series()[6]
1/3*X^3*Y^3
sage: sum(1 for s in E(X*Y).structures([1,2,3], ["a", "b", "c"]))
6
"""
F = self._left
G = self._args
m = len(G) # == F.parent()._arity
k = self.parent()._arity # == G[i].parent()._arity
labels = label_sets(k, labels)
# make label sets disjoint
U = [(e, i) for i, l in enumerate(labels) for e in l]

def split_set(C):
C_split = defaultdict(list)
for e, i in C:
C_split[i].append(e)
return [C_split[i] for i in range(k)]

Par_U = SetPartitions(U)
for pi in Par_U:
# Fix an arbitrary order of the blocks
pi_list = list(pi)
# Generate all functions chi from pi to {0, ..., m-1}
for chi in itertools.product(range(m), repeat=len(pi_list)):
chi_inv = defaultdict(list)
for b, i in zip(pi_list, chi):
chi_inv[i].append(b)

# The set of structures is the Cartesian product of
# the structures in F[chi_inv[i] for i in range(m)]
# and for each set C in chi_inv[i] the set of
# structures in G_i[C]
F_s = F.structures(*[[tuple(b) for b in chi_inv[i]] for i in range(m)])
G_s = [G[i].structures(*split_set(C)) for i in range(m) for C in chi_inv[i]]
yield from itertools.product(F_s, itertools.product(*G_s))


class LazySpecies(LazyCompletionGradedAlgebra):
Expand Down Expand Up @@ -719,14 +771,14 @@ def __init__(self, base_ring, names, sparse):
if self._arity == 1:
self.Graphs = lambda: GraphSpecies(self)
self.SetPartitions = lambda: SetPartitionSpecies(self)
self.Sets = lambda: SetSpecies(self)
self.Sets = lambda min=0: SetSpecies(self, min)
self.Cycles = lambda: CycleSpecies(self)


class SetSpecies(LazySpeciesElement):
def __init__(self, parent):
def __init__(self, parent, min):
P = parent._laurent_poly_ring
S = parent(SymmetricGroup)
S = parent(lambda n: SymmetricGroup(n) if n >= min else 0)
super().__init__(parent, S._coeff_stream)

def structures(self, *labels):
Expand Down Expand Up @@ -785,8 +837,8 @@ def isotypes(self, labels):
class SetPartitionSpecies(LazySpeciesElement):
def __init__(self, parent):
P = parent._laurent_poly_ring
E = parent(SymmetricGroup)
E1 = parent(lambda n: SymmetricGroup(n) if n else 0)
E = parent.Sets()
E1 = parent.Sets(min=1)
super().__init__(parent, E(E1)._coeff_stream)

def isotypes(self, labels):
Expand Down

0 comments on commit 84086df

Please sign in to comment.