sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
sage: UC = PBW.tensor(C)
Lazy family (Term map from Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'> to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis # The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'>}
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
Hey Vit,
Some of these issues are probably related to bad input. Let us start with *.algebras_generators(). It is useful to look at the output:
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
So it is expecting a simple root as input. Similarly, for your tensor product:
sage: UC = PBW.tensor(C)
Lazy family (Term map from Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'> to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis # The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'>}
The tensor product as QQ-modules knows that it is a QQ-algebra, but it plays it safe and uses its basis as the generating set, which in turn, is a Cartesian product of the bases of its factors. Subsequently, the keys for the basis is the Cartesian product of the keys of the factors. So in this case, the (1,1) corresponds to the keys for the Clifford algebra basis (more of a by-product of the implementation, but the subsets are natural):
alpha = PBW.algebra_generators().keys()
PBW.basis()[alpha[0]] == PBW.algebra_generators()[alpha[0]]
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
So it is expecting subsets and that the user will not input bad data. There is no reason for it to simplify and not a bug. Granted, we could put a check on the user input here, but there is a speed penalty as this can be a well-used code path internally. Moreover, ducktyping can also be useful. So we are fairly permissive here, but not without due cause IMO.
x = cb[(1,1,0,1)]
print(simplify(x))
print(type(x))
print(f*f*e*f)
print(type(f*f*e*f))
print(f*f*e*f == x)
Do not confuse a bug with a not-yet-implemented feature: (noncommutative) polynomial rings are not in AlgebrasWithBasis, so it is not expected that they work with something like tensor(). However, it would be a good feature to add. :)
if you want to access the basis, use the .basis() method.
Also, how is pbw_basis not an intuitive name for obtaining the PBW basis (there is also the fully spelled out version too)? If you want to change the ordering, RTM of "PBW?" to pass in an ordering function to L.pbw_basis().
Now the fact that you sometimes obtaining random attribute errors when running that code block is a definite bug. Please submit a trac ticket.
In general, I think it is difficult to determine the tensor product of two (non commutative, non PBW) algebras over an arbitrary subalgebra. There is some code for doing smash products somewhere on #15874, but it has bitrotted and IDK if that will give you what you want. I did write some code to compute Verma modules via the PBW basis. I had to work somewhat hard to make it work, and it wasn't apparent to me how to extend that to more general framework.
Best,
Travis
Some of these issues are probably related to bad input. Let us start with *.algebras_generators(). It is useful to look at the output:
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
So it is expecting a simple root as input. Similarly, for your tensor product:
sage: UC = PBW.tensor(C)
Lazy family (Term map from Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'> to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis # The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'>}
The tensor product as QQ-modules knows that it is a QQ-algebra, but it plays it safe and uses its basis as the generating set, which in turn, is a Cartesian product of the bases of its factors. Subsequently, the keys for the basis is the Cartesian product of the keys of the factors. So in this case, the (1,1) corresponds to the keys for the Clifford algebra basis (more of a by-product of the implementation, but the subsets are natural):
That sounds fine. But for a newcomer it's really hard to figure out what should he input. I am still not sure myself. Consider this:
alpha = PBW.algebra_generators().keys()
PBW.basis()[alpha[0]] == PBW.algebra_generators()[alpha[0]]
I think this is a bug.
sage: PBW.basis()
Lazy family (Term map from Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]} to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis(i))_{i in Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}}
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
So it is expecting subsets and that the user will not input bad data. There is no reason for it to simplify and not a bug. Granted, we could put a check on the user input here, but there is a speed penalty as this can be a well-used code path internally. Moreover, ducktyping can also be useful. So we are fairly permissive here, but not without due cause IMO.
Pardon my ignorance, but If there is no simplification then what is all this good for? It does simplify for universal enveloping algebra and so it should do it for Clifford algebras as well. Also I have a big issue with naming convention here. The method basis() does not produce a basis!
sage: Q = QuadraticForm(QQ, 2, [1,0,1])
sage: C = CliffordAlgebra(Q)
sage: g = list(C.algebra_generators()); g
[e0, e1]
sage: prod(g[i] for i in [0,0,1,0,1,1,0,0])
-e0*e1
sage: set((1,1,0,1))
{0, 1}
I understand that it might be convenient for implementation details to use tuples of numbers (not subsets!!!) to index elements, but why can I index with E, F and H in the universal enveloping algebra case and not with e and f in the Clifford algebra case?
It seems that accessing Clifford algebra elements through basis just messes up with the simplification.
x = cb[(1,1,0,1)]
print(simplify(x))
print(type(x))
print(f*f*e*f)
print(type(f*f*e*f))
print(f*f*e*f == x)Do not confuse a bug with a not-yet-implemented feature: (noncommutative) polynomial rings are not in AlgebrasWithBasis, so it is not expected that they work with something like tensor(). However, it would be a good feature to add. :)
I guess are referring to my complaints about not being able to take tensor product with noncommutative ring. I see the naming convention as a BUG. If the method has "algebra" in it's name, it should produce algebra and not a ring. If a method has "basis" in its name, it should produce basis not a generating set as C.basis() does or a basis and not an algebra as pbw_basis() does.
sage: list(C.basis())
[1, e0, e1, e0*e1]
if you want to access the basis, use the .basis() method.
Also, how is pbw_basis not an intuitive name for obtaining the PBW basis (there is also the fully spelled out version too)? If you want to change the ordering, RTM of "PBW?" to pass in an ordering function to L.pbw_basis().
For naming conventions see above. I checked out helpstring for PBW and I am still not sure how to produce e.g. E, F, H ordering. I suggest to move this helpstring to L.pbw_basis().
Now the fact that you sometimes obtaining random attribute errors when running that code block is a definite bug. Please submit a trac ticket.Submitted as https://trac.sagemath.org/ticket/24822
In general, I think it is difficult to determine the tensor product of two (non commutative, non PBW) algebras over an arbitrary subalgebra. There is some code for doing smash products somewhere on #15874, but it has bitrotted and IDK if that will give you what you want. I did write some code to compute Verma modules via the PBW basis. I had to work somewhat hard to make it work, and it wasn't apparent to me how to extend that to more general framework.
Verma modules (for finite-dimensional semisimple Lie algebras) were exactly what I had in mind. Are they already in Sage somewhere? I haven't seen them.
Hey Vit,Some of these issues are probably related to bad input. Let us start with *.algebras_generators(). It is useful to look at the output:
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
So it is expecting a simple root as input. Similarly, for your tensor product:
sage: UC = PBW.tensor(C)
Lazy family (Term map from Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'> to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis # The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Image of Cartesian product of Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}, Subsets of {0, 1} by <type 'tuple'>}
The tensor product as QQ-modules knows that it is a QQ-algebra, but it plays it safe and uses its basis as the generating set, which in turn, is a Cartesian product of the bases of its factors. Subsequently, the keys for the basis is the Cartesian product of the keys of the factors. So in this case, the (1,1) corresponds to the keys for the Clifford algebra basis (more of a by-product of the implementation, but the subsets are natural):
That sounds fine. But for a newcomer it's really hard to figure out what should he input. I am still not sure myself. Consider this:
alpha = PBW.algebra_generators().keys()
PBW.basis()[alpha[0]] == PBW.algebra_generators()[alpha[0]]
I think this is a bug.
No, it is not. The keys for the basis of the PBW are different than those for the algebra generators. See the output:
sage: PBW.basis()
Lazy family (Term map from Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]} to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis(i))_{i in Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}}
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
It clearly indicates that the basis keys should be an element of a free abelian monoid. LBYL. Now in this case, if we did try to convert the input into the keys, it should work. See https://trac.sagemath.org/ticket/18750. Actually, it is not as bad as I remembered in terms of outright timings, but there are some other technical issues.
sage: PBW.basis().keys().an_element()
PBW[alpha[1]]^2*PBW[alphacheck[1]]^2*PBW[-alpha[1]]^3
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
So it is expecting subsets and that the user will not input bad data. There is no reason for it to simplify and not a bug. Granted, we could put a check on the user input here, but there is a speed penalty as this can be a well-used code path internally. Moreover, ducktyping can also be useful. So we are fairly permissive here, but not without due cause IMO.
Pardon my ignorance, but If there is no simplification then what is all this good for? It does simplify for universal enveloping algebra and so it should do it for Clifford algebras as well. Also I have a big issue with naming convention here. The method basis() does not produce a basis!
it is bad input. It does produce a basis, one indexed by subsets, not words/multisets. In math terms, if you have a sequence (x_i)_{i \in I}, then want x_j, where j \notin I, then you have an error. With #18750, this input might instead raise an error. If you want to do that, then you can do this:
sage: Q = QuadraticForm(QQ, 2, [1,0,1])
sage: C = CliffordAlgebra(Q)
sage: g = list(C.algebra_generators()); g
[e0, e1]
sage: prod(g[i] for i in [0,0,1,0,1,1,0,0])
-e0*e1
If you took your input and wrapped it with set:
sage: set((1,1,0,1))
{0, 1}
which would be the other possible outcome with #18750.
I understand that it might be convenient for implementation details to use tuples of numbers (not subsets!!!) to index elements, but why can I index with E, F and H in the universal enveloping algebra case and not with e and f in the Clifford algebra case?
It seems that accessing Clifford algebra elements through basis just messes up with the simplification.
x = cb[(1,1,0,1)]
print(simplify(x))
print(type(x))
print(f*f*e*f)
print(type(f*f*e*f))
print(f*f*e*f == x)Do not confuse a bug with a not-yet-implemented feature: (noncommutative) polynomial rings are not in AlgebrasWithBasis, so it is not expected that they work with something like tensor(). However, it would be a good feature to add. :)
I guess are referring to my complaints about not being able to take tensor product with noncommutative ring. I see the naming convention as a BUG. If the method has "algebra" in it's name, it should produce algebra and not a ring. If a method has "basis" in its name, it should produce basis not a generating set as C.basis() does or a basis and not an algebra as pbw_basis() does.
Remember that we are bound by the facilities of computer science and programming within Sage as well, which are usually much stronger constraints than mathematics (e.g., consider the set of real numbers). For the current implementation of tensor products, we require the algebra to be in AlgebrasWithBasis. I would not say limitations of the current framework to be a bug. Also, NC poly rings are in the category of algebras, so it does produce an algebra.
C.basis() does produce a basis.
sage: list(C.basis())
[1, e0, e1, e0*e1]
Now pbw_basis() does return an algebra in a particular basis, so in some ways, it is returning a basis, just not for the Lie algebra. So now I see why you feel it is not completely natural. However, do you have a proposal for how to have convenient access to the PBW basis of U(g)? IMO, it cannot be connected with universal_enveloping_algebra() because that only has to return a class modeling the UEA, which should not be required to have a PBW basis method. Also, I feel that a PBW basis is really more closely connected to the Lie algebra and it is clear to someone working in this field what pbw_basis would return.
def universal_enveloping_algebra(self, pbw_basis_ordering=None):
"""
Examples of pbw_basis_ordering:
"""
if pbw_basis_ordering
is None:
return self._universal_enveloping_algebra() # return the noncommutative ring
else:
return self._pbw_basis(pbw_basis_ordering
) # return the UAE with PBW basis given by the ordering
if you want to access the basis, use the .basis() method.
Also, how is pbw_basis not an intuitive name for obtaining the PBW basis (there is also the fully spelled out version too)? If you want to change the ordering, RTM of "PBW?" to pass in an ordering function to L.pbw_basis().
For naming conventions see above. I checked out helpstring for PBW and I am still not sure how to produce e.g. E, F, H ordering. I suggest to move this helpstring to L.pbw_basis().
-1 It is connected with the construction of the PBW class and not handled in the pbw_basis() method. However, I do agree that it would be good to have an (different) example in the pbw_basis() and a reference to the PBW class in the docstring.
Now the fact that you sometimes obtaining random attribute errors when running that code block is a definite bug. Please submit a trac ticket.Submitted as https://trac.sagemath.org/ticket/24822
Great, thank you.
In general, I think it is difficult to determine the tensor product of two (non commutative, non PBW) algebras over an arbitrary subalgebra. There is some code for doing smash products somewhere on #15874, but it has bitrotted and IDK if that will give you what you want. I did write some code to compute Verma modules via the PBW basis. I had to work somewhat hard to make it work, and it wasn't apparent to me how to extend that to more general framework.
Verma modules (for finite-dimensional semisimple Lie algebras) were exactly what I had in mind. Are they already in Sage somewhere? I haven't seen them.
See https://trac.sagemath.org/ticket/23517. I try to track the overall progress of Lie algebras in Sage in essentially metaticket https://trac.sagemath.org/ticket/14901.
Best,
Travis
--
You received this message because you are subscribed to a topic in the Google Groups "sage-devel" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sage-devel/XK-RxN3_qvY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to sage-devel+unsubscribe@googlegroups.com.
To post to this group, send email to sage-...@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.
No, it is not. The keys for the basis of the PBW are different than those for the algebra generators. See the output:
sage: PBW.basis()
Lazy family (Term map from Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]} to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis(i))_{i in Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}}
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
It clearly indicates that the basis keys should be an element of a free abelian monoid. LBYL. Now in this case, if we did try to convert the input into the keys, it should work. See https://trac.sagemath.org/ticket/18750. Actually, it is not as bad as I remembered in terms of outright timings, but there are some other technical issues.
Oh. Sorry. I admit that I have trouble parsing the Lazy family description.
Free abelian monoid... Hmmm... What free abelian monoid?
sage: PBW.basis().keys().an_element()PBW[alpha[1]]^2*PBW[alphacheck[1]]^2*PBW[-alpha[1]]^3
So PBW.basis() is _indexed_ by elements of the basis of PBW? I am sorry for all these stupid questions but (as you can clearly see) I am confused as hell.
I looked at the ticket and I have no idea what it is about.
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
So it is expecting subsets and that the user will not input bad data. There is no reason for it to simplify and not a bug. Granted, we could put a check on the user input here, but there is a speed penalty as this can be a well-used code path internally. Moreover, ducktyping can also be useful. So we are fairly permissive here, but not without due cause IMO.
Pardon my ignorance, but If there is no simplification then what is all this good for? It does simplify for universal enveloping algebra and so it should do it for Clifford algebras as well. Also I have a big issue with naming convention here. The method basis() does not produce a basis!
it is bad input. It does produce a basis, one indexed by subsets, not words/multisets. In math terms, if you have a sequence (x_i)_{i \in I}, then want x_j, where j \notin I, then you have an error. With #18750, this input might instead raise an error. If you want to do that, then you can do this:
sage: Q = QuadraticForm(QQ, 2, [1,0,1])
sage: C = CliffordAlgebra(Q)
sage: g = list(C.algebra_generators()); g
[e0, e1]
sage: prod(g[i] for i in [0,0,1,0,1,1,0,0])
-e0*e1
If you took your input and wrapped it with set:
sage: set((1,1,0,1))
{0, 1}
which would be the other possible outcome with #18750.
But sets are unhashable so how do I actually input the correct keys to cb = C.basis()?
sage: C.basis().keys()
Subsets of {0, 1}
sage: list(_)
[(), (0,), (1,), (0, 1)]
Another way to solve my original problem (which is to construct certain element of U \otimes C) would be to take tensor product of elements of U and C. Something like UC.tensor_elements(E*F+F*E, e*f - f*e).
Remember that we are bound by the facilities of computer science and programming within Sage as well, which are usually much stronger constraints than mathematics (e.g., consider the set of real numbers). For the current implementation of tensor products, we require the algebra to be in AlgebrasWithBasis. I would not say limitations of the current framework to be a bug. Also, NC poly rings are in the category of algebras, so it does produce an algebra.
I understand. I just object to naming conventions. I mean the object that results from calling universal_algebra() presents itself as a ring. How can I know that it is actually also in category of algebras without digging through the code?
foo.category()
C.basis() does produce a basis.
sage: list(C.basis())
[1, e0, e1, e0*e1]
Now pbw_basis() does return an algebra in a particular basis, so in some ways, it is returning a basis, just not for the Lie algebra. So now I see why you feel it is not completely natural. However, do you have a proposal for how to have convenient access to the PBW basis of U(g)? IMO, it cannot be connected with universal_enveloping_algebra() because that only has to return a class modeling the UEA, which should not be required to have a PBW basis method. Also, I feel that a PBW basis is really more closely connected to the Lie algebra and it is clear to someone working in this field what pbw_basis would return.
But that nonocmmutative ring that one gets from universal_enveloping_algebra() also has some implicit basis. What is this ring actually good for? I would think that most people would want to work with some PBW basis anyway.
My objection is not only that pbw_basis() doesn't return a basis of L, but also that it returns algebra (with a preffered chosen basis).
I propose to get rid of pbw_basis method and introduce optional argument pbw_basis_ordering to universal_enveloping_algebra method.
sage: L.pbw_basis()
Universal enveloping algebra of Lie algebra of ['A', 2] in the Chevalley basis in the Poincare-Birkhoff-Witt basis
sage: L.universal_enveloping_algebra()
Noncommutative
Multivariate Polynomial Ring in b0, b1, b2, b3, b4, b5, b6, b7 over
Rational Field, nc-relations: {b5*b0: b0*b5 - b4, b6*b3: b3*b6 + 2*b6, .................
I had that confusion about the pbw_basis method, as well. From my (non expert) point of view I would have expected the following:
What is now your L.pbw_basis() I expected to be L.universal_enveloping_algebra(). This would match what the representation string is telling you:
sage: L.pbw_basis()
Universal enveloping algebra of Lie algebra of ['A', 2] in the Chevalley basis in the Poincare-Birkhoff-Witt basis
What is now your L.universal_enveloping_algebra() is just another (isomorphic) realization. Therefore it could be accessed in this way:
L.universal_enveloping_algebra().as_nc_polynomial_ring()
matching what the representation string is telling you:
sage: L.universal_enveloping_algebra()
Noncommutative
Multivariate Polynomial Ring in b0, b1, b2, b3, b4, b5, b6, b7 over
Rational Field, nc-relations: {b5*b0: b0*b5 - b4, b6*b3: b3*b6 + 2*b6, .................
Furthermore, conversion maps between these two realization (in both directions) are desirable. The access to the PBW-basis would be
L.universal_enveloping_algebra().basis()
for which a shorthand L.pbw_basis() maybe be implemented (or not).
please don't take my poste as a suggestion. I'm not close enough to the subject that I really could do that.
I just wanted to point out where the confusion comes from (hoping you have I good Idea what we can do against it).
No, it is not. The keys for the basis of the PBW are different than those for the algebra generators. See the output:
sage: PBW.basis()
Lazy family (Term map from Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]} to Universal enveloping algebra of Lie algebra of ['A', 1] in the Chevalley basis in the Poincare-Birkhoff-Witt basis(i))_{i in Free abelian monoid indexed by {alpha[1], alphacheck[1], -alpha[1]}}
sage: PBW.algebra_generators()
Finite family {-alpha[1]: PBW[-alpha[1]], alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]]}
It clearly indicates that the basis keys should be an element of a free abelian monoid. LBYL. Now in this case, if we did try to convert the input into the keys, it should work. See https://trac.sagemath.org/ticket/18750. Actually, it is not as bad as I remembered in terms of outright timings, but there are some other technical issues.
Oh. Sorry. I admit that I have trouble parsing the Lazy family description.
Yea, I agree it is a bit heavy. There are some ways it could be simplified by saying the function is something like "the monomial map".
Free abelian monoid... Hmmm... What free abelian monoid?
sage: PBW.basis().keys().an_element()PBW[alpha[1]]^2*PBW[alphacheck[1]]^2*PBW[-alpha[1]]^3
So PBW.basis() is _indexed_ by elements of the basis of PBW? I am sorry for all these stupid questions but (as you can clearly see) I am confused as hell.
No, they are just have the same names. A good parallel would be the polynomial ring R = ZZ[x,y] in the natural basis. Here, R is the ZZ-algebra of the abelian monoid A = <x,y>, and subsequently, the basis elements are indexed by elements in A. We can call the elements in the monoid <c,d>, but that induces undue overhead on the programmer. For the PBW case, granted it is not a monoid algebra, so we cannot simply coerce in things from the indexing monoid (but of course, conversion is allowed), but the design is there. I would just be taking products of the algebra generators anyways and not worrying about constructing elements via the basis.
I looked at the ticket and I have no idea what it is about.
Right now, if we are trying to construct a monomial, we do not convert it into the indexing set of the basis and instead trust the user to do it. The ticket #18750 is about changing that.
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
So it is expecting subsets and that the user will not input bad data. There is no reason for it to simplify and not a bug. Granted, we could put a check on the user input here, but there is a speed penalty as this can be a well-used code path internally. Moreover, ducktyping can also be useful. So we are fairly permissive here, but not without due cause IMO.
Pardon my ignorance, but If there is no simplification then what is all this good for? It does simplify for universal enveloping algebra and so it should do it for Clifford algebras as well. Also I have a big issue with naming convention here. The method basis() does not produce a basis!
it is bad input. It does produce a basis, one indexed by subsets, not words/multisets. In math terms, if you have a sequence (x_i)_{i \in I}, then want x_j, where j \notin I, then you have an error. With #18750, this input might instead raise an error. If you want to do that, then you can do this:
sage: Q = QuadraticForm(QQ, 2, [1,0,1])
sage: C = CliffordAlgebra(Q)
sage: g = list(C.algebra_generators()); g
[e0, e1]
sage: prod(g[i] for i in [0,0,1,0,1,1,0,0])
-e0*e1
If you took your input and wrapped it with set:
sage: set((1,1,0,1))
{0, 1}
which would be the other possible outcome with #18750.
But sets are unhashable so how do I actually input the correct keys to cb = C.basis()?
Here we get into implementation details, and given your previous complaint about index sets, you are not going to like it. The object used to model the subsets are tuples.]
sage: C.basis().keys()
Subsets of {0, 1}
sage: list(_)
[(), (0,), (1,), (0, 1)]
However, we do require an explicit total order on the generators to have a well-defined representative of a monomial.
Another way to solve my original problem (which is to construct certain element of U \otimes C) would be to take tensor product of elements of U and C. Something like UC.tensor_elements(E*F+F*E, e*f - f*e).
You can always do tensor([x,y]), and you do not need to explicitly create the parent that way as well.
Remember that we are bound by the facilities of computer science and programming within Sage as well, which are usually much stronger constraints than mathematics (e.g., consider the set of real numbers). For the current implementation of tensor products, we require the algebra to be in AlgebrasWithBasis. I would not say limitations of the current framework to be a bug. Also, NC poly rings are in the category of algebras, so it does produce an algebra.
I understand. I just object to naming conventions. I mean the object that results from calling universal_algebra() presents itself as a ring. How can I know that it is actually also in category of algebras without digging through the code?
foo.category()C.basis() does produce a basis.
sage: list(C.basis())
[1, e0, e1, e0*e1]
Now pbw_basis() does return an algebra in a particular basis, so in some ways, it is returning a basis, just not for the Lie algebra. So now I see why you feel it is not completely natural. However, do you have a proposal for how to have convenient access to the PBW basis of U(g)? IMO, it cannot be connected with universal_enveloping_algebra() because that only has to return a class modeling the UEA, which should not be required to have a PBW basis method. Also, I feel that a PBW basis is really more closely connected to the Lie algebra and it is clear to someone working in this field what pbw_basis would return.
But that nonocmmutative ring that one gets from universal_enveloping_algebra() also has some implicit basis. What is this ring actually good for? I would think that most people would want to work with some PBW basis anyway.
Perfect bases (the q=1 version of a crystal basis) are equally good. Just having the existence of the UEA can allow you to do a fair bit of the representation theory. Also, there is no reason why we should limit someone doing a Lie algebra implementation to having the UEA be in the PBW basis. Also, for the free Lie algebra, its UEA is the free algebra, which has a natural basis you can work with.
I agree that the (NC) poly rings should be in the category of AlgebrasWithBasis as they are given with a distinguished basis, but there are methods that need to be implemented and some inconsistencies to resolve IIRC.
My objection is not only that pbw_basis() doesn't return a basis of L, but also that it returns algebra (with a preffered chosen basis).
I agree that it is not the best that it does not return a basis of L, but there is fundamentally no difference between a basis of the UEA and the UEA in a distinguished basis (other than possibly the interface).
I propose to get rid of pbw_basis method and introduce optional argument pbw_basis_ordering to universal_enveloping_algebra method.
Very strong -1. I do not believe the UEA should be forced to be in the PBW basis, which is what you are effectively making it do. Either that or you do cannot impose the behavior of a PBW basis. It also imposes much stronger restrictions on universal_enveloping_algebra(). In your proposal as well, the code is suggesting that it should be two separate methods and there is no easy way to construct the UEA in some PBW basis. I am open to changing the name of the method pbw_basis(), but I oppose merging it with universal_enveloping_algebra().
Best,
Travis
Free abelian monoid... Hmmm... What free abelian monoid?
sage: PBW.basis().keys().an_element()PBW[alpha[1]]^2*PBW[alphacheck[1]]^2*PBW[-alpha[1]]^3
So PBW.basis() is _indexed_ by elements of the basis of PBW? I am sorry for all these stupid questions but (as you can clearly see) I am confused as hell.
No, they are just have the same names. A good parallel would be the polynomial ring R = ZZ[x,y] in the natural basis. Here, R is the ZZ-algebra of the abelian monoid A = <x,y>, and subsequently, the basis elements are indexed by elements in A. We can call the elements in the monoid <c,d>, but that induces undue overhead on the programmer. For the PBW case, granted it is not a monoid algebra, so we cannot simply coerce in things from the indexing monoid (but of course, conversion is allowed), but the design is there. I would just be taking products of the algebra generators anyways and not worrying about constructing elements via the basis.
Thank you for clarification. I checked and they are different objects. They just have the same _repr_ string. Probably nothing to be done about that.
I looked at the ticket and I have no idea what it is about.
Right now, if we are trying to construct a monomial, we do not convert it into the indexing set of the basis and instead trust the user to do it. The ticket #18750 is about changing that.
OK. I don't really understand the wording of the ticket. I checked the example given there and it works and as far as I can tell it works as it should. In my opinion, Sage should give errors when the user tries to input something like
C.basis()[(1,0)]
I don't know enough about implementation details to see why any performance hit there would matter. In case the speed is really needed perhaps we could have another (private) method without the checks that would be used in heavy calculations? Waiting few hours more for some extensive calculations is definitely better than risking a worng output because you somewhere made a transposition error (0, 1) -> (1, 0).
sage: C.basis()
Lazy family (Term map from Subsets of {0, 1} to The Clifford algebra of the Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 1 ](i))_{i in Subsets of {0, 1}}
So it is expecting subsets and that the user will not input bad data. There is no reason for it to simplify and not a bug. Granted, we could put a check on the user input here, but there is a speed penalty as this can be a well-used code path internally. Moreover, ducktyping can also be useful. So we are fairly permissive here, but not without due cause IMO.
Pardon my ignorance, but If there is no simplification then what is all this good for? It does simplify for universal enveloping algebra and so it should do it for Clifford algebras as well. Also I have a big issue with naming convention here. The method basis() does not produce a basis!
it is bad input. It does produce a basis, one indexed by subsets, not words/multisets. In math terms, if you have a sequence (x_i)_{i \in I}, then want x_j, where j \notin I, then you have an error. With #18750, this input might instead raise an error. If you want to do that, then you can do this:
sage: Q = QuadraticForm(QQ, 2, [1,0,1])
sage: C = CliffordAlgebra(Q)
sage: g = list(C.algebra_generators()); g
[e0, e1]
sage: prod(g[i] for i in [0,0,1,0,1,1,0,0])
-e0*e1
If you took your input and wrapped it with set:
sage: set((1,1,0,1))
{0, 1}
which would be the other possible outcome with #18750.
But sets are unhashable so how do I actually input the correct keys to cb = C.basis()?
Here we get into implementation details, and given your previous complaint about index sets, you are not going to like it. The object used to model the subsets are tuples.]
And right there is the problem I have. Why do I, as a user, should know anything about the implementation details? Example of usage would bring me a long way. (Hence I propose to create a ticket for adding more examples into docstrings.)
Perhaps even better would be to have a more descriptive docstring for SubsetsSorted that would explain that the objects are actually ordered tuples. Or at least that the objects are SortedSets.
sage: C.basis().keys()
Subsets of {0, 1}
sage: list(_)
[(), (0,), (1,), (0, 1)]
However, we do require an explicit total order on the generators to have a well-defined representative of a monomial.
Another way to solve my original problem (which is to construct certain element of U \otimes C) would be to take tensor product of elements of U and C. Something like UC.tensor_elements(E*F+F*E, e*f - f*e).
You can always do tensor([x,y]), and you do not need to explicitly create the parent that way as well.
That's awesome! Great. It would be nicer if it worked even without the square brackets but that's just nitpicking. More importantly -- where are these features documented?
Remember that we are bound by the facilities of computer science and programming within Sage as well, which are usually much stronger constraints than mathematics (e.g., consider the set of real numbers). For the current implementation of tensor products, we require the algebra to be in AlgebrasWithBasis. I would not say limitations of the current framework to be a bug. Also, NC poly rings are in the category of algebras, so it does produce an algebra.
I understand. I just object to naming conventions. I mean the object that results from calling universal_algebra() presents itself as a ring. How can I know that it is actually also in category of algebras without digging through the code?
foo.category()C.basis() does produce a basis.
sage: list(C.basis())
[1, e0, e1, e0*e1]
Now pbw_basis() does return an algebra in a particular basis, so in some ways, it is returning a basis, just not for the Lie algebra. So now I see why you feel it is not completely natural. However, do you have a proposal for how to have convenient access to the PBW basis of U(g)? IMO, it cannot be connected with universal_enveloping_algebra() because that only has to return a class modeling the UEA, which should not be required to have a PBW basis method. Also, I feel that a PBW basis is really more closely connected to the Lie algebra and it is clear to someone working in this field what pbw_basis would return.
But that nonocmmutative ring that one gets from universal_enveloping_algebra() also has some implicit basis. What is this ring actually good for? I would think that most people would want to work with some PBW basis anyway.
Perfect bases (the q=1 version of a crystal basis) are equally good. Just having the existence of the UEA can allow you to do a fair bit of the representation theory. Also, there is no reason why we should limit someone doing a Lie algebra implementation to having the UEA be in the PBW basis. Also, for the free Lie algebra, its UEA is the free algebra, which has a natural basis you can work with.
I agree that the (NC) poly rings should be in the category of AlgebrasWithBasis as they are given with a distinguished basis, but there are methods that need to be implemented and some inconsistencies to resolve IIRC.
Perhaps a topic for SageDays94?
My objection is not only that pbw_basis() doesn't return a basis of L, but also that it returns algebra (with a preffered chosen basis).
I agree that it is not the best that it does not return a basis of L, but there is fundamentally no difference between a basis of the UEA and the UEA in a distinguished basis (other than possibly the interface).
There is a big conceptual difference between algebra and a basis of an algebra. For all practical purposes, pbw_basis() returns an object that behaves and is used, as far as I can see, as an algebra. I showed the current behavior to participants of SageDays93 and we all agreed that the current behavior of universal_enveloping_algebra() and pbw_basis() is confusing.
I propose to get rid of pbw_basis method and introduce optional argument pbw_basis_ordering to universal_enveloping_algebra method.
Very strong -1. I do not believe the UEA should be forced to be in the PBW basis, which is what you are effectively making it do. Either that or you do cannot impose the behavior of a PBW basis. It also imposes much stronger restrictions on universal_enveloping_algebra(). In your proposal as well, the code is suggesting that it should be two separate methods and there is no easy way to construct the UEA in some PBW basis. I am open to changing the name of the method pbw_basis(), but I oppose merging it with universal_enveloping_algebra().
Sorry, I don't understand. What restrictions are you talking about here? PBW basis always exists. Is it not true that all Lie algebras in Sage have one basis or another?
In my opinion, the object coming from pbw_basis() is much more useful and will be used by more people than the one coming from universal_enveloping_algebra().
sage: L = lie_algebras.sl(QQ,2)
sage: UEA = L.universal_enveloping_algebra()
sage: e,h,f = UEA.gens()
sage: I = UEA.ideal(e^2-h, f^2-h, side='twosided')
sage: I.syzygy_module()
Somebody actually proposed the same thing as Sebastian. Since, as you say, there are implementation difficulties with that approach, what about: universal_enveloping_algebra -> abstract_universal_enveloping_algebra & pbw_basis -> universal_enveloping_algebra? Another suggestion was pbw_basis -> universal_enveloping_algebra_with_pbw_basis.
def universal_enveloping_algebra(self, implementation=None, **kwds):
if implementation is None:
return self.lift.codomain()
elif implementation is "PBW":
return self.pbw_basis(**kwds)
else:
raise ValueError("invalid implementation")
Perhaps even better would be to have a more descriptive docstring for SubsetsSorted that would explain that the objects are actually ordered tuples. Or at least that the objects are SortedSets.
Sometimes we need to make tradeoffs for ease of programming maintenance and speed. Now we can check the user input to put it into correct form, but IMO it is needless technical debt and wasted CPU cycles to use a more complicated class than Python's tuple.
sage: C.basis().keys()
Subsets of {0, 1}
sage: list(_)
[(), (0,), (1,), (0, 1)]
However, we do require an explicit total order on the generators to have a well-defined representative of a monomial.
Another way to solve my original problem (which is to construct certain element of U \otimes C) would be to take tensor product of elements of U and C. Something like UC.tensor_elements(E*F+F*E, e*f - f*e).
You can always do tensor([x,y]), and you do not need to explicitly create the parent that way as well.
That's awesome! Great. It would be nicer if it worked even without the square brackets but that's just nitpicking. More importantly -- where are these features documented?
It is in CombinatorialFreeModule_tensor. I was thinking there was an example in "tensor()", but there is not. We should add one to tensor().
Remember that we are bound by the facilities of computer science and programming within Sage as well, which are usually much stronger constraints than mathematics (e.g., consider the set of real numbers). For the current implementation of tensor products, we require the algebra to be in AlgebrasWithBasis. I would not say limitations of the current framework to be a bug. Also, NC poly rings are in the category of algebras, so it does produce an algebra.
I understand. I just object to naming conventions. I mean the object that results from calling universal_algebra() presents itself as a ring. How can I know that it is actually also in category of algebras without digging through the code?
foo.category()C.basis() does produce a basis.
sage: list(C.basis())
[1, e0, e1, e0*e1]
Now pbw_basis() does return an algebra in a particular basis, so in some ways, it is returning a basis, just not for the Lie algebra. So now I see why you feel it is not completely natural. However, do you have a proposal for how to have convenient access to the PBW basis of U(g)? IMO, it cannot be connected with universal_enveloping_algebra() because that only has to return a class modeling the UEA, which should not be required to have a PBW basis method. Also, I feel that a PBW basis is really more closely connected to the Lie algebra and it is clear to someone working in this field what pbw_basis would return.
But that nonocmmutative ring that one gets from universal_enveloping_algebra() also has some implicit basis. What is this ring actually good for? I would think that most people would want to work with some PBW basis anyway.
Perfect bases (the q=1 version of a crystal basis) are equally good. Just having the existence of the UEA can allow you to do a fair bit of the representation theory. Also, there is no reason why we should limit someone doing a Lie algebra implementation to having the UEA be in the PBW basis. Also, for the free Lie algebra, its UEA is the free algebra, which has a natural basis you can work with.
I agree that the (NC) poly rings should be in the category of AlgebrasWithBasis as they are given with a distinguished basis, but there are methods that need to be implemented and some inconsistencies to resolve IIRC.
Perhaps a topic for SageDays94?
+1 <shameless plug>You should also apply for funding as a participant for SageDays@ICERM too.</shameless plug>
My objection is not only that pbw_basis() doesn't return a basis of L, but also that it returns algebra (with a preffered chosen basis).
I agree that it is not the best that it does not return a basis of L, but there is fundamentally no difference between a basis of the UEA and the UEA in a distinguished basis (other than possibly the interface).
There is a big conceptual difference between algebra and a basis of an algebra. For all practical purposes, pbw_basis() returns an object that behaves and is used, as far as I can see, as an algebra. I showed the current behavior to participants of SageDays93 and we all agreed that the current behavior of universal_enveloping_algebra() and pbw_basis() is confusing.
I do not know how you presented it, but I feel that it a bit unfair to say because you yourself had said you are confused by it. Also, the pbw_basis() is not an algebra in the abstract concept but a class modeling a chosen PBW basis of the UEA. So there is a lot more structure (and limitations).
I propose to get rid of pbw_basis method and introduce optional argument pbw_basis_ordering to universal_enveloping_algebra method.
Very strong -1. I do not believe the UEA should be forced to be in the PBW basis, which is what you are effectively making it do. Either that or you do cannot impose the behavior of a PBW basis. It also imposes much stronger restrictions on universal_enveloping_algebra(). In your proposal as well, the code is suggesting that it should be two separate methods and there is no easy way to construct the UEA in some PBW basis. I am open to changing the name of the method pbw_basis(), but I oppose merging it with universal_enveloping_algebra().
Sorry, I don't understand. What restrictions are you talking about here? PBW basis always exists. Is it not true that all Lie algebras in Sage have one basis or another?
Mathematical abstraction versus concrete computation. Abstractly, you always have a PBW basis, so abstractly you always have an isomorphism with any other class modeling a basis of the UEA. However, you may not know what that isomorphism is concretely. Hence, it is impossible to define a coercion between a PBW basis and a generic basis of the UEA. However, by attaching a pbw_basis() to any UEA (which, as I said above, is wholly impractical to do), you are tacitly saying there should be a way to go from that UEA implementation to the object returned by the pbw_basis (I would certainly object).
Also, I believe it is possible to define a Lie algebra from an associative algebra that does not have a (distinguished) basis, and so this Lie algebra would not have a (distinguished) basis. At least, I do not believe there are any technical limitations to this. You can also define an object in Lie algebras as being a set of matrices satisfying certain conditions closed under commutators and not know what an explicit basis is. While it does not afford you much in the way of features currently, its not to say that there might be enough structure there to do something useful with it. There is no reason to limit the future.
In my opinion, the object coming from pbw_basis() is much more useful and will be used by more people than the one coming from universal_enveloping_algebra().
That is great for your applications. What if you want to look at certain ideals of the UEA and, say, compute its syzygy module:
sage: L = lie_algebras.sl(QQ,2)
sage: UEA = L.universal_enveloping_algebra()
sage: e,h,f = UEA.gens()
sage: I = UEA.ideal(e^2-h, f^2-h, side='twosided')
sage: I.syzygy_module()
Being fair, I don't know if people actually look at such things, but I know there are ways to compute Gröbner bases of NC ideals in Singular (Plural?); this was the first hit on Google "noncommutative groebner basis, singular"
https://www.ricam.oeaw.ac.at/specsem/srs/groeb/download/Levandovskyy_ncgb.pdf
So it might just be a matter of exposing Singular features in Sage to do things like quotients in NC rings, whereas it do similar computations with the PBW basis would require a significant amount of work currently.
Somebody actually proposed the same thing as Sebastian. Since, as you say, there are implementation difficulties with that approach, what about: universal_enveloping_algebra -> abstract_universal_enveloping_algebra & pbw_basis -> universal_enveloping_algebra? Another suggestion was pbw_basis -> universal_enveloping_algebra_with_pbw_basis.
I believe that is completely unmanageable unless I am misunderstanding something about your approach. You would require a (sub)class for each Lie algebra that wanted to implement a different UEA that the PBW basis. Let me say again that mathematics has a lot more freedom than computer implementations; the canonical being the real numbers and formal power series.
Here is an idea based on one of your suggestions for how to have universal_enveloping_algebra() be more, ahem, universal.
def universal_enveloping_algebra(self, implementation=None, **kwds):
if implementation is None:
return self.lift.codomain()
elif implementation is "PBW":
return self.pbw_basis(**kwds)
else:
raise ValueError("invalid implementation")
This way you can specify the implementation with having a default being the (distinguished) one from _construct_UEA() and you get the PBW basis. (Well, technically this would go in the LieAlgebrasWithBasis category and the one in LieAlgebras would not have the extra PBW implementation elif.)
I've created #24914.
I will get around to it by the end of the week. I would appreciate pointers to where tensor() is defined
sage: import_statements(tensor)
from sage.categories.tensor import tensor
and how would one actually define an arbitrary ordering for pbw_basis.
+1 <shameless plug>You should also apply for funding as a participant for SageDays@ICERM too.</shameless plug>
Will do. Thanks!
My objection is not only that pbw_basis() doesn't return a basis of L, but also that it returns algebra (with a preffered chosen basis).
I agree that it is not the best that it does not return a basis of L, but there is fundamentally no difference between a basis of the UEA and the UEA in a distinguished basis (other than possibly the interface).
There is a big conceptual difference between algebra and a basis of an algebra. For all practical purposes, pbw_basis() returns an object that behaves and is used, as far as I can see, as an algebra. I showed the current behavior to participants of SageDays93 and we all agreed that the current behavior of universal_enveloping_algebra() and pbw_basis() is confusing.
I do not know how you presented it, but I feel that it a bit unfair to say because you yourself had said you are confused by it. Also, the pbw_basis() is not an algebra in the abstract concept but a class modeling a chosen PBW basis of the UEA. So there is a lot more structure (and limitations).
Sorry. I tried to be fair. I am attachign the notebook I used for demonstration.
Somebody actually proposed the same thing as Sebastian. Since, as you say, there are implementation difficulties with that approach, what about: universal_enveloping_algebra -> abstract_universal_enveloping_algebra & pbw_basis -> universal_enveloping_algebra? Another suggestion was pbw_basis -> universal_enveloping_algebra_with_pbw_basis.
I believe that is completely unmanageable unless I am misunderstanding something about your approach. You would require a (sub)class for each Lie algebra that wanted to implement a different UEA that the PBW basis. Let me say again that mathematics has a lot more freedom than computer implementations; the canonical being the real numbers and formal power series.
Here is an idea based on one of your suggestions for how to have universal_enveloping_algebra() be more, ahem, universal.
def universal_enveloping_algebra(self, implementation=None, **kwds):
if implementation is None:
return self.lift.codomain()
elif implementation is "PBW":
return self.pbw_basis(**kwds)
else:
raise ValueError("invalid implementation")
This way you can specify the implementation with having a default being the (distinguished) one from _construct_UEA() and you get the PBW basis. (Well, technically this would go in the LieAlgebrasWithBasis category and the one in LieAlgebras would not have the extra PBW implementation elif.)
I believe this is pretty much what I suggested on 23.2. The latter suggestions are merely renames of the current methods. I think the absolute minimum we should do is to rename pbw_basis to something like universal_enveloping_algebra_pbw That way the naming is not confusing and the feature is easily discoverable by the user. Merging these two methods in the way you propose is IMHO nicer API.