/**************************************************************************** ** ** 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 partial perm is of the form: * * [image set, domain, codegree, entries of image list] * * An element of the internal rep of a partial perm in T_PPERM2 must be * at most 65535 and be of UInt2. The <codegree> is just the degree of * the inverse or equivalently the maximum element of the image. *
*****************************************************************************/
#define RequirePartialPerm(funcname, op) \
RequireArgumentCondition(funcname, op, IS_PPERM(op), \ "must be a partial permutation")
static ModuleStateOffset PPermStateOffset = -1;
typedefstruct {
/************************************************************************** * *V TmpPPerm . . . . . . . handle of the buffer bag of the pperm package * * 'TmpPPerm' is the handle of a bag of type 'T_PPERM4', which is * created at initialization time of this package. Functions in this * package can use this bag for whatever purpose they want. They have * to make sure of course that it is large enough. * * The buffer is *not* guaranteed to have any particular value, routines * that require a zero-initialization need to do this at the start.
*/
Obj TmpPPerm;
Obj NEW_PPERM2(UInt deg)
{ // No assert since the values stored in this pperm must be UInt2s but the // degree might be a UInt4. return NEW_PPERM<UInt2>(deg);
}
cpt = INT_INTOBJ(pt); if (cpt > CODEG_PPERM<T>(f)) return Fail;
i = 0;
ptf = CONST_ADDR_PPERM<T>(f);
deg = DEG_PPERM<T>(f); while (i < deg && ptf[i] != cpt)
i++; if (i == deg || ptf[i] != cpt) return Fail; return INTOBJ_INT(i + 1);
}
/***************************************************************************** * GAP functions for partial perms
*****************************************************************************/
// find if we are PPERM2 or PPERM4
codeg = 0;
i = deg; while (codeg < 65536 && i > 0) {
j = INT_INTOBJ(ELM_LIST(img, i--)); if (j > codeg)
codeg = j;
} if (codeg < 65536) {
f = NEW_PPERM2(deg);
ptf2 = ADDR_PPERM2(f); for (i = 0; i < deg; i++) {
j = INT_INTOBJ(ELM_LIST(img, i + 1));
*ptf2++ = (UInt2)j;
}
SET_CODEG_PPERM2(f, codeg); // codeg is already known
} else {
f = NEW_PPERM4(deg);
ptf4 = ADDR_PPERM4(f); for (i = 0; i < deg; i++) {
j = INT_INTOBJ(ELM_LIST(img, i + 1)); if (j > codeg)
codeg = j;
*ptf4++ = (UInt4)j;
}
SET_CODEG_PPERM4(f, codeg);
} return f;
}
// assumes that dom is a set and that img is duplicatefree static Obj FuncSparsePartialPermNC(Obj self, Obj dom, Obj img)
{
RequireSmallList(SELF_NAME, dom);
RequireSmallList(SELF_NAME, img);
RequireSameLength(SELF_NAME, dom, img);
// find if we are PPERM2 or PPERM4
codeg = 0;
i = rank; while (codeg < 65536 && i > 0) {
j = INT_INTOBJ(ELM_PLIST(img, i--)); if (j > codeg)
codeg = j;
}
// create the pperm if (codeg < 65536) {
f = NEW_PPERM2(deg);
ptf2 = ADDR_PPERM2(f); for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(img, i));
ptf2[INT_INTOBJ(ELM_PLIST(dom, i)) - 1] = j;
}
SET_CODEG_PPERM2(f, codeg);
} else {
f = NEW_PPERM4(deg);
ptf4 = ADDR_PPERM4(f); for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(img, i)); if (j > codeg)
codeg = j;
ptf4[INT_INTOBJ(ELM_PLIST(dom, i)) - 1] = j;
}
SET_CODEG_PPERM4(f, codeg);
}
SET_DOM_PPERM(f, dom);
SET_IMG_PPERM(f, img);
CHANGED_BAG(f); return f;
}
// the degree of pperm is the maximum point where it is defined static Obj FuncDegreeOfPartialPerm(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f); return INTOBJ_INT(DEG_PPERM(f));
}
// the codegree of pperm is the maximum point in its image
// the rank is the number of points where it is defined static Obj FuncRankOfPartialPerm(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f); return INTOBJ_INT(RANK_PPERM(f));
}
// domain of a partial perm static Obj FuncDOMAIN_PPERM(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f);
if (DOM_PPERM(f) == NULL) {
INIT_PPERM(f);
} return DOM_PPERM(f);
}
// image list of pperm static Obj FuncIMAGE_PPERM(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f);
if (TNUM_OBJ(f) == T_PPERM2) {
deg = DEG_PPERM2(f);
ptf2 = ADDR_PPERM2(f);
dom = DOM_PPERM(f);
// find chains for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(dom, i)) - 1; if (ptseen[j] == 0) {
ptseen[j] = 2;
len = 1; for (k = ptf2[j]; (k <= deg && ptf2[k - 1] != 0);
k = ptf2[k - 1]) {
len++;
ptseen[k - 1] = 2;
}
ptseen[k - 1] = 2; if (len > pow)
pow = len;
}
}
// find cycles for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(dom, i)) - 1; if (ptseen[j] == 1) {
len = 1; for (k = ptf2[j]; k != j + 1; k = ptf2[k - 1]) {
len++;
ptseen[k - 1] = 0;
}
ord = LcmInt(ord, INTOBJ_INT(len)); // update ptseen, in case a garbage collection happened
ptseen = ADDR_PPERM4(TmpPPerm);
}
}
} else {
deg = DEG_PPERM4(f);
ptf4 = ADDR_PPERM4(f);
dom = DOM_PPERM(f);
// find chains for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(dom, i)) - 1; if (ptseen[j] == 0) {
ptseen[j] = 2;
len = 1; for (k = ptf4[j]; (k <= deg && ptf4[k - 1] != 0);
k = ptf4[k - 1]) {
len++;
ptseen[k - 1] = 2;
}
ptseen[k - 1] = 2; if (len > pow)
pow = len;
}
}
// find cycles for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(dom, i)) - 1; if (ptseen[j] == 1) {
len = 1; for (k = ptf4[j]; k != j + 1; k = ptf4[k - 1]) {
len++;
ptseen[k - 1] = 0;
}
ord = LcmInt(ord, INTOBJ_INT(len)); // update ptseen, in case a garbage collection happened
ptseen = ADDR_PPERM4(TmpPPerm);
}
}
} return NewPlistFromArgs(INTOBJ_INT(pow + 1), ord);
}
// the least power of <f> which is an idempotent static Obj FuncSMALLEST_IDEM_POW_PPERM(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f);
Obj x, ind, per, pow;
x = FuncINDEX_PERIOD_PPERM(self, f);
ind = ELM_PLIST(x, 1);
per = ELM_PLIST(x, 2);
pow = per; while (LtInt(pow, ind))
pow = SumInt(pow, per); return pow;
}
// returns the least list <out> such that for all <i> in [1..degree(f)] // there exists <j> in <out> and a pos int <k> such that <j^(f^k)=i>. static Obj FuncCOMPONENT_REPS_PPERM(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f);
// the number of components of a partial perm (as a functional digraph) static Obj FuncNR_COMPONENTS_PPERM(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f);
UInt i, j, n, rank, k, deg, nr;
UInt2 * ptf2;
UInt4 * ptseen, *ptf4;
Obj dom, img;
// the points that can be obtained from <pt> by successively applying <f>. static Obj FuncCOMPONENT_PPERM_INT(Obj self, Obj f, Obj pt)
{
RequirePartialPerm(SELF_NAME, f);
RequireSmallInt(SELF_NAME, pt);
UInt i, j, deg, len;
Obj out;
i = INT_INTOBJ(pt);
if (TNUM_OBJ(f) == T_PPERM2) {
deg = DEG_PPERM2(f);
if (i > deg || (ADDR_PPERM2(f))[i - 1] == 0) {
out = NewEmptyPlist(); return out;
}
if (codeg < 65536) {
g = NEW_PPERM2(codeg);
ptg2 = ADDR_PPERM2(g); for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(img, i)) - 1;
ptg2[j] = j + 1;
} if (IS_SSORT_LIST(img)) {
SET_DOM_PPERM(g, img);
SET_IMG_PPERM(g, img);
}
SET_CODEG_PPERM2(g, codeg);
} else {
g = NEW_PPERM4(codeg);
ptg4 = ADDR_PPERM4(g); for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(img, i)) - 1;
ptg4[j] = j + 1;
} if (IS_SSORT_LIST(img)) {
SET_DOM_PPERM(g, img);
SET_IMG_PPERM(g, img);
}
SET_CODEG_PPERM4(g, codeg);
}
CHANGED_BAG(g); return g;
}
// f<=g if and only if f is a restriction of g template <typename TF, typename TG> static Obj NaturalLeqPartialPerm(Obj f, Obj g)
{
UInt def, deg, i, j, rank; const TF * ptf; const TG * ptg;
Obj dom;
// the union of f and g where this defines an injective function template <typename TF, typename TG> static Obj JOIN_PPERMS(Obj f, Obj g)
{ typedeftypename ResultType<TF, TG>::type Res;
for (i = 0; i < deg; i++) {
j = IMAGEPP(i + 1, ptf4, degf); if (IMAGEPP(i + 1, ptg4, degg) == j) {
ptmeet4[i] = j; if (j > codeg)
codeg = j;
}
}
SET_CODEG_PPERM4(meet, codeg);
} return meet;
}
// restricted partial perm where set is assumed to be a set of positive ints static Obj FuncRESTRICTED_PPERM(Obj self, Obj f, Obj set)
{
GAP_ASSERT(IS_LIST(set));
UInt i, j, n, codeg, deg;
UInt2 *ptf2, *ptg2;
UInt4 *ptf4, *ptg4;
Obj g;
// find pos in list corresponding to degree of new pperm while (n > 0 && (UInt)INT_INTOBJ(ELM_LIST(set, n)) > deg)
n--; while (n > 0 && ptf2[INT_INTOBJ(ELM_LIST(set, n)) - 1] == 0)
n--; if (n == 0) return EmptyPartialPerm;
g = NEW_PPERM2(INT_INTOBJ(ELM_LIST(set, n)));
ptf2 = ADDR_PPERM2(f);
ptg2 = ADDR_PPERM2(g);
for (i = 0; i < n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i + 1)) - 1;
ptg2[j] = ptf2[j]; if (ptg2[j] > codeg)
codeg = ptg2[j];
}
SET_CODEG_PPERM2(g, codeg); return g;
} elseif (TNUM_OBJ(f) == T_PPERM4) {
deg = DEG_PPERM4(f);
ptf4 = ADDR_PPERM4(f);
while (n > 0 && (UInt)INT_INTOBJ(ELM_LIST(set, n)) > deg)
n--; while (n > 0 && ptf4[INT_INTOBJ(ELM_LIST(set, n)) - 1] == 0)
n--; if (n == 0) return EmptyPartialPerm;
g = NEW_PPERM4(INT_INTOBJ(ELM_LIST(set, n)));
ptf4 = ADDR_PPERM4(f);
ptg4 = ADDR_PPERM4(g);
for (i = 0; i < n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i + 1)) - 1;
ptg4[j] = ptf4[j]; if (ptg4[j] > codeg)
codeg = ptg4[j];
}
SET_CODEG_PPERM4(g, codeg); return g;
} return Fail;
}
// convert a permutation <p> to a partial perm on <set>, which is assumed to // be a set of positive integers static Obj FuncAS_PPERM_PERM(Obj self, Obj p, Obj set)
{
GAP_ASSERT(IS_PERM(p));
GAP_ASSERT(IS_LIST(set));
UInt i, j, n, deg, codeg, dep;
UInt2 *ptf2, *ptp2;
UInt4 *ptf4, *ptp4;
Obj f;
n = LEN_LIST(set); if (n == 0) return EmptyPartialPerm;
deg = INT_INTOBJ(ELM_LIST(set, n));
codeg = 0;
if (TNUM_OBJ(p) == T_PERM2) {
dep = DEG_PERM2(p); if (deg < 65536) { if (dep < deg) {
f = NEW_PPERM2(deg);
ptf2 = ADDR_PPERM2(f);
ptp2 = ADDR_PERM2(p); for (i = 1; i <= n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i)) - 1;
ptf2[j] = IMAGE(j, ptp2, dep) + 1;
}
SET_CODEG_PPERM2(f, deg);
} else { // deg(f)<=deg(p)<=65536
f = NEW_PPERM2(deg);
ptf2 = ADDR_PPERM2(f);
ptp2 = ADDR_PERM2(p); for (i = 1; i <= n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i)) - 1;
ptf2[j] = ptp2[j] + 1; if (ptf2[j] > codeg)
codeg = ptf2[j];
}
SET_CODEG_PPERM2(f, codeg);
}
} else { // deg(p)<=65536<=deg(f)
f = NEW_PPERM4(deg);
ptf4 = ADDR_PPERM4(f);
ptp2 = ADDR_PERM2(p); for (i = 1; i <= n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i)) - 1;
ptf4[j] = IMAGE(j, ptp2, dep) + 1;
}
SET_CODEG_PPERM4(f, deg);
}
} else { // p is PERM4
dep = DEG_PERM4(p); if (dep < deg) {
f = NEW_PPERM4(deg);
ptf4 = ADDR_PPERM4(f);
ptp4 = ADDR_PERM4(p); for (i = 1; i <= n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i)) - 1;
ptf4[j] = IMAGE(j, ptp4, dep) + 1;
}
SET_CODEG_PPERM4(f, deg);
} else { // deg<=dep // find the codeg
i = deg;
ptp4 = ADDR_PERM4(p); while (codeg < 65536 && i > 0) {
j = ptp4[INT_INTOBJ(ELM_LIST(set, i--)) - 1] + 1; if (j > codeg)
codeg = j;
} if (codeg < 65536) {
f = NEW_PPERM2(deg);
ptf2 = ADDR_PPERM2(f);
ptp4 = ADDR_PERM4(p); for (i = 1; i <= n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i)) - 1;
ptf2[j] = ptp4[j] + 1;
}
SET_CODEG_PPERM2(f, codeg);
} else {
f = NEW_PPERM4(deg);
ptf4 = ADDR_PPERM4(f);
ptp4 = ADDR_PERM4(p); for (i = 1; i <= n; i++) {
j = INT_INTOBJ(ELM_LIST(set, i)) - 1;
ptf4[j] = ptp4[j] + 1; if (ptf4[j] > codeg)
codeg = ptf4[j];
}
SET_CODEG_PPERM4(f, deg);
}
}
} return f;
}
// for a partial perm with equal dom and img static Obj FuncAS_PERM_PPERM(Obj self, Obj f)
{
RequirePartialPerm(SELF_NAME, f);
img = FuncIMAGE_SET_PPERM(self, f);
dom = DOM_PPERM(f); if (!EQ(img, dom)) { return Fail;
} if (TNUM_OBJ(f) == T_PPERM2) {
deg = DEG_PPERM2(f);
p = NEW_PERM2(deg);
ptp2 = ADDR_PERM2(p);
ptf2 = ADDR_PPERM2(f); for (i = 0; i < deg; i++)
ptp2[i] = i;
rank = RANK_PPERM2(f); for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(dom, i)) - 1;
ptp2[j] = ptf2[j] - 1;
}
} else {
deg = DEG_PPERM4(f);
p = NEW_PERM4(deg);
ptp4 = ADDR_PERM4(p);
ptf4 = ADDR_PPERM4(f); for (i = 0; i < deg; i++)
ptp4[i] = i;
rank = RANK_PPERM4(f); for (i = 1; i <= rank; i++) {
j = INT_INTOBJ(ELM_PLIST(dom, i)) - 1;
ptp4[j] = ptf4[j] - 1;
}
} return p;
}
// the permutation induced on im(f) by f^-1*g when im(g)=im(f) // and dom(f)=dom(g), no checking static Obj FuncPERM_LEFT_QUO_PPERM_NC(Obj self, Obj f, Obj g)
{
RequirePartialPerm(SELF_NAME, f);
RequirePartialPerm(SELF_NAME, g);
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.