if current_function_argument_number >= 0 and current_function_argument_number <> number_of_proposed_arguments then
Error( "while adding a derivation for ", target_op_name, ": given function has ", current_function_argument_number, " arguments but should have ", number_of_proposed_arguments );
fi;
fi;
#= comment for Julia if PositionSublist( String( category_filter ), "CanCompute" ) <> fail then
Print( "WARNING: The CategoryFilter of a derivation for ", target_op_name, " uses `CanCompute`. Please register all preconditions explicitly.\n" );
fi; # =#
# canonicalize used ops
used_op_names_with_multiples_and_category_getters := [ ];
for x in used_ops_with_multiples_and_category_getters do
if Length( x ) < 2 or not IsFunction( x[1] ) or not IsInt( x[2] ) then
Error( "preconditions must be of the form `[op, mult, getter]`, where `getter` is optional" );
fi;
if (Length( x ) = 2 or (Length( x ) = 3 and x[3] = fail)) and NameFunction( x[1] ) = target_op_name then
Error( "A derivation for ", target_op_name, " has itself as a precondition. This is not supported because we cannot compute a well-defined weight.\n" );
if Length( collected_list ) <> Length( used_op_names_with_multiples_and_category_getters ) or not ForAll( collected_list, c -> c in used_op_names_with_multiples_and_category_getters ) then
SortBy( used_op_names_with_multiples_and_category_getters, x -> x[1] );
SortBy( collected_list, x -> x[1] );
Print( "WARNING: You have installed a derivation for ", target_op_name, " with preconditions ", used_op_names_with_multiples_and_category_getters, " but the automated detection has detected the following list of preconditions: ", collected_list, ".\n", "If this is a bug in the automated detection, please report it.\n"
);
fi;
fi; # =#
if NumberArgumentsFunction( category_filter ) = 0 or NumberArgumentsFunction( category_filter ) > 1then
Error( "the CategoryFilter of a derivation must accept exactly one argument" );
fi;
if ForAny( used_op_names_with_multiples_and_category_getters, x -> x[3] <> fail ) and category_filter = IsCapCategory then
Print( "WARNING: A derivation for ", target_op_name, " depends on other categories (e.g. RangeCategoryOfHomomorphismStructure) but does no test via the CategoryFilter if the other categories are available (e.g. by testing HasRangeCategoryOfHomomorphismStructure).\n" );
fi;
if IsProperty( category_filter ) then
# for Julia
wrapped_category_filter := cat -> Tester( category_filter )( cat ) and category_filter( cat );
#= comment for Julia
wrapped_category_filter := Tester( category_filter ) and category_filter; # =#
InstallMethod( String,
[ IsDerivedMethod ], function( d )
return Concatenation( "derivation ", Description( d ), " of operation ", TargetOperation( d ) ); end );
InstallMethod( ViewString,
[ IsDerivedMethod ], function( d )
return Concatenation( "<", String( d ), ">" ); end );
InstallMethod( IsApplicableToCategory,
[ IsDerivedMethod, IsCapCategory ], function( d, C )
return CategoryFilter( d )( C ); end );
for x in UsedOperationsWithMultiplesAndCategoryGetters( derivation ) do # We add all operations, even those with category getters: In case the category getter # returns the category itself, this allows to recursively trigger derivations correctly.
Add( graph!.derivations_by_used_ops.(x[1]), derivation );
od;
if IsEmpty( UsedOperationsWithMultiplesAndCategoryGetters( derivation ) ) then
InstallGlobalFunction( AddDerivationToCAP, FunctionWithNamedArguments(
[ # When compiling categories, a derivation does not cause overhead anymore, so we would like to simply set `Weight` to 0. # However, the weight 1 is currently needed to prevent the installation of cyclic derivations.
[ "Weight", 1 ],
[ "CategoryFilter", IsCapCategory ],
[ "WeightLoopMultiple", 2 ],
[ "CategoryGetters", Immutable( rec( ) ) ],
[ "FunctionCalledBeforeInstallation", false ],
[ "is_with_given_derivation", false ],
[ "is_autogenerated_by_CompilerForCAP", false ],
], function( CAP_NAMED_ARGUMENTS, target_op, description, used_ops_with_multiples_and_category_getters, func )
local weight, category_filter, loop_multiplier, category_getters, function_called_before_installation, option_is_with_given_derivation, option_is_autogenerated_by_CompilerForCAP;
if new_weight < current_weight or (new_weight = current_weight and current_derivation <> fail and d!.position_in_derivations_by_target < current_derivation!.position_in_derivations_by_target) then
for op_name in Operations( DerivationGraph( owl ) ) do
for d in DerivationsOfOperation( DerivationGraph( owl ), op_name ) do
TryToTriggerDerivation( owl, d );
od;
od;
end );
InstallMethod( Saturate,
[ IsOperationWeightList ], function( owl )
local current_weight_list;
while true do
current_weight_list := StructuralCopy( owl!.operation_weights );
Reevaluate( owl ); if current_weight_list = owl!.operation_weights then
break; fi;
od;
InstallMethod( PrintDerivationTree,
[ IsOperationWeightList, IsString ], function( owl, op_name )
local print_node, get_children;
print_node := function( node )
local w, mult, op, d;
mult := node[ 2 ];
op := node[ 1 ]; if op = fail then
Print( " ", mult );
return; fi;
w := CurrentOperationWeight( owl, op );
d := DerivationOfOperation( owl, op ); if mult <> fail then
Print( "+ ", mult, " * " ); fi; if w = infinity then
Print( "(not installed)" ); else
Print( "(", w, ")" ); fi;
Print( " ", op ); if w <> infinity then
Print( " " ); if d = fail then
Print( "[primitive]" ); else
Print( "[derived:", Description( d ), "]" ); fi; fi; end;
get_children := function( node )
local op, d;
op := node[ 1 ]; if op = fail then
return []; fi;
d := DerivationOfOperation( owl, op ); if d = fail then
return []; else
return Concatenation( [ [ fail, AdditionalWeight( d ) ] ],
UsedOperationsWithMultiplesAndCategoryGetters( d ) ); fi; end;
PrintTree( [ op_name, fail ],
print_node,
get_children ); end );
InstallGlobalFunction( AddFinalDerivation, FunctionWithNamedArguments(
[ # When compiling categories, a derivation does not cause overhead anymore, so we would like to simply set `Weight` to 0. # However, the weight 1 is currently needed to prevent the installation of cyclic derivations.
[ "Weight", 1 ],
[ "CategoryFilter", IsCapCategory ],
[ "WeightLoopMultiple", 2 ],
[ "CategoryGetters", Immutable( rec( ) ) ],
[ "FunctionCalledBeforeInstallation", false ],
], function( CAP_NAMED_ARGUMENTS, target_op, description, can_compute, cannot_compute, func )
InstallGlobalFunction( AddFinalDerivationBundle, FunctionWithNamedArguments(
[ # When compiling categories, a derivation does not cause overhead anymore, so we would like to simply set `Weight` to 0. # However, the weight 1 is currently needed to prevent the installation of cyclic derivations.
[ "Weight", 1 ],
[ "CategoryFilter", IsCapCategory ],
[ "WeightLoopMultiple", 2 ],
[ "CategoryGetters", Immutable( rec( ) ) ],
[ "FunctionCalledBeforeInstallation", false ],
], function( CAP_NAMED_ARGUMENTS, description, can_compute, cannot_compute, additional_functions... )
local weight, category_filter, loop_multiplier, category_getters, function_called_before_installation, operations_to_install, union_of_collected_lists, derivations, derivation, used_op_names_with_multiples_and_category_getters, dummy_derivation, final_derivation, i, x, current_additional_func;
Error( "trying to add a final derivation without any functions to install" );
fi;
for i in [ 1 .. Length( additional_functions ) ] do
if not (IsList( additional_functions[i] ) and Length( additional_functions[i] ) = 3) then
Error( "additional functions must be given as triples [ <operation>, <preconditions>, <function> ]" );
fi;
if IsList( Last( additional_functions[i] ) ) then
Error( "passing lists of functions to `AddFinalDerivation` is not supported anymore" );
fi;
if not additional_functions[i][1] in cannot_compute then
Print( "WARNING: A final derivation installs ", NameFunction( additional_functions[i][1] ), " but does not list it in its exclude list.\n" );
fi;
od;
for x in can_compute do
if Length( x ) < 2 or not IsFunction( x[1] ) or not IsInt( x[2] ) then
Error( "preconditions must be of the form `[op, mult, getter]`, where `getter` is optional" );
fi;
# check that preconditions do not appear in cannot_compute (which in particular includes all operations installed by this final derivation, as checked above) if (Length( x ) = 2 or (Length( x ) = 3 and x[3] = fail)) and x[1] in cannot_compute then
Error( "A final derivation for ", NameFunction( additional_functions[1][1] ), " has precondition ", NameFunction( x[1] ), " which is also in its exclude list.\n" );
fi;
od;
if Length( additional_functions ) = 1 and StartsWith( NameFunction( additional_functions[1][1] ), "IsomorphismFrom" ) then
Print( "WARNING: You are installing a final derivation for ", NameFunction( additional_functions[1][1] ), " which does not include its inverse. You should probably use a bundled final derivation to also install its inverse.\n" );
fi;
## Find symbols in functions
operations_to_install := [ ];
union_of_collected_lists := [ ];
derivations := [ ];
for current_additional_func in additional_functions do
# Operations may use operations from the same final derivation as long as the latter are installed before the former. # In this case, the used operations are no preconditions and thus should not go into union_of_collected_lists.
used_op_names_with_multiples_and_category_getters := Filtered( used_op_names_with_multiples_and_category_getters, x -> not x[1] in operations_to_install );
# only used to check if we can install all the derivations in `derivations`
dummy_derivation := CreateDerivation( "internal dummy function of a final derivation", "dummy derivation",
can_compute,
ReturnTrue, 1,
category_filter,
loop_multiplier,
category_getters
);
if Length( union_of_collected_lists ) <> Length( used_op_names_with_multiples_and_category_getters ) or not ForAll( union_of_collected_lists, c -> c in used_op_names_with_multiples_and_category_getters ) then
SortBy( used_op_names_with_multiples_and_category_getters, x -> x[1] );
SortBy( union_of_collected_lists, x -> x[1] );
Print( "WARNING: You have installed a final derivation for ", TargetOperation( derivations[1] ), " with preconditions ", used_op_names_with_multiples_and_category_getters, " but the following list of preconditions was expected: ", union_of_collected_lists, ".\n", "If this is a bug in the automated detection, please report it.\n"
);
# Trigger ordinary derivations, but do not install them yet: # While triggering derivations, cheaper derivations can become available, but we do not want to overwrite methods.
# When installing a final derivation bundle, the installation of the first operations in the bundle # might trigger (normal) derivations of later operations it the bundle, which might be cheaper then # the derivations provided in the bundle. if new_weight <= current_weight then
function( cell )
local weight_list, list_of_methods, i, current_weight, can_compute, cannot_compute;
if IsCapCategory( cell ) then
weight_list := cell!.derivations_weight_list; elif IsCapCategoryCell( cell ) then
weight_list := CapCategory( cell )!.derivations_weight_list; else
Error( "Input must be a category or a cell" ); fi;
# `SizeScreen()[1] - 3` is taken from the code for package banners
Print( ListWithIdenticalEntries( SizeScreen()[1] - 3, '-' ), "\n" ); if category_filter( category ) then
Print( TextAttr.b4, name, TextAttr.reset, " can be derived by\n" ); else if IsFilter( category_filter ) then
Print( "If ", Name( category ), " would be ", JoinStringsWithSeparator( Filtered( NamesFilter( category_filter ), name -> not StartsWith( name, "Has" ) ), " and " ) ); else
Print( "If ", Name( category ), " would fulfill the conditions given by\n\n" );
Display( category_filter ); fi;
Print( "\nthen ", TextAttr.b4, name, TextAttr.reset, " could be derived by\n" ); fi;
for x in UsedOperationsWithMultiplesAndCategoryGetters( current_derivation.derivation ) do
if x[3] = fail then
if CanCompute( category, x[1] ) then
weight := OperationWeight( category, x[1] );
else
weight := infinity;
fi;
category_getter_string := "";
else
if category_filter( category ) and CanCompute( x[3](category), x[1] ) then
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.