-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENHANCE: Added RingWithOneByStructureConstants #5486
Conversation
5b46e37
to
d886bb4
Compare
lib/ringhom.gi
Outdated
@@ -557,18 +559,17 @@ function( R, I ) | |||
R2:=Range(hom); | |||
I:=Subring(R2,List(GeneratorsOfRing(I),x->Image(hom,x))); | |||
nat:=NaturalHomomorphismByIdeal(R2,I); | |||
return RingHomomorphismByImages(R,Range(nat),GeneratorsOfRing(R), | |||
List(GeneratorsOfRing(R),x->Image(nat,Image(hom,i)))); | |||
return RingHomomorphismByImages(R,Range(nat),Rgens, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps if this NaturalHomomorphismByIdeal
notices that IsRingWithOne(R)
is true, it could use this to make the quotient a ring-with-one, too, and set its one element?
lib/ringsc.gi
Outdated
A:= RingWithOneByGenerators( gens ); | ||
SetOne(A,one); | ||
else | ||
A:= RingByGenerators( gens ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So now we sometimes get a ring-with-one, and sometimes a ring, depending on a heuristic the user can not control; potentially changing the outcome of existing computations and tests?
This may work well in your concrete situation, but might it not cause problems in other situations that then are hard to compensate? I am worried we'll again see failing package tests and then someone has to waste time dealing with that.
How about instead adding an (optional?) argument that indicates whether the constructed ring should be a ring-with-one? Then the behaviour could be:
- if the argument is not given, or is set to `false, we construct a ring as before
- if the argument is given, and set to
true
, we use your heuristic, and produce an error if it fails - optional: if the argument is set to
"try"
, we do what your PR does right now (i.e. try to find a one, but if that fails, just go on) -- while I am surprised that this is useful, it clearly is to you, so we can of course support it - if the argument is set a "description of a ring element" (probably a vector relative to the base of the SC ring?), we assume that element is the identity element, and use that (possibly after validating it is an identity).
Wonder if @ChrisJefferson @ThomasBreuer have any thoughts about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the proposal right then the function RingByStructureConstants
shall decide whether its return value is a ring or ring-with-one, depending on some heuristics. An analogon in the world of multiplicative structures would be SemigroupByMultiplicationTable
returning sometimes a monoid and sometimes just a semigroup.
Do we really want this?
This looks to me like asking for trouble, from a conceptual point of view.
Why can't we just introduce RingWithOneByStructureConstants
, which takes the description of the identity element as a separate argument? In situations where one knows that the result should be regarded as a ring-with-one, one can call this function, and otherwise one first creates the ring and then asks for AsRingWithOne
--and if that is expected to be too expensive then one could introduce AsRingWithOneCheap
or so, which just checks some heuristics and gives up if this fails. (Note that the underlying family setup and element arithmetic of the original ring can be kept.)
There are similar situations in the GAP library which could be improved in the same direction:
Currently we do not have AlgebrawithOneByStructureConstants
and DivisionRingByStructureConstants
.
(There is an old comment in the function QuaternionAlgebra
that AlgebrawithOneByStructureConstants
would be useful, and I have code for that somewhere, but I admit that I never tried to add this to the GAP library.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An analogon in the world of multiplicative structures would be SemigroupByMultiplicationTable returning sometimes a monoid and sometimes just a semigroup.
I think the answer is "no, we don't want this", although it was probably me that introduced this behaviour in the first place (sorry!). The reason for doing so was that most users seem to expect IsMonoid
to return true
if the semigroup they've defined is mathematically a monoid, not whether it belongs to the category of monoids (in the gap sense). However, in retrospect, as has been said elsewhere in this thread, using a function like Semigroup
or SemigroupByMultiplicationTable
in other code is harder than it should be because some times it returns a semigroup and sometimes a monoid, and so the reasoning that goes in the calling code is more complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I never understood why WithOne
is not a property, but a separate category (but I also never understood why one would not adjoin an identity to semigroups if needed, so we only have monoids, so I might be missing a concept).
The main issue for allowing a ring with one if possible at all is that some functionality absolutely requires a ring in the WithOne category. The existing test is bad (I could not come up with a better one, though there surely must be), and the limit was just to avoid a calculation not terminating. We could put this instead behind an option (though I would prefer the option to skip the check, rather than trigger it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concerning the difference between Something
and SomethingWithOne
, the general idea is that different concepts of generation imply different categories in the sense of GAP's IsCategory
.
Here is a situation where one runs into difficulties if one does not keep the two concepts separate.
Consider the idempotent m:= [ [ 1, 0 ], [ 0, 0 ] ]
, a 2x2 matrix.
The algebra generated by m
is 1-dimensional, it has a multiplicative identity, but it does not contain the identity matrix m^0 = One( m )
.
The algebra-with-one generated by m
is 2-dimensional, it contains also m^0
.
Formally extending a semigroup or an algebra by an identity is no problem in theory, but in a concrete implementation one will in general create new objects and an embedding morphism.
What is the problem with explicitly calling RingWithOneByStructureConstants
if one needs a ring-with-one?
- One knows that there is an identity but one does not know which element it is, it is expensive to compute it, and in fact one does not really need this identity in the computations?
- Or one has a large number of rings, many of them contain an identity, and if one knows this then certain computations are much cheaper? (For example, the generic
RadicalOfAlgebra
method distinguishes the two situations.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is a situation where one runs into difficulties if one does not keep the two concepts separate.
Sure. RingByGenerators
or RingWithOneByGenerators
are different things. My puzzling goes towards making this part of the category of the created object, rather than a property. An object created as RingByGenerators
can never be a RingWithOne
, even if a One
is found.
What is the problem with explicitly calling RingWithOneByStructureConstants if one needs a ring-with-one?
The problem is basically that when starting to create rings through structure constants, one does not realize that one needs to make the ring explicitly a ring-with-one, so that basic functionality for matrices or polynomials works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relevant question on MSE:
https://math.stackexchange.com/questions/4756076/viewing-monoid-rings-as-rings-with-identity-in-gap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concerning the remark
My puzzling goes towards making this part of the category of the created object, rather than a property.
The relevant part of the GAP documentation is the section on Operational Structure of Domains, in particular the following sentence.
One important difference between the operational structure and the properties of a domain is that the operational structure is fixed when the domain is constructed, whereas properties can be discovered later.
For a domain D, having an identity (meaning that each element has an identity, it is the same identity for all elements in D, and this identity is an element of D) is regarded as part of the operational structure in the same way as having a multiplication on D or having inverses in D.
7b650f0
to
773a695
Compare
lib/ringsc.gi
Outdated
@@ -338,62 +338,61 @@ end ); | |||
## where `$c_{ijk}$ = <sctable>[i][j][1][i_k]' | |||
## and `<sctable>[i][j][2][i_k] = k'. | |||
## | |||
InstallGlobalFunction( RingByStructureConstants, function( arg ) | |||
BindGlobal("DoRingBySC",function(marg,oneinfo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW you could retain the name arg
instead of changing to marg
- it only has a special meaning when it is the sole argument to the function.
lib/ringsc.gi
Outdated
or (IsList(e) and IsList(e[1]) and IsList(e[1][1])) then | ||
e:=true; # no extra argument for one given -- force search | ||
else | ||
m:=m{[1..Length(m)-1]}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly more efficient would be this (but of course it doesn't matter here)
m:=m{[1..Length(m)-1]}; | |
Remove(m); |
lib/ringsc.gd
Outdated
@@ -47,11 +48,15 @@ DeclareSynonym("IsSubringSCRing",IsRing and IsSCRingObjCollection); | |||
## it can be either a string <A>name</A> | |||
## (then <A>name</A><C>1</C>, <A>name</A><C>2</C> etc. are chosen) | |||
## or a list of strings which are then chosen. | |||
## In the case of <C>RingWithOneByStructureConstants</C> the last argument | |||
## can be a vector describign the one element, or <C>true</C>, in which |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
## can be a vector describign the one element, or <C>true</C>, in which | |
## can be a vector describing the one element, or <C>true</C>, in which |
lib/ringsc.gd
Outdated
@@ -47,11 +48,15 @@ DeclareSynonym("IsSubringSCRing",IsRing and IsSCRingObjCollection); | |||
## it can be either a string <A>name</A> | |||
## (then <A>name</A><C>1</C>, <A>name</A><C>2</C> etc. are chosen) | |||
## or a list of strings which are then chosen. | |||
## In the case of <C>RingWithOneByStructureConstants</C> the last argument | |||
## can be a vector describign the one element, or <C>true</C>, in which | |||
## case the code searches for the one element. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds as if it was absolute, but in reality, the code just tries to find a one element; but it still may fail (as in the previous version of the PR), and then it just returns a ring, not a ring-with-one; and we are back to the problem that now this may sometimes do one thing and sometimes another...
lib/ringsc.gi
Outdated
repeat | ||
Add(A,new); | ||
new:=new*gens[i]; | ||
until new in A; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this be an infinite loop if gens[i]
has infinite order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if the order is finite but large, we store the huge list A
, when we only need the last item in the cases we care about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the whole list (to find a loop. Of course one could use the idea of Pollard rho to avoid the list.
It is a very basic implementation that can handle the cases of smallish rings (which is all I needed for the time being), and I hope will at some point be replaced with a better method (solving equations).
lib/ringsc.gi
Outdated
|
||
if one=fail then | ||
# if not too big go through elements | ||
if Product(moduli)<=10^5 then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meta question, out of curiosity, but: finding a unit element amounts to solving a linear system of equations over the integers (complicated a bit by the fact that we have these moduli in place). Why don't we just solve this?
(This is a honest question, not a veiled request/suggestion: I merely wonder if you tried this and it has problems; or if you decided to not do it to quickly get something working, even if incomplete. I am certainly not "demanding" that this be implemented in this PR; though it might be a good idea to add a comment suggesting that the general case could also be dealt with, if someone has need for it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I thought about it (and thus did not worry too much about the efficiency of the current horrible method), but it will be congruences with (potentially) different, nonprime moduli, and I did not have a read-made algorithm at hand, nor wante dto hack up a "quick" solution that likely would contain errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK makes sense
folowing complaints, now changed to adding
RingWithOneBySC
without adding too much code duplication