I implemented (well, the implementation is trivial) the following, and I'd like feedback. I am not completely sure whether the interface for the second variant, where the generators of the acting group are required, is ideal, but I think it looks useable.
A more serious problem is that orbits are currently computed twice: once when creating the generators of the permutation group, and another time, when asking for them.
Martin
"""
...
We can create a permutation group from a group action::
sage: A = lambda x: (2*x) % 6
sage: X = [0,1,2,3,4,5]
sage: G = PermutationGroup(action=A, domain=X)
sage: G.orbits()
[[0], [1, 2, 4], [3], [5]]
sage: A = lambda g, x: vector(g*x, immutable=True)
sage: X = [vector(x, immutable=True) for x in GF(3)^2]
sage: G = SL(2,3); G.gens()
(
[1 1] [0 1]
[0 1], [2 0]
)
sage: H = PermutationGroup(G.gens(), action=A, domain=X)
sage: H.orbits()
[[(0, 0)], [(1, 0), (0, 2), (2, 2), (2, 0), (1, 2), (2, 1), (0, 1), (1, 1)]]
sage: H.gens()
[((0,1),(1,1),(2,1))((0,2),(2,2),(1,2)),
((1,0),(0,2),(2,0),(0,1))((1,1),(1,2),(2,2),(2,1))]
...
"""
if not is_ExpectElement(gens) and hasattr(gens, '_permgroup_'):
return gens._permgroup_()
if gens is not None and not isinstance(gens, (tuple, list, GapElement)):
raise TypeError("gens must be a tuple, list, or GapElement")
gap_group = kwds.get("gap_group", None)
domain = kwds.get("domain", None)
canonicalize = kwds.get("canonicalize", True)
category = kwds.get("category", None)
action = kwds.get("action", None)
if action is not None:
if domain is None:
raise ValueError("you must specify the domain for an action")
from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition
if gap_group is not None:
raise ValueError("gap_group is not supported with action")
if gens is None and gap_group is None:
gens = [tuple(o) for o in orbit_decomposition(domain, action)]
else:
gens = [[tuple(o) for o in orbit_decomposition(domain, lambda x: action(g, x))]
for g in gens]
if args:
from sage.misc.superseded import deprecation
deprecation(31510, "gap_group, domain, canonicalize, category will become keyword only")
if len(args) > 4:
raise ValueError("invalid input")
args = list(args)
gap_group = args.pop(0)
if args:
domain = args.pop(0)
if args:
canonicalize = args.pop(0)
if args:
category = args.pop(0)
return PermutationGroup_generic(gens=gens, gap_group=gap_group, domain=domain,
canonicalize=canonicalize, category=category)