Opened 2 years ago
Last modified 6 months ago
#21413 needs_info enhancement
A class for ring extensions
Reported by:  caruso  Owned by:  

Priority:  major  Milestone:  sage7.4 
Component:  algebra  Keywords:  sd75 
Cc:  jsrn, defeo, bruno, nthiery, SimonKing, saraedum  Merged in:  
Authors:  Reviewers:  
Report Upstream:  N/A  Work issues:  
Branch:  u/caruso/21413/class_ring_extension (Commits)  Commit:  656ec777d4030fffa17a65f85c4cce87ca7d289e 
Dependencies:  Stopgaps: 
Description (last modified by )
Sage actually provides a rich framework for dealing with all classical algebraic structures: rings, fields, algebras, etc.
Nevertheless, given (for instance) two fields K and L with K \subset L, it is not possible to build the extension L/K as a Sage object. However one can easily imagine methods related to this extension (e.g. degree
, discriminant
, normal_basis
, decompose_on_basis
, etc.)
With Bruno Grenet, Johan Rosenkilde and Luca De Feo, we raised this issue at Sage Days 75. A summary of our discussion is available here.
This ticket implements very generic classes for ring extensions. Other more specific classes (e.g. for field extensions or even finite field extensions) are coming soon...
Change History (31)
comment:1 Changed 2 years ago by
 Branch set to u/caruso/21413/class_ring_extension
comment:2 Changed 2 years ago by
 Commit set to 556da4d4c006f305384a3368018809323d0e0997
comment:3 Changed 2 years ago by
 Commit changed from 556da4d4c006f305384a3368018809323d0e0997 to c82968fff27df846064805774d1d3bf39ddc9759
comment:4 Changed 2 years ago by
 Commit changed from c82968fff27df846064805774d1d3bf39ddc9759 to 036fb2a439cd9ee534d8e9489da02a3dde2452ea
Branch pushed to git repo; I updated commit sha1. New commits:
f0a7ce4  Doctest from the class AlgebraFromMorphism and some methods of this class

b6c9a33  Doctest fixed

67c82c7  Merge branch 'develop' into 21413/class_ring_extension

8d70dbe  Code split in several files. More doctests.

efa3689  Doctest for BaseActionOnRing

7f8ce2d  Doctest for the class AlgebraToRing_coercion

991cc70  Doctest for the class AlgebraFMElement

036fb2a  Adding licence & author

comment:5 Changed 2 years ago by
 Description modified (diff)
 Status changed from new to needs_review
comment:6 Changed 2 years ago by
Wow, this is great Xavier! Sorry for not being more active before  I promise to look more at it tomorrow.
I'm wondering whether it's a good idea to merge the "framework" before the first concrete instantiation? I.e. whether we should try to get the fieldextensionalgebra finished before considering this as mature? (I know you have bad experience with too large patches, but if we don't put too much stuff in the field extension as a first approximation, perhaps it's ok).
Best, Johan
comment:7 followup: ↓ 8 Changed 2 years ago by
In the following, the extension is A = L/K with L and K rings. L.base()
is B.
Sometimes B is a subring of K.
Right now this AlgebraFromMorphism
is mainly a thin wrapper around the
L, so e.g. A elements are represented internally as elements of L, and this is
also how you print them. Can you try to convince me of the value from a user's
POV that he can do arithmetic on his elements inside this algebra, rather than
dropping the whole Algebra idea and just letting RingExtension
be some
nonparent object with fancy methods on it like decompose_on_basis
?
What I had in mind after SD75 is that RingExtension
is an Algebra
as in "a
vector space equipped with a bilinear product"; in other words, when I want to
see L as a vector space over K, I use RingExtension
. In this world, it makes
sense to have arithmetic on elements of A
and they should print (and possibly
be internally represented by) vectors over K; because that's the whole point of
why I'm wrapping L.
In that world, AlgebraFromMorphism
shouldn't have a gen
method because it
isn't really focused on its personality as a ring (it might have a
multiplicative_generator
if you like). But it should definitely have a basis
method.
Other remarks that I got by looking at the code. Let's see where the above discussion takes us before doing much about the stuff below:
 Why are you not giving
self._base
as argument toCommutativeAlgebra.__init__
? You write in a comment that we don't want a coercion mapbase > self
 I don't see why not? I guess this is related to the left/right action dichotomy you have?  The module doc for
algebra_from_morphism is too short
. It should explain what this module is and what is offered. Redundancy is not bad.  A method "def something(self)" should never have the docstring "Return the something of self". That's utterly unhelpful :)
from_base_ring
has an extremely bad name considering that it doesn't embed an element of the base. I think we need to establish some proper nomenclature and do some commutation diagrams in the doc of this module. The doc for
scalar_restriction
is very hard to read. Attempt to write before INPUT what this means. Could we write something like
If ``newbase`` is a subring of `self.base()`, then the scalar restriction of `self` to `newbase` is the ring extension `self.ring()/newbase`. The defining morphism will be the composition of `f` and ``self.defining_morphism()`` where `f` is the coercion map from `newbase` to `self.base()`. ``newbase`` can be given as an extension, ... ``newbase`` can be given as a morphism, ...
What is the argument for allowing extensions and morphisms as arguments to
scalar_restriction
? Is it really something you would normally do? Couldn't the user just doA.scalar_restriction(mymorphism.codomain())
, etc.?
 I don't like
ring
andbase
. They are too short and it's not clear which is which.  Speaking in parents, you let K * A = A but you let A * K = L. Won't this be a major source of confusion for users? I think your nasty example with noncommutativity at the end of
RingExtension
doc makes this even worse! I'm also very concerned that this might break several things in Sage since you're inheriting fromCommutativeAlgebra
.  Doc of
RingExtension
: can we make a commuting diagram to describe the coercion between L1/K1 and L2/K2? Something like
K1 > L1 ^     v K2 > L2
Best, Johan
comment:8 in reply to: ↑ 7 ; followup: ↓ 9 Changed 2 years ago by
Replying to jsrn:
Right now this
AlgebraFromMorphism
is mainly a thin wrapper around the L, so e.g. A elements are represented internally as elements of L, and this is also how you print them. Can you try to convince me of the value from a user's POV that he can do arithmetic on his elements inside this algebra, rather than dropping the whole Algebra idea and just lettingRingExtension
be some nonparent object with fancy methods on it likedecompose_on_basis
?
Maybe I misunderstand your proposal but I really think that a ring extension should be a parent because we really want to take advantage of the coercion stuff.
Nonetheless, the question "should it derive from CommutativeAlgebra
?" is arguable and I can imagine arguments in both directions.
What I had in mind after SD75 is that
RingExtension
is anAlgebra
as in "a vector space equipped with a bilinear product"; in other words, when I want to see L as a vector space over K, I useRingExtension
.
It is definitely.
In this world, it makes sense to have arithmetic on elements of
A
and they should print (and possibly be internally represented by) vectors over K; because that's the whole point of why I'm wrapping L.
I agree. But all of this has to be implemented in subclasses. For now, I just wrote a very general class which is supposed to deal with all algebras (possibly not free, not finite...) so it is of course difficult to implement concrete methods.
But these methods clearly exist. Here is a farfromexhaustive list: scalar_restriction
(which is already implemented), __mul__
(usual product of algebras), tensor_product
, scalar_extension
, cayley_differentials
, krull_relative_dimension
, is_free
, is_finite
, is_flat
, is_etale
, is_smooth
, is_open_immersion
, is_closed_immersion
, is_galois
, galois_group
. And for elements: trace
, norm
.
If you insist, I can put these methods in the general class and let them raise NotImplementedError
... but it would be difficult to write the doctest :)
In that world,
AlgebraFromMorphism
shouldn't have agen
method because it isn't really focused on its personality as a ring (it might have amultiplicative_generator
if you like).
The generator of an algebra is a welldefined mathematical notion: the algebra L/K is generated by x if $K \cup {x}$ generates L as a ring. So it clearly makes sense to have a gen
method.
But it should definitely have a
basis
method.
Well there does exist algebras which are not free. So the basis
method is clearly something we want. However it should not be inserted in such a general class but in the subclass FreeAlgebraFromMorphism
or FiniteFreeAlgebraFromMorphism
(which is coming soon).
Why are you not giving
self._base
as argument toCommutativeAlgebra.__init__
? You write in a comment that we don't want a coercion mapbase > self
 I don't see why not? I guess this is related to the left/right action dichotomy you have?
Suppose that we create an algebra L/K with a defining morphism phi : K > L which is not a coercion map. If K coerces to L/K through phi and L/K coerces to L, then we would derive that K coerces to L through phi.
Such a situation really occurs in every day life (at least for people working in algebraic geometry). For instance, if K has characteristic p, these people often consider K as an algebra over itself *through the Frobenius morphism* (which is definitely not a coercion map).
The module doc for
algebra_from_morphism is too short
. It should explain what this module is and what is offered.Redundancy is not bad.
A method "def something(self)" should never have the docstring "Return the something of self". That's utterly unhelpful :)
Ok for both. I'll try to fix this.
from_base_ring
has an extremely bad name considering that it doesn't embed an element of the base. I think we need to establish some proper nomenclature and do some commutation diagrams in the doc of this module.
It is not my fault :). This method is needed by the coercion model.
The doc for
scalar_restriction
is very hard to read. Attempt to write before INPUT what this means. Could we write something like
Ok. I'll do it.
What is the argument for allowing extensions and morphisms as arguments to
scalar_restriction
? Is it really something you would normally do? Couldn't the user just doA.scalar_restriction(mymorphism.codomain())
, etc.?
Sure, it is something we normally do... just as composing ring homomorphisms.
I don't like
ring
andbase
. They are too short and it's not clear which is which.
Ok for changing. I'm also not completed satisfied with these names. Do you have some propositions?
Speaking in parents, you let K * A = A but you let A * K = L. Won't this be a major source of confusion for users? I think your nasty example with noncommutativity at the end of
RingExtension
doc makes this even worse!
I definitely agree that it is not perfect, but I have not found something better :). The point is that I really want to have algebras_from_morphisms_which_are_not_coercion_maps and I think that implementing the action of scalars (through the defining morphism) is the least we can do.
I'm also very concerned that this might break several things in Sage since you're inheriting from
CommutativeAlgebra
.
It is one reason why I'm sure that we should inherit from CommutativeAlgebra
Doc of
RingExtension
: can we make a commuting diagram to describe the coercion between L1/K1 and L2/K2?
Ok.
Xavier
comment:9 in reply to: ↑ 8 ; followup: ↓ 10 Changed 2 years ago by
 Cc nthiery SimonKing added
 Status changed from needs_review to needs_info
Thanks for your careful explanations. I'm learning a lot here.
Replying to carus:
Maybe I misunderstand your proposal but I really think that a ring extension should be a parent because we really want to take advantage of the coercion stuff.
Nonetheless, the question "should it derive from
CommutativeAlgebra
?" is arguable and I can imagine arguments in both directions.
OK, so "coercion stuff" is an argument in favour of a Parent. I guess you mean that many objects will magically coerce to the DoWhatIMean behaviour on methods. But if a weird/surprising behaviour follows from forcing it into the category framework, perhaps that's an argument against it.
At least having a RingExtension
being a class with lots of service methods, sort of like David's RelativeFiniteFieldExtension
, there will be no arithmetic problems. You could also put norm
and trace
there.
In this world, it makes sense to have arithmetic on elements of
A
and they should print (and possibly be internally represented by) vectors over K; because that's the whole point of why I'm wrapping L.I agree. But all of this has to be implemented in subclasses. For now, I just wrote a very general class which is supposed to deal with all algebras (possibly not free, not finite...) so it is of course difficult to implement concrete methods.
OK, that makes sense. I can see why the general class would have very weak functionality then.
But these methods clearly exist. Here is a farfromexhaustive list: .... If you insist, I can put these methods in the general class and let them raise
NotImplementedError
... but it would be difficult to write the doctest :)
Perhaps that's not a bad idea: it's nicer that any algebra will have the methods you expect and then throw NotImplementedError
rather than not advertising the method at all.
The doctest can be on a more concrete class that does implement the method. If none exist for this ticket, the doctest will just be one demonstrating the NotImplentedError
for now, with the sole purpose of doctest coverage ;)
The generator of an algebra is a welldefined mathematical notion: the algebra L/K is generated by x if $K \cup {x}$ generates L as a ring. So it clearly makes sense to have a
gen
method.
Hmm, but couldn't there be multiple generators? E.g. F[x,y]/F
?
Well there does exist algebras which are not free. So the
basis
method is clearly something we want. However it should not be inserted in such a general class but in the subclassFreeAlgebraFromMorphism
orFiniteFreeAlgebraFromMorphism
(which is coming soon).
OK, argument accepted. But I think this kind of stuff reinforces that we should try to design the first concrete RingExtension
, e.g. FiniteFieldExtension
simultaneously with this ticket. Then we'll better be able to judge what goes where and how it should look to be useful on both sides.
Suppose that we create an algebra L/K with a defining morphism phi : K > L which is not a coercion map. If K coerces to L/K through phi and L/K coerces to L, then we would derive that K coerces to L through phi.
Such a situation really occurs in every day life (at least for people working in algebraic geometry). For instance, if K has characteristic p, these people often consider K as an algebra over itself *through the Frobenius morphism* (which is definitely not a coercion map).
Yikes! So we must disallow coercion from K > L/K
. But we should allow A(k)
and k*a
, a*k
, k + a
, etc. for k in K
and a in A
. And A(a * l)
is
different from a * A(l)
. Oh man...
It seems to me that this is really dangerous territory  but perhaps
unavoidable. Someone implementing algorithms for CommutativeAlgebra
is going
to assume that there is coercion from base
to self
. And that multiplication
of base
and self
elements commute!
Perhaps CommutativeAlgebra
should be called something different, and
AlgebraFromMorphism
should have a different base class. I've cc'ed Nicolas
Thiery and Simon King in this discussion to chip in.
from_base_ring
has an extremely bad name considering that it doesn't embed an element of the base. I think we need to establish some proper nomenclature and do some commutation diagrams in the doc of this module.It is not my fault :). This method is needed by the coercion model.
Eew, yet another symptom that we're perhaps abusing the current hierarchy.
Why doesn't GF(9)
have from_base_ring
? What kind of Parent requires it?
What is the argument for allowing extensions and morphisms as arguments to
scalar_restriction
? Is it really something you would normally do? Couldn't the user just doA.scalar_restriction(mymorphism.codomain())
, etc.?Sure, it is something we normally do... just as composing ring homomorphisms.
So it is something where established mathematical notation supports this
directly? It's much more explicit to just write
A.scalar_restriction(Aother.ring())
, so I'd prefer not supporting
A.scalar_restriction(Aother)
, except if a properly educated mathematician
would be very surprised if this didn't exist.
I don't like
ring
andbase
. They are too short and it's not clear which is which.Ok for changing. I'm also not completed satisfied with these names. Do you have some propositions?
We should probably first figure out what to do hierarchywise. But perhaps
keep ring > ring_of_element
and base > ring_of_scalars
. Alternative element_ring
resp. scalar_ring
.
Speaking in parents, you let K * A = A but you let A * K = L. Won't this be a major source of confusion for users? I think your nasty example with noncommutativity at the end of
RingExtension
doc makes this even worse!I definitely agree that it is not perfect, but I have not found something better :). The point is that I really want to have algebras_from_morphisms_which_are_not_coercion_maps and I think that implementing the action of scalars (through the defining morphism) is the least we can do.
What do you mean "is the least we can do"?
Why is this an argument to make left and right actions different? Couldn't you implement the same left/right action, namely mapping K > A
by phi
, followed by multiplication in A
.
Best, Johan
comment:10 in reply to: ↑ 9 Changed 2 years ago by
Replying to jsrn:
Perhaps that's not a bad idea: it's nicer that any algebra will have the methods you expect and then throw
NotImplementedError
rather than not advertising the method at all.
OK. But, on the other hand, the list of possible methods is possibly quite long. Having a parent with 90% not implemented methods is also not that nice.
The generator of an algebra is a welldefined mathematical notion: the algebra L/K is generated by x if $K \cup {x}$ generates L as a ring. So it clearly makes sense to have a
gen
method.Hmm, but couldn't there be multiple generators? E.g.
F[x,y]/F
?
Yes, of course.
For traditional rings, the current behaviour of gen
is rather stange (to me):
sage: R.<x,y> = QQ[] sage: R.gen() x
Is that normal?
OK, argument accepted. But I think this kind of stuff reinforces that we should try to design the first concrete
RingExtension
, e.g.FiniteFieldExtension
simultaneously with this ticket. Then we'll better be able to judge what goes where and how it should look to be useful on both sides.
I just do not want this ticket to become too big.
But I agree for implementing FiniteFieldExtension
here.
Yikes! So we must disallow coercion from
K > L/K
. But we should allowA(k)
andk*a
,a*k
,k + a
, etc. fork in K
anda in A
. AndA(a * l)
is different froma * A(l)
. Oh man...
(First, let me emphasize that this issue only occurs when the defining morphism is not a coercion map.)
Currently A(k)
, a*k
, k + a
uses coercion maps (and not defining morphism): for instance, if K coerces to L then k+a
is the addition in L while if K does not coerce to L, k+a
produces an error. Only k*a
(implemented by a left action of K on L/K) uses the defining morphism.
I agree that it is really confusing but the same confusion appears exactly in the same way in the "theory". So I assume that people who really wants to work with algebras whose defining morphisms are not coercion maps are very aware of this source of confusion!
Why left action and not right action? Because usually scalars act on the left (for instance, we write 2x
and not x2
when x lies in some vector space). I nevertheless agree that this convention is not very strong. Another option would be to implement both actions (at some point I actually did this) but it then becomes impossible to multiply an element of K by an element of L without writing explicitly the conversion.
Probably the best solution would be to have a completely different operator for the action of the base through the defining morphism. But which one? Is it a good idea to override the dot operator?
Why doesn't
GF(9)
havefrom_base_ring
? What kind of Parent requires it?
I think (but I'm not quite sure) that it is used when no coercing map is set from self._base
to self
.
So it is something where established mathematical notation supports this directly? It's much more explicit to just write
A.scalar_restriction(Aother.ring())
, so I'd prefer not supportingA.scalar_restriction(Aother)
, except if a properly educated mathematician would be very surprised if this didn't exist.
I think that sometimes mathematicians may want to invoke A.scalar_restriction(Aother)
. For instance assume that we have an algebra A defined over C[X]. The fibre of A at the point x is by definition the scalar extension of A with respect to the morphism C[X] > C mapping X to x. (It is actually also A/(Xx), but sometimes we really want to think of it as a scalar extension.)
Actually we probably prefer to use the "base_change" in that case. So maybe we can implement two methods: first scalar_extension
which always uses coercion maps and second base_change
which accepts all constructions.
I think that implementing the action of scalars (through the defining morphism) is the least we can do.
What do you mean "is the least we can do"?
When we want to regard L as a Kalgebra, a basic thing we want to have is the action of K on L defining the algebra.
comment:11 followup: ↓ 12 Changed 2 years ago by
I just found this ticket and I only have a vague idea about what this ticket does. I am curious if the present ticket would solve or at least help one solve each of the following problems (of mine)? I believe that these cases are not supported by Sage yet.
 Suppose F is a nonprime finite field, say
GF(3^2)
. I want to construct an extension field E over F. SoE,phi=F.extension(4,map=True)
gives the extension fieldGF(3^8)
and the embedding phi. This currently only works for prime fields.
 Suppose K is a field and R is a subring of K. Suppose K is the fraction field of R. Let e be an element of K. Then
d=e.denominator(R)
gives a denominator of e in R such thatd*e.numerator(R)
is in R.
 Let E,F be rings. Suppose phi is a homomorphism from E to F. I want to extend phi to a homomorphism psi from the polynomial ring R=E[x] to F mapping x to c in F. Thus
psi(a2*x^2+a1*x+a0)==phi(a2)*c^2+phi(a1)*c+phi(a0)
. Perhaps I wantR.hom([c],F, base=phi)
or like to work.
comment:12 in reply to: ↑ 11 ; followup: ↓ 13 Changed 2 years ago by
Replying to klee:
 Suppose F is a nonprime finite field, say
GF(3^2)
. I want to construct an extension field E over F. SoE,phi=F.extension(4,map=True)
gives the extension fieldGF(3^8)
and the embedding phi. This currently only works for prime fields.
That currently works fine, just try it.
If you want to go from F
back to E
for any of the elements phi(E)
, use phi.section()
.
If you want to express F
as a vector space over E
, things are more limited. We implemented basic support for it in sage.coding.relative_finite_field_extension
. This ticket is about making that functionality much more general and thought out, and getting it into the core algebra of Sage.
 Suppose K is a field and R is a subring of K. Suppose K is the fraction field of R. Let e be an element of K. Then
d=e.denominator(R)
gives a denominator of e in R such thatd*e.numerator(R)
is in R.
That also currently works fine. I just tested with R = GF(3^2)['x']
:
sage: R = GF(3^2)['x'] sage: K = R.fraction_field() sage: e = K.random_element() sage: e.denominator() (z2 + 2)*x^2 + (z2 + 1)*x sage: e.denominator().parent() Univariate Polynomial Ring in x over Finite Field in z2 of size 3^2 sage: e.denominator() in R True sage: R( e.denominator() * e ) (2*z2 + 2)*x^2 + (z2 + 2)*x + z2
 Let E,F be rings. Suppose phi is a homomorphism from E to F. I want to extend phi to a homomorphism psi from the polynomial ring R=E[x] to F mapping x to c in F. Thus
psi(a2*x^2+a1*x+a0)==phi(a2)*c^2+phi(a1)*c+phi(a0)
. Perhaps I wantR.hom([c],F, base=phi)
or like to work.
That seems more tricky to do. Note that it can easily be split into the composition of two homomorphisms:
mapCoef: E[x] > F[x] a*x^i > phi(a)*x^i eval: F[x] > F x > c
The eval homomorphism can be created in the current Sage, but I don't know how to conveniently create mapCoef
(as a Morphism
object).
Best, Johan
comment:13 in reply to: ↑ 12 Changed 2 years ago by
Replying to jsrn:
Replying to klee:
 Suppose F is a nonprime finite field, say
GF(3^2)
. I want to construct an extension field E over F. SoE,phi=F.extension(4,map=True)
gives the extension fieldGF(3^8)
and the embedding phi. This currently only works for prime fields.That currently works fine, just try it.
If you want to go from
F
back toE
for any of the elementsphi(E)
, usephi.section()
.If you want to express
F
as a vector space overE
, things are more limited. We implemented basic support for it insage.coding.relative_finite_field_extension
. This ticket is about making that functionality much more general and thought out, and getting it into the core algebra of Sage.
Nice. Good luck!
comment:14 Changed 2 years ago by
The following reference might be useful for the design of the class:
Lattices of Compatibly Embedded Finite Fields  WIEB BOSMA, JOHN CANNON AND ALLAN STEEL 1997
as various extensions should be compatible to each other...
comment:15 Changed 2 years ago by
 Branch changed from u/caruso/21413/class_ring_extension to u/defeo/21413/class_ring_extension
comment:16 Changed 2 years ago by
 Commit changed from 036fb2a439cd9ee534d8e9489da02a3dde2452ea to 5c1c5b680fe08406fc6d34ccdddca13ee695ab78
Doctest failures:
sage t src/sage/rings/algebra_from_morphism.py ********************************************************************** File "src/sage/rings/algebra_from_morphism.py", line 260, in sage.rings.algebra_from_morphism.AlgebraFromMorphism._pushout_ Failed example: E2._pushout_(E1) is E2 Expected: True Got: False ********************************************************************** File "src/sage/rings/algebra_from_morphism.py", line 262, in sage.rings.algebra_from_morphism.AlgebraFromMorphism._pushout_ Failed example: E1._pushout_(E2) is E2 Expected: True Got: False ********************************************************************** File "src/sage/rings/algebra_from_morphism.py", line 265, in sage.rings.algebra_from_morphism.AlgebraFromMorphism._pushout_ Failed example: E1._pushout_(L2) is L2 Expected: True Got: False ********************************************************************** File "src/sage/rings/algebra_from_morphism.py", line 272, in sage.rings.algebra_from_morphism.AlgebraFromMorphism._pushout_ Failed example: E1p._pushout_(E2) is L2 Expected: True Got: False ********************************************************************** File "src/sage/rings/algebra_from_morphism.py", line 276, in sage.rings.algebra_from_morphism.AlgebraFromMorphism._pushout_ Failed example: E1p._pushout_(E2p) is L2 Expected: True Got: False ********************************************************************** 1 item had failures: 5 of 11 in sage.rings.algebra_from_morphism.AlgebraFromMorphism._pushout_ [119 tests, 5 failures, 0.86 s]  sage t src/sage/rings/algebra_from_morphism.py # 5 doctests failed  Total time for all tests: 0.9 seconds cpu time: 0.9 seconds cumulative wall time: 0.9 seconds
New commits:
5c1c5b6  Merge 7.6.beta2

comment:17 followup: ↓ 18 Changed 2 years ago by
Had you guys notice that there is this interface in Sage, which returns a mostly empty shell:
sage: K = GF(5^2) sage: L = GF(5^4) sage: E = L.algebra(K, category=Semigroups()) sage: E Free module generated by Finite Field in z4 of size 5^4 over Finite Field in z2 of size 5^2 sage: E.an_element() 2*B[0] + 2*B[z4] + 3*B[z4^2] sage: E.categories() [Category of finite dimensional semigroup algebras over Finite Field in z2 of size 5^2, Category of semigroup algebras over Finite Field in z2 of size 5^2, Category of associative algebras over Finite Field in z2 of size 5^2, Category of rngs, Category of associative additive commutative additive associative additive unital distributive magmas and additive magmas, Category of magma algebras over Finite Field in z2 of size 5^2, Category of magmatic algebras with basis over Finite Field in z2 of size 5^2, Category of magmatic algebras over Finite Field in z2 of size 5^2, Category of additive commutative additive associative additive unital distributive magmas and additive magmas, Category of additive commutative additive associative distributive magmas and additive magmas, Category of additive associative distributive magmas and additive magmas, Category of distributive magmas and additive magmas, Category of magmas and additive magmas, Category of finite semigroups, Category of semigroups, Category of magmas, Category of finite dimensional modules with basis over Finite Field in z2 of size 5^2, Category of set algebras over Finite Field in z2 of size 5^2, Category of vector spaces with basis over Finite Field in z2 of size 5^2, Category of modules with basis over Finite Field in z2 of size 5^2, Category of finite dimensional modules over Finite Field in z2 of size 5^2, Category of vector spaces over Finite Field in z2 of size 5^2, Category of modules over Finite Field in z2 of size 5^2, Category of bimodules over Finite Field in z2 of size 5^2 on the left and Finite Field in z2 of size 5^2 on the right, Category of right modules over Finite Field in z2 of size 5^2, Category of left modules over Finite Field in z2 of size 5^2, Category of commutative additive groups, Category of additive groups, Category of additive inverse additive unital additive magmas, Category of commutative additive monoids, Category of additive monoids, Category of additive unital additive magmas, Category of commutative additive semigroups, Category of additive commutative additive magmas, Category of additive semigroups, Category of additive magmas, Category of finite sets, Category of sets, Category of sets with partial maps, Category of objects]
comment:18 in reply to: ↑ 17 ; followup: ↓ 20 Changed 2 years ago by
Replying to defeo:
Had you guys notice that there is this interface in Sage, which returns a mostly empty shell:
In what sense would it be relevant for this ticket?
comment:19 followup: ↓ 21 Changed 2 years ago by
Hello, as you might have guessed, I'm trying to resurrect this ticket.
My biggest concern is the same as Johan's: I find k*a != a*k
very confusing for two reasons:
 It is silently not commutative;
 The parent of
a*k
is neitherA
norK
.
However I think the fix is simple: explicit is better than implicit, get rid of the coercion A > L
. I find the following idiom completely reasonable:
sage: K = GF(5^2); z2 = K.gen() sage: L = GF(5^4); z4 = L.gen() sage: A = RingExtension(L, K, K.frobenius_endomorphism()) sage: z2 * E(z4) 4*z4^3 + 3*z4^2 + 2*z4 + 2 sage: E(z4) * z2 TypeError: ... sage: L(E(z4)) * z2 z4^3 + 2*z4^2 + 4*z4 + 3
It could be useful if the left action was represented by an operator other than *
, however there is no acceptable operator in Python (.
cannot be overridden and @
(matmul) was only introduced in Python 3.5).
Or maybe just have the right action be the same as the left action, which apparently you already did.
comment:20 in reply to: ↑ 18 ; followup: ↓ 22 Changed 2 years ago by
Replying to SimonKing:
Replying to defeo:
Had you guys notice that there is this interface in Sage, which returns a mostly empty shell:
In what sense would it be relevant for this ticket?
At the very least, it is confusing that there is a method defined on L
whose name suggests it might return RingExtension(L, K)
, and it returns a completely unrelated object instead.
We had already discussed of various possible APIs for this, and L.algebra_over(K)
was one of those. I think Johan was in favour of this kind of API, rather than cluttering the namespace with yet another mysterious name RingExtension
. It would be quite confusing to have L.algebra()
and L.algebra_over()
.
comment:21 in reply to: ↑ 19 ; followup: ↓ 23 Changed 2 years ago by
Replying to defeo:
My biggest concern is the same as Johan's: I find
k*a != a*k
very confusing for two reasons:
 It is silently not commutative;
No problem, from my perspective. While "+" normally denotes a commutative operation in mathematics, "*" is generally not supposed to be commutative.
 The parent of
a*k
is neitherA
norK
.
Why would that be a problem? If a=x+2
is in ZZ[x]
and x=1/2
is in QQ
then a*x
neither is in ZZ[x]
nor in QQ
.
It could be useful if the left action was represented by an operator other than
*
, however there is no acceptable operator in Python (.
cannot be overridden and@
(matmul) was only introduced in Python 3.5).
Perhaps x>>a
and a<<x
?
Best regards, Simon
comment:22 in reply to: ↑ 20 ; followup: ↓ 24 Changed 2 years ago by
Replying to defeo:
At the very least, it is confusing that there is a method defined on
L
whose name suggests it might returnRingExtension(L, K)
, and it returns a completely unrelated object instead.
I would not expect L.algebra(K)
to return RingExtension(L,K)
but to return the K
algebra with basis L
whose multiplication is induced by the multiplication in L
(hence L
is only supposed to be a multiplicative monoid).
We had already discussed of various possible APIs for this, and
L.algebra_over(K)
was one of those. I think Johan was in favour of this kind of API, rather than cluttering the namespace with yet another mysterious nameRingExtension
.
I agree. When developing SageMath, we should avoid adding further stuff to the global namespace, whenever possible.
It would be quite confusing to have
L.algebra()
andL.algebra_over()
.
Perhaps a little variation: L.as_algebra_over(K)
. Or, changing perspective: L
is an extension of K
; so, L/K
should be returned by a method of K
, not by a method of L
. Say, K.extension(L)
.
comment:23 in reply to: ↑ 21 Changed 2 years ago by
Replying to SimonKing:
Replying to defeo:
My biggest concern is the same as Johan's: I find
k*a != a*k
very confusing for two reasons:
 It is silently not commutative;
No problem, from my perspective. While "+" normally denotes a commutative operation in mathematics, "*" is generally not supposed to be commutative.
I expect it to be associative, at least. With the proposed code (k*a)*k != k*(a*k)
.
 The parent of
a*k
is neitherA
norK
.Why would that be a problem? If
a=x+2
is inZZ[x]
andx=1/2
is ina*x
neither is inZZ[x]
nor in
I know the coercion system finds common parents, but in your example parent(a*x) == parent(x*a)
, and I expect the same here. I know there are exceptions even to this (e.g., matrices), but here we are talking about a commutative ring A
, so I expect *
to behave like its internal multiplication.
By a very common stretch of notation, I am glad to accept k*a
as a shorthand for phi(k)*a
, but I really don't see why a*k
should be a shorthand for L(a)*L(k)
. If we want such exotic semantics, then we should use another symbol than *
. See below
It could be useful if the left action was represented by an operator other than
*
, however there is no acceptable operator in Python (.
cannot be overridden and@
(matmul) was only introduced in Python 3.5).Perhaps
x>>a
anda<<x
?
That's quite ugly, but as I said, it would be the only sensible way to support such exotic semantics.
Let's keep in mind that 90% of Sage users are going to use this to work with field extensions of finite fields or number fields. They expect k*a
to mean "scalar multiplication of a
by k
", not to raise an exception.
The uses proposed by Xavier are certainly important, and it would be nice to support them, but I think those mathematicians who want to work with them should be ready to accept a slightly more explicit notation (an explicit conversion, or a different operator). If they really want to have k*a == a*k^p
, then they should use a dedicated class such as SkewPolynomialRing
.
comment:24 in reply to: ↑ 22 Changed 2 years ago by
Replying to SimonKing:
Replying to defeo:
At the very least, it is confusing that there is a method defined on
L
whose name suggests it might returnRingExtension(L, K)
, and it returns a completely unrelated object instead.I would not expect
L.algebra(K)
to returnRingExtension(L,K)
but to return theK
algebra with basisL
whose multiplication is induced by the multiplication inL
(henceL
is only supposed to be a multiplicative monoid).
I frankly don't know what I expect from L.algebra(K)
. I would run it, and see what comes out.
Perhaps a little variation:
L.as_algebra_over(K)
. Or, changing perspective:L
is an extension ofK
; so,L/K
should be returned by a method ofK
, not by a method ofL
. Say,K.extension(L)
.
We had already considered this possibility. The problem is that K.extension()
is already defined for most rings, and it returns a ring. It wouldn't break compatibility, but it would be a bit surprising if QQ.extension(x^2+1)
returned a number field, whereas QQ.extension(K)
returned an algebra object.
Of course, it could be K.extension_algebra(L)
.
comment:25 Changed 2 years ago by
 Cc saraedum added
comment:26 Changed 18 months ago by
I am just reading up on this ticket, it has quote a long discussion. Does it still really need info? If so could someone who knows what info put that in the ticket description?
comment:27 Changed 18 months ago by
The "info" the ticket needs is a few decisions on trickier points of the design. But perhaps what would be most useful is a concrete suggestion by updating the ticket's code. I would personally also really like to see how e.g. a finite field extension of #20284 would be instantiated in the current  quite abstract  proposal.
comment:28 Changed 18 months ago by
Yes I agree that is important to get the design right, especially since this touches something that touches quite a few areas of sage, since finite fields are far from the only place that one wants to consider relative extensions.
It is quite difficult for me to grasp what the "current proposal" is from the all the discussion that has been going on here. Or is the the one linked to in the description. I need this for something else as well so I plan to work on this.
What I think is that sage already has a class for relative extensions, and that class is called CommutativeAlgebra? from sage.rings.ring . The only problem is that right now that class is a dummy class which has almost nothing implemented yet.
So what I propose is the following, try to put as much general code as possible in CommutativeAlgebra? and set up a framework there that makes it easy later for concrete implementations of rings/fields to see themselves as Algebras over over other bases then their current base. And use this framework to make things work as follows:
sage: GF(81).vector_space() #note this already works Vector space of dimension 4 over Finite Field of size 3 sage: GF81_as_GF_9_algeba = Algebras(GF(9))(GF(81)) sage: GF81_as_GF_9_algeba.vector_space() Vector space of dimension 2 over Finite Field in z2 of size 3^2
For the more complicated cases where there is no coercion morphism yet we can try to make the following work
Algebras(GF(9))(GF(81), morphism=my_morhpism)
comment:29 Changed 18 months ago by
The main objection by @caruso, and the reason for the code he wrote, was that most on the interface, and some algorithms, can also be useful for noncommutative algebras.
He is especially interested in "skew algebras". Citing @caruso:
The point is that I really want to have algebras_from_morphisms_which_are_not_coercion_maps and I think that implementing the action of scalars (through the defining morphism) is the least we can do.
comment:30 Changed 6 months ago by
 Branch changed from u/defeo/21413/class_ring_extension to u/caruso/21413/class_ring_extension
comment:31 Changed 6 months ago by
 Commit changed from 5c1c5b680fe08406fc6d34ccdddca13ee695ab78 to 656ec777d4030fffa17a65f85c4cce87ca7d289e
Branch pushed to git repo; I updated commit sha1. New commits:
656ec77  Small fixes

Branch pushed to git repo; I updated commit sha1. New commits:
Coercion system improved