Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

hulpke
Copy link
Contributor

@hulpke hulpke commented Aug 12, 2023

folowing complaints, now changed to adding RingWithOneBySC without adding too much code duplication

@hulpke hulpke added kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements release notes: not needed PRs introducing changes that are wholly irrelevant to the release notes labels Aug 12, 2023
@hulpke hulpke force-pushed the testbed branch 2 times, most recently from 5b46e37 to d886bb4 Compare August 13, 2023 00:39
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,
Copy link
Member

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 );
Copy link
Member

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?

Copy link
Contributor

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

Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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.

@hulpke hulpke force-pushed the testbed branch 2 times, most recently from 7b650f0 to 773a695 Compare August 22, 2023 17:31
@hulpke hulpke changed the title ENHANCE: Try to generate SCRings as Ring-with-one ENHANCE: Asses RingWithOneByStructureConstants Aug 22, 2023
@hulpke hulpke changed the title ENHANCE: Asses RingWithOneByStructureConstants ENHANCE: Added RingWithOneByStructureConstants Aug 22, 2023
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)
Copy link
Member

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]};
Copy link
Member

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)

Suggested change
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## 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.
Copy link
Member

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;
Copy link
Member

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?

Copy link
Member

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.

Copy link
Contributor Author

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
Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK makes sense

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements release notes: not needed PRs introducing changes that are wholly irrelevant to the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants