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

Commit 49129ea

Browse files
committed
Allowing an arbitrary skew-symmetric matrix as input to determine the multiplication.
1 parent d7f05ce commit 49129ea

File tree

1 file changed

+93
-18
lines changed

1 file changed

+93
-18
lines changed

src/sage/algebras/q_commuting_polynomials.py

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,31 @@
1919
from sage.misc.cachefunc import cached_method
2020
from sage.sets.family import Family
2121
from sage.rings.infinity import infinity
22+
from sage.rings.integer_ring import ZZ
2223
from sage.categories.algebras import Algebras
2324
from sage.combinat.free_module import CombinatorialFreeModule
24-
from sage.monoids.free_abelian_monoid import FreeAbelianMonoid, FreeAbelianMonoid_class
25+
from sage.monoids.free_abelian_monoid import FreeAbelianMonoid
26+
from sage.matrix.constructor import matrix
27+
from sage.structure.element import Matrix
2528

2629
class qCommutingPolynomials(CombinatorialFreeModule):
2730
r"""
2831
The algebra of `q`-commuting polynomials.
2932
30-
Let `R` be a commutative ring, and fix an element `q \in R`. We say two
31-
distinct variables `x` and `y` `q`-*commute* if they satisfy the relation
33+
Let `R` be a commutative ring, and fix an element `q \in R`. Let
34+
B = (B_{xy})_{x,y \in I}` be a skew-symmetric bilinear form with
35+
index set `I`. Let `R[I]_{q,B}` denote the polynomial ring in the variables
36+
`I` such that we have the `q`-*commuting* relation for `x, y \in I`:
3237
3338
.. MATH::
3439
35-
x y = q \cdot y x.
40+
y x = q^{B_{xy}} \cdot x y.
3641
37-
These form a graded `R`-algebra with a natural basis given by monomials
38-
written in increasing order. These then satisfy a `q`-analog of the
39-
classical binomial coefficient theorem:
42+
This is a graded `R`-algebra with a natural basis given by monomials
43+
written in increasing order with respect to some total order on `I`.
44+
45+
When `B_{xy} = 1` and `B_{yx} = -1` for all `x < y`, then we have
46+
a `q`-analog of the classical binomial coefficient theorem:
4047
4148
.. MATH::
4249
@@ -47,14 +54,38 @@ class qCommutingPolynomials(CombinatorialFreeModule):
4754
sage: q = ZZ['q'].fraction_field().gen()
4855
sage: R.<x,y> = algebras.qCommutingPolynomials(q)
4956
50-
We verify the `q`-binomial theorem::
57+
We verify a case of the `q`-binomial theorem::
5158
5259
sage: f = (x + y)^10
5360
sage: all(f[b] == q_binomial(10, b.list()[0]) for b in f.support())
5461
True
62+
63+
We now do a computation with a non-standard `B` matrix::
64+
65+
sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]])
66+
sage: B
67+
[ 0 1 2]
68+
[-1 0 3]
69+
[-2 -3 0]
70+
sage: q = ZZ['q'].gen()
71+
sage: R.<x,y,z> = algebras.qCommutingPolynomials(q, B)
72+
sage: y * x
73+
q*x*y
74+
sage: z * x
75+
q^2*x*z
76+
sage: z * y
77+
q^3*y*z
78+
79+
sage: f = (x + z)^10
80+
sage: all(f[b] == q_binomial(10, b.list()[0], q^2) for b in f.support())
81+
True
82+
83+
sage: f = (y + z)^10
84+
sage: all(f[b] == q_binomial(10, b.list()[1], q^3) for b in f.support())
85+
True
5586
"""
5687
@staticmethod
57-
def __classcall_private__(cls, q, n=None, base_ring=None, names=None):
88+
def __classcall_private__(cls, q, n=None, B=None, base_ring=None, names=None):
5889
r"""
5990
Normalize input to ensure a unique representation.
6091
@@ -70,13 +101,34 @@ def __classcall_private__(cls, q, n=None, base_ring=None, names=None):
70101
if base_ring is not None:
71102
q = base_ring(q)
72103

73-
if isinstance(n, FreeAbelianMonoid_class):
74-
indices = n
104+
if B is None and isinstance(n, Matrix):
105+
n, B = B, n
106+
107+
if names is None:
108+
raise ValueError("the names of the variables must be given")
109+
from sage.structure.category_object import normalize_names
110+
if n is None:
111+
if isinstance(names, str):
112+
n = names.count(',') + 1
113+
else:
114+
n = len(names)
115+
names = normalize_names(n, names)
116+
n = len(names)
117+
if B is None:
118+
B = matrix.zero(ZZ, n)
119+
for i in range(n):
120+
for j in range(i+1, n):
121+
B[i,j] = 1
122+
B[j,i] = -1
123+
B.set_immutable()
75124
else:
76-
indices = FreeAbelianMonoid(n, names)
77-
return super().__classcall__(cls, q, indices)
125+
if not B.is_skew_symmetric():
126+
raise ValueError("the matrix must be skew symmetric")
127+
B = B.change_ring(ZZ)
128+
B.set_immutable()
129+
return super().__classcall__(cls, q=q, B=B, names=names)
78130

79-
def __init__(self, q, indices):
131+
def __init__(self, q, B, names):
80132
r"""
81133
Initialize ``self``.
82134
@@ -87,7 +139,9 @@ def __init__(self, q, indices):
87139
sage: TestSuite(R).run()
88140
"""
89141
self._q = q
142+
self._B = B
90143
base_ring = q.parent()
144+
indices = FreeAbelianMonoid(len(names), names)
91145
category = Algebras(base_ring).WithBasis().Graded()
92146
CombinatorialFreeModule.__init__(self, base_ring, indices,
93147
bracket=False, prefix='',
@@ -104,10 +158,13 @@ def _repr_(self):
104158
sage: R.<x,y,z> = algebras.qCommutingPolynomials(q)
105159
sage: R
106160
q-commuting polynomial ring in x, y, z over Fraction Field of
107-
Univariate Polynomial Ring in q over Integer Ring
161+
Univariate Polynomial Ring in q over Integer Ring with matrix:
162+
[ 0 1 1]
163+
[-1 0 1]
164+
[-1 -1 0]
108165
"""
109166
names = ", ".join(self.variable_names())
110-
return "{}-commuting polynomial ring in {} over {}".format(self._q, names, self.base_ring())
167+
return "{}-commuting polynomial ring in {} over {} with matrix:\n{}".format(self._q, names, self.base_ring(), self._B)
111168

112169
def _latex_(self):
113170
r"""
@@ -142,7 +199,7 @@ def _term_key(x):
142199
return (sum(L), L)
143200

144201
def gen(self, i):
145-
"""
202+
r"""
146203
Return the ``i``-generator of ``self``.
147204
148205
EXAMPLES::
@@ -260,6 +317,24 @@ def product_on_basis(self, x, y):
260317
x^3 + (q^2+q+1)*x^2*y + (q^2+q+1)*x*y^2 + y^3
261318
sage: (x + y)^4
262319
x^4 + (q^3+q^2+q+1)*x^3*y + (q^4+q^3+2*q^2+q+1)*x^2*y^2 + (q^3+q^2+q+1)*x*y^3 + y^4
320+
321+
With a non-standard `B` matrix::
322+
323+
sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]])
324+
sage: q = ZZ['q'].fraction_field().gen()
325+
sage: R.<x,y,z> = algebras.qCommutingPolynomials(q, B=B)
326+
sage: x * y
327+
x*y
328+
sage: y * x^2
329+
q^2*x^2*y
330+
sage: z^2 * x
331+
q^4*x*z^2
332+
sage: z^2 * x^3
333+
q^12*x^3*z^2
334+
sage: z^2 * y
335+
q^6*y*z^2
336+
sage: z^2 * y^3
337+
q^18*y^3*z^2
263338
"""
264339
# Special case for multiplying by 1
265340
if x == self.one_basis():
@@ -271,6 +346,6 @@ def product_on_basis(self, x, y):
271346
Ly = y.list()
272347

273348
# This could be made more efficient
274-
qpow = sum(exp * sum(Ly[:i]) for i,exp in enumerate(Lx))
349+
qpow = sum(exp * sum(self._B[j,i] * val for j, val in enumerate(Ly[:i])) for i,exp in enumerate(Lx))
275350
return self.term(x * y, self._q ** qpow)
276351

0 commit comments

Comments
 (0)