Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/groupoids/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 11.8.2025 mit Größe 55 kB image not shown  

Quelle  mwohom.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

############################################################################
##
#W  mwohom.gi              GAP4 package `groupoids'            Chris Wensley
#W                                                              & Emma Moore
##  
##  This file contains generic methods for mappings of magmas with objects

#############################################################################
##  Standard error messages

MAGMA_HOMOMORPHISM_CONSTRUCTORS := Concatenation(
    "The standard operations which construct a magma mapping are:\n",
    "1.  HomomorphismFromSinglePiece( src, rng, hom, imobs );\n", 
    "2.  HomomorphismToSinglePiece( src, rng, list of [hom,imobs]'s );\n",
    "3.  HomomorphismByUnion( src, rng, list of disjoint mappings );\n", 
    "4.  MagmaWithObjectsHomomorphism( one of previous parameter options );" );

#############################################################################
##
#F  MagmaWithObjectsHomomorphism(<g1>,<g2>,<maps>)          union of mappings 
#F  MagmaWithObjectsHomomorphism(<g1>,<g2>,<piece images>) single piece range 
#F  MagmaWithObjectsHomomorphism(<g1>,<g2>,<hom>,<imobs>)    connected source 
##
InstallGlobalFunction( MagmaWithObjectsHomomorphism, function( arg )

    local nargs, id, rays; 

    nargs := Length( arg );
    if ( ( nargs < 3 ) or not IsMagmaWithObjects( arg[1] ) or 
         ( nargs > 4 ) or not IsMagmaWithObjects( arg[2] ) ) then 
        Info( InfoGroupoids, 1, MAGMA_HOMOMORPHISM_CONSTRUCTORS );
        return fail;
    fi;
    # mwo, mwo, magma mapping, object images
    if ( ( nargs = 4 ) and IsSinglePiece( arg[1] ) 
                       and IsMagmaHomomorphism( arg[3] ) 
                       and IsHomogeneousList( arg[4] ) ) then 
        Info( InfoGroupoids, 2, "HomomorphismFromSinglePiece" );
        return HomomorphismFromSinglePiece(arg[1],arg[2],arg[3],arg[4]); 
    # mwo, mwo, list of mappings
    elif ( ( nargs = 3 ) and IsHomogeneousList( arg[3] ) 
            and IsMagmaWithObjectsHomomorphism( arg[3][1] ) ) then
        Info( InfoGroupoids, 2, "HomomorphismByUnion" );
        return HomomorphismByUnion( arg[1], arg[2], arg[3] );
    # mwo, mwo, list of [mapping,[images of objects]] pairs
    elif ( ( nargs = 3 ) and IsHomogeneousList( arg[3] ) 
           and IsList( arg[3][1] ) and IsList( arg[3][1][1] ) ) then 
        Info( InfoGroupoids, 2, "HomomorphismToSinglePiece" );
        return HomomorphismToSinglePiece( arg[1], arg[2], arg[3] );
    else
        Info( InfoGroupoids, 1, MAGMA_HOMOMORPHISM_CONSTRUCTORS );
        return fail;
    fi;
end );

#############################################################################
##
#M  MappingWithObjectsByFunction 
##
InstallMethod( MappingWithObjectsByFunction,
    "generic method for a mapping by function of connected magmas", true,
    [ IsMagmaWithObjects, IsMagmaWithObjects, IsFunction, IsHomogeneousList ], 
    0,
function( m1, m2, fun, imo )

    local map, ok;

    map := rec(); 
    ObjectifyWithAttributes( map, IsMWOMappingToSinglePieceType, 
        Source, m1, 
        Range, m2, 
        UnderlyingFunction, fun, 
        ImagesOfObjects, imo,   
        RespectsMultiplication, true, 
        IsGeneralMappingToSinglePiece, true, 
        IsMappingWithObjectsByFunction, true );
    return map; 
end );

#############################################################################
##
#M  HomomorphismFromSinglePieceNC 
#M  HomomorphismFromSinglePiece 
##
InstallMethod( HomomorphismFromSinglePieceNC,
    "generic method for a mapping of connected magmas", true,
    [ IsSinglePiece, IsSinglePiece, IsMagmaHomomorphism, IsHomogeneousList ], 
    0,
function( m1, m2, hom, imo )
    return HomomorphismToSinglePieceNC( m1, m2, [ [ hom, imo ] ] );
end );

InstallMethod( HomomorphismFromSinglePiece,
    "generic method for a mapping of connected magmas", true,
    [ IsSinglePiece, IsSinglePiece, IsMagmaHomomorphism, IsHomogeneousList ], 
    0,
function( m1, m2, hom, imo )

    local o1, o2, no2, mag1, mag2;

    Info( InfoGroupoids, 3, "homomorphism from single piece magma" ); 
    o1 := m1!.objects;
    o2 := m2!.objects;
    no2 := Length( o2 );
    if not ( Length( imo ) = Length( o1 ) ) then
        Error( "object images of incorrect length" );
    fi;
    if not ForAll( imo, o -> o in o2 ) then
        Error( "object images not in the objects of m2" );
    fi;
    mag1 := m1!.magma; 
    mag2 := m2!.magma;
    if not ( ( Source(hom) = mag1 ) and ( Range(hom) = mag2 ) ) then
        Error( "hom not a mapping m1!.magma -> m2!.magma" );
    fi;
    return HomomorphismFromSinglePieceNC( m1, m2, hom, imo );
end );

#############################################################################
##
#M  HomomorphismToSinglePieceNC  
#M  HomomorphismToSinglePiece
##
InstallMethod( HomomorphismToSinglePieceNC,
    "generic method for a mapping to a single piece magma", true,
    [ IsMagmaWithObjects, IsSinglePiece, IsHomogeneousList ], 0,
function( mag1, mag2, images )

    local map, ok, imo;

    Info( InfoGroupoids, 3, "homomorphism to a single piece magma - NC" ); 
    map := rec(); 
    ObjectifyWithAttributes( map, IsMWOMappingToSinglePieceType, 
        Source, mag1, 
        Range, mag2, 
        MappingToSinglePieceData, images,
        ImagesOfObjects, Flat( List( images, L -> L[2] ) ),   
        RespectsMultiplication, true, 
        IsHomomorphismToSinglePiece, true );
    ok := IsInjectiveOnObjects( map ); 
    ok := IsSurjectiveOnObjects( map ); 
    if ( ( "IsMonoidWithObjects" in CategoriesOfObject( mag1 ) ) and 
         ( "IsMonoidWithObjects" in CategoriesOfObject( mag2 ) ) ) then 
        SetIsMonoidWithObjectsHomomorphism( map, true ); 
    elif ( ( "IsSemigroupWithObjects" in CategoriesOfObject( mag1 ) ) and 
           ( "IsSemigroupWithObjects" in CategoriesOfObject( mag2 ) ) ) then 
        SetIsSemigroupWithObjectsHomomorphism( map, true );
    elif ( ( "IsMagmaWithObjects" in CategoriesOfObject( mag1 ) ) and 
           ( "IsMagmaWithObjects" in CategoriesOfObject( mag2 ) ) ) then 
        SetIsMagmaWithObjectsHomomorphism( map, true );
    fi; 
    ok := IsHomomorphismFromSinglePiece( map ); 
    return map; 
end );

InstallMethod( HomomorphismToSinglePiece, 
    "generic method for a mapping to a single piece magma", true,
    [ IsMagmaWithObjects, IsSinglePiece, IsHomogeneousList ], 0,
function( mwo1, mwo2, maps )

    local pieces, o2, m2, j, pj, h, mor;

    Info( InfoGroupoids, 3, "homomorphism to a single piece magma:", maps ); 
    pieces := Pieces( mwo1 ); 
    o2 := mwo2!.objects;
    m2 := mwo2!.magma;
    for j in [1..Length(pieces)] do 
        pj := pieces[j];
        h := maps[j][1];
        if not IsMagmaHomomorphism( h ) then
            Error( "h is not a magma homomorphism" );
        fi;
        if not ( ( Source(h) = pj!.magma ) and ( Range(h) = m2 ) ) then
            Error( "homs not a mapping m1!.magma -> m2!.magma" );
        fi;
        if not ( Length( maps[j][2] ) = Length( pj!.objects ) ) then 
            Error( "incorrect length for maps of objects" ); 
        fi;
        if not IsSubset( o2, maps[j][2] ) then 
            Error( "objects in the image not objects in m2" );
        fi;
    od;
    return HomomorphismToSinglePieceNC( mwo1, mwo2, maps ); 
end );

InstallMethod( HomomorphismToSinglePieceNC,
    "generic method for a mapping to a single piece magma", true,
    [ IsGroupoid, IsSinglePiece, IsHomogeneousList ], 0,
function( gpd1, gpd2, homs )

    local data, map, ok, imo;

    Info( InfoGroupoids, 3, "homomorphism to a single piece groupoid - NC" ); 
    data := List( homs, h -> MappingToSinglePieceData(h)[1] ); 
    map := rec(); 
    ObjectifyWithAttributes( map, IsGroupoidMappingToSinglePieceType, 
        Source, gpd1, 
        Range, gpd2, 
        MappingToSinglePieceData, data,  
        MappingToSinglePieceMaps, homs,  
        RespectsMultiplication, true, 
        IsHomomorphismToSinglePiece, true );
    ok := IsInjectiveOnObjects( map ); 
    ok := IsSurjectiveOnObjects( map ); 
    ok := IsGroupWithObjectsHomomorphism( map ); 
    ok := IsHomomorphismFromSinglePiece( map );
    return map; 
end );

InstallMethod( HomomorphismToSinglePiece,
    "generic method for a mapping to a single piece magma", true,
    [ IsGroupoid, IsSinglePiece, IsHomogeneousList ], 0,
function( mwo1, mwo2, homs )

    local pieces, o2, j, h;

    Info( InfoGroupoids, 3, "morphism to a single piece groupoid:\n", homs ); 
    pieces := Pieces( mwo1 ); 
    if not ( Length( pieces ) = Length( homs ) ) then 
        Error( "there should be one homomorphism for each piece in mwo1" ); 
    fi;
    o2 := mwo2!.objects;
    for j in [1..Length(pieces)] do 
        h := homs[j];
        if not IsMagmaWithObjectsHomomorphism( h ) then
            Error( "h is not a magma with objects homomorphism" );
        fi;
        if not ( ( Source(h) = pieces[j] ) and ( Range(h) = mwo2 ) ) then
            Error( "sources/ranges of homs do not agree with mwo1/mwo2" );
        fi;
    od;
    return HomomorphismToSinglePieceNC( mwo1, mwo2, homs );
end );

#############################################################################
##
#M  HomomorphismByUnionNC  
#M  HomomorphismByUnion
##
InstallMethod( HomomorphismByUnionNC, 
    "generic method for a magma mapping", true,
    [ IsMagmaWithObjects, IsMagmaWithObjects, IsList ], 0,  
function( mag1, mag2, images )

    local type, map, inj, pieces1, nc1, pieces2, nc2, obs1, 
          part, i, m, src;

    if IsSinglePiece( mag2 ) then 
        Info( InfoGroupoids, 1, "better to use single piece function" );
        return HomomorphismToSinglePiece( mag1, mag2, images );
    fi; 
    if ( ( "IsGroupoid" in CategoriesOfObject( mag1 ) ) and 
         ( "IsGroupoid" in CategoriesOfObject( mag2 ) ) ) then 
        type := IsGroupoidMappingWithPiecesType; 
    else 
        type := IsMWOMappingWithPiecesType; 
    fi;
    map := rec(); 
    ObjectifyWithAttributes( map, type, 
        Source, mag1,
        Range, mag2,
        PiecesOfMapping, images,
        IsGeneralMappingToSinglePiece, false );
    inj := IsInjectiveOnObjects( map ); 
    pieces1 := Pieces( mag1 );
    nc1 := Length( pieces1 );
    pieces2 := Pieces( mag2 );
    nc2 := Length( pieces2 );
    obs1 := List( pieces1, g -> g!.objects[1] ); 
    part := ListWithIdenticalEntries( nc2, 0 );
    for i in [1..nc2] do
        m := images[i];
        src := Source( m );
        if IsSinglePiece( src ) then
            part[i] := [ Position( obs1, src!.objects[1] ) ];
        else
            part[i] := List( Pieces( src ),  
                       c -> Position( obs1, c!.objects[1] ) );
        fi;
    od;
    Info( InfoGroupoids, 3, "part = ", part );
    SetPartitionOfSource( map, part );
    return map; 
end );

InstallMethod( HomomorphismByUnion, 
    "generic method for a magma mapping", true,
    [ IsMagmaWithObjects, IsMagmaWithObjects, IsList ], 0, 
function( mag1, mag2, maps )

    local pieces1, nc1, pieces2, nc2, lenmaps, lenpieces, npieces, expand, 
          src1, img1, g, ppos, pos2, piecesmap, L, i, j, k, m, filt, 
          mapj, srcj;

    if not ForAll( maps, IsGeneralMappingWithObjects ) then 
        Error( "all maps should have IsGeneralMappingWithObjects" ); 
    fi; 
    if IsSinglePiece( mag2 ) then 
        Info( InfoGroupoids, 1, "better to use single piece function" );
        return HomomorphismToSinglePieceNC( mag1, mag2, maps ); 
    fi;
    pieces1 := Pieces( mag1 );
    nc1 := Length( pieces1 );
    pieces2 := Pieces( mag2 );
    nc2 := Length( pieces2 );
    lenmaps := Length( maps ); 
    lenpieces := ListWithIdenticalEntries( lenmaps, 0 );
    for i in [1..lenmaps] do 
        m := maps[i];
        if not HasPiecesOfMapping( m ) then 
            lenpieces[i] := 1; 
        else 
            lenpieces[i] := Length( PiecesOfMapping( m ) );
        fi;
    od;
    npieces := Sum( lenpieces );    
    expand := ListWithIdenticalEntries( npieces, 0 );
    j := 0;
    for i in [1..Length(maps)] do
        m := maps[i];
        if HasPiecesOfMapping( m ) then
            piecesmap := PiecesOfMapping( m );
            for k in [1..Length( piecesmap )] do
                j := j+1;
                expand[j] := piecesmap[k];
            od;
        else
            j := j+1;
            expand[j] := m;
        fi;
    od;
    Info( InfoGroupoids, 3, "expanded maps:", expand );
    src1 := List( expand, Source );
    img1 := UnionOfPieces( List( maps, m -> ImagesSource( m ) ) );
    ppos := PiecePositions( mag2, img1 );
    Info( InfoGroupoids, 3, " ppos = ", ppos );
    if ( fail in ppos ) then
        Error( "not all m have source in mag1" );
    fi;
    ## construct the constituent mappings
    piecesmap := ListWithIdenticalEntries( nc2, 0 );
    for j in [1..nc2] do
        filt := Filtered( [1..npieces], k -> ppos[k] = j );
        mapj := maps{filt};
        srcj := UnionOfPieces( src1{filt} );
        piecesmap[j] := HomomorphismToSinglePiece( srcj, pieces2[j], mapj );
    od;

##    ##  more efficient to use PieceNrOfObject here ??
##    pos2 := List( maps, m -> Position( pieces2, 
##                      PieceOfObject( mag2, Range(m)!.objects[1] ) ) );
##    if ( fail in pos2 ) then
##        Error( "not all m have range in mag2" );
##    fi;
##    if IsDuplicateFree( pos2 ) then
##        ## reorder if necessary
##        Info( InfoGroupoids, 2, "duplicate free case" );
##        L := [1..nc2];
##        SortParallel( pos2, L );
##        piecesmap := List( L, j -> expand[j] );
##        return HomomorphismByUnionNC( mag1, mag2, piecesmap );
##    else
##        ## construct the constituent mappings
##        piecesmap := ListWithIdenticalEntries( nc2, 0 );
##        for j in [1..nc2] do
##            filt := Filtered( pos2, i -> (i=j) );
##            mapj := List( filt, i -> maps[i] );
##            if ( Length( filt ) = 1 ) then
##                piecesmap[j] := mapj[1]; 
##            else
##                if ( Length( filt ) = nc1 ) then
##                    src := mag1;
##                else
##                    src := UnionOfPieces( List(filt), i -> Source(maps[i]) );
##                fi;
##                piecesmap[j] := 
##                    HomomorphismToSinglePiece( src, pieces2[j], mapj );
##            fi;
##        od;
        return HomomorphismByUnionNC( mag1, mag2, piecesmap );
##    fi;
end );

#############################################################################
##
#M  IsomorphismNewObjects
##
InstallMethod( IsomorphismNewObjects, "for a single piece mwo", true,
    [ IsSinglePiece, IsHomogeneousList ], 0,
function( m1, ob2 )

    local isgpd, iso, ob1, mag, m2, id;

    ob1 := m1!.objects; 
    if not ( Length(ob1) = Length(ob2) ) then
        Error( "object sets have different lengths" );
    fi;
    mag := m1!.magma;
    m2 := SinglePieceMagmaWithObjects( mag, ShallowCopy( Set( ob2 ) ) );
    id := IdentityMapping( mag );
    iso := HomomorphismFromSinglePiece( m1, m2, id, ob2 ); 
    return iso;
end );

InstallMethod( IsomorphismNewObjects, "generic method for a magma", true,
    [ IsMagmaWithObjects, IsHomogeneousList ], 0,
function( m1, ob2 )

    local isos, pieces1, nc1, i, m2, iso;

    pieces1 := Pieces( m1 );
    nc1 := Length( pieces1 );
    if not ( Length(ob2) = nc1 ) then
        Error( "new list of lists of objects has incorrect length" );
    fi;
    isos := ListWithIdenticalEntries( nc1, 0 );
    for i in [1..nc1] do 
        isos[i] := IsomorphismNewObjects( pieces1[i], ob2[i] );
    od;
    m2 := UnionOfPieces( List( isos, Range ) );
    iso := HomomorphismByUnion( m1, m2, isos );
    return iso;
end );

#############################################################################
##
#M  IdentityMapping
##
InstallOtherMethod( IdentityMapping, "for a magma with objects", true, 
    [ IsMagmaWithObjects ], 0,
function( mwo )

    local pieces, gp, gens, id, len, homs, iso;

    if IsSinglePiece( mwo ) then
        iso := HomomorphismToSinglePieceNC
            ( mwo, mwo, [ [mwo!.objects, IdentityMapping(mwo!.magma)] ] ); 
    elif ( HasIsHomogeneousDiscreteGroupoid( mwo ) 
           and IsHomogeneousDiscreteGroupoid( mwo ) ) then 
        id := IdentityMapping( Pieces(mwo)[1]!.magma ); 
        len := Length( ObjectList( mwo ) ); 
        homs := ListWithIdenticalEntries( len, id ); 
        iso := GroupoidAutomorphismByGroupAutos( mwo, homs ); 
    else
        pieces := List( Pieces( mwo ), IdentityMapping );
        iso := MagmaWithObjectsHomomorphism( mwo, mwo, pieces );
    fi;
    SetIsInjectiveOnObjects( iso, true );
    SetIsSurjectiveOnObjects( iso, true );
    return iso;
end );

#############################################################################
##
#M  ImagesOfObjects
##
InstallMethod( ImagesOfObjects, "for a magma mapping", true,
    [ IsMagmaWithObjectsHomomorphism and IsHomomorphismToSinglePiece ], 0,
function( map )

    local data, src, obs, ims, c, i, obc, imc, j, pos;

    data := MappingToSinglePieceData( map );
    if ( Length( data ) = 1 ) then
        return data[1][2];
    else
        src := Source( map );
        obs := ObjectList( src );
        ims := ShallowCopy( obs );
        c := Pieces( src ); 
        for i in [1..Length(c)] do 
            obc := c[i]!.objects;
            imc := data[i][2];
            for j in [1..Length(obc)] do
                pos := Position( obs, obc[j] );
                ims[pos] := imc[j];
            od;
        od;
        return ims;
    fi;
end );

InstallMethod( ImagesOfObjects, "for a magma mapping", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )

    local src, obs, ims, i, c, obc, o, pos;

    src := Source( map );
    obs := ObjectList( src );
    ims := ShallowCopy( obs );
    for c in PiecesOfMapping( map ) do
        obc := Source( c )!.objects;
        for i in [1..Length(obc)] do
            pos := Position( obs, obc[i] );
            ims[pos] := ImagesOfObjects( c )[i];
        od;
    od;
    return ims;
end ); 

#############################################################################
##
#M  IsSemigroupWithObjectsHomomorphism
#M  IsMonoidWithObjectsHomomorphism 
#M  IsGroupWithObjectsHomomorphism
##
InstallMethod( IsSemigroupWithObjectsHomomorphism, 
    "for a mapping with objects", true, [ IsMagmaWithObjectsHomomorphism ], 0,
function( map ) 
    return 
        ( ( "IsSemigroupWithObjects" in CategoriesOfObject( Source(map) ) ) and  
          ( "IsSemigroupWithObjects" in CategoriesOfObject( Range(map) ) ) ); 
end );

InstallMethod( IsMonoidWithObjectsHomomorphism, "for a mapping with objects", 
    true, [ IsMagmaWithObjectsHomomorphism ], 0,
function( map ) 
    return 
        ( ( "IsMonoidWithObjects" in CategoriesOfObject( Source(map) ) ) and 
          ( "IsMonoidWithObjects" in CategoriesOfObject( Range(map) ) ) ); 
end );

InstallMethod( IsGroupWithObjectsHomomorphism, "for a mapping with objects", 
    true, [ IsMagmaWithObjectsHomomorphism ], 0,
function( map ) 
    return ( IsGroupoid( Source(map) ) and IsGroupoid( Range(map) ) ); 
end );

#############################################################################
##
#M  IsGeneralMappingToSinglePiece
#M  IsGeneralMappingFromSinglePiece 
##
InstallMethod( IsGeneralMappingToSinglePiece, 
    "for a mapping with objects", true, [ IsMagmaWithObjectsHomomorphism ], 0,
function( map ) 
    return IsSinglePiece( Range( map ) ); 
end );

InstallMethod( IsGeneralMappingFromSinglePiece, 
    "for a mapping with objects", true, [ IsMagmaWithObjectsHomomorphism ], 0,
function( map ) 
    return IsSinglePiece( Source( map ) ); 
end );

#############################################################################
##
#M  IsConstantOnObjects
#M  IsInjectiveOnObjects 
#M  IsSurjectiveOnObjects 
#M  IsBijectiveOnObjects
##
InstallMethod( IsConstantOnObjects,
    "generic method for a magma mapping with objects", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )
    return Source( map )!.objects = ImagesOfObjects( map ); 
end );

InstallMethod( IsInjectiveOnObjects, "for a mapping with objects", true,
    [ IsHomomorphismToSinglePiece ], 0,
function( map )

    local images, imo;

    imo := ImagesOfObjects( map );
    if not ( imo = fail ) then 
        return IsDuplicateFree( Flat( imo ) );
    elif IsHomomorphismToSinglePiece( map ) then
        images := MappingToSinglePieceData( map );
        imo := Flat( List( images, L -> L[2] ) ); 
        return IsDuplicateFree( imo ); 
    elif ( HasIsGeneralMappingFromHomogeneousDiscrete( map ) 
           and IsGeneralMappingFromHomogeneousDiscrete( map ) ) then 
        return IsDuplicateFree( map!.oims ); 
    else  ## mapping has pieces
        imo := List( PiecesOfMapping( map ), 
                     m -> MappingToSinglePieceData(m)[2] );
        return IsDuplicateFree( Flat( imo ) );
    fi;
end );

InstallMethod( IsInjectiveOnObjects, "for a mapping with objects", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )
    return ForAll( PiecesOfMapping( map ), IsInjectiveOnObjects ); 
end );

InstallMethod( IsInjectiveOnObjects, 
    "for a mapping from a homogeneous, discrete groupoid", true,
    [ IsGroupoidHomomorphismFromHomogeneousDiscreteRep ], 0,
function( map ) 
    return IsDuplicateFree( ImagesOfObjects( map ) ); 
end );

InstallMethod( IsSurjectiveOnObjects, "for a mapping with objects", true,
    [ IsHomomorphismToSinglePiece ], 0,
function( map ) 

    local obr, images, imo;

    obr := ObjectList( Range( map ) ); 
    if HasImagesOfObjects( map ) then 
        imo := Flat( ImagesOfObjects( map ) );
    elif IsHomomorphismToSinglePiece( map ) then
        images := MappingToSinglePieceData( map );
        imo := Flat( List( images, L -> L[2] ) );
    else  ## mapping has pieces
        imo := Flat( List( PiecesOfMapping( map ), 
                     m -> MappingToSinglePieceData(m)[1][2] ) );
    fi;
    return ( Set(imo) = obr );
end );

InstallMethod( IsSurjectiveOnObjects, "for a mapping with objects", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )
    return ForAll( PiecesOfMapping( map ), IsSurjectiveOnObjects ); 
end );

InstallMethod( IsSurjectiveOnObjects, 
    "for a mapping from a homogeneous, discrete groupoid", true,
    [ IsGroupoidHomomorphismFromHomogeneousDiscreteRep ], 0,
function( map ) 

    local obr, images, imo;

    obr := ObjectList( Range( map ) ); 
    imo := ImagesOfObjects( map );
    return ( Set(imo) = obr ); 
end );

InstallMethod( IsBijectiveOnObjects, "for a mapping with objects", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map ) 
    return IsInjectiveOnObjects( map ) and IsSurjectiveOnObjects( map ); 
end ); 

##############################################################################
##
#M  IsEndomorphismWithObjects( map ) . . . . . . . . . .  for a magma mapping
#M  IsAutomorphismWithObjects( map ) . . . . . . . . . .  for a magma mapping
##
InstallMethod( IsEndomorphismWithObjects, "for a magma mapping", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )
    return ( Source( map ) = Range( map ) );
end );

InstallMethod( IsAutomorphismWithObjects, "for a magma mapping", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )
    return ( IsEndomorphismWithObjects( map ) 
             and IsInjectiveOnObjects( map ) 
             and IsSurjectiveOnObjects( map ) );
end );

#############################################################################
##
#M  InverseGeneralMapping
#M  InverseMapping
##
InstallMethod( InverseMapping, "for a magma mapping", true,
    [ IsMagmaWithObjectsHomomorphism and IsInjectiveOnObjects 
                                and IsSurjectiveOnObjects ], 0,
function( map )
    return InverseGeneralMapping( map );
end );

InstallMethod( InverseGeneralMapping, "for a magma mapping", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )

    local pieces, isos, inv;

    Info( InfoGroupoids, 3, "InverseGeneralMapping for magma mappings" );
    pieces := PiecesOfMapping( map );
    isos := List( pieces, InverseGeneralMapping );
    inv := HomomorphismByUnion( Range(map), Source(map), isos );
    SetIsInjectiveOnObjects( inv, true );
    SetIsSurjectiveOnObjects( inv, true );
    return inv;
end );

InstallMethod( InverseGeneralMapping, "for a single piece mapping", true,
    [ IsMagmaWithObjectsHomomorphism and IsHomomorphismToSinglePiece ], 0,
function( map )

    local m1, m2, ob1, ob2, nob, hom21, len, sc1, sc2, obhom1, inv;

    if not (IsInjectiveOnObjects(map) and IsSurjectiveOnObjects(map)) then
        Error( "mapping with objects not bijective" );
    fi;
    Info( InfoGroupoids, 3, "InverseGeneralMapping for single piece mappings" );
    m1 := Source( map );
    if not IsSinglePiece( m1 ) then
        Error( "source is not single piece" );
    fi;
    m2 := Range( map );
    ob1 := m1!.objects;
    ob2 := m2!.objects;
    nob := Length( ob1 );
    obhom1 := MappingToSinglePieceData( map );
    len := Length( obhom1 );
    sc1 := ShallowCopy( ob1 );
    sc2 := ShallowCopy( obhom1[1][2] );
    SortParallel( sc2, sc1 );
    hom21 := InverseGeneralMapping( obhom1[1][1] );
    SetIsTotal( hom21, true );
    SetRespectsMultiplication( hom21, true );
    SetIsInjective( hom21, true );
    SetIsSurjective( hom21, true );
    inv := HomomorphismFromSinglePiece( m2, m1, hom21, sc1 );
    SetIsInjectiveOnObjects( inv, true );
    SetIsSurjectiveOnObjects( inv, true );
    return inv;
end );

InstallMethod( InverseGeneralMapping, "for a groupoid isomorphism", true,
    [ IsGroupWithObjectsHomomorphism and IsHomomorphismFromSinglePiece], 0,
function( iso )

    local src, rng, obss, obsr, nobs, imobs, L, invobs, pos1, pi, 
          rhom, rgps, rgpr, ids, idr, irhom, c, b, genss, ngenss, nggenss, 
          gensr, ngensr, nggensr, images, r, u, v, q, pq, rayrq, j, rayuv, 
          g, i, y, invy, w, rayvw, f, p, pp, rayrp, k, rayuw, h, invf, inv; 

    if not (IsInjectiveOnObjects(iso) and IsSurjectiveOnObjects(iso)) then
        Error( "mapping not bijective on objects" );
    fi; 
    Info( InfoGroupoids, 1, "InverseGeneralMapping for groupoid isos" ); 
    src := Source( iso );
    obss := src!.objects;
    rng := Range( iso ); 
    obsr := rng!.objects;
    nobs := Length( obss );
    imobs := ImagesOfObjects( iso ); 
    L := [1..nobs]; 
    SortParallel( ShallowCopy(imobs), L ); 
    invobs := List( L, i -> obss[i] ); 
    pos1 := Position( invobs, obss[1] );
    pi := PermList(L)^-1; 
    rhom := RootGroupHomomorphism( iso ); 
    rgps := RootGroup( src ); 
    rgpr := RootGroup( rng );
    ids := Arrow( src, One( rgps ), obss[1], obss[1] ); 
    idr := Arrow( rng, One( rgpr ), obsr[1], obsr[1] ); 
    if not IsBijective( rhom ) then 
        Error( "root group homomorphism has no inverse" ); 
    fi; 
    irhom := InverseGeneralMapping( rhom ); 
    genss := GeneratorsOfGroupoid( src );
    ngenss := Length( genss ); 
    nggenss := ngenss - nobs + 1;
    gensr := GeneratorsOfGroupoid( rng ); 
    ngensr := Length( gensr );
    nggensr := ngensr - nobs + 1;
    images := [1..ngensr]; 
    r := obss[1]; 
    u := imobs[1];
    v := obsr[1]; 
    q := invobs[1]; 
    pq := Position( obss, q ); 
    if ( pq = 1 ) then 
        rayrq := ids;  
    else 
        rayrq := genss[ nggenss + pq - 1 ]; 
    fi; 
    j := rayrq![2];
    rayuv := ImageElm( iso, rayrq );
    g := rayuv![2]; 
    for i in [1..nggensr] do 
        y := gensr[i]![2]; 
        invy := ImageElm( irhom, y^(g^-1) )^j; 
        images[i] := Arrow( src, invy, q, q ); 
    od; 
    for i in [2..nobs] do 
        w := obsr[i];
        rayvw := gensr[nggensr+i-1]; 
        f := rayvw![2]; 
        p := invobs[i]; 
        pp := Position( obss, p );
        if ( pp = 1 ) then 
            rayrp := ids; 
        else 
            rayrp := genss[ nggenss + pp - 1 ];
        fi; 
        k := rayrp![2]; 
        rayuw := ImageElm( iso, rayrp ); 
        h := rayuw![2]; 
        invf := (j^-1) * ImageElm( irhom, g*f*h^-1 ) * k;
        images[ nggensr + i -1 ] := Arrow( src, invf, q, p ); 
    od; 
    inv := GroupoidHomomorphism( rng, src, gensr, images );
    SetIsInjectiveOnObjects( inv, true );
    SetIsSurjectiveOnObjects( inv, true );
    SetInverseGeneralMapping( iso, inv );
    SetInverseGeneralMapping( inv, iso );
    return inv;
end );

InstallMethod( InverseGeneralMapping, "for gpd auto by object perm", true,
    [ IsGroupoidAutomorphismByObjectPerm ], 0,
function( aut )

    local gpd, obs, nobs, imobs, L, invobs, inv; 

    Info( InfoGroupoids, 1, "InverseGeneralMapping for object perm auto" );
    gpd := Source( aut );
    obs := gpd!.objects;
    nobs := Length( obs );
    imobs := ImagesOfObjects( aut ); 
    L := [1..nobs]; 
    SortParallel( ShallowCopy(imobs), L ); 
    invobs := List( L, i -> obs[i] ); 
    inv := GroupoidAutomorphismByObjectPerm( gpd, invobs ); 
    SetIsEndomorphismWithObjects( inv, true );
    SetIsInjectiveOnObjects( inv, true );
    SetIsSurjectiveOnObjects( inv, true );
    SetInverseGeneralMapping( aut, inv );
    SetInverseGeneralMapping( inv, aut );
    return inv;
end );

InstallMethod( InverseGeneralMapping, "for gpd auto by group auto", true,
    [ IsGroupoidAutomorphismByGroupAuto ], 0,
function( aut )

    local gpd, rhom, irhom, ok, inv; 

    Info( InfoGroupoids, 1, "InverseGeneralMapping for group auto auto" );
    gpd := Source( aut );
    rhom := RootGroupHomomorphism( aut ); 
    irhom := InverseGeneralMapping( rhom );
    ok := IsGroupHomomorphism( irhom );
    inv := GroupoidAutomorphismByGroupAuto( gpd, irhom ); 
    SetIsEndomorphismWithObjects( inv, true );
    SetIsInjectiveOnObjects( inv, true );
    SetIsSurjectiveOnObjects( inv, true );
    SetInverseGeneralMapping( aut, inv );
    SetInverseGeneralMapping( inv, aut );
    return inv;
end );

InstallMethod( InverseGeneralMapping, "for gpd auto by ray shifts", true,
    [ IsGroupoidAutomorphismByRayShifts ], 0,
function( aut )

    local gpd, r, len, s, h, inv; 

    Info( InfoGroupoids, 1, "InverseGeneralMapping for ray shifts auto" );
    gpd := Source( aut );
    r := RaysOfGroupoid( gpd );
    len := Length( r );
    s := ImageElementsOfRays( aut );
    h := List( [1..len], i -> s[i]^-1 * r[i] ); 
    inv := GroupoidAutomorphismByRayShifts( gpd, h ); 
    SetIsEndomorphismWithObjects( inv, true );
    SetIsInjectiveOnObjects( inv, true );
    SetIsSurjectiveOnObjects( inv, true );
    SetInverseGeneralMapping( aut, inv );
    SetInverseGeneralMapping( inv, aut );
    return inv;
end );

InstallMethod( InverseGeneralMapping, "for hom from discrete gpd with objects", 
    true, [ IsGroupWithObjectsHomomorphism and 
            IsGroupoidHomomorphismFromHomogeneousDiscrete ], 0,
function( map )

    local src, rng, obs, oims1, oims2, homs, ihoms, inv; 

    if not IsBijectiveOnObjects( map ) then 
        Error( "expecting map to be bijective on objects" ); 
    fi; 
    Info( InfoGroupoids, 3, 
          "InverseGeneralMapping for hom from discrete groupoid" );
    src := Source( map ); 
    rng := Range( map ); 
    if not ( IsHomogeneousDomainWithObjects( rng ) and 
             IsDiscreteDomainWithObjects( rng ) ) then 
        Error( "expecting range to be homogeneous discrete" ); 
    fi; 
    obs := ShallowCopy( src!.objects ); 
    oims1 := ShallowCopy( ImagesOfObjects( map ) ); 
    oims2 := ShallowCopy( oims1 ); 
    homs := ShallowCopy( ObjectHomomorphisms( map ) ); 
    SortParallel( oims1, obs ); 
    SortParallel( oims2, homs ); 
    ihoms := List( homs, InverseGeneralMapping );
    inv := GroupoidHomomorphismFromHomogeneousDiscrete( src,rng,ihoms,obs ); 
    SetInverseGeneralMapping( map, inv );
    SetInverseGeneralMapping( inv, map );
    return inv;
end ); 

#############################################################################
##
#M  \=( <m1>, <m2> )  . . . . . . . . . . . .  equality of two magma mappings
##
InstallMethod( \=, "for 2 single piece mappings", true,
    [ IsHomomorphismToSinglePiece, IsHomomorphismToSinglePiece ], 0,
function( m1, m2 )
    Info( InfoGroupoids, 4, 
          "\\= for IsHomomorphismToSinglePiece in mwohom.gi" ); 
    return ( ( Source( m1 ) =  Source( m2 ) ) and
             ( Range( m1 ) = Range( m2 ) ) and 
             ( MappingToSinglePieceData( m1 ) 
               = MappingToSinglePieceData( m2 ) ) );
end );

InstallMethod( \=, "for 2 magma mappings", true,
    [ IsMappingWithPiecesRep, IsMappingWithPiecesRep ], 0,
function( m1, m2 )

    local c1, c2, nc, src1, src2, rng1, rng2, j, s, spos, r, rpos, L, ok;

    Info( InfoGroupoids, 4, "\\= for IsMappingWithPiecesRep in mwohom.gi" ); 
    c1 := PiecesOfMapping( m1 );
    c2 := PiecesOfMapping( m2 );
    nc := Length( c1 );
    if ( nc <> Length( c2 ) ) then
        return false;
    fi;
    src1 := List( c1, Source );
    src2 := List( c2, Source );
    rng1 := List( c1, Range );
    rng2 := List( c2, Range );
    L := ListWithIdenticalEntries( nc, 0 );
    for j in [1..nc] do
        s := src1[j];
        spos := Position( src2, s );
        r := rng1[j];
        rpos := Position( rng2, r );
        if ( ( spos = fail ) or ( rpos = fail ) or ( spos <> rpos ) ) then
            return false;
        fi;
        ok := ( c1[j] = c2[spos] );
        if ( ok = false ) then
            return false;
        fi;
        L[j] := spos;
    od;
    Sort( L );
    return ( L = Set(L) );
end );

InstallMethod( \=, "for 2 connected groupoid mappings", true,
    [ IsDefaultGroupoidHomomorphismRep, 
      IsDefaultGroupoidHomomorphismRep ], 0,
function( m1, m2 ) 
    Info( InfoGroupoids, 4, 
          "\\= for IsDefaultGroupoidHomomorphismRep in gpdhom.gi" ); 
    if not ( ( Source( m1 ) =  Source( m2 ) ) 
            and ( Range( m1 ) = Range( m2 ) ) ) then 
        return false; 
    fi; 
    if not ( ImagesOfObjects( m1 ) = ImagesOfObjects( m2 ) ) then 
        return false; 
    fi; 
    if ( HasIsGeneralMappingToSinglePiece( m1 ) 
        and IsGeneralMappingToSinglePiece( m1 ) ) then  
        return ( ( RootGroupHomomorphism( m1 ) = RootGroupHomomorphism( m2 ) ) 
             and ( ImageElementsOfRays( m1 ) = ImageElementsOfRays( m2 ) ) ); 
    else 
        return fail; 
    fi; 
end );

InstallMethod( \=, "for 2 mappings of homogeneous discrete groupoids", true,
    [ IsGroupoidHomomorphismFromHomogeneousDiscreteRep, 
      IsGroupoidHomomorphismFromHomogeneousDiscreteRep ], 0,
function( m1, m2 )
    Info( InfoGroupoids, 4, 
          "\\= for discrete homogensous groupoids in mwohom.gi" ); 
    return ( ( Source( m1 ) =  Source( m2 ) ) and
             ( Range( m1 ) = Range( m2 ) ) and 
             ( ImagesOfObjects( m1 ) = ImagesOfObjects( m2 ) ) and 
             ( ObjectHomomorphisms( m1 ) = ObjectHomomorphisms( m2 ) ) );
end );

#############################################################################
##
#M  \*( <m1>, <m2> )  . . . . . .  product of two magma with objects mappings 
##
InstallMethod( \*, "for 2 magma mappings", true,
    [ IsMagmaWithObjectsHomomorphism, IsMagmaWithObjectsHomomorphism ], 0,
function( m1, m2 )

    local src1, rng1, src2, rng2, pcs1, pcr1, pcs2, pcr2, pcm1, len1, 
          pcm2, len2, pieces, i, pi, oi, found, j; 

    ## general * implemented 12/01/11 
    src1 := Source( m1 ); 
    rng1 := Range( m1 );
    src2 := Source( m2 );
    rng2 := Range( m2 ); 
    if not IsSubdomainWithObjects( src2, rng1 ) then
        Error( "Range(m1) not a submagma of Source(m2)" );
    fi;
    pcs1 := Pieces( src1 ); 
    pcr1 := Pieces( rng1 ); 
    pcs2 := Pieces( src2 ); 
    pcr2 := Pieces( rng2 ); 
    pcm1 := PiecesOfMapping( m1 );
    len1 := Length( pcm1 );
    pcm2 := PiecesOfMapping( m2 ); 
    len2 := Length( pcm2 ); 
    pieces := ListWithIdenticalEntries( len1, 0 ); 
    for i in [1..len1] do 
        pi := pcr1[i]; 
        oi := pi!.objects; 
        found := false; 
        j := 0; 
        while ( ( found = false ) and ( j < len2 ) ) do 
            j := j+1; 
            if ( oi = pcs2[j]!.objects ) then 
                found := true; 
                pieces[i] := pcm1[i] * pcm2[j]; 
            fi; 
        od; 
        if ( found = false ) then 
            Error( "composite piece not found" ); 
        fi; 
    od; 
    return HomomorphismByUnion( src1, rng2, pieces );
end );

InstallMethod( \*, "for 2 single piece magma mappings", true,
    [ IsMagmaWithObjectsHomomorphism, IsHomomorphismToSinglePiece ], 0,
function( map1, map2 )

    local src1, rng1, src2, rng2, pos, pieces1, len1, i, m, maps, 
          images, imo1, hom1, s1, ob1, nob1, imo2, hom2, s2, ob2, nob2,
          imo12, j, o, p, hom;

    Info( InfoGroupoids, 3, "second method for * with map2 single piece" );
    src1 := Source( map1 );
    rng1 := Range( map1 );
    src2 := Source( map2 );
    rng2 := Range( map2 ); 
    if not IsSubdomainWithObjects( src2, rng1 ) then
        Error( "Range(map1) not a submagma of Source(map2)" );
    fi;
    pieces1 := PiecesOfMapping( map1 );
    len1 := Length( pieces1 );
    maps := ListWithIdenticalEntries( len1, 0 );
    images := MappingToSinglePieceData( map2 );
    for i in [1..len1] do
        m := pieces1[i];
        if not IsSinglePiece( Source(m) ) then
            Print( "general * not yet implemented\n" );
            return fail;
        fi;
        imo1 := MappingToSinglePieceData(m)[1][2];
        hom1 := MappingToSinglePieceData(m)[1][1];
        s1 := Source( m );
        ob1 := s1!.objects;
        nob1 := Length( ob1 );
        pos := Position( Pieces( src2 ), Range( m ) );
        s2 := Pieces( src2 )[pos];
        ob2 := s2!.objects;
        nob2 := Length( ob2 );
        imo2 := images[pos][2];
        hom2 := images[pos][1];
        imo12 := ListWithIdenticalEntries( nob1, 0 );
        for j in [1..nob1] do
            o := imo1[j];
            p := Position( ob2, o );
            imo12[j] := imo2[p];
        od;
        hom := hom1 * hom2;
        maps[i] := HomomorphismToSinglePiece( s1, rng2, [ [imo12,hom] ] );
    od;
    return HomomorphismByUnion( src1, rng2, maps );
end );

InstallMethod( \*, "for two single piece magma mappings", true,
    [ IsHomomorphismToSinglePiece, IsHomomorphismToSinglePiece ], 0,
function( m1, m2 )

    local s1, r1, s2, r2, oi1, ob1, nob1, ob2, oi2, oi12, j, o, p, hom, 
          gens, images;

    Info( InfoGroupoids, 3, 
          "third method for * with map1 & map2 single piece" );
    s1 := Source( m1 );
    if not IsSinglePiece( s1 ) then 
        Error("source of m1 not single piece - general method not installed");
    fi;
    r1 := Range( m1 );
    s2 := Source( m2 );
    r2 := Range( m2 );
    if not IsSubdomainWithObjects( s2, r1 ) then
        Error( "Range(m1) not a submagma of Source(m2)" );
    fi;
    oi1 := MappingToSinglePieceData( m1 )[1];
    ob1 := s1!.objects;
    nob1 := Length( ob1 );
    ob2 := s2!.objects;
    oi2 := MappingToSinglePieceData( m2 )[1];
    oi12 := ListWithIdenticalEntries( nob1, 0 );
    for j in [1..nob1] do
        o := oi1[2][j];
        p := Position( ob2, o );
        oi12[j] := oi2[2][p];
    od;
    hom := oi1[1] * oi2[1];
    if IsGroupoid( s1 ) and IsSinglePiece( s1 ) then
        gens := GeneratorsOfGroupoid( s1 );
        images := List( gens, g -> ImageElm( m1, g ) );
        images := List( images, g -> ImageElm( m2, g ) );
        return GroupoidHomomorphismFromSinglePiece( s1, r2, gens, images ); 
    else
        return HomomorphismToSinglePiece( s1, r2, [ [ hom, oi12 ] ] );
    fi;
end );

InstallMethod( \*, "for 2 connected groupoid homomorphisms", true,
    [ IsGroupoidHomomorphism and IsDefaultGroupoidHomomorphismRep, 
      IsGroupoidHomomorphism and IsDefaultGroupoidHomomorphismRep ], 0,
function( m1, m2 )

    local s1, r1, s2, r2, mgi1, img1, img2;

    Info( InfoGroupoids, 2, 
          "method 1 for * with IsDefaultGroupoidHomomorphismRep" );
    s1 := Source( m1 ); 
    r1 := Range( m1 );
    s2 := Source( m2 );
    r2 := Range( m2 );
    if not IsSubdomainWithObjects( s2, r1 ) then
        Error( "Range(m1) not a subgroupoid of Source(m2)" );
    fi; 
    mgi1 := MappingGeneratorsImages( m1 ); 
    img1 := mgi1[2]; 
    img2 := List( img1, a -> ImageElm( m2, a ) ); 
    return GroupoidHomomorphismFromSinglePieceNC( s1, r2, mgi1[1], img2 );
end );

InstallMethod( \*, "for maps from hom discrete groupoids", true,
    [ IsGroupoidHomomorphismFromHomogeneousDiscreteRep, 
      IsGroupoidHomomorphismFromHomogeneousDiscreteRep ], 0,
function( m1, m2 )

    local s1, r1, s2, r2, ob1, nob1, ob2, io1, io2, 
          homs, oims, hom1, hom2, pos, j, m;

    Info( InfoGroupoids, 3, "method 2 for * with maps from hom discrete gpds" );
    s1 := Source( m1 ); 
    r1 := Range( m1 );
    s2 := Source( m2 );
    r2 := Range( m2 );
    if not IsSubdomainWithObjects( s2, r1 ) then
        Error( "Range(m1) not a subgroupoid of Source(m2)" );
    fi; 
    ob1 := s1!.objects;
    nob1 := Length( ob1 );
    ob2 := s2!.objects; 
    io1 := ImagesOfObjects( m1 ); 
    io2 := ImagesOfObjects( m2 ); 
    oims := [1..nob1]; 
    homs := [1..nob1]; 
    hom1 := ObjectHomomorphisms( m1 ); 
    hom2 := ObjectHomomorphisms( m2 ); 
    for j in [1..nob1] do 
        pos := Position( ob2, io1[j] ); 
        oims[j] := io2[ pos ]; 
        homs[j] := hom1[j] * hom2[pos]; 
    od; 
    m := GroupoidHomomorphismFromHomogeneousDiscreteNC( s1, r2, homs, oims ); 
    SetIsGroupWithObjectsHomomorphism( m, true );
    return m; 
end );

InstallMethod( \*, "for map from hom discrete with any gpd hom", true,
    [ IsGroupoidHomomorphismFromHomogeneousDiscreteRep, 
      IsGroupoidHomomorphism and IsDefaultGroupoidHomomorphismRep ], 0,
function( m1, m2 )

    local s1, r1, s2, r2, ob1, nob1, ob2, io1, io2, homs, oims, hom1, j;

    Info( InfoGroupoids, 2, 
          "method 3 for * with first a map from hom discrete" );
    s1 := Source( m1 ); 
    r1 := Range( m1 );
    s2 := Source( m2 );
    r2 := Range( m2 );
    if not IsSubdomainWithObjects( s2, r1 ) then
        Error( "Range(m1) not a subgroupoid of Source(m2)" );
    fi; 
    ob1 := s1!.objects;
    nob1 := Length( ob1 );
    ob2 := s2!.objects; 
    io1 := ImagesOfObjects( m1 ); 
    io2 := ImagesOfObjects( m2 ); 
    oims := [1..nob1]; 
    homs := [1..nob1]; 
    hom1 := ObjectHomomorphisms( m1 ); 
    for j in [1..nob1] do
        oims[j] := io2[ Position( ob2, io1[j] ) ]; 
        homs[j] := hom1[j] * ObjectGroupHomomorphism( m2, io1[j] ); 
    od;
    return GroupoidHomomorphismFromHomogeneousDiscreteNC( s1, r2, homs, oims );
end );

#############################################################################
##
#M  \^( <e>, <n> )  . . . . . . . . . . power of a magma with objects mapping
##
InstallMethod( \^, "for a magma with objects mapping and an integer", true,
    [ IsMagmaWithObjectsHomomorphism, IsInt ], 0,
function( map, n )

    local i, m1, m2; 

    if not ( ( Source(map) = Range(map) ) or ( n = -1 ) ) then
        Error( "source <> range  or  n <> -1" );
    fi;
    if ( n = 1 ) then
        return map;
    elif ( n = 0 ) then
        return IdentityMapping( Source( map ) );
    elif ( n = -1 ) then
        return InverseGeneralMapping( map );
    elif ( n > 1 ) then
        m1 := map;
        for i in [2..n] do
            m2 := map * m1;
            m1 := m2;
        od;
        return m1;
    else  ## n < -1
        return InverseGeneralMapping( map )^(-n);
    fi;
    Info( InfoGroupoids, 1, "unexpected failure in \^" ); 
    return fail;
end );

#############################################################################
##
#M  Order( <m> )  . . . . . . . . . . . . . . . . . .  of a magma mapping
##
InstallMethod( Order, "for a magma mapping", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function( map )
    Print( "Order only implemented for single piece mappings at present\n" );
    return fail;
end );

InstallMethod( Order, "for a single piece magma mapping", true,
    [ IsHomomorphismToSinglePiece and IsAutomorphismWithObjects ], 0, 
function( m )

    local im, obsrc, oblist, obord, hom, homord, ok;

    im := InverseMapping( m ); 
    if (  im = fail ) then
        Error( "inverse does not exist" );
    fi; 
    obsrc := ObjectList( Source( m ) );
    oblist := List( ImagesOfObjects( m ), o -> Position( obsrc, o ) );
    obord := Order( PermList( oblist ) );
    hom := RootGroupHomomorphism( m );
    homord := Order( hom);
    return Lcm( [ obord, homord ] );
end );

#############################################################################
##
#M  String, ViewString, PrintString, ViewObj, PrintObj 
##  . . . . . . . . . . . . . . for homomorphisms between magmas with objects 
##
InstallMethod( String, "for a magma with objects homomorphism", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0, 
function( hom ) 
    if ( "IsGroupoidHomomorphism" in CategoriesOfObject(hom) ) then 
        return( STRINGIFY( "groupoid homomorphism" ) ); 
    else 
        return( STRINGIFY( "magma with objects homomorphism" ) ); 
    fi;
end );

InstallMethod( ViewString, "for a magma with objects homomorphism", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0, String ); 

InstallMethod( PrintString, "for a magma with objects homomorphism", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0, String ); 

InstallMethod( ViewObj, "for a magma with objects homomorphism", true, 
    [ IsMagmaWithObjectsHomomorphism ], 0, PrintObj ); 

InstallMethod( PrintObj, "for mwo homomorphism to single piece", true,
    [ IsHomomorphismToSinglePiece ], 0, 
function ( hom ) 
    local src, rng, mgi, ngens, i; 
    src := Source( hom ); 
    rng := Range( hom ); 
    if ( "IsGroupoidHomomorphism" in CategoriesOfObject(hom) ) then 
        Print( "groupoid homomorphism : " ); 
    else 
        Print( "magma with objects homomorphism : " ); 
    fi;
    if ( HasName( src ) and HasName( rng ) ) then 
        Print( src, " -> ", rng, "\n" ); 
    else 
        Print( "\n" );
    fi; 
    if ( "IsGroupoidHomomorphism" in CategoriesOfObject(hom) ) then 
        Print( MappingGeneratorsImages( hom ) ); 
    else 
        Print( MappingToSinglePieceData( hom ) ); 
    fi;
end );

InstallMethod( PrintObj, "for a general mwo mapping by function", true,
    [ IsMappingWithObjectsByFunction ], 10, 
function ( map ) 
    Print( "magma with objects mapping by function : " );  
    Print( Source( map ), " -> ", Range( map ), "\n" );  
    Print( "function: ", UnderlyingFunction( map ) );  
end );

InstallMethod( PrintObj, "for a general mwo homomorphism", true,
    [ IsMagmaWithObjectsHomomorphism ], 0, 
function ( hom ) 
    Print( "magma with objects homomorphism : " );  
    if ( HasName( Source(hom) ) and HasName( Range(hom) ) ) then 
        Print( Source(hom), " -> ", Range(hom), "\n" ); 
    fi; 
    Print( PiecesOfMapping( hom ) );  
end );

InstallMethod( PrintObj, "for a groupoid homomorphism", true,
    [ IsGroupoidHomomorphism ], 0, 
function ( hom ) 

    local h; 

    if HasPiecesOfMapping( hom ) then 
        Print( "groupoid homomorphism from several pieces : \n" );
        for h in PiecesOfMapping( hom ) do 
            Print( h, "\n" ); 
        od; 
    else 
        Print( "groupoid homomorphism : " );
        if ( HasName( Source(hom) ) and HasName( Range(hom) ) ) then 
            Print( Source(hom), " -> ", Range(hom), "\n" ); 
        elif IsGroupoidHomomorphismFromHomogeneousDiscrete( hom ) then 
            Print( "morphism from a homogeneous discrete groupoid:\n" ); 
            Print( ObjectList(Source(hom)), " -> ", 
                   ImagesOfObjects(hom), "\n" ); 
            Print( "object homomorphisms:\n" );  
            for h in ObjectHomomorphisms( hom ) do 
                Print( h, "\n" ); 
            od; 
        else 
            Print( MappingToSinglePieceData( hom ) ); 
        fi; 
    fi;
end ); 

#############################################################################
##
#M  Display
##
InstallMethod( Display, "for a homomorphsim to a single piece magma", true,
    [ IsHomomorphismToSinglePiece ], 0,
function ( hom )

    local homs, imo, src, rng, isgpd, pieces, i, c, maps, map1, mgi, len;

    Info( InfoGroupoids, 2, "first display method for homs in mwohom.gi" );
    src := Source( hom );
    rng := Range( hom );
    isgpd := "IsGroupoid" in CategoriesOfObject(rng); 
    if isgpd then 
        Print( "homomorphism to single piece groupoid" );
    else 
        Print( "homomorphism to single piece magma" );
    fi;
    imo := ImagesOfObjects( hom ); 
    if HasMappingToSinglePieceMaps( hom ) then 
        maps := MappingToSinglePieceMaps( hom ); 
    else 
        maps := MappingToSinglePieceData( hom );
    fi;
    len := Length( maps );
    if ( len = 1 ) then 
        if ( HasName( src ) and HasName( rng ) ) then 
            Print( ": ", src, " -> ", rng, "\n" ); 
        else 
            Print( ":\n" );
            Print( "[ ", src, " ] -> [ ", rng, " ]\n" );
        fi; 
        map1 := maps[1]; 
        if isgpd then 
            Print( "root group homomorphism:\n" );
            mgi := MappingGeneratorsImages( map1[1] );
            for i in [1..Length( mgi[1] )] do
                Print( mgi[1][i], " -> " );
                Display( mgi[2][i] );
            od;
        else 
            Print( " magma hom: " ); 
            Display( map1[1] ); 
        fi;
        Print( "object map: ", src!.objects, " -> ", imo, "\n"); 
        if ( Length( map1 ) > 2 ) then 
            Print( "ray images: ", map1[3], "\n" );
        fi; 
    else
        Print( " with mappings:\n" );
        for i in [1..len] do
            Print( "(", i, ") : " ); 
            Display( maps[i] );
        od;
    fi;
end );

InstallMethod( Display, "generic method for a magma mapping", true,
    [ IsGeneralMappingWithObjects ], 0,
function ( hom )

    local src, rng, isgpd, chom, pieces, i, c, maps, len;

    Info( InfoGroupoids, 2, "second display method for homs in mwohom.gi" );
    src := Source( hom );
    rng := Range( hom );
    isgpd := ( "IsGroupoid" in CategoriesOfObject( src ) ) and
             ( "IsGroupoid" in CategoriesOfObject( rng ) );   
    if isgpd then 
        Print( "groupoid homomorphism: " );
    else
        Print( "magma homomorphism: " );
    fi;
    Print( Source( hom ), " -> ",  Range( hom ), " with pieces :\n" );
    for chom in PiecesOfMapping( hom ) do
        src := Source( chom );
        rng := Range( chom );
        if HasMappingToSinglePieceMaps( chom ) then 
            maps := MappingToSinglePieceMaps( chom ); 
        else 
            maps := MappingToSinglePieceData( chom );
        fi;
        len := Length( maps );
        if ( len = 1 ) then
            Display( maps[1] ); 
        else 
            for i in [1..len] do 
                Print( "(", i, ") : " ); 
                Display( maps[i] ); 
            od;
        fi;
    od;
end );

#############################################################################
##
#M  ImageElm( <map>, <e> )
##
InstallOtherMethod( ImageElm, "for a magma with objects hom", true,
   [ IsHomomorphismToSinglePiece, IsMultiplicativeElementWithObjects ], 0,
function ( map, e )

    local G1, ce, C1, pe, Ge, obs1, hom, obs2, mag2, t2, h2, g2;

    #?  need to include some tests here ?? 
    Info( InfoGroupoids, 3, 
          "this is the first ImageElm function in mwohom.gi" ); 
    G1 := Source( map );
    ce := PieceOfObject( G1, e![3] );
    C1 := Pieces( G1 );
    pe := Position( C1, ce );
    Ge := C1[pe];
    obs1 := Ge!.objects;
    hom := MappingToSinglePieceData( map )[pe][1];
    obs2 := MappingToSinglePieceData( map )[pe][2]; 
    #?  this is not the correct range magma ??
    mag2 := Range( map ); 
    t2 := obs2[ Position( obs1, e![3] ) ];
    h2 := obs2[ Position( obs1, e![4] ) ]; 
    g2 := ImageElm( hom, e![2] );
    return MultiplicativeElementWithObjects( mag2, g2, t2, h2 );
end );

InstallOtherMethod( ImageElm, "for a magma with objects hom", true,
   [ IsGeneralMappingWithObjects, IsMultiplicativeElementWithObjects ], 0,
function ( map, e )

    local M1, C1, pe, obs1, pom, pim, obs2, t2, h2, g2; 

    Info( InfoGroupoids, 3, 
          "this is the second ImageElm function in mwohom.gi" ); 
    M1 := Source( map ); 
    C1 := Pieces( M1 );
    pe := Position( C1, PieceOfObject( M1, e![3] ) ); 
    obs1 := C1[pe]!.objects; 
    pom := PiecesOfMapping( map )[pe]; 
    pim := MappingToSinglePieceData( pom )[1];
    obs2 := pim[2]; 
    t2 := obs2[ Position( obs1, e![3] ) ];
    h2 := obs2[ Position( obs1, e![4] ) ]; 
    g2 := ImageElm( pim[1], e![2] );
    return MultiplicativeElementWithObjects( Range( map ), g2, t2, h2 );
end ); 

InstallOtherMethod( ImageElm, "for a magma with objects endomorphism", true,
    [ IsHomomorphismToSinglePiece and IsEndomorphismWithObjects, 
      IsMultiplicativeElementWithObjects ], 0,
function ( map, elt )

    local mag, obs, one, gensims, gens, ims, rhom, 
          e, j, ej, pj, k, ek, pk, r, im;

    Info( InfoGroupoids, 3, 
          "this is the third ImageElm function in mwohom.gi" ); 
    mag := Source( map );
    obs := mag!.objects; 
    one := One( mag!.magma );
    gensims := MappingGeneratorsImages( map )[1];
    gens := gensims[1]; 
    ims := gensims[2];
    #? (13/09/17) was: rhom := HomsOfMapping( map )[1]; 
    rhom := MappingToSinglePieceData( map )[1][1]; 
    e := ImageElm( rhom, elt![2] ); 
    j := elt![2];
    pj := Position( obs, elt![3] );
    k := elt![3];
    pk := Position( obs, elt![4] );
    r := Length( GeneratorsOfMagma( Source( rhom ) ) ); 
    ## n := Length( m!.objects ); 
    if ( pj = 1 ) then 
        ej := one;
    else
        ej := ims[r+pj-1]![2]; 
    fi;
    if ( pk = 1 ) then
        ek := one;
    else
        ek := ims[r+pk-1]![2]; 
    fi; 
    #?  MagmaElement only requires two parameters ??
    im := MagmaElement( mag, ej^(-1)*e*ek, j, k );
    return im;
end );

InstallOtherMethod( ImageElm, "for a mapping with objects by function", true,
   [ IsMappingWithObjectsByFunction, IsMultiplicativeElementWithObjects ], 10,
function ( map, e )

    local fun, fe, obs, imo, pt, ph; 

    Info( InfoGroupoids, 3, 
          "this is the fourth ImageElm function in mwohom.gi" ); 
    fun := UnderlyingFunction( map ); 
    fe := fun( e ); 
    obs := Source( map )!.objects; 
    imo := ImagesOfObjects( map );
    pt := Position( obs, e![3] ); 
    ph := Position( obs, e![4] ); 
    if not ( ( fe![3] = imo[pt] ) and ( fe![4] = imo[ph] ) ) then 
        Error( "wrong objects in ImageElm" );
    else 
        return fe; 
    fi;
end ); 

InstallOtherMethod( ImagesSource, "for a magma mapping", true, 
    [ IsHomomorphismToSinglePiece ], 0,
function ( map )

    local src, par, impar, gens, imgs, imo, hom, img, rng;

    Info( InfoGroupoids, 3, "ImagesSource for a map to a single piece" ); 
    if not IsInjectiveOnObjects( map ) then
        Error( "not yet implemented when not injective on objects" );
    fi;
    src := Source( map );
    if not IsSinglePiece( src ) then 
        Error( "not yet implemented when source not a single piece" ); 
    fi; 
    if HasParentMappingGroupoids( map ) then 
        par := ParentMappingGroupoids( map ); 
        impar := ImagesSource( par );
        gens := GeneratorsOfGroupoid( src );
        imgs := List( gens, g -> ImageElm( map, g ) ); 
        return SinglePieceSubgroupoidByGenerators( impar, imgs ); 
    fi;
    imo := ShallowCopy( ImagesOfObjects( map ) );
    Sort( imo );
    hom := MappingToSinglePieceData( map )[1][1];
    img := Image( hom );
    rng := Range( map );
    if ( ( imo = rng!.objects ) and ( img = rng!.magma ) ) then
        return rng;
    elif HasLargerDirectProductGroupoid( rng ) then 
        return SubdomainWithObjects( 
                   LargerDirectProductGroupoid( rng ), [ [ img, imo ] ] );
    else
        return SubdomainWithObjects( rng, [ [ img, imo ] ] );
    fi;
end );

InstallOtherMethod( ImagesSource, "for a magma mapping", true,
    [ IsMagmaWithObjectsHomomorphism ], 0,
function ( map )
    Error( "not yet implemented when Range(map) is not single piece" );
    Info( InfoGroupoids, 3, "ImagesSource for a map to more than one piece" ); 
end );

#############################################################################
##
#M  IsEndoGeneralMapping( <map> )
##
InstallMethod( IsEndoGeneralMapping, "for a mwo mapping", true,
  [ IsMagmaWithObjectsHomomorphism ], 0,
function ( map ) 

    local obs; 

    obs := Source( map )!.objects; 
    return ForAll( MappingToSinglePieceData( map ), 
        c -> ( IsEndoGeneralMapping( c[1] ) and IsSubset( obs, c[2] ) ) ); 
end ); 

[ Dauer der Verarbeitung: 0.111 Sekunden  ]