staticvoid addStrongGeneratorNR(
PermGroup *G, /* Group to which strong gen is adjoined. */
Permutation *newGen); /* The new strong generator. It must move */
/* Main function for the Schreier-Todd-Coxeter-Sim function for constructing a base, strong generating set, and strong presentation for a permutation group.
Note: If G has relators initially, they will be assumed to be correct, and will be used. However, in this case, it should already
have inverse permutations. */
/* If initialization is requested, perform initializations. */ if ( sOptions.initialize ) {
/* Allocate fields within G. */ if ( G->base || G->basicOrbLen || G->basicOrbit || G->schreierVec )
ERROR( "schreierToddCoxeterSims", "A group field that must be null initially was nonnull.")
G->base = allocIntArrayBaseSize();
G->basicOrbLen = allocIntArrayBaseSize();
G->basicOrbit = (UnsignedS **) allocPtrArrayBaseSize();
G->schreierVec = (Permutation ***) allocPtrArrayBaseSize();
/* Allocate G->order and set G->order to 1. */ if ( !G->order ) {
G->order = allocFactoredInt();
G->order->noOfFactors = 0;
}
/* Delete identity generators from G if present. Return immediately if
G is the identity group. */
removeIdentityGens( G); if ( !G->generator ) { /* Should we allocate G->base, etc??? */
G->baseSize = 0; return;
}
/* Adjoin an inverse image array to each permutation if absent. */
adjoinGenInverses( G);
/* Choose an initial segment of the base so that each generator moves
some base point. */
initializeBase( G);
/* Fill in the level of each generator, and make each generator essential
at its level and above. */ for ( gen = G->generator ; gen ; gen = gen->next ) {
gen->level = levelIn( G, gen);
MAKE_NOT_ESSENTIAL_ALL( gen); for ( level = 1 ; level <= gen->level ; ++level )
MAKE_ESSENTIAL_AT_LEVEL( gen, level);
}
/* Allocate the orbit length, basic orbit, and Schreier vector arrays. Set G->order (previously allocated) to the product of the basic orbit
lengths. */
G->order->noOfFactors = 0; for ( level = 1 ; level <= G->baseSize ; ++level ) {
G->basicOrbLen[level] = 1;
G->basicOrbit[level] = allocIntArrayDegree();
G->schreierVec[level] = allocPtrArrayDegree();
}
}
/* Expand the generator arrays if extra cosets are specified. */ if ( sOptions.maxExtraCosets > 0 )
expandGenerators( G, sOptions.maxExtraCosets);
/* Adjoin inverse permutations, and construct (or reconstruct) the
Schreier vectors, using all generators at each level. */ for ( gen = G->generator ; gen ; gen = gen->next ) if ( !gen->invPermutation )
adjoinInverseGen( G, gen); for ( level = 1 ; level <= G->baseSize ; ++level ) {
constructBasicOrbit( G, level, "AllGensAtLevel" );
svecOK[level] = TRUE;
}
/* Find max size for deduction queue, if not specified. */ if ( sOptions.maxDeducQueueSize == UNKNOWN )
sOptions.maxDeducQueueSize = 2 * degree + options.maxBaseSize +
sOptions.maxExtraCosets;
/* Add generator order and product order relators to relator list. */
tempWord.position = allocPtrArrayWordSize(); for ( gen = G->generator ; gen ; gen = gen->next ) if ( gen->name[0] != '*' ) {
pOrder = permOrder( gen); if ( pOrder > 2 && pOrder <= sOptions.genOrderLimit ) {
tempWord.length = pOrder; for ( j = 1 ; j <= pOrder ; ++j )
tempWord.position[j] = gen;
newRel = addRelatorSortedFromWord( G, &tempWord, TRUE, TRUE);
++numberOfRelators;
totalRelatorLength += newRel->length;
++numberSelected;
totalSelectedLength += newRel->length;
maxRelatorLength = MAX ( maxRelatorLength, newRel->length);
}
} if ( sOptions.prodOrderLimit >= 2 ) for ( gen = G->generator ; gen ; gen = gen->next ) if ( gen->name[0] != '*' ) for ( gen1 = gen->next ; gen1 ; gen1 = gen1->next ) if ( (pOrder = prodOrderBounded( gen, gen1,
sOptions.prodOrderLimit)) > 0 ) {
tempWord.length = 2 * pOrder; for ( j = 1 ; j <= pOrder ; ++j ) {
tempWord.position[2*j-1] = gen;
tempWord.position[2*j] = gen1;
}
newRel = addRelatorSortedFromWord( G, &tempWord, TRUE, TRUE);
++numberOfRelators;
totalRelatorLength += newRel->length;
++numberSelected;
totalSelectedLength += newRel->length;
maxRelatorLength = MAX ( maxRelatorLength, newRel->length);
}
freePtrArrayDegree( tempWord.position);
/* If G has any relators, construct the appropriate occurencesOfGen
lists. */ for ( rel = G->relator ; rel ; rel = rel->next ) {
numberAdded = addOccurencesForRelator( rel, MAX_INT);
informNewRelator( rel, numberAdded);
}
/* If extra cosets are specified, construct the data structures required
for extra cosets. */ if ( sOptions.maxExtraCosets ) {
nextCos = (Unsigned *) malloc( sizeof(Unsigned) *
(sOptions.maxExtraCosets+2) ); if ( !nextCos )
ERROR( "schreierToddCoxeterSims", "Out of memory.")
nextCos -= degree;
prevCos = (Unsigned *) malloc( sizeof(Unsigned) *
(sOptions.maxExtraCosets+2) ); if ( !prevCos )
ERROR( "schreierToddCoxeterSims", "Out of memory.")
prevCos -= degree;
ff = (Unsigned *) malloc( sizeof(Unsigned) *
(sOptions.maxExtraCosets+2) ); if ( !ff )
ERROR( "schreierToddCoxeterSims", "Out of memory.")
ff -= degree;
bb = (Unsigned *) malloc( sizeof(Unsigned) *
(sOptions.maxExtraCosets+2) ); if ( !bb )
ERROR( "schreierToddCoxeterSims", "Out of memory.")
bb -= degree;
equivCoset = (Unsigned *) malloc( sizeof(Unsigned) *
(degree+sOptions.maxExtraCosets+2) ); if ( !equivCoset )
ERROR( "schreierToddCoxeterSims", "Out of memory.")
}
/* Now we repeatedly check whether G^(level)_{alpha_level} = G(level+1) (*) holds for level = G->baseSize,...,2,1. However, (*) fails, we add a new strong generator, possibly a new base point, and adjust level. Note the procedure checkStabilizer returns TRUE if and only if (*) holds. If (*) fails, it sets j, h, and w as follows: L denotes level, s is a Schreier generator of H^(L+1), h = s u_{L+1}(d_{L+1})^-1 u_{j-1}(d_{j-1})^-1 fixes a_1,...,a_{j-1}, If j <= G->baseSize, a_j^h not in Delta_j. If j = G->baseSize+1, h != identity.
w is h in word form. */
level = G->baseSize; while ( level > 0 ) { if ( !svecOK[level] || sOptions.alwaysRebuildSvec ) {
constructBasicOrbit( G, level, "AllGensAtLevel" );
svecOK[level] = TRUE;
} if ( (sOptions.maxExtraCosets == 0 &&
checkStabilizer( G, knownBase, level, &j, &h, &w)) ||
(sOptions.maxExtraCosets > 0 &&
xCheckStabilizer( G, knownBase, level, &j, &h, &w)) )
--level; else { if ( j == G->baseSize+1 ) {
G->base[++G->baseSize] = pointMovedBy( h);
G->basicOrbLen[G->baseSize] = 1;
G->basicOrbit[G->baseSize] = allocIntArrayDegree();
G->schreierVec[G->baseSize] = allocPtrArrayDegree();
}
assignGenName( G, h);
addStrongGeneratorNR( G, h);
adjoinInverseGen( G, h);
w->position[++w->length] = h->invPermutation;
newRel = addRelatorSortedFromWord( G, w, TRUE, TRUE);
++numberOfRelators;
totalRelatorLength += newRel->length;
++numberSelected;
totalSelectedLength += newRel->length;
maxRelatorLength = MAX ( maxRelatorLength, newRel->length);
numberAdded = addOccurencesForRelator( newRel, MAX_INT);
informNewRelator( newRel, numberAdded); for ( k = level + 1 ; k <= j; ++k )
svecOK[k] = FALSE;
level = j;
}
}
/* This function checkStabilizer( G, knownBase, level, j, h, w) checks whether G^(level)_{alpha_level} = G(level+1). (*) It returns true if (*) holds and false otherwise. If (*) fails, it also sets j and returns a new permutation h and a new word w as follows. L denotes level, s is a Schreier generator of H^(L+1), h = s u_{L+1}(d_{L+1})^-1 u_{j-1}(d_{j-1})^-1 fixes a_1,...,a_{j-1}, If j <= G->baseSize, a_j^h not in Delta_j. If j = G->baseSize+1, h != identity. w is h in word form.
/* Link the generators at specified level, using xNext. */
genHeader = linkGensAtLevel( G, level);
/* Flag all table entries at this level. Also empty the deduction
queue. */
MAKE_EMPTY( deductionQueue); for ( gen = genHeader ; gen ; gen = gen->xNext ) for ( i = 1 ; i <= basicOrbLen ; ++i ) {
pt = basicOrbit[i];
gen->image[pt] |= HB;
++totalTableEntries;
}
/* Now put the subgroup generator entries for H^(level+1) in the table,
and enqueue them. */ for ( gen = genHeader ; gen ; gen = gen->xNext ) if ( gen->level > level ) {
gen->image[basicOrbit[1]] = basicOrbit[1];
++tableEntriesFilled;
newDeduc.pnt = newDeduc.img = basicOrbit[1]; newDeduc.gn = gen;
ATTEMPT_ENQUEUE( deductionQueue, newDeduc)
}
/* Now make those definitions corresponding to the Schreier vector. */ for ( i = 2 ; i <= basicOrbLen ; ++i ) {
pt = basicOrbit[i];
gen = schreierVec[pt];
prevPt = gen->invImage[pt] & NHB;
gen->image[prevPt] = pt;
++tableEntriesFilled;
newDeduc.pnt = prevPt; newDeduc.img = pt; newDeduc.gn = gen;
ATTEMPT_ENQUEUE( deductionQueue, newDeduc); if ( gen->invImage[pt] & HB ) {
gen->invImage[pt] = prevPt;
++tableEntriesFilled;
newDeduc.pnt = pt; newDeduc.img = prevPt;
newDeduc.gn = gen->invPermutation;
ATTEMPT_ENQUEUE( deductionQueue, newDeduc);
}
}
/* Perform initial enumerations till deduction queue is empty. */ while ( NOT_EMPTY(deductionQueue) ) {
DEQUEUE( deductionQueue , deduc);
findConsequences( deductionQueue, level, &deduc);
}
/* This function xCheckStabilizer( G, knownBase, level, j, h, w) checks whether G^(level)_{alpha_level} = G(level+1). (*) It returns true if (*) holds and false otherwise. If (*) fails, it also sets j and returns a new permutation h and a new word w as follows. L denotes level, s is a Schreier generator of H^(L+1), h = s u_{L+1}(d_{L+1})^-1 u_{j-1}(d_{j-1})^-1 fixes a_1,...,a_{j-1}, If j <= G->baseSize, a_j^h not in Delta_j. If j = G->baseSize+1, h != identity. w is h in word form.
/* First time, allocate the deduction queue and definition list. */ if ( !deductionQueue ) {
deductionQueue = (DeductionQueue *) malloc( sizeof(DeductionQueue) ); if ( !deductionQueue )
ERROR( "xCheckStabilizer", "Out of memory.")
deductionQueue->deduc = (Deduction *) malloc(
sOptions.maxDeducQueueSize * sizeof(Deduction)); if ( !deductionQueue->deduc )
ERROR( "checkStabilizer", "Out of memory.")
defnList = (DefinitionList *) malloc( sizeof(DefinitionList) ); if ( !defnList )
ERROR( "xCheckStabilizer", "Out of memory.")
defnList->coset = (Unsigned *) malloc(
sOptions.maxExtraCosets * sizeof(Unsigned) ); if ( !defnList->coset )
ERROR( "xCheckStabilizer", "Out of memory.")
defnList->image = (Unsigned *) malloc(
sOptions.maxExtraCosets * sizeof(Unsigned) ); if ( !defnList->image )
ERROR( "xCheckStabilizer", "Out of memory.")
defnList->gen = (Permutation **) malloc(
sOptions.maxExtraCosets * sizeof(Permutation *) ); if ( !defnList->gen )
ERROR( "xCheckStabilizer", "Out of memory.")
}
totalTableEntries = tableEntriesFilled = 0;
/* Compute number of extra cosets at this level. */
extraCosetsAtLevel = (Unsigned) MIN(
(unsignedlong) sOptions.maxExtraCosets,
sOptions.percentExtraCosets * ((unsignedlong) basicOrbLen + 99) / 100 );
currentExtraCosets = 0;
/* Link the generators at specified level, using xNext. */
genHeader = linkGensAtLevel( G, level);
/* Initialize data structures for extra cosets. */
firstCos = 0;
freeCosHeader = degree + 1; for ( i = 1 ; i <= degree ; ++i )
equivCoset[i] = i; for ( i = degree + 1 ; i < degree + extraCosetsAtLevel ; ++i )
nextCos[i] = i + 1;
nextCos[degree+extraCosetsAtLevel] = 0; for ( i = degree + 1 ; i <= degree + extraCosetsAtLevel ; ++i )
bb[i] = i; for ( gen = genHeader ; gen ; gen = gen->xNext ) for ( i = degree + 1 ; i <= degree + extraCosetsAtLevel ; ++i )
gen->image[i] = HB;
defnList->head = defnList->tail = defnList->size = 0;
/* Flag all table entries at this level. Also empty the deduction
queue. */
MAKE_EMPTY( deductionQueue); for ( gen = genHeader ; gen ; gen = gen->xNext ) for ( i = 1 ; i <= basicOrbLen ; ++i ) {
pt = basicOrbit[i];
gen->image[pt] |= HB;
++totalTableEntries;
}
/* Now put the subgroup generator entries for H^(level+1) in the table,
and enqueue them. */ for ( gen = genHeader ; gen ; gen = gen->xNext ) if ( gen->level > level ) {
gen->image[basicOrbit[1]] = basicOrbit[1];
++tableEntriesFilled;
newDeduc.pnt = newDeduc.img = basicOrbit[1]; newDeduc.gn = gen;
ATTEMPT_ENQUEUE( deductionQueue, newDeduc)
}
/* Now make those definitions corresponding to the Schreier vector. */ for ( i = 2 ; i <= basicOrbLen ; ++i ) {
pt = basicOrbit[i];
gen = schreierVec[pt];
prevPt = gen->invImage[pt] & NHB;
gen->image[prevPt] = pt;
++tableEntriesFilled;
newDeduc.pnt = prevPt; newDeduc.img = pt; newDeduc.gn = gen;
ATTEMPT_ENQUEUE( deductionQueue, newDeduc); if ( gen->invImage[pt] & HB ) {
gen->invImage[pt] = prevPt;
++tableEntriesFilled;
newDeduc.pnt = pt; newDeduc.img = prevPt;
newDeduc.gn = gen->invPermutation;
ATTEMPT_ENQUEUE( deductionQueue, newDeduc);
}
}
/* Perform initial enumerations till deduction queue is empty. */ while ( NOT_EMPTY(deductionQueue) ) {
DEQUEUE( deductionQueue , deduc);
xFindConsequences( G, deductionQueue, level, &deduc, genHeader);
}
/* DEBUGGING -- REQUIRES FIXING, SINCE THERE SHOULD BE NO EXTRA COSETS HERE. */ for ( j = firstCos ; j ; j = nextCos[j] ) for ( gen = genHeader ; gen ; gen = gen->xNext ) if ( gen->image[j] < degree )
gen->invImage[gen->image[j]] = equivCoset[j];
/* The function computeSchreierGen( G, level, point, gen) computes the Schreier generator u_level(point) * gen * bar(u_level(point^gen))^-1 for G^(level+1). Here point must lie in Delta_level and gen must be a generator in G^(level). The function returns a word (with newly allocated position field), representing the Schreier generator, and a new image array, representing the image of 1,2,...,n under the word.
NOTE this function takes account of the fact that generating permutations
may have the leftmost bit set as a flag. */
/* The function xComputeSchreierGen( G, level, point, gen) is identical to computeSchreierGen( G, level, point, gen) except that it takes account
of the possibility of temporary cosets ( > degree) in the table. */
/* The function reduce( G, level, j, wh) takes a word-image pair representing an element of G^(level) and it modifies it by right-multiplying by u_{level+1}^-1(d_{level+1} ... u_{j-1}^-1(d_{level+1}) so that it fixes a_{level+1},...,a_{j-1} and either i) j <= G->baseSize, and a_j^wh not in Delta_j. ii) j == G->baseSize+1, and wh != 1. iii) j == G->baseSize+1, and wh == 1.
It returns false in cases (i) and (ii) and true in case (iii). */
/* The function xReduce( G, level, j, wh) is identical to Reduce( G, level, j, wh) except that it takes account of the possibility
of temporary cosets ( > degree) in the table. */
/* This function may be used to adjoin a new strong generator to a permutation group WITHOUT reconstructing basic orbits. Also, the
essential fields are not modified in any way. */
void addStrongGeneratorNR(
PermGroup *G, /* Group to which strong gen is adjoined. */
Permutation *newGen) /* The new strong generator. It must move
a base point (not checked). */
{ Unsigned i;
/* Append inverse image of new strong generator, if absent. */ if ( !newGen->invImage )
adjoinInvImage( newGen);
/* Find level of new strong generator. */
newGen->level = levelIn( G, newGen);
/* The function prodOrderBounded( perm1, perm2, bound) returns the order of the product of permutations perm1 and perm2, provided this order is less
than or equal to bound, and returns 0 otherwise. */
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 und die Messung sind noch experimentell.