diff --git a/CHANGES.md b/CHANGES.md
index 50a0499..c2422f7 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -3,6 +3,10 @@ This file describes changes in the smallgrp package.
# 1.6dev
- Require GAP 4.12
+ - `NumberSmallGroups` now accepts a list of orders and the selection
+ criteria of `AllSmallGroups`, as in `NumberSmallGroups(96, IsAbelian)`.
+ It counts by listing the ids, so it costs what `IdsOfAllSmallGroups`
+ costs (issue #68)
- Selection by `IsAbelian`, `IsNilpotentGroup`, `IsSupersolvableGroup`,
`IsSolvableGroup`, `RankPGroup` and `PClassPGroup` now avoids
constructing the groups for most orders which had no precomputed data,
diff --git a/gap/small.gd b/gap/small.gd
index 4ef887f..63b2698 100644
--- a/gap/small.gd
+++ b/gap/small.gd
@@ -703,6 +703,10 @@ DeclareGlobalFunction( "SelectSmallGroups" );
##
## reports which criteria are indexed
## for a given order.
+##
+## returns the ids of these groups instead
+## of the groups themselves, and just their
+## number.
## AllSmallGroups( 6 );
## [ ,
@@ -790,11 +794,12 @@ DeclareSynonym( "IdsOfAllGroups", IdsOfAllSmallGroups );
#############################################################################
##
#F NumberSmallGroups( )
+#F NumberSmallGroups( )
##
## <#GAPDoc Label="NumberSmallGroups">
##
-##
-##
+##
+##
##
##
## returns the number of groups of order order.
@@ -806,6 +811,21 @@ DeclareSynonym( "IdsOfAllGroups", IdsOfAllSmallGroups );
## gap> NumberSmallGroups( 4096 );
## Error, the library of groups of size 4096 is not available
## ]]>
+##
+## The function also accepts the arguments of
+## and counts the groups that function would
+## return.
+## NumberSmallGroups( [ 1 .. 100 ] );
+## 1048
+## gap> NumberSmallGroups( 96, IsAbelian );
+## 7
+## ]]>
+##
+## Orders alone are answered from the numbers of groups. Otherwise the
+## cost is that of : the indexed criteria
+## are applied first, whatever order the criteria are given in, and only
+## the groups a remaining criterion must be tested on are constructed.
##
##
## <#/GAPDoc>
diff --git a/gap/small.gi b/gap/small.gi
index a396f17..ccdae55 100644
--- a/gap/small.gi
+++ b/gap/small.gi
@@ -638,16 +638,12 @@ end );
#############################################################################
##
-#F NumberSmallGroups()
+#F SMALL_GROUPS_NUMBER( )
##
-## returns the number of groups of the order .
-InstallGlobalFunction( NumberSmallGroups, function( size )
+SMALL_GROUPS_NUMBER := function( size )
local inforec;
- if not IsPosInt( size ) then
- Error( "usage: NumberSmallGroups( order )" );
- fi;
- if size = 1024 then
+ if size = 1024 then
return 49487367289;
fi;
@@ -656,10 +652,51 @@ InstallGlobalFunction( NumberSmallGroups, function( size )
Error( "the library of groups of size ", size, " is not available" );
fi;
- if IsBound( inforec.number ) then
+ if IsBound( inforec.number ) then
return inforec.number;
fi;
return NUMBER_SMALL_GROUPS_FUNCS[ inforec.func ]( size, inforec ).number;
+end;
+
+#############################################################################
+##
+#F NumberSmallGroups()
+#F NumberSmallGroups()
+##
+## returns the number of the groups 'AllSmallGroups' would return for .
+InstallGlobalFunction( NumberSmallGroups, function( arg )
+ local argl, sizes;
+
+ # the classical form, just an order
+ if Length( arg ) = 1 and IsPosInt( arg[ 1 ] ) then
+ return SMALL_GROUPS_NUMBER( arg[ 1 ] );
+ fi;
+
+ # 'Size' may precede the orders
+ argl := arg;
+ if Length( argl ) > 0 and argl[ 1 ] = Size then
+ argl := argl{ [ 2 .. Length( argl ) ] };
+ fi;
+
+ # without a criterion the numbers of the orders just add up. A single
+ # list argument is the orders; a second one would be group numbers and
+ # is left to 'SelectSmallGroups'.
+ sizes := fail;
+ if Length( argl ) = 1 and IsList( argl[ 1 ] ) then
+ sizes := argl[ 1 ];
+ elif Length( argl ) > 0 and ForAll( argl, IsPosInt ) then
+ sizes := argl;
+ fi;
+ if sizes <> fail and ForAll( sizes, IsPosInt ) then
+ return Sum( sizes, SMALL_GROUPS_NUMBER );
+ fi;
+
+ if Length( arg ) <= 1 then
+ Error( "usage: NumberSmallGroups( order )" );
+ fi;
+
+ # so far counting the groups is not cheaper than listing their ids
+ return Length( SelectSmallGroups( arg, true, true ) );
end );
#############################################################################
diff --git a/tst/small.tst b/tst/small.tst
index 95d9064..7ceb05d 100644
--- a/tst/small.tst
+++ b/tst/small.tst
@@ -104,10 +104,18 @@ gap> IdGroup(G);
################################################################################
# NumberSmallGroups GlobalFunction
################################################################################
+gap> NumberSmallGroups();
+Error, usage: NumberSmallGroups( order )
gap> NumberSmallGroups(fail);
Error, usage: NumberSmallGroups( order )
gap> NumberSmallGroups(0);
Error, usage: NumberSmallGroups( order )
+gap> NumberSmallGroups(Size);
+Error, usage: NumberSmallGroups( order )
+gap> NumberSmallGroups("abc");
+Error, usage: NumberSmallGroups( order )
+gap> NumberSmallGroups([ 1, fail ]);
+Error, usage: NumberSmallGroups( order )
gap> NumberSmallGroups(19);
1
gap> NumberSmallGroups(1024);
@@ -121,6 +129,50 @@ gap> NumberSmallGroups(5^6);
gap> NumberSmallGroups(5*7*9*11*13);
22
+# orders alone need no group at all
+gap> NumberSmallGroups([]);
+0
+gap> NumberSmallGroups([ 1 .. 100 ]);
+1048
+gap> NumberSmallGroups(Size, [ 1 .. 100 ]);
+1048
+gap> NumberSmallGroups(60, 1024);
+49487367302
+gap> NumberSmallGroups(Size, [ 1000, 3996 ]);
+Error, the library of groups of size 3996 is not available
+
+# with selection criteria
+gap> NumberSmallGroups(96, IsAbelian);
+7
+gap> NumberSmallGroups(96, IsAbelian, false);
+224
+gap> NrSmallGroups(96, IsAbelian) + NrSmallGroups(96, IsAbelian, false)
+> = NrSmallGroups(96);
+true
+gap> NumberSmallGroups(Size, [ 1 .. 100 ], IsSolvableGroup, false);
+1
+gap> NumberSmallGroups(Size, 60, IsSupersolvableGroup, true);
+11
+gap> ForAll([ 1 .. 100 ], n -> NumberSmallGroups(n, IsNilpotentGroup)
+> = Length(IdsOfAllSmallGroups(n, IsNilpotentGroup)));
+true
+
+# the indexed criteria come first, whatever order they are given in
+gap> NumberSmallGroups(512, IsAbelian, true, Exponent, 2);
+1
+gap> NumberSmallGroups(512, Exponent, 2, IsAbelian, true);
+1
+
+# a list of group numbers may narrow down the selection
+gap> NumberSmallGroups(60, [ 1 .. 10 ]);
+10
+gap> NumberSmallGroups(60, [ 1 .. 10 ], IsNilpotentGroup);
+1
+
+# selection criteria need the library, even where the number does not
+gap> NumberSmallGroups(1024, IsAbelian);
+Error, AllSmallGroups / OneSmallGroup: groups of order 1024 not available
+
################################################################################
# SelectSmallGroups GlobalFunction (called by AllSmallGroups or OneSmallGroup)
################################################################################