Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support left and right actions for species #38975

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 84 additions & 30 deletions src/sage/rings/species.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

"""

from itertools import accumulate, chain
from itertools import accumulate, chain, product

from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis
from sage.categories.modules import Modules
Expand Down Expand Up @@ -730,34 +730,35 @@
Element = AtomicSpeciesElement


def _stabilizer_subgroups(G, X, a):
def _stabilizer_subgroups(G, X, a, side='right', check=True):
r"""
Return subgroups conjugate to the stabilizer subgroups of the
given (left) group action.
given group action.

INPUT:

- ``G`` -- the acting group
- ``X`` -- the set ``G`` is acting on
- ``a`` -- the (left) action
- ``a`` -- the action, a function `G\times X\to X` if ``side`` is
``'left'``, `X\times G\to X` if ``side`` is ``'right'``

EXAMPLES::

sage: from sage.rings.species import _stabilizer_subgroups
sage: S = SymmetricGroup(4)
sage: X = SetPartitions(S.degree(), [2,2])
sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x])
sage: _stabilizer_subgroups(S, X, a)
sage: _stabilizer_subgroups(S, X, a, side='left')
[Permutation Group with generators [(1,2), (1,3)(2,4)]]

sage: S = SymmetricGroup(8)
sage: X = SetPartitions(S.degree(), [3,3,2])
sage: _stabilizer_subgroups(S, X, a)
sage: _stabilizer_subgroups(S, X, a, side='left', check=False)
[Permutation Group with generators [(7,8), (6,7), (4,5), (1,3)(2,6)(4,7)(5,8), (1,3)]]

sage: S = SymmetricGroup(4)
sage: X = SetPartitions(S.degree(), 2)
sage: _stabilizer_subgroups(S, X, a)
sage: _stabilizer_subgroups(S, X, a, side='left')
[Permutation Group with generators [(1,4), (1,3,4)],
Permutation Group with generators [(1,3)(2,4), (1,4)]]

Expand All @@ -766,19 +767,54 @@

sage: S = SymmetricGroup([1,2,4,5,3,6]).young_subgroup([4, 2])
sage: X = [pi for pi in SetPartitions(6, [3,3]) if all(sum(1 for e in b if e % 3) == 2 for b in pi)]
sage: _stabilizer_subgroups(S, X, a)
sage: _stabilizer_subgroups(S, X, a, side='left')
[Permutation Group with generators [(1,2), (4,5), (1,4)(2,5)(3,6)]]

TESTS::

sage: _stabilizer_subgroups(SymmetricGroup(2), [1], lambda pi, H: H)
sage: _stabilizer_subgroups(SymmetricGroup(2), [1], lambda pi, H: H, side='left')
[Permutation Group with generators [(1,2)]]

sage: _stabilizer_subgroups(SymmetricGroup(2), [1, 1], lambda pi, H: H, side='left')
Traceback (most recent call last):
...
ValueError: The argument X must be a set, but [1, 1] contains duplicates

sage: G = SymmetricGroup(3)
sage: X = [1, 2, 3]
sage: _stabilizer_subgroups(G, X, lambda pi, x: pi(x), side='left')
[Permutation Group with generators [(2,3)]]
sage: _stabilizer_subgroups(G, X, lambda x, pi: pi(x), side='right')
Traceback (most recent call last):
...
ValueError: The given function is not a right group action: g=(1,3,2), h=(2,3), x=1 do not satisfy the condition
"""
to_gap = {x: i for i, x in enumerate(X, 1)}

X = set(X) # because orbit_decomposition turns X into a set
g_orbits = [orbit_decomposition(X, lambda x: a(g, x))
for g in G.gens()]
X_set = set(X) # because orbit_decomposition turns X into a set

if len(X_set) != len(X):
raise ValueError(f"The argument X must be a set, but {X} contains duplicates")

if side == "left":
if check:
for g, h, x in product(G, G, X):
# Warning: the product in permutation groups is left-to-right composition
if not a(h * g, x) == a(g, a(h, x)):
raise ValueError(f"The given function is not a left group action: g={g}, h={h}, x={x} do not satisfy the condition")

Check warning on line 804 in src/sage/rings/species.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/species.py#L804

Added line #L804 was not covered by tests

g_orbits = [orbit_decomposition(X_set, lambda x: a(g, x))
for g in G.gens()]
elif side == "right":
if check:
for g, h, x in product(G, G, X):
if not a(x, h * g) == a(a(x, g), h):
raise ValueError(f"The given function is not a right group action: g={g}, h={h}, x={x} do not satisfy the condition")

g_orbits = [orbit_decomposition(X_set, lambda x: a(x, g))
for g in G.gens()]
else:
raise ValueError(f"The argument side must be 'left' or 'right' but is {side}")

Check warning on line 817 in src/sage/rings/species.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/species.py#L817

Added line #L817 was not covered by tests

gens = [PermutationGroupElement([tuple([to_gap[x] for x in o])
for o in g_orbit])
Expand Down Expand Up @@ -873,13 +909,15 @@
INPUT:

- ``G`` -- element of ``self`` (in this case ``pi`` must be
``None``) permutation group, or pair ``(X, a)`` consisting
of a finite set and a transitive action
``None``) or permutation group, or triple ``(X, a, side)``
consisting of a finite set, a transitive action and
a string 'left' or 'right'; the side can be omitted, it is
then assumed to be 'right'
- ``pi`` -- ``dict`` mapping sorts to iterables whose union
is the domain of ``G`` (if ``G`` is a permutation group) or
the domain of the acting symmetric group (if ``G`` is a
pair ``(X, a)``); if `k=1` and ``G`` is a permutation
group, ``pi`` can be omitted
triple ``(X, a, side)``); if `k=1` and ``G`` is a
permutation group, ``pi`` can be omitted
- ``check`` -- boolean (default: ``True``); skip input
checking if ``False``

Expand All @@ -901,11 +939,11 @@
sage: M = MolecularSpecies("X")
sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x])
sage: X = SetPartitions(4, [2, 2])
sage: M((X, a), {0: X.base_set()})
sage: M((X, a, 'left'), {0: X.base_set()})
P_4

sage: X = SetPartitions(8, [4, 2, 2])
sage: M((X, a), {0: X.base_set()})
sage: M((X, a, 'left'), {0: X.base_set()}, check=False)
E_4*P_4

TESTS::
Expand All @@ -922,7 +960,7 @@

sage: X = SetPartitions(4, 2)
sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x])
sage: M((X, a), {0: [1,2], 1: [3,4]})
sage: M((X, a, 'left'), {0: [1,2], 1: [3,4]})
Traceback (most recent call last):
...
ValueError: action is not transitive
Expand Down Expand Up @@ -962,18 +1000,25 @@
...
ValueError: 0 must be a permutation group or a pair (X, a)
specifying a group action of the symmetric group on pi=None

"""
if parent(G) is self:
# pi cannot be None because of framework
raise ValueError("cannot reassign sorts to a molecular species")

if isinstance(G, tuple):
X, a = G
if len(G) == 2:
X, a = G
side = 'right'

Check warning on line 1012 in src/sage/rings/species.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/species.py#L1011-L1012

Added lines #L1011 - L1012 were not covered by tests
else:
X, a, side = G
if side not in ['left', 'right']:
raise ValueError(f"the side must be 'right' or 'left', but is {side}")

Check warning on line 1016 in src/sage/rings/species.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/species.py#L1016

Added line #L1016 was not covered by tests
dompart = [sorted(pi.get(s, [])) for s in range(self._arity)]
S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2]
+ [(b[0], b[1]) for b in dompart if len(b) > 1],
domain=list(chain(*dompart)))
H = _stabilizer_subgroups(S, X, a)
H = _stabilizer_subgroups(S, X, a, side=side, check=check)
if len(H) > 1:
raise ValueError("action is not transitive")
G = H[0]
Expand Down Expand Up @@ -2072,8 +2117,10 @@
INPUT:

- ``G`` -- element of ``self`` (in this case ``pi`` must be
``None``), permutation group, or pair ``(X, a)`` consisting
of a finite set and an action
``None``) or permutation group, or triple ``(X, a, side)``
consisting of a finite set, an action and a string 'left'
or 'right'; the side can be omitted, it is then assumed to
be 'right'
- ``pi`` -- ``dict`` mapping sorts to iterables whose union
is the domain of ``G`` (if ``G`` is a permutation group) or
the domain of the acting symmetric group (if ``G`` is a
Expand All @@ -2091,13 +2138,13 @@

sage: X = SetPartitions(4, 2)
sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x])
sage: P((X, a), {0: [1,2], 1: [3,4]})
sage: P((X, a, 'left'), {0: [1,2], 1: [3,4]})
E_2(X)*E_2(Y) + X^2*E_2(Y) + E_2(XY) + Y^2*E_2(X)

sage: P = PolynomialSpecies(ZZ, ["X"])
sage: X = SetPartitions(4, 2)
sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x])
sage: P((X, a), {0: [1,2,3,4]})
sage: P((X, a, 'left'), {0: [1,2,3,4]})
X*E_3 + P_4

The species of permutation groups::
Expand All @@ -2106,10 +2153,10 @@
sage: n = 4
sage: S = SymmetricGroup(n)
sage: X = S.subgroups()
sage: def act(pi, G): # WARNING: returning H does not work because of equality problems
sage: def act(G, pi): # WARNING: returning H does not work because of equality problems
....: H = S.subgroup(G.conjugate(pi).gens())
....: return next(K for K in X if K == H)
sage: P((X, act), {0: range(1, n+1)})
sage: P((X, act), {0: range(1, n+1)}, check=False)
4*E_4 + 4*P_4 + E_2^2 + 2*X*E_3

Create a multisort species given an action::
Expand All @@ -2127,7 +2174,7 @@
....: if r == t and c == b:
....: return r, c
....: raise ValueError
sage: P((X, lambda g, x: act(x[0], x[1], g)), pi)
sage: P((X, lambda g, x: act(x[0], x[1], g), 'left'), pi)
2*Y*E_2(X)

TESTS::
Expand Down Expand Up @@ -2157,18 +2204,25 @@
ValueError: 1/2 must be an element of the base ring, a permutation
group or a pair (X, a) specifying a group action of the symmetric
group on pi=None

"""
if parent(G) is self:
# pi cannot be None because of framework
raise ValueError("cannot reassign sorts to a polynomial species")

if isinstance(G, tuple):
X, a = G
if len(G) == 2:
X, a = G
side = 'right'
else:
X, a, side = G
if side not in ['left', 'right']:
raise ValueError(f"the side must be 'right' or 'left', but is {side}")

Check warning on line 2220 in src/sage/rings/species.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/species.py#L2220

Added line #L2220 was not covered by tests
dompart = [sorted(pi.get(s, [])) for s in range(self._arity)]
S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2]
+ [(b[0], b[1]) for b in dompart if len(b) > 1],
domain=list(chain(*dompart)))
Hs = _stabilizer_subgroups(S, X, a)
Hs = _stabilizer_subgroups(S, X, a, side=side, check=check)
return self.sum_of_terms((self._indices(H, pi, check=check), ZZ.one())
for H in Hs)

Expand Down
Loading