Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/cap/gap/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 22.8.2025 mit Größe 61 kB image not shown  

Quelle  ToolsForCategories.gi   Sprache: unbekannt

 
# SPDX-License-Identifier: GPL-2.0-or-later
# CAP: Categories, Algorithms, Programming
#
# Implementations
#

##
# some options should affect the whole function stack and should hence not be consumed by FunctionWithNamedArguments
BindGlobal( "CAP_INTERNAL_GLOBAL_OPTIONS", [ "no_precompiled_code" ] );

InstallGlobalFunction( "FunctionWithNamedArguments", function ( specification, func )
    
    Assert( 0, IsList( specification ) );
    Assert( 0, IsFunction( func ) );
    Assert( 0, ForAll( specification, x -> IsList( x ) and Length( x ) = 2 and IsString( x[1] ) and not IsMutable( x[2] ) ) );
    Assert( 0, NumberArgumentsFunction( func ) >= 1 or NumberArgumentsFunction( func ) <= -2 );
    Assert( 0, NamesLocalVariablesFunction( func )[1] = "CAP_NAMED_ARGUMENTS" );
    
    return function ( args... )
      local CAP_NAMED_ARGUMENTS, current_options, result, s;
        
        CAP_NAMED_ARGUMENTS := rec( );
        
        if IsEmpty( OptionsStack ) then
            
            current_options := rec( );
            
        else
            
            current_options := Last( OptionsStack );
            
        fi;
        
        for s in specification do
            
            if IsBound( current_options.(s[1]) ) then
                
                CAP_NAMED_ARGUMENTS.(s[1]) := current_options.(s[1]);
                
                if not s[1] in CAP_INTERNAL_GLOBAL_OPTIONS then
                    
                    Unbind( current_options.(s[1]) );
                    
                fi;
                
            else
                
                CAP_NAMED_ARGUMENTS.(s[1]) := s[2];
                
            fi;
            
        od;
        
        result := CallFuncListWrap( func, Concatenation( [ CAP_NAMED_ARGUMENTS ], args ) );
        
        if Length( result ) = 1 then
            
            return result[1];
            
        fi;
        
        Assert( 0, Length( result ) = 0 );
        
    end;
    
end );

#####################################
##
## Install add
##
#####################################

InstallGlobalFunction( "CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING", function ( string, args... )
  local category, is_ring_element, ring, n;
    
    if not IsString( string ) then
        
        Error( string, " is not a string" );
        
    fi;
    
    if Length( args ) > 1 then
        
        Error( "CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING must be called with at most two arguments" );
        
    elif Length( args ) = 1 then
        
        category := args[1];
        
    else
        
        category := false;
        
    fi;
    
    if string = "pair_of_morphisms" then
        
        string := "2_tuple_of_morphisms";
        
    fi;
    
    if string = "bool" then
        
        return rec( filter := IsBool );
        
    elif string = "integer" then
        
        return rec( filter := IsInt );
        
    elif string = "nonneg_integer_or_infinity" then
        
        return rec( filter := IsCyclotomic );
        
    elif string = "category" then
        
        return CapJitDataTypeOfCategory( category );
        
    elif string = "object" then
        
        return CapJitDataTypeOfObjectOfCategory( category );
        
    elif string = "morphism" then
        
        return CapJitDataTypeOfMorphismOfCategory( category );
        
    elif string = "twocell" then
        
        return CapJitDataTypeOfTwoCellOfCategory( category );
        
    elif string = "list_of_objects" then
        
        return CapJitDataTypeOfListOf( CapJitDataTypeOfObjectOfCategory( category ) );
        
    elif string = "list_of_morphisms" then
        
        return CapJitDataTypeOfListOf( CapJitDataTypeOfMorphismOfCategory( category ) );
        
    elif string = "list_of_lists_of_morphisms" then
        
        return CapJitDataTypeOfListOf( CapJitDataTypeOfListOf( CapJitDataTypeOfMorphismOfCategory( category ) ) );
        
    elif string = "list_of_twocells" then
        
        return CapJitDataTypeOfListOf( CapJitDataTypeOfTwoCellOfCategory( category ) );
        
    elif string = "object_in_range_category_of_homomorphism_structure" then
        
        if not IsIdenticalObj( category, false ) and not HasRangeCategoryOfHomomorphismStructure( category ) then
            
            Display( Concatenation( "WARNING: You are calling an Add function for a CAP operation for \"", Name( category ), "\" which is part of a homomorphism structure but the category has no RangeCategoryOfHomomorphismStructure (yet)" ) );
            
        fi;
        
        if IsIdenticalObj( category, false ) or not HasRangeCategoryOfHomomorphismStructure( category ) then
            
            return CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( "object" );
            
        else
            
            return CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( "object", RangeCategoryOfHomomorphismStructure( category ) );
            
        fi;
        
    elif string = "morphism_in_range_category_of_homomorphism_structure" then
        
        if not IsIdenticalObj( category, false ) and not HasRangeCategoryOfHomomorphismStructure( category ) then
            
            Display( Concatenation( "WARNING: You are calling an Add function for a CAP operation for \"", Name( category ), "\" which is part of a homomorphism structure but the category has no RangeCategoryOfHomomorphismStructure (yet)" ) );
            
        fi;
        
        if IsIdenticalObj( category, false ) or not HasRangeCategoryOfHomomorphismStructure( category ) then
            
            return CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( "morphism" );
            
        else
            
            return CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( "morphism", RangeCategoryOfHomomorphismStructure( category ) );
            
        fi;
        
    elif string = "object_datum" then
        
        if not IsIdenticalObj( category, false ) then
            
            # might be `fail`
            return ObjectDatumType( category );
            
        else
            
            return fail;
            
        fi;
        
    elif string = "morphism_datum" then
        
        if not IsIdenticalObj( category, false ) then
            
            # might be `fail`
            return MorphismDatumType( category );
            
        else
            
            return fail;
            
        fi;
        
    elif string = "element_of_commutative_ring_of_linear_structure" then
        
        if not IsIdenticalObj( category, false ) and not HasCommutativeRingOfLinearCategory( category ) then
            
            Print( "WARNING: You are calling an Add function for a CAP operation for \"", Name( category ), "\" which is part of the linear structure over a commutative ring but the category has no CommutativeRingOfLinearCategory (yet).\n" );
            
        fi;
        
        if IsIdenticalObj( category, false ) or not HasCommutativeRingOfLinearCategory( category ) then
            
            return CapJitDataTypeOfElementOfRing( false );
            
        fi;
        
        return CapJitDataTypeOfElementOfRing( CommutativeRingOfLinearCategory( category ) );
        
    elif string = "list_of_elements_of_commutative_ring_of_linear_structure" then
        
        return CapJitDataTypeOfListOf( CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( "element_of_commutative_ring_of_linear_structure", category ) );
        
    elif string = "list_of_integers_and_list_of_morphisms" then
        
        return CapJitDataTypeOfNTupleOf( 2,
                       CapJitDataTypeOfListOf( IsInt ),
                       CapJitDataTypeOfListOf( CapJitDataTypeOfMorphismOfCategory( category ) ) );
        
    elif string = "arbitrary_list" then
        
        return CapJitDataTypeOfListOf( IsObject );
        
    elif EndsWith( string, "_tuple_of_morphisms" ) and ForAll( string{[ 1 .. Length( string ) - Length( "_tuple_of_morphisms" ) ]}, IsDigitChar ) then
        
        n := Int( string{[ 1 .. Length( string ) - Length( "_tuple_of_morphisms" ) ]} );
        
        return rec(
            filter := IsNTuple,
            element_types := ListWithIdenticalEntries( n, CapJitDataTypeOfMorphismOfCategory( category ) ),
        );
        
    else
        
        Error( "filter type ", string, " is not recognized, see the documentation for allowed values" );
        
    fi;
    
end );

InstallGlobalFunction( CAP_INTERNAL_GET_DATA_TYPES_FROM_STRINGS,
  
  function( list, args... )
    local category;
    
    if Length( args ) > 1 then
        
        Error( "CAP_INTERNAL_GET_DATA_TYPES_FROM_STRINGS must be called with at most two arguments" );
        
    elif Length( args ) = 1 then
        
        category := args[1];
        
    else
        
        category := false;
        
    fi;
    
    return List( list, l -> CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( l, category ) );
    
end );

InstallGlobalFunction( CAP_INTERNAL_REPLACED_STRING_WITH_FILTER,
  
  function( filter_string, args... )
    local category, data_type;
    
    if Length( args ) > 1 then
        
        Error( "CAP_INTERNAL_REPLACED_STRING_WITH_FILTER must be called with at most two arguments" );
        
    elif Length( args ) = 1 then
        
        category := args[1];
        
    else
        
        category := false;
        
    fi;
    
    data_type := CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( filter_string, category );
    
    if data_type = fail then
        
        return IsObject;
        
    elif IsSpecializationOfFilter( IsNTuple, data_type.filter ) then
        
        # `IsNTuple` deliberately does not imply `IsList` because we want to treat tuples and lists in different ways in CompilerForCAP.
        # However, on the GAP level tuples are just dense lists.
        return IsDenseList;
        
    else
        
        return data_type.filter;
        
    fi;
    
end );

InstallGlobalFunction( CAP_INTERNAL_REPLACED_STRINGS_WITH_FILTERS,
  
  function( list, args... )
    local category;
    
    if Length( args ) > 1 then
        
        Error( "CAP_INTERNAL_REPLACED_STRINGS_WITH_FILTERS must be called with at most two arguments" );
        
    elif Length( args ) = 1 then
        
        category := args[1];
        
    else
        
        category := false;
        
    fi;
    
    return List( list, l -> CAP_INTERNAL_REPLACED_STRING_WITH_FILTER( l, category ) );
    
end );

InstallGlobalFunction( CAP_INTERNAL_REPLACED_STRINGS_WITH_FILTERS_FOR_JULIA,
  
  function( list, args... )
    local category;
    
    if Length( args ) > 1 then
        
        Error( "CAP_INTERNAL_REPLACED_STRINGS_WITH_FILTERS_FOR_JULIA must be called with at most two arguments" );
        
    elif Length( args ) = 1 then
        
        category := args[1];
        
    else
        
        category := false;
        
    fi;
    
    return List( list, function ( l )
      local filter;
        
        filter := CAP_INTERNAL_REPLACED_STRING_WITH_FILTER( l, category );
        
        if filter = IsList then
            
            return ValueGlobal( "IsJuliaObject" );
            
        else
            
            return filter;
            
        fi;
        
    end );
    
end );

InstallGlobalFunction( "CAP_INTERNAL_ASSERT_VALUE_IS_OF_TYPE_GETTER",
  
  function( data_type, human_readable_identifier_getter )
    local generic_help_string, filter, asserts_value_is_of_element_type, assert_value_is_of_element_type;
    
    Assert( 0, IsFunction( human_readable_identifier_getter ) );
    
    generic_help_string := " You can access the value via the local variable 'value' in a break loop.";
    
    filter := data_type.filter;
    
    # `IsBool( fail ) = true`, but we do not want to include `fail`
    if IsSpecializationOfFilter( IsBool, filter ) then
        
        return function( value, args... )
            
            if not (value = true or value = false) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " is neither `true` nor `false`.", generic_help_string );
                
            fi;
            
        end;
        
    elif IsSpecializationOfFilter( IsFunction, filter ) then
        
        return function( value, args... )
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
            if NumberArgumentsFunction( value ) >= 0 and NumberArgumentsFunction( value ) <> Length( data_type.signature[1] ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " has ", NumberArgumentsFunction( value ), " arguments but ", Length( data_type.signature[1] ), " were expected.", generic_help_string );
                
            fi;
            
        end;
        
    elif IsSpecializationOfFilter( IsList, filter ) then
        
        assert_value_is_of_element_type := CAP_INTERNAL_ASSERT_VALUE_IS_OF_TYPE_GETTER( data_type.element_type, { i, outer_args } -> Concatenation( "the ", String( i ), ". entry of ", CallFuncList( human_readable_identifier_getter, outer_args ) ) );
        
        return function( value, args... )
          local i;
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
            for i in [ 1 .. Length( value ) ] do
                
                #= comment for Julia
                # Julia does not have non-dense lists
                if not IsBound( value[i] ) then
                    
                    Error( "the ", i, ". entry of ", CallFuncList( human_readable_identifier_getter, args ), " is not bound.", generic_help_string );
                    
                fi;
                # =#
                
                assert_value_is_of_element_type( value[i], i, args );
                
            od;
            
        end;
        
    elif IsSpecializationOfFilter( IsNTuple, filter ) then
        
        asserts_value_is_of_element_type := List( [ 1 .. Length( data_type.element_types ) ], i -> CAP_INTERNAL_ASSERT_VALUE_IS_OF_TYPE_GETTER( data_type.element_types[i], { outer_args } -> Concatenation( "the ", String( i ), ". entry of ", CallFuncList( human_readable_identifier_getter, outer_args ) ) ) );
        
        return function( value, args... )
          local i;
            
            # tuples are modeled as lists
            if not IsDenseList( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter IsDenseList (implementation filter of IsNTuple).", generic_help_string );
                
            fi;
            
            if Length( value ) <> Length( data_type.element_types ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " has length ", Length( value ), " but ", Length( data_type.element_types ), " was expected.", generic_help_string );
                
            fi;
            
            for i in [ 1 .. Length( value ) ] do
                
                asserts_value_is_of_element_type[i]( value[i], args );
                
            od;
            
        end;
        
    elif IsSpecializationOfFilter( IsCapCategory, filter ) then
        
        return function( value, args... )
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
            if IsBound( data_type.category ) and not IsIdenticalObj( data_type.category, false ) and not IsIdenticalObj( value, data_type.category ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " is not the expected category although it lies in the category filter of the expected category. This should never happen, please report this using the CAP_project's issue tracker.", generic_help_string );
                
            fi;
            
        end;
        
    elif IsSpecializationOfFilter( IsCapCategoryObject, filter ) then
        
        return function( value, args... )
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
            CAP_INTERNAL_ASSERT_IS_OBJECT_OF_CATEGORY( value, data_type.category, {} -> CallFuncList( human_readable_identifier_getter, args ) );
            
        end;
        
    elif IsSpecializationOfFilter( IsCapCategoryMorphism, filter ) then
        
        return function( value, args... )
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
            CAP_INTERNAL_ASSERT_IS_MORPHISM_OF_CATEGORY( value, data_type.category, {} -> CallFuncList( human_readable_identifier_getter, args ) );
            
        end;
        
    elif IsSpecializationOfFilter( IsCapCategoryTwoCell, filter ) then
        
        return function( value, args... )
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
            CAP_INTERNAL_ASSERT_IS_TWO_CELL_OF_CATEGORY( value, data_type.category, {} -> CallFuncList( human_readable_identifier_getter, args ) );
            
        end;
        
    else
        
        return function( value, args... )
            
            if not filter( value ) then
                
                Error( CallFuncList( human_readable_identifier_getter, args ), " does not lie in the expected filter ", filter, ".", generic_help_string );
                
            fi;
            
        end;
        
    fi;
    
end );

InstallGlobalFunction( CAP_INTERNAL_RETURN_OPTION_OR_DEFAULT,
    
  function( option_name, default )
    local value;
    
    value := ValueOption( option_name );
    
    if value = fail then
        return default;
    fi;
    
    return value;
end );

BindGlobal( "CAP_INTERNAL_REPLACE_ADDITIONAL_SYMBOL_APPEARANCE",
  
  function( appearance_list, replacement_record )
    local remove_list, new_appearances, current_appearance, pos, current_appearance_nr, current_replacement, i;
    
    appearance_list := StructuralCopy( appearance_list );
    
    remove_list := [];
    new_appearances := [];
    
    for current_appearance_nr in [ 1 .. Length( appearance_list ) ] do
        
        current_appearance := appearance_list[ current_appearance_nr ];
        
        if IsBound( replacement_record.(current_appearance[1]) ) then
            
            Add( remove_list, current_appearance_nr );
            
            for current_replacement in replacement_record.(current_appearance[1]) do
                
                pos := PositionProperty( appearance_list, x -> x[1] = current_replacement[1] and x[3] = current_appearance[3] );
                
                if pos = fail then
                    
                    Add( new_appearances, [ current_replacement[ 1 ], current_replacement[ 2 ] * current_appearance[ 2 ], current_appearance[3] ] );
                    
                else
                    
                    appearance_list[pos][2] := appearance_list[pos][2] + current_replacement[ 2 ] * current_appearance[ 2 ];
                    
                fi;
                
            od;
            
        fi;
        
    od;
    
    for i in Reversed( remove_list ) do
        
        Remove( appearance_list, i );
        
    od;
    
    return Concatenation( appearance_list, new_appearances );
    
end );

##
InstallGlobalFunction( "CAP_INTERNAL_FIND_APPEARANCE_OF_SYMBOL_IN_FUNCTION",
  
  function( func, symbol_list, loop_multiple, replacement_record, category_getters )
    local func_as_string, func_stream, func_as_list, loop_power, symbol_appearance_list, current_symbol, category_getter, pos, i;
    
    if IsOperation( func ) then
        
        func_as_string := NameFunction( func );
        
    else
        
        func_as_string := "";
        
        func_stream := OutputTextString( func_as_string, false );
        
        SetPrintFormattingStatus( func_stream, false );
        
        PrintTo( func_stream, func );
        
        CloseStream( func_stream );
        
    fi;
    
    RemoveCharacters( func_as_string, "()[];," );
    
    NormalizeWhitespace( func_as_string );
    
    func_as_list := SplitString( func_as_string, " " );
    
    loop_power := 0;
    
    symbol_appearance_list := [ ];
    
    symbol_list := Concatenation( symbol_list, RecNames( replacement_record ) );
    
    # remove first "function" and last "end"
    Assert( 0, func_as_list[1] = "function" );
    Assert( 0, Last( func_as_list ) = "end" );
    
    func_as_list := func_as_list{[ 2 .. Length( func_as_list ) - 1 ]};
    
    for i in [ 1 .. Length( func_as_list ) ] do
        
        current_symbol := func_as_list[i];
        
        if current_symbol in symbol_list then
            
            # function cannot end with a symbol
            Assert( 0, i < Length( func_as_list ) );
            
            if IsBound( category_getters.(func_as_list[i + 1]) ) then
                
                category_getter := category_getters.(func_as_list[i + 1]);
                
            else
                
                category_getter := fail;
                
            fi;
            
            pos := PositionProperty( symbol_appearance_list, x -> x[1] = current_symbol and x[3] = category_getter );
            
            if pos = fail then
                
                Add( symbol_appearance_list, [ current_symbol, loop_multiple^loop_power, category_getter ] );
                
            else
                
                symbol_appearance_list[pos][2] := symbol_appearance_list[pos][2] + loop_multiple^loop_power;
                
            fi;
            
        # Technically, the head of a "for" loop is only executed once.
        # We could simply start the detection at "do", but this would exclude the header of "while" loops
        # which indeed is executed multiple times.
        elif current_symbol in [ "for", "while", "repeat", "function" ] then
            
            loop_power := loop_power + 1;
            
        # Technically, the part after "until" is also executed multiple times.
        elif current_symbol in [ "od", "until", "end" ] then
            
            loop_power := loop_power - 1;
            
        fi;
        
    od;
    
    if loop_power <> 0 then
        
        Error( "The automated detection of CAP operations could not detect loops properly. If the reserved word `for` appears in <func_as_string> (e.g. in a string), this is probably the cause. If not, please report this as a bug mentioning <func_as_string>." );
        
    fi;
    
    symbol_appearance_list := CAP_INTERNAL_REPLACE_ADDITIONAL_SYMBOL_APPEARANCE( symbol_appearance_list, replacement_record );
    return symbol_appearance_list;
    
end );

##
InstallGlobalFunction( CAP_INTERNAL_MERGE_PRECONDITIONS_LIST,
  
  function( list1, list2 )
    local pos, current_precondition;
    
    list2 := List( list2, x -> ShallowCopy( x ) );
    
    for current_precondition in list1 do
        
        pos := PositionProperty( list2, x -> x[1] = current_precondition[1] and x[3] = current_precondition[3] );
        
        if pos = fail then
            
            Add( list2, current_precondition );
            
        else
            
            list2[pos][2] := Maximum( list2[pos][2], current_precondition[2] );
            
        fi;
        
    od;
    
    return list2;
    
end );

##
InstallGlobalFunction( ListKnownCategoricalProperties,
                      
  function( category )
    local list, name;
    
    if not IsCapCategory( category ) then
      
      Error( "the input is not a category" );
      
    fi;
    
    list := [ ];
    
    for name in Set( Filtered( Concatenation( CAP_INTERNAL_CATEGORICAL_PROPERTIES_LIST ), x -> x <> fail ) ) do
      
      if Tester( ValueGlobal( name ) )( category ) and ValueGlobal( name )( category ) then
        
        Add( list, name );
      
      fi;
      
    od;
    
    return list;
    
end );

InstallGlobalFunction( HelpForCAP,
  
  function()
    local filename, stream, string;
    
    filename := DirectoriesPackageLibrary( "CAP", "" );
    filename := filename[ 1 ];
    filename := Filename( filename, "help_for_CAP.md" );
    
    stream := InputTextFile( filename );
    string := ReadAll( stream );
    CloseStream( stream );
    
    Print( string );
    
end );

InstallGlobalFunction( CachingStatistic,
  
  function( category, arg... )
    local operations, current_cache_name, current_cache;
    
    operations := arg;
    
    if Length( operations ) = 0 then
        operations := RecNames( category!.caches );
    fi;
    
    operations := ShallowCopy( operations );
    Sort( operations );
    
    Print( "Caching statistics for category ", Name( category ), "\n" );
    Print( "===============================================\n" );
    
    for current_cache_name in operations do
        Print( current_cache_name, ": " );
        if not IsBound( category!.caches.(current_cache_name) ) then
            Print( "not installed yet\n" );
            continue;
        fi;
        current_cache := category!.caches.(current_cache_name);
        if IsDisabledCache( current_cache ) then
            Print( "disabled\n" );
            continue;
        fi;
        if IsWeakCache( current_cache ) then
            Print( "weak cache, " );
        elif IsCrispCache( current_cache ) then
            Print( "crisp cache, " );
        fi;
        Print( "hits: ", String( current_cache!.hit_counter ), ", misses: ", String( current_cache!.miss_counter ), ", " );
        Print( String( Length( PositionsProperty( current_cache!.value, ReturnTrue ) ) ), " objects stored\n" );
    od;
    
end );

InstallGlobalFunction( InstallDeprecatedAlias,
  
  function( alias_name, function_name, deprecation_date )
    
    #= comment for Julia
    BindGlobal( alias_name, function ( args... )
      local result;
        
        Print(
          Concatenation(
          "WARNING: ", alias_name, " is deprecated and will not be supported after ", deprecation_date, ". Please use ", function_name, " instead.\n"
          )
        );
        
        result := CallFuncListWrap( ValueGlobal( function_name ), args );
        
        if not IsEmpty( result ) then
            
            return result[1];
            
        fi;
        
    end );
    # =#
    
end );

##
InstallGlobalFunction( "IsSpecializationOfFilter", function ( filter_1, filter_2 )
  local data_type_1, data_type_2;
    
    if IsString( filter_1 ) then
        
        data_type_1 := CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( filter_1 );
        
        if data_type_1 = fail then
            
            filter_1 := IsObject;
            
        else
            
            filter_1 := data_type_1.filter;
            
        fi;
        
    fi;
    
    if IsString( filter_2 ) then
        
        data_type_2 := CAP_INTERNAL_GET_DATA_TYPE_FROM_STRING( filter_2 );
        
        if data_type_2 = fail then
            
            filter_2 := IsObject;
            
        else
            
            filter_2 := data_type_2.filter;
            
        fi;
        
    fi;
    
    return IS_SUBSET_FLAGS( WITH_IMPS_FLAGS( FLAGS_FILTER( filter_2 ) ), WITH_IMPS_FLAGS( FLAGS_FILTER( filter_1 ) ) );
    
end );

##
InstallGlobalFunction( "IsSpecializationOfFilterList", function ( filter_list1, filter_list2 )
    
    if filter_list1 = "any" then
        
        return true;
        
    elif filter_list2 = "any" then
        
        return false;
        
    fi;
    
    return Length( filter_list1 ) = Length( filter_list2 ) and ForAll( [ 1 .. Length( filter_list1 ) ], i -> IsSpecializationOfFilter( filter_list1[i], filter_list2[i] ) );
    
end );

##
InstallGlobalFunction( InstallMethodForCompilerForCAP,
  
  function( args... )
    local operation, method, filters;
    
    # let InstallMethod do the type checking
    CallFuncList( InstallMethod, args );
    
    operation := First( args );
    method := Last( args );
    
    if IsList( args[Length( args ) - 1] ) then
        
        filters := args[Length( args ) - 1];
        
    elif IsList( args[Length( args ) - 2] ) then
        
        filters := args[Length( args ) - 2];
        
    else
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "this should never happen" );
        
    fi;
    
    CapJitAddKnownMethod( operation, filters, method );
    
end );

##
InstallGlobalFunction( InstallOtherMethodForCompilerForCAP,
  
  function( args... )
    local operation, method, filters;
    
    # let InstallOtherMethod do the type checking
    CallFuncList( InstallOtherMethod, args );
    
    operation := First( args );
    method := Last( args );
    
    if IsList( args[Length( args ) - 1] ) then
        
        filters := args[Length( args ) - 1];
        
    elif IsList( args[Length( args ) - 2] ) then
        
        filters := args[Length( args ) - 2];
        
    else
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "this should never happen" );
        
    fi;
    
    CapJitAddKnownMethod( operation, filters, method );
    
end );

##
BindGlobal( "CAP_JIT_INTERNAL_KNOWN_METHODS", rec( ) );

InstallGlobalFunction( CapJitAddKnownMethod,
  
  function( operation, filters, method )
    local operation_name, wrapper_operation_name, known_methods;
    
    if not IsOperation( operation ) or not IsList( filters ) or not IsFunction( method ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "usage: CapJitAddKnownMethod( <operation>, <list of filters>, <method> )" );
        
    fi;
    
    if IsEmpty( filters ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "installing methods without filters is currently not supported" );
        
    fi;
    
    operation_name := NameFunction( operation );
    
    if IsBound( CAP_INTERNAL_METHOD_NAME_RECORD.(operation_name) ) and Length( filters ) = Length( CAP_INTERNAL_METHOD_NAME_RECORD.(operation_name).filter_list ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( operation_name, " is already installed as a CAP operation with the same number of arguments" );
        
    fi;
    
    # check if we deal with a KeyDependentOperation
    if EndsWith( operation_name, "Op" ) then
        
        wrapper_operation_name := operation_name{[ 1 .. Length( operation_name ) - 2 ]};
        
        if IsBoundGlobal( wrapper_operation_name ) and ValueGlobal( wrapper_operation_name ) in WRAPPER_OPERATIONS then
            
            operation_name := wrapper_operation_name;
            
        fi;
        
    fi;
    
    if not IsBound( CAP_JIT_INTERNAL_KNOWN_METHODS.(operation_name) ) then
        
        CAP_JIT_INTERNAL_KNOWN_METHODS.(operation_name) := [ ];
        
    fi;
    
    known_methods := CAP_JIT_INTERNAL_KNOWN_METHODS.(operation_name);
    
    if IsSpecializationOfFilter( "category", filters[1] ) then
        
        if ForAny( known_methods, m -> Length( m.filters ) = Length( filters ) and ( IsSpecializationOfFilter( m.filters[1], filters[1] ) or IsSpecializationOfFilter( filters[1], m.filters[1] ) ) ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "there is already a method known for ", operation_name, " with a category filter which implies the current category filter or is implied by it" );
            
        fi;
        
    else
        
        if IsSpecializationOfFilter( filters[1], "category" ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "The first filter is implied by `IsCapCategory`, this is not supported." );
            
        fi;
        
        if ForAny( known_methods,
            m -> Length( m.filters ) = Length( filters ) and ForAll( [ 1 .. Length( filters ) ], i -> IsSpecializationOfFilter( m.filters[i], filters[i] ) or IsSpecializationOfFilter( filters[i], m.filters[i] ) )
        ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "there is already a method known for ", operation_name, " with a comparable filter list (see documentation of `CapJitAddKnownMethod`)" );
            
        fi;
        
    fi;
    
    Add( known_methods, rec( filters := filters, method := method ) );
    
end );

##
BindGlobal( "CAP_JIT_INTERNAL_TYPE_SIGNATURES", rec( ) );

InstallGlobalFunction( "CapJitAddTypeSignature", function ( name, input_filters, output_data_type )
    
    #= comment for Julia
    if IsCategory( ValueGlobal( name ) ) and Length( input_filters ) = 1 then
        
        Error( "adding type signatures for GAP categories applied to a single argument is not supported" );
        
    fi;
    
    if input_filters <> "any" then
        
        if not IsList( input_filters ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "<input_filters> must be a list or the string \"any\"" );
            
        fi;
        
        if not ForAll( input_filters, filter -> IsFilter( filter ) ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "<input_filters> must be a list of filters or the string \"any\"" );
            
        fi;
        
        if ForAny( input_filters, f -> IsSpecializationOfFilter( IsFunction, f ) ) and (not IsFunction( output_data_type ) or NumberArgumentsFunction( output_data_type ) <> 2) then
            
            if not name in [ "CreateCapCategoryObjectWithAttributes", "CreateCapCategoryMorphismWithAttributes" ] then
                
                # COVERAGE_IGNORE_BLOCK_START
                Print(
                    "WARNING: You are adding a type signature for ", name, " which can get a function as input but you do not compute the signature of the function. ",
                    "This will work for references to global functions but not for literal functions. ",
                    "See `List` in `CompilerForCAP/gap/InferDataTypes.gi` for an example of how to handle the signature of functions properly.\n"
                );
                # COVERAGE_IGNORE_BLOCK_END
                
            fi;
            
        fi;
        
    fi;
    
    if not IsBound( CAP_JIT_INTERNAL_TYPE_SIGNATURES.(name) ) then
        
        CAP_JIT_INTERNAL_TYPE_SIGNATURES.(name) := [ ];
        
    fi;
    
    if ForAny( CAP_JIT_INTERNAL_TYPE_SIGNATURES.(name), signature -> IsSpecializationOfFilterList( signature[1], input_filters ) or IsSpecializationOfFilterList( input_filters, signature[1] ) ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "there already exists a signature for ", name, " with filters implying the current filters or being implied by them" );
        
    fi;
    
    if not ForAny( [ IsFilter, IsRecord, IsFunction ], f -> f( output_data_type ) ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "<output_data_type> must be a filter, a record, or a function" );
        
    fi;
    
    if IsFilter( output_data_type ) then
        
        output_data_type := rec( filter := output_data_type );
        
    fi;
    
    Add( CAP_JIT_INTERNAL_TYPE_SIGNATURES.(name), [ input_filters, output_data_type ] );
    # =#
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfListOf, function ( element_type )
    
    if IsFilter( element_type ) then
        
        element_type := rec( filter := element_type );
        
    fi;
    
    if not IsRecord( element_type ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "<element_type> must be a filter or a record" );
        
    fi;
    
    return rec( filter := IsList, element_type := element_type );
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfNTupleOf, function ( n, element_types... )
    
    Assert( 0, Length( element_types ) = n );
    
    element_types := List( element_types, function ( t )
        
        if IsFilter( t ) then
            
            return rec( filter := t );
            
        else
            
            return t;
            
        fi;
        
    end );
    
    if not ForAll( element_types, t -> IsRecord( t ) ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "<element_types...> must be filters or records" );
        
    fi;
    
    return rec( filter := IsNTuple, element_types := element_types );
    
end );

#= comment for Julia
##
InstallGlobalFunction( CapJitDataTypeOfGroup, function ( group )
  local type;
    
    if IsIdenticalObj( group, false ) then
        
        type := rec(
            filter := IsGroup,
        );
        
    else
        
        type := rec(
            filter := IsGroup,
            group := group,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfElementOfGroup, function ( group )
  local type;
    
    if IsIdenticalObj( group, false ) then
        
        type := rec(
            filter := IsMultiplicativeElementWithInverse,
        );
        
    else
        
        type := rec(
            filter := IsMultiplicativeElementWithInverse,
            group := group,
        );
        
    fi;
    
    return type;
    
end );
# =#

##
InstallGlobalFunction( CapJitDataTypeOfRing, function ( ring )
  local type;
    
    if IsIdenticalObj( ring, false ) then
        
        type := rec(
            filter := IsRing,
        );
        
    else
        
        type := rec(
            filter := RingFilter( ring ),
            ring := ring,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfElementOfRing, function ( ring )
  local type;
    
    if IsIdenticalObj( ring, false ) then
        
        type := rec(
            filter := IsRingElement,
        );
        
    else
        
        type := rec(
            filter := RingElementFilter( ring ),
            ring := ring,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfCategory, function ( cat )
  local type;
    
    if IsIdenticalObj( cat, false ) then
        
        type := rec(
            filter := IsCapCategory,
        );
        
    else
        
        type := rec(
            filter := CategoryFilter( cat ),
            category := cat,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfObjectOfCategory, function ( cat )
  local type;
    
    if IsIdenticalObj( cat, false ) then
        
        type := rec(
            filter := IsCapCategoryObject,
        );
        
    else
        
        type := rec(
            filter := ObjectFilter( cat ),
            category := cat,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfMorphismOfCategory, function ( cat )
  local type;
    
    if IsIdenticalObj( cat, false ) then
        
        type := rec(
            filter := IsCapCategoryMorphism,
        );
        
    else
        
        type := rec(
            filter := MorphismFilter( cat ),
            category := cat,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitDataTypeOfTwoCellOfCategory, function ( cat )
  local type;
    
    if IsIdenticalObj( cat, false ) then
        
        type := rec(
            filter := IsCapCategoryTwoCell,
        );
        
    else
        
        type := rec(
            filter := TwoCellFilter( cat ),
            category := cat,
        );
        
    fi;
    
    return type;
    
end );

##
InstallGlobalFunction( CapJitTypedExpression, function ( value, data_type_getter )
    
    # We try to execute data_type_getter to increase the code coverage.
    # This approach has some downsides:
    # * Previously, the implementation of `CapJitTypedExpression` was simply `ReturnFirst`, which should be faster.
    # * To avoid runtime overhead, we only execute the code below for assertion level >= 2 (which is used in the tests).
    #   However, this leads to a possibly unexpected difference when executing code in tests and by hand.
    # * We can only execute data_type_getter if it has 0 arguments.
    
    Assert( 2, (function ( )
      local data_type;
        
        if NumberArgumentsFunction( data_type_getter ) = 0 then
            
            data_type := data_type_getter( );
            
        elif NumberArgumentsFunction( data_type_getter ) = 1 then
            
            # we do not have access to the category and hence cannot check anything
            return true;
            
        else
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "the data type getter of CapJitTypedExpression must be a function accepting either no argument or a single argument" );
            
        fi;
        
        if IsFilter( data_type ) then
            
            data_type := rec( filter := data_type );
            
        fi;
        
        if not IsRecord( data_type ) or not IsBound( data_type.filter ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "CapJitTypedExpression has returned ", data_type, " which is not a valid data type" );
            
        fi;
        
        # simple plausibility check
        if not data_type.filter( value ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "<value> does not lie in <data_type.filter>" );
            
        fi;
        
        return true;
        
    end)( ) );
    
    return value;
    
end );

##
InstallGlobalFunction( CapFixpoint, function ( predicate, func, initial_value )
  local x, y;
    
    y := initial_value;
    
    while true do
        x := y;
        y := func( x );
        if predicate( x, y ) then
            break;
        fi;
    od;
    
    return y;
    
end );

##
InstallMethod( Iterated,
               [ IsList, IsFunction, IsObject ],
               
  function( list, func, initial_value )
    
    return Iterated( Concatenation( [ initial_value ], list ), func );
    
end );

##
InstallMethod( Iterated,
               [ IsList, IsFunction, IsObject, IsObject ],
               
  function( list, func, initial_value, terminal_value )
    
    return Iterated( Concatenation( [ initial_value ], list, [ terminal_value ] ), func );
    
end );

##
InstallGlobalFunction( TransitivelyNeededOtherPackages, function ( package_name )
  local collected_dependencies, package_info, dep, p;
    
    collected_dependencies := [ package_name ];
    
    for dep in collected_dependencies do
        
        package_info := First( PackageInfo( dep ) );
        
        if package_info = fail then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( dep, " is not the name of an available package" );
            
        fi;
        
        for p in package_info.Dependencies.NeededOtherPackages do
            
            if not p[1] in collected_dependencies then
                
                Add( collected_dependencies, p[1] );
                
            fi;
            
        od;
        
    od;
    
    return collected_dependencies;
    
end );

##
InstallMethod( SafePosition,
               [ IsList, IsObject ],
               
  function( list, obj )
    local pos;
    
    pos := Position( list, obj );
    
    Assert( 0, pos <> fail );
    
    return pos;
    
end );

##
InstallMethod( SafeUniquePosition,
               [ IsList, IsObject ],
               
  function( list, obj )
    local positions;
    
    positions := Positions( list, obj );
    
    Assert( 0, Length( positions ) = 1 );
    
    return positions[1];
    
end );

##
InstallMethod( SafePositionProperty,
               [ IsList, IsFunction ],
               
  function( list, func )
    local pos;
    
    pos := PositionProperty( list, func );
    
    Assert( 0, pos <> fail );
    
    return pos;
    
end );

##
InstallMethod( SafeUniquePositionProperty,
               [ IsList, IsFunction ],
               
  function( list, func )
    local positions;
    
    positions := PositionsProperty( list, func );
    
    Assert( 0, Length( positions ) = 1 );
    
    return positions[1];
    
end );

##
InstallMethod( SafeFirst,
               [ IsList, IsFunction ],
               
  function( list, func )
    local entry;
    
    entry := First( list, func );
    
    Assert( 0, entry <> fail );
    
    return entry;
    
end );

##
InstallMethod( SafeUniqueEntry,
               [ IsList, IsFunction ],
               
  function( list, func )
    local positions;
    
    positions := PositionsProperty( list, func );
    
    Assert( 0, Length( positions ) = 1 );
    
    return list[positions[1]];
    
end );

##
#= comment for Julia
# We want `args` to be a list but in Julia it's a tuple -> we need a separate implementation for Julia
InstallGlobalFunction( NTuple, function ( n, args... )
    
    Assert( 0, Length( args ) = n );
    
    return args;
    
end );
# =#

##
InstallGlobalFunction( Pair, function ( first, second )
    #% CAP_JIT_RESOLVE_FUNCTION
    
    return NTuple( 2, first, second );
    
end );

##
InstallGlobalFunction( Triple, function ( first, second, third )
    #% CAP_JIT_RESOLVE_FUNCTION
    
    return NTuple( 3, first, second, third );
    
end );

##
InstallGlobalFunction( TransposedMatWithGivenDimensions, function ( nr_rows, nr_cols, listlist )
    
    if not ( Length( listlist ) = nr_rows and ForAll( listlist, row -> Length( row ) = nr_cols ) ) then
        Error( "the arguments passed to 'TransposedMatWithGivenDimensions' are inconsistent!\n" );
    fi;
    
    if nr_rows = 0 then
        return List( [ 1 .. nr_cols ], i -> [ ] );
    else
        return TransposedMat( listlist );
    fi;
    
end );

##
InstallGlobalFunction( HandlePrecompiledTowers, FunctionWithNamedArguments(
  [
    [ "no_precompiled_code", false ],
  ],
  function ( CAP_NAMED_ARGUMENTS, category, underlying_category, constructor_name )
    local precompiled_towers, remaining_constructors_in_tower, precompiled_functions_adder, info;
    
    if not IsBound( underlying_category!.compiler_hints ) or not IsBound( underlying_category!.compiler_hints.precompiled_towers ) then
        
        return;
        
    fi;
    
    if not IsList( underlying_category!.compiler_hints.precompiled_towers ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "`underlying_category!.compiler_hints.precompiled_towers` must be a list" );
        
    fi;
    
    precompiled_towers := [ ];
    
    for info in underlying_category!.compiler_hints.precompiled_towers do
        
        if not (IsRecord( info ) and IsBound( info.remaining_constructors_in_tower ) and IsBound( info.precompiled_functions_adder )) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "the entries of `underlying_category!.compiler_hints.precompiled_towers` must be records with components `remaining_constructors_in_tower` and `precompiled_functions_adder`" );
            
        fi;
        
        remaining_constructors_in_tower := info.remaining_constructors_in_tower;
        precompiled_functions_adder := info.precompiled_functions_adder;
        
        if not IsList( remaining_constructors_in_tower ) or IsEmpty( remaining_constructors_in_tower ) then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "`remaining_constructors_in_tower` must be a non-empty list" );
            
        fi;
        
        if not IsFunction( precompiled_functions_adder ) or NumberArgumentsFunction( precompiled_functions_adder ) <> 1 then
            
            # COVERAGE_IGNORE_NEXT_LINE
            Error( "`precompiled_functions_adder` must be a function accepting a single argument" );
            
        fi;
        
        if remaining_constructors_in_tower[1] = constructor_name then
            
            if Length( remaining_constructors_in_tower ) = 1 then
                
                if not CAP_NAMED_ARGUMENTS.no_precompiled_code then
                    
                    # add precompiled functions
                    CallFuncList( precompiled_functions_adder, [ category ] );
                    
                fi;
                
            else
                
                # pass information on to the next level
                Add( precompiled_towers, rec(
                    remaining_constructors_in_tower := remaining_constructors_in_tower{[ 2 .. Length( remaining_constructors_in_tower ) ]},
                    precompiled_functions_adder := precompiled_functions_adder,
                ) );
                
            fi;
            
        fi;
        
    od;
    
    if not IsEmpty( precompiled_towers ) then
        
        if not IsBound( category!.compiler_hints ) then
            
            category!.compiler_hints := rec( );
            
        fi;
        
        if not IsBound( category!.compiler_hints.precompiled_towers ) then
            
            category!.compiler_hints.precompiled_towers := [ ];
            
        fi;
        
        category!.compiler_hints.precompiled_towers := Concatenation( category!.compiler_hints.precompiled_towers, precompiled_towers );
        
    fi;
    
    # return void for Julia
    return;
    
end ) );

InstallGlobalFunction( CAP_JIT_INCOMPLETE_LOGIC, IdFunc );
InstallGlobalFunction( CAP_JIT_EXPR_CASE_WRAPPER, IdFunc );

##
#= comment for Julia
# Julia does not have non-dense lists and thus needs a separate implementation
InstallGlobalFunction( ListWithKeys, function ( list, func )
  local res, i;
    
    # see implementation of `List`
    
    res := EmptyPlist( Length( list ) );
    
    # hack to save type adjustments and conversions (e.g. to blist)
    if Length( list ) > 0 then
        
        res[Length( list )] := 1;
        
    fi;
    
    for i in [ 1 .. Length( list ) ] do
        
        res[i] := func( i, list[i] );
        
    od;
    
    return res;
    
end );
# =#

##
InstallGlobalFunction( SumWithKeys, function ( list, func )
  local sum, i;
    
    # see implementation of `Sum`
    
    if IsEmpty( list ) then
        
        sum := 0;
        
    else
        
        sum := func( 1, list[1] );
        
        for i in [ 2 .. Length( list ) ] do
            
            sum := sum + func( i, list[i] );
            
        od;
        
    fi;
    
    return sum;
    
end );

##
InstallGlobalFunction( ProductWithKeys, function ( list, func )
  local product, i;
    
    # adapted implementation of `Product`
    
    if IsEmpty( list ) then
        
        product := 1;
        
    else
        
        product := func( 1, list[1] );
        
        for i in [ 2 .. Length( list ) ] do
            
            product := product * func( i, list[i] );
            
        od;
        
    fi;
    
    return product;
    
end );

##
InstallGlobalFunction( ForAllWithKeys, function ( list, func )
  local i;
    
    # adapted implementation of `ForAll`
    
    for i in [ 1 .. Length( list ) ] do
        
        if not func( i, list[i] ) then
            
            return false;
            
        fi;
        
    od;
    
    return true;
    
end );

##
InstallGlobalFunction( ForAnyWithKeys, function ( list, func )
  local i;
    
    # adapted implementation of `ForAny`
    
    for i in [ 1 .. Length( list ) ] do
        
        if func( i, list[i] ) then
            
            return true;
            
        fi;
        
    od;
    
    return false;
    
end );

##
InstallGlobalFunction( NumberWithKeys, function ( list, func )
  local nr, i;
    
    # adapted implementation of `Number`
    
    nr := 0;
    
    for i in [ 1 .. Length( list ) ] do
        
        if func( i, list[i] ) then
            
            nr := nr + 1;
            
        fi;
        
    od;
    
    return nr;
    
end );

##
#= comment for Julia
# Julia does not have non-dense lists and thus needs a separate implementation
InstallGlobalFunction( FilteredWithKeys, function ( list, func )
  local res, i, elm, j;
    
    # adapted implementation of `Filtered`
    
    res := list{[ ]};
    
    i := 0;
    
    for j in [ 1 .. Length( list ) ] do
        
        elm := list[j];
        
        if func( j, elm ) then
            
            i := i + 1;
            
            res[i] := elm;
            
        fi;
        
    od;
    
    return res;
    
end );
# =#

##
InstallGlobalFunction( FirstWithKeys, function ( list, func )
  local elm, i;
    
    # adapted implementation of `First`
    
    for i in [ 1 .. Length( list ) ] do
        
        elm := list[i];
        
        if func( i, elm ) then
            
            return elm;
            
        fi;
        
    od;
    
    return fail;
    
end );

##
InstallGlobalFunction( LastWithKeys, function ( list, func )
  local elm, i;
    
    # adapted implementation of `Last`
    
    for i in Reversed( [ 1 .. Length( list ) ] ) do
        
        elm := list[i];
        
        if func( i, elm ) then
            
            return elm;
            
        fi;
        
    od;
    
    return fail;
    
end );

if IsPackageMarkedForLoading( "Browse", ">= 1.5" ) then

    InstallGlobalFunction( BrowseCachingStatistic,
      
      function( category )
        local operations, current_cache_name, current_cache, value_matrix, names, cols, current_list;
        
        value_matrix := [ ];
        names := [ ];
        cols := [ [ "status", "hits", "misses", "stored" ] ];
        
        operations := ShallowCopy( RecNames( category!.caches ) );
        Sort( operations );
        
        for current_cache_name in operations do
            Add( names, [ current_cache_name ] );
            if not IsBound( category!.caches.(current_cache_name) ) then
                Add( value_matrix, [ "not installed", "-", "-", "-" ] );
                continue;
            fi;
            current_cache := category!.caches.(current_cache_name);
            if current_cache = "none" or IsDisabledCache( current_cache ) then
                Add( value_matrix, [ "deactivated", "-", "-", "-" ] );
                continue;
            fi;
            current_list := [ ];
            if IsWeakCache( current_cache ) then
                Add( current_list, "weak" );
            elif IsCrispCache( current_cache ) then
                Add( current_list, "crisp" );
            fi;
            
            Append( current_list, [ current_cache!.hit_counter, current_cache!.miss_counter, Length( PositionsProperty( current_cache!.value, ReturnTrue ) ) ] );
            Add( value_matrix, current_list );
        od;
        
        NCurses.BrowseDenseList( value_matrix, rec( labelsCol := cols, labelsRow := names ) );
        
    end );

fi;

##
InstallGlobalFunction( CAP_INTERNAL_ASSERT_IS_CELL_OF_CATEGORY,
  
  function( cell, category, human_readable_identifier_getter )
    local generic_help_string;
    
    Assert( 0, IsFunction( human_readable_identifier_getter ) );
    
    generic_help_string := " You can access the category cell and category via the local variables 'cell' and 'category' in a break loop.";
    
    if not IsCapCategoryCell( cell ) then
        Error( human_readable_identifier_getter( ), " does not lie in the filter IsCapCategoryCell.", generic_help_string );
    fi;
    
    if not HasCapCategory( cell ) then
        Error( human_readable_identifier_getter( ), " has no CAP category.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not IsIdenticalObj( CapCategory( cell ), category ) then
        Error( "The CapCategory of ", human_readable_identifier_getter( ), " is not identical to the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
end );

##
InstallGlobalFunction( CAP_INTERNAL_ASSERT_IS_OBJECT_OF_CATEGORY,
  
  function( object, category, human_readable_identifier_getter )
    local generic_help_string;
    
    Assert( 0, IsFunction( human_readable_identifier_getter ) );
    
    generic_help_string := " You can access the object and category via the local variables 'object' and 'category' in a break loop.";
    
    if not IsCapCategoryObject( object ) then
        Error( human_readable_identifier_getter( ), " does not lie in the filter IsCapCategoryObject.", generic_help_string );
    fi;
    
    if not HasCapCategory( object ) then
        Error( human_readable_identifier_getter( ), " has no CAP category.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not IsIdenticalObj( CapCategory( object ), category ) then
        Error( "The CapCategory of ", human_readable_identifier_getter( ), " is not identical to the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not ObjectFilter( category )( object ) then
        Error( human_readable_identifier_getter( ), " does not lie in the object filter of the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
end );

##
InstallGlobalFunction( CAP_INTERNAL_ASSERT_IS_MORPHISM_OF_CATEGORY,
  
  function( morphism, category, human_readable_identifier_getter )
    local generic_help_string;
    
    Assert( 0, IsFunction( human_readable_identifier_getter ) );
    
    generic_help_string := " You can access the morphism and category via the local variables 'morphism' and 'category' in a break loop.";
    
    if not IsCapCategoryMorphism( morphism ) then
        Error( human_readable_identifier_getter( ), " does not lie in the filter IsCapCategoryMorphism.", generic_help_string );
    fi;
    
    if not HasCapCategory( morphism ) then
        Error( human_readable_identifier_getter( ), " has no CAP category.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not IsIdenticalObj( CapCategory( morphism ), category ) then
        Error( "the CAP-category of ", human_readable_identifier_getter( ), " is not identical to the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not MorphismFilter( category )( morphism ) then
        Error( human_readable_identifier_getter( ), " does not lie in the morphism filter of the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
    if not HasSource( morphism ) then
        Error( human_readable_identifier_getter( ), " has no source.", generic_help_string );
    fi;
    
    CAP_INTERNAL_ASSERT_IS_OBJECT_OF_CATEGORY( Source( morphism ), category, {} -> Concatenation( "the source of ", human_readable_identifier_getter( ) ) );
    
    if not HasRange( morphism ) then
        Error( human_readable_identifier_getter( ), " has no range.", generic_help_string );
    fi;
    
    CAP_INTERNAL_ASSERT_IS_OBJECT_OF_CATEGORY( Range( morphism ), category, {} -> Concatenation( "the range of ", human_readable_identifier_getter( ) ) );
    
end );

##
InstallGlobalFunction( CAP_INTERNAL_ASSERT_IS_TWO_CELL_OF_CATEGORY,
  
  function( two_cell, category, human_readable_identifier_getter )
    local generic_help_string;
    
    Assert( 0, IsFunction( human_readable_identifier_getter ) );
    
    generic_help_string := " You can access the 2-cell and category via the local variables 'two_cell' and 'category' in a break loop.";
    
    if not IsCapCategoryTwoCell( two_cell ) then
        Error( human_readable_identifier_getter( ), " does not lie in the filter IsCapCategoryTwoCell.", generic_help_string );
    fi;
    
    if not HasCapCategory( two_cell ) then
        Error( human_readable_identifier_getter( ), " has no CAP category.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not IsIdenticalObj( CapCategory( two_cell ), category ) then
        Error( "the CapCategory of ", human_readable_identifier_getter( ), " is not identical to the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
    if not IsIdenticalObj( category, false ) and not TwoCellFilter( category )( two_cell ) then
        Error( human_readable_identifier_getter( ), " does not lie in the 2-cell filter of the category named \033[1m", Name( category ), "\033[0m.", generic_help_string );
    fi;
    
    if not HasSource( two_cell ) then
        Error( human_readable_identifier_getter( ), " has no source.", generic_help_string );
    fi;
    
    CAP_INTERNAL_ASSERT_IS_MORPHISM_OF_CATEGORY( Source( two_cell ), category, {} -> Concatenation( "the source of ", human_readable_identifier_getter( ) ) );
    
    if not HasRange( two_cell ) then
        Error( human_readable_identifier_getter( ), " has no range.", generic_help_string );
    fi;
    
    CAP_INTERNAL_ASSERT_IS_MORPHISM_OF_CATEGORY( Range( two_cell ), category, {} -> Concatenation( "the range of ", human_readable_identifier_getter( ) ) );
    
end );

##
InstallGlobalFunction( PackageOfCAPOperation, function ( operation_name )
  local packages;
    
    if not IsBound( CAP_INTERNAL_METHOD_NAME_RECORD.(operation_name) ) then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( operation_name, " is not a CAP operation" );
        
    fi;
    
    packages := Filtered( RecNames( CAP_INTERNAL_METHOD_NAME_RECORDS_BY_PACKAGE ), package -> IsBound( CAP_INTERNAL_METHOD_NAME_RECORDS_BY_PACKAGE.(package).(operation_name) ) );
    
    if Length( packages ) = 0 then
        
        return fail;
        
    elif Length( packages ) > 1 then
        
        # COVERAGE_IGNORE_NEXT_LINE
        Error( "Found multiple packages for CAP operation ", operation_name );
        
    fi;
    
    return packages[1];
    
end );

##
InstallGlobalFunction( CreateGapObjectWithAttributes, function( type, additional_arguments_list... )
    local arg_list;
    
    arg_list := Concatenation(
        [ rec( ), type ], additional_arguments_list
    );
    
    return CallFuncList( ObjectifyWithAttributes, arg_list );
    
end );

[ Verzeichnis aufwärts0.90unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]