passagemath-groups 10.6.30__cp313-cp313-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_groups-10.6.30.dist-info/METADATA +112 -0
- passagemath_groups-10.6.30.dist-info/RECORD +39 -0
- passagemath_groups-10.6.30.dist-info/WHEEL +6 -0
- passagemath_groups-10.6.30.dist-info/top_level.txt +2 -0
- passagemath_groups.dylibs/libgap.10.dylib +0 -0
- passagemath_groups.dylibs/libgmp.10.dylib +0 -0
- passagemath_groups.dylibs/libreadline.8.2.dylib +0 -0
- passagemath_groups.dylibs/libz.1.3.1.dylib +0 -0
- sage/all__sagemath_groups.py +21 -0
- sage/geometry/all__sagemath_groups.py +1 -0
- sage/geometry/palp_normal_form.cpython-313-darwin.so +0 -0
- sage/geometry/palp_normal_form.pyx +401 -0
- sage/groups/abelian_gps/all.py +25 -0
- sage/groups/all.py +5 -0
- sage/groups/all__sagemath_groups.py +32 -0
- sage/groups/artin.py +1074 -0
- sage/groups/braid.py +3806 -0
- sage/groups/cactus_group.py +1001 -0
- sage/groups/cubic_braid.py +2052 -0
- sage/groups/finitely_presented.py +1896 -0
- sage/groups/finitely_presented_catalog.py +27 -0
- sage/groups/finitely_presented_named.py +592 -0
- sage/groups/fqf_orthogonal.py +579 -0
- sage/groups/free_group.py +944 -0
- sage/groups/group_exp.py +360 -0
- sage/groups/group_semidirect_product.py +504 -0
- sage/groups/kernel_subgroup.py +231 -0
- sage/groups/lie_gps/all.py +1 -0
- sage/groups/lie_gps/catalog.py +8 -0
- sage/groups/lie_gps/nilpotent_lie_group.py +945 -0
- sage/groups/misc_gps/all.py +1 -0
- sage/groups/misc_gps/misc_groups.py +11 -0
- sage/groups/misc_gps/misc_groups_catalog.py +33 -0
- sage/groups/raag.py +866 -0
- sage/groups/semimonomial_transformations/all.py +1 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation.cpython-313-darwin.so +0 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation.pxd +9 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation.pyx +346 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +512 -0
sage/groups/raag.py
ADDED
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-groups
|
|
2
|
+
# sage.doctest: needs sage.graphs sage.rings.number_field
|
|
3
|
+
r"""
|
|
4
|
+
Right-Angled Artin Groups
|
|
5
|
+
|
|
6
|
+
A *right-angled Artin group* (often abbreviated as RAAG) is a group which
|
|
7
|
+
has a presentation whose only relations are commutators between generators.
|
|
8
|
+
These are also known as graph groups, since they are (uniquely) encoded by
|
|
9
|
+
(simple) graphs, or partially commutative groups.
|
|
10
|
+
|
|
11
|
+
AUTHORS:
|
|
12
|
+
|
|
13
|
+
- Travis Scrimshaw (2013-09-01): Initial version
|
|
14
|
+
- Travis Scrimshaw (2018-02-05): Made compatible with
|
|
15
|
+
:class:`~sage.groups.artin.ArtinGroup`
|
|
16
|
+
"""
|
|
17
|
+
# ***************************************************************************
|
|
18
|
+
# Copyright (C) 2013,2018 Travis Scrimshaw <tcscrims at gmail.com>
|
|
19
|
+
#
|
|
20
|
+
# This program is free software: you can redistribute it and/or modify
|
|
21
|
+
# it under the terms of the GNU General Public License as published by
|
|
22
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
23
|
+
# (at your option) any later version.
|
|
24
|
+
# https://www.gnu.org/licenses/
|
|
25
|
+
# ****************************************************************************
|
|
26
|
+
from sage.libs.gap.element import GapElement
|
|
27
|
+
|
|
28
|
+
from sage.misc.cachefunc import cached_method
|
|
29
|
+
from sage.structure.richcmp import richcmp
|
|
30
|
+
from sage.groups.finitely_presented import FinitelyPresentedGroup, FinitelyPresentedGroupElement
|
|
31
|
+
from sage.groups.free_group import FreeGroup
|
|
32
|
+
from sage.groups.artin import ArtinGroup, ArtinGroupElement
|
|
33
|
+
from sage.graphs.graph import Graph
|
|
34
|
+
from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix
|
|
35
|
+
from sage.combinat.root_system.coxeter_group import CoxeterGroup
|
|
36
|
+
|
|
37
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
|
38
|
+
from sage.categories.fields import Fields
|
|
39
|
+
from sage.categories.groups import Groups
|
|
40
|
+
from sage.categories.algebras_with_basis import AlgebrasWithBasis
|
|
41
|
+
from sage.algebras.clifford_algebra_element import CohomologyRAAGElement
|
|
42
|
+
from sage.typeset.ascii_art import ascii_art
|
|
43
|
+
from sage.typeset.unicode_art import unicode_art
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class RightAngledArtinGroup(ArtinGroup):
|
|
47
|
+
r"""
|
|
48
|
+
The right-angled Artin group defined by a graph `G`.
|
|
49
|
+
|
|
50
|
+
Let `\Gamma = \{V(\Gamma), E(\Gamma)\}` be a simple graph.
|
|
51
|
+
A *right-angled Artin group* (commonly abbreviated as RAAG) is the group
|
|
52
|
+
|
|
53
|
+
.. MATH::
|
|
54
|
+
|
|
55
|
+
A_{\Gamma} = \langle g_v : v \in V(\Gamma)
|
|
56
|
+
\mid [g_u, g_v] \text{ if } \{u, v\} \notin E(\Gamma) \rangle.
|
|
57
|
+
|
|
58
|
+
These are sometimes known as graph groups or partially commutative groups.
|
|
59
|
+
This RAAG's contains both free groups, given by the complete graphs,
|
|
60
|
+
and free abelian groups, given by disjoint vertices.
|
|
61
|
+
|
|
62
|
+
.. WARNING::
|
|
63
|
+
|
|
64
|
+
This is the opposite convention of some papers.
|
|
65
|
+
|
|
66
|
+
Right-angled Artin groups contain many remarkable properties and have a
|
|
67
|
+
very rich structure despite their simple presentation. Here are some
|
|
68
|
+
known facts:
|
|
69
|
+
|
|
70
|
+
- The word problem is solvable.
|
|
71
|
+
- They are known to be rigid; that is for any finite simple graphs
|
|
72
|
+
`\Delta` and `\Gamma`, we have `A_{\Delta} \cong A_{\Gamma}` if and
|
|
73
|
+
only if `\Delta \cong \Gamma` [Dro1987]_.
|
|
74
|
+
- They embed as a finite index subgroup of a right-angled Coxeter group
|
|
75
|
+
(which is the same definition as above except with the additional
|
|
76
|
+
relations `g_v^2 = 1` for all `v \in V(\Gamma)`).
|
|
77
|
+
- In [BB1997]_, it was shown they contain subgroups that satisfy the
|
|
78
|
+
property `FP_2` but are not finitely presented by considering the
|
|
79
|
+
kernel of `\phi : A_{\Gamma} \to \ZZ` by `g_v \mapsto 1` (i.e. words of
|
|
80
|
+
exponent sum 0).
|
|
81
|
+
- `A_{\Gamma}` has a finite `K(\pi, 1)` space.
|
|
82
|
+
- `A_{\Gamma}` acts freely and cocompactly on a finite dimensional
|
|
83
|
+
`CAT(0)` space, and so it is biautomatic.
|
|
84
|
+
- Given an Artin group `B` with generators `s_i`, then any subgroup
|
|
85
|
+
generated by a collection of `v_i = s_i^{k_i}` where `k_i \geq 2` is a
|
|
86
|
+
RAAG where `[v_i, v_j] = 1` if and only if `[s_i, s_j] = 1` [CP2001]_.
|
|
87
|
+
|
|
88
|
+
The normal forms for RAAG's in Sage are those described in [VW1994]_ and
|
|
89
|
+
gathers commuting groups together.
|
|
90
|
+
|
|
91
|
+
INPUT:
|
|
92
|
+
|
|
93
|
+
- ``G`` -- a graph
|
|
94
|
+
- ``names`` -- string or list of generator names
|
|
95
|
+
|
|
96
|
+
EXAMPLES::
|
|
97
|
+
|
|
98
|
+
sage: Gamma = Graph(4)
|
|
99
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
100
|
+
sage: a,b,c,d = G.gens()
|
|
101
|
+
sage: a*c*d^4*a^-3*b
|
|
102
|
+
v0^-2*v1*v2*v3^4
|
|
103
|
+
|
|
104
|
+
sage: Gamma = graphs.CompleteGraph(4)
|
|
105
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
106
|
+
sage: a,b,c,d = G.gens()
|
|
107
|
+
sage: a*c*d^4*a^-3*b
|
|
108
|
+
v0*v2*v3^4*v0^-3*v1
|
|
109
|
+
|
|
110
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
111
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
112
|
+
sage: G
|
|
113
|
+
Right-angled Artin group of Cycle graph
|
|
114
|
+
sage: a,b,c,d,e = G.gens()
|
|
115
|
+
sage: d*b*a*d
|
|
116
|
+
v1*v3^2*v0
|
|
117
|
+
sage: e^-1*c*b*e*b^-1*c^-4
|
|
118
|
+
v2^-3
|
|
119
|
+
|
|
120
|
+
We create the previous example but with different variable names::
|
|
121
|
+
|
|
122
|
+
sage: G.<a,b,c,d,e> = RightAngledArtinGroup(Gamma)
|
|
123
|
+
sage: G
|
|
124
|
+
Right-angled Artin group of Cycle graph
|
|
125
|
+
sage: d*b*a*d
|
|
126
|
+
b*d^2*a
|
|
127
|
+
sage: e^-1*c*b*e*b^-1*c^-4
|
|
128
|
+
c^-3
|
|
129
|
+
|
|
130
|
+
REFERENCES:
|
|
131
|
+
|
|
132
|
+
- [Cha2006]_
|
|
133
|
+
- [BB1997]_
|
|
134
|
+
- [Dro1987]_
|
|
135
|
+
- [CP2001]_
|
|
136
|
+
- [VW1994]_
|
|
137
|
+
|
|
138
|
+
- :wikipedia:`Artin_group#Right-angled_Artin_groups`
|
|
139
|
+
"""
|
|
140
|
+
@staticmethod
|
|
141
|
+
def __classcall_private__(cls, G, names=None):
|
|
142
|
+
"""
|
|
143
|
+
Normalize input to ensure a unique representation.
|
|
144
|
+
|
|
145
|
+
TESTS::
|
|
146
|
+
|
|
147
|
+
sage: G1 = RightAngledArtinGroup(graphs.CycleGraph(5))
|
|
148
|
+
sage: Gamma = Graph([(0,1),(1,2),(2,3),(3,4),(4,0)])
|
|
149
|
+
sage: G2 = RightAngledArtinGroup(Gamma)
|
|
150
|
+
sage: G3 = RightAngledArtinGroup([(0,1),(1,2),(2,3),(3,4),(4,0)])
|
|
151
|
+
sage: G4 = RightAngledArtinGroup(Gamma, 'v')
|
|
152
|
+
sage: G1 is G2 and G2 is G3 and G3 is G4
|
|
153
|
+
True
|
|
154
|
+
|
|
155
|
+
Handle the empty graph::
|
|
156
|
+
|
|
157
|
+
sage: RightAngledArtinGroup(Graph())
|
|
158
|
+
Traceback (most recent call last):
|
|
159
|
+
...
|
|
160
|
+
ValueError: the graph must not be empty
|
|
161
|
+
"""
|
|
162
|
+
if not isinstance(G, Graph):
|
|
163
|
+
G = Graph(G, immutable=True)
|
|
164
|
+
else:
|
|
165
|
+
G = G.copy(immutable=True)
|
|
166
|
+
if G.num_verts() == 0:
|
|
167
|
+
raise ValueError("the graph must not be empty")
|
|
168
|
+
if names is None:
|
|
169
|
+
names = 'v'
|
|
170
|
+
if isinstance(names, str):
|
|
171
|
+
if ',' in names:
|
|
172
|
+
names = [x.strip() for x in names.split(',')]
|
|
173
|
+
else:
|
|
174
|
+
names = [names + str(v) for v in G.vertices(sort=False)]
|
|
175
|
+
names = tuple(names)
|
|
176
|
+
if len(names) != G.num_verts():
|
|
177
|
+
raise ValueError("the number of generators must match the"
|
|
178
|
+
" number of vertices of the defining graph")
|
|
179
|
+
return super().__classcall__(cls, G, names)
|
|
180
|
+
|
|
181
|
+
def __init__(self, G, names):
|
|
182
|
+
"""
|
|
183
|
+
Initialize ``self``.
|
|
184
|
+
|
|
185
|
+
TESTS::
|
|
186
|
+
|
|
187
|
+
sage: G = RightAngledArtinGroup(graphs.CycleGraph(5))
|
|
188
|
+
sage: TestSuite(G).run()
|
|
189
|
+
sage: G.category()
|
|
190
|
+
Category of infinite groups
|
|
191
|
+
"""
|
|
192
|
+
self._graph = G
|
|
193
|
+
F = FreeGroup(names=names)
|
|
194
|
+
CG = Graph(G).complement() # Make sure it's mutable
|
|
195
|
+
CG.relabel() # Standardize the labels
|
|
196
|
+
cm = [[-1] * CG.num_verts() for _ in range(CG.num_verts())]
|
|
197
|
+
for i in range(CG.num_verts()):
|
|
198
|
+
cm[i][i] = 1
|
|
199
|
+
for u, v in CG.edge_iterator(labels=False):
|
|
200
|
+
cm[u][v] = 2
|
|
201
|
+
cm[v][u] = 2
|
|
202
|
+
self._coxeter_group = CoxeterGroup(CoxeterMatrix(cm, index_set=G.vertices(sort=True)))
|
|
203
|
+
rels = tuple(F([i + 1, j + 1, -i - 1, -j - 1])
|
|
204
|
+
for i, j in CG.edge_iterator(labels=False)) # +/- 1 for indexing
|
|
205
|
+
FinitelyPresentedGroup.__init__(self, F, rels,
|
|
206
|
+
category=Groups().Infinite())
|
|
207
|
+
|
|
208
|
+
def _repr_(self) -> str:
|
|
209
|
+
"""
|
|
210
|
+
Return a string representation of ``self``.
|
|
211
|
+
|
|
212
|
+
TESTS::
|
|
213
|
+
|
|
214
|
+
sage: RightAngledArtinGroup(graphs.CycleGraph(5))
|
|
215
|
+
Right-angled Artin group of Cycle graph
|
|
216
|
+
"""
|
|
217
|
+
return "Right-angled Artin group of {}".format(self._graph)
|
|
218
|
+
|
|
219
|
+
def gen(self, i):
|
|
220
|
+
"""
|
|
221
|
+
Return the ``i``-th generator of ``self``.
|
|
222
|
+
|
|
223
|
+
EXAMPLES::
|
|
224
|
+
|
|
225
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
226
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
227
|
+
sage: G.gen(2)
|
|
228
|
+
v2
|
|
229
|
+
"""
|
|
230
|
+
return self.element_class(self, ([i, 1],))
|
|
231
|
+
|
|
232
|
+
def gens(self) -> tuple:
|
|
233
|
+
"""
|
|
234
|
+
Return the generators of ``self``.
|
|
235
|
+
|
|
236
|
+
EXAMPLES::
|
|
237
|
+
|
|
238
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
239
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
240
|
+
sage: G.gens()
|
|
241
|
+
(v0, v1, v2, v3, v4)
|
|
242
|
+
sage: Gamma = Graph([('x', 'y'), ('y', 'zeta')])
|
|
243
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
244
|
+
sage: G.gens()
|
|
245
|
+
(vx, vy, vzeta)
|
|
246
|
+
"""
|
|
247
|
+
return tuple(self.gen(i) for i in range(self._graph.num_verts()))
|
|
248
|
+
|
|
249
|
+
def ngens(self):
|
|
250
|
+
"""
|
|
251
|
+
Return the number of generators of ``self``.
|
|
252
|
+
|
|
253
|
+
EXAMPLES::
|
|
254
|
+
|
|
255
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
256
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
257
|
+
sage: G.ngens()
|
|
258
|
+
5
|
|
259
|
+
"""
|
|
260
|
+
return self._graph.num_verts()
|
|
261
|
+
|
|
262
|
+
def graph(self):
|
|
263
|
+
"""
|
|
264
|
+
Return the defining graph of ``self``.
|
|
265
|
+
|
|
266
|
+
EXAMPLES::
|
|
267
|
+
|
|
268
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
269
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
270
|
+
sage: G.graph()
|
|
271
|
+
Cycle graph: Graph on 5 vertices
|
|
272
|
+
"""
|
|
273
|
+
return self._graph
|
|
274
|
+
|
|
275
|
+
@cached_method
|
|
276
|
+
def one(self):
|
|
277
|
+
"""
|
|
278
|
+
Return the identity element `1`.
|
|
279
|
+
|
|
280
|
+
EXAMPLES::
|
|
281
|
+
|
|
282
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
283
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
284
|
+
sage: G.one()
|
|
285
|
+
1
|
|
286
|
+
"""
|
|
287
|
+
return self.element_class(self, ())
|
|
288
|
+
|
|
289
|
+
one_element = one
|
|
290
|
+
|
|
291
|
+
def _element_constructor_(self, x):
|
|
292
|
+
"""
|
|
293
|
+
Construct an element of ``self`` from ``x``.
|
|
294
|
+
|
|
295
|
+
TESTS::
|
|
296
|
+
|
|
297
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
298
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
299
|
+
sage: elt = G([[0,3], [3,1], [2,1], [1,1], [3,1]]); elt
|
|
300
|
+
v0^3*v3*v2*v1*v3
|
|
301
|
+
sage: G(elt)
|
|
302
|
+
v0^3*v3*v2*v1*v3
|
|
303
|
+
sage: G(1)
|
|
304
|
+
1
|
|
305
|
+
"""
|
|
306
|
+
if isinstance(x, RightAngledArtinGroup.Element):
|
|
307
|
+
raise ValueError("there is no coercion from {} into {}".format(x.parent(), self))
|
|
308
|
+
if x == 1:
|
|
309
|
+
return self.one()
|
|
310
|
+
verts = self._graph.vertices(sort=True)
|
|
311
|
+
x = [[verts.index(s[0]), s[1]] for s in x]
|
|
312
|
+
return self.element_class(self, self._normal_form(x))
|
|
313
|
+
|
|
314
|
+
def _normal_form(self, word):
|
|
315
|
+
"""
|
|
316
|
+
Return the normal form of the word ``word``.
|
|
317
|
+
|
|
318
|
+
Helper function for creating elements.
|
|
319
|
+
|
|
320
|
+
EXAMPLES::
|
|
321
|
+
|
|
322
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
323
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
324
|
+
sage: G._normal_form([[0,2], [3,1], [2,1], [0,1], [1,1], [3,1]])
|
|
325
|
+
([0, 3], [3, 1], [2, 1], [1, 1], [3, 1])
|
|
326
|
+
sage: a,b,c,d,e = G.gens()
|
|
327
|
+
sage: a^2 * d * c * a * b * d
|
|
328
|
+
v0^3*v3*v2*v1*v3
|
|
329
|
+
sage: a*b*d == d*a*b and a*b*d == a*d*b
|
|
330
|
+
True
|
|
331
|
+
sage: a*c*a^-1*c^-1
|
|
332
|
+
1
|
|
333
|
+
sage: (a*b*c*d*e)^2 * (a*b*c*d*e)^-2
|
|
334
|
+
1
|
|
335
|
+
"""
|
|
336
|
+
pos = 0
|
|
337
|
+
G = self._graph
|
|
338
|
+
v = G.vertices(sort=True)
|
|
339
|
+
w = [list(x) for x in word] # Make a (2 level) deep copy
|
|
340
|
+
while pos < len(w):
|
|
341
|
+
comm_set = [w[pos][0]]
|
|
342
|
+
# The current set of totally commuting elements
|
|
343
|
+
i = pos + 1
|
|
344
|
+
|
|
345
|
+
while i < len(w):
|
|
346
|
+
letter = w[i][0] # The current letter
|
|
347
|
+
# Check if this could fit in the commuting set
|
|
348
|
+
if letter in comm_set:
|
|
349
|
+
# Try to move it in
|
|
350
|
+
if any(G.has_edge(v[w[j][0]], v[letter])
|
|
351
|
+
for j in range(pos + len(comm_set), i)):
|
|
352
|
+
# We can't, so go onto the next letter
|
|
353
|
+
i += 1
|
|
354
|
+
continue
|
|
355
|
+
j = comm_set.index(letter)
|
|
356
|
+
w[pos + j][1] += w[i][1]
|
|
357
|
+
w.pop(i)
|
|
358
|
+
i -= 1 # Since we removed a syllable
|
|
359
|
+
# Check cancellations
|
|
360
|
+
if w[pos + j][1] == 0:
|
|
361
|
+
w.pop(pos + j)
|
|
362
|
+
comm_set.pop(j)
|
|
363
|
+
i -= 1
|
|
364
|
+
if not comm_set:
|
|
365
|
+
pos = 0
|
|
366
|
+
# Start again since cancellation can be pronounced effects
|
|
367
|
+
break
|
|
368
|
+
elif all(not G.has_edge(v[w[j][0]], v[letter])
|
|
369
|
+
for j in range(pos, i)):
|
|
370
|
+
j = 0
|
|
371
|
+
for x in comm_set:
|
|
372
|
+
if x > letter:
|
|
373
|
+
break
|
|
374
|
+
j += 1
|
|
375
|
+
w.insert(pos + j, w.pop(i))
|
|
376
|
+
comm_set.insert(j, letter)
|
|
377
|
+
|
|
378
|
+
i += 1
|
|
379
|
+
pos += len(comm_set)
|
|
380
|
+
return tuple(w)
|
|
381
|
+
|
|
382
|
+
def cohomology(self, F=None):
|
|
383
|
+
"""
|
|
384
|
+
Return the cohomology ring of ``self`` over the field ``F``.
|
|
385
|
+
|
|
386
|
+
EXAMPLES::
|
|
387
|
+
|
|
388
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
389
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
390
|
+
sage: A.cohomology()
|
|
391
|
+
Cohomology ring of Right-angled Artin group of Cycle graph
|
|
392
|
+
with coefficients in Rational Field
|
|
393
|
+
"""
|
|
394
|
+
if F is None:
|
|
395
|
+
from sage.rings.rational_field import QQ
|
|
396
|
+
F = QQ
|
|
397
|
+
return CohomologyRAAG(F, self)
|
|
398
|
+
|
|
399
|
+
class Element(ArtinGroupElement):
|
|
400
|
+
"""
|
|
401
|
+
An element of a right-angled Artin group (RAAG).
|
|
402
|
+
|
|
403
|
+
Elements of RAAGs are modeled as lists of pairs ``[i, p]`` where
|
|
404
|
+
``i`` is the index of a vertex in the defining graph (with some
|
|
405
|
+
fixed order of the vertices) and ``p`` is the power.
|
|
406
|
+
"""
|
|
407
|
+
def __init__(self, parent, lst):
|
|
408
|
+
"""
|
|
409
|
+
Initialize ``self``.
|
|
410
|
+
|
|
411
|
+
TESTS::
|
|
412
|
+
|
|
413
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
414
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
415
|
+
sage: elt = G.prod(G.gens())
|
|
416
|
+
sage: TestSuite(elt).run()
|
|
417
|
+
|
|
418
|
+
sage: g = G([[0,-3], [2,2], [3,-1], [2,4]])
|
|
419
|
+
sage: h = G.element_class(G, g.gap())
|
|
420
|
+
sage: assert g.gap() == h.gap()
|
|
421
|
+
sage: assert g._data == h._data
|
|
422
|
+
|
|
423
|
+
sage: g = G.one()
|
|
424
|
+
sage: h = G.element_class(G, g.gap())
|
|
425
|
+
sage: assert g.gap() == h.gap()
|
|
426
|
+
sage: assert g._data == h._data
|
|
427
|
+
"""
|
|
428
|
+
if isinstance(lst, GapElement):
|
|
429
|
+
# e.g. direct call from GroupLibGAP
|
|
430
|
+
FinitelyPresentedGroupElement.__init__(self, parent, lst)
|
|
431
|
+
data = []
|
|
432
|
+
j = None
|
|
433
|
+
mult = 0
|
|
434
|
+
for i in self.Tietze():
|
|
435
|
+
if j is None:
|
|
436
|
+
j = i
|
|
437
|
+
mult = 1
|
|
438
|
+
elif j == i:
|
|
439
|
+
mult += 1
|
|
440
|
+
else:
|
|
441
|
+
if j < 0:
|
|
442
|
+
data.append([-j - 1, -mult])
|
|
443
|
+
else:
|
|
444
|
+
data.append([j - 1, mult])
|
|
445
|
+
j = i
|
|
446
|
+
mult = 1
|
|
447
|
+
if j is not None:
|
|
448
|
+
if j < 0:
|
|
449
|
+
data.append([-j - 1, -mult])
|
|
450
|
+
else:
|
|
451
|
+
data.append([j - 1, mult])
|
|
452
|
+
self._data = tuple(data)
|
|
453
|
+
else:
|
|
454
|
+
self._data = lst
|
|
455
|
+
elt = []
|
|
456
|
+
for i, p in lst:
|
|
457
|
+
if p > 0:
|
|
458
|
+
elt.extend([i + 1] * p)
|
|
459
|
+
elif p < 0:
|
|
460
|
+
elt.extend([-i - 1] * -p)
|
|
461
|
+
FinitelyPresentedGroupElement.__init__(self, parent, elt)
|
|
462
|
+
|
|
463
|
+
def __reduce__(self):
|
|
464
|
+
"""
|
|
465
|
+
Used in pickling.
|
|
466
|
+
|
|
467
|
+
TESTS::
|
|
468
|
+
|
|
469
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
470
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
471
|
+
sage: elt = G.prod(G.gens())
|
|
472
|
+
sage: loads(dumps(elt)) == elt
|
|
473
|
+
True
|
|
474
|
+
"""
|
|
475
|
+
P = self.parent()
|
|
476
|
+
V = P._graph.vertices(sort=True)
|
|
477
|
+
return (P, ([[V[i], p] for i, p in self._data],))
|
|
478
|
+
|
|
479
|
+
def _repr_(self) -> str:
|
|
480
|
+
"""
|
|
481
|
+
Return a string representation of ``self``.
|
|
482
|
+
|
|
483
|
+
TESTS::
|
|
484
|
+
|
|
485
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
486
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
487
|
+
sage: a,b,c,d,e = G.gens()
|
|
488
|
+
sage: a * b^2 * e^-3
|
|
489
|
+
v0*v1^2*v4^-3
|
|
490
|
+
sage: Gamma = Graph([('x', 'y'), ('y', 'zeta')])
|
|
491
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
492
|
+
sage: x,y,z = G.gens()
|
|
493
|
+
sage: z * y^-2 * x^3
|
|
494
|
+
vzeta*vy^-2*vx^3
|
|
495
|
+
sage: G.<a,b,c> = RightAngledArtinGroup(Gamma)
|
|
496
|
+
sage: c * b^-2 * a^3
|
|
497
|
+
c*b^-2*a^3
|
|
498
|
+
"""
|
|
499
|
+
if not self._data:
|
|
500
|
+
return '1'
|
|
501
|
+
v = self.parent().variable_names()
|
|
502
|
+
|
|
503
|
+
def to_str(name, p):
|
|
504
|
+
if p == 1:
|
|
505
|
+
return "{}".format(name)
|
|
506
|
+
return "{}^{}".format(name, p)
|
|
507
|
+
|
|
508
|
+
return '*'.join(to_str(v[i], p) for i, p in self._data)
|
|
509
|
+
|
|
510
|
+
def _latex_(self) -> str:
|
|
511
|
+
r"""
|
|
512
|
+
Return a LaTeX representation of ``self``.
|
|
513
|
+
|
|
514
|
+
TESTS::
|
|
515
|
+
|
|
516
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
517
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
518
|
+
sage: a,b,c,d,e = G.gens()
|
|
519
|
+
sage: latex(a*b*e^-4*d^3)
|
|
520
|
+
\sigma_{0}\sigma_{1}\sigma_{4}^{-4}\sigma_{3}^{3}
|
|
521
|
+
sage: latex(G.one())
|
|
522
|
+
1
|
|
523
|
+
sage: Gamma = Graph([('x', 'y'), ('y', 'zeta')])
|
|
524
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
525
|
+
sage: x,y,z = G.gens()
|
|
526
|
+
sage: latex(x^-5*y*z^3)
|
|
527
|
+
\sigma_{\text{\texttt{x}}}^{-5}\sigma_{\text{\texttt{y}}}\sigma_{\text{\texttt{zeta}}}^{3}
|
|
528
|
+
"""
|
|
529
|
+
if not self._data:
|
|
530
|
+
return '1'
|
|
531
|
+
|
|
532
|
+
from sage.misc.latex import latex
|
|
533
|
+
latexrepr = ''
|
|
534
|
+
v = self.parent()._graph.vertices(sort=True)
|
|
535
|
+
for i, p in self._data:
|
|
536
|
+
latexrepr += "\\sigma_{{{}}}".format(latex(v[i]))
|
|
537
|
+
if p != 1:
|
|
538
|
+
latexrepr += "^{{{}}}".format(p)
|
|
539
|
+
return latexrepr
|
|
540
|
+
|
|
541
|
+
def _mul_(self, y):
|
|
542
|
+
"""
|
|
543
|
+
Return ``self`` multiplied by ``y``.
|
|
544
|
+
|
|
545
|
+
TESTS::
|
|
546
|
+
|
|
547
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
548
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
549
|
+
sage: a,b,c,d,e = G.gens()
|
|
550
|
+
sage: a * b
|
|
551
|
+
v0*v1
|
|
552
|
+
sage: b * a
|
|
553
|
+
v1*v0
|
|
554
|
+
sage: a*b*c*d*e
|
|
555
|
+
v0*v1*v2*v3*v4
|
|
556
|
+
sage: a^2*d*c*a*b*d
|
|
557
|
+
v0^3*v3*v2*v1*v3
|
|
558
|
+
sage: e^-1*a*b*d*c*a^-2*e*d*b^2*e*b^-3
|
|
559
|
+
v4^-1*v0*v3*v1*v0^-2*v2*v1^-1*v4*v3*v4
|
|
560
|
+
"""
|
|
561
|
+
P = self.parent()
|
|
562
|
+
lst = self._data + y._data
|
|
563
|
+
return self.__class__(P, P._normal_form(lst))
|
|
564
|
+
|
|
565
|
+
def __pow__(self, n):
|
|
566
|
+
"""
|
|
567
|
+
Implement exponentiation.
|
|
568
|
+
|
|
569
|
+
TESTS::
|
|
570
|
+
|
|
571
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
572
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
573
|
+
sage: elt = G.prod(G.gens())
|
|
574
|
+
sage: elt**3
|
|
575
|
+
v0*v1*v2*v3*v4*v0*v1*v2*v3*v4*v0*v1*v2*v3*v4
|
|
576
|
+
sage: elt^-2
|
|
577
|
+
v4^-1*v3^-1*v2^-1*v1^-1*v0^-1*v4^-1*v3^-1*v2^-1*v1^-1*v0^-1
|
|
578
|
+
sage: elt^0
|
|
579
|
+
1
|
|
580
|
+
"""
|
|
581
|
+
P = self.parent()
|
|
582
|
+
if not n:
|
|
583
|
+
return P.one()
|
|
584
|
+
|
|
585
|
+
if n < 0:
|
|
586
|
+
lst = sum((self._data for i in range(-n)), ()) # Positive product
|
|
587
|
+
lst = [[x[0], -x[1]] for x in reversed(lst)] # Now invert
|
|
588
|
+
return self.__class__(P, P._normal_form(lst))
|
|
589
|
+
|
|
590
|
+
lst = sum((self._data for i in range(n)), ())
|
|
591
|
+
return self.__class__(self.parent(), P._normal_form(lst))
|
|
592
|
+
|
|
593
|
+
def __invert__(self):
|
|
594
|
+
"""
|
|
595
|
+
Return the inverse of ``self``.
|
|
596
|
+
|
|
597
|
+
TESTS::
|
|
598
|
+
|
|
599
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
600
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
601
|
+
sage: a,b,c,d,e = G.gens()
|
|
602
|
+
sage: (a * b)^-2
|
|
603
|
+
v1^-1*v0^-1*v1^-1*v0^-1
|
|
604
|
+
"""
|
|
605
|
+
P = self.parent()
|
|
606
|
+
lst = [[x[0], -x[1]] for x in reversed(self._data)]
|
|
607
|
+
return self.__class__(P, P._normal_form(lst))
|
|
608
|
+
|
|
609
|
+
def _richcmp_(self, other, op) -> bool:
|
|
610
|
+
"""
|
|
611
|
+
Compare ``self`` and ``other``.
|
|
612
|
+
|
|
613
|
+
TESTS::
|
|
614
|
+
|
|
615
|
+
sage: A = ArtinGroup(['B',3])
|
|
616
|
+
sage: x = A([1, 2, 1])
|
|
617
|
+
sage: y = A([2, 1, 2])
|
|
618
|
+
sage: x == y
|
|
619
|
+
True
|
|
620
|
+
sage: x < y^(-1)
|
|
621
|
+
True
|
|
622
|
+
sage: A([]) == A.one()
|
|
623
|
+
True
|
|
624
|
+
sage: x = A([2, 3, 2, 3])
|
|
625
|
+
sage: y = A([3, 2, 3, 2])
|
|
626
|
+
sage: x == y
|
|
627
|
+
True
|
|
628
|
+
sage: x < y^(-1)
|
|
629
|
+
True
|
|
630
|
+
"""
|
|
631
|
+
return richcmp(self._data, other._data, op)
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
class CohomologyRAAG(CombinatorialFreeModule):
|
|
635
|
+
r"""
|
|
636
|
+
The cohomology ring of a right-angled Artin group.
|
|
637
|
+
|
|
638
|
+
The cohomology ring of a right-angled Artin group `A`, defined by
|
|
639
|
+
the graph `G`, with coefficients in a field `F` is isomorphic to
|
|
640
|
+
the exterior algebra of `F^N`, where `N` is the number of vertices
|
|
641
|
+
in `G`, modulo the quadratic relations `e_i \wedge e_j = 0` if and
|
|
642
|
+
only if `(i, j)` is an edge in `G`. This algebra is sometimes also
|
|
643
|
+
known as the Cartier-Foata algebra.
|
|
644
|
+
|
|
645
|
+
REFERENCES:
|
|
646
|
+
|
|
647
|
+
- [CQ2019]_
|
|
648
|
+
"""
|
|
649
|
+
def __init__(self, R, A):
|
|
650
|
+
"""
|
|
651
|
+
Initialize ``self``.
|
|
652
|
+
|
|
653
|
+
TESTS::
|
|
654
|
+
|
|
655
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
656
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
657
|
+
sage: H = A.cohomology()
|
|
658
|
+
sage: TestSuite(H).run()
|
|
659
|
+
|
|
660
|
+
sage: A.cohomology(ZZ)
|
|
661
|
+
Traceback (most recent call last):
|
|
662
|
+
...
|
|
663
|
+
NotImplementedError: only implemented with coefficients in a field
|
|
664
|
+
"""
|
|
665
|
+
if R not in Fields():
|
|
666
|
+
raise NotImplementedError("only implemented with coefficients in a field")
|
|
667
|
+
self._group = A
|
|
668
|
+
|
|
669
|
+
names = tuple(['e' + name[1:] for name in A.variable_names()])
|
|
670
|
+
from sage.graphs.independent_sets import IndependentSets
|
|
671
|
+
from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
|
|
672
|
+
indices = [tuple(ind_set) for ind_set in IndependentSets(A._graph)]
|
|
673
|
+
indices = FiniteEnumeratedSet(indices)
|
|
674
|
+
cat = AlgebrasWithBasis(R.category()).Super().Graded().FiniteDimensional()
|
|
675
|
+
CombinatorialFreeModule.__init__(self, R, indices, category=cat, prefix='H')
|
|
676
|
+
self._assign_names(names)
|
|
677
|
+
|
|
678
|
+
def _repr_(self) -> str:
|
|
679
|
+
"""
|
|
680
|
+
Return a string representation of ``self``.
|
|
681
|
+
|
|
682
|
+
EXAMPLES::
|
|
683
|
+
|
|
684
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
685
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
686
|
+
sage: A.cohomology()
|
|
687
|
+
Cohomology ring of Right-angled Artin group of Cycle graph
|
|
688
|
+
with coefficients in Rational Field
|
|
689
|
+
"""
|
|
690
|
+
return "Cohomology ring of {} with coefficients in {}".format(self._group, self.base_ring())
|
|
691
|
+
|
|
692
|
+
def _repr_term(self, m) -> str:
|
|
693
|
+
"""
|
|
694
|
+
Return a string representation of the basis element indexed by ``m``.
|
|
695
|
+
|
|
696
|
+
EXAMPLES::
|
|
697
|
+
|
|
698
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
699
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
700
|
+
sage: H = A.cohomology()
|
|
701
|
+
sage: H._repr_term((0,1,3))
|
|
702
|
+
'e0*e1*e3'
|
|
703
|
+
sage: w,x,y,z = H.algebra_generators()
|
|
704
|
+
sage: y*w + x*z
|
|
705
|
+
-e0*e2 + e1*e3
|
|
706
|
+
"""
|
|
707
|
+
if not m:
|
|
708
|
+
return '1'
|
|
709
|
+
return '*'.join('e' + str(i) for i in m)
|
|
710
|
+
|
|
711
|
+
def _ascii_art_term(self, m):
|
|
712
|
+
r"""
|
|
713
|
+
Return ascii art for the basis element indexed by ``m``.
|
|
714
|
+
|
|
715
|
+
EXAMPLES::
|
|
716
|
+
|
|
717
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
718
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
719
|
+
sage: H = A.cohomology()
|
|
720
|
+
sage: H._ascii_art_term((0,1,3))
|
|
721
|
+
e0/\e1/\e3
|
|
722
|
+
sage: w,x,y,z = H.algebra_generators()
|
|
723
|
+
sage: ascii_art(y*w + 2*x*z)
|
|
724
|
+
-e0/\e2 + 2*e1/\e3
|
|
725
|
+
"""
|
|
726
|
+
if not m:
|
|
727
|
+
return ascii_art('1')
|
|
728
|
+
wedge = '/\\'
|
|
729
|
+
return ascii_art(*['e' + str(i) for i in m], sep=wedge)
|
|
730
|
+
|
|
731
|
+
def _unicode_art_term(self, m):
|
|
732
|
+
"""
|
|
733
|
+
Return unicode art for the basis element indexed by ``m``.
|
|
734
|
+
|
|
735
|
+
EXAMPLES::
|
|
736
|
+
|
|
737
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
738
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
739
|
+
sage: H = A.cohomology()
|
|
740
|
+
sage: H._unicode_art_term((0,1,3))
|
|
741
|
+
e0∧e1∧e3
|
|
742
|
+
sage: w,x,y,z = H.algebra_generators()
|
|
743
|
+
sage: unicode_art(y*w + x*z)
|
|
744
|
+
-e0∧e2 + e1∧e3
|
|
745
|
+
"""
|
|
746
|
+
if not m:
|
|
747
|
+
return unicode_art('1')
|
|
748
|
+
import unicodedata
|
|
749
|
+
wedge = unicodedata.lookup('LOGICAL AND')
|
|
750
|
+
return unicode_art(*['e' + str(i) for i in m], sep=wedge)
|
|
751
|
+
|
|
752
|
+
def _latex_term(self, m):
|
|
753
|
+
r"""
|
|
754
|
+
Return a `\LaTeX` representation of the basis element indexed by ``m``.
|
|
755
|
+
|
|
756
|
+
EXAMPLES::
|
|
757
|
+
|
|
758
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
759
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
760
|
+
sage: H = A.cohomology()
|
|
761
|
+
sage: H._latex_term((0,1,3))
|
|
762
|
+
'e_{0} \\wedge e_{1} \\wedge e_{3}'
|
|
763
|
+
"""
|
|
764
|
+
if not m:
|
|
765
|
+
return '1'
|
|
766
|
+
from sage.misc.latex import latex
|
|
767
|
+
return " \\wedge ".join('e_{{{}}}'.format(latex(i)) for i in m)
|
|
768
|
+
|
|
769
|
+
def gen(self, i):
|
|
770
|
+
"""
|
|
771
|
+
Return the ``i``-th standard generator of the algebra ``self``.
|
|
772
|
+
|
|
773
|
+
This corresponds to the ``i``-th vertex in the graph
|
|
774
|
+
(under a fixed ordering of the vertices).
|
|
775
|
+
|
|
776
|
+
EXAMPLES::
|
|
777
|
+
|
|
778
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
779
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
780
|
+
sage: H = A.cohomology()
|
|
781
|
+
sage: H.gen(0)
|
|
782
|
+
e0
|
|
783
|
+
sage: H.gen(1)
|
|
784
|
+
e1
|
|
785
|
+
"""
|
|
786
|
+
return self._from_dict({(i,): self.base_ring().one()}, remove_zeros=False)
|
|
787
|
+
|
|
788
|
+
@cached_method
|
|
789
|
+
def one_basis(self):
|
|
790
|
+
"""
|
|
791
|
+
Return the basis element indexing `1` of ``self``.
|
|
792
|
+
|
|
793
|
+
EXAMPLES::
|
|
794
|
+
|
|
795
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
796
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
797
|
+
sage: H = A.cohomology()
|
|
798
|
+
sage: H.one_basis()
|
|
799
|
+
()
|
|
800
|
+
"""
|
|
801
|
+
return ()
|
|
802
|
+
|
|
803
|
+
@cached_method
|
|
804
|
+
def algebra_generators(self):
|
|
805
|
+
"""
|
|
806
|
+
Return the algebra generators of ``self``.
|
|
807
|
+
|
|
808
|
+
EXAMPLES::
|
|
809
|
+
|
|
810
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
811
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
812
|
+
sage: H = A.cohomology()
|
|
813
|
+
sage: H.algebra_generators()
|
|
814
|
+
Finite family {0: e0, 1: e1, 2: e2, 3: e3}
|
|
815
|
+
"""
|
|
816
|
+
V = self._group._graph.vertices(True)
|
|
817
|
+
d = {x: self.gen(i) for i, x in enumerate(V)}
|
|
818
|
+
from sage.sets.family import Family
|
|
819
|
+
return Family(V, lambda x: d[x])
|
|
820
|
+
|
|
821
|
+
def gens(self) -> tuple:
|
|
822
|
+
r"""
|
|
823
|
+
Return the generators of ``self`` (as an algebra).
|
|
824
|
+
|
|
825
|
+
EXAMPLES::
|
|
826
|
+
|
|
827
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
828
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
829
|
+
sage: H = A.cohomology()
|
|
830
|
+
sage: H.gens()
|
|
831
|
+
(e0, e1, e2, e3)
|
|
832
|
+
"""
|
|
833
|
+
return tuple(self.algebra_generators())
|
|
834
|
+
|
|
835
|
+
def ngens(self):
|
|
836
|
+
"""
|
|
837
|
+
Return the number of algebra generators of ``self``.
|
|
838
|
+
|
|
839
|
+
EXAMPLES::
|
|
840
|
+
|
|
841
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
842
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
843
|
+
sage: H = A.cohomology()
|
|
844
|
+
sage: H.ngens()
|
|
845
|
+
4
|
|
846
|
+
"""
|
|
847
|
+
return self._group._graph.num_verts()
|
|
848
|
+
|
|
849
|
+
def degree_on_basis(self, I):
|
|
850
|
+
"""
|
|
851
|
+
Return the degree on the basis element ``clique``.
|
|
852
|
+
|
|
853
|
+
EXAMPLES::
|
|
854
|
+
|
|
855
|
+
sage: C4 = graphs.CycleGraph(4)
|
|
856
|
+
sage: A = groups.misc.RightAngledArtin(C4)
|
|
857
|
+
sage: H = A.cohomology()
|
|
858
|
+
sage: sorted([H.degree_on_basis(I) for I in H.basis().keys()])
|
|
859
|
+
[0, 1, 1, 1, 1, 2, 2]
|
|
860
|
+
"""
|
|
861
|
+
return len(I)
|
|
862
|
+
|
|
863
|
+
class Element(CohomologyRAAGElement):
|
|
864
|
+
"""
|
|
865
|
+
An element in the cohomology ring of a right-angled Artin group.
|
|
866
|
+
"""
|