Skip to content

Commit 87955da

Browse files
author
Release Manager
committed
gh-37015: Implement the Aomoto complex of the Orlik-Solomon algebra and Hilbert series for filtered modules <!-- ^^^^^ 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 --> We implement the Aomoto complex of the Orlik-Solomon algebra $A$, which is defined as the chain complex on $A$ with the differential defined by $\omega \wedge$ for any $\omega \in A_1$. We also provide an implemented of Hilbert series for any filtered module, where those for finite rank modules return honest polynomials. (This was originally going to be just for the Orlik-Solomon algebra, but the implementation trivially generalizes.) <!-- 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: #37015 Reported by: Travis Scrimshaw Reviewer(s): Frédéric Chapoton, Travis Scrimshaw
2 parents 00b9047 + 438803d commit 87955da

File tree

5 files changed

+173
-8
lines changed

5 files changed

+173
-8
lines changed

src/doc/en/reference/references/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,10 @@ REFERENCES:
13621362
complexes and posets. I*. Trans. of
13631363
Amer. Math. Soc. **348** No. 4. (1996)
13641364
1365+
.. [BY2016] Pauline Bailet and Masahiko Yoshinaga. *Vanishing results for the
1366+
Aomoto complex of real hyperplane arrangements via minimality*.
1367+
J. Singularities. **14** (2016), 74-90.
1368+
13651369
.. [BZ01] \A. Berenstein, A. Zelevinsky
13661370
*Tensor product multiplicities, canonical bases
13671371
and totally positive varieties*

src/sage/algebras/orlik_solomon.py

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,6 @@ def as_gca(self):
492492
20*x^3 + 29*x^2 + 10*x + 1
493493
sage: [len(A.basis(i)) for i in range(5)]
494494
[1, 10, 29, 20, 0]
495-
496495
"""
497496
from sage.algebras.commutative_dga import GradedCommutativeAlgebra
498497
gens = self.algebra_generators()
@@ -519,8 +518,8 @@ def as_gca(self):
519518

520519
def as_cdga(self):
521520
r"""
522-
Return the commutative differential graded algebra corresponding to ``self``
523-
with the trivial differential.
521+
Return the commutative differential graded algebra corresponding
522+
to ``self`` with the trivial differential.
524523
525524
EXAMPLES::
526525
@@ -537,6 +536,76 @@ def as_cdga(self):
537536
"""
538537
return self.as_gca().cdg_algebra({})
539538

539+
def aomoto_complex(self, omega):
540+
r"""
541+
Return the Aomoto complex of ``self`` defined by ``omega``.
542+
543+
Let `A(M)` be an Orlik-Solomon algebra of a matroid `M`. Let
544+
`\omega \in A(M)_1` be an element of (homogeneous) degree 1.
545+
The Aomoto complete is the chain complex defined on `A(M)`
546+
with the differential defined by `\omega \wedge`.
547+
548+
EXAMPLES::
549+
550+
sage: OS = hyperplane_arrangements.braid(3).orlik_solomon_algebra(QQ)
551+
sage: gens = OS.algebra_generators()
552+
sage: AC = OS.aomoto_complex(gens[0])
553+
sage: ascii_art(AC)
554+
[0]
555+
[1 0 0] [0]
556+
[0 1 0] [1]
557+
0 <-- C_2 <-------- C_1 <---- C_0 <-- 0
558+
sage: AC.homology()
559+
{0: Vector space of dimension 0 over Rational Field,
560+
1: Vector space of dimension 0 over Rational Field,
561+
2: Vector space of dimension 0 over Rational Field}
562+
563+
sage: AC = OS.aomoto_complex(-2*gens[0] + gens[1] + gens[2]); ascii_art(AC)
564+
[ 1]
565+
[-1 -1 -1] [ 1]
566+
[-1 -1 -1] [-2]
567+
0 <-- C_2 <----------- C_1 <----- C_0 <-- 0
568+
sage: AC.homology()
569+
{0: Vector space of dimension 0 over Rational Field,
570+
1: Vector space of dimension 1 over Rational Field,
571+
2: Vector space of dimension 1 over Rational Field}
572+
573+
TESTS::
574+
575+
sage: OS = hyperplane_arrangements.braid(4).orlik_solomon_algebra(QQ)
576+
sage: gens = OS.algebra_generators()
577+
sage: OS.aomoto_complex(gens[0] * gens[1] * gens[3])
578+
Traceback (most recent call last):
579+
...
580+
ValueError: omega must be a homogeneous element of degree 1
581+
582+
REFERENCES:
583+
584+
- [BY2016]_
585+
"""
586+
if not omega.is_homogeneous() or omega.degree() != 1:
587+
raise ValueError("omega must be a homogeneous element of degree 1")
588+
from sage.homology.chain_complex import ChainComplex
589+
R = self.base_ring()
590+
from collections import defaultdict
591+
from sage.matrix.constructor import matrix
592+
graded_basis = defaultdict(list)
593+
B = self.basis()
594+
for k in B.keys():
595+
graded_basis[len(k)].append(k)
596+
degrees = list(graded_basis)
597+
data = {i: matrix.zero(R, len(graded_basis[i+1]), len(graded_basis[i]))
598+
for i in degrees}
599+
for i in degrees:
600+
mat = data[i]
601+
for j, key in enumerate(graded_basis[i]):
602+
ret = (omega * B[key]).monomial_coefficients(copy=False)
603+
for k, imkey in enumerate(graded_basis[i+1]):
604+
if imkey in ret:
605+
mat[k,j] = ret[imkey]
606+
mat.set_immutable()
607+
return ChainComplex(data, R)
608+
540609

541610
class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule):
542611
r"""

src/sage/categories/filtered_modules_with_basis.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from sage.misc.abstract_method import abstract_method
3333
from sage.misc.cachefunc import cached_method
3434
from sage.categories.subobjects import SubobjectsCategory
35+
from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring
3536

3637
class FilteredModulesWithBasis(FilteredModulesCategory):
3738
r"""
@@ -246,6 +247,52 @@ def homogeneous_component(self, d):
246247
M.rename("Degree {} homogeneous component of {}".format(d, self))
247248
return M
248249

250+
def hilbert_series(self, prec=None):
251+
r"""
252+
Return the Hilbert series of ``self``.
253+
254+
Let `R` be a commutative ring (with unit). Let
255+
`M = \bigcup_{n=0}^{\infty} M_n` be a filtered `R`-module.
256+
The *Hilbert series* of `M` is the formal power series
257+
258+
.. MATH::
259+
260+
H(t) = \sum_{n=0}^{\infty} \ell(M_n / M_{n-1}) t^n,
261+
262+
where `\ell(N)` is the *length* of `N`, which is the
263+
longest chain of submodules (over `R`), and by convention
264+
`M_{-1} = \{0\}`. By the assumptions of the category,
265+
`M_n / M_{n-1}` is a free `R`-module, and so `\ell(M_n / M_{n-1})`
266+
is equal to the rank of `M_n / M_{n-1}`.
267+
268+
INPUT:
269+
270+
- ``prec`` -- (default: `\infty`) the precision
271+
272+
OUTPUT:
273+
274+
If the precision is finite, then this returns an element in the
275+
:class:`PowerSeriesRing` over ``ZZ``. Otherwise it returns an
276+
element in the :class:`LazyPowerSeriesRing` over ``ZZ``.
277+
278+
EXAMPLES::
279+
280+
sage: A = GradedModulesWithBasis(ZZ).example()
281+
sage: A.hilbert_series()
282+
1 + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 11*t^6 + O(t^7)
283+
sage: A.hilbert_series(10)
284+
1 + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 11*t^6 + 15*t^7 + 22*t^8 + 30*t^9 + O(t^10)
285+
"""
286+
from sage.rings.integer_ring import ZZ
287+
if prec is None:
288+
from sage.rings.lazy_series_ring import LazyPowerSeriesRing
289+
R = LazyPowerSeriesRing(ZZ, 't')
290+
return R(lambda n: self.homogeneous_component_basis(n).cardinality())
291+
from sage.rings.power_series_ring import PowerSeriesRing
292+
R = PowerSeriesRing(ZZ, 't')
293+
elt = R([self.homogeneous_component_basis(n).cardinality() for n in range(prec)])
294+
return elt.O(prec)
295+
249296
def graded_algebra(self):
250297
r"""
251298
Return the associated graded module to ``self``.
@@ -1112,3 +1159,47 @@ def maximal_degree(self):
11121159
2
11131160
"""
11141161
return self.lift().maximal_degree()
1162+
1163+
class FiniteDimensional(CategoryWithAxiom_over_base_ring):
1164+
class ParentMethods:
1165+
def hilbert_series(self, prec=None):
1166+
r"""
1167+
Return the Hilbert series of ``self`` as a polynomial.
1168+
1169+
Let `R` be a commutative ring (with unit). Let
1170+
`M = \bigcup_{n=0}^{\infty} M_n` be a filtered `R`-module.
1171+
The *Hilbert series* of `M` is the formal power series
1172+
1173+
.. MATH::
1174+
1175+
H(t) = \sum_{n=0}^{\infty} \ell(M_n / M_{n-1}) t^n,
1176+
1177+
where `\ell(N)` is the *length* of `N`, which is the
1178+
longest chain of submodules (over `R`), and by convention
1179+
`M_{-1} = \{0\}`. By the assumptions of the category,
1180+
`M_n / M_{n-1}` is a free `R`-module, and so
1181+
`\ell(M_n / M_{n-1})` is equal to the rank of `M_n / M_{n-1}`.
1182+
1183+
EXAMPLES::
1184+
1185+
sage: OS = hyperplane_arrangements.braid(3).orlik_solomon_algebra(QQ)
1186+
sage: OS.hilbert_series()
1187+
2*t^2 + 3*t + 1
1188+
1189+
sage: OS = matroids.Uniform(5, 3).orlik_solomon_algebra(ZZ)
1190+
sage: OS.hilbert_series()
1191+
t^3 + 3*t^2 + 3*t + 1
1192+
1193+
sage: OS = matroids.PG(2, 3).orlik_solomon_algebra(ZZ['x','y'])
1194+
sage: OS.hilbert_series()
1195+
27*t^3 + 39*t^2 + 13*t + 1
1196+
"""
1197+
from collections import defaultdict
1198+
from sage.rings.integer_ring import ZZ
1199+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
1200+
R = self.base_ring()
1201+
PR = PolynomialRing(ZZ, 't')
1202+
dims = defaultdict(ZZ)
1203+
for b in self.basis():
1204+
dims[b.homogeneous_degree()] += 1
1205+
return PR(dims)

src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class FiniteDimensionalGradedLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ri
3232
Category of finite dimensional graded Lie algebras with basis over Integer Ring
3333
sage: C.super_categories()
3434
[Category of graded Lie algebras with basis over Integer Ring,
35+
Category of finite dimensional filtered modules with basis over Integer Ring,
3536
Category of finite dimensional Lie algebras with basis over Integer Ring]
3637
3738
sage: C is LieAlgebras(ZZ).WithBasis().FiniteDimensional().Graded()

src/sage/categories/graded_modules_with_basis.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def submodule(self, gens, check=True, already_echelonized=False,
122122
Join of
123123
Category of graded vector spaces with basis over Rational Field and
124124
Category of subobjects of filtered modules with basis over Rational Field and
125-
Category of finite dimensional vector spaces with basis over Rational Field
125+
Category of finite dimensional filtered modules with basis over Rational Field
126126
sage: S.basis()[0].degree()
127127
1
128128
sage: S.basis()[1].degree()
@@ -135,7 +135,7 @@ def submodule(self, gens, check=True, already_echelonized=False,
135135
Join of
136136
Category of graded vector spaces with basis over Rational Field and
137137
Category of subobjects of filtered modules with basis over Rational Field and
138-
Category of finite dimensional vector spaces with basis over Rational Field
138+
Category of finite dimensional filtered modules with basis over Rational Field
139139
140140
If it is generated by inhomogeneous elements, then it is
141141
filtered by default::
@@ -144,8 +144,8 @@ def submodule(self, gens, check=True, already_echelonized=False,
144144
sage: F.category() # needs sage.combinat sage.modules
145145
Join of
146146
Category of subobjects of filtered modules with basis over Rational Field and
147-
Category of filtered vector spaces with basis over Rational Field and
148-
Category of finite dimensional vector spaces with basis over Rational Field
147+
Category of finite dimensional filtered modules with basis over Rational Field and
148+
Category of filtered vector spaces with basis over Rational Field
149149
150150
If ``category`` is specified, then it does not give any extra
151151
structure to the submodule (we can think of this as applying
@@ -233,7 +233,7 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate
233233
Join of
234234
Category of quotients of graded modules with basis over Rational Field and
235235
Category of graded vector spaces with basis over Rational Field and
236-
Category of finite dimensional vector spaces with basis over Rational Field
236+
Category of finite dimensional filtered modules with basis over Rational Field
237237
238238
.. SEEALSO::
239239

0 commit comments

Comments
 (0)