-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Helpers for Information about Operations and Filters #1593
Conversation
d9a9111
to
fd37ebc
Compare
Codecov Report
@@ Coverage Diff @@
## master #1593 +/- ##
==========================================
+ Coverage 64.01% 64.01% +<.01%
==========================================
Files 996 998 +2
Lines 327615 327604 -11
Branches 13213 13212 -1
==========================================
- Hits 209717 209715 -2
+ Misses 115043 115038 -5
+ Partials 2855 2851 -4
|
ae303d5
to
671fac3
Compare
lib/type.gd
Outdated
|
||
############################################################################# | ||
## | ||
#F ClassOfOperation( <op> ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at TAB completions for Class
: there are tons of them. Perhaps call this KindOfOperation
instead? Or something else?
lib/type.gd
Outdated
## | ||
## <Description> | ||
## returns <C>true</C> if <A>object</A> is a category, and <C>false</C> | ||
## otherwise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somebody who is new to GAP and does not know about "GAP" categories, representations etc. might think that IsCategory
and IsRepresentation
deal with the mathematical concepts. This is unavoidable to a degree, but I think it would be helpful if we at least explain this in the help entries for them, e.g. by inserting a ref to the relevant sections on categories resp. representations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course such a link wouldn't hurt for the other IsFOO
functions either.
@@ -5,4 +5,4 @@ | |||
gap> IS_MUTABLE_OBJ; | |||
<Category "IsMutable"> | |||
gap> Setter(IS_MUTABLE_OBJ); | |||
<Category "<<filter-setter>>"> | |||
<Filter "<<filter-setter>>"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that right? What is causing this diff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short story: The diff was caused by a bug that I introduced in ClassOfOperation
.
Both Category
and Filter
are wrong though: a setter is neither a filter nor a category; I made a fix that detects setters and gives Setter
as the class of the operation.
hpcgap/tst/testinstall/type.tst
Outdated
<Category "IsMagma"> | ||
|
||
# | ||
gap> f := function() atomic readonly FILTER_REGION do return ForAll([1..Length(FILTERS)], id -> id = IdOfFilter(FILTERS[id])); od; end;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this wrapped into a function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If one doesn't use the function the result (true
or false
) is not printed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha. So how about Display(ForAll(...))
? Or perhaps even this:
gap> atomic readonly FILTER_REGION do filters := Immutable(FILTERS); od;
gap> ForAll([1..Length(filters)], id -> id = IdOfFilter(filters[id]));
true
8e99fb5
to
3ad3440
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except for minor nitpicks, this seems fine now.
lib/type.gi
Outdated
local type, flags, types, catok, repok, propok, seenprop, | ||
t, res; | ||
if not IsOperation(op) then | ||
ErrorNoReturn("<op> must be an operation"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost everywhere else, we say <oper>
. I'd adjust at the very least the error message, but perhaps also rename the argument?
Point is, if I see oper
anywhere in the GAP code, I immediately know what it means/is.
lib/type.gi
Outdated
fi; | ||
|
||
type := "Operation"; | ||
if IS_IDENTICAL_OBJ(op,IS_OBJECT) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space after comma?
hpcgap/tst/testinstall/type.tst
Outdated
<Category "IsMagma"> | ||
|
||
# | ||
gap> atomic readonly FILTER_REGION do Display(ForAll([1..Length(FILTERS)], id -> id = IdOfFilter(FILTERS[id]))); od; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So how about this:
gap> atomic readonly FILTER_REGION do filters := Immutable(FILTERS); od;
gap> ForAll([1..Length(filters)], id -> id = IdOfFilter(filters[id]));
true
fe8854f
to
56d768e
Compare
* ClassOfOperation, to determine the "class" of an operation which is one of filter, category, representation, property, attribute, or operation. * IsCategory, IsRepresentation, IsProperty, IsAttribute determine wheter an object is a category, property, or attribute respectively * FilterByName retrieve filter by name * IdOfFilter return the index of a given filter in the global list FILTERS of filters * IdOfFilterByName return the index of a filter in the global list of filters given its name * CategoryByName return category by name
edb5325
to
75873f8
Compare
It now detects setters correctly
75873f8
to
e939aad
Compare
Finally, tests pass so this is now ready. |
x -> IS_IDENTICAL_OBJ(x, IS_OBJECT) | ||
or ( IS_OPERATION( x ) | ||
and ( (FLAG1_FILTER( x ) <> 0 and FLAGS_FILTER(x) <> false) | ||
or x in FILTERS ) ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I am not sure I understand this (both old and new version). Perhaps we can walk through it? (And perhaps the comment above it could be expanded to explain it, too?)
So first we handle IS_OBJECT
/IsObject
, which is special. OK. next we exclude everything that is not an operation, also fine.
But now in the old code, we look at FLAG1_FILTER( x )
, and it is non-zero, we consider x
a filter. Aha. But this is not quite right, as we have:
gap> FLAG1_FILTER(Setter(IsPGroup));
625
So I guess that's why you changed this to also requite FLAGS_FILTER(x) <> false
? How about instead or additional using NARG_FUNC(x)=1
? I simply suggest that as it is immediately clear to me why that's a necessary condition for a filter, while FLAGS_FILTER(x) <> false
isn't (simply because I have to look up what it does). But anyway, if using FLAGS_FILTER
is "correct", that's also fine.
So... that leaves the question: Why do we need the final or x in FILTERS
? Aha:
gap> Length(FILTERS);
2212
gap> Number(FILTERS, x -> IsOperation(x) and FLAG1_FILTER(x) = 0);
905
gap> foo:=Filtered(FILTERS, x -> IsOperation(x) and FLAG1_FILTER(x) = 0);;
gap> for i in [1..10] do Display(Random(foo)); od;
<Filter "HasUpperCentralSeriesOfGroup">
<Filter "HasDecomposedRationalClass">
<Filter "HasOrdersClassRepresentatives">
<Filter "HasCharacteristic">
<Filter "HasFpElmEqualityMethod">
<Filter "HasBlocksAttr">
<Filter "HasLargestElementGroup">
<Filter "HasAlternatingSubgroup">
<Filter "HasExp">
<Filter "HasTestSubnormallyMonomial">
gap> HasExp; Exp;
<Filter "HasExp">
<Attribute "Exp">
gap> HasAlternatingSubgroup; AlternatingSubgroup;
<Filter "HasAlternatingSubgroup">
<Attribute "AlternatingSubgroup">
Aha! So testers for attributes fall through:
gap> FLAG1_FILTER(HasExp);
0
gap> FLAG2_FILTER(HasExp);
308
gap> FLAGS_FILTER(HasExp);
<flag list>
Hmm...
gap> Number(FILTERS, x -> IsOperation(x) and FLAGS_FILTER(x) = false);
0
gap> FLAGS_FILTER(IS_OBJECT);
<flag list>
gap> FLAG1_FILTER(Exp);
0
gap> FLAG2_FILTER(Exp);
308
gap> FLAGS_FILTER(Exp);
<flag list>
At this point I got a headache, and started to wonder: Why don't we add a bit "isFilter" to the header of an operation, and add an IS_FILTER
function to the kernel, which just returns that bit?
Note that we don't even need to grow the operation header for this, we could split ENABLED_ATTR
into a bitfield. (I'd start by adding an OperationHeader
struct, as described previously)
Anyway: none of that is necessary for this PR: even adding a better comment can come in another PR. Let's just not forget...
This the first part of #1236, but heavily refactored.
It adds the following
ClassOfOperation
, to determine the "class" of an operationwhich is one of filter, category, representation, property,
attribute, or operation.
IsCategory
,IsRepresentation
,IsProperty
,IsAttribute
determine wheter an object is a category, property, or
attribute respectively
FilterByName
retrieve filter by nameIdOfFilter
return the index of a given filter in the globallist FILTERS of filters
IdOfFilterByName
return the index of a filter in the globallist of filters given its name
CategoryByName
return category by name