Examples
User documentation
The main reason for creating a DivMask is to permit a quick, coarse
test of divisibility between power products -- but before you read on, you
might like to consider using PPWithMask instead, which offers
essentially the same advantages with a *much more convenient interface*.
We say that DivMasks permit a "coarse" test because we accept as
responses definitely not divisible or possibly divisible (but
further checks must be conducted to decide for certain).
For example the radical of a PP .... (WORK-IN-PROGRESS)
DivMasks are
a fairly low-level concept, and probably of little use to most normal
CoCoALib users. If you need to do conduct a great many divisibility tests
(between power products) and think you're interested, read on (assuming you
have already decided that PPWithMask does not fulfill your needs).
Note: currently DivMasks cannot be used to ascertain coprimality (see Bugs section).
To use DivMasks you must master two concepts. Firstly, the DivMask
itself is simply a bitset wrapped up in a class. The size of the bitset is
determined at compile time. There are various rules for how to set the
bits in the bitset, but they all satisfy the following guiding principle:
ift1dividest2then(DivMask(t1) & DivMask(t2)) == DivMask(t1)
i.e.DivMask(t1)is a "subset" ofDivMask(t2)
There are no other guarantees: in particular, the converse of the guiding principle does not hold in general.
Constructors and pseudo-constructors
You can create five different sorts of DivMaskRule:
WORK-IN-PROGRESS: explain what a DivMaskRule is
-
NewDivMaskNull(); -
no bit is ever set (relatively fast, but otherwise pretty useless).
(It is useful when a
DivMaskRuleis required and you know you won't use it) -
NewDivMaskSingleBit(); -
if the
k-th exponent in the PP is strictly positive then thek-th bit is set: at most a single bit is used for each indeterminate, indets withindex >= DivMask::ourMaskWidthare ignored completely. -
NewDivMaskSingleBitWrap(); -
if the
k-th exponent in the PP is strictly positive then thek%DivMask::ourMaskWidth-th bit is set: all indets are taken into account, and each bit is used for a set of indeterminates. This implementation is good when we have many indeterminates in supposedly sparse PPs. (So far I don't have good examples with more than 2*ourMaskWidth indeterminates) -
NewDivMaskEvenPowers(); -
This rule may set several bits for a PP divisible by a "high" power of
an indeterminate. For instance, with a mask width of
32 and 4 indets, up to 8 bits can be set for each indet: sets 1 bit if
exponent is 1 or 2, set 2 bits if exponent is 3 or 4, etc. The actual number
of bits set is
ceiling(exponent/2). This implementation is good when we have few indeterminates with high exponents (e.g. Buchberger's algorithm). It is equivalent toSingleBitWrapImplif the number of indets is bigger thanourMaskWidth. -
NewDivMaskHashing(); -
this rule uses a hashing scheme to allow many bits to be set for each indet
even when there are many indets. The number of bits set for an indet
is
ceiling(sqrt(exponent)). Supposedly the implementation works well in all cases (e.g. few indets and high degrees, or many indets and low degrees) For indet x the first bit set has indexx%ourMaskWidth, and in general the k-th bit set has index(x + k*hash2)%ourMaskWidth. (See code for definition of hash2)
Operations
Operations with DivMaskRule
The type DivMaskRule is used to set the bits in a DivMask object.
The possible function calls are:
DMR->myAssignFromExpv(mask, exps, NumIndets)-- sets mask according to PP with exponent vector exps. Currently the parameterexpsmust be of typevector<SmallExponent_t>, but this may change. This function might be quite expensive and its cost depends on theDivMaskRule, but this is not a problem if it is called much more rarely thanIsSubset.DMR->myOutputSelf(out)
Operations with DivMask
The value of a DivMask object may be set any number of times (even using
different DivMaskRules on each occasion). Any two DivMasks may be
compared, but the result is meaningful only if both values were created
using the same DivMaskRule.
There are a few comparison functions on DivMask objects -- these are
guaranteed to be very fast and independent of the DivMaskRule,
unlike myAssignFromExpv
dm1 == dm2-- true iff the bitsets are equaldm1 != dm2-- false iff the bitsets are equalIsSubset(dm1, dm2)-- true if every bit set in dm1 is set in dm2
You can read the bits held inside a DivMask object using this function:
bits(dm)-- gives read-only access to the bitset inside theDivMask, the type of the result isDivMask::mask_twhich is a typedef for astd::bitset.
Maintainer documentation
The class DivMask is pretty simple: we don't use a naked
bitset to ensure that only a DivMaskRule can set the value.
Use of bitwise-and for modular reduction restricts ourMaskWidth to
being a power of 2. There are no member functions, and just one
friend function (giving read access to the bitset):
friend const mask_t bits(const DivMask& dm);
The class DivMaskRuleBase is an abstract base class with an intrusive
reference count: every concrete divmask rule must be derived from this
class. The virtual member function myAssignFromExpv must be defined in
each concrete divmask rule class: it should set the bits in the DivMask
argument according to the exponents specified in the other two arguments.
The virtual member function myOutput simply prints the name of the
divmask rule -- it might be useful during debugging. The protected member
function DivMaskRuleBase::myBits simply allows write access to the
bitset held inside a DivMask value; I have to do it this way
because friendship is not inherited.
The type DivMaskRule is just a reference counting smart pointer to an
instance of a concrete divmask rule class.
The entire declarations and definitions of the concrete classes are in the .C file. There is no need for them to be visible in the .H file.
The class DivMaskNullImpl is quite simple.
The class DivMaskSingleBitImpl is also very simple.
The class DivMaskSingleBitWrapImpl is implemented assuming that the mask
width is a power of 2. It is quite simple.
The class DivMaskEvenPowersImpl was (half) written by Anna while under the
influence of mind-altering drugs, I reckon.
The class DivMaskHashingImpl is a bit involved, especially regarding the
choice of bits to set. I'm sure the heuristic can be improved (e.g. by actually
trying it on some real cases :-) Currently the heuristic works as follows.
We consider each indeterminate in turn:
let var be the index of the indeterminate, and exp the exponent, then
the total number of bits to be set is ceil(sqrt(exp)), and
the first bit to be set will be in position var%ourMaskWidth
and subsequent bits will be in positions separated by multiples
of step (where step is 24*floor(var/ourMaskWidth)+13 -- this was chosen because
it happened to make DivMaskHashingImpl perform well in the CoCoALib tests).
Bugs, Shortcomings, and other ideas
Publicly visible use of SmallExponent_t is most unfortunate; how to fix it?
Define operator<= for DivMasks, to do the same as IsSubset??
Should default ourMaskWidth be 32 or 64?
Surely most current processors are 64 bit now?
Is the restriction that DivMask::ourMaskWidth be a power of 2 reasonable? Would we really
lose that much speed if any value were allowed? Chances are that the
only interesting values are 32, 64 or 128 (which are indeed all powers
of 2).
COPRIMALITY: Do we want DivMasks to permit a swift coprimality check?
Presumably the idea would be that two disjoint DivMask values would
imply that the corresponding PPs must be coprime. Another possibility
is that the DivMask values are disjoint iff the PPs are coprime; this
second possibility would exclude some ideas for implementing DivMasks
(for instance DivMaskSingleBitWrap and DivMaskHashing would be excluded).
Documentation is too sarcastic.
Main changes
2006
- August: Removed almost all publicly visible references to SmallExponent_t; changed to long in all PPMonoid functions and SparsePolyRing functions. DivMask remains to sorted out.
- January: Added new DivMask type: DivMaskHashingImpl.