<Chapter Label="Funct">
<Heading>&Circle; functions</Heading>

To use the &Circle; package first you need to load it as follows:

<Log>
<![CDATA[
gap> LoadPackage("circle");
-----------------------------------------------------------------------------
Loading  Circle 1.6.5 (Adjoint groups of finite rings)
by Olexandr Konovalov (https://alex-konovalov.github.io/) and
   Panagiotis Soules (psoules@math.uoa.gr).
maintained by:
   Olexandr Konovalov (https://alex-konovalov.github.io/).
Homepage: https://gap-packages.github.io/circle
Report issues at https://github.com/gap-packages/circle/issues
-----------------------------------------------------------------------------
true
gap>
]]>
</Log>

Note that if you entered examples from the previous chapter, you need
to restart &GAP; before loading the &Circle; package.


<Section Label="CircleObjects">
<Heading>Circle objects</Heading>

Because for elements of the ring <M>R</M> the ordinary multiplication
is already denoted by <C>*</C>, for the implementation of the circle
multiplication in the adjoint semigroup we need to wrap up ring 
elements as CircleObjects, for which <C>*</C> is defined to be the 
circle multiplication.

<ManSection>
   <Attr Name="CircleObject" 
         Arg="x" />
<Description>	      
Let <A>x</A> be a ring element. Then <C>CircleObject(x)</C> returns the
corresponding circle object. If <A>x</A> lies in the family <C>fam</C>,
then <C>CircleObject(x)</C> lies in the family <Ref Fam="CircleFamily"/>,
corresponding to the family <C>fam</C>.

<Example>
<![CDATA[
gap> a := CircleObject( 2 );
CircleObject( 2 )
]]>
</Example>

</Description>        
</ManSection>


<ManSection>
   <Attr Name="UnderlyingRingElement" 
         Arg="x" />
<Description>	      
Returns the corresponding ring element for the circle object <A>x</A>.
<Example>
<![CDATA[
gap> a := CircleObject( 2 );
CircleObject( 2 )
gap> UnderlyingRingElement( a );    
2
]]>
</Example>

</Description>        
</ManSection>


<ManSection>
   <Filt Name="IsCircleObject" 
         Arg="x" 
         Type="Category" />
   <Filt Name="IsCircleObjectCollection" 
         Arg="x" 
         Type="Category" />  
<Description>	      
An object <A>x</A> lies in the category <C>IsCircleObject</C> if and
only if it lies in a family constructed by <Ref Attr="CircleFamily"/>. 
Since circle objects can be multiplied via <C>*</C> with elements in 
their family, and we need operations <C>One</C> and <C>Inverse</C> to 
deal with groups they generate, circle objects are implemented in the 
category <C>IsMultiplicativeElementWithInverse</C>. A collection of 
circle objects (e.g. adjoint semigroup or adjoint group) will lie in 
the category <C>IsCircleObjectCollection</C>.
  
<Example>
<![CDATA[
gap> IsCircleObject( 2 ); IsCircleObject( CircleObject( 2 ) );            
false
true
gap> IsMultiplicativeElementWithInverse( CircleObject( 2 ) );
true
gap> IsCircleObjectCollection( [ CircleObject(0), CircleObject(2) ] );
true
]]>
</Example>

</Description> 
</ManSection>

<ManSection>
   <Filt Name="IsPositionalObjectOneSlotRep" 
         Arg="x" 
         Type="Representation" />
   <Filt Name="IsDefaultCircleObject" 
         Arg="x" 
         Type="Representation" />         
<Description>
To store the corresponding circle object, we need only to store the 
underlying ring element. Since this is quite common situation, we 
defined the representation <C>IsPositionalObjectOneSlotRep</C> for a 
more general case. Then we defined <C>IsDefaultCircleObject</C> as a
synonym of <C>IsPositionalObjectOneSlotRep</C> for objects in 
<Ref Filt="IsCircleObject" />.

<Example>
<![CDATA[
gap> IsPositionalObjectOneSlotRep( CircleObject( 2 ) );
true
gap> IsDefaultCircleObject( CircleObject( 2 ) );                          
true
]]>
</Example>

</Description>              
</ManSection>

<ManSection>
   <Attr Name="CircleFamily"
         Arg="fam" />
<Description>    
<C>CircleFamily(fam)</C> is a family, elements of which are in one-to-one
correspondence with elements of the family <A>fam</A>,
but with the circle multiplication as an infix multiplication.
That is, for <M>x</M>, <M>y</M> in <A>fam</A>, the product of their images 
in the <C>CircleFamily(fam)</C> will be the image of <M> x + y + x y </M>.
The relation between these families is demonstrated by the following equality:

<Example>
<![CDATA[
gap> FamilyObj( CircleObject ( 2 ) ) = CircleFamily( FamilyObj( 2 ) );
true
]]>
</Example>

</Description> 
</ManSection>

</Section>

<Section Label="CircleOperations">
<Heading>Operations with circle objects</Heading>
 
<ManSection>
   <Oper Name="One" 
         Arg="x" />
<Description>	      
This operation returns the multiplicative neutral element 
for the circle object <A>x</A>. The result is the circle 
object corresponding to the additive neutral element of 
the appropriate ring. 

<Example>
<![CDATA[
gap> One( CircleObject( 5 ) );
CircleObject( 0 )
gap> One( CircleObject( 5 ) ) = CircleObject( Zero( 5 ) );
true
gap> One( CircleObject( [ [ 1, 1 ],[ 0, 1 ] ] ) );
CircleObject( [ [ 0, 0 ], [ 0, 0 ] ] )
]]>
</Example>

</Description>        
</ManSection>


<ManSection>
   <Oper Name="InverseOp" 
         Arg="x" />
<Description>	      
For a circle object <A>x</A>, returns the multiplicative 
inverse of <A>x</A> with respect to the circle multiplication; 
if such one does not exist then <K>fail</K> is returned.<P/>

In our implementation we assume that the underlying ring is a 
subring of the ring with one, thus, if the circle inverse for 
an element <M>x</M> exists, than it can be computed as <M>-x(1+x)^{-1}</M>.

<Example>
<![CDATA[
gap> CircleObject( -2 )^-1;                        
CircleObject( -2 )
gap> CircleObject( 2 )^-1; 
CircleObject( -2/3 )
gap> CircleObject( -2 )*CircleObject( -2 )^-1;
CircleObject( 0 )
]]>
</Example>

<Example>
<![CDATA[
gap> m := CircleObject( [ [ 1, 1 ], [ 0, 1 ] ] );   
CircleObject( [ [ 1, 1 ], [ 0, 1 ] ] )
gap> m^-1;    
CircleObject( [ [ -1/2, -1/4 ], [ 0, -1/2 ] ] )
gap> m * m^-1;
CircleObject( [ [ 0, 0 ], [ 0, 0 ] ] )
gap> CircleObject( [ [ 0, 1 ], [ 1, 0 ] ] )^-1; 
fail
]]>
</Example>

</Description>        
</ManSection>


<ManSection>
   <Oper Name="IsUnit" 
         Arg="[ R, ] x" />
<Description>
Let <A>x</A> be a circle object corresponding to an element of 
the ring <A>R</A>. Then the operation <C>IsUnit</C> returns 
<C>true</C>, if <A>x</A> is invertible in <A>R</A> with respect
to the circle multiplication, and <C>false</C> otherwise.

<Example>
<![CDATA[
gap> IsUnit( Integers, CircleObject( -2 ) );
true
gap> IsUnit( Integers, CircleObject( 2 ) ); 
false
gap> IsUnit( Rationals, CircleObject( 2 ) );        
true
gap> IsUnit( ZmodnZ(8), CircleObject( ZmodnZObj(2,8) ) );
true
gap> m := CircleObject( [ [ 1, 1 ],[ 0, 1 ] ] );;
gap> IsUnit( FullMatrixAlgebra( Rationals, 2 ), m );
true
]]>
</Example>



If the first argument is omitted, the result will be returned with respect
to the default ring of the circle object <A>x</A>.

<Example>
<![CDATA[
gap> IsUnit( CircleObject( -2 ) );
true
gap> IsUnit( CircleObject( 2 ) ); 
false
gap> IsUnit( CircleObject( ZmodnZObj(2,8) ) );
true
gap> IsUnit( CircleObject( [ [ 1, 1 ],[ 0, 1 ] ] ) );                                    
false
]]>
</Example>

</Description>              
</ManSection>


<ManSection>
   <Oper Name="IsCircleUnit" 
         Arg="[ R, ] x" />
<Description>
Let <A>x</A> be an element of the ring <A>R</A>. Then 
<C>IsCircleUnit( R, x )</C> determines whether <A>x</A> is invertible
in <A>R</A> with respect to the circle multilpication. This is 
equivalent to the condition that 1+<A>x</A> is a unit in <A>R</A> 
with respect to the ordinary multiplication. 

<Example>
<![CDATA[
gap> IsCircleUnit( Integers, -2 );
true
gap> IsCircleUnit( Integers, 2 ); 
false
gap> IsCircleUnit( Rationals, 2 );          
true
gap> IsCircleUnit( ZmodnZ(8), ZmodnZObj(2,8) ); 
true
gap> m := [ [ 1, 1 ],[ 0, 1 ] ];                
[ [ 1, 1 ], [ 0, 1 ] ]
gap> IsCircleUnit( FullMatrixAlgebra(Rationals,2), m );
true
]]>
</Example>

If the first argument is omitted, the result will be returned with respect
to the default ring of <A>x</A>.

<Example>
<![CDATA[
gap> IsCircleUnit( -2 );                               
true
gap> IsCircleUnit( 2 ); 
false
gap> IsCircleUnit( ZmodnZObj(2,8) );           
true
gap> IsCircleUnit( [ [ 1, 1 ],[ 0, 1 ] ] ); 
false
]]>
</Example>

</Description>              
</ManSection>

</Section>


<Section Label="CircleAdjointGroups">
<Heading>Construction of the adjoint semigroup and adjoint group</Heading>

<ManSection>
   <Attr Name="AdjointSemigroup" 
         Arg="R" />
<Description>
If <A>R</A> is a finite ring then <C>AdjointSemigroup(<A>R</A>)</C> will 
return the monoid which is formed by all elements of <A>R</A> with
respect to the circle multiplication.
<P/>

The implementation is rather straightforward and was added to provide a 
link to the &GAP; functionality for semigroups. It assumes that the
enumaration of all elements of the ring <A>R</A> is feasible.

<Example>
<![CDATA[
gap> R:=Ring( [ ZmodnZObj(2,8) ] );;
gap> S:=AdjointSemigroup(R);
<monoid with 4 generators>
]]>
</Example>

</Description> 

</ManSection>


<ManSection>
   <Attr Name="AdjointGroup" 
         Arg="R" />
<Description>
If <A>R</A> is a finite radical algebra then 
<C>AdjointGroup(<A>R</A>)</C> will return the adjoint group 
of <A>R</A>, given as a group generated by a set of circle objects.
<P/> 

To compute the adjoint group of a finite radical algebra,
&Circle; uses the fact that all elements of a radical algebra 
form a group with respect to the circle multiplication. Thus,
the adjoint group of <A>R</A> coincides with <A>R</A> elementwise,
and we can randomly select an appropriate set of generators for
the adjoint group. 
<P/>

The warning is displayed by <C>IsGeneratorsOfMagmaWithInverses</C>
method defined in <File>gap4r4/lib/grp.gi</File> and may be ignored.
<P/>

<B>WARNINGS:</B>
<P/>

1. The set of generators of the returned group is not required 
to be a generating set of minimal possible order.
<P/>

2. <C>AdjointGroup</C> is stored as an attribute of <A>R</A>, 
so for the same copy of <A>R</A> calling it again you will get 
the same result. But if you will create another copy of <A>R</A>
in the future, the output may differ because of the random 
selection of generators. If you want to have the same generating
set, next time you should construct a group immediately specifying
circle objects that generate it.
<P/>

3. In most cases, to investigate some properties of the adjoint 
group, it is necessary first to convert it to an isomorphic 
permutation group or to a PcGroup.
<P/>

For example, we can create the following commutative 2-dimensional
radical algebra of order 4 over the field of two elements, 
and show that its adjoint group is a cyclic group of order 4:

<Example>
<![CDATA[
gap> x:=[ [ 0, 1, 0 ],
>         [ 0, 0, 1 ],
>         [ 0, 0, 0 ] ];;
gap> R := Algebra( GF(2), [ One(GF(2))*x ] );;
gap> RadicalOfAlgebra( R ) = R;
true
gap> Dimension(R);
2
gap> G := AdjointGroup( R );;
gap> Size( R ) = Size( G );
true
gap> StructureDescription( G );
"C4"
]]>
</Example>

In the following example we construct a non-commutative 
3-dimensional radical algebra of order 8 over the field 
of two elements, and demonstrate that its adjoint group 
is the dihedral group of order 8:

<Alt Only="LaTeX">\pagebreak</Alt>

<Example>
<![CDATA[
gap> x:=[ [ 0, 1, 0 ],
>         [ 0, 0, 0 ],     
>         [ 0, 0, 0 ] ];;
gap> y:=[ [ 0, 0, 0 ],     
>         [ 0, 0, 1 ],  
>         [ 0, 0, 0 ] ];;
gap> R := Algebra( GF(2), One(GF(2))*[x,y] );  
<algebra over GF(2), with 2 generators>
gap> RadicalOfAlgebra(R) = R;                
true
gap> Dimension(R);
3
gap> G := AdjointGroup( R );
<group of size 8 with 2 generators>
gap> StructureDescription( G );
"D8"
]]>
</Example>

If the ring <A>R</A> is not a radical algebra, 
then &Circle; will use another approach. We will enumerate 
all elements of the ring <A>R</A> and select those that are units with 
respect to the circle multiplication.
Then we will use a random approach similar to the case of the radical
algebra, to find some generating set of the adjoint group. Again, all 
warnings 1-3 above refer also to this case. 
<P/>

Of course, enumeration of all elements of <A>R</A> should be feasible
for this computation.
In the following example we demonstrate how it works for rings, 
generated by residue classes:

<Example>
<![CDATA[
gap> R := Ring( [ ZmodnZObj(2,8) ] );;
gap> G := AdjointGroup( R );
<group of size 4 with 2 generators>
gap> StructureDescription( G );
"C2 x C2"
gap> R := Ring( [ ZmodnZObj(2,256) ] );;
gap> G := AdjointGroup( R );;
gap> StructureDescription( G );
"C64 x C2"
]]>
</Example>

Due to the <Ref Attr="AdjointSemigroup" />, there is also another way to 
compute the adjoint group of a ring <M>R</M> by means of the computation of its
adjoint semigroup <M>S(R)</M> and taking the Green's <M>H</M>-class of the 
multiplicative neutral element of <M>S(R)</M>. Let us repeat the last example
in this way:

<Example>
<![CDATA[
gap> R := Ring( [ ZmodnZObj(2,256) ] );; 
gap> S := AdjointSemigroup( R );
<monoid with 128 generators>
gap> H := GreensHClassOfElement(S,One(S));
<Green's H-class: <object>>
gap> G:=AsGroup(H);
<group of size 128 with 2 generators>
gap> StructureDescription(G);
"C64 x C2"
]]>
</Example>

However, the conversion of the Green's <M>H</M>-class to the group may take
some time which may vary dependently on the particular ring in question, and
will also display a lot of warnings about the default 
<C>IsGeneratorsOfMagmaWithInverses</C> method, so we did not implemented 
this as as standard method. In the following example the method based on
Green's <M>H</M>-class is much slower than an application of
earlier described random approach (20s vs 10ms):

<Example>
<![CDATA[
gap> R := Ring( [ ZmodnZObj(2,256) ] );;
gap> AdjointGroup(R);;
gap> R := Ring( [ ZmodnZObj(2,256) ] );;
gap> S:=AdjointSemigroup(R); 
<monoid with 128 generators>
gap> AsGroup(GreensHClassOfElement(S,One(S))); 
<group of size 128 with 2 generators>
]]>
</Example>
  

Finally, note that if <A>R</A> has a unity <M>1</M>, then the set <M>1+R^{ad}</M>, 
where <M>R^{ad}</M> is the adjoint semigroup of <A>R</A>, coincides
with the multiplicative semigroup <M>R^{mult}</M> of <M>R</M>, and the map 
<M> r \mapsto (1+r) </M> for <M>r</M> in <M>R</M> is an isomorphism 
from <M>R^{ad}</M> onto <M>R^{mult}</M>. 
<P/>

Similarly, the set <M>1+R^*</M>, where <M>R^{*}</M> is the adjoint 
group of <A>R</A>, coincides with the unit group of <M>R</M>, 
which we denote <M>U(R)</M>, and the map <M>r \mapsto (1+r)</M> 
for <M>r</M> in <M>R</M> is an isomorphism from <M>R^*</M> onto 
<M>U(R)</M>.
<P/>

We demonstrate this isomorphism using the following example. 

<Example>
<![CDATA[
gap> LoadPackage( "laguna", false );
true
gap> FG := GroupRing( GF(2), DihedralGroup(8) );
<algebra-with-one over GF(2), with 3 generators>
gap> R := AugmentationIdeal( FG );;
gap> G := AdjointGroup( R );;
gap> IdGroup( G );
[ 128, 170 ]
gap> IdGroup( Units( FG ) );
#I  LAGUNA package: Computing the unit group ...
[ 128, 170 ]
]]>
</Example>

Thus, dependently on the ring <C>R</C> in question, it might be possible 
that you can compute much faster its unit group using <C>Units(R)</C> than
its adjoint group using <C>AdjointGroup(R)</C>. This is why in an attempt
of computation of the adjoint group of the ring with one a warning message
will be displayed:
<P/>

<Example>
<![CDATA[
gap> Size( AdjointGroup( GroupRing( GF(2), DihedralGroup(8) ) ) );

WARNING: usage of AdjointGroup for associative ring <R> with one!!! 
In this case the adjoint group is isomorphic to the unit group 
Units(<R>), which possibly may be computed faster!!! 

128
gap> Size( AdjointGroup( Integers mod 11 ) );                  

WARNING: usage of AdjointGroup for associative ring <R> with one!!! 
In this case the adjoint group is isomorphic to the unit group 
Units(<R>), which possibly may be computed faster!!! 

10
]]>
</Example>

If <A>R</A> is infinite, an error message will appear,
telling that &Circle; does not provide methods to deal
with infinite rings.

</Description>              
</ManSection>
  
</Section>


<!-- ######################################################### -->

<Section Label="Service">
<Heading>Service functions</Heading>


<ManSection>
   <InfoClass Name="InfoCircle" />
<Description>
<C>InfoCircle</C> is a special Info class for &Circle; algorithms.
It has 2 levels: 0 (default) and 1. To change info level to 
<C>k</C>, use command <C>SetInfoLevel(InfoCircle, k)</C>. 

<Example>
<![CDATA[
gap> SetInfoLevel( InfoCircle, 1 );
gap> SetInfoLevel(InfoCircle,1);
gap> R := Ring( [ ZmodnZObj(2,8) ]);;
gap> G := AdjointGroup( R );
#I  Circle : <R> is not a radical algebra, computing circle units ...
#I  Circle : searching generators for adjoint group ...
<group of size 4 with 2 generators>
gap> SetInfoLevel( InfoCircle, 0 );
]]>
</Example>

</Description>
</ManSection>

</Section>

</Chapter>