Skip to content

Commit df70a6a

Browse files
committed
CAP: Avoid duplicate methods for primitive replacements
When a primitive CAP operation is replaced by another primitive implementation, update the category operation record without installing another method with identical filters. Installed dispatch methods now consult the current operation record, so the latest implementation is used while preserving the added_functions history. This avoids Julia method-overwrite errors during module precompilation. Add CapOperationInstallationInfo and emit a level-1 message when an accepted primitive installation replaces another primitive implementation. Include the operation, category, and old and new weights. CompilerForCAP previously used the number of accepted Add-functions as the expected number of installed GAP methods. These counts can differ depending on whether implementations are primitive, derived, final derived, or precompiled derived. In particular, replacing one primitive implementation with another changes the function used by the existing GAP method without installing a new method. Track the actual number of methods installed by CAP per operation and use it when checking for manually installed competing methods. Bump CAP to v2026.07-04 and CompilerForCAP to v2026.07-01.
1 parent 3f8578a commit df70a6a

6 files changed

Lines changed: 41 additions & 7 deletions

File tree

CAP/PackageInfo.g

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SetPackageInfo( rec(
1010

1111
PackageName := "CAP",
1212
Subtitle := "Categories, Algorithms, Programming",
13-
Version := "2026.07-03",
13+
Version := "2026.07-04",
1414
Date := (function ( ) if IsBound( GAPInfo.SystemEnvironment.GAP_PKG_RELEASE_DATE ) then return GAPInfo.SystemEnvironment.GAP_PKG_RELEASE_DATE; else return Concatenation( ~.Version{[ 1 .. 4 ]}, "-", ~.Version{[ 6, 7 ]}, "-01" ); fi; end)( ),
1515
License := "GPL-2.0-or-later",
1616

CAP/gap/CAP.gi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ InstallGlobalFunction( "CreateCapCategoryWithDataTypes", FunctionWithNamedArgume
333333
od;
334334

335335
obj!.added_functions := rec( );
336+
337+
obj!.number_of_installed_methods := rec( );
336338

337339
obj!.operations := rec( );
338340

CAP/gap/InstallAdds.gd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#! @Section InstallAdd Function
1010

11+
DeclareInfoClass( "CapOperationInstallationInfo" );
12+
1113
DeclareOperation( "AddCapOperation", [ IsString, IsCapCategory, IsFunction, IsInt ] );
1214

1315
DeclareGlobalFunction( "CAP_INTERNAL_INSTALL_ADDS_FROM_RECORD" );

CAP/gap/InstallAdds.gi

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ InstallMethod( AddCapOperation,
2323
[ "IsPrecompiledDerivation", false ],
2424
],
2525
function( CAP_NAMED_ARGUMENTS, function_name, category, func_to_install, weight )
26-
local record, category_name, is_derivation, is_final_derivation, is_precompiled_derivation, type, replaced_filter_list,
26+
local record, category_name, is_derivation, is_final_derivation, is_precompiled_derivation, type, replaces_primitive_installation, replaced_filter_list,
2727
input_human_readable_identifier_getter, input_sanity_check_functions, data_type, output_human_readable_identifier_getter,
2828
output_data_type, output_sanity_check_function, filter_string;
2929

@@ -68,6 +68,8 @@ InstallMethod( AddCapOperation,
6868
type := "primitive_installation";
6969

7070
fi;
71+
72+
replaces_primitive_installation := false;
7173

7274
# Display a warning in various cases when overwriting existing functions
7375
if IsBound( category!.operations.(function_name) ) then
@@ -88,6 +90,20 @@ InstallMethod( AddCapOperation,
8890
return;
8991

9092
fi;
93+
94+
replaces_primitive_installation :=
95+
category!.operations.( function_name ).type = "primitive_installation" and
96+
type = "primitive_installation";
97+
98+
if replaces_primitive_installation then
99+
100+
Info( CapOperationInstallationInfo, 1,
101+
"Duplicate primitive installation for ", function_name,
102+
" in category \"", category_name,
103+
"\": replacing weight ", category!.operations.( function_name ).weight,
104+
" with weight ", weight, "." );
105+
106+
fi;
91107

92108
if category!.operations.( function_name ).type = "primitive_installation" then
93109

@@ -221,6 +237,20 @@ InstallMethod( AddCapOperation,
221237
fi;
222238

223239
fi;
240+
241+
if replaces_primitive_installation then
242+
243+
return;
244+
245+
fi;
246+
247+
if not IsBound( category!.number_of_installed_methods.( function_name ) ) then
248+
249+
category!.number_of_installed_methods.( function_name ) := 0;
250+
251+
fi;
252+
253+
category!.number_of_installed_methods.( function_name ) := category!.number_of_installed_methods.( function_name ) + 1;
224254

225255
if not category!.overhead then
226256

@@ -229,7 +259,7 @@ InstallMethod( AddCapOperation,
229259

230260
function( arg )
231261

232-
return CallFuncList( func_to_install, arg );
262+
return CallFuncList( category!.operations.( function_name ).func, arg );
233263

234264
end );
235265

@@ -280,7 +310,7 @@ InstallMethod( AddCapOperation,
280310

281311
fi;
282312

283-
result := CallFuncList( func_to_install, arg );
313+
result := CallFuncList( category!.operations.( function_name ).func, arg );
284314

285315
if collect_timing_statistics then
286316

CompilerForCAP/PackageInfo.g

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SetPackageInfo( rec(
1010

1111
PackageName := "CompilerForCAP",
1212
Subtitle := "Speed up and verify categorical algorithms",
13-
Version := "2026.06-06",
13+
Version := "2026.07-01",
1414
Date := (function ( ) if IsBound( GAPInfo.SystemEnvironment.GAP_PKG_RELEASE_DATE ) then return GAPInfo.SystemEnvironment.GAP_PKG_RELEASE_DATE; else return Concatenation( ~.Version{[ 1 .. 4 ]}, "-", ~.Version{[ 6, 7 ]}, "-01" ); fi; end)( ),
1515
License := "GPL-2.0-or-later",
1616

@@ -70,7 +70,7 @@ Dependencies := rec(
7070
GAP := ">= 4.13.0",
7171
NeededOtherPackages := [
7272
[ "ToolsForHomalg", ">= 2026.04-01" ],
73-
[ "CAP", ">= 2026.06-03" ],
73+
[ "CAP", ">= 2026.07-04" ],
7474
],
7575
SuggestedOtherPackages := [ ],
7676
ExternalConditions := [ ],

CompilerForCAP/gap/ResolveOperations.gi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ InstallGlobalFunction( CapJitResolvedOperations, function ( tree )
159159
Info( InfoCapJit, 1, "####" );
160160
Info( InfoCapJit, 1, Concatenation( "Resolve CAP operation ", operation_name, ", recurse compilation." ) );
161161

162-
CAP_JIT_INTERNAL_WARN_ABOUT_SIMILAR_METHODS( operation, Length( info.filter_list ), [ CapJitDataTypeOfCategory( category ).filter ], Length( category!.added_functions.(operation_name) ), { operation_name } -> Concatenation(
162+
CAP_JIT_INTERNAL_WARN_ABOUT_SIMILAR_METHODS( operation, Length( info.filter_list ), [ CapJitDataTypeOfCategory( category ).filter ], category!.number_of_installed_methods.(operation_name), { operation_name } -> Concatenation(
163163
# COVERAGE_IGNORE_BLOCK_START
164164
"WARNING: A method for the CAP operation ", operation_name, " was installed manually (e.g. using Install(Other)Method), ",
165165
"but CompilerForCAP will always resolve the methods installed via CAP's Add-functions.\n"

0 commit comments

Comments
 (0)