|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Alexander Hulpke.
##
## Copyright of GAP belongs to its developers, whose names are too numerous
## to list here. Please refer to the COPYRIGHT file for details.
##
## SPDX-License-Identifier: GPL-2.0-or-later
##
## This file allows some fancy accesses to the method selection
##
#############################################################################
##
#F Print_Value(<val>)
##
## <ManSection>
## <Func Name="Print_Value" Arg='val'/>
##
## <Description>
## print a number factorized by SUM_FLAGS
## </Description>
## </ManSection>
##
BindGlobal("Print_Value_SFF",function(val)
if val>SUM_FLAGS and val < infinity then
Print(QuoInt(val,SUM_FLAGS),"*SUM_FLAGS");
val:=val mod SUM_FLAGS;
if val>0 then
Print("+",val);
fi;
else
Print(val);
fi;
end);
#############################################################################
##
#F ApplicableMethod( <opr>, <args>[, <printlevel>[, <nr>]] )
#F ApplicableMethodTypes( <opr>, <args>[, <printlevel>[, <nr>]] )
##
## <#GAPDoc Label="ApplicableMethod">
## <ManSection>
## <Func Name="ApplicableMethod" Arg='opr, args[, printlevel[, nr]]'/>
## <Func Name="ApplicableMethodTypes" Arg='opr, args[, printlevel[, nr]]'/>
##
## <Description>
## Called with two arguments, <Ref Func="ApplicableMethod"/> returns the
## method of highest rank that is applicable for the operation <A>opr</A>
## with the arguments in the list <A>args</A>.
## The default <A>printlevel</A> is <C>0</C>.
## If no method is applicable then <K>fail</K> is returned.
## <P/>
## If a positive integer is given as the fourth argument <A>nr</A> then
## <Ref Func="ApplicableMethod"/> returns the <A>nr</A>-th applicable method
## for the operation <A>opr</A> with the arguments in the list <A>args</A>,
## where the methods are ordered according to descending rank.
## If less than <A>nr</A> methods are applicable then <K>fail</K> is
## returned.
## <P/>
## If the fourth argument <A>nr</A> is the string <C>"all"</C> then
## <Ref Func="ApplicableMethod"/>
## returns a list of all applicable methods for <A>opr</A> with arguments
## <A>args</A>, ordered according to descending rank.
## <P/>
## Depending on the integer value <A>printlevel</A>, additional information is
## printed. Admissible values and their meaning are as follows.
## <P/>
## <List>
## <Mark>0</Mark>
## <Item>
## no information,
## </Item>
## <Mark>1</Mark>
## <Item>
## information about the applicable method,
## </Item>
## <Mark>2</Mark>
## <Item>
## also information about the not applicable methods of higher rank,
## </Item>
## <Mark>3</Mark>
## <Item>
## also for each not applicable method the first reason why it is not
## applicable,
## </Item>
## <Mark>4</Mark>
## <Item>
## also for each not applicable method all reasons why it is not
## applicable.
## </Item>
## <Mark>6</Mark>
## <Item>
## also the function body of the selected method(s)
## </Item>
## </List>
## <P/>
## When a method returned by <Ref Func="ApplicableMethod"/> is called then
## it returns either the desired result or the string
## <C>"TRY_NEXT_METHOD"</C>, which corresponds to a call to
## <Ref Func="TryNextMethod"/> in the method and means that
## the method selection would call the next applicable method.
## <P/>
## <E>Note:</E>
## The &GAP; kernel provides special treatment for the infix operations
## <C>\+</C>, <C>\-</C>, <C>\*</C>, <C>\/</C>, <C>\^</C>, <C>\mod</C> and
## <C>\in</C>.
## For some kernel objects (notably cyclotomic numbers,
## finite field elements and row vectors thereof) it calls kernel methods
## circumventing the method selection mechanism.
## Therefore for these operations <Ref Func="ApplicableMethod"/> may return
## a method which is not the kernel method actually used.
## <P/>
## The function <Ref Func="ApplicableMethodTypes"/> takes the <E>types</E>
## or <E>filters</E> of the arguments as argument (if only filters are given
## of course family predicates cannot be tested).
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL("ApplicableMethodTypes",function(arg)
local oper,narg,args,skip,verbos,fams,flags,i,j,methods,flag,flag2,
m,nam,val,erg,has,need,isconstructor;
if Length(arg)<2 or not IsList(arg[2]) or not IsFunction(arg[1]) then
Error("usage: ApplicableMethodTypes(<opr>,<arglist>[,<verbosity>[,<nr>]])");
fi;
oper:=arg[1];
isconstructor:=IS_CONSTRUCTOR(oper);
args:=arg[2];
if Length(arg)>2 then
verbos:=arg[3];
else
verbos:=0;
fi;
if Length(arg)>3 then
if IsInt( arg[4] ) then
skip:=arg[4] - 1;
else
skip:= -1;
fi;
erg:=[];
else
skip:=0;
fi;
narg:=Length(args);
# get families and filters
flags:=[];
fams:=[];
for i in args do
if IsFilter(i) then
Add(flags,WITH_IMPS_FLAGS(FLAGS_FILTER(i)));
Add(fams,fail);
elif IsType(i) then
Add(flags,i![2]);
Add(fams,i![1]);
else
Error("wrong kind of argument");
fi;
od;
if ForAny(fams,i->i=fail) then
fams:=fail;
Info(InfoWarning,1,"Family predicate cannot be tested");
fi;
methods:=MethodsOperation(oper,narg);
if verbos > 0 then
Print("#I Searching Method for ",NameFunction(oper)," with ",
Pluralize(narg, "argument"), ":\n");
fi;
if verbos > 0 then
Print("#I Total: ", Pluralize(Length(methods), "entry"), "\n");
fi;
for i in [1..Length(methods)] do
m := methods[i];
nam:=m.info;
val:=m.rank;
oper:=m.func;
if verbos>1 then
Print("#I Method ",i,": ``",nam,"''");
if IsBound(m.location) then
Print(" at ", m.location[1], ":", m.location[2]);
elif LocationFunc(oper) <> fail then
Print(" at ",LocationFunc(oper));
fi;
Print(", value: ");
Print_Value_SFF(val);
Print("\n");
fi;
flag:=true;
j:=1;
while j<=narg and (flag or verbos>3) and not m.early do
if j=1 and isconstructor then
flag2:=IS_SUBSET_FLAGS(m.argFilt[j],flags[j]);
else
flag2:=IS_SUBSET_FLAGS(flags[j],m.argFilt[j]);
fi;
flag:=flag and flag2;
if flag2=false and verbos>2 then
need:=NamesFilter(m.argFilt[j]);
if j=1 and isconstructor then
Print("#I - ",Ordinal(j)," argument must be ",
need,"\n");
else
has:=NamesFilter(flags[j]);
Print("#I - ",Ordinal(j)," argument needs ",
Filtered(need,i->not i in has),"\n");
fi;
fi;
j:=j+1;
od;
if flag then
if m.early or fams=fail or CallFuncList(m.famPred,fams) then
if verbos=1 then
Print("#I Method ",i,": ``",nam,"''");
if IsBound(m.location) then
Print(" at ", m.location[1], ":", m.location[2]);
elif LocationFunc(oper) <> fail then
Print(" at ",LocationFunc(oper));
fi;
Print(" , value: ");
Print_Value_SFF(val);
Print("\n");
fi;
if verbos>5 then
Print("#I Function Body:\n");
Print(oper);
fi;
if skip=0 then
return oper;
else
Add(erg,oper);
skip:=skip-1;
if verbos>0 then
Print("#I Skipped:\n");
fi;
fi;
elif verbos>2 then
Print("#I - bad family relations\n");
fi;
fi;
od;
if skip<0 then
return erg;
else
return fail;
fi;
end);
BIND_GLOBAL("ApplicableMethod",function(arg)
local i,l;
if Length(arg)<2 or not IsList(arg[2]) or not IsFunction(arg[1]) then
Error("usage: ApplicableMethod(<opr>,<arglist>[,<verbosity>[,<nr>]])");
fi;
l:=ShallowCopy(arg[2]);
for i in [1..Length(l)] do
if i=1 and IS_CONSTRUCTOR(arg[1]) then
l[i]:=l[i];
else
l[i]:=TypeObj(l[i]);
fi;
od;
arg[2]:=l;
return CallFuncList(ApplicableMethodTypes,arg);
end);
#############################################################################
##
#F ShowImpliedFilters( <filter> )
##
## <#GAPDoc Label="ShowImpliedFilters">
## <ManSection>
## <Func Name="ShowImpliedFilters" Arg='filter'/>
##
## <Description>
## Displays information about the filters that may be
## implied by <A>filter</A>. They are given by their names.
## <Ref Func="ShowImpliedFilters"/> first displays the names of all filters
## that are unconditionally implied by <A>filter</A>. It then displays
## implications that require further filters to be present (indicating
## by <C>+</C> the required further filters).
## <Example><![CDATA[
## gap> ShowImpliedFilters(IsNilpotentGroup);
## Implies:
## IsListOrCollection
## IsCollection
## IsDuplicateFree
## IsExtLElement
## CategoryCollections(IsExtLElement)
## IsExtRElement
## CategoryCollections(IsExtRElement)
## CategoryCollections(IsMultiplicativeElement)
## CategoryCollections(IsMultiplicativeElementWithOne)
## CategoryCollections(IsMultiplicativeElementWithInverse)
## IsGeneralizedDomain
## IsMagma
## IsMagmaWithOne
## IsMagmaWithInversesIfNonzero
## IsMagmaWithInverses
## IsAssociative
## HasMultiplicativeNeutralElement
## IsGeneratorsOfSemigroup
## IsSimpleSemigroup
## IsRegularSemigroup
## IsInverseSemigroup
## IsCompletelyRegularSemigroup
## IsGroupAsSemigroup
## IsMonoidAsSemigroup
## IsOrthodoxSemigroup
## IsSupersolvableGroup
## IsSolvableGroup
## IsNilpotentByFinite
##
##
## May imply with:
## +IsFinitelyGeneratedGroup
## IsPolycyclicGroup
##
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL("ShowImpliedFilters",function(filter)
local flags, implied, f, extra_implications, implication, name, diff_reqs,
diff_impls, reduced;
flags:=FLAGS_FILTER(filter);
implied := WITH_IMPS_FLAGS(flags);
atomic readonly IMPLICATIONS_SIMPLE do
# select all implications which involved <filter> in the requirements
f:=Filtered(IMPLICATIONS_SIMPLE, x->IS_SUBSET_FLAGS(x[2],flags));
Append(f, Filtered(IMPLICATIONS_COMPOSED, x->IS_SUBSET_FLAGS(x[2],flags)));
od; # end atomic
extra_implications:=[];
for implication in f do
# the additional requirements
diff_reqs:=SUB_FLAGS(implication[2],flags);
if SIZE_FLAGS(diff_reqs) = 0 then
Assert(0, IS_SUBSET_FLAGS(implied,implication[1]));
continue;
fi;
# the combined implications...
diff_impls:=implication[1];
# ... minus those implications that already follow from <filter>
diff_impls:=SUB_FLAGS(diff_impls,implied);
# ... minus those implications that already follow from diff_reqs
diff_impls:=SUB_FLAGS(diff_impls,WITH_IMPS_FLAGS(diff_reqs));
if SIZE_FLAGS(diff_impls) > 0 then
Add(extra_implications, [diff_reqs, diff_impls]);
fi;
od;
# remove "obvious" implications
if IS_ELEMENTARY_FILTER(filter) then
implied := SUB_FLAGS(implied, flags);
fi;
reduced:= function( trues )
atomic readonly FILTER_REGION do
return Filtered( trues,
i -> not ( INFO_FILTERS[i] in FNUM_TPRS
and FLAG1_FILTER( FILTERS[i] ) in trues ) );
od;
end;
if SIZE_FLAGS(implied) > 0 then
Print("Implies:\n");
for name in NamesFilter( reduced( TRUES_FLAGS( implied ) ) ) do
Print(" ",name,"\n");
od;
fi;
if Length(extra_implications) > 0 then
Print("\n\nMay imply with:\n");
for implication in extra_implications do
for name in NamesFilter( reduced( TRUES_FLAGS( implication[1] ) ) ) do
Print("+",name,"\n");
od;
for name in NamesFilter( reduced( TRUES_FLAGS( implication[2] ) ) ) do
Print(" ",name,"\n");
od;
Print("\n");
od;
fi;
end);
#############################################################################
##
#F ShowDeclarationsOfOperation( <oper> )
##
## <#GAPDoc Label="ShowDeclarationsOfOperation">
## <ManSection>
## <Func Name="ShowDeclarationsOfOperation" Arg='oper'/>
##
## <Description>
## Displays information about all declarations of the operation <A>oper</A>,
## including the location of each declaration and the argument filters.
## <Log><![CDATA[
## gap> ShowDeclarationsOfOperation(IsFinite);
## Available declarations for operation <Property "IsFinite">:
## 1: GAPROOT/lib/coll.gd:1451 with 1 argument, and filters [ IsListOrCollection ]
## 2: GAPROOT/lib/float.gd:212 with 1 argument, and filters [ IsFloat ]
## 3: GAPROOT/lib/ctbl.gd:1195 with 1 argument, and filters [ IsNearlyCharacterTable ]
## ]]></Log>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL("ShowDeclarationsOfOperation",function(oper)
local locs, reqs, i, r, f;
if not IsOperation(oper) then
Error("<oper> must be an operation");
fi;
Print("Available declarations for operation ", oper, ":\n");
locs := GET_DECLARATION_LOCATIONS(oper);
if locs = fail then
return;
fi;
reqs := GET_OPER_FLAGS(oper);
f := function(filt)
filt:=NamesFilter(filt);
if Length(filt) = 0 then filt := ["IsObject"]; fi;
return filt;
end;
for i in [1.. Length(locs)] do
r := List(reqs[i], r -> JoinStringsWithSeparator(f(r), " and \c"));
Print(String(i, 3), ": ", locs[i][1], "\c:", locs[i][2], "\c",
" with ", Length(reqs[i]), "\c",
" arguments, and filters [ ", "\c",
JoinStringsWithSeparator(r, ", "),
" ]\n"
);
od;
end);
#############################################################################
##
#F PageSource( func ) . . . . . . . . . . . . . . . show source code in pager
##
## <#GAPDoc Label="PageSource">
## <ManSection>
## <Func Name="PageSource" Arg='func[, nr]'/>
##
## <Description>
## This shows the file containing the source code of the function or method
## <A>func</A> in a pager (see <Ref Func="Pager"/>). The display starts at
## a line shortly before the code of <A>func</A>.<P/>
##
## For operations <A>func</A> the function shows the source code of the
## declaration of <A>func</A>. Operations can have several declarations, use
## the optional second argument to specify which one should be shown (in the
## order the declarations were read); the default is to show the first.<P/>
##
## For kernel functions the function tries to show the C source code.<P/>
##
## If GAP cannot find a file containing the source code this will be indicated.
## <P/>
## Usage examples:<Br/>
## <C>met := ApplicableMethod(\^, [(1,2),2743527]); PageSource(met);</C><Br/>
## <C>PageSource(Combinations);</C><Br/>
## <C>PageSource(SORT_LIST); </C><Br/>
## <C>PageSource(Size, 2);</C><Br/>
## <C>ct := CharacterTable(Group((1,2,3))); </C><Br/>
## <C>met := ApplicableMethod(Size,[ct]); PageSource(met); </C>
## <P/>
## </Description>
## </ManSection>
## <#/GAPDoc>
BIND_GLOBAL("PageSource", function ( fun, nr... )
local f, n, l, s, ss, locs;
if Length(nr) > 0 and IsPosInt(nr[1]) then
n := nr[1];
else
n := 1;
fi;
l := fail;
f := FILENAME_FUNC( fun );
if IsString(f) and Length(f)>0 and f[1] <> '/' then
# first assume it is a local path, otherwise look in GAP roots
if not IsReadableFile(f) then
if Length(f) > 7 and f{[1..8]} = "GAPROOT/" then
f := f{[9..Length(f)]};
fi;
f := Filename(List(GAPInfo.RootPaths, Directory), f);
fi;
fi;
if f = fail and fun in OPERATIONS then
# for operations we show the location(s) of their declaration
locs := GET_DECLARATION_LOCATIONS(fun);
if n > Length(locs) then
Print("Operation ", NameFunction(fun), " has only ",
Length(locs), " declarations. ",
"To find an installed method see ?ApplicableMethod.\n");
return;
else
if Length(locs) > 1 then
Print("Operation ", NameFunction(fun), " has ",
Length(locs), " declarations, showing number ", n, ". ",
"To find an installed method see ?ApplicableMethod.\n");
fi;
f := locs[n][1];
l := locs[n][2];
fi;
fi;
if f <> fail then
if l = fail then
l := STARTLINE_FUNC( fun );
if l <> fail then
l := Maximum(l-5, 1);
elif IsKernelFunction(fun) then
# page correct C source file and try to find line in C
# source starting `Obj Func<fun>`
s := String(fun);
ss:=SplitString(s,""," <>");
s := First(ss, a-> ':' in a);
if s <> fail then
ss := SplitString(s,":","");
l := Concatenation("Obj Func", ss[2]);
fi;
fi;
fi;
fi;
if f = fail or l = fail then
if IsKernelFunction(fun) then
Print("Cannot locate source of kernel function ",
NameFunction(fun),".\n");
else
Print( "Source not available.\n" );
fi;
else
if not IsExistingFile(f) and IsExistingFile(Concatenation(f, ".gz")) then
f:= Concatenation(f, ".gz");
fi;
if not (IsExistingFile(f) and IsReadableFile(f)) then
Print( "Cannot access code from file \"",f,"\".\n");
else
Print( "Showing source in ", f, " (from line ", l, ")\n" );
Pager(rec(lines := StringFile(f), formatted := true, start := l));
fi;
fi;
end);
[ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet)
]
|