BUGS in tensor products of algebras

217 views
Skip to first unread message

Vít Tuček

unread,
Feb 21, 2018, 10:29:50 AM2/21/18
to sage-devel
Hi!

I would like to do some calculations but I hit the wall with in the very beginning. The following was tested on 8.2-beta6

L = lie_algebras.sl(QQ, 2)
U = L.universal_enveloping_algebra() # Noncommutative Multivariate Polynomial Ring => can't do tensor product with algebra. BUG?
PBW = L.pbw_basis() # universal enveloping algebra  =>  can do tensor product with algebra but very nonintuitive name  BUG? Also, how do I define ordering on the basis?

E, F, H = PBW.algebra_generators()

Q = QuadraticForm(QQ, 2, [1,0,1])
C = CliffordAlgebra(Q)
e, f = C.algebra_generators()

UC = PBW.tensor(C) # but how to access its basis?   
x = UC.algebra_generators()[(E, e)] # this actually defines some element but it has broken _repr_ and _latex_ so I can't see it.
UC.algebra_generators()[E*F - F*E, (1, 1)] # works but what's with (1, 1)? I found it by accident! Wait, it doesn't simplify e1*e1 to 1! BUG!

# So let's try tensor product in other order to see if it always simplifies the first term in the product
CU = C.tensor(PBW) # AttributeError: 'Rings_with_category' object has no attribute 'TensorProducts'
### Strange. I tried running it in a restarted kernel for the second time to be sure and it worked.

# Hmmm. But this tensor product of C with itself works.
CC = C.tensor(C)
CC.algebra_generators()[(0,0), (1,1)] # But it does not simplify on either side!

Acutally, you might encounter random AttributeErrors when tensoring algebras. The trace is attached and it's appearance was completely random. This was produced by running

set_random_seed(2)
L = lie_algebras.sl(QQ, 2)
U = L.universal_enveloping_algebra()
PBW = L.pbw_basis()
E, F, H = PBW.algebra_generators()
Q = QuadraticForm(QQ, 2, [1,0,1])
C = CliffordAlgebra(Q)
e, f = C.algebra_generators()
UC = PBW.tensor(C)
x = UC.algebra_generators()[(E, e)]
UC.algebra_generators()[E*F - F*E, (1, 1)]

In several fresh Sage shells. Once in ten times it gives you an error.

Best regards,
                          Vit Tucek

P.S.: How would I define tensor product of two algebras over a common subalgebra?

Travis Scrimshaw

unread,
Feb 21, 2018, 8:44:44 PM2/21/18
to sage-devel
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):

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.

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

Vít Tuček

unread,
Feb 22, 2018, 11:20:34 AM2/22/18
to sage-devel
Hey Travis,
 thank you for clarification.

Dne čtvrtek 22. února 2018 2:44:44 UTC+1 Travis Scrimshaw napsal(a):
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.

 
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!

 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.
 

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.

 
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.
 
Best,
Travis


Best regards,
                         Vit

Travis Scrimshaw

unread,
Feb 22, 2018, 6:15:59 PM2/22/18
to sage-devel
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: 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.
 

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.

 

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

Vít Tuček

unread,
Feb 23, 2018, 6:59:36 AM2/23/18
to sage-...@googlegroups.com
Hi!

Dne pátek 23. února 2018 0:15:59 UTC+1 Travis Scrimshaw napsal(a):
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.


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()? 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).
 
 
 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.


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?
 
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. Something like this:

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.

If you don't like my proposal above then I have no objections here.

 
Now the fact that you sometimes obtaining random attribute errors when running that code block is a definite bug. Please submit a trac ticket.

 

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.

Awesome!
 

Best,
Travis


Best,
             Vit

--
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.

Travis Scrimshaw

unread,
Feb 23, 2018, 5:28:21 PM2/23/18
to sage-devel

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

Sebastian Oehms

unread,
Feb 24, 2018, 11:19:07 AM2/24/18
to sage-devel
Hi Travis,

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).

Best,
Sebastian

Travis Scrimshaw

unread,
Feb 26, 2018, 6:04:55 AM2/26/18
to sage-devel


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).

That is both horrible to work with and practically impossible to do. You require every implementation returned of UEA to know how to go to a PBW basis (and in principle, from). There is no reasonable way to expect the Lie algebra to know how to do this, and you would have to (IMO needlessly) subclass, e.g., NC poly ring, which is generally not a UEA. Also, while NC poly ring is generic, it would only work for finite-dimensional Lie algebras. We could do this with a category for UEAs, but I do not see any benefit to having this overhead and complications. Also, what about the cases where the only reasonable implementation of the UEA is the PBW basis? What about when there are multiple realizations*? Why should the UEA require anything special about the implementation? For the places where I do need the specialized things, that is why there is the separate pbw_basis().

Also, by being in the category of ModulesWithBasis(), the .basis() must return the distinguished basis object, not an isomorphic algebra (since we consider categories to be like abstract classes and defining the API).

Also, think about it this way, say we have a global function PBWBasis. It would naturally take in a Lie algebra (and optional ordering of the basis) as input. Now in many ways L.pbw_basis() is equivalent to pbw_basis(L) and the PBW basis is strongly correlated to the Lie algebra. So it is natural IMO to have such a method and as a primary entry point.

Best,
Travis

* - Although to be fair, this is currently something that will need to be addressed with the current framework. However, there is a possible approaches by returning an algebra that has multiple realizations.

Sebastian Oehms

unread,
Feb 26, 2018, 10:16:27 AM2/26/18
to sage-...@googlegroups.com
Hi Travis,

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).

Best,
Sebastian


Travis Scrimshaw

unread,
Feb 27, 2018, 7:45:30 AM2/27/18
to sage-devel


please don't take my poste as a suggestion. I'm not close enough to the subject that I really could do that.

That doesn't mean you cannot have a good suggestion.
 
I just wanted to point out where the confusion comes from (hoping you have I good Idea what we can do against it).

I've tried a few different approaches and this is the one that both felt natural and worked well. I am open to suggestions, despite what it may seem, but I do have some use-cases in mind and want to keep as much flexibility as possible.

Best,
Travis

Vít Tuček

unread,
Feb 28, 2018, 5:22:36 PM2/28/18
to sage-devel
Hi!

Dne pátek 23. února 2018 23:28:21 UTC+1 Travis Scrimshaw napsal(a):

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.
 

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(). 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.

Best,
Travis

Travis Scrimshaw

unread,
Mar 1, 2018, 6:08:46 PM3/1/18
to sage-devel

 
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.

The reason for that is somewhere between being natural and being lazy. The easiest way to implement the PBW basis was to pass the prefix to the underlying basis indexing set and not do any string parsing and replacing in the subclass of CombinatorialFreeModule. I also felt it was natural as I outlined above.
 
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)]

Not if the basis is indexed by tuples or the indexing set that takes tuples as input? You then put the burden on the user and double create the indexing elements (or worse, you force a containment test). Also, there is no reason why we should force the indexing set to be a subclass of Parent or be a callable object.

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).

It is used in a tight loop (which this code can be), that can a few hours can actually be double the time it used to take.
 
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.)

+1 Go ahead and create it. I will be happy to review it.
 
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.)

Best,
Travis

Vít Tuček

unread,
Mar 6, 2018, 9:06:47 AM3/6/18
to sage-devel


Dne pátek 2. března 2018 0:08:46 UTC+1 Travis Scrimshaw napsal(a):

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 and how would one actually define an arbitrary ordering for pbw_basis.
 
 
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>

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.
 
 
 
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.
 

OK. Now I understand the need for abstract UAE. Thank you very much for clarification.
 
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.
 
algebras.ipynb

Travis Scrimshaw

unread,
Mar 6, 2018, 5:44:13 PM3/6/18
to sage-devel


I've created #24914.

IMO, would be better to have individual tickets for each file/issue as they are independent. If you decide to do that, you can either keep #24914 as a meta-ticket or recycle it as one of the tickets for one of the specific issues.
 
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

One of the most useful tools for development IMO. :)

 
and how would one actually define an arbitrary ordering for pbw_basis.
 
There is the example in the PBW class and in the Verma modules code. The API is you define a function that takes an index of the Lie algebra's basis and returns a key object just like for Python's sorted() key parameter (in fact, it essentially feeds it off to sorted()).


+1 <shameless plug>You should also apply for funding as a participant for SageDays@ICERM too.</shameless plug>

Will do. Thanks!

It will be great to talk to you in person at both of these and work on improving (Lie) algebras in Sage. :)
 
 
 
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.

I do not mean to suggest you did not try, but I just feel it is hard to be.
 
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.

It is not in a couple of key areas. The biggest is that is gives you a hook to have multiple implementations (say, as an NC poly ring, the PBW basis, and some other class that is custom built for your purposes). It also has a consistent API for those Lie algebras that may not have a distinguished basis. Let me be clear, I am in no way proposing or suggesting removing pbw_basis().

I also do not like the suggested change of the method name. It is too much of a mouthful and does not offer really any clarity IMO. Again, if we rewrite L.pbw_basis() in function form of pbw_basis(L), wouldn't you prefer that over universal_enveloping_algebra_pbw_basis(L)? Now we can have that be an alias, but we also then should have the alias universal_enveloping_algebra_poincare_birkhoff_witt_basis().

Best,
Travis

Reply all
Reply to author
Forward
0 new messages