Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->1<!-- %% -->2<!-- %W arith.tex GAP manual Thomas Breuer -->3<!-- %% -->4<!-- %H @(#)<M>Id: arith.tex,v 4.4 2000/01/21 13:21:28 gap Exp </M> -->5<!-- %% -->67<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->8<Chapter Label="An Example -- Designing Arithmetic Operations">9<Heading>An Example – Designing Arithmetic Operations</Heading>1011In this chapter, we give a –hopefully typical–12example of extending &GAP; by new objects with prescribed13arithmetic operations (for a simple approach that may be useful14to get started though does not permit to exploit all potential15features, see also <Ref Func="ArithmeticElementCreator"/>).1617<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->18<Section Label="New Arithmetic Operations vs. New Objects">19<Heading>New Arithmetic Operations vs. New Objects</Heading>2021A usual procedure in mathematics is the definition of new operations for22given objects;23here are a few typical examples.24The Lie bracket defines an interesting new multiplicative25structure on a given (associative) algebra.26Forming a group ring can be viewed as defining a new addition for the27elements of the given group, and extending the multiplication to sums28of group elements in a natural way.29Forming the exterior algebra of a given vector space can be viewed as30defining a new multiplication for the vectors in a natural way.31<P/>32&GAP; does <E>not</E> support such a procedure.33The main reason for this is that in &GAP;, the multiplication in a group,34a ring etc. is always written as <C>*</C>,35and the addition in a vector space, a ring etc. is always written as <C>+</C>.36Therefore it is not possible to define the Lie bracket as a37<Q>second multiplication</Q> for the elements of a given algebra;38in fact, the multiplication in Lie algebras in &GAP; is denoted by <C>*</C>.39Analogously, constructing the group ring as sketched above is impossible40if an addition is already defined for the elements;41note the difference between the usual addition of matrices and the42addition in the group ring of a matrix group!43(See Chapter <Ref Chap="Magma Rings"/> for an example.)44Similarly, there is already a multiplication defined for row vectors45(yielding the standard scalar product), hence these vectors cannot be46regarded as elements of the exterior algebra of the space.47<P/>48In situations such as the ones mentioned above,49&GAP;'s way to deal with the structures in question is the following.50Instead of defining <E>new</E> operations for the <E>given</E> objects,51<E>new</E> objects are created to which the <E>given</E> arithmetic operations52<C>*</C> and <C>+</C> are then made applicable.53<P/>54With this construction, matrix Lie algebras consist of matrices that are55different from the matrices with associative multiplication;56technically, the type of a matrix determines how it is multiplied with57other matrices (see <Ref Func="IsMatrix"/>).58A matrix with the Lie bracket as its multiplication can be created with59the function <Ref Func="LieObject"/>60from a matrix with the usual associative multiplication.61<P/>62Group rings (more general: magma rings,63see Chapter <Ref Chap="Magma Rings"/>)64can be constructed with <Ref Func="FreeMagmaRing"/>65from a coefficient ring and a group.66The elements of the group are not contained in such a group ring,67one has to use an embedding map for creating a group ring element that68corresponds to a given group element.69<P/>70It should be noted that the &GAP; approach to the construction of71Lie algebras from associative algebras is generic in the sense72that all objects in the filter <Ref Filt="IsLieObject"/> use the73same methods for their addition, multiplication etc.,74by delegating to the <Q>underlying</Q> objects of the associative algebra,75no matter what these objects actually are.76Analogously, also the construction of group rings is generic.7778</Section>798081<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->82<Section Label="Designing new Multiplicative Objects">83<Heading>Designing new Multiplicative Objects</Heading>8485The goal of this section is to implement objects with a prescribed86multiplication.87Let us assume that we are given a field <M>F</M>,88and that we want to define a new multiplication <M>*</M> on <M>F</M>89that is given by <M>a * b = a b - a - b + 2</M>;90here <M>a b</M> denotes the ordinary product in <M>F</M>.91<P/>92By the discussion in Section <Ref Sect="New Arithmetic Operations vs. New Objects"/>,93we know that we cannot define a new multiplication on <M>F</M> itself94but have to create new objects.95<P/>96We want to distinguish these new objects from all other &GAP; objects,97in order to describe for example the situation that two of our objects98shall be multiplied.99This distinction is made via the <E>type</E> of the objects.100More precisely, we declare a new <E>filter</E>, a function that will return101<K>true</K> for our new objects, and <K>false</K> for all other &GAP; objects.102This can be done by calling <Ref Func="DeclareFilter"/>,103but since our objects will know about the value already when they are104constructed, the filter can be created with105<Ref Func="DeclareCategory"/> or <Ref Func="NewCategory"/>.106<P/>107<Log><![CDATA[108DeclareCategory( "IsMyObject", IsObject );109]]></Log>110<P/>111The idea is that the new multiplication will be installed only112for objects that <Q>lie in the category <C>IsMyObject</C></Q>.113<P/>114The next question is what internal data our new objects store,115and how they are accessed.116The easiest solution is to store the <Q>underlying</Q> object from the117field <M>F</M>.118&GAP; provides two general possibilities how to store this,119namely record-like and list-like structures120(for examples, see <Ref Sect="Component Objects"/> and <Ref Sect="Positional Objects"/>).121We decide to store the data in a list-like structure, at position 1.122This <E>representation</E> is declared as follows.123<P/>124<Log><![CDATA[125DeclareRepresentation( "IsMyObjectListRep", IsPositionalObjectRep, [ 1 ] );126]]></Log>127<P/>128Of course we can argue that this declaration is superfluous129because <E>all</E> objects in the category <C>IsMyObject</C> will be represented130this way;131it is possible to proceed like that,132but often (in more complicated situations) it turns out to be useful133that several representations are available for <Q>the same element</Q>.134<P/>135For creating the type of our objects, we need to specify to which <E>family</E>136(see <Ref Sect="Families"/>) the objects shall belong.137For the moment, we need not say anything about relations to other &GAP;138objects,139thus the only requirement is that all new objects lie in the <E>same</E> family;140therefore we create a <E>new</E> family.141Also we are not interested in properties that some of our objects have142and others do not have,143thus we need only one type,144and store it in a global variable.145<P/>146<Log><![CDATA[147MyType:= NewType( NewFamily( "MyFamily" ),148IsMyObject and IsMyObjectListRep );149]]></Log>150<P/>151The next step is to write a function that creates a new object.152It may look as follows.153<Log><![CDATA[154MyObject:= val -> Objectify( MyType, [ Immutable( val ) ] );155]]></Log>156Note that we store an <E>immutable copy</E> of the argument in the returned157object;158without doing so, for example if the argument would be a mutable matrix159then the corresponding new object would be changed whenever the matrix160is changed161(see <Ref Sect="Mutability and Copyability"/> for more162details about mutability).163<P/>164Having entered the above &GAP; code, we can create some of our objects.165<Log><![CDATA[166gap> a:= MyObject( 3 ); b:= MyObject( 5 );167<object>168<object>169gap> a![1]; b![1];17031715172]]></Log>173But clearly a lot is missing.174Besides the fact that the desired multiplication is not yet installed,175we see that also the way how the objects are printed is not satisfactory.176<P/>177Let us improve the latter first.178There are two &GAP; functions <Ref Func="View"/> and179<Ref Func="Print"/> for showing objects180on the screen.181<Ref Func="View"/> is thought to show a short and human182readable form of the object,183and <Ref Func="Print"/> is thought to show a not necessarily184short form that is &GAP; readable whenever this makes sense.185We decide to show <C>a</C> as <C><A>3</A></C> by186<Ref Func="View"/>, and to show the construction187<C>MyObject( 3 )</C> by <Ref Func="Print"/>;188the methods are installed for the underlying operations189<Ref Func="ViewObj"/> and190<Ref Func="PrintObj"/>.191<Log><![CDATA[192InstallMethod( ViewObj,193"for object in `IsMyObject'",194[ IsMyObject and IsMyObjectListRep ],195function( obj )196Print( "<", obj![1], ">" );197end );198199InstallMethod( PrintObj,200"for object in `IsMyObject'",201[ IsMyObject and IsMyObjectListRep ],202function( obj )203Print( "MyObject( ", obj![1], " )" );204end );205]]></Log>206<P/>207This is the result of the above installations.208<Log><![CDATA[209gap> a; Print( a, "\n" );210<3>211MyObject( 3 )212]]></Log>213<P/>214And now we try to install the multiplication.215<P/>216<Log><![CDATA[217InstallMethod( \*,218"for two objects in `IsMyObject'",219[ IsMyObject and IsMyObjectListRep,220IsMyObject and IsMyObjectListRep ],221function( a, b )222return MyObject( a![1] * b![1] - a![1] - b![1] + 2 );223end );224]]></Log>225<P/>226When we enter the above code, &GAP; runs into an error.227This is due to the fact that the operation <Ref Func="\*"/>228is declared for two arguments that lie in the category229<Ref Func="IsMultiplicativeElement"/>.230One could circumvent the check whether the method matches the231declaration of the operation, by calling <Ref Func="InstallOtherMethod"/>232instead of <Ref Func="InstallMethod"/>.233But it would make sense if our objects would lie in234<Ref Func="IsMultiplicativeElement"/>,235for example because some generic methods236for objects with multiplication would be available then,237such as powering by positive integers via repeated squaring.238So we want that <C>IsMyObject</C> implies239<Ref Func="IsMultiplicativeElement"/>.240The easiest way to achieve such implications is to use the241implied filter as second argument of the <Ref Func="DeclareCategory"/> call;242but since we do not want to start anew,243we can also install the implication afterwards.244<P/>245<Log><![CDATA[246InstallTrueMethod( IsMultiplicativeElement, IsMyObject );247]]></Log>248<P/>249Afterwards, installing the multiplication works without problems.250Note that <C>MyType</C> and therefore also <C>a</C> and <C>b</C> are <E>not</E>251affected by this implication, so we construct them anew.252<P/>253<Log><![CDATA[254gap> MyType:= NewType( NewFamily( "MyFamily" ),255> IsMyObject and IsMyObjectListRep );;256gap> a:= MyObject( 3 );; b:= MyObject( 5 );;257gap> a*b; a^27;258<9>259<134217729>260]]></Log>261<P/>262Powering the new objects by negative integers is not possible yet,263because &GAP; does not know how to compute the inverse of an element <M>a</M>,264say, which is defined as the unique element <M>a'</M> such that both265<M>a a'</M> and <M>a' a</M> are <Q>the unique multiplicative neutral266element that belongs to <M>a</M></Q>.267<P/>268And also this neutral element, if it exists,269cannot be computed by &GAP; in our current situation.270It does, however, make sense to ask for the multiplicative neutral271element of a given magma, and for inverses of elements in the magma.272<P/>273But before we can form domains of our objects,274we must define when two objects are regarded as equal;275note that this is necessary in order to decide about the uniqueness276of neutral and inverse elements.277In our situation, equality is defined in the obvious way.278For being able to form sets of our objects,279also an ordering via <Ref Func="\<"/> is defined for them.280<P/>281<Log><![CDATA[282InstallMethod( \=,283"for two objects in `IsMyObject'",284[ IsMyObject and IsMyObjectListRep,285IsMyObject and IsMyObjectListRep ],286function( a, b )287return a![1] = b![1];288end );289290InstallMethod( \<,291"for two objects in `IsMyObject'",292[ IsMyObject and IsMyObjectListRep,293IsMyObject and IsMyObjectListRep ],294function( a, b )295return a![1] < b![1];296end );297]]></Log>298<P/>299Let us look at an example.300We start with finite field elements because then the domains are finite,301hence the generic methods for such domains will have a chance to succeed.302<P/>303<Log><![CDATA[304gap> a:= MyObject( Z(7) );305<Z(7)>306gap> m:= Magma( a );307<magma with 1 generators>308gap> e:= MultiplicativeNeutralElement( m );309<Z(7)^2>310gap> elms:= AsList( m );311[ <Z(7)>, <Z(7)^2>, <Z(7)^5> ]312gap> ForAll( elms, x -> ForAny( elms, y -> x*y = e and y*x = e ) );313true314gap> List( elms, x -> First( elms, y -> x*y = e and y*x = e ) );315[ <Z(7)^5>, <Z(7)^2>, <Z(7)> ]316]]></Log>317<P/>318So a multiplicative neutral element exists,319in fact all elements in the magma <C>m</C> are invertible.320But what about the following.321<P/>322<Log><![CDATA[323gap> b:= MyObject( Z(7)^0 ); m:= Magma( a, b );324<Z(7)^0>325<magma with 2 generators>326gap> elms:= AsList( m );327[ <Z(7)^0>, <Z(7)>, <Z(7)^2>, <Z(7)^5> ]328gap> e:= MultiplicativeNeutralElement( m );329<Z(7)^2>330gap> ForAll( elms, x -> ForAny( elms, y -> x*y = e and y*x = e ) );331false332gap> List( elms, x -> b * x );333[ <Z(7)^0>, <Z(7)^0>, <Z(7)^0>, <Z(7)^0> ]334]]></Log>335<P/>336Here we found a multiplicative neutral element,337but the element <C>b</C> does not have an inverse.338If an addition would be defined for our elements then we would say339that <C>b</C> behaves like a zero element.340<P/>341When we started to implement the new objects,342we said that we wanted to define the new multiplication for elements343of a given field <M>F</M>.344In principle, the current implementation would admit also something345like <C>MyObject( 2 ) * MyObject( Z(7) )</C>.346But if we decide that our initial assumption holds,347we may define the identity and the inverse of the object <C><a></C> as348<C><2*e></C> and <C><a/(a-e)></C>, respectively,349where <C>e</C> is the identity element in <M>F</M> and <C>/</C> denotes the division350in <M>F</M>;351note that the element <C><e></C> is not invertible,352and that the above definitions are determined by the multiplication353defined for our objects.354Further note that after the installations shown below,355also <C>One( MyObject( 1 ) )</C> is defined.356<P/>357(For technical reasons, we do not install the intended methods for358the attributes <Ref Func="One"/> and359<Ref Func="Inverse"/> but for the operations360<Ref Func="OneOp"/>361and <Ref Func="InverseOp"/>.362This is because for certain kinds of objects –mainly matrices–363one wants to support a method to compute a <E>mutable</E> identity or364inverse, and the attribute needs only a method that takes this365object, makes it immutable, and then returns this object.366As stated above, we only want to deal with immutable objects,367so this distinction is not really interesting for us.)368<P/>369A more interesting point to note is that we should mark our objects370as likely to be invertible,371since we add the possibility to invert them.372Again, this could have been part of the declaration of <C>IsMyObject</C>,373but we may also formulate an implication for the existing category.374<P/>375<Log><![CDATA[376InstallTrueMethod( IsMultiplicativeElementWithInverse, IsMyObject );377378InstallMethod( OneOp,379"for an object in `IsMyObject'",380[ IsMyObject and IsMyObjectListRep ],381a -> MyObject( 2 * One( a![1] ) ) );382383InstallMethod( InverseOp,384"for an object in `IsMyObject'",385[ IsMyObject and IsMyObjectListRep ],386a -> MyObject( a![1] / ( a![1] - One( a![1] ) ) ) );387]]></Log>388Now we can form groups of our (nonzero) elements.389<Log><![CDATA[390gap> MyType:= NewType( NewFamily( "MyFamily" ),391> IsMyObject and IsMyObjectListRep );;392gap>393gap> a:= MyObject( Z(7) );394<Z(7)>395gap> b:= MyObject( 0*Z(7) ); g:= Group( a, b );396<0*Z(7)>397<group with 2 generators>398gap> Size( g );3996400]]></Log>401<P/>402We are completely free to define an <E>addition</E> for our elements,403a natural one is given by <C><a> + <b> = <a+b-1></C>.404As we did for the multiplication, we first change <C>IsMyObject</C>405such that the additive structure is also known.406<Log><![CDATA[407InstallTrueMethod( IsAdditiveElementWithInverse, IsMyObject );408]]></Log>409Next we install the methods for the addition,410and those to compute the additive neutral element411and the additive inverse.412<P/>413<Log><![CDATA[414InstallMethod( \+,415"for two objects in `IsMyObject'",416[ IsMyObject and IsMyObjectListRep,417IsMyObject and IsMyObjectListRep ],418function( a, b )419return MyObject( a![1] + b![1] - 1 );420end );421422InstallMethod( ZeroOp,423"for an object in `IsMyObject'",424[ IsMyObject and IsMyObjectListRep ],425a -> MyObject( One( a![1] ) ) );426427InstallMethod( AdditiveInverseOp,428"for an object in `IsMyObject'",429[ IsMyObject and IsMyObjectListRep ],430a -> MyObject( a![1] / ( a![1] - One( a![1] ) ) ) );431]]></Log>432<P/>433Let us try whether the addition works.434<P/>435<Log><![CDATA[436gap> MyType:= NewType( NewFamily( "MyFamily" ),437> IsMyObject and IsMyObjectListRep );;438gap> a:= MyObject( Z(7) );; b:= MyObject( 0*Z(7) );;439gap> m:= AdditiveMagma( a, b );440<additive magma with 2 generators>441gap> Size( m );4427443]]></Log>444<P/>445Similar as installing a multiplication automatically makes446powering by integers available,447multiplication with integers becomes available with the addition.448<P/>449<Log><![CDATA[450gap> 2 * a;451<Z(7)^5>452gap> a+a;453<Z(7)^5>454gap> MyObject( 2*Z(7)^0 ) * a;455<Z(7)>456]]></Log>457<P/>458In particular we see that this multiplication does <E>not</E> coincide459with the multiplication of two of our objects,460that is, an integer <E>cannot</E> be used as a shorthand for one of the461new objects in a multiplication.462<P/>463(It should be possible to create a <E>field</E> with the new multiplication464and addition.465Currently this fails, due to missing methods for computing466several kinds of generators from field generators,467for computing the characteristic in the case that the family does not468know this in advance,469for checking with <Ref Func="AsField"/> whether a domain470is in fact a field, for computing the closure as a field.)471<P/>472It should be emphasized that the mechanism described above may be not473suitable for the situation that one wants to consider many different474multiplications <Q>on the same set of objects</Q>,475since the installation of a new multiplication requires the declaration476of at least one new filter and the installation of several methods.477But the design of &GAP; is not suitable for such dynamic method478installations.479<P/>480Turning this argument the other way round,481the implementation of the new arithmetics defined by the above482multiplication and addition is available for any field <M>F</M>,483one need not repeat it for each field one is interested in.484<P/>485Similar to the above situation,486the construction of a magma ring <M>RM</M> from a coefficient ring <M>R</M>487and a magma <M>M</M> is implemented only once,488since the definition of the arithmetic operations depends only on the489given multiplication of <M>M</M> and not on <M>M</M> itself.490So the addition is not implemented for the elements in <M>M</M> or491–more precisely– for an isomorphic copy.492In some sense, the addition is installed <Q>for the multiplication</Q>,493and as mentioned in Section <Ref Sect="New Arithmetic Operations vs. New Objects"/>,494there is only one multiplication <Ref Func="\*"/> in &GAP;.495496</Section>497</Chapter>498499500<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->501<!-- %% -->502<!-- %E -->503504505506