Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
is_symmetric for multivariate polynomials
Browse files Browse the repository at this point in the history
Implement action of permutation group element on ETuple and is_symmetric
on multivariate polynomials.
  • Loading branch information
videlec committed Apr 24, 2020
1 parent 249fc90 commit ccdd618
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/sage/groups/perm_gps/permgroup_element.pxd
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from sage.structure.element cimport MultiplicativeGroupElement, MonoidElement, Element
from sage.structure.list_clone cimport ClonableIntArray
from sage.rings.polynomial.polydict cimport ETuple
from sage.libs.gap.element cimport GapElement

cdef class PermutationGroupElement(MultiplicativeGroupElement):
Expand All @@ -24,3 +25,4 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement):
cdef public __custom_name
cpdef list _act_on_list_on_position(self, list x)
cpdef ClonableIntArray _act_on_array_on_position(self, ClonableIntArray x)
cpdef ETuple _act_on_etuple_on_position(self, ETuple x, bint self_on_left)
42 changes: 41 additions & 1 deletion src/sage/groups/perm_gps/permgroup_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ import random

import sage.groups.old as group

from libc.stdlib cimport qsort

from cysignals.memory cimport sig_malloc, sig_calloc, sig_realloc, sig_free
from cpython.list cimport *

Expand Down Expand Up @@ -139,7 +141,8 @@ cdef arith_llong arith = arith_llong()
cdef extern from *:
long long LLONG_MAX

#import permgroup_named
cdef int etuple_index_cmp(const void * a, const void * b) nogil:
return ((<int *> a)[0] > (<int *> b)[0]) - ((<int *> a)[0] < (<int *> b)[0])

def make_permgroup_element(G, x):
"""
Expand Down Expand Up @@ -1132,6 +1135,43 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement):
y.set_immutable()
return y

cpdef ETuple _act_on_etuple_on_position(self, ETuple x, bint self_on_left):
r"""
Return the right action of this permutation on the ETuple ``x``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple
sage: S = SymmetricGroup(6)
sage: e = ETuple([1,2,3,4,5,6])
sage: S("(1,4)")._act_on_etuple_on_position(e, True)
(4, 2, 3, 1, 5, 6)
sage: S("(1,2,3,4,5,6)")._act_on_etuple_on_position(e, True)
(6, 1, 2, 3, 4, 5)
sage: S("(1,3,5)(2,4,6)")._act_on_etuple_on_position(e, False)
(3, 4, 5, 6, 1, 2)
sage: e = ETuple([1,2,0,0,0,6])
sage: S("(1,4)")._act_on_etuple_on_position(e, True)
(0, 2, 0, 1, 0, 6)
sage: S("(1,2,3,4,5,6)")._act_on_etuple_on_position(e, True)
(6, 1, 2, 0, 0, 0)
"""
cdef size_t ind
cdef ETuple result = ETuple.__new__(ETuple)

if not self_on_left:
self = ~self

result._length = x._length
result._nonzero = x._nonzero
result._data = <int*> sig_malloc(sizeof(int)*result._nonzero*2)
for ind in range(x._nonzero):
result._data[2*ind] = self.perm[x._data[2*ind]] # index
result._data[2*ind + 1] = x._data[2*ind+1] # exponent
qsort(result._data, result._nonzero, 2 * sizeof(int), etuple_index_cmp)
return result

cpdef _act_on_(self, x, bint self_on_left):
"""
Return the right action of self on left.
Expand Down
83 changes: 83 additions & 0 deletions src/sage/rings/polynomial/multi_polynomial.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,89 @@ cdef class MPolynomial(CommutativeRingElement):
else:
return self.parent().change_ring(R)(self.dict())

def is_symmetric(self, group=None):
r"""
Return whether this polynomial is symmetric.
INPUT:
- ``group`` (optional) - if set, test whether the polynomial is
symmetric with respect to the given permutation group.
EXAMPLES::
sage: R.<x,y,z> = QQ[]
sage: p = (x+y+z)**2 - 3 * (x+y)*(x+z)*(y+z)
sage: p.is_symmetric()
True
sage: (x + y - z).is_symmetric()
False
sage: R.one().is_symmetric()
True
sage: p = (x-y)*(y-z)*(z-x)
sage: p.is_symmetric()
False
sage: p.is_symmetric(AlternatingGroup(3))
True
sage: R.<x,y> = QQ[]
sage: ((x + y)**2).is_symmetric()
True
sage: R.one().is_symmetric()
True
sage: (x + 2*y).is_symmetric()
False
An example with a GAP permutation group (here the quaternions)::
sage: R = PolynomialRing(QQ, 'x', 8)
sage: x = R.gens()
sage: p = sum(prod(x[i] for i in e) for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), (3,4,5), (3,4,6), (3,5,6), (4,5,6)])
sage: p.is_symmetric(libgap.TransitiveGroup(8, 5))
True
sage: p = sum(prod(x[i] for i in e) for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), (3,4,5), (3,4,6), (3,5,6)])
sage: p.is_symmetric(libgap.TransitiveGroup(8, 5))
False
TESTS::
sage: R = PolynomialRing(QQ, 'x', 3)
sage: R.one().is_symmetric(3)
Traceback (most recent call last):
...
ValueError: wrong argument 'group'
"""
n = self.parent().ngens()
if n <= 1:
return True
if group is None:
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
S = SymmetricGroup(n)
gens = S.gens()
else:
try:
# for Sage group
gens = group.gens()
except AttributeError:
# for GAP group
try:
gens = group.GeneratorsOfGroup()
except AttributeError:
raise ValueError("wrong argument 'group'")
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
S = SymmetricGroup(n)
gens = [S(g) for g in gens]

cdef dict coeffs = self.dict()
zero = self.base_ring().zero()
for e in self.exponents():
coeff = coeffs[e]
for g in gens:
if coeffs.get(g._act_on_etuple_on_position(e, True), zero) != coeff:
return False
return True

def _gap_(self, gap):
"""
Return a representation of ``self`` in the GAP interface
Expand Down

0 comments on commit ccdd618

Please sign in to comment.