/****************************************************************************
**
*A collect.c ANUPQ source Eamonn O'Brien
**
*Y Copyright 1995-2001, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
*Y Copyright 1995-2001, School of Mathematical Sciences, ANU, Australia
**
*/
#include "pq_defs.h"
#include "pcp_vars.h"
#include "constants.h"
#define MAXEXP (1 << 30)
void stack_overflow(void);
void integer_overflow(void);
void add_string(int string,
int length,
int exponent,
int collected_part,
struct pcp_vars *pcp);
/* an exponent vector with base address collected_part
is multiplied on the right by a string with base address
pointer; the string is assumed to be normal
this routine follows the algorithm devised by
M.R. Vaughan-Lee for collection from the left;
step numbers correspond to step numbers in
"Collection from the Left" by M.R. Vaughan-Lee,
J. Symbolic Computation (1990) 9, 725-733
this version embodies a simpler form of combinatorial
collection as described on page 733, which lessens the
chance of integer overflow; it also incorporates recursion
when adding strings and generators to the exponent vector
during the collection algorithm, pointers to a number of strings
are stored on a stack; theoretically, the stack depth could get
as large as (p - 1) * pcp->lastg * pcp->cc, but, in practice, depths
this large do not arise; however, it could be necessary to increase
the dimensions of the stack arrays for some calculations with large
groups; STACK_SIZE is the maximum depth of the stack; this constant
is declared in the constants header file; overflow is tested in
this algorithm
integer overflow is also tested for, although it can only arise
if p^3 > 2^31; if p^2 > 2^31, integer overflow can arise which
is not tested for
if either overflow arises, a message is printed out and
the program terminates;
#####################################################################
note the sections in this code enclosed within
#ifndef EXPONENT_P
#endif
if you insert as part of the header material of this file
#define EXPONENT_P
or supply EXPONENT_P as a -D flag to the compiler, then the
resulting collector assumes that all generators of the pcp
have order p and does not execute these portions of the code */
/* stack size on Apollo causes problems */
#ifdef APOLLO
static t_int strstk[STACK_SIZE]; /* string stack */
static t_int lenstk[STACK_SIZE]; /* length stack */
static t_int expstk[STACK_SIZE]; /* exponent stack */
#endif
/* if Lie program, use different collect routine */
#if defined(GROUP)
void collect(int pointer, int collected_part, struct pcp_vars *pcp)
{
register int *y = y_address;
register int p1; /* string pointer */
register int ce; /* collected exponent */
register int cg; /* collected generator */
register int ug; /* uncollected generator */
register int ue; /* uncollected exponent */
register int sp = 0; /* stack pointer */
register int exp; /* exponent */
register int len = 1; /* length */
register int str; /* string pointer */
register int halfwt; /* last generator with weight <= cc/2 */
register int thirdwt; /* last generator with weight <= cc/3 */
register int weight_diff; /* current class - weight of ug */
register int entry; /* value to be inserted in collected part */
register int firstcg; /* first collected generator for loop counter */
register int lastcg; /* last collected generator for loop counter */
register int maxexp; /* max exponent allowed in call to add_string */
register int cp = collected_part;
register int class_end = pcp->clend;
register int current_class = pcp->cc;
register int prime = pcp->p;
register int pm1 = pcp->pm1;
register int p_pcomm = pcp->ppcomm;
register int p_power = pcp->ppower;
register int structure = pcp->structure;
#ifndef APOLLO
int strstk[STACK_SIZE]; /* string stack */
int lenstk[STACK_SIZE]; /* length stack */
int expstk[STACK_SIZE]; /* exponent stack */
#endif
register int i;
#include "access.h"
/* if prime is 2, use special collector */
if (prime == 2) {
collectp2(pointer, collected_part, pcp);
return;
}
/* Step (0) --
initialize collector */
if (pointer < 0)
lenstk[0] = y[-pointer + 1];
else if (pointer == 0)
return;
strstk[0] = pointer;
expstk[0] = 1;
maxexp = (MAXEXP / prime) * 2;
halfwt = y[class_end + current_class / 2];
thirdwt = y[class_end + current_class / 3];
/* Step (1) --
process next word on stack */
while (sp >= 0) {
str = strstk[sp];
exp = expstk[sp];
/* check if str is a string or a generator */
if (str < 0) {
/* we have a genuine string */
len = lenstk[sp];
sp--;
/* get first generator exponent pair from string */
i = y[-str + 2];
ug = FIELD2(i);
/* if ug > halfwt, the string can be added to the
collected part without creating any commutators */
if (ug > halfwt) {
add_string(str, len, exp, cp, pcp);
continue;
}
/* ug <= halfwt and so exp must equal 1; stack remainder of string */
ue = FIELD1(i);
if (len != 1) {
strstk[++sp] = str - 1;
lenstk[sp] = len - 1;
}
} else {
/* str is a generator */
ug = str;
ue = exp;
sp--;
/* if ug > halfwt, ug commutes with all higher generators */
if (ug > halfwt) {
add_string(ug, 1, ue, cp, pcp);
continue;
}
}
/* ug <= halfwt; if ug > thirdwt, any commutators arising in
collecting ug commute with all generators after ug, so ug
can be collected without stacking up collected part */
if (ug <= thirdwt) {
/* Step (2) --
combinatorial collection;
scan collected part towards the left;
bypass generators we know must commute with ug;
when 2 * WT(cg) + WT(ug) > current_class, all generators
occurring in [cg, ug] commute with each other;
[cg^ce, ug] = [cg, ug]^ce;
if cg1,..., cgk all satisfy this weight condition then
[cg1 * ... * cgk, ug] = [cg1, ug] ... [cgk, ug] */
if (ue != 1) {
/* we only move one ug at a time; stack ug^(ue - 1) */
if (++sp >= STACK_SIZE)
stack_overflow();
strstk[sp] = ug;
expstk[sp] = ue - 1;
ue = 1;
}
weight_diff = current_class - WT(y[structure + ug]);
firstcg = y[class_end + weight_diff];
lastcg = y[class_end + weight_diff / 2];
/* scan collected part to the left, bypassing generators
which must commute with ug; the collected part between
lastcg and firstcg contains a word w; we add in [w, ug] */
for (cg = firstcg; cg > ug; cg--) {
ce = y[cp + cg];
if (ce != 0) {
/* add [cg, ug]^ce to the collected part */
p1 = y[p_pcomm + cg] + ug;
p1 = y[p1];
if (p1 != 0) {
if (cg <= lastcg)
break;
if (p1 < 0)
len = y[-p1 + 1];
add_string(p1, len, ce, cp, pcp);
}
}
}
if (cg == ug) {
/* we have reached ug position during combinatorial
collection; add 1 to ug entry of collected part
without stacking any entries if appropriate */
if (y[cp + ug] == pm1) {
if (y[p_power + ug] == 0) {
y[cp + ug] = 0;
continue;
}
} else {
++y[cp + ug];
continue;
}
}
/* we have now added in [w, ug]; stack up
collected part between firstcg and cg + 1 */
for (i = firstcg; i > cg; i--) {
ce = y[cp + i];
if (ce != 0) {
y[cp + i] = 0;
if (++sp >= STACK_SIZE)
stack_overflow();
strstk[sp] = i;
expstk[sp] = ce;
}
}
/* Step (3) --
ordinary collection; we have moved ug to the cg position;
continue scanning to the left */
for (; cg > ug; cg--) {
ce = y[cp + cg];
if (ce != 0) {
/* zero the cg entry of collected part */
y[cp + cg] = 0;
/* get [cg, ug] */
p1 = y[p_pcomm + cg] + ug;
p1 = y[p1];
if (p1 == 0) {
/* cg commutes with ug so stack cg^ce */
if (++sp >= STACK_SIZE)
stack_overflow();
strstk[sp] = cg;
expstk[sp] = ce;
} else {
/* cg does not commute with ug;
we can only move ug past one cg at a time;
stack [cg, ug] and then cg a total of ce times */
if (sp + ce + ce >= STACK_SIZE)
stack_overflow();
if (p1 < 0)
len = y[-p1 + 1];
for (; ce > 0; --ce) {
strstk[++sp] = p1;
lenstk[sp] = len;
expstk[sp] = 1;
strstk[++sp] = cg;
expstk[sp] = 1;
}
}
}
}
/* we have moved ug to the correct position;
add 1 to the ug entry of collected part */
add_string(ug, 1, 1, cp, pcp);
continue;
} /* ug <= thirdwt */
/* Step (6) -- ug > thirdwt;
move ug^ue past entries in the collected part, adding
commutators directly to the collected part;
scan collected part towards the left, bypassing generators
we know must commute with ug; if the cg position in
the collected part contains an entry ce then this
represents cg^ce; [cg^ce, ug^ue] = [cg, ug]^(ce * ue),
and we add the ce * ue power of [cg, ug] directly to
the collected part */
weight_diff = current_class - WT(y[structure + ug]);
firstcg = y[class_end + weight_diff];
for (cg = firstcg; cg > ug; cg--) {
ce = y[cp + cg];
if (ce != 0) {
/* add [cg, ug]^(ce * ue) directly to the collected part */
p1 = y[p_pcomm + cg];
p1 = y[p1 + ug];
if (p1 != 0) {
exp = ce * ue;
if (exp > maxexp)
integer_overflow();
if (p1 < 0)
len = y[-p1 + 1];
add_string(p1, len, exp, cp, pcp);
}
}
}
/* add ue to the ug entry of collected part */
entry = y[cp + ug] + ue;
if (entry < prime) {
y[cp + ug] = entry;
continue;
} else {
y[cp + ug] = entry - prime;
p1 = y[p_power + ug];
if (p1 == 0)
continue;
}
/* adding ue to the ug entry has created an entry >= prime;
we have to stack some of collected part */
for (cg = firstcg; cg > ug; cg--) {
ce = y[cp + cg];
if (ce != 0) {
/* set entry to zero and stack cg^ce */
y[cp + cg] = 0;
if (++sp >= STACK_SIZE)
stack_overflow();
strstk[sp] = cg;
expstk[sp] = ce;
}
}
/* add in ug^p; p1 is a pointer to ug^p */
if (p1 < 0)
len = y[-p1 + 1];
add_string(p1, len, 1, cp, pcp);
continue;
}
}
#endif /* GROUP*/
/* add exponent times the string with address string and length length
directly to the collected part with base address collected_part,
recursively adding powers as required */
void add_string(int string,
int length,
int exponent,
int collected_part,
struct pcp_vars *pcp)
{
register int *y = y_address;
register int cp = collected_part;
register int exp = exponent;
register int len = length;
register int str = string;
register int entry;
register int ug;
register int ue;
register int power;
register int class_begin = pcp->ccbeg;
register int prime = pcp->p;
register int p_power = pcp->ppower;
register int i;
int lower, upper;
#include "access.h"
if (str > 0) {
/* Step (4) --
we have moved generator str to the correct position;
add exp to the str entry of the collected part;
reduce entry modulo p and add a power of str^p
to the collected part if necessary */
entry = y[cp + str] + exp;
y[cp + str] = entry % prime;
if (str < class_begin) {
exp = entry / prime;
#ifndef EXPONENT_P
if (exp != 0) {
/* we need to recursively add in (str^p)^exp */
str = y[p_power + str];
if (str != 0) {
if (str < 0)
len = y[-str + 1];
add_string(str, len, exp, cp, pcp);
}
}
#endif
}
} else {
/* Step (5) --
add string with base address -str and length len
directly to the collected part exp times; if this
creates an entry >= prime we reduce the entry modulo
prime and add in the appropriate power */
lower = -str + 2;
upper = -str + len + 1;
/* get one generator exponent pair at a time from string */
for (i = lower; i <= upper; i++) {
ug = FIELD2(y[i]);
ue = FIELD1(y[i]) * exp;
entry = y[cp + ug] + ue;
/* add ue to ug entry of the collected part and reduce mod p */
y[cp + ug] = entry % prime;
#ifndef EXPONENT_P
/* we need to recursively add in (ug^p)^power */
if (ug < class_begin) {
power = entry / prime;
if (power != 0) {
str = y[p_power + ug];
if (str != 0) {
if (str < 0)
len = y[-str + 1];
add_string(str, len, power, cp, pcp);
}
}
}
#endif
}
}
}
/* stack is not big enough */
void stack_overflow(void)
{
printf("Stack overflow in collection routine; you should increase\n");
printf("value of STACK_SIZE in constants.h and recompile.\n");
exit(FAILURE);
}
/* arithmetic overflow */
void integer_overflow(void)
{
printf("Arithmetic overflow may occur in collection ");
printf("routine. Results may be invalid.\n");
exit(FAILURE);
}
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|