//
// DeepThought: This package provides functions for multiplication and
// other computations in finitely generated nilpotent groups based on the
// Deep Thought algorithm.
//
#include "gap_all.h" // GAP headers
#define IS_INTPOS(obj) (TNUM_OBJ(obj) == T_INTPOS)
#define IS_INTNEG(obj) (TNUM_OBJ(obj) == T_INTNEG)
#define IS_LARGEINT(obj) (IS_INTPOS(obj) || IS_INTNEG(obj))
#define IS_INT(obj) (IS_INTOBJ(obj) || IS_LARGEINT(obj))
#define IS_NEGATIVE(obj) (IS_INTOBJ(obj) ? ((Int)obj < 0) : IS_INTNEG(obj))
#define IS_POSITIVE(obj) (IS_INTOBJ(obj) ? ((Int)obj > 1) : IS_INTPOS(obj))
#define IS_ODD(obj) (IS_INTOBJ(obj) ? ((Int)obj & 4) : (VAL_LIMB0(obj) & 1))
#define IS_EVEN(obj) (!IS_ODD(obj))
#ifdef IS_PREC_REP
// for compatibility with GAP <= 4.8
#define IS_PREC(x) IS_PREC_REP(x)
#endif
static UInt RNleft, RNright, RNlength, RNnum, RNside;
static Obj FuncDTP_Binomial(Obj self, Obj N, Obj K)
{
// handle some special cases
if (K == INTOBJ_INT(1)) // K=1 is the most frequent case for us, so check it first
return N;
// restrict input
if (!IS_INT(N) || !IS_INT(K))
return Fail;
if (K == INTOBJ_INT(0))
return INTOBJ_INT(1);
if (IS_NEGATIVE(K))
return INTOBJ_INT(0);
// from now on, k >= 2
if (K == N)
return INTOBJ_INT(1);
if (IS_NEGATIVE(N))
return Fail; // TODO: implement this (does it happen?)
if (LtInt(N, K))
return INTOBJ_INT(0);
// We only support immediate integers for k. Anything else at this point
// would lead to output that's far too big for storage anyway.
if (!IS_INTOBJ(K))
return Fail;
Int k = INT_INTOBJ(K);
Int i;
Obj res = N;
Int quot = 1;
// "unroll" the first few operations, to avoid repeated divisions, while
// hopefully keeping res small enough to be represented as an immediate
// (if N wasn't too big)
for (i = 2; i <= k && i <= 6; ++i) {
N = DiffInt(N, INTOBJ_INT(1));
res = ProdInt(res, N);
quot *= i;
}
res = QuoInt(res, INTOBJ_INT(quot));
// now the general case
for (; i <= k; ++i) {
N = DiffInt(N, INTOBJ_INT(1));
res = ProdInt(res, N);
res = QuoInt(res, INTOBJ_INT(i));
}
return res;
}
static Obj FuncDTP_SequenceLetter(Obj self, Obj letter, Obj seq)
{
if (!IS_PREC(letter))
ErrorMayQuit("DTP_SequenceLetter: <letter> must be a plain record (not a %s)",
(Int)TNAM_OBJ(letter), 0L);
if (!IS_PLIST(seq))
ErrorMayQuit("DTP_SequenceLetter: <seq> must be a plain list (not a %s)",
(Int)TNAM_OBJ(seq), 0L);
if (IsbPRec(letter, RNleft))
FuncDTP_SequenceLetter(self, ElmPRec(letter, RNleft), seq);
if (IsbPRec(letter, RNright))
FuncDTP_SequenceLetter(self, ElmPRec(letter, RNright), seq);
UInt len = LEN_PLIST(seq);
AssPlist(seq, len+1, letter);
return 0;
}
static Obj FuncDTP_Seq_i(Obj self, Obj letter, Obj i)
{
if (!IS_PREC(letter))
ErrorMayQuit("DTP_Seq_I: <letter> must be a plain record (not a %s)",
(Int)TNAM_OBJ(letter), 0L);
if (!IS_INT(i))
ErrorMayQuit("DTP_Seq_i: <i> must be an integer (not a %s)",
(Int)TNAM_OBJ(letter), 0L);
// We only support immediate integers for i. Anything else at this point
// would lead to output that's far too big for storage anyway.
if (!IS_INTOBJ(i))
return Fail;
while( ElmPRec(letter, RNlength) > i ){
Obj left = ElmPRec(letter, RNleft);
if( ElmPRec(left, RNlength) >= i )
{
letter = left;
} else {
i = DiffInt( i, ElmPRec(left, RNlength) );
letter = ElmPRec(letter, RNright);
}
}
if(ElmPRec(letter, RNlength) != i){
ErrorMayQuit("DTP_Seq_i: Assertion failure, letter.l <> i", 0, 0);
}
return letter;
}
static Obj FuncDTP_AreAlmostEqual(Obj self, Obj letter1, Obj letter2)
{
if (!IS_PREC(letter1))
ErrorMayQuit("DTP_AreAlmostEqual: <letter1> must be a plain record (not a %s)",
(Int)TNAM_OBJ(letter1), 0L);
if (!IS_PREC(letter2))
ErrorMayQuit("DTP_AreAlmostEqual: <letter2> must be a plain record (not a %s)",
(Int)TNAM_OBJ(letter2), 0L);
// We must have letter1.num = letter2.num
// and both must have the same length
if( !EQ( ElmPRec(letter1, RNnum), ElmPRec(letter2, RNnum) ) ||
!EQ( ElmPRec(letter1, RNlength), ElmPRec(letter2, RNlength) ) )
{
return False;
}
// check whether both are atoms / non-atoms:
UInt is_atom = IsbPRec(letter1, RNside); // 1 <=> letter1 is atom
if( is_atom == IsbPRec(letter2, RNside) ){
if( is_atom == 1) // both are atoms
{
if( EQ( ElmPRec(letter1, RNside), ElmPRec(letter2, RNside) ) ){
return True;
} else {
return False;
}
} else { // both are non-atoms
if( EQ( ElmPRec(letter1, RNleft), ElmPRec(letter2, RNleft) ) &&
EQ( ElmPRec(letter1, RNright), ElmPRec(letter2, RNright) ) ){
return True;
} else {
return False;
}
}
} else { // one is an atom, the other one a non-atom
return False;
}
}
// Table of functions to export
static StructGVarFunc GVarFuncs [] = {
GVAR_FUNC(DTP_Binomial, 2, "n, k"),
GVAR_FUNC(DTP_SequenceLetter, 2, "letter, seq"),
GVAR_FUNC(DTP_Seq_i, 2, "letter, i"),
GVAR_FUNC(DTP_AreAlmostEqual, 2, "letter1, letter2"),
{ 0 } /* Finish with an empty entry */
};
/****************************************************************************
**
*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
*/
static Int InitKernel( StructInitInfo *module )
{
/* init filters and functions */
InitHdlrFuncsFromTable( GVarFuncs );
/* return success */
return 0;
}
static Int PostRestore( StructInitInfo *module )
{
RNleft = RNamName("left");
RNright = RNamName("right");
RNlength = RNamName("l");
RNnum = RNamName("num");
RNside = RNamName("side");
return 0;
}
/****************************************************************************
**
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
*/
static Int InitLibrary( StructInitInfo *module )
{
/* init filters and functions */
InitGVarFuncsFromTable( GVarFuncs );
PostRestore(module);
/* return success */
return 0;
}
/****************************************************************************
**
*F InitInfopl() . . . . . . . . . . . . . . . . . table of init functions
*/
static StructInitInfo module = {
.type = MODULE_DYNAMIC,
.name = "DeepThought",
.initKernel = InitKernel,
.initLibrary = InitLibrary,
.postRestore = PostRestore,
};
StructInitInfo *Init__Dynamic( void )
{
return &module;
}
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland
|
|