/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later
*/
/***************************************************************************** * * A transformation <f> has internal representation as follows: * * [Obj* image set, Obj* flat kernel, Obj* external degree, * entries image list] * * The <internal degree> of <f> is just the length of <entries image * list>, this is accessed here using <DEG_TRANS2> and <DEG_TRANS4>. * * Transformations must always have internal degree greater than or equal * to the largest point in <entries image list>. * * An element of <entries image list> of a transformation in T_TRANS2 * must be at most 65535 and be UInt2. Hence the internal and external * degrees of a T_TRANS2 are at most 65536. If <f> is T_TRANS4, then the * elements of <entries image list> must be UInt4. * * The <image set> and <flat kernel> are found relative to the internal * degree of the transformation, and must not be changed after they are * first found. * * The <external degree> is the largest non-negative integer <n> such * that n ^ f != n or i ^ f = n for some i != n, or equivalently the * degree of a transformation is the least non-negative <n> such that [n * + 1, n + 2, .. ] is fixed pointwise by <f>. This value is an invariant * of <f>, in the sense that it does not depend on the internal * representation. In GAP, DegreeOfTransformation(f) returns the external * degree, so that if f = g, then DegreeOfTransformation(f) = * DegreeOfTransformation(g). * * In this file, the external degree of a transformation is accessed * using FuncDegreeOfTransformation(self, f), and the internal degree is * accessed using DEG_TRANS2/4(f). *
*****************************************************************************/
#define MIN(a, b) (a < b ? a : b) #define MAX(a, b) (a < b ? b : a)
#define RequireTransformation(funcname, op) \
RequireArgumentCondition(funcname, op, IS_TRANS(op), \ "must be a transformation")
/**************************************************************************** ** *F GetPositiveListEntryEx, GetPositiveListEntry ** ** Extract list[idx] and check that it is a positive small integer; if so, ** return that integer; otherwise raise an error.
*/ staticInt GetPositiveListEntryEx(constchar * funcname,
Obj list, Int idx, constchar * argname)
{
Obj value = ELM_LIST(list, idx); if (!IS_POS_INTOBJ(value)) { char buf[1024];
snprintf(buf, sizeof(buf), "%s[%d]", argname, (int)idx);
buf[sizeof(buf) - 1] = '\0';
RequireArgumentEx(funcname, value, buf, "must be a positive small integer");
} return INT_INTOBJ(value);
}
// The only transformation created within this file that is of type // T_TRANS4 and that does not have (internal) degree 65537 or greater // is ID_TRANS4.
if (0 < len) {
data = ADDR_OBJ(res);
tmp = data[1];
k = 1; for (i = 2; i <= len; i++) { if (tmp != data[i]) {
k++;
tmp = data[i];
data[k] = tmp;
}
} if (k < len) {
ResizeBag(res, (k + 1) * sizeof(Obj));
SET_LEN_PLIST(res, k);
}
}
}
/******************************************************************************* ** GAP level functions for creating transformations
*******************************************************************************/
// Returns a transformation with list of images <list>, this does not check // that <list> is really a list or that its entries define a transformation.
deg = 0; for (i = LEN_LIST(src); 1 <= i; i--) {
s = GetPositiveListEntry("TransformationListListNC", src, i);
r = GetPositiveListEntry("TransformationListListNC", ran, i);
if (s != r) { if (s > deg) {
deg = s;
} if (r > deg) {
deg = r;
}
}
}
if (deg <= 65536) {
f = NEW_TRANS2(deg);
ptf2 = ADDR_TRANS2(f); for (i = 0; i < deg; i++) {
ptf2[i] = i;
} for (i = LEN_LIST(src); 1 <= i; i--) {
s = INT_INTOBJ(ELM_LIST(src, i));
r = INT_INTOBJ(ELM_LIST(ran, i)); // deg may be smaller than s if s = r if (s != r) {
ptf2[s - 1] = r - 1;
}
}
} else {
f = NEW_TRANS4(deg);
ptf4 = ADDR_TRANS4(f); for (i = 0; i < deg; i++) {
ptf4[i] = i;
} for (i = LEN_LIST(src); 1 <= i; i--) {
s = INT_INTOBJ(ELM_LIST(src, i));
r = INT_INTOBJ(ELM_LIST(ran, i)); if (s != r) {
ptf4[s - 1] = r - 1;
}
}
} return f;
}
// Returns a transformation with image <img> and flat kernel <ker> under the // (unchecked) assumption that the arguments are valid and that there is such // a transformation, i.e. that the maximum value in <ker> equals the length // of <img>.
// Returns an idempotent transformation with image <img> and flat kernel <ker> // under the (unchecked) assumption that the arguments are valid and that // there // is such a transformation, i.e. that the maximum value in <ker> equals the // length of <img>. // // Note that this does not return the same transformation as TRANS_IMG_KER_NC // with the same arguments.
deg = DEG_TRANS(f);
img = FuncIMAGE_SET_TRANS(self, f);
ker = NEW_PLIST(T_PLIST_CYC, deg);
SET_LEN_PLIST(ker, deg);
len = LEN_PLIST(img);
j = 1;
n = 0;
for (i = 0; i < deg; i++) { if (j < len && i + 1 == (UInt)INT_INTOBJ(ELM_PLIST(img, j + 1))) {
j++;
}
SET_ELM_PLIST(ker, ++n, INTOBJ_INT(j));
} return FuncIDEM_IMG_KER_NC(self, img, ker);
}
/******************************************************************************* ** GAP level functions for degree and rank of transformations
*******************************************************************************/
// Returns the degree of the transformation <f>, i.e. the least value <n> such // that <f> fixes [n + 1, n + 2, .. ].
static Obj FuncDegreeOfTransformation(Obj self, Obj f)
{
UInt n, i, deg; const UInt2 * ptf2; const UInt4 * ptf4;
RequireTransformation(SELF_NAME, f);
if (EXT_TRANS(f) == NULL) {
n = DEG_TRANS(f); if (TNUM_OBJ(f) == T_TRANS2) {
ptf2 = CONST_ADDR_TRANS2(f); if (ptf2[n - 1] != n - 1) {
SET_EXT_TRANS(f, INTOBJ_INT(n));
} else {
deg = 0; for (i = 0; i < n; i++) { if (ptf2[i] > i && ptf2[i] + 1 > deg) {
deg = ptf2[i] + 1;
} elseif (ptf2[i] < i && i + 1 > deg) {
deg = i + 1;
}
}
SET_EXT_TRANS(f, INTOBJ_INT(deg));
}
} else {
ptf4 = CONST_ADDR_TRANS4(f); if (ptf4[n - 1] != n - 1) {
SET_EXT_TRANS(f, INTOBJ_INT(n));
} else {
deg = 0; for (i = 0; i < n; i++) { if (ptf4[i] > i && ptf4[i] + 1 > deg) {
deg = ptf4[i] + 1;
} elseif (ptf4[i] < i && i + 1 > deg) {
deg = i + 1;
}
}
SET_EXT_TRANS(f, INTOBJ_INT(deg));
}
}
} return EXT_TRANS(f);
}
// Returns the rank of transformation, i.e. number of distinct values in // [(1)f .. (n)f] where n = DegreeOfTransformation(f).
m = INT_INTOBJ(n);
deg = DEG_TRANS(f); if (m >= deg) {
rank = RANK_TRANS(f) - deg + m;
} elseif (TNUM_OBJ(f) == T_TRANS2) {
pttmp = ResizeInitTmpTrans(deg);
ptf2 = CONST_ADDR_TRANS2(f);
rank = 0; for (i = 0; i < m; i++) { if (pttmp[ptf2[i]] == 0) {
rank++;
pttmp[ptf2[i]] = 1;
}
}
} else {
pttmp = ResizeInitTmpTrans(deg);
ptf4 = CONST_ADDR_TRANS4(f);
rank = 0; for (i = 0; i < m; i++) { if (pttmp[ptf4[i]] == 0) {
rank++;
pttmp[ptf4[i]] = 1;
}
}
} return INTOBJ_INT(rank);
}
// Returns the rank of the transformation <f> on the <list>, i.e. the number // of // distinct values in [(list[1])f .. (list[n])f], where <list> consists of // positive ints.
len = LEN_LIST(list);
rank = 0; if (TNUM_OBJ(f) == T_TRANS2) {
def = DEG_TRANS2(f);
pttmp = ResizeInitTmpTrans(def);
ptf2 = CONST_ADDR_TRANS2(f); for (i = 1; i <= len; i++) {
j = GetPositiveListEntry("RANK_TRANS_LIST", list, i) - 1; if (j < def) {
j = ptf2[j]; if (pttmp[j] == 0) {
rank++;
pttmp[j] = 1;
}
} else {
rank++;
}
}
} else {
def = DEG_TRANS4(f);
pttmp = ResizeInitTmpTrans(def);
ptf4 = CONST_ADDR_TRANS4(f); for (i = 1; i <= len; i++) {
j = GetPositiveListEntry("RANK_TRANS_LIST", list, i) - 1; if (j < def) {
j = ptf4[j]; if (pttmp[j] == 0) {
rank++;
pttmp[j] = 1;
}
} else {
rank++;
}
}
}
return INTOBJ_INT(rank);
}
/******************************************************************************* ** GAP level functions for the kernel and preimages of a transformation
*******************************************************************************/
// Returns the flat kernel of transformation on // [1 .. DegreeOfTransformation(f)].
// copy the kernel set up to minimum of m, deg if (m < deg) { for (i = 0; i < m; i++) {
*ptnew++ = *ptker++;
}
} else { // m > deg for (i = 0; i < deg; i++) {
*ptnew++ = *ptker++;
} // we must now add another (m - deg) points, // starting with the class number (rank + 1) for (i = 1; i <= m - deg; i++) {
*ptnew++ = INTOBJ_INT(i + RANK_TRANS(f));
}
} return newObj;
}
// Returns the kernel of a transformation <f> as a partition of [1 .. n].
if (nr == 0) {
RetypeBag(out, T_PLIST_EMPTY);
SET_LEN_PLIST(out, 0);
}
return out;
}
/******************************************************************************* ** GAP level functions for the image sets and lists of a transformation
*******************************************************************************/
// Returns the duplicate free list of images of the transformation f on // [1 .. n] where n = DEG_TRANS(f). Note that this might not be sorted.
// copy the image set for (i = 0; i < len; i++) {
*ptnew++ = *ptim++;
} // add newObj points for (i = deg + 1; i <= m; i++) {
*ptnew++ = INTOBJ_INT(i);
}
} return newObj;
}
// Returns the image list [(1)f .. (n)f] of the transformation f.
if (m == 0) {
out = NewImmutableEmptyPlist(); return out;
}
out = NEW_PLIST_IMM(T_PLIST_CYC, m);
if (TNUM_OBJ(f) == T_TRANS2) {
ptf2 = CONST_ADDR_TRANS2(f);
deg = MIN(DEG_TRANS2(f), m); for (i = 0; i < deg; i++) {
SET_ELM_PLIST(out, i + 1, INTOBJ_INT(ptf2[i] + 1));
}
} else {
ptf4 = CONST_ADDR_TRANS4(f);
deg = MIN(DEG_TRANS4(f), m); for (i = 0; i < deg; i++) {
SET_ELM_PLIST(out, i + 1, INTOBJ_INT(ptf4[i] + 1));
}
} for (; i < m; i++)
SET_ELM_PLIST(out, i + 1, INTOBJ_INT(i + 1));
SET_LEN_PLIST(out, (Int)m); return out;
}
/******************************************************************************* ** GAP level functions for properties of transformations
*******************************************************************************/
if (TNUM_OBJ(f) == T_TRANS2) {
deg = DEG_TRANS2(f);
ptf2 = CONST_ADDR_TRANS2(f); for (i = 0; i < deg; i++) { if (ptf2[ptf2[i]] != ptf2[i]) { returnFalse;
}
}
} else {
deg = DEG_TRANS4(f);
ptf4 = CONST_ADDR_TRANS4(f); for (i = 0; i < deg; i++) { if (ptf4[ptf4[i]] != ptf4[i]) { returnFalse;
}
}
} returnTrue;
}
/******************************************************************************* ** GAP level functions for attributes of transformations
*******************************************************************************/
// Returns the least m and r such that f ^ (m + r) = f ^ m, where f is a // transformation.
if (deg == 0) { return NewPlistFromArgs(INTOBJ_INT(1), INTOBJ_INT(1));
}
// seen[pt] = 0 -> haven't seen pt before // // seen[pt] = d where (1 <= d <= deg) // -> pt belongs to a component we've seen before and (pt)f ^ (d - 1) // belongs to a cycle // // seen[pt] = deg + 1 -> pt belongs to a component not seen before
seen = ResizeInitTmpTrans(deg);
pow = 2;
ord = INTOBJ_INT(1);
if (TNUM_OBJ(f) == T_TRANS2) {
ptf2 = CONST_ADDR_TRANS2(f); for (i = 0; i < deg; i++) { if (seen[i] == 0) {
len = 0; // repeatedly apply f to pt until we see something we've seen // already for (pt = i; seen[pt] == 0; pt = ptf2[pt], len++) {
seen[pt] = deg + 1;
}
last_pt = pt; if (seen[pt] <= deg) { // pt belongs to a component we've seen before
dist = seen[pt] + len; // the distance of i from the cycle in its component + 1
} else { // pt belongs to a component we've not seen before
for (cyc = 0; seen[pt] == deg + 1; pt = ptf2[pt], cyc++) { // go around the cycle again and set the value of // seen, // and get the length of the cycle
seen[pt] = 1;
}
ord = LcmInt(ord, INTOBJ_INT(cyc));
// the distance of i from the cycle in its component + 1
dist = len - cyc + 1;
// update bag pointers, in case a garbage collection happened
ptf2 = CONST_ADDR_TRANS2(f);
seen = AddrTmpTrans();
} if (dist > pow) {
pow = dist;
} // record the distances of the points from the cycle for (pt = i; pt != last_pt; pt = ptf2[pt]) {
seen[pt] = dist--;
}
}
}
} else {
ptf4 = CONST_ADDR_TRANS4(f); for (i = 0; i < deg; i++) { if (seen[i] == 0) {
len = 0; // repeatedly apply f to pt until we see something we've seen // already for (pt = i; seen[pt] == 0; pt = ptf4[pt], len++) {
seen[pt] = deg + 1;
}
last_pt = pt; if (seen[pt] <= deg) { // pt belongs to a component we've seen before
dist = seen[pt] + len; // the distance of i from the cycle in its component + 1
} else { // pt belongs to a component we've not seen before
for (cyc = 0; seen[pt] == deg + 1; pt = ptf4[pt], cyc++) { // go around the cycle again and set the value of // seen, // and get the length of the cycle
seen[pt] = 1;
}
ord = LcmInt(ord, INTOBJ_INT(cyc));
// the distance of i from the cycle in its component + 1
dist = len - cyc + 1;
// update bag pointers, in case a garbage collection happened
ptf4 = CONST_ADDR_TRANS4(f);
seen = AddrTmpTrans();
} if (dist > pow) {
pow = dist;
} // record the distances of the points from the cycle for (pt = i; pt != last_pt; pt = ptf4[pt]) {
seen[pt] = dist--;
}
}
}
}
x = FuncIndexPeriodOfTransformation(self, f);
ind = ELM_PLIST(x, 1);
per = ELM_PLIST(x, 2);
pow = per; while (LtInt(pow, ind)) {
pow = SumInt(pow, per);
} return pow;
}
/******************************************************************************* ** GAP level functions for regularity of transformations
*******************************************************************************/
// Returns True if the transformation or list <obj> is injective on the list // <list>.
RequireSmallList(SELF_NAME, list); if (!IS_TRANS(obj) && !IS_LIST(obj)) {
RequireArgument(SELF_NAME, obj, "must be a transformation or a list");
} // init buffer
n = (IS_TRANS(obj) ? DEG_TRANS(obj) : LEN_LIST(obj));
pttmp = ResizeInitTmpTrans(n);
if (TNUM_OBJ(obj) == T_TRANS2) {
ptt2 = CONST_ADDR_TRANS2(obj); for (i = LEN_LIST(list); i >= 1; i--) {
j = GetPositiveListEntry("IsInjectiveListTrans", list, i); if (j <= n) { if (pttmp[ptt2[j - 1]] != 0) { returnFalse;
}
pttmp[ptt2[j - 1]] = 1;
}
}
} elseif (TNUM_OBJ(obj) == T_TRANS4) {
ptt4 = CONST_ADDR_TRANS4(obj); for (i = LEN_LIST(list); i >= 1; i--) {
j = GetPositiveListEntry("IsInjectiveListTrans", list, i); if (j <= n) { if (pttmp[ptt4[j - 1]] != 0) { returnFalse;
}
pttmp[ptt4[j - 1]] = 1;
}
}
} else { // obj is a list, first we check it describes a transformation for (i = 1; i <= n; i++) {
j = GetPositiveListEntry("IsInjectiveListTrans", obj, i); if (j > n) {
ErrorQuit( " must be a list of positive small integers " "in the range [1 .. %d]",
(Int)n, 0);
}
} for (i = LEN_LIST(list); i >= 1; i--) {
j = GetPositiveListEntry("IsInjectiveListTrans", list, i); if (j <= n) { if (pttmp[INT_INTOBJ(ELM_LIST(obj, j)) - 1] != 0) { returnFalse;
}
pttmp[INT_INTOBJ(ELM_LIST(obj, j)) - 1] = 1;
}
}
} returnTrue;
}
// Returns a transformation g such that transformation f * g * f = f and // g * f * g = g, where f is a transformation.
if (TNUM_OBJ(f) == T_TRANS2) {
deg = DEG_TRANS2(f);
g = NEW_TRANS2(deg);
ptf2 = CONST_ADDR_TRANS2(f);
ptg2 = ADDR_TRANS2(g); for (i = 0; i < deg; i++) {
ptg2[i] = 0;
} for (i = deg - 1; i > 0; i--) {
ptg2[ptf2[i]] = i;
} // to ensure that 1 is in the image and so rank of g equals that of f
ptg2[ptf2[0]] = 0;
} else {
deg = DEG_TRANS4(f);
g = NEW_TRANS4(deg);
ptf4 = CONST_ADDR_TRANS4(f);
ptg4 = ADDR_TRANS4(g); for (i = 0; i < deg; i++) {
ptg4[i] = 0;
} for (i = deg - 1; i > 0; i--) {
ptg4[ptf4[i]] = i;
} // to ensure that 1 is in the image and so rank of g equals that of f
ptg4[ptf4[0]] = 0;
} return g;
}
/******************************************************************************* ** GAP level functions for actions of transformations
*******************************************************************************/
// Returns the flat kernel of a transformation obtained by multiplying <f> by // any transformation with kernel equal to <ker>. If the argument <ker> = // [0], then the flat kernel of <f> on [1 .. <n>] is returned. Otherwise, the // argument <n> is redundant.
// FIXME this should just always return a flat kernel of length <n>, the // special case should be removed, and [0] should be replaced by [1 .. n] in // the Semigroup package.
len = LEN_LIST(ker); if (len == 1 && ELM_LIST(ker, 1) == INTOBJ_INT(0)) { return FuncFLAT_KERNEL_TRANS_INT(self, f, n);
}
rank = 1;
deg = INT_INTOBJ(FuncDegreeOfTransformation(self, f)); if (len < deg) {
ErrorQuit("ON_KERNEL_ANTI_ACTION: the length of " "must be at least %d",
(Int)deg, 0);
}
if (len == 0) {
out = NewImmutableEmptyPlist(); return out;
}
out = NEW_PLIST_IMM(T_PLIST_CYC, len);
SET_LEN_PLIST(out, len);
pttmp = ResizeInitTmpTrans(len);
if (TNUM_OBJ(f) == T_TRANS2) {
ptf2 = CONST_ADDR_TRANS2(f); for (i = 0; i < deg; i++) { // <f> then <g> with ker(<g>) = <ker>
j = INT_INTOBJ(ELM_LIST(ker, ptf2[i] + 1)) - 1; // f first! if (pttmp[j] == 0) {
pttmp[j] = rank++;
}
SET_ELM_PLIST(out, i + 1, INTOBJ_INT(pttmp[j]));
}
} else {
ptf4 = CONST_ADDR_TRANS4(f); for (i = 0; i < deg; i++) { // <f> then <g> with ker(<g>) = <ker>
j = INT_INTOBJ(ELM_LIST(ker, ptf4[i] + 1)) - 1; // f first! if (pttmp[j] == 0) {
pttmp[j] = rank++;
}
SET_ELM_PLIST(out, i + 1, INTOBJ_INT(pttmp[j]));
}
}
i++; for (; i <= len; i++) { // just <ker>
j = INT_INTOBJ(ELM_LIST(ker, i)) - 1; if (pttmp[j] == 0) {
pttmp[j] = rank++;
}
SET_ELM_PLIST(out, i, INTOBJ_INT(pttmp[j]));
} return out;
}
/******************************************************************************* ** GAP level functions for changing representation of a permutation to a ** transformation
*******************************************************************************/
// Returns a transformation <f> such that (i)f = (i)p for all i <= n where <p> // is a permutation <p> and <n> is a positive integer. Note that the returned // transformation is not necessarily a permutation (mathematically), when n is // less than the largest moved point of p.
// find largest moved point if (TNUM_OBJ(p) == T_PERM2) {
ptPerm2 = CONST_ADDR_PERM2(p); for (sup = DEG_PERM2(p); 1 <= sup; sup--) { if (ptPerm2[sup - 1] != sup - 1) { break;
}
} return FuncAS_TRANS_PERM_INT(self, p, INTOBJ_INT(sup));
} else {
ptPerm4 = CONST_ADDR_PERM4(p); for (sup = DEG_PERM4(p); 1 <= sup; sup--) { if (ptPerm4[sup - 1] != sup - 1) { break;
}
} return FuncAS_TRANS_PERM_INT(self, p, INTOBJ_INT(sup));
}
}
/******************************************************************************* ** GAP level functions for changing representation of a transformation to a ** permutation
*******************************************************************************/
// Returns a permutation mathematically equal to the transformation <f> if // possible, and returns Fail if it is not possible
for (i = 0; i < max; i++) {
ptp[i] = i;
} for (i = 0; i < min; i++) {
ptp[ptf2[i]] = ptg2[i];
} for (; i < deg; i++) {
ptp[i] = ptg2[i];
} for (; i < def; i++) {
ptp[ptf2[i]] = i;
}
} elseif (TNUM_OBJ(f) == T_TRANS2 && TNUM_OBJ(g) == T_TRANS4) {
ptf2 = CONST_ADDR_TRANS2(f);
ptg4 = CONST_ADDR_TRANS4(g);
for (i = 0; i < max; i++) {
ptp[i] = i;
} for (i = 0; i < min; i++) {
ptp[ptf2[i]] = ptg4[i];
} for (; i < deg; i++) {
ptp[i] = ptg4[i];
} for (; i < def; i++) { // The only transformation created within this file that is of // type // T_TRANS4 and that does not have (internal) degree 65537 or // greater // is ID_TRANS4.
ptp[ptf2[i]] = i;
}
} elseif (TNUM_OBJ(f) == T_TRANS4 && TNUM_OBJ(g) == T_TRANS2) {
ptf4 = CONST_ADDR_TRANS4(f);
ptg2 = CONST_ADDR_TRANS2(g);
for (i = 0; i < max; i++) {
ptp[i] = i;
} for (i = 0; i < min; i++) {
ptp[ptf4[i]] = ptg2[i];
} for (; i < deg; i++) { // The only transformation created within this file that is of // type // T_TRANS4 and that does not have (internal) degree 65537 or // greater // is ID_TRANS4.
ptp[i] = ptg2[i];
} for (; i < def; i++) {
ptp[ptf4[i]] = i;
}
} elseif (TNUM_OBJ(f) == T_TRANS4 && TNUM_OBJ(g) == T_TRANS4) {
ptf4 = CONST_ADDR_TRANS4(f);
ptg4 = CONST_ADDR_TRANS4(g);
for (i = 0; i < max; i++) {
ptp[i] = i;
} for (i = 0; i < min; i++) {
ptp[ptf4[i]] = ptg4[i];
} for (; i < deg; i++) {
ptp[i] = ptg4[i];
} for (; i < def; i++) {
ptp[ptf4[i]] = i;
}
} return perm;
}
/******************************************************************************* ** GAP level functions for changing representation of a transformation to a ** transformation
*******************************************************************************/
// Returns a transformation g such that (i)g = (i)f for all i in list, and // where (i)g = i for every other value of i.
// g fixes every point for (i = 0; i < deg; i++) {
ptg2[i] = i;
}
// g acts like f on list * / for (i = 0; i < len; i++) {
k = GetPositiveListEntry("RestrictedTransformation", list, i + 1) - 1; if (k < deg) {
ptg2[k] = ptf2[k];
}
}
} else {
deg = DEG_TRANS4(f);
g = NEW_TRANS4(deg);
// g fixes every point for (i = 0; i < deg; i++) {
ptg4[i] = i;
}
// g acts like f on list for (i = 0; i < len; i++) {
k = GetPositiveListEntry("RestrictedTransformation", list, i + 1) - 1; if (k < deg) {
ptg4[k] = ptf4[k];
}
}
} return g;
}
// AsTransformation for a transformation <f> and a pos int <m> either // restricts // <f> to [1 .. m] or returns <f> depending on whether m is less than or equal // DegreeOfTransformation(f) or not.
// In the first form, this is similar to TRIM_TRANS except that a new // transformation is returned.
static Obj FuncAS_TRANS_TRANS(Obj self, Obj f, Obj m)
{ const UInt2 *ptf2; const UInt4 *ptf4;
UInt2 *ptg2;
UInt4 *ptg4;
UInt i, n, def;
Obj g;
if (TNUM_OBJ(f) == T_TRANS2) {
g = NEW_TRANS2(n);
ptf2 = CONST_ADDR_TRANS2(f);
ptg2 = ADDR_TRANS2(g); for (i = 0; i < n; i++) { if (ptf2[i] > n - 1) { return Fail;
}
ptg2[i] = ptf2[i];
}
} else { if (n > 65536) { // g is T_TRANS4
g = NEW_TRANS4(n);
ptf4 = CONST_ADDR_TRANS4(f);
ptg4 = ADDR_TRANS4(g); for (i = 0; i < n; i++) { if (ptf4[i] > n - 1) { return Fail;
}
ptg4[i] = ptf4[i];
}
} else { // f is T_TRANS4 but n <= 65536 < def and so g will be T_TRANS2
g = NEW_TRANS2(n);
ptf4 = CONST_ADDR_TRANS4(f);
ptg2 = ADDR_TRANS2(g); for (i = 0; i < n; i++) { if (ptf4[i] > n - 1) { return Fail;
}
ptg2[i] = (UInt2)ptf4[i];
}
}
} return g;
}
// Changes the transformation <f> in-place to reduce the degree to <m>. It is // assumed that f is actually a transformation of [1 .. m], i.e. that i ^ f <= // m for all i in [1 .. m].
/******************************************************************************* ** GAP level functions for hashing transformations
*******************************************************************************/
/******************************************************************************* ** GAP level functions for moved points (and related) of a transformation
*******************************************************************************/
// Returns the largest value i such that (i)f <> i or 0 if no such i exists.
RequireTransformation(SELF_NAME, f);
max = 0; if (TNUM_OBJ(f) == T_TRANS2) {
def = DEG_TRANS2(f);
ptf2 = CONST_ADDR_TRANS2(f); for (i = DEG_TRANS2(f); 1 <= i; i--) { if (ptf2[i - 1] != i - 1) { break;
}
} for (; 1 <= i; i--) { if (ptf2[i - 1] + 1 > max) {
max = ptf2[i - 1] + 1; if (max == def) { break;
}
}
}
} else {
def = DEG_TRANS4(f);
ptf4 = CONST_ADDR_TRANS4(f); for (i = DEG_TRANS4(f); 1 <= i; i--) { if (ptf4[i - 1] != i - 1) { break;
}
} for (; 1 <= i; i--) { if (ptf4[i - 1] + 1 > max) {
max = ptf4[i - 1] + 1; if (max == def) break;
}
}
} return INTOBJ_INT(max);
}
// Returns the smallest value <i> such that (i)f <> i if it exists, and Fail // if // not. Note that this differs from the GAP level function which returns // infinity if (i)f = i for all i.
if (TNUM_OBJ(f) == T_TRANS2) {
ptf2 = CONST_ADDR_TRANS2(f);
deg = DEG_TRANS2(f); for (i = 1; i <= deg; i++) { if (ptf2[i - 1] != i - 1) { break;
}
}
} else {
ptf4 = CONST_ADDR_TRANS4(f);
deg = DEG_TRANS4(f); for (i = 1; i <= deg; i++) { if (ptf4[i - 1] != i - 1) { break;
}
}
} return INTOBJ_INT(i);
}
// Returns the smallest value in [SmallestMovedPoint(f) .. // LargestMovedPoint(f)] ^ f if it exists and Fail if it does not. Note that // this differs from the GAP level function which returns infinity if (i)f = i // for all i.
len = 0; if (TNUM_OBJ(f) == T_TRANS2) {
deg = DEG_TRANS2(f);
out = NEW_PLIST(T_PLIST_CYC_SSORT, 0);
ptf2 = CONST_ADDR_TRANS2(f); for (i = 0; i < deg; i++) { if (ptf2[i] != i) {
AssPlist(out, ++len, INTOBJ_INT(i + 1));
ptf2 = CONST_ADDR_TRANS2(f);
}
}
} else {
deg = DEG_TRANS4(f);
out = NEW_PLIST(T_PLIST_CYC_SSORT, 0);
ptf4 = CONST_ADDR_TRANS4(f); for (i = 0; i < deg; i++) { if (ptf4[i] != i) {
AssPlist(out, ++len, INTOBJ_INT(i + 1));
ptf4 = CONST_ADDR_TRANS4(f);
}
}
}
if (LEN_PLIST(out) == 0) {
RetypeBag(out, T_PLIST_EMPTY);
}
return out;
}
/******************************************************************************* ** GAP level functions for connected components of a transformation
*******************************************************************************/
// Returns the representatives, in the following sense, of the components of // the transformation <f>. For every i in [1 .. DegreeOfTransformation(<f>)] // there exists a representative j and a positive integer k such that i ^ (<f> // ^ k) = j. The least number of representatives is returned and these // representatives are partitioned according to the component they belong to.
if (deg == 0) {
out = NewEmptyPlist(); return out;
}
img = FuncUNSORTED_IMAGE_SET_TRANS(self, f);
out = NEW_PLIST(T_PLIST, 1);
seen = ResizeInitTmpTrans(deg);
for (i = 1; i <= (UInt)LEN_PLIST(img); i++) {
seen[INT_INTOBJ(ELM_PLIST(img, i)) - 1] = 1;
}
if (TNUM_OBJ(f) == T_TRANS2) {
ptf2 = CONST_ADDR_TRANS2(f);
nr = 1; for (i = 0; i < deg; i++) { if (seen[i] == 0) { // i belongs to dom(f) but not im(f) // repeatedly apply f to pt until we see something we've seen // already
pt = i; do {
seen[pt] = nr + 1;
pt = ptf2[pt];
} while (seen[pt] == 1);
index = seen[pt];
if (index != nr + 1) { // pt belongs to a component we've seen before
ptf2 = CONST_ADDR_TRANS2(f);
pt = i; do {
seen[pt] = index;
pt = ptf2[pt];
} while (seen[pt] == nr + 1);
comp = ELM_PLIST(out, seen[pt] - 1);
AssPlist(comp, LEN_PLIST(comp) + 1, INTOBJ_INT(i + 1));
} else { // pt belongs to a component we've not seen before
comp = NEW_PLIST(T_PLIST_CYC, 1);
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.80 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.