Skip to content

Commit 3ad892a

Browse files
author
Release Manager
committed
gh-37393: Tensor, exterior, and symmetric product of semigroup representations <!-- ^^^^^ Please provide a concise, informative and self-explanatory title. Don't put issue numbers in there, do this in the PR body below. For example, instead of "Fixes #1234" use "Introduce new method to calculate 1+1" --> <!-- Describe your changes here in detail --> This allows us to take tensor,. exterior, and symmetric products of semigroup representations. We also provide the following additional changes/improvements to help build examples and fix bugs: - Reflection representation of Coxeter groups. - Latex output of the identity in Artin groups and permutation groups. - ascii and unicode art of CFMs that do not have a `one_basis()`. <!-- Why is this change required? What problem does it solve? --> <!-- If this PR resolves an open issue, please link to it here. For example "Fixes #12345". --> <!-- If your change requires a documentation PR, please link it appropriately. --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> <!-- Feel free to remove irrelevant items. --> - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation accordingly. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on - #12345: short description why this is a dependency - #34567: ... --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> URL: #37393 Reported by: Travis Scrimshaw Reviewer(s): Frédéric Chapoton, Matthias Köppe, Travis Scrimshaw, trevorkarn
2 parents 28965ac + d9a4a01 commit 3ad892a

File tree

7 files changed

+1319
-267
lines changed

7 files changed

+1319
-267
lines changed

src/sage/algebras/clifford_algebra.py

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class CliffordAlgebraIndices(UniqueRepresentation, Parent):
5151
A facade parent for the indices of Clifford algebra.
5252
Users should not create instances of this class directly.
5353
"""
54-
def __init__(self, Qdim):
54+
def __init__(self, Qdim, degree=None):
5555
r"""
5656
Initialize ``self``.
5757
@@ -67,9 +67,30 @@ def __init__(self, Qdim):
6767
1111
6868
sage: type(i)
6969
<class 'sage.data_structures.bitset.FrozenBitset'>
70+
71+
sage: idx = CliffordAlgebraIndices(7, 3)
72+
sage: idx._nbits
73+
7
74+
sage: idx._degree
75+
3
76+
sage: idx._cardinality
77+
35
78+
79+
sage: idx = CliffordAlgebraIndices(7, 0)
80+
sage: idx._nbits
81+
7
82+
sage: idx._degree
83+
0
84+
sage: idx._cardinality
85+
1
7086
"""
7187
self._nbits = Qdim
72-
self._cardinality = 2 ** Qdim
88+
if degree is None:
89+
self._cardinality = 2 ** Qdim
90+
else:
91+
from sage.arith.misc import binomial
92+
self._cardinality = binomial(Qdim, degree)
93+
self._degree = degree
7394
# the if statement here is in case Qdim is 0.
7495
category = FiniteEnumeratedSets().Facade()
7596
Parent.__init__(self, category=category, facade=True)
@@ -92,10 +113,16 @@ def _element_constructor_(self, x):
92113
00001
93114
000001
94115
0000001
116+
117+
sage: idx = CliffordAlgebraIndices(0)
118+
sage: idx([])
119+
0
95120
"""
96121
if isinstance(x, (list, tuple, set, frozenset)):
97122
if len(x) > self._nbits:
98123
raise ValueError(f"{x=} is too long")
124+
if not x:
125+
return FrozenBitset()
99126
return FrozenBitset(x)
100127

101128
if isinstance(x, int):
@@ -129,6 +156,12 @@ def cardinality(self):
129156
True
130157
sage: len(idx) == 2^7
131158
True
159+
160+
sage: idx = CliffordAlgebraIndices(7, 3)
161+
sage: idx.cardinality() == binomial(7, 3)
162+
True
163+
sage: len(idx) == binomial(7, 3)
164+
True
132165
"""
133166
return self._cardinality
134167

@@ -149,14 +182,20 @@ def _repr_(self):
149182
Subsets of {0}
150183
sage: CliffordAlgebraIndices(2)
151184
Subsets of {0,1}
185+
sage: CliffordAlgebraIndices(5, 3)
186+
Subsets of {0,1,...,4} of size 3
152187
"""
188+
if self._degree is not None:
189+
extra = f" of size {self._degree}"
190+
else:
191+
extra = ""
153192
if self._nbits == 0:
154-
return "Subsets of {}"
193+
return "Subsets of {}" + extra
155194
if self._nbits == 1:
156-
return "Subsets of {0}"
195+
return "Subsets of {0}" + extra
157196
if self._nbits == 2:
158-
return "Subsets of {0,1}"
159-
return f"Subsets of {{0,1,...,{self._nbits-1}}}"
197+
return "Subsets of {0,1}" + extra
198+
return f"Subsets of {{0,1,...,{self._nbits-1}}}" + extra
160199

161200
def _latex_(self):
162201
r"""
@@ -166,21 +205,27 @@ def _latex_(self):
166205
167206
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
168207
sage: latex(CliffordAlgebraIndices(7))
169-
\mathcal{P}({0,1,\ldots,6})
208+
\mathcal{P}(\{0,1,\ldots,6\})
170209
sage: latex(CliffordAlgebraIndices(0))
171210
\mathcal{P}(\emptyset)
172211
sage: latex(CliffordAlgebraIndices(1))
173-
\mathcal{P}({0})
212+
\mathcal{P}(\{0\})
174213
sage: latex(CliffordAlgebraIndices(2))
175-
\mathcal{P}({0,1})
214+
\mathcal{P}(\{0,1\})
215+
sage: latex(CliffordAlgebraIndices(2, 1))
216+
\mathcal{P}(\{0,1\}, 1)
176217
"""
218+
if self._degree is not None:
219+
extra = f", {self._degree}"
220+
else:
221+
extra = ""
177222
if self._nbits == 0:
178-
return "\\mathcal{P}(\\emptyset)"
223+
return f"\\mathcal{{P}}(\\emptyset{extra})"
179224
if self._nbits == 1:
180-
return "\\mathcal{P}({0})"
225+
return f"\\mathcal{{P}}(\\{{0\\}}{extra})"
181226
if self._nbits == 2:
182-
return "\\mathcal{P}({0,1})"
183-
return f"\\mathcal{{P}}({{0,1,\\ldots,{self._nbits-1}}})"
227+
return f"\\mathcal{{P}}(\\{{0,1\\}}{extra})"
228+
return f"\\mathcal{{P}}(\\{{0,1,\\ldots,{self._nbits-1}\\}}{extra})"
184229

185230
def __iter__(self):
186231
r"""
@@ -200,9 +245,25 @@ def __iter__(self):
200245
101
201246
011
202247
111
248+
249+
sage: idx = CliffordAlgebraIndices(5, 3)
250+
sage: list(idx)
251+
[111, 1101, 11001, 1011, 10101, 10011, 0111, 01101, 01011, 00111]
252+
253+
sage: idx = CliffordAlgebraIndices(7, 0)
254+
sage: list(idx)
255+
[0]
203256
"""
204257
import itertools
205258
n = self._nbits
259+
if self._degree is not None:
260+
if self._degree == 0: # special corner case
261+
yield FrozenBitset()
262+
return
263+
for C in itertools.combinations(range(n), self._degree):
264+
yield FrozenBitset(C)
265+
return
266+
206267
yield FrozenBitset()
207268
k = 1
208269
while k <= n:
@@ -226,11 +287,35 @@ def __contains__(self, elt):
226287
True
227288
sage: FrozenBitset('000001') in idx
228289
False
290+
291+
sage: idx = CliffordAlgebraIndices(6, 3)
292+
sage: FrozenBitset('01011') in idx
293+
True
294+
sage: FrozenBitset('00011') in idx
295+
False
296+
sage: int(7) in idx
297+
True
298+
sage: int(8) in idx
299+
False
300+
301+
sage: idx = CliffordAlgebraIndices(7, 0)
302+
sage: FrozenBitset() in idx
303+
True
304+
sage: FrozenBitset('01') in idx
305+
False
306+
sage: int(0) in idx
307+
True
308+
sage: int(5) in idx
309+
False
229310
"""
230311
if isinstance(elt, int):
312+
if self._degree is not None and sum(ZZ(elt).bits()) != self._degree:
313+
return False
231314
return elt < self._cardinality and elt >= 0
232315
if not isinstance(elt, FrozenBitset):
233316
return False
317+
if self._degree is not None and len(elt) != self._degree:
318+
return False
234319
return elt.capacity() <= self._nbits
235320

236321
def _an_element_(self):
@@ -252,14 +337,26 @@ def _an_element_(self):
252337
sage: idx = CliffordAlgebraIndices(3)
253338
sage: idx._an_element_()
254339
11
340+
sage: idx = CliffordAlgebraIndices(5, 3)
341+
sage: idx._an_element_()
342+
111
343+
sage: idx = CliffordAlgebraIndices(7, 0)
344+
sage: idx._an_element_()
345+
0
255346
"""
256347
if not self._nbits:
257348
return FrozenBitset()
258349

350+
if self._degree is not None:
351+
if self._degree == 0: # special corner case
352+
return FrozenBitset()
353+
return FrozenBitset(range(self._degree))
354+
259355
from sage.combinat.subset import SubsetsSorted
260356
X = SubsetsSorted(range(self._nbits))
261357
return FrozenBitset(X.an_element())
262358

359+
263360
class CliffordAlgebra(CombinatorialFreeModule):
264361
r"""
265362
The Clifford algebra of a quadratic form.

src/sage/categories/coxeter_groups.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,14 +952,52 @@ def sign_representation(self, base_ring=None, side="twosided"):
952952
Sign representation of
953953
Weyl Group of type ['A', 1, 1] (as a matrix group acting on the root space)
954954
over Integer Ring
955-
956955
"""
957956
if base_ring is None:
958957
from sage.rings.integer_ring import ZZ
959958
base_ring = ZZ
960959
from sage.modules.with_basis.representation import SignRepresentationCoxeterGroup
961960
return SignRepresentationCoxeterGroup(self, base_ring)
962961

962+
def reflection_representation(self, base_ring=None, side="left"):
963+
r"""
964+
Return the reflection representation of ``self``.
965+
966+
This is also the canonical faithful representation of a
967+
Coxeter group.
968+
969+
INPUT:
970+
971+
- ``base_ring`` -- (optional) the base ring; the default is
972+
the base ring of :meth:`canonical_representation`
973+
- ``side`` -- ignored
974+
975+
EXAMPLES::
976+
977+
sage: W = CoxeterGroup(['D', 4])
978+
sage: W.reflection_representation()
979+
Reflection representation of Finite Coxeter group over
980+
Integer Ring with Coxeter matrix:
981+
[1 3 2 2]
982+
[3 1 3 3]
983+
[2 3 1 2]
984+
[2 3 2 1]
985+
986+
sage: W = CoxeterGroup(['I', 13])
987+
sage: W.reflection_representation()
988+
Reflection representation of Finite Coxeter group over
989+
Universal Cyclotomic Field with Coxeter matrix:
990+
[ 1 13]
991+
[13 1]
992+
993+
sage: W = WeylGroup(["B", 3, 1])
994+
sage: W.reflection_representation(QQ)
995+
Reflection representation of Weyl Group of type ['B', 3, 1]
996+
(as a matrix group acting on the root space)
997+
"""
998+
from sage.modules.with_basis.representation import ReflectionRepresentation
999+
return ReflectionRepresentation(self, base_ring)
1000+
9631001
def demazure_product(self, Q):
9641002
r"""
9651003
Return the Demazure product of the list ``Q`` in ``self``.
@@ -1169,6 +1207,11 @@ def canonical_representation(self):
11691207
r"""
11701208
Return the canonical faithful representation of ``self``.
11711209
1210+
.. SEEALSO::
1211+
1212+
To obtain the underlying module with the action, use
1213+
:meth:`reflection_representation`.
1214+
11721215
EXAMPLES::
11731216
11741217
sage: W = WeylGroup("A3") # needs sage.combinat sage.groups

src/sage/groups/artin.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def _latex_(self):
5757
5858
TESTS::
5959
60-
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
60+
sage: A = ArtinGroup(['B', 3]) # needs sage.rings.number_field
6161
sage: b = A([1, 2, 3, -1, 2, -3]) # needs sage.rings.number_field
6262
sage: b._latex_() # needs sage.rings.number_field
6363
'\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}'
@@ -66,9 +66,14 @@ def _latex_(self):
6666
sage: b = B([1, 2, 3, -1, 2, -3])
6767
sage: b._latex_()
6868
'\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}'
69+
sage: B.one()._latex_()
70+
'1'
6971
"""
72+
word = self.Tietze()
73+
if not word:
74+
return '1'
7075
return ''.join(r"\sigma_{%s}^{-1}" % (-i) if i < 0 else r"\sigma_{%s}" % i
71-
for i in self.Tietze())
76+
for i in word)
7277

7378
def exponent_sum(self):
7479
"""

src/sage/groups/perm_gps/permgroup_element.pyx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -948,10 +948,15 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement):
948948
sage: S = SymmetricGroup(['a', 'b'])
949949
sage: latex(S.gens())
950950
\left((\text{\texttt{a}},\text{\texttt{b}})\right)
951+
sage: latex(S.one())
952+
1
951953
"""
954+
cycle_tuples = self.cycle_tuples()
955+
if not cycle_tuples:
956+
return '1'
952957
from sage.misc.latex import latex
953958
return "".join(("(" + ",".join(latex(x) for x in cycle) + ")")
954-
for cycle in self.cycle_tuples())
959+
for cycle in cycle_tuples)
955960

956961
def __getitem__(self, i):
957962
r"""

0 commit comments

Comments
 (0)