|
# SPDX-License-Identifier: GPL-2.0-or-later
# CAP: Categories, Algorithms, Programming
#
# Implementations
#
InstallGlobalFunction( "CAP_INTERNAL_GENERATE_CONVENIENCE_METHODS_FOR_LIMITS",
function ( package_name, method_name_record, limits )
local output_string, generate_universal_morphism_convenience, generate_functorial_convenience_method, number_of_diagram_arguments, limit, output_path;
output_string :=
"""# SPDX-License-Identifier: GPL-2.0-or-later
# CAP: Categories, Algorithms, Programming
#
# Implementations
#
# THIS FILE IS AUTOMATICALLY GENERATED, SEE LimitConvenience.gi
""";
#### helper functions
generate_universal_morphism_convenience := function( limit, universal_morphism_name, object_name, diagram_position )
local current_string, test_object_position, diagram_filter_list_string, tau_filter, list_selector;
if not diagram_position in [ "Source", "Range" ] then
Error( "diagram_position must be \"Source\" or \"Range\"" );
fi;
if limit.number_of_unbound_morphisms = 0 then
# diagram can be derived from morphism(s) via diagram_position
if limit.number_of_targets = 1 then
Error( "this case is currently not supported" );
elif limit.number_of_targets > 1 then
# derive diagram from morphisms via diagram_position
current_string := Concatenation(
"\n",
"##\n",
"InstallMethod( ", universal_morphism_name, ",\n",
" [ IsList ],\n",
" \n",
" function( list )\n",
" #% CAP_JIT_RESOLVE_FUNCTION\n",
" \n",
" return ", universal_morphism_name, "( CapCategory( list[1] ), list );\n",
" \n",
"end );\n",
"\n",
"##\n",
"InstallOtherMethod( ", universal_morphism_name, ",\n",
" [ IsCapCategory, IsList ],\n",
" \n",
" function( cat, list )\n",
" #% CAP_JIT_RESOLVE_FUNCTION\n",
" \n",
" return ", universal_morphism_name, "( cat, List( list, ", diagram_position, " ), list );\n",
" \n",
"end );\n",
"\n",
"##\n",
"InstallOtherMethod( ", universal_morphism_name, ",\n",
" [ IsCapCategoryObject, IsList ],\n",
" \n",
" function( test_object, list )\n",
" #% CAP_JIT_RESOLVE_FUNCTION\n",
" \n",
" return ", universal_morphism_name, "( CapCategory( test_object ), test_object, list );\n",
" \n",
"end );\n",
"\n",
"##\n",
"InstallOtherMethod( ", universal_morphism_name, ",\n",
" [ IsCapCategory, IsCapCategoryObject, IsList ],\n",
" \n",
" function( cat, test_object, list )\n",
" #% CAP_JIT_RESOLVE_FUNCTION\n",
" \n",
" return ", universal_morphism_name, "( cat, List( list, ", diagram_position, " ), test_object, list );\n",
" \n",
"end );\n"
);
output_string := Concatenation( output_string, current_string );
fi;
fi;
# derive test object
if IsOperation( ValueGlobal( universal_morphism_name ) ) then
if diagram_position = "Source" then
test_object_position := "Range";
elif diagram_position = "Range" then
test_object_position := "Source";
else
Error( "this should never happen" );
fi;
if limit.number_of_targets = 1 then
tau_filter := "IsCapCategoryMorphism";
list_selector := "";
else
tau_filter := "IsList";
list_selector := "[1]";
fi;
current_string := ReplacedStringViaRecord( """
InstallOtherMethod( without_given_universal_morphism,
[ diagram_filter_list..., tau_filter ],
function( diagram_arguments..., tau )
#% CAP_JIT_RESOLVE_FUNCTION
return without_given_universal_morphism( diagram_arguments..., test_object_position( selected_tau ), tau );
end );
InstallOtherMethod( without_given_universal_morphism,
[ IsCapCategory, diagram_filter_list..., tau_filter ],
function( cat, diagram_arguments..., tau )
#% CAP_JIT_RESOLVE_FUNCTION
return without_given_universal_morphism( cat, diagram_arguments..., test_object_position( selected_tau ), tau );
end );
InstallOtherMethod( with_given_universal_morphism,
[ diagram_filter_list..., tau_filter, IsCapCategoryObject ],
function( diagram_arguments..., tau, P )
#% CAP_JIT_RESOLVE_FUNCTION
return with_given_universal_morphism( diagram_arguments..., test_object_position( selected_tau ), tau, P );
end );
InstallOtherMethod( with_given_universal_morphism,
[ IsCapCategory, diagram_filter_list..., tau_filter, IsCapCategoryObject ],
function( cat, diagram_arguments..., tau, P )
#% CAP_JIT_RESOLVE_FUNCTION
return with_given_universal_morphism( cat, diagram_arguments..., test_object_position( selected_tau ), tau, P );
end );
""",
rec(
without_given_universal_morphism := universal_morphism_name,
with_given_universal_morphism := Concatenation( universal_morphism_name, "WithGiven", object_name ),
diagram_filter_list := List( CAP_INTERNAL_REPLACED_STRINGS_WITH_FILTERS( limit.diagram_filter_list ), NameFunction ),
tau_filter := tau_filter,
diagram_arguments := limit.diagram_arguments_names,
test_object_position := test_object_position,
selected_tau := Concatenation( "tau", list_selector ),
)
);
output_string := Concatenation( output_string, current_string );
fi;
end;
generate_functorial_convenience_method := function( limit, limit_colimit, object_name, functorial_name, functorial_with_given_name )
local functorial_with_given_record, filter_list, arguments_names, arguments_string, source_diagram_arguments_string, range_diagram_arguments_string, replaced_filter_list, current_string, input_arguments_names, source_argument_name, range_argument_name, source_diagram_arguments_names, range_diagram_arguments_names, equalizer_preprocessing, test_string, additional_preconditions, test_arguments, universal_morphism_with_given_name, call_arguments;
Assert( 0, limit_colimit in [ "limit", "colimit" ] );
functorial_with_given_record := method_name_record.( limit.limit_functorial_with_given_name );
if Length( limit.diagram_filter_list ) > 0 and limit.number_of_unbound_morphisms = 0 and (limit.limit_object_name <> limit.colimit_object_name or limit_colimit = "limit") then
# convenience: derive diagrams from arguments
filter_list := limit.diagram_morphism_filter_list;
arguments_names := limit.diagram_morphism_arguments_names;
Assert( 0, Length( filter_list ) = 1 );
Assert( 0, Length( arguments_names ) = 1 );
arguments_string := JoinStringsWithSeparator( arguments_names, ", " );
if limit.number_of_targets = 1 then
source_diagram_arguments_string := Concatenation( "Source( ", arguments_string, " )" );
range_diagram_arguments_string := Concatenation( "Range( ", arguments_string, " )" );
else
source_diagram_arguments_string := Concatenation( "List( ", arguments_string, ", Source )" );
range_diagram_arguments_string := Concatenation( "List( ", arguments_string, ", Range )" );
fi;
replaced_filter_list := List( CAP_INTERNAL_REPLACED_STRINGS_WITH_FILTERS( filter_list ), NameFunction );
current_string := ReplacedStringViaRecord( """
##
InstallOtherMethod( functorial_name,
[ filter_list... ],
function( input_arguments... )
return functorial_name( source_diagram_arguments, input_arguments..., range_diagram_arguments );
end );
""",
rec(
functorial_name := functorial_name,
filter_list := replaced_filter_list,
input_arguments := arguments_names,
source_diagram_arguments := source_diagram_arguments_string,
range_diagram_arguments := range_diagram_arguments_string,
)
);
output_string := Concatenation( output_string, current_string );
# it is safe to use InstallOtherMethodForCompilerForCAP because there is no other two-argument convenience method for functorials
current_string := ReplacedStringViaRecord( """
##
InstallOtherMethodForCompilerForCAP( functorial_name,
[ IsCapCategory, filter_list... ],
function( cat, input_arguments... )
return functorial_name( cat, source_diagram_arguments, input_arguments..., range_diagram_arguments );
end );
""",
rec(
functorial_name := functorial_name,
filter_list := replaced_filter_list,
input_arguments := arguments_names,
source_diagram_arguments := source_diagram_arguments_string,
range_diagram_arguments := range_diagram_arguments_string,
)
);
output_string := Concatenation( output_string, current_string );
current_string := ReplacedStringViaRecord( """
##
InstallOtherMethod( functorial_with_given_name,
[ IsCapCategoryObject, filter_list..., IsCapCategoryObject ],
function( source, input_arguments..., range )
return functorial_with_given_name( source, source_diagram_arguments, input_arguments..., range_diagram_arguments, range );
end );
""",
rec(
functorial_with_given_name := functorial_with_given_name,
filter_list := replaced_filter_list,
input_arguments := arguments_names,
source_diagram_arguments := source_diagram_arguments_string,
range_diagram_arguments := range_diagram_arguments_string,
)
);
output_string := Concatenation( output_string, current_string );
# it is safe to use InstallOtherMethodForCompilerForCAP because there is no other four-argument convenience method for with given functorials
current_string := ReplacedStringViaRecord( """
##
InstallOtherMethodForCompilerForCAP( functorial_with_given_name,
[ IsCapCategory, IsCapCategoryObject, filter_list..., IsCapCategoryObject ],
function( cat, source, input_arguments..., range )
return functorial_with_given_name( cat, source, source_diagram_arguments, input_arguments..., range_diagram_arguments, range );
end );
""",
rec(
functorial_with_given_name := functorial_with_given_name,
filter_list := replaced_filter_list,
input_arguments := arguments_names,
source_diagram_arguments := source_diagram_arguments_string,
range_diagram_arguments := range_diagram_arguments_string,
)
);
output_string := Concatenation( output_string, current_string );
fi;
# derive functorials from the universality of the limit
# only do this for limits, colimits will be handled by the automatic dualization of derivations
if limit_colimit = "limit" then
Assert( 0, Length( limit.diagram_morphism_filter_list ) <= 1 );
Assert( 0, Length( limit.diagram_morphism_arguments_names ) <= 1 );
input_arguments_names := functorial_with_given_record.input_arguments_names;
source_argument_name := input_arguments_names[2];
range_argument_name := Last( input_arguments_names );
source_diagram_arguments_names := limit.functorial_source_diagram_arguments_names;
range_diagram_arguments_names := limit.functorial_range_diagram_arguments_names;
# EqualizerFunctorialWithGivenEqualizers would have 8 arguments if the source objects would be given
# -> we have to work around this and derive the source objects from the morphism between the diagrams.
equalizer_preprocessing := "";
if Length( limit.diagram_filter_list ) > 0 then
if limit.number_of_targets = 1 then
Assert( 0, limit.diagram_morphism_arguments_names = [ "mu" ] );
test_string := ReplacedStringViaRecord(
"PreCompose( cat, projection_with_given( cat, source_diagram..., source_object ), mu )",
rec(
projection_with_given := limit.limit_projection_with_given_name,
source_diagram := source_diagram_arguments_names,
source_object := source_argument_name,
)
);
additional_preconditions := [ "[ PreCompose, 1 ]", Concatenation( "[ ", limit.limit_projection_with_given_name, ", 1 ]" ) ];
if limit.number_of_unbound_morphisms > 1 then
if limit.limit_object_name <> "Equalizer" then
Error( "This is a hack which might not be valid in general." );
fi;
# we are in the Equalizer case, which needs special handling (see above)
equalizer_preprocessing := "local Y, Yp;\n \n Y := Source( mu );\n Yp := Range( mu );\n ";
fi;
else
Assert( 0, limit.diagram_morphism_arguments_names = [ "L" ] );
test_string := ReplacedStringViaRecord(
"List( [ 1 .. Length( L ) ], i -> PreCompose( cat, projection_with_given( cat, source_diagram..., i, source_object ), L[i] ) )",
rec(
projection_with_given := limit.limit_projection_with_given_name,
source_diagram := source_diagram_arguments_names,
source_object := source_argument_name,
)
);
additional_preconditions := [ "[ PreCompose, 2 ]", Concatenation( "[ ", limit.limit_projection_with_given_name, ", 2 ]" ) ];
fi;
test_arguments := [ test_string ];
else
Assert( 0, limit.diagram_morphism_arguments_names = [ ] );
test_arguments := [ ];
additional_preconditions := [ ];
fi;
universal_morphism_with_given_name := limit.limit_universal_morphism_with_given_name;
call_arguments := Concatenation( [ "cat" ], range_diagram_arguments_names, [ source_argument_name ], test_arguments, [ range_argument_name ] );
current_string := ReplacedStringViaRecord( """
##
AddDerivationToCAP( functorial_with_given_name,
"functorial_with_given_name using the universality of the limit_colimit",
[ preconditions... ],
function( input_arguments... )
equalizer_preprocessing
return universal_morphism_with_given( call_arguments... );
end );
""",
rec(
functorial_with_given_name := functorial_with_given_name,
input_arguments := input_arguments_names,
preconditions := Concatenation( [ Concatenation( "[", universal_morphism_with_given_name, ", 1 ]" ) ], additional_preconditions ),
equalizer_preprocessing := equalizer_preprocessing,
universal_morphism_with_given := universal_morphism_with_given_name,
call_arguments := call_arguments,
limit_colimit := limit_colimit,
)
);
output_string := Concatenation( output_string, current_string );
# derive functorial of empty limits from IdentityMorphism
if Length( limit.diagram_filter_list ) = 0 then
current_string := ReplacedStringViaRecord( """
##
AddDerivationToCAP( functorial_name,
"functorial_name by taking the identity morphism of object_name",
[ [ object_name, 1 ],
[ IdentityMorphism, 1 ] ],
function( cat )
return IdentityMorphism( cat, object_name( cat ) );
end );
""",
rec(
functorial_name := functorial_name,
object_name := object_name,
)
);
output_string := Concatenation( output_string, current_string );
fi;
fi;
end;
for limit in limits do
number_of_diagram_arguments := Length( limit.diagram_filter_list );
if number_of_diagram_arguments > 0 then
#### universal morphism convenience
generate_universal_morphism_convenience( limit, limit.limit_universal_morphism_name, limit.limit_object_name, "Range" );
generate_universal_morphism_convenience( limit, limit.colimit_universal_morphism_name, limit.colimit_object_name, "Source" );
fi;
#### functorial convenience method
generate_functorial_convenience_method( limit, "limit", limit.limit_object_name, limit.limit_functorial_name, limit.limit_functorial_with_given_name );
generate_functorial_convenience_method( limit, "colimit", limit.colimit_object_name, limit.colimit_functorial_name, limit.colimit_functorial_with_given_name );
od;
if not IsExistingFileInPackageForHomalg( package_name, "LimitConvenienceOutput.gi" ) or output_string <> ReadFileFromPackageForHomalg( package_name, "LimitConvenienceOutput.gi" ) then
output_path := Filename( DirectoryTemporary( ), "LimitConvenienceOutput.gi" );
WriteFileForHomalg( output_path, output_string );
Display( Concatenation(
"WARNING: The file LimitConvenienceOutput.gi differs from the automatically generated one. ",
"You can view the automatically generated file at the following path: ",
output_path
) );
fi;
end );
[ Dauer der Verarbeitung: 0.37 Sekunden
(vorverarbeitet)
]
|