Skip to content

Commit

Permalink
gh-37393: Tensor, exterior, and symmetric product of semigroup repres…
Browse files Browse the repository at this point in the history
…entations

    
<!-- ^^^^^
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
  • Loading branch information
Release Manager committed Mar 29, 2024
2 parents 28965ac + d9a4a01 commit 3ad892a
Show file tree
Hide file tree
Showing 7 changed files with 1,319 additions and 267 deletions.
123 changes: 110 additions & 13 deletions src/sage/algebras/clifford_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class CliffordAlgebraIndices(UniqueRepresentation, Parent):
A facade parent for the indices of Clifford algebra.
Users should not create instances of this class directly.
"""
def __init__(self, Qdim):
def __init__(self, Qdim, degree=None):
r"""
Initialize ``self``.
Expand All @@ -67,9 +67,30 @@ def __init__(self, Qdim):
1111
sage: type(i)
<class 'sage.data_structures.bitset.FrozenBitset'>
sage: idx = CliffordAlgebraIndices(7, 3)
sage: idx._nbits
7
sage: idx._degree
3
sage: idx._cardinality
35
sage: idx = CliffordAlgebraIndices(7, 0)
sage: idx._nbits
7
sage: idx._degree
0
sage: idx._cardinality
1
"""
self._nbits = Qdim
self._cardinality = 2 ** Qdim
if degree is None:
self._cardinality = 2 ** Qdim
else:
from sage.arith.misc import binomial
self._cardinality = binomial(Qdim, degree)
self._degree = degree
# the if statement here is in case Qdim is 0.
category = FiniteEnumeratedSets().Facade()
Parent.__init__(self, category=category, facade=True)
Expand All @@ -92,10 +113,16 @@ def _element_constructor_(self, x):
00001
000001
0000001
sage: idx = CliffordAlgebraIndices(0)
sage: idx([])
0
"""
if isinstance(x, (list, tuple, set, frozenset)):
if len(x) > self._nbits:
raise ValueError(f"{x=} is too long")
if not x:
return FrozenBitset()
return FrozenBitset(x)

if isinstance(x, int):
Expand Down Expand Up @@ -129,6 +156,12 @@ def cardinality(self):
True
sage: len(idx) == 2^7
True
sage: idx = CliffordAlgebraIndices(7, 3)
sage: idx.cardinality() == binomial(7, 3)
True
sage: len(idx) == binomial(7, 3)
True
"""
return self._cardinality

Expand All @@ -149,14 +182,20 @@ def _repr_(self):
Subsets of {0}
sage: CliffordAlgebraIndices(2)
Subsets of {0,1}
sage: CliffordAlgebraIndices(5, 3)
Subsets of {0,1,...,4} of size 3
"""
if self._degree is not None:
extra = f" of size {self._degree}"
else:
extra = ""
if self._nbits == 0:
return "Subsets of {}"
return "Subsets of {}" + extra
if self._nbits == 1:
return "Subsets of {0}"
return "Subsets of {0}" + extra
if self._nbits == 2:
return "Subsets of {0,1}"
return f"Subsets of {{0,1,...,{self._nbits-1}}}"
return "Subsets of {0,1}" + extra
return f"Subsets of {{0,1,...,{self._nbits-1}}}" + extra

def _latex_(self):
r"""
Expand All @@ -166,21 +205,27 @@ def _latex_(self):
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
sage: latex(CliffordAlgebraIndices(7))
\mathcal{P}({0,1,\ldots,6})
\mathcal{P}(\{0,1,\ldots,6\})
sage: latex(CliffordAlgebraIndices(0))
\mathcal{P}(\emptyset)
sage: latex(CliffordAlgebraIndices(1))
\mathcal{P}({0})
\mathcal{P}(\{0\})
sage: latex(CliffordAlgebraIndices(2))
\mathcal{P}({0,1})
\mathcal{P}(\{0,1\})
sage: latex(CliffordAlgebraIndices(2, 1))
\mathcal{P}(\{0,1\}, 1)
"""
if self._degree is not None:
extra = f", {self._degree}"
else:
extra = ""
if self._nbits == 0:
return "\\mathcal{P}(\\emptyset)"
return f"\\mathcal{{P}}(\\emptyset{extra})"
if self._nbits == 1:
return "\\mathcal{P}({0})"
return f"\\mathcal{{P}}(\\{{0\\}}{extra})"
if self._nbits == 2:
return "\\mathcal{P}({0,1})"
return f"\\mathcal{{P}}({{0,1,\\ldots,{self._nbits-1}}})"
return f"\\mathcal{{P}}(\\{{0,1\\}}{extra})"
return f"\\mathcal{{P}}(\\{{0,1,\\ldots,{self._nbits-1}\\}}{extra})"

def __iter__(self):
r"""
Expand All @@ -200,9 +245,25 @@ def __iter__(self):
101
011
111
sage: idx = CliffordAlgebraIndices(5, 3)
sage: list(idx)
[111, 1101, 11001, 1011, 10101, 10011, 0111, 01101, 01011, 00111]
sage: idx = CliffordAlgebraIndices(7, 0)
sage: list(idx)
[0]
"""
import itertools
n = self._nbits
if self._degree is not None:
if self._degree == 0: # special corner case
yield FrozenBitset()
return
for C in itertools.combinations(range(n), self._degree):
yield FrozenBitset(C)
return

yield FrozenBitset()
k = 1
while k <= n:
Expand All @@ -226,11 +287,35 @@ def __contains__(self, elt):
True
sage: FrozenBitset('000001') in idx
False
sage: idx = CliffordAlgebraIndices(6, 3)
sage: FrozenBitset('01011') in idx
True
sage: FrozenBitset('00011') in idx
False
sage: int(7) in idx
True
sage: int(8) in idx
False
sage: idx = CliffordAlgebraIndices(7, 0)
sage: FrozenBitset() in idx
True
sage: FrozenBitset('01') in idx
False
sage: int(0) in idx
True
sage: int(5) in idx
False
"""
if isinstance(elt, int):
if self._degree is not None and sum(ZZ(elt).bits()) != self._degree:
return False
return elt < self._cardinality and elt >= 0
if not isinstance(elt, FrozenBitset):
return False
if self._degree is not None and len(elt) != self._degree:
return False
return elt.capacity() <= self._nbits

def _an_element_(self):
Expand All @@ -252,14 +337,26 @@ def _an_element_(self):
sage: idx = CliffordAlgebraIndices(3)
sage: idx._an_element_()
11
sage: idx = CliffordAlgebraIndices(5, 3)
sage: idx._an_element_()
111
sage: idx = CliffordAlgebraIndices(7, 0)
sage: idx._an_element_()
0
"""
if not self._nbits:
return FrozenBitset()

if self._degree is not None:
if self._degree == 0: # special corner case
return FrozenBitset()
return FrozenBitset(range(self._degree))

from sage.combinat.subset import SubsetsSorted
X = SubsetsSorted(range(self._nbits))
return FrozenBitset(X.an_element())


class CliffordAlgebra(CombinatorialFreeModule):
r"""
The Clifford algebra of a quadratic form.
Expand Down
45 changes: 44 additions & 1 deletion src/sage/categories/coxeter_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,14 +952,52 @@ def sign_representation(self, base_ring=None, side="twosided"):
Sign representation of
Weyl Group of type ['A', 1, 1] (as a matrix group acting on the root space)
over Integer Ring
"""
if base_ring is None:
from sage.rings.integer_ring import ZZ
base_ring = ZZ
from sage.modules.with_basis.representation import SignRepresentationCoxeterGroup
return SignRepresentationCoxeterGroup(self, base_ring)

def reflection_representation(self, base_ring=None, side="left"):
r"""
Return the reflection representation of ``self``.
This is also the canonical faithful representation of a
Coxeter group.
INPUT:
- ``base_ring`` -- (optional) the base ring; the default is
the base ring of :meth:`canonical_representation`
- ``side`` -- ignored
EXAMPLES::
sage: W = CoxeterGroup(['D', 4])
sage: W.reflection_representation()
Reflection representation of Finite Coxeter group over
Integer Ring with Coxeter matrix:
[1 3 2 2]
[3 1 3 3]
[2 3 1 2]
[2 3 2 1]
sage: W = CoxeterGroup(['I', 13])
sage: W.reflection_representation()
Reflection representation of Finite Coxeter group over
Universal Cyclotomic Field with Coxeter matrix:
[ 1 13]
[13 1]
sage: W = WeylGroup(["B", 3, 1])
sage: W.reflection_representation(QQ)
Reflection representation of Weyl Group of type ['B', 3, 1]
(as a matrix group acting on the root space)
"""
from sage.modules.with_basis.representation import ReflectionRepresentation
return ReflectionRepresentation(self, base_ring)

def demazure_product(self, Q):
r"""
Return the Demazure product of the list ``Q`` in ``self``.
Expand Down Expand Up @@ -1169,6 +1207,11 @@ def canonical_representation(self):
r"""
Return the canonical faithful representation of ``self``.
.. SEEALSO::
To obtain the underlying module with the action, use
:meth:`reflection_representation`.
EXAMPLES::
sage: W = WeylGroup("A3") # needs sage.combinat sage.groups
Expand Down
9 changes: 7 additions & 2 deletions src/sage/groups/artin.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _latex_(self):
TESTS::
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
sage: A = ArtinGroup(['B', 3]) # needs sage.rings.number_field
sage: b = A([1, 2, 3, -1, 2, -3]) # needs sage.rings.number_field
sage: b._latex_() # needs sage.rings.number_field
'\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}'
Expand All @@ -66,9 +66,14 @@ def _latex_(self):
sage: b = B([1, 2, 3, -1, 2, -3])
sage: b._latex_()
'\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}'
sage: B.one()._latex_()
'1'
"""
word = self.Tietze()
if not word:
return '1'
return ''.join(r"\sigma_{%s}^{-1}" % (-i) if i < 0 else r"\sigma_{%s}" % i
for i in self.Tietze())
for i in word)

def exponent_sum(self):
"""
Expand Down
7 changes: 6 additions & 1 deletion src/sage/groups/perm_gps/permgroup_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -948,10 +948,15 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement):
sage: S = SymmetricGroup(['a', 'b'])
sage: latex(S.gens())
\left((\text{\texttt{a}},\text{\texttt{b}})\right)
sage: latex(S.one())
1
"""
cycle_tuples = self.cycle_tuples()
if not cycle_tuples:
return '1'
from sage.misc.latex import latex
return "".join(("(" + ",".join(latex(x) for x in cycle) + ")")
for cycle in self.cycle_tuples())
for cycle in cycle_tuples)

def __getitem__(self, i):
r"""
Expand Down
Loading

0 comments on commit 3ad892a

Please sign in to comment.