1############################################################################# 2## 3## This file is part of GAP, a system for computational discrete algebra. 4## This file's authors include Alexander Hulpke. 5## 6## Copyright of GAP belongs to its developers, whose names are too numerous 7## to list here. Please refer to the COPYRIGHT file for details. 8## 9## SPDX-License-Identifier: GPL-2.0-or-later 10## 11## This file allows some fancy accesses to the method selection 12## 13 14############################################################################# 15## 16#F Print_Value(<val>) 17## 18## <ManSection> 19## <Func Name="Print_Value" Arg='val'/> 20## 21## <Description> 22## print a number factorized by SUM_FLAGS 23## </Description> 24## </ManSection> 25## 26BindGlobal("Print_Value_SFF",function(val) 27 if val>SUM_FLAGS then 28 Print(QuoInt(val,SUM_FLAGS),"*SUM_FLAGS"); 29 val:=val mod SUM_FLAGS; 30 if val>0 then 31 Print("+",val); 32 fi; 33 else 34 Print(val); 35 fi; 36end); 37 38############################################################################# 39## 40#F ApplicableMethod( <opr>, <args>[, <printlevel>[, <nr>]] ) 41#F ApplicableMethodTypes( <opr>, <args>[, <printlevel>[, <nr>]] ) 42## 43## <#GAPDoc Label="ApplicableMethod"> 44## <ManSection> 45## <Func Name="ApplicableMethod" Arg='opr, args[, printlevel[, nr]]'/> 46## <Func Name="ApplicableMethodTypes" Arg='opr, args[, printlevel[, nr]]'/> 47## 48## <Description> 49## Called with two arguments, <Ref Func="ApplicableMethod"/> returns the 50## method of highest rank that is applicable for the operation <A>opr</A> 51## with the arguments in the list <A>args</A>. 52## The default <A>printlevel</A> is <C>0</C>. 53## If no method is applicable then <K>fail</K> is returned. 54## <P/> 55## If a positive integer is given as the fourth argument <A>nr</A> then 56## <Ref Func="ApplicableMethod"/> returns the <A>nr</A>-th applicable method 57## for the operation <A>opr</A> with the arguments in the list <A>args</A>, 58## where the methods are ordered according to descending rank. 59## If less than <A>nr</A> methods are applicable then <K>fail</K> is 60## returned. 61## <P/> 62## If the fourth argument <A>nr</A> is the string <C>"all"</C> then 63## <Ref Func="ApplicableMethod"/> 64## returns a list of all applicable methods for <A>opr</A> with arguments 65## <A>args</A>, ordered according to descending rank. 66## <P/> 67## Depending on the integer value <A>printlevel</A>, additional information is 68## printed. Admissible values and their meaning are as follows. 69## <P/> 70## <List> 71## <Mark>0</Mark> 72## <Item> 73## no information, 74## </Item> 75## <Mark>1</Mark> 76## <Item> 77## information about the applicable method, 78## </Item> 79## <Mark>2</Mark> 80## <Item> 81## also information about the not applicable methods of higher rank, 82## </Item> 83## <Mark>3</Mark> 84## <Item> 85## also for each not applicable method the first reason why it is not 86## applicable, 87## </Item> 88## <Mark>4</Mark> 89## <Item> 90## also for each not applicable method all reasons why it is not 91## applicable. 92## </Item> 93## <Mark>6</Mark> 94## <Item> 95## also the function body of the selected method(s) 96## </Item> 97## </List> 98## <P/> 99## When a method returned by <Ref Func="ApplicableMethod"/> is called then 100## it returns either the desired result or the string 101## <C>"TRY_NEXT_METHOD"</C>, which corresponds to a call to 102## <Ref Func="TryNextMethod"/> in the method and means that 103## the method selection would call the next applicable method. 104## <P/> 105## <E>Note:</E> 106## The &GAP; kernel provides special treatment for the infix operations 107## <C>\+</C>, <C>\-</C>, <C>\*</C>, <C>\/</C>, <C>\^</C>, <C>\mod</C> and 108## <C>\in</C>. 109## For some kernel objects (notably cyclotomic numbers, 110## finite field elements and row vectors thereof) it calls kernel methods 111## circumventing the method selection mechanism. 112## Therefore for these operations <Ref Func="ApplicableMethod"/> may return 113## a method which is not the kernel method actually used. 114## <P/> 115## The function <Ref Func="ApplicableMethodTypes"/> takes the <E>types</E> 116## or <E>filters</E> of the arguments as argument (if only filters are given 117## of course family predicates cannot be tested). 118## </Description> 119## </ManSection> 120## <#/GAPDoc> 121## 122BIND_GLOBAL("ApplicableMethodTypes",function(arg) 123local oper,narg,args,skip,verbos,fams,flags,i,j,methods,flag,flag2, 124 m,nam,val,erg,has,need,isconstructor; 125 if Length(arg)<2 or not IsList(arg[2]) or not IsFunction(arg[1]) then 126 Error("usage: ApplicableMethodTypes(<opr>,<arglist>[,<verbosity>[,<nr>]])"); 127 fi; 128 oper:=arg[1]; 129 isconstructor:=IS_CONSTRUCTOR(oper); 130 args:=arg[2]; 131 if Length(arg)>2 then 132 verbos:=arg[3]; 133 else 134 verbos:=0; 135 fi; 136 if Length(arg)>3 then 137 if IsInt( arg[4] ) then 138 skip:=arg[4] - 1; 139 else 140 skip:= -1; 141 fi; 142 erg:=[]; 143 else 144 skip:=0; 145 fi; 146 narg:=Length(args); 147 148 # get families and filters 149 flags:=[]; 150 fams:=[]; 151 for i in args do 152 if IsFilter(i) then 153 Add(flags,FLAGS_FILTER(i)); 154 Add(fams,fail); 155 elif IsType(i) then 156 Add(flags,i![2]); 157 Add(fams,i![1]); 158 else 159 Error("wrong kind of argument"); 160 fi; 161 od; 162 163 if ForAny(fams,i->i=fail) then 164 fams:=fail; 165 Info(InfoWarning,1,"Family predicate cannot be tested"); 166 fi; 167 168 methods:=MethodsOperation(oper,narg); 169 if verbos > 0 then 170 Print("#I Searching Method for ",NameFunction(oper)," with ",narg, 171 " arguments:\n"); 172 fi; 173 if verbos > 0 then 174 Print("#I Total: ", Length(methods)," entries\n"); 175 fi; 176 for i in [1..Length(methods)] do 177 m := methods[i]; 178 nam:=m.info; 179 val:=m.rank; 180 oper:=m.func; 181 if verbos>1 then 182 Print("#I Method ",i,": ``",nam,"''"); 183 if IsBound(m.location) then 184 Print(" at ", m.location[1], ":", m.location[2]); 185 elif LocationFunc(oper) <> "" then 186 Print(" at ",LocationFunc(oper)); 187 fi; 188 Print(", value: "); 189 Print_Value_SFF(val); 190 Print("\n"); 191 fi; 192 flag:=true; 193 j:=1; 194 while j<=narg and (flag or verbos>3) do 195 if j=1 and isconstructor then 196 flag2:=IS_SUBSET_FLAGS(m.argFilt[j],flags[j]); 197 else 198 flag2:=IS_SUBSET_FLAGS(flags[j],m.argFilt[j]); 199 fi; 200 flag:=flag and flag2; 201 if flag2=false and verbos>2 then 202 need:=NamesFilter(m.argFilt[j]); 203 if j=1 and isconstructor then 204 Print("#I - ",Ordinal(j)," argument must be ", 205 need,"\n"); 206 else 207 has:=NamesFilter(flags[j]); 208 Print("#I - ",Ordinal(j)," argument needs ", 209 Filtered(need,i->not i in has),"\n"); 210 fi; 211 fi; 212 j:=j+1; 213 od; 214 if flag then 215 if fams=fail or CallFuncList(m.famPred,fams) then 216 if verbos=1 then 217 Print("#I Method ",i,": ``",nam,"''"); 218 if IsBound(m.location) then 219 Print(" at ", m.location[1], ":", m.location[2]); 220 elif LocationFunc(oper) <> "" then 221 Print(" at ",LocationFunc(oper)); 222 fi; 223 Print(" , value: "); 224 Print_Value_SFF(val); 225 Print("\n"); 226 fi; 227 if verbos>5 then 228 Print("#I Function Body:\n"); 229 Print(oper); 230 fi; 231 if skip=0 then 232 return oper; 233 else 234 Add(erg,oper); 235 skip:=skip-1; 236 if verbos>0 then 237 Print("#I Skipped:\n"); 238 fi; 239 fi; 240 elif verbos>2 then 241 Print("#I - bad family relations\n"); 242 fi; 243 fi; 244 od; 245 if skip<0 then 246 return erg; 247 else 248 return fail; 249 fi; 250end); 251 252BIND_GLOBAL("ApplicableMethod",function(arg) 253local i,l; 254 if Length(arg)<2 or not IsList(arg[2]) or not IsFunction(arg[1]) then 255 Error("usage: ApplicableMethod(<opr>,<arglist>[,<verbosity>[,<nr>]])"); 256 fi; 257 l:=ShallowCopy(arg[2]); 258 for i in [1..Length(l)] do 259 if i=1 and IS_CONSTRUCTOR(arg[1]) then 260 l[i]:=l[i]; 261 else 262 l[i]:=TypeObj(l[i]); 263 fi; 264 od; 265 arg[2]:=l; 266 return CallFuncList(ApplicableMethodTypes,arg); 267end); 268 269############################################################################# 270## 271#F ShowImpliedFilters( <filter> ) 272## 273## <#GAPDoc Label="ShowImpliedFilters"> 274## <ManSection> 275## <Func Name="ShowImpliedFilters" Arg='filter'/> 276## 277## <Description> 278## Displays information about the filters that may be 279## implied by <A>filter</A>. They are given by their names. 280## <Ref Func="ShowImpliedFilters"/> first displays the names of all filters 281## that are unconditionally implied by <A>filter</A>. It then displays 282## implications that require further filters to be present (indicating 283## by <C>+</C> the required further filters). 284## <Example><![CDATA[ 285## gap> ShowImpliedFilters(IsNilpotentGroup); 286## Implies: 287## IsListOrCollection 288## IsCollection 289## IsDuplicateFree 290## IsExtLElement 291## CategoryCollections(IsExtLElement) 292## IsExtRElement 293## CategoryCollections(IsExtRElement) 294## CategoryCollections(IsMultiplicativeElement) 295## CategoryCollections(IsMultiplicativeElementWithOne) 296## CategoryCollections(IsMultiplicativeElementWithInverse) 297## IsGeneralizedDomain 298## IsMagma 299## IsMagmaWithOne 300## IsMagmaWithInversesIfNonzero 301## IsMagmaWithInverses 302## IsAssociative 303## HasMultiplicativeNeutralElement 304## IsGeneratorsOfSemigroup 305## IsSimpleSemigroup 306## IsRegularSemigroup 307## IsInverseSemigroup 308## IsCompletelyRegularSemigroup 309## IsGroupAsSemigroup 310## IsMonoidAsSemigroup 311## IsOrthodoxSemigroup 312## IsSupersolvableGroup 313## IsSolvableGroup 314## IsNilpotentByFinite 315## 316## 317## May imply with: 318## +IsFinitelyGeneratedGroup 319## IsPolycyclicGroup 320## 321## ]]></Example> 322## </Description> 323## </ManSection> 324## <#/GAPDoc> 325## 326BIND_GLOBAL("ShowImpliedFilters",function(filter) 327 local flags, implied, f, extra_implications, implication, name, diff_reqs, 328 diff_impls, reduced; 329 330 flags:=FLAGS_FILTER(filter); 331 implied := WITH_IMPS_FLAGS(flags); 332 atomic readonly IMPLICATIONS_SIMPLE do 333 # select all implications which involved <filter> in the requirements 334 f:=Filtered(IMPLICATIONS_SIMPLE, x->IS_SUBSET_FLAGS(x[2],flags)); 335 Append(f, Filtered(IMPLICATIONS_COMPOSED, x->IS_SUBSET_FLAGS(x[2],flags))); 336 od; # end atomic 337 338 extra_implications:=[]; 339 for implication in f do 340 # the additional requirements 341 diff_reqs:=SUB_FLAGS(implication[2],flags); 342 if SIZE_FLAGS(diff_reqs) = 0 then 343 Assert(0, IS_SUBSET_FLAGS(implied,implication[1])); 344 continue; 345 fi; 346 # the combined implications... 347 diff_impls:=implication[1]; 348 # ... minus those implications that already follow from <filter> 349 diff_impls:=SUB_FLAGS(diff_impls,implied); 350 # ... minus those implications that already follow from diff_reqs 351 diff_impls:=SUB_FLAGS(diff_impls,WITH_IMPS_FLAGS(diff_reqs)); 352 if SIZE_FLAGS(diff_impls) > 0 then 353 Add(extra_implications, [diff_reqs, diff_impls]); 354 fi; 355 od; 356 357 # remove "obvious" implications 358 if IS_ELEMENTARY_FILTER(filter) then 359 implied := SUB_FLAGS(implied, flags); 360 fi; 361 362 reduced:= function( trues ) 363 atomic readonly FILTER_REGION do 364 return Filtered( trues, 365 i -> not ( INFO_FILTERS[i] in FNUM_TPRS 366 and FLAG1_FILTER( FILTERS[i] ) in trues ) ); 367 od; 368 end; 369 370 if SIZE_FLAGS(implied) > 0 then 371 Print("Implies:\n"); 372 for name in NamesFilter( reduced( TRUES_FLAGS( implied ) ) ) do 373 Print(" ",name,"\n"); 374 od; 375 fi; 376 377 if Length(extra_implications) > 0 then 378 Print("\n\nMay imply with:\n"); 379 for implication in extra_implications do 380 for name in NamesFilter( reduced( TRUES_FLAGS( implication[1] ) ) ) do 381 Print("+",name,"\n"); 382 od; 383 for name in NamesFilter( reduced( TRUES_FLAGS( implication[2] ) ) ) do 384 Print(" ",name,"\n"); 385 od; 386 Print("\n"); 387 od; 388 fi; 389end); 390 391 392############################################################################# 393## 394#F ShowDeclarationsOfOperation( <oper> ) 395## 396## <#GAPDoc Label="ShowDeclarationsOfOperation"> 397## <ManSection> 398## <Func Name="ShowDeclarationsOfOperation" Arg='oper'/> 399## 400## <Description> 401## Displays information about all declarations of the operation <A>oper</A>, 402## including the location of each declaration and the argument filters. 403## <Log><![CDATA[ 404## gap> ShowDeclarationsOfOperation(IsFinite); 405## Available declarations for operation <Property "IsFinite">: 406## 1: GAPROOT/lib/coll.gd:1451 with 1 arguments, and filters [ IsListOrCollection ] 407## 2: GAPROOT/lib/float.gd:212 with 1 arguments, and filters [ IsFloat ] 408## 3: GAPROOT/lib/ctbl.gd:1195 with 1 arguments, and filters [ IsNearlyCharacterTable ] 409## ]]></Log> 410## </Description> 411## </ManSection> 412## <#/GAPDoc> 413## 414BIND_GLOBAL("ShowDeclarationsOfOperation",function(oper) 415 local locs, reqs, i, r; 416 if not IsOperation(oper) then 417 Error("<oper> must be an operation"); 418 fi; 419 Print("Available declarations for operation ", oper, ":\n"); 420 locs := GET_DECLARATION_LOCATIONS(oper); 421 if locs = fail then 422 return; 423 fi; 424 reqs := GET_OPER_FLAGS(oper); 425 for i in [1.. Length(locs)] do 426 r := List(reqs[i], r -> JoinStringsWithSeparator(NamesFilter(r), " and \c")); 427 Print(String(i, 3), ": ", locs[i][1], "\c:", locs[i][2], "\c", 428 " with ", Length(reqs[i]), "\c", 429 " arguments, and filters [ ", "\c", 430 JoinStringsWithSeparator(r, ", "), 431 " ]\n" 432 ); 433 od; 434end); 435 436 437############################################################################# 438## 439#F PageSource( func ) . . . . . . . . . . . . . . . show source code in pager 440## 441## <#GAPDoc Label="PageSource"> 442## <ManSection> 443## <Func Name="PageSource" Arg='func[, nr]'/> 444## 445## <Description> 446## This shows the file containing the source code of the function or method 447## <A>func</A> in a pager (see <Ref Func="Pager"/>). The display starts at 448## a line shortly before the code of <A>func</A>.<P/> 449## 450## For operations <A>func</A> the function shows the source code of the 451## declaration of <A>func</A>. Operations can have several declarations, use 452## the optional second argument to specify which one should be shown (in the 453## order the declarations were read); the default is to show the first.<P/> 454## 455## For kernel functions the function tries to show the C source code.<P/> 456## 457## If GAP cannot find a file containing the source code this will be indicated. 458## <P/> 459## Usage examples:<Br/> 460## <C>met := ApplicableMethod(\^, [(1,2),2743527]); PageSource(met);</C><Br/> 461## <C>PageSource(Combinations);</C><Br/> 462## <C>PageSource(SORT_LIST); </C><Br/> 463## <C>PageSource(Size, 2);</C><Br/> 464## <C>ct := CharacterTable(Group((1,2,3))); </C><Br/> 465## <C>met := ApplicableMethod(Size,[ct]); PageSource(met); </C> 466## <P/> 467## </Description> 468## </ManSection> 469## <#/GAPDoc> 470BIND_GLOBAL("PageSource", function ( fun, nr... ) 471 local f, n, l, s, ss, locs; 472 473 if Length(nr) > 0 and IsPosInt(nr[1]) then 474 n := nr[1]; 475 else 476 n := 1; 477 fi; 478 l := fail; 479 f := FILENAME_FUNC( fun ); 480 if IsString(f) and Length(f)>0 and f[1] <> '/' then 481 # first assume it is a local path, otherwise look in GAP roots 482 if not IsReadableFile(f) then 483 if Length(f) > 7 and f{[1..8]} = "GAPROOT/" then 484 f := f{[9..Length(f)]}; 485 fi; 486 f := Filename(List(GAPInfo.RootPaths, Directory), f); 487 fi; 488 fi; 489 if f = fail and fun in OPERATIONS then 490 # for operations we show the location(s) of their declaration 491 locs := GET_DECLARATION_LOCATIONS(fun); 492 if n > Length(locs) then 493 Print("Operation ", NameFunction(fun), " has only ", 494 Length(locs), " declarations.\n"); 495 return; 496 else 497 if Length(locs) > 1 then 498 Print("Operation ", NameFunction(fun), " has ", 499 Length(locs), " declarations, showing number ", n, ".\n"); 500 fi; 501 f := locs[n][1]; 502 l := locs[n][2]; 503 fi; 504 fi; 505 if f <> fail then 506 if l = fail then 507 l := STARTLINE_FUNC( fun ); 508 if l <> fail then 509 l := Maximum(l-5, 1); 510 elif IsKernelFunction(fun) then 511 # page correct C source file and try to find line in C 512 # source starting `Obj Func<fun>` 513 s := String(fun); 514 ss:=SplitString(s,""," <>"); 515 s := First(ss, a-> ':' in a); 516 if s <> fail then 517 ss := SplitString(s,":",""); 518 l := Concatenation("/Obj *Func", ss[2]); 519 fi; 520 fi; 521 fi; 522 fi; 523 if f = fail or l = fail then 524 if IsKernelFunction(fun) then 525 Print("Cannot locate source of kernel function ", 526 NameFunction(fun),".\n"); 527 else 528 Print( "Source not available.\n" ); 529 fi; 530 elif not (IsExistingFile(f) and IsReadableFile(f)) then 531 Print( "Cannot access code from file \"",f,"\".\n"); 532 else 533 Print( "Showing source in ", f, " (from line ", l, ")\n" ); 534 Pager(rec(lines := StringFile(f), formatted := true, start := l)); 535 fi; 536end); 537