From 60e9354ab4ebafced481d02884fd0a4567ce0a85 Mon Sep 17 00:00:00 2001 From: Steve Linton Date: Tue, 31 Oct 2017 01:41:58 +0100 Subject: [PATCH 1/5] permutat: add SIZEBAG_PERM2/4, turn macros into static inline funcs --- src/exprs.c | 12 +++++------ src/intrprtr.c | 10 ++++----- src/permutat.c | 20 +++++++++--------- src/permutat.h | 55 ++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/exprs.c b/src/exprs.c index 6d3b742802..3bd27f2fd4 100644 --- a/src/exprs.c +++ b/src/exprs.c @@ -868,10 +868,10 @@ Obj EvalPermExpr ( c, MAX_DEG_PERM4); /* if necessary resize the permutation */ - if ( SIZE_OBJ(perm)/sizeof(UInt4) < c ) { - ResizeBag( perm, (c + 1023) / 1024 * 1024 * sizeof(UInt4) ); - ptr4 = ADDR_PERM4( perm ); - for ( k = m+1; k <= SIZE_OBJ(perm)/sizeof(UInt4); k++ ) { + if (DEG_PERM4(perm) < c) { + ResizeBag(perm, SIZEBAG_PERM4((c + 1023) / 1024 * 1024)); + ptr4 = ADDR_PERM4(perm); + for (k = m + 1; k <= DEG_PERM4(perm); k++) { ptr4[k-1] = k-1; } } @@ -911,12 +911,12 @@ Obj EvalPermExpr ( ptr2[k-1] = ptr4[k-1]; }; RetypeBag( perm, T_PERM2 ); - ResizeBag( perm, m * sizeof(UInt2) ); + ResizeBag(perm, SIZEBAG_PERM2(m)); } /* otherwise just shorten the permutation */ else { - ResizeBag( perm, m * sizeof(UInt4) ); + ResizeBag(perm, SIZEBAG_PERM4(m)); } /* return the permutation */ diff --git a/src/intrprtr.c b/src/intrprtr.c index 74f1a8960c..03a88db91d 100644 --- a/src/intrprtr.c +++ b/src/intrprtr.c @@ -1984,10 +1984,10 @@ void IntrPermCycle ( c, MAX_DEG_PERM4); /* if necessary resize the permutation */ - if ( SIZE_OBJ(perm)/sizeof(UInt4) < c ) { - ResizeBag( perm, (c + 1023) / 1024 * 1024 * sizeof(UInt4) ); + if (DEG_PERM4(perm) < c) { + ResizeBag(perm, SIZEBAG_PERM4((c + 1023) / 1024 * 1024)); ptr4 = ADDR_PERM4( perm ); - for ( k = m+1; k <= SIZE_OBJ(perm)/sizeof(UInt4); k++ ) { + for (k = m + 1; k <= DEG_PERM4(perm); k++) { ptr4[k-1] = k-1; } } @@ -2057,12 +2057,12 @@ void IntrPerm ( ptr2[k-1] = ptr4[k-1]; }; RetypeBag( perm, T_PERM2 ); - ResizeBag( perm, m * sizeof(UInt2) ); + ResizeBag(perm, SIZEBAG_PERM2(m)); } /* otherwise just shorten the permutation */ else { - ResizeBag( perm, m * sizeof(UInt4) ); + ResizeBag(perm, SIZEBAG_PERM4(m)); } } diff --git a/src/permutat.c b/src/permutat.c index f3e0330579..1d08fa97df 100644 --- a/src/permutat.c +++ b/src/permutat.c @@ -2281,7 +2281,7 @@ Obj FuncPermList ( degPerm = LEN_LIST( list ); /* make sure that the global buffer bag is large enough for checkin*/ - UseTmpPerm(degPerm*sizeof(UInt2)); + UseTmpPerm(SIZEBAG_PERM2(degPerm)); /* allocate the bag for the permutation and get pointer */ perm = NEW_PERM2( degPerm ); @@ -2350,7 +2350,7 @@ Obj FuncPermList ( degPerm, MAX_DEG_PERM4); /* make sure that the global buffer bag is large enough for checkin*/ - UseTmpPerm(degPerm*sizeof(UInt4)); + UseTmpPerm(SIZEBAG_PERM4(degPerm)); /* allocate the bag for the permutation and get pointer */ perm = NEW_PERM4( degPerm ); @@ -3632,12 +3632,12 @@ Obj FuncTRIM_PERM ( if ( TNUM_OBJ(perm) == T_PERM2 ) { rdeg = deg < DEG_PERM2(perm) ? deg : DEG_PERM2(perm); - ResizeBag( perm, sizeof(UInt2)*rdeg); + ResizeBag(perm, SIZEBAG_PERM2(rdeg)); } else { rdeg = deg < DEG_PERM4(perm) ? deg : DEG_PERM4(perm); if (rdeg > 65536UL ) { - ResizeBag( perm, sizeof(UInt4)*rdeg); + ResizeBag(perm, SIZEBAG_PERM4(rdeg)); } else { /* Convert to 2Byte rep: move the points up */ @@ -3646,7 +3646,7 @@ Obj FuncTRIM_PERM ( ((UInt2*)addr)[i]=(UInt2)addr[i]; } RetypeBag( perm, T_PERM2 ); - ResizeBag( perm, sizeof(UInt2)*rdeg); + ResizeBag(perm, SIZEBAG_PERM2(rdeg)); } } @@ -4262,10 +4262,10 @@ Obj Array2Perm ( c, MAX_DEG_PERM4); /* if necessary resize the permutation */ - if ( SIZE_OBJ(perm)/sizeof(UInt4) < c ) { - ResizeBag( perm, (c + 1023) / 1024 * 1024 * sizeof(UInt4) ); + if (DEG_PERM4(perm) < c) { + ResizeBag(perm, SIZEBAG_PERM4((c + 1023) / 1024 * 1024)); ptr4 = ADDR_PERM4( perm ); - for ( k = m+1; k <= SIZE_OBJ(perm)/sizeof(UInt4); k++ ) { + for (k = m + 1; k <= DEG_PERM4(perm); k++) { ptr4[k-1] = k-1; } } @@ -4305,12 +4305,12 @@ Obj Array2Perm ( ptr2[k-1] = ptr4[k-1]; }; RetypeBag( perm, T_PERM2 ); - ResizeBag( perm, m * sizeof(UInt2) ); + ResizeBag(perm, SIZEBAG_PERM2(m)); } /* otherwise just shorten the permutation */ else { - ResizeBag( perm, m * sizeof(UInt4) ); + ResizeBag(perm, SIZEBAG_PERM4(m)); } /* return the permutation */ diff --git a/src/permutat.h b/src/permutat.h index 74dd480ca2..31b48fa27b 100644 --- a/src/permutat.h +++ b/src/permutat.h @@ -23,12 +23,55 @@ *F DEG_PERM4() . . . . . . . . . . . . . degree of (large) permutation *F ADDR_PERM4() . . . . . . . absolute address of (large) permutation */ -#define NEW_PERM2(deg) NewBag( T_PERM2, (deg) * sizeof(UInt2)) -#define DEG_PERM2(perm) (SIZE_OBJ(perm) / sizeof(UInt2)) -#define ADDR_PERM2(perm) ((UInt2*)ADDR_OBJ(perm)) -#define NEW_PERM4(deg) NewBag( T_PERM4, (deg) * sizeof(UInt4)) -#define DEG_PERM4(perm) (SIZE_OBJ(perm) / sizeof(UInt4)) -#define ADDR_PERM4(perm) ((UInt4*)ADDR_OBJ(perm)) +static inline UInt SIZEBAG_PERM2(UInt deg) +{ + return sizeof(Obj) + deg * sizeof(UInt2); +} + +static inline Obj NEW_PERM2(UInt deg) +{ + return NewBag(T_PERM2, SIZEBAG_PERM2(deg)); +} + +static inline UInt DEG_PERM2(Obj perm) +{ + return (SIZE_OBJ(perm) - sizeof(Obj)) / sizeof(UInt2); +} + +static inline UInt2 * ADDR_PERM2(Obj perm) +{ + return (UInt2 *)(ADDR_OBJ(perm) + 1); +} + +static inline const UInt2 * CONST_ADDR_PERM2(Obj perm) +{ + return (const UInt2 *)(CONST_ADDR_OBJ(perm) + 1); +} + +static inline UInt SIZEBAG_PERM4(UInt deg) +{ + return sizeof(Obj) + deg * sizeof(UInt4); +} + +static inline Obj NEW_PERM4(UInt deg) +{ + return NewBag(T_PERM4, SIZEBAG_PERM4(deg)); +} + +static inline UInt DEG_PERM4(Obj perm) +{ + return (SIZE_OBJ(perm) - sizeof(Obj)) / sizeof(UInt4); +} + +static inline UInt4 * ADDR_PERM4(Obj perm) +{ + return (UInt4 *)(ADDR_OBJ(perm) + 1); +} + +static inline const UInt4 * CONST_ADDR_PERM4(Obj perm) +{ + return (const UInt4 *)(CONST_ADDR_OBJ(perm) + 1); +} #define IMAGE(i,pt,dg) (((i) < (dg)) ? (pt)[(i)] : (i)) From 45b20d01284d052872dce2d720a95439547dcccb Mon Sep 17 00:00:00 2001 From: Steve Linton Date: Tue, 31 Oct 2017 01:48:59 +0100 Subject: [PATCH 2/5] permutat.c: use CONST_ADDR_* and const qualifier in some places --- src/permutat.c | 62 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/permutat.c b/src/permutat.c index 1d08fa97df..c5050f378e 100644 --- a/src/permutat.c +++ b/src/permutat.c @@ -1178,7 +1178,7 @@ Obj PowPerm2Int ( { Obj pow; /* handle of the power (result) */ UInt2 * ptP; /* pointer to the power */ - UInt2 * ptL; /* pointer to the permutation */ + const UInt2 * ptL; /* pointer to the permutation */ UInt2 * ptKnown; /* pointer to temporary bag */ UInt deg; /* degree of the permutation */ Int exp, e; /* exponent (right operand) */ @@ -1202,7 +1202,7 @@ Obj PowPerm2Int ( /* get pointer to the permutation and the power */ exp = INT_INTOBJ(opR); - ptL = ADDR_PERM2(opL); + ptL = CONST_ADDR_PERM2(opL); ptP = ADDR_PERM2(pow); /* loop over the points of the permutation */ @@ -1228,7 +1228,7 @@ Obj PowPerm2Int ( /* get pointer to the permutation and the power */ exp = INT_INTOBJ(opR); - ptL = ADDR_PERM2(opL); + ptL = CONST_ADDR_PERM2(opL); ptP = ADDR_PERM2(pow); /* loop over all cycles */ @@ -1273,7 +1273,7 @@ Obj PowPerm2Int ( ptKnown[p] = 0; /* get pointer to the permutation and the power */ - ptL = ADDR_PERM2(opL); + ptL = CONST_ADDR_PERM2(opL); ptP = ADDR_PERM2(pow); /* loop over all cycles */ @@ -1310,7 +1310,7 @@ Obj PowPerm2Int ( else if ( IS_INTOBJ(opR) && INT_INTOBJ(opR) == -1 ) { /* get pointer to the permutation and the power */ - ptL = ADDR_PERM2(opL); + ptL = CONST_ADDR_PERM2(opL); ptP = ADDR_PERM2(pow); /* invert the permutation */ @@ -1439,7 +1439,7 @@ Obj PowPerm4Int ( { Obj pow; /* handle of the power (result) */ UInt4 * ptP; /* pointer to the power */ - UInt4 * ptL; /* pointer to the permutation */ + const UInt4 * ptL; /* pointer to the permutation */ UInt4 * ptKnown; /* pointer to temporary bag */ UInt deg; /* degree of the permutation */ Int exp, e; /* exponent (right operand) */ @@ -1462,7 +1462,7 @@ Obj PowPerm4Int ( /* get pointer to the permutation and the power */ exp = INT_INTOBJ(opR); - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* loop over the points of the permutation */ @@ -1489,7 +1489,7 @@ Obj PowPerm4Int ( /* get pointer to the permutation and the power */ exp = INT_INTOBJ(opR); - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* loop over all cycles */ @@ -1534,7 +1534,7 @@ Obj PowPerm4Int ( ptKnown[p] = 0; /* get pointer to the permutation and the power */ - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* loop over all cycles */ @@ -1571,7 +1571,7 @@ Obj PowPerm4Int ( else if ( IS_INTOBJ(opR) && INT_INTOBJ(opR) == -1 ) { /* get pointer to the permutation and the power */ - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* invert the permutation */ @@ -1586,7 +1586,7 @@ Obj PowPerm4Int ( /* get pointer to the permutation and the power */ exp = -INT_INTOBJ(opR); - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* loop over the points */ @@ -1612,7 +1612,7 @@ Obj PowPerm4Int ( /* get pointer to the permutation and the power */ exp = -INT_INTOBJ(opR); - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* loop over all cycles */ @@ -1658,7 +1658,7 @@ Obj PowPerm4Int ( /* get pointer to the permutation and the power */ opR = ProdInt( INTOBJ_INT(-1), opR ); - ptL = ADDR_PERM4(opL); + ptL = CONST_ADDR_PERM4(opL); ptP = ADDR_PERM4(pow); /* loop over all cycles */ @@ -1794,7 +1794,7 @@ Obj QuoIntPerm2 ( { Int pre; /* preimage (result) */ Int img; /* image (left operand) */ - UInt2 * ptR; /* pointer to the permutation */ + const UInt2 * ptR; /* pointer to the permutation */ /* large positive integers (> 2^28-1) are fixed by any permutation */ if ( TNUM_OBJ(opL) == T_INTPOS ) @@ -1828,7 +1828,7 @@ Obj QuoIntPerm4 ( { Int pre; /* preimage (result) */ Int img; /* image (left operand) */ - UInt4 * ptR; /* pointer to the permutation */ + const UInt4 * ptR; /* pointer to the permutation */ /* large positive integers (> 2^28-1) are fixed by any permutation */ if ( TNUM_OBJ(opL) == T_INTPOS ) @@ -1873,9 +1873,9 @@ Obj PowPerm22 ( UInt degC; /* degree of the conjugation */ UInt2 * ptC; /* pointer to the conjugation */ UInt degL; /* degree of the left operand */ - UInt2 * ptL; /* pointer to the left operand */ + const UInt2 * ptL; /* pointer to the left operand */ UInt degR; /* degree of the right operand */ - UInt2 * ptR; /* pointer to the right operand */ + const UInt2 * ptR; /* pointer to the right operand */ UInt p; /* loop variable */ /* compute the size of the result and allocate a bag */ @@ -1885,8 +1885,8 @@ Obj PowPerm22 ( cnj = NEW_PERM2( degC ); /* set up the pointers */ - ptL = ADDR_PERM2(opL); - ptR = ADDR_PERM2(opR); + ptL = CONST_ADDR_PERM2(opL); + ptR = CONST_ADDR_PERM2(opR); ptC = ADDR_PERM2(cnj); /* its faster if the both permutations have the same size */ @@ -1913,9 +1913,9 @@ Obj PowPerm24 ( UInt degC; /* degree of the conjugation */ UInt4 * ptC; /* pointer to the conjugation */ UInt degL; /* degree of the left operand */ - UInt2 * ptL; /* pointer to the left operand */ + const UInt2 * ptL; /* pointer to the left operand */ UInt degR; /* degree of the right operand */ - UInt4 * ptR; /* pointer to the right operand */ + const UInt4 * ptR; /* pointer to the right operand */ UInt p; /* loop variable */ /* compute the size of the result and allocate a bag */ @@ -1925,8 +1925,8 @@ Obj PowPerm24 ( cnj = NEW_PERM4( degC ); /* set up the pointers */ - ptL = ADDR_PERM2(opL); - ptR = ADDR_PERM4(opR); + ptL = CONST_ADDR_PERM2(opL); + ptR = CONST_ADDR_PERM4(opR); ptC = ADDR_PERM4(cnj); /* its faster if the both permutations have the same size */ @@ -1953,9 +1953,9 @@ Obj PowPerm42 ( UInt degC; /* degree of the conjugation */ UInt4 * ptC; /* pointer to the conjugation */ UInt degL; /* degree of the left operand */ - UInt4 * ptL; /* pointer to the left operand */ + const UInt4 * ptL; /* pointer to the left operand */ UInt degR; /* degree of the right operand */ - UInt2 * ptR; /* pointer to the right operand */ + const UInt2 * ptR; /* pointer to the right operand */ UInt p; /* loop variable */ /* compute the size of the result and allocate a bag */ @@ -1965,8 +1965,8 @@ Obj PowPerm42 ( cnj = NEW_PERM4( degC ); /* set up the pointers */ - ptL = ADDR_PERM4(opL); - ptR = ADDR_PERM2(opR); + ptL = CONST_ADDR_PERM4(opL); + ptR = CONST_ADDR_PERM2(opR); ptC = ADDR_PERM4(cnj); /* its faster if the both permutations have the same size */ @@ -1993,9 +1993,9 @@ Obj PowPerm44 ( UInt degC; /* degree of the conjugation */ UInt4 * ptC; /* pointer to the conjugation */ UInt degL; /* degree of the left operand */ - UInt4 * ptL; /* pointer to the left operand */ + const UInt4 * ptL; /* pointer to the left operand */ UInt degR; /* degree of the right operand */ - UInt4 * ptR; /* pointer to the right operand */ + const UInt4 * ptR; /* pointer to the right operand */ UInt p; /* loop variable */ /* compute the size of the result and allocate a bag */ @@ -2005,8 +2005,8 @@ Obj PowPerm44 ( cnj = NEW_PERM4( degC ); /* set up the pointers */ - ptL = ADDR_PERM4(opL); - ptR = ADDR_PERM4(opR); + ptL = CONST_ADDR_PERM4(opL); + ptR = CONST_ADDR_PERM4(opR); ptC = ADDR_PERM4(cnj); /* its faster if the both permutations have the same size */ From b44be650feb258c04882c6bd124d7d083da8d24c Mon Sep 17 00:00:00 2001 From: Steve Linton Date: Tue, 31 Oct 2017 01:51:54 +0100 Subject: [PATCH 3/5] Store inverses in permutation --- lib/dicthf.gi | 4 +- src/permutat.c | 77 ++++++++++++++++++--------- src/permutat.h | 25 +++++++++ tst/testinstall/opers/MemoryUsage.tst | 2 +- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/lib/dicthf.gi b/lib/dicthf.gi index 210cb1ded8..0f2dfd692c 100644 --- a/lib/dicthf.gi +++ b/lib/dicthf.gi @@ -208,7 +208,7 @@ function(d,pe) if IsPerm4Rep(p) then # is it a proper 4byte perm? if l>65536 then - return HashKeyBag(p,255,0,4*l); + return HashKeyBag(p,255,GAPInfo.BytesPerVariable,4*l); else # the permutation does not require 4 bytes. Trim in two # byte representation (we need to do this to get consistent @@ -217,7 +217,7 @@ function(d,pe) fi; fi; # now we have a Perm2Rep: - return HashKeyBag(p,255,0,2*l); + return HashKeyBag(p,255,GAPInfo.BytesPerVariable,2*l); end; end); diff --git a/src/permutat.c b/src/permutat.c index c5050f378e..c6df059f48 100644 --- a/src/permutat.c +++ b/src/permutat.c @@ -1185,12 +1185,14 @@ Obj PowPerm2Int ( UInt len; /* length of cycle (result) */ UInt p, q, r; /* loop variables */ - - /* handle zeroth and first powers separately */ + + /* handle zeroth and first powers and stored inverses separately */ if ( opR == INTOBJ_INT(0)) return IdentityPerm; if ( opR == INTOBJ_INT(1)) return opL; + if (opR == INTOBJ_INT(-1) && STOREDINV_PERM(opL) != 0) + return STOREDINV_PERM(opL); /* get the operands and allocate a result bag */ deg = DEG_PERM2(opL); @@ -1446,11 +1448,14 @@ Obj PowPerm4Int ( UInt len; /* length of cycle (result) */ UInt p, q, r; /* loop variables */ - /* handle zeroth and first powers separately */ + /* handle zeroth and first powers separately and stored inverses */ if ( opR == INTOBJ_INT(0)) return IdentityPerm; if ( opR == INTOBJ_INT(1)) return opL; + if (opR == INTOBJ_INT(-1) && STOREDINV_PERM(opL) != 0) + return STOREDINV_PERM(opL); + /* get the operands and allocate a result bag */ deg = DEG_PERM4(opL); @@ -1703,7 +1708,12 @@ Obj PowPerm4Int ( Obj InvPerm ( Obj perm ) { - return POW( perm, INTOBJ_INT(-1) ); + Obj inv = STOREDINV_PERM(perm); + if (inv != 0) + return inv; + inv = POW(perm, INTOBJ_INT(-1)); + SET_STOREDINV_PERM(perm, inv); + return inv; } @@ -1792,7 +1802,7 @@ Obj QuoIntPerm2 ( Obj opL, Obj opR ) { - Int pre; /* preimage (result) */ + UInt2 pre; /* preimage (result) */ Int img; /* image (left operand) */ const UInt2 * ptR; /* pointer to the permutation */ @@ -1810,23 +1820,30 @@ Obj QuoIntPerm2 ( return QUO( opL, opR ); } + Obj inv = STOREDINV_PERM(opR); + + if (inv != 0) + return INTOBJ_INT( + IMAGE(img - 1, CONST_ADDR_PERM2(inv), DEG_PERM2(inv)) + 1); + /* compute the preimage */ - pre = img; - ptR = ADDR_PERM2(opR); if ( img <= DEG_PERM2(opR) ) { - while ( ptR[ pre-1 ] != img-1 ) - pre = ptR[ pre-1 ] + 1; - } - - /* return it */ - return INTOBJ_INT(pre); + pre = (UInt2)(img - 1); + ptR = CONST_ADDR_PERM2(opR); + while (ptR[pre] != (UInt2)(img - 1)) + pre = ptR[pre]; + /* return it */ + return INTOBJ_INT(pre + 1); + } + else + return INTOBJ_INT(img); } Obj QuoIntPerm4 ( Obj opL, Obj opR ) { - Int pre; /* preimage (result) */ + UInt4 pre; /* preimage (result) */ Int img; /* image (left operand) */ const UInt4 * ptR; /* pointer to the permutation */ @@ -1844,16 +1861,23 @@ Obj QuoIntPerm4 ( return QUO( opL, opR ); } + Obj inv = STOREDINV_PERM(opR); + + if (inv != 0) + return INTOBJ_INT( + IMAGE(img - 1, CONST_ADDR_PERM4(inv), DEG_PERM4(inv)) + 1); + /* compute the preimage */ - pre = img; - ptR = ADDR_PERM4(opR); if ( img <= DEG_PERM4(opR) ) { - while ( ptR[ pre-1 ] != img-1 ) - pre = ptR[ pre-1 ] + 1; - } - - /* return it */ - return INTOBJ_INT(pre); + pre = (UInt4)(img - 1); + ptR = CONST_ADDR_PERM4(opR); + while (ptR[pre] != (UInt4)(img - 1)) + pre = ptR[pre]; + /* return it */ + return INTOBJ_INT((Int)(pre + 1)); + } + else + return INTOBJ_INT(img); } @@ -4151,6 +4175,7 @@ void SavePerm2( Obj perm) UInt i; UInt2 *ptr; UInt len; + SaveSubObj(STOREDINV_PERM(perm)); len = DEG_PERM2(perm); ptr = ADDR_PERM2(perm); for (i = 0; i < len; i++) @@ -4168,6 +4193,7 @@ void SavePerm4( Obj perm) UInt i; UInt4 *ptr; UInt len; + SaveSubObj(STOREDINV_PERM(perm)); len = DEG_PERM4(perm); ptr = ADDR_PERM4(perm); for (i = 0; i < len; i++) @@ -4185,6 +4211,7 @@ void LoadPerm2( Obj perm) UInt i; UInt2 *ptr; UInt len; + ADDR_OBJ(perm)[0] = LoadSubObj(); // stored inverse len = DEG_PERM2(perm); ptr = ADDR_PERM2(perm); for (i = 0; i < len; i++) @@ -4202,6 +4229,7 @@ void LoadPerm4( Obj perm) UInt i; UInt4 *ptr; UInt len; + ADDR_OBJ(perm)[0] = LoadSubObj(); // stored inverse len = DEG_PERM4(perm); ptr = ADDR_PERM4(perm); for (i = 0; i < len; i++) @@ -4834,9 +4862,9 @@ static Int InitKernel ( { /* install the marking function */ InfoBags[ T_PERM2 ].name = "permutation (small)"; - InitMarkFuncBags( T_PERM2 , MarkNoSubBags ); + InitMarkFuncBags(T_PERM2, MarkOneSubBags); InfoBags[ T_PERM4 ].name = "permutation (large)"; - InitMarkFuncBags( T_PERM4 , MarkNoSubBags ); + InitMarkFuncBags(T_PERM4, MarkOneSubBags); MakeBagTypePublic( T_PERM2); MakeBagTypePublic( T_PERM4); @@ -4846,6 +4874,7 @@ static Int InitKernel ( ImportGVarFromLibrary( "TYPE_PERM2", &TYPE_PERM2 ); ImportGVarFromLibrary( "TYPE_PERM4", &TYPE_PERM4 ); + TypeObjFuncs[ T_PERM2 ] = TypePerm2; TypeObjFuncs[ T_PERM4 ] = TypePerm4; diff --git a/src/permutat.h b/src/permutat.h index 31b48fa27b..d892f5333d 100644 --- a/src/permutat.h +++ b/src/permutat.h @@ -73,6 +73,31 @@ static inline const UInt4 * CONST_ADDR_PERM4(Obj perm) return (const UInt4 *)(CONST_ADDR_OBJ(perm) + 1); } +static inline Obj STOREDINV_PERM(Obj perm) +{ + return ADDR_OBJ(perm)[0]; +} + +/* SET_STOREDINV_PERM should only be used in neither perm, nor inv has + a stored inverse already. It's OK (although inefficient) if perm and inv + are identical */ +static inline void SET_STOREDINV_PERM(Obj perm, Obj inv) +{ + /* check for the possibility that inv is in a different representation to + perm. It could be that perm actually acts on < 2^16 points but is in + PERM4 representation and some clever code has represented the inverse + as PERM2. It could be that someone introduces a new representation + altogether */ + if (TNUM_OBJ(inv) == TNUM_OBJ(perm)) { + GAP_ASSERT(STOREDINV_PERM(perm) == 0 && STOREDINV_PERM(inv) == 0); + ADDR_OBJ(perm)[0] = inv; + CHANGED_BAG(perm); + ADDR_OBJ(inv)[0] = perm; + CHANGED_BAG(inv); + } +} + + #define IMAGE(i,pt,dg) (((i) < (dg)) ? (pt)[(i)] : (i)) #ifdef SYS_IS_64_BIT diff --git a/tst/testinstall/opers/MemoryUsage.tst b/tst/testinstall/opers/MemoryUsage.tst index 1ffbd1ccc0..01b5164943 100644 --- a/tst/testinstall/opers/MemoryUsage.tst +++ b/tst/testinstall/opers/MemoryUsage.tst @@ -15,7 +15,7 @@ gap> MemoryUsage(Z(2)) / GAPInfo.BytesPerVariable; gap> MemoryUsage(Z(3)) / GAPInfo.BytesPerVariable; 1 gap> g := (1,2,3);; -gap> MemoryUsage(g) - MU_MemBagHeader - MU_MemPointer; +gap> MemoryUsage(g) - MU_MemBagHeader - MU_MemPointer - GAPInfo.BytesPerVariable; 6 # From 31b034cce7d311c302098ac9e8bd84e7ee76df60 Mon Sep 17 00:00:00 2001 From: Steve Linton Date: Tue, 31 Oct 2017 01:53:40 +0100 Subject: [PATCH 4/5] Eagerly compute inverse of "small" perms in QuoIntPerm2/4 For permutations whose degree is less than PERM_INVERSE_THRESHOLD, QuoIntPerm2/4 compute and store the inverse --- doc/ref/permutat.xml | 4 ++-- lib/permutat.g | 23 +++++++++++++++++++++++ src/permutat.c | 13 +++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/doc/ref/permutat.xml b/doc/ref/permutat.xml index 9acc270d71..89cc4c8298 100644 --- a/doc/ref/permutat.xml +++ b/doc/ref/permutat.xml @@ -26,8 +26,7 @@ Permutations in &GAP; are entered and displayed in cycle notation, such as (1,2,3)(4,5).

The preimage of the point i under the permutation p can be -computed as i/p, -without constructing the inverse of p. +computed as i/p, see .

For arithmetic operations for permutations and their precedence, see . @@ -47,6 +46,7 @@ the category test function for permutations is . <#Include Label="IsPerm"> <#Include Label="IsPermCollection"> <#Include Label="PermutationsFamily"> +<#Include Label="PERM_INVERSE_THRESHOLD"> diff --git a/lib/permutat.g b/lib/permutat.g index e7d6708a84..30d7e3b120 100644 --- a/lib/permutat.g +++ b/lib/permutat.g @@ -763,6 +763,29 @@ InstallMethod( DistancePerms, "for general permutations", function(x,y) return NrMovedPoints(x/y); end); +############################################################################# +## +#V PERM_INVERSE_THRESHOLD . . . . cut off for when inverses are computed +## eagerly +## +## <#GAPDoc Label="PERM_INVERSE_THRESHOLD"> +## +## +## +## +## For permutations of degree up to PERM_INVERSE_THRESHOLD whenever +## the inverse image of a point under a permutations is needed, the entire +## inverse is computed and stored. Otherwise, if the inverse is not stored, +## the point is traced around the cycle it is part of to find the inverse +## image. This takes time when it happens, and uses memory, but saves time +## on a variety of subsequent computations. This threshold can be adjusted +## by simply assigning to the variable. The default is 10000. +## +## +## <#/GAPDoc> + +PERM_INVERSE_THRESHOLD := 10000; + ############################################################################# diff --git a/src/permutat.c b/src/permutat.c index c6df059f48..b5ae09276d 100644 --- a/src/permutat.c +++ b/src/permutat.c @@ -1798,6 +1798,8 @@ Obj PowIntPerm4 ( ** point and so on, until we come back to . The last point is the ** preimage of . This is faster because the cycles are usually short. */ +static Obj PERM_INVERSE_THRESHOLD; + Obj QuoIntPerm2 ( Obj opL, Obj opR ) @@ -1822,6 +1824,11 @@ Obj QuoIntPerm2 ( Obj inv = STOREDINV_PERM(opR); + if (inv == 0 && PERM_INVERSE_THRESHOLD != 0 && + IS_INTOBJ(PERM_INVERSE_THRESHOLD) && + DEG_PERM2(opR) <= INT_INTOBJ(PERM_INVERSE_THRESHOLD)) + inv = InvPerm(opR); + if (inv != 0) return INTOBJ_INT( IMAGE(img - 1, CONST_ADDR_PERM2(inv), DEG_PERM2(inv)) + 1); @@ -1863,6 +1870,11 @@ Obj QuoIntPerm4 ( Obj inv = STOREDINV_PERM(opR); + if (inv == 0 && PERM_INVERSE_THRESHOLD != 0 && + IS_INTOBJ(PERM_INVERSE_THRESHOLD) && + DEG_PERM2(opR) <= INT_INTOBJ(PERM_INVERSE_THRESHOLD)) + inv = InvPerm(opR); + if (inv != 0) return INTOBJ_INT( IMAGE(img - 1, CONST_ADDR_PERM4(inv), DEG_PERM4(inv)) + 1); @@ -4869,6 +4881,7 @@ static Int InitKernel ( MakeBagTypePublic( T_PERM2); MakeBagTypePublic( T_PERM4); + ImportGVarFromLibrary("PERM_INVERSE_THRESHOLD", &PERM_INVERSE_THRESHOLD); /* install the type functions */ ImportGVarFromLibrary( "TYPE_PERM2", &TYPE_PERM2 ); From 78a75e0462b51934afd6952144458752322cde5d Mon Sep 17 00:00:00 2001 From: Steve Linton Date: Tue, 31 Oct 2017 01:54:06 +0100 Subject: [PATCH 5/5] Simplify computation of quotients of permutations Taking the quotient of permutations x/y involves computing y^-1, which was previously stored in a temporary buffer and then discarded. Since we now remember inverses, just compute x*y^-1 which does essentially the same thing AND stores the inverse. It's also much shorter code. --- src/permutat.c | 200 ++----------------------------------------------- 1 file changed, 7 insertions(+), 193 deletions(-) diff --git a/src/permutat.c b/src/permutat.c index b5ae09276d..121a170a35 100644 --- a/src/permutat.c +++ b/src/permutat.c @@ -781,197 +781,11 @@ Obj ProdPerm44 ( ** Unfortunatly this can not be done in steps, we need 2 * ** steps. */ -Obj QuoPerm22 ( - Obj opL, - Obj opR ) -{ - Obj quo; /* handle of the quotient (result) */ - UInt degQ; /* degree of the quotient */ - UInt2 * ptQ; /* pointer to the quotient */ - UInt degL; /* degree of the left operand */ - UInt2 * ptL; /* pointer to the left operand */ - UInt degR; /* degree of the right operand */ - UInt2 * ptR; /* pointer to the right operand */ - UInt2 * ptI; /* pointer to the inverse */ - UInt p; /* loop variable */ - - /* compute the size of the result and allocate a bag */ - degL = DEG_PERM2(opL); - degR = DEG_PERM2(opR); - degQ = degL < degR ? degR : degL; - quo = NEW_PERM2( degQ ); - - /* make sure that the buffer bag is large enough to hold the inverse */ - UseTmpPerm(SIZE_OBJ(opR)); - - /* invert the right permutation into the buffer bag */ - ptI = ADDR_PERM2(TmpPerm); - ptR = ADDR_PERM2(opR); - for ( p = 0; p < degR; p++ ) - ptI[ *ptR++ ] = p; - - /* multiply the left permutation with the inverse */ - ptL = ADDR_PERM2(opL); - ptI = ADDR_PERM2(TmpPerm); - ptQ = ADDR_PERM2(quo); - if ( degL <= degR ) { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = ptI[ *(ptL++) ]; - for ( p = degL; p < degR; p++ ) - *(ptQ++) = ptI[ p ]; - } - else { - for ( p = 0; p < degL; p++ ) - - *(ptQ++) = IMAGE( ptL[ p ], ptI, degR ); - } - - /* return the result */ - return quo; -} +Obj InvPerm(Obj); -Obj QuoPerm24 ( - Obj opL, - Obj opR ) +Obj QuoPerm(Obj opL, Obj opR) { - Obj quo; /* handle of the quotient (result) */ - UInt degQ; /* degree of the quotient */ - UInt4 * ptQ; /* pointer to the quotient */ - UInt degL; /* degree of the left operand */ - UInt2 * ptL; /* pointer to the left operand */ - UInt degR; /* degree of the right operand */ - UInt4 * ptR; /* pointer to the right operand */ - UInt4 * ptI; /* pointer to the inverse */ - UInt p; /* loop variable */ - - /* compute the size of the result and allocate a bag */ - degL = DEG_PERM2(opL); - degR = DEG_PERM4(opR); - degQ = degL < degR ? degR : degL; - quo = NEW_PERM4( degQ ); - - /* make sure that the buffer bag is large enough to hold the inverse */ - UseTmpPerm(SIZE_OBJ(opR)); - - /* invert the right permutation into the buffer bag */ - ptI = ADDR_PERM4(TmpPerm); - ptR = ADDR_PERM4(opR); - for ( p = 0; p < degR; p++ ) - ptI[ *ptR++ ] = p; - - /* multiply the left permutation with the inverse */ - ptL = ADDR_PERM2(opL); - ptI = ADDR_PERM4(TmpPerm); - ptQ = ADDR_PERM4(quo); - if ( degL <= degR ) { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = ptI[ *(ptL++) ]; - for ( p = degL; p < degR; p++ ) - *(ptQ++) = ptI[ p ]; - } - else { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = IMAGE( ptL[ p ], ptI, degR ); - } - - /* return the result */ - return quo; -} - -Obj QuoPerm42 ( - Obj opL, - Obj opR ) -{ - Obj quo; /* handle of the quotient (result) */ - UInt degQ; /* degree of the quotient */ - UInt4 * ptQ; /* pointer to the quotient */ - UInt degL; /* degree of the left operand */ - UInt4 * ptL; /* pointer to the left operand */ - UInt degR; /* degree of the right operand */ - UInt2 * ptR; /* pointer to the right operand */ - UInt2 * ptI; /* pointer to the inverse */ - UInt p; /* loop variable */ - - /* compute the size of the result and allocate a bag */ - degL = DEG_PERM4(opL); - degR = DEG_PERM2(opR); - degQ = degL < degR ? degR : degL; - quo = NEW_PERM4( degQ ); - - /* make sure that the buffer bag is large enough to hold the inverse */ - UseTmpPerm(SIZE_OBJ(opR)); - - /* invert the right permutation into the buffer bag */ - ptI = ADDR_PERM2(TmpPerm); - ptR = ADDR_PERM2(opR); - for ( p = 0; p < degR; p++ ) - ptI[ *ptR++ ] = p; - - /* multiply the left permutation with the inverse */ - ptL = ADDR_PERM4(opL); - ptI = ADDR_PERM2(TmpPerm); - ptQ = ADDR_PERM4(quo); - if ( degL <= degR ) { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = ptI[ *(ptL++) ]; - for ( p = degL; p < degR; p++ ) - *(ptQ++) = ptI[ p ]; - } - else { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = IMAGE( ptL[ p ], ptI, degR ); - } - - /* return the result */ - return quo; -} - -Obj QuoPerm44 ( - Obj opL, - Obj opR ) -{ - Obj quo; /* handle of the quotient (result) */ - UInt degQ; /* degree of the quotient */ - UInt4 * ptQ; /* pointer to the quotient */ - UInt degL; /* degree of the left operand */ - UInt4 * ptL; /* pointer to the left operand */ - UInt degR; /* degree of the right operand */ - UInt4 * ptR; /* pointer to the right operand */ - UInt4 * ptI; /* pointer to the inverse */ - UInt p; /* loop variable */ - - /* compute the size of the result and allocate a bag */ - degL = DEG_PERM4(opL); - degR = DEG_PERM4(opR); - degQ = degL < degR ? degR : degL; - quo = NEW_PERM4( degQ ); - - /* make sure that the buffer bag is large enough to hold the inverse */ - UseTmpPerm(SIZE_OBJ(opR)); - - /* invert the right permutation into the buffer bag */ - ptI = ADDR_PERM4(TmpPerm); - ptR = ADDR_PERM4(opR); - for ( p = 0; p < degR; p++ ) - ptI[ *ptR++ ] = p; - - /* multiply the left permutation with the inverse */ - ptL = ADDR_PERM4(opL); - ptI = ADDR_PERM4(TmpPerm); - ptQ = ADDR_PERM4(quo); - if ( degL <= degR ) { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = ptI[ *(ptL++) ]; - for ( p = degL; p < degR; p++ ) - *(ptQ++) = ptI[ p ]; - } - else { - for ( p = 0; p < degL; p++ ) - *(ptQ++) = IMAGE( ptL[ p ], ptI, degR ); - } - - /* return the result */ - return quo; + return PROD(opL, InvPerm(opR)); } @@ -4928,10 +4742,10 @@ static Int InitKernel ( ProdFuncs[ T_PERM2 ][ T_PERM4 ] = ProdPerm24; ProdFuncs[ T_PERM4 ][ T_PERM2 ] = ProdPerm42; ProdFuncs[ T_PERM4 ][ T_PERM4 ] = ProdPerm44; - QuoFuncs [ T_PERM2 ][ T_PERM2 ] = QuoPerm22; - QuoFuncs [ T_PERM2 ][ T_PERM4 ] = QuoPerm24; - QuoFuncs [ T_PERM4 ][ T_PERM2 ] = QuoPerm42; - QuoFuncs [ T_PERM4 ][ T_PERM4 ] = QuoPerm44; + QuoFuncs[T_PERM2][T_PERM2] = QuoPerm; + QuoFuncs[T_PERM2][T_PERM4] = QuoPerm; + QuoFuncs[T_PERM4][T_PERM2] = QuoPerm; + QuoFuncs[T_PERM4][T_PERM4] = QuoPerm; LQuoFuncs[ T_PERM2 ][ T_PERM2 ] = LQuoPerm22; LQuoFuncs[ T_PERM2 ][ T_PERM4 ] = LQuoPerm24; LQuoFuncs[ T_PERM4 ][ T_PERM2 ] = LQuoPerm42;