|
# SPDX-License-Identifier: GPL-2.0-or-later
# CAP: Categories, Algorithms, Programming
#
# Implementations
#
#! @Chapter Opposite category
###################################
##
#! @Section Functor is an involution
##
###################################
##################################
##
## Constructor
##
##################################
##
InstallMethod( Opposite,
[ IsCapCategoryObject ],
function( object )
return Opposite( Opposite( CapCategory( object ) ), object );
end );
##
InstallOtherMethod( Opposite,
[ IsCapCategory, IsCapCategoryObject ],
function( opposite_cat, object )
return ObjectConstructor( opposite_cat, object );
end );
##
InstallMethod( Opposite,
[ IsCapCategoryMorphism ],
function( morphism )
return Opposite( Opposite( CapCategory( morphism ) ), morphism );
end );
##
InstallOtherMethod( Opposite,
[ IsCapCategory, IsCapCategoryMorphism ],
function( opposite_cat, morphism )
local source, range;
source := ObjectConstructor( opposite_cat, Range( morphism ) );
range := ObjectConstructor( opposite_cat, Source( morphism ) );
return MorphismConstructor( opposite_cat, source, morphism, range );
end );
InstallGlobalFunction( CAP_INTERNAL_OPPOSITE_RECURSIVE,
function( obj )
if IsCapCategory( obj ) then
return OppositeCategory( obj );
elif IsCapCategoryObject( obj ) then
return ObjectDatum( CapCategory( obj ), obj );
elif IsCapCategoryMorphism( obj ) then
return MorphismDatum( CapCategory( obj ), obj );
elif IsList( obj ) then
return List( obj, CAP_INTERNAL_OPPOSITE_RECURSIVE );
else
return obj;
fi;
end );
BindGlobal( "CAP_INTERNAL_INSTALL_OPPOSITE_ADDS_FROM_CATEGORY",
function( opposite_category, category, only_primitive_operations, only_primitive_operations_and_hom_structure )
local recnames, list_of_underlying_operations, operations_of_homomorphism_structure,
installed_operations_of_homomorphism_structure_and_external_hom, H,
current_recname, current_entry, dual_operation_name, filter_list, input_arguments_names, return_type, func_string,
preprocessor_string, dual_arguments, tmp,
postprocessor_string, output_source_getter_string, output_range_getter_string, return_statement,
func, weight, list_of_attributes, attr, tester, setter;
## Take care of attributes
## TODO: if there are more instances, set markers in the MethodRecord
list_of_attributes := [ CommutativeRingOfLinearCategory ];
for attr in list_of_attributes do
tester := Tester( attr );
if not tester( opposite_category ) and tester( category ) then
setter := Setter( attr );
setter( opposite_category, attr( category ) );
fi;
od;
recnames := AsSortedList( RecNames( CAP_INTERNAL_METHOD_NAME_RECORD ) );
## No support for twocells
recnames := Difference( recnames,
[ "HorizontalPreCompose",
"HorizontalPostCompose",
"VerticalPreCompose",
"VerticalPostCompose",
"IdenticalTwoCell" ] );
if only_primitive_operations or only_primitive_operations_and_hom_structure then
list_of_underlying_operations := ListPrimitivelyInstalledOperationsOfCategory( category );
else
list_of_underlying_operations := ListInstalledOperationsOfCategory( category );
fi;
operations_of_homomorphism_structure :=
[ "DistinguishedObjectOfHomomorphismStructure",
"HomomorphismStructureOnObjects",
"HomomorphismStructureOnMorphisms",
"HomomorphismStructureOnMorphismsWithGivenObjects",
"InterpretMorphismAsMorphismFromDistinguishedObjectToHomomorphismStructure",
"InterpretMorphismAsMorphismFromDistinguishedObjectToHomomorphismStructureWithGivenObjects",
"InterpretMorphismFromDistinguishedObjectToHomomorphismStructureAsMorphism",
];
if not IsEmpty( Intersection( list_of_underlying_operations, operations_of_homomorphism_structure ) ) then
SetRangeCategoryOfHomomorphismStructure( opposite_category, RangeCategoryOfHomomorphismStructure( category ) );
fi;
if only_primitive_operations_and_hom_structure then
installed_operations_of_homomorphism_structure_and_external_hom :=
Intersection( ListInstalledOperationsOfCategory( category ),
[ "DistinguishedObjectOfHomomorphismStructure",
"HomomorphismStructureOnObjects",
"HomomorphismStructureOnMorphisms",
"HomomorphismStructureOnMorphismsWithGivenObjects",
"InterpretMorphismAsMorphismFromDistinguishedObjectToHomomorphismStructure",
"InterpretMorphismAsMorphismFromDistinguishedObjectToHomomorphismStructureWithGivenObjects",
"InterpretMorphismFromDistinguishedObjectToHomomorphismStructureAsMorphism",
"MorphismsOfExternalHom",
"BasisOfExternalHom",
"CoefficientsOfMorphism",
] );
## the opposite category has the same enrichment as the original category:
if HasRangeCategoryOfHomomorphismStructure( category ) then
H := RangeCategoryOfHomomorphismStructure( category );
SetRangeCategoryOfHomomorphismStructure( opposite_category, H );
## be sure the above assignment succeeded:
Assert( 0, IsIdenticalObj( H, RangeCategoryOfHomomorphismStructure( opposite_category ) ) );
list_of_underlying_operations := Concatenation( list_of_underlying_operations, installed_operations_of_homomorphism_structure_and_external_hom );
list_of_underlying_operations := Set( list_of_underlying_operations );
fi;
fi;
for current_recname in recnames do
current_entry := CAP_INTERNAL_METHOD_NAME_RECORD.( current_recname );
## Conservative
if not IsBound( current_entry.dual_operation ) then
continue;
fi;
dual_operation_name := current_entry.dual_operation;
if not dual_operation_name in list_of_underlying_operations then
continue;
fi;
filter_list := current_entry.filter_list;
input_arguments_names := current_entry.input_arguments_names;
return_type := current_entry.return_type;
func_string :=
"""
function ( input_arguments... )
local dual_preprocessor_func, prep_arg, result, dual_postprocessor_func;
preprocessor_string
result := dual_operation_name( dual_arguments... );
postprocessor_string
return_statement
end
""";
if IsBound( current_entry.dual_preprocessor_func_string ) then
preprocessor_string := ReplacedStringViaRecord(
"""
dual_preprocessor_func := dual_preprocessor_func_string;
prep_arg := dual_preprocessor_func( input_arguments... );
#% CAP_JIT_DROP_NEXT_STATEMENT
Assert( 0, IsIdenticalObj( prep_arg[1], OppositeCategory( cat ) ) );
""",
rec(
dual_preprocessor_func_string := current_entry.dual_preprocessor_func_string,
input_arguments := input_arguments_names,
)
);
Assert( 0, filter_list[1] = "category" );
dual_arguments := List( [ 2 .. Length( filter_list ) ], i -> Concatenation( "prep_arg[", String( i ), "]" ) );
else
preprocessor_string := "";
Assert( 0, filter_list[1] = "category" );
dual_arguments := List( [ 2 .. Length( filter_list ) ], function( i )
local filter, argument_name;
filter := filter_list[i];
argument_name := input_arguments_names[i];
if filter = "object" then
return Concatenation( "ObjectDatum( cat, ", argument_name, " )" );
elif filter = "morphism" then
return Concatenation( "MorphismDatum( cat, ", argument_name, " )" );
elif filter in [ "integer", "element_of_commutative_ring_of_linear_structure", "nonneg_integer_or_infinity", "list_of_elements_of_commutative_ring_of_linear_structure" ] then
return argument_name;
elif filter = "list_of_objects" then
return Concatenation( "List( ", argument_name, ", x -> ObjectDatum( cat, x ) )" );
elif filter = "list_of_morphisms" then
return Concatenation( "List( ", argument_name, ", x -> MorphismDatum( cat, x ) )" );
elif filter = "list_of_integers_and_list_of_morphisms" then
return Concatenation( "Pair( ", argument_name, "[1], List( ", argument_name, "[2], x -> MorphismDatum( cat, x ) ) )" );
else
Error( "this case is not handled yet" );
fi;
end );
if current_entry.dual_arguments_reversed then
dual_arguments := Reversed( dual_arguments );
fi;
if current_entry.is_with_given and IsBound( current_entry.dual_with_given_objects_reversed ) and current_entry.dual_with_given_objects_reversed then
tmp := dual_arguments[1];
dual_arguments[1] := dual_arguments[Length( dual_arguments)];
dual_arguments[Length( dual_arguments)] := tmp;
fi;
fi;
dual_arguments := Concatenation( [ "OppositeCategory( cat )" ], dual_arguments );
if IsBound( current_entry.dual_postprocessor_func_string ) then
postprocessor_string := Concatenation( "dual_postprocessor_func := ", current_entry.dual_postprocessor_func_string, ";" );
return_statement := "return dual_postprocessor_func( result );";
else
postprocessor_string := "";
if return_type = "object" then
return_statement := "return ObjectConstructor( cat, result );";
elif return_type = "morphism" then
return_statement := "return MorphismConstructor( cat, output_source_getter, result, output_range_getter );";
if IsBound( current_entry.output_source_getter_string ) and IsBound( current_entry.can_always_compute_output_source_getter ) and current_entry.can_always_compute_output_source_getter then
output_source_getter_string := current_entry.output_source_getter_string;
else
output_source_getter_string := "ObjectConstructor( cat, Range( result ) )";
fi;
if IsBound( current_entry.output_range_getter_string ) and IsBound( current_entry.can_always_compute_output_range_getter ) and current_entry.can_always_compute_output_range_getter then
output_range_getter_string := current_entry.output_range_getter_string;
else
output_range_getter_string := "ObjectConstructor( cat, Source( result ) )";
fi;
return_statement := ReplacedStringViaRecord( return_statement, rec(
output_source_getter := output_source_getter_string,
output_range_getter := output_range_getter_string,
) );
elif return_type = "list_of_morphisms" then
return_statement := "return List( result, mor -> MorphismConstructor( cat, ObjectConstructor( cat, Range( mor ) ), mor, ObjectConstructor( cat, Source( mor ) ) ) );";
elif return_type = "list_of_objects" then
return_statement := "return List( result, obj -> ObjectConstructor( cat, obj ) );";
elif return_type = "bool" then
return_statement := "return result;";
elif return_type = "nonneg_integer_or_infinity" then
return_statement := "return result;";
else
Error( "this case is not handled yet" );
fi;
fi;
func_string := ReplacedStringViaRecord( func_string, rec(
input_arguments := input_arguments_names,
preprocessor_string := preprocessor_string,
dual_arguments := dual_arguments,
dual_operation_name := dual_operation_name,
postprocessor_string := postprocessor_string,
return_statement := return_statement
) );
func := EvalString( func_string );
weight := OperationWeight( category, dual_operation_name );
AddCapOperation( current_recname, opposite_category, func, weight );
od;
end );
##
InstallMethod( Opposite,
[ IsCapCategory, IsString ],
FunctionWithNamedArguments(
[
[ "only_primitive_operations", false ],
[ "only_primitive_operations_and_hom_structure", false ],
],
function( CAP_NAMED_ARGUMENTS, category, name )
local opposite_category, known_properties, opposite_property_pairs, pair;
if not IsFinalized( category ) then
Error( "Input category must be finalized to create opposite category" );
fi;
opposite_category := CreateCapCategoryWithDataTypes(
name, WasCreatedAsOppositeCategory,
IsCapCategoryOppositeObject, IsCapCategoryOppositeMorphism, IsCapCategoryTwoCell,
CapJitDataTypeOfObjectOfCategory( category ), CapJitDataTypeOfMorphismOfCategory( category ), CapJitDataTypeOfTwoCellOfCategory( category )
: is_computable := category!.is_computable
);
if IsBound( category!.supports_empty_limits ) then
opposite_category!.supports_empty_limits := category!.supports_empty_limits;
fi;
opposite_category!.compiler_hints := rec(
category_attribute_names := [
"OppositeCategory",
],
);
SetOppositeCategory( opposite_category, category );
SetOpposite( opposite_category, category );
# A category might have multiple different instances of opposite categories.
# Only the first instance is used for attributes (of the category and its objects and morphisms).
if not HasOpposite( category ) then
SetOpposite( category, opposite_category );
fi;
known_properties := ListKnownCategoricalProperties( category );
opposite_property_pairs := Filtered( CAP_INTERNAL_CATEGORICAL_PROPERTIES_LIST, x -> x[2] <> fail );
for pair in opposite_property_pairs do
# plausibility check
if not Reversed( pair ) in opposite_property_pairs then
Error( "The pair of categorical properties <pair> was registered using `AddCategoricalProperty`, but the reversed pair was not." );
fi;
if pair[1] in known_properties then
Setter( ValueGlobal( pair[2] ) )( opposite_category, true );
fi;
od;
AddObjectConstructor( opposite_category, function( cat, object )
local opposite_object;
#% CAP_JIT_DROP_NEXT_STATEMENT
CAP_INTERNAL_ASSERT_IS_OBJECT_OF_CATEGORY( object, OppositeCategory( cat ), {} -> "the object datum given to the object constructor of <cat>" );
# A category might have multiple different instances of opposite categories.
# Only the first instance is used for attributes (of the category and its objects and morphisms).
#% CAP_JIT_DROP_NEXT_STATEMENT
if HasOpposite( object ) and IsIdenticalObj( Opposite( OppositeCategory( cat ) ), cat ) then
return Opposite( object );
fi;
opposite_object := CreateCapCategoryObjectWithAttributes( cat,
Opposite, object );
#% CAP_JIT_DROP_NEXT_STATEMENT
if CapCategory( object )!.predicate_logic then
#= comment for Julia
INSTALL_TODO_LIST_ENTRIES_FOR_OPPOSITE_OBJECT( object );
# =#
fi;
# A category might have multiple different instances of opposite categories.
# Only the first instance is used for attributes (of the category and its objects and morphisms).
#% CAP_JIT_DROP_NEXT_STATEMENT
if IsIdenticalObj( Opposite( OppositeCategory( cat ) ), cat ) then
SetOpposite( object, opposite_object );
fi;
return opposite_object;
end );
AddObjectDatum( opposite_category, function( cat, opposite_object )
return Opposite( opposite_object );
end );
AddMorphismConstructor( opposite_category, function( cat, source, morphism, range )
local opposite_morphism;
#% CAP_JIT_DROP_NEXT_STATEMENT
CAP_INTERNAL_ASSERT_IS_MORPHISM_OF_CATEGORY( morphism, OppositeCategory( cat ), {} -> "the morphism datum given to the morphism constructor of <cat>" );
if not IsEqualForObjects( OppositeCategory( cat ), Source( morphism ), Opposite( range ) ) then
Error( "the source of the morphism datum must be equal to <Opposite( range )>" );
fi;
if not IsEqualForObjects( OppositeCategory( cat ), Range( morphism ), Opposite( source ) ) then
Error( "the range of the morphism datum must be equal to <Opposite( source )>" );
fi;
# A category might have multiple different instances of opposite categories.
# Only the first instance is used for attributes (of the category and its objects and morphisms).
#% CAP_JIT_DROP_NEXT_STATEMENT
if HasOpposite( morphism ) and IsIdenticalObj( Opposite( OppositeCategory( cat ) ), cat ) then
return Opposite( morphism );
fi;
opposite_morphism := CreateCapCategoryMorphismWithAttributes( cat,
source, range,
Opposite, morphism );
#% CAP_JIT_DROP_NEXT_STATEMENT
if CapCategory( morphism )!.predicate_logic then
#= comment for Julia
INSTALL_TODO_LIST_ENTRIES_FOR_OPPOSITE_MORPHISM( morphism );
# =#
fi;
# A category might have multiple different instances of opposite categories.
# Only the first instance is used for attributes (of the category and its objects and morphisms).
#% CAP_JIT_DROP_NEXT_STATEMENT
if IsIdenticalObj( Opposite( OppositeCategory( cat ) ), cat ) then
SetOpposite( morphism, opposite_morphism );
fi;
return opposite_morphism;
end );
AddMorphismDatum( opposite_category, function( cat, opposite_morphism )
return Opposite( opposite_morphism );
end );
CAP_INTERNAL_INSTALL_OPPOSITE_ADDS_FROM_CATEGORY( opposite_category, category, CAP_NAMED_ARGUMENTS.only_primitive_operations, CAP_NAMED_ARGUMENTS.only_primitive_operations_and_hom_structure );
Finalize( opposite_category );
if category!.predicate_logic then
#= comment for Julia
INSTALL_TODO_LIST_ENTRIES_FOR_OPPOSITE_CATEGORY( category );
# =#
fi;
return opposite_category;
end ) );
##
InstallMethod( Opposite,
[ IsCapCategory ],
FunctionWithNamedArguments(
[
[ "only_primitive_operations", false ],
[ "only_primitive_operations_and_hom_structure", false ],
],
function( CAP_NAMED_ARGUMENTS, category )
local opposite_category;
opposite_category := Concatenation( "Opposite( ", Name( category ), " )" );
return Opposite( category, opposite_category : only_primitive_operations := CAP_NAMED_ARGUMENTS.only_primitive_operations, only_primitive_operations_and_hom_structure := CAP_NAMED_ARGUMENTS.only_primitive_operations_and_hom_structure );
end ) );
##################################
##
## Methods
##
##################################
InstallGlobalFunction( INSTALL_TODO_LIST_ENTRIES_FOR_OPPOSITE_CATEGORY,
function( category )
local opposite_property_pairs, entry, pair;
opposite_property_pairs := Filtered( CAP_INTERNAL_CATEGORICAL_PROPERTIES_LIST, x -> x[2] <> fail );
# prepare special format for ToDoListEntryToMaintainFollowingAttributes
opposite_property_pairs := List( opposite_property_pairs, x -> [ "", x ] );
entry := ToDoListEntryToMaintainFollowingAttributes( [ [ category, "Opposite" ] ],
[ category, [ Opposite, category ] ],
opposite_property_pairs );
AddToToDoList( entry );
entry := ToDoListEntryToMaintainFollowingAttributes( [ [ category, "Opposite" ] ],
[ [ Opposite, category ], category ],
opposite_property_pairs );
AddToToDoList( entry );
end );
InstallGlobalFunction( INSTALL_TODO_LIST_ENTRIES_FOR_OPPOSITE_MORPHISM,
function( morphism )
local entry;
entry := ToDoListEntryToMaintainFollowingAttributes( [ [ morphism, "Opposite" ] ],
[ morphism, [ Opposite, morphism ] ],
CAP_INTERNAL_OPPOSITE_PROPERTY_PAIRS_FOR_MORPHISMS );
AddToToDoList( entry );
entry := ToDoListEntryToMaintainFollowingAttributes( [ [ morphism, "Opposite" ] ],
[ [ Opposite, morphism ], morphism ],
CAP_INTERNAL_OPPOSITE_PROPERTY_PAIRS_FOR_MORPHISMS );
AddToToDoList( entry );
end );
InstallGlobalFunction( INSTALL_TODO_LIST_ENTRIES_FOR_OPPOSITE_OBJECT,
function( object )
local entry_list, entry;
entry := ToDoListEntryToMaintainFollowingAttributes( [ [ object, "Opposite" ] ],
[ object, [ Opposite, object ] ],
CAP_INTERNAL_OPPOSITE_PROPERTY_PAIRS_FOR_OBJECTS );
AddToToDoList( entry );
entry := ToDoListEntryToMaintainFollowingAttributes( [ [ object, "Opposite" ] ],
[ [ Opposite, object ], object ],
CAP_INTERNAL_OPPOSITE_PROPERTY_PAIRS_FOR_OBJECTS );
AddToToDoList( entry );
end );
##
InstallMethod( DisplayString,
[ IsCapCategoryOppositeObject ],
function( object )
return Concatenation( DisplayString( Opposite( object ) ), "\nAn object in ", Name( CapCategory( object ) ), " given by the above data\n" );
end );
##
InstallMethod( DisplayString,
[ IsCapCategoryOppositeMorphism ],
function( morphism )
return Concatenation( DisplayString( Opposite( morphism ) ), "\nA morphism in ", Name( CapCategory( morphism ) ), " given by the above data\n" );
end );
[ Dauer der Verarbeitung: 0.36 Sekunden
(vorverarbeitet)
]
|